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:
Eric Pouech 2022-03-01 09:25:56 +01:00 committed by Alexandre Julliard
parent ce6365551b
commit ef8d44e58e
5 changed files with 118 additions and 21 deletions

View File

@ -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;
} }

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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: