kernelbase: Support CONSOLE_READCONSOLE_CONTROL in ReadConsoleW.
Signed-off-by: Eric Pouech <eric.pouech@gmail.com> Signed-off-by: Jacek Caban <jacek@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
ce6365551b
commit
ef8d44e58e
|
@ -2021,8 +2021,36 @@ BOOL WINAPI ReadConsoleW( HANDLE handle, void *buffer, DWORD length, DWORD *coun
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = console_ioctl( handle, IOCTL_CONDRV_READ_CONSOLE, NULL, 0, buffer,
|
if (reserved)
|
||||||
length * sizeof(WCHAR), count );
|
{
|
||||||
|
CONSOLE_READCONSOLE_CONTROL* crc = reserved;
|
||||||
|
char *tmp;
|
||||||
|
|
||||||
|
if (crc->nLength != sizeof(*crc) || crc->nInitialChars >= length)
|
||||||
|
{
|
||||||
|
SetLastError( ERROR_INVALID_PARAMETER );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (!(tmp = HeapAlloc( GetProcessHeap(), 0, sizeof(DWORD) + crc->nInitialChars * sizeof(WCHAR) )))
|
||||||
|
{
|
||||||
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy( tmp, &crc->dwCtrlWakeupMask, sizeof(DWORD) );
|
||||||
|
memcpy( tmp + sizeof(DWORD), buffer, crc->nInitialChars * sizeof(WCHAR) );
|
||||||
|
ret = console_ioctl( handle, IOCTL_CONDRV_READ_CONSOLE_CONTROL,
|
||||||
|
tmp, sizeof(DWORD) + crc->nInitialChars * sizeof(WCHAR),
|
||||||
|
buffer, length * sizeof(WCHAR),
|
||||||
|
count );
|
||||||
|
crc->dwConsoleKeyState = 0;
|
||||||
|
HeapFree( GetProcessHeap(), 0, tmp );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = console_ioctl( handle, IOCTL_CONDRV_READ_CONSOLE, NULL, 0, buffer,
|
||||||
|
length * sizeof(WCHAR), count );
|
||||||
|
}
|
||||||
if (ret) *count /= sizeof(WCHAR);
|
if (ret) *count /= sizeof(WCHAR);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#define IOCTL_CONDRV_FLUSH CTL_CODE(FILE_DEVICE_CONSOLE, 21, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
#define IOCTL_CONDRV_FLUSH CTL_CODE(FILE_DEVICE_CONSOLE, 21, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||||
#define IOCTL_CONDRV_GET_WINDOW CTL_CODE(FILE_DEVICE_CONSOLE, 22, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
#define IOCTL_CONDRV_GET_WINDOW CTL_CODE(FILE_DEVICE_CONSOLE, 22, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||||
#define IOCTL_CONDRV_GET_PROCESS_LIST CTL_CODE(FILE_DEVICE_CONSOLE, 23, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
#define IOCTL_CONDRV_GET_PROCESS_LIST CTL_CODE(FILE_DEVICE_CONSOLE, 23, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||||
|
#define IOCTL_CONDRV_READ_CONSOLE_CONTROL CTL_CODE(FILE_DEVICE_CONSOLE, 24, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||||
|
|
||||||
/* console output ioctls */
|
/* console output ioctls */
|
||||||
#define IOCTL_CONDRV_WRITE_CONSOLE CTL_CODE(FILE_DEVICE_CONSOLE, 30, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
#define IOCTL_CONDRV_WRITE_CONSOLE CTL_CODE(FILE_DEVICE_CONSOLE, 30, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||||
|
|
|
@ -492,8 +492,9 @@ static void read_from_buffer( struct console *console, size_t out_size )
|
||||||
switch( console->read_ioctl )
|
switch( console->read_ioctl )
|
||||||
{
|
{
|
||||||
case IOCTL_CONDRV_READ_CONSOLE:
|
case IOCTL_CONDRV_READ_CONSOLE:
|
||||||
|
case IOCTL_CONDRV_READ_CONSOLE_CONTROL:
|
||||||
out_size = min( out_size, console->read_buffer_count * sizeof(WCHAR) );
|
out_size = min( out_size, console->read_buffer_count * sizeof(WCHAR) );
|
||||||
read_complete( console, STATUS_SUCCESS, console->read_buffer, out_size, console->record_count != 0 );
|
read_complete( console, STATUS_SUCCESS, console->read_buffer, out_size, console->record_count != 0 );
|
||||||
read_len = out_size / sizeof(WCHAR);
|
read_len = out_size / sizeof(WCHAR);
|
||||||
break;
|
break;
|
||||||
case IOCTL_CONDRV_READ_FILE:
|
case IOCTL_CONDRV_READ_FILE:
|
||||||
|
@ -1155,7 +1156,7 @@ static unsigned int edit_line_string_width( const WCHAR *str, unsigned int len)
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_read_output( struct console *console )
|
static void update_read_output( struct console *console, BOOL newline )
|
||||||
{
|
{
|
||||||
struct screen_buffer *screen_buffer = console->active;
|
struct screen_buffer *screen_buffer = console->active;
|
||||||
struct edit_line *ctx = &console->edit_line;
|
struct edit_line *ctx = &console->edit_line;
|
||||||
|
@ -1203,7 +1204,7 @@ static void update_read_output( struct console *console )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ctx->status)
|
if (newline)
|
||||||
{
|
{
|
||||||
offset = edit_line_string_width( ctx->buf, ctx->len );
|
offset = edit_line_string_width( ctx->buf, ctx->len );
|
||||||
screen_buffer->cursor_x = 0;
|
screen_buffer->cursor_x = 0;
|
||||||
|
@ -1241,10 +1242,14 @@ static void update_read_output( struct console *console )
|
||||||
update_window_config( screen_buffer->console, TRUE );
|
update_window_config( screen_buffer->console, TRUE );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* can end on any ctrl-character: from 0x00 up to 0x1F) */
|
||||||
|
#define FIRST_NON_CONTROL_CHAR (L' ')
|
||||||
|
|
||||||
static NTSTATUS process_console_input( struct console *console )
|
static NTSTATUS process_console_input( struct console *console )
|
||||||
{
|
{
|
||||||
struct edit_line *ctx = &console->edit_line;
|
struct edit_line *ctx = &console->edit_line;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
WCHAR ctrl_value = FIRST_NON_CONTROL_CHAR;
|
||||||
|
|
||||||
switch (console->read_ioctl)
|
switch (console->read_ioctl)
|
||||||
{
|
{
|
||||||
|
@ -1252,6 +1257,7 @@ static NTSTATUS process_console_input( struct console *console )
|
||||||
if (console->record_count) read_console_input( console, console->pending_read );
|
if (console->record_count) read_console_input( console, console->pending_read );
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
case IOCTL_CONDRV_READ_CONSOLE:
|
case IOCTL_CONDRV_READ_CONSOLE:
|
||||||
|
case IOCTL_CONDRV_READ_CONSOLE_CONTROL:
|
||||||
case IOCTL_CONDRV_READ_FILE:
|
case IOCTL_CONDRV_READ_FILE:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1284,6 +1290,19 @@ static NTSTATUS process_console_input( struct console *console )
|
||||||
/* mask out some bits which don't interest us */
|
/* mask out some bits which don't interest us */
|
||||||
state = ir.Event.KeyEvent.dwControlKeyState & ~(NUMLOCK_ON|SCROLLLOCK_ON|CAPSLOCK_ON|ENHANCED_KEY);
|
state = ir.Event.KeyEvent.dwControlKeyState & ~(NUMLOCK_ON|SCROLLLOCK_ON|CAPSLOCK_ON|ENHANCED_KEY);
|
||||||
|
|
||||||
|
if (ctx->ctrl_mask &&
|
||||||
|
ir.Event.KeyEvent.uChar.UnicodeChar &&
|
||||||
|
ir.Event.KeyEvent.uChar.UnicodeChar < FIRST_NON_CONTROL_CHAR)
|
||||||
|
{
|
||||||
|
if (ctx->ctrl_mask & (1u << ir.Event.KeyEvent.uChar.UnicodeChar))
|
||||||
|
{
|
||||||
|
ctrl_value = ir.Event.KeyEvent.uChar.UnicodeChar;
|
||||||
|
ctx->status = STATUS_SUCCESS;
|
||||||
|
TRACE("Found ctrl char in mask: ^%lc %x\n", ir.Event.KeyEvent.uChar.UnicodeChar + '@', ctx->ctrl_mask);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ir.Event.KeyEvent.uChar.UnicodeChar == 10) continue;
|
||||||
|
}
|
||||||
func = NULL;
|
func = NULL;
|
||||||
for (map = console->edition_mode ? emacs_key_map : win32_key_map; map->entries != NULL; map++)
|
for (map = console->edition_mode ? emacs_key_map : win32_key_map; map->entries != NULL; map++)
|
||||||
{
|
{
|
||||||
|
@ -1326,7 +1345,7 @@ static NTSTATUS process_console_input( struct console *console )
|
||||||
}
|
}
|
||||||
else if (ctx->len >= console->pending_read / sizeof(WCHAR))
|
else if (ctx->len >= console->pending_read / sizeof(WCHAR))
|
||||||
ctx->status = STATUS_SUCCESS;
|
ctx->status = STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (console->record_count > i) memmove( console->records, console->records + i,
|
if (console->record_count > i) memmove( console->records, console->records + i,
|
||||||
|
@ -1336,19 +1355,26 @@ static NTSTATUS process_console_input( struct console *console )
|
||||||
if (ctx->status == STATUS_PENDING && !(console->mode & ENABLE_LINE_INPUT) && ctx->len)
|
if (ctx->status == STATUS_PENDING && !(console->mode & ENABLE_LINE_INPUT) && ctx->len)
|
||||||
ctx->status = STATUS_SUCCESS;
|
ctx->status = STATUS_SUCCESS;
|
||||||
|
|
||||||
if (console->mode & ENABLE_ECHO_INPUT) update_read_output( console );
|
if (console->mode & ENABLE_ECHO_INPUT) update_read_output( console, !ctx->status && ctrl_value == FIRST_NON_CONTROL_CHAR );
|
||||||
if (ctx->status == STATUS_PENDING) return STATUS_SUCCESS;
|
if (ctx->status == STATUS_PENDING) return STATUS_SUCCESS;
|
||||||
|
|
||||||
if (!ctx->status && (console->mode & ENABLE_LINE_INPUT))
|
if (!ctx->status && (console->mode & ENABLE_LINE_INPUT))
|
||||||
{
|
{
|
||||||
if (ctx->len) append_input_history( console, ctx->buf, ctx->len * sizeof(WCHAR) );
|
if (ctrl_value < FIRST_NON_CONTROL_CHAR)
|
||||||
if (edit_line_grow(console, 2))
|
|
||||||
{
|
{
|
||||||
ctx->buf[ctx->len++] = '\r';
|
edit_line_insert( console, &ctrl_value, 1 );
|
||||||
ctx->buf[ctx->len++] = '\n';
|
|
||||||
ctx->buf[ctx->len] = 0;
|
|
||||||
TRACE( "return %s\n", debugstr_wn( ctx->buf, ctx->len ));
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ctx->len) append_input_history( console, ctx->buf, ctx->len * sizeof(WCHAR) );
|
||||||
|
if (edit_line_grow(console, 2))
|
||||||
|
{
|
||||||
|
ctx->buf[ctx->len++] = '\r';
|
||||||
|
ctx->buf[ctx->len++] = '\n';
|
||||||
|
ctx->buf[ctx->len] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TRACE( "return %s\n", debugstr_wn( ctx->buf, ctx->len ));
|
||||||
}
|
}
|
||||||
|
|
||||||
console->read_buffer = ctx->buf;
|
console->read_buffer = ctx->buf;
|
||||||
|
@ -1365,8 +1391,10 @@ static NTSTATUS process_console_input( struct console *console )
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS read_console( struct console *console, unsigned int ioctl, size_t out_size )
|
static NTSTATUS read_console( struct console *console, unsigned int ioctl, size_t out_size,
|
||||||
|
const WCHAR *initial, unsigned int initial_len, unsigned int ctrl_mask )
|
||||||
{
|
{
|
||||||
|
struct edit_line *ctx = &console->edit_line;
|
||||||
TRACE("\n");
|
TRACE("\n");
|
||||||
|
|
||||||
if (out_size > INT_MAX)
|
if (out_size > INT_MAX)
|
||||||
|
@ -1382,11 +1410,37 @@ static NTSTATUS read_console( struct console *console, unsigned int ioctl, size_
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
console->edit_line.history_index = console->history_index;
|
ctx->history_index = console->history_index;
|
||||||
console->edit_line.home_x = console->active->cursor_x;
|
ctx->home_x = console->active->cursor_x;
|
||||||
console->edit_line.home_y = console->active->cursor_y;
|
ctx->home_y = console->active->cursor_y;
|
||||||
console->edit_line.status = STATUS_PENDING;
|
ctx->status = STATUS_PENDING;
|
||||||
if (edit_line_grow( console, 1 )) console->edit_line.buf[0] = 0;
|
if (initial_len && edit_line_grow( console, initial_len + 1 ))
|
||||||
|
{
|
||||||
|
unsigned offset = edit_line_string_width( initial, initial_len );
|
||||||
|
if (offset > ctx->home_x)
|
||||||
|
{
|
||||||
|
int deltay;
|
||||||
|
offset -= ctx->home_x;
|
||||||
|
deltay = offset / console->active->width;
|
||||||
|
if (ctx->home_y >= deltay)
|
||||||
|
ctx->home_y -= deltay;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ctx->home_y = 0;
|
||||||
|
FIXME("Support for negative ordinates is missing\n");
|
||||||
|
}
|
||||||
|
ctx->home_x = console->active->width - 1 - (offset % console->active->width);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ctx->home_x -= offset;
|
||||||
|
ctx->cursor = initial_len;
|
||||||
|
memcpy( ctx->buf, initial, initial_len * sizeof(WCHAR) );
|
||||||
|
ctx->buf[initial_len] = 0;
|
||||||
|
ctx->len = initial_len;
|
||||||
|
ctx->end_offset = initial_len;
|
||||||
|
}
|
||||||
|
else if (edit_line_grow( console, 1 )) ctx->buf[0] = 0;
|
||||||
|
ctx->ctrl_mask = ctrl_mask;
|
||||||
|
|
||||||
console->pending_read = out_size;
|
console->pending_read = out_size;
|
||||||
return process_console_input( console );
|
return process_console_input( console );
|
||||||
|
@ -2502,13 +2556,25 @@ static NTSTATUS console_input_ioctl( struct console *console, unsigned int code,
|
||||||
case IOCTL_CONDRV_READ_CONSOLE:
|
case IOCTL_CONDRV_READ_CONSOLE:
|
||||||
if (in_size || *out_size % sizeof(WCHAR)) return STATUS_INVALID_PARAMETER;
|
if (in_size || *out_size % sizeof(WCHAR)) return STATUS_INVALID_PARAMETER;
|
||||||
ensure_tty_input_thread( console );
|
ensure_tty_input_thread( console );
|
||||||
status = read_console( console, code, *out_size );
|
status = read_console( console, code, *out_size, NULL, 0, 0 );
|
||||||
|
*out_size = 0;
|
||||||
|
return status;
|
||||||
|
|
||||||
|
case IOCTL_CONDRV_READ_CONSOLE_CONTROL:
|
||||||
|
if ((in_size < sizeof(DWORD)) || ((in_size - sizeof(DWORD)) % sizeof(WCHAR)) ||
|
||||||
|
(*out_size % sizeof(WCHAR)))
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
ensure_tty_input_thread( console );
|
||||||
|
status = read_console( console, code, *out_size,
|
||||||
|
(const WCHAR*)((const char*)in_data + sizeof(DWORD)),
|
||||||
|
(in_size - sizeof(DWORD)) / sizeof(WCHAR),
|
||||||
|
*(DWORD*)in_data );
|
||||||
*out_size = 0;
|
*out_size = 0;
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
case IOCTL_CONDRV_READ_FILE:
|
case IOCTL_CONDRV_READ_FILE:
|
||||||
ensure_tty_input_thread( console );
|
ensure_tty_input_thread( console );
|
||||||
status = read_console( console, code, *out_size );
|
status = read_console( console, code, *out_size, NULL, 0, 0 );
|
||||||
*out_size = 0;
|
*out_size = 0;
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,7 @@ struct edit_line
|
||||||
unsigned int end_offset; /* offset of the last written char */
|
unsigned int end_offset; /* offset of the last written char */
|
||||||
unsigned int home_x; /* home position */
|
unsigned int home_x; /* home position */
|
||||||
unsigned int home_y;
|
unsigned int home_y;
|
||||||
|
unsigned int ctrl_mask; /* mask for ctrl characters for completion */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct console
|
struct console
|
||||||
|
|
|
@ -952,6 +952,7 @@ static int is_blocking_read_ioctl( unsigned int code )
|
||||||
{
|
{
|
||||||
case IOCTL_CONDRV_READ_INPUT:
|
case IOCTL_CONDRV_READ_INPUT:
|
||||||
case IOCTL_CONDRV_READ_CONSOLE:
|
case IOCTL_CONDRV_READ_CONSOLE:
|
||||||
|
case IOCTL_CONDRV_READ_CONSOLE_CONTROL:
|
||||||
case IOCTL_CONDRV_READ_FILE:
|
case IOCTL_CONDRV_READ_FILE:
|
||||||
return 1;
|
return 1;
|
||||||
default:
|
default:
|
||||||
|
|
Loading…
Reference in New Issue