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;
}
ret = console_ioctl( handle, IOCTL_CONDRV_READ_CONSOLE, NULL, 0, buffer,
length * sizeof(WCHAR), count );
if (reserved)
{
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);
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_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_READ_CONSOLE_CONTROL CTL_CODE(FILE_DEVICE_CONSOLE, 24, METHOD_BUFFERED, FILE_READ_ACCESS)
/* console output ioctls */
#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 )
{
case IOCTL_CONDRV_READ_CONSOLE:
case IOCTL_CONDRV_READ_CONSOLE_CONTROL:
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);
break;
case IOCTL_CONDRV_READ_FILE:
@ -1155,7 +1156,7 @@ static unsigned int edit_line_string_width( const WCHAR *str, unsigned int len)
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 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 );
screen_buffer->cursor_x = 0;
@ -1241,10 +1242,14 @@ static void update_read_output( struct console *console )
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 )
{
struct edit_line *ctx = &console->edit_line;
unsigned int i;
WCHAR ctrl_value = FIRST_NON_CONTROL_CHAR;
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 );
return STATUS_SUCCESS;
case IOCTL_CONDRV_READ_CONSOLE:
case IOCTL_CONDRV_READ_CONSOLE_CONTROL:
case IOCTL_CONDRV_READ_FILE:
break;
default:
@ -1284,6 +1290,19 @@ static NTSTATUS process_console_input( struct console *console )
/* mask out some bits which don't interest us */
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;
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))
ctx->status = STATUS_SUCCESS;
}
}
}
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)
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 && (console->mode & ENABLE_LINE_INPUT))
{
if (ctx->len) append_input_history( console, ctx->buf, ctx->len * sizeof(WCHAR) );
if (edit_line_grow(console, 2))
if (ctrl_value < FIRST_NON_CONTROL_CHAR)
{
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 ));
edit_line_insert( console, &ctrl_value, 1 );
}
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;
@ -1365,8 +1391,10 @@ static NTSTATUS process_console_input( struct console *console )
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");
if (out_size > INT_MAX)
@ -1382,11 +1410,37 @@ static NTSTATUS read_console( struct console *console, unsigned int ioctl, size_
return STATUS_SUCCESS;
}
console->edit_line.history_index = console->history_index;
console->edit_line.home_x = console->active->cursor_x;
console->edit_line.home_y = console->active->cursor_y;
console->edit_line.status = STATUS_PENDING;
if (edit_line_grow( console, 1 )) console->edit_line.buf[0] = 0;
ctx->history_index = console->history_index;
ctx->home_x = console->active->cursor_x;
ctx->home_y = console->active->cursor_y;
ctx->status = STATUS_PENDING;
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;
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:
if (in_size || *out_size % sizeof(WCHAR)) return STATUS_INVALID_PARAMETER;
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;
return status;
case IOCTL_CONDRV_READ_FILE:
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;

View File

@ -69,6 +69,7 @@ struct edit_line
unsigned int end_offset; /* offset of the last written char */
unsigned int home_x; /* home position */
unsigned int home_y;
unsigned int ctrl_mask; /* mask for ctrl characters for completion */
};
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_CONSOLE:
case IOCTL_CONDRV_READ_CONSOLE_CONTROL:
case IOCTL_CONDRV_READ_FILE:
return 1;
default: