Module: wine Branch: master Commit: 01c05387ce56ad99bd0b629a41317d7058a82462 URL: https://source.winehq.org/git/wine.git/?a=commit;h=01c05387ce56ad99bd0b629a4...
Author: Jacek Caban jacek@codeweavers.com Date: Fri Aug 28 14:25:37 2020 +0200
conhost: Implement IOCTL_CONDRV_WRITE_OUTPUT.
Signed-off-by: Jacek Caban jacek@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
programs/conhost/conhost.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+)
diff --git a/programs/conhost/conhost.c b/programs/conhost/conhost.c index a8fd9abf28..4fbfc19a08 100644 --- a/programs/conhost/conhost.c +++ b/programs/conhost/conhost.c @@ -469,6 +469,82 @@ static NTSTATUS set_output_info( struct screen_buffer *screen_buffer, return STATUS_SUCCESS; }
+static NTSTATUS write_output( struct screen_buffer *screen_buffer, const struct condrv_output_params *params, + size_t in_size, size_t *out_size ) +{ + unsigned int i, entry_size, entry_cnt, x, y; + char_info_t *dest; + char *src; + + entry_size = params->mode == CHAR_INFO_MODE_TEXTATTR ? sizeof(char_info_t) : sizeof(WCHAR); + entry_cnt = (in_size - sizeof(*params)) / entry_size; + + TRACE( "(%u,%u) cnt %u\n", params->x, params->y, entry_cnt ); + + if (params->x >= screen_buffer->width) + { + *out_size = 0; + return STATUS_SUCCESS; + } + + for (i = 0, src = (char *)(params + 1); i < entry_cnt; i++, src += entry_size) + { + if (params->width) + { + x = params->x + i % params->width; + y = params->y + i / params->width; + if (x >= screen_buffer->width) continue; + } + else + { + x = (params->x + i) % screen_buffer->width; + y = params->y + (params->x + i) / screen_buffer->width; + } + if (y >= screen_buffer->height) break; + + dest = &screen_buffer->data[y * screen_buffer->width + x]; + switch(params->mode) + { + case CHAR_INFO_MODE_TEXT: + dest->ch = *(const WCHAR *)src; + break; + case CHAR_INFO_MODE_ATTR: + dest->attr = *(const unsigned short *)src; + break; + case CHAR_INFO_MODE_TEXTATTR: + *dest = *(const char_info_t *)src; + break; + case CHAR_INFO_MODE_TEXTSTDATTR: + dest->ch = *(const WCHAR *)src; + dest->attr = screen_buffer->attr; + break; + default: + return STATUS_INVALID_PARAMETER; + } + } + + if (*out_size == sizeof(SMALL_RECT)) + { + SMALL_RECT *region; + unsigned int width = params->width; + x = params->x; + y = params->y; + if (!(region = alloc_ioctl_buffer( sizeof(*region )))) return STATUS_NO_MEMORY; + region->Left = x; + region->Top = y; + region->Right = min( x + width, screen_buffer->width ) - 1; + region->Bottom = min( y + entry_cnt / width, screen_buffer->height ) - 1; + } + else + { + DWORD *result; + if (!(result = alloc_ioctl_buffer( sizeof(*result )))) return STATUS_NO_MEMORY; + *result = i; + } + + return STATUS_SUCCESS; +} + static NTSTATUS set_console_title( struct console *console, const WCHAR *in_title, size_t size ) { WCHAR *title = NULL; @@ -517,6 +593,12 @@ static NTSTATUS screen_buffer_ioctl( struct screen_buffer *screen_buffer, unsign TRACE( "set %x mode\n", screen_buffer->mode ); return STATUS_SUCCESS;
+ case IOCTL_CONDRV_WRITE_OUTPUT: + if ((*out_size != sizeof(DWORD) && *out_size != sizeof(SMALL_RECT)) || + in_size < sizeof(struct condrv_output_params)) + return STATUS_INVALID_PARAMETER; + return write_output( screen_buffer, in_data, in_size, out_size ); + case IOCTL_CONDRV_GET_OUTPUT_INFO: if (in_size || *out_size < sizeof(struct condrv_output_info)) return STATUS_INVALID_PARAMETER; return get_output_info( screen_buffer, out_size );