Module: wine Branch: master Commit: 44052219aa0e6412a0f595f830c0cdf6e82ea70c URL: https://source.winehq.org/git/wine.git/?a=commit;h=44052219aa0e6412a0f595f83...
Author: Jacek Caban jacek@codeweavers.com Date: Tue Jul 28 17:10:23 2020 +0200
server: Introduce IOCTL_CONDRV_READ_OUTPUT ioctl.
Signed-off-by: Jacek Caban jacek@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
include/wine/condrv.h | 3 +- server/console.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++-- server/trace.c | 1 + 3 files changed, 90 insertions(+), 4 deletions(-)
diff --git a/include/wine/condrv.h b/include/wine/condrv.h index a47a4f2775..839db84ea5 100644 --- a/include/wine/condrv.h +++ b/include/wine/condrv.h @@ -37,6 +37,7 @@ #define IOCTL_CONDRV_SET_TITLE CTL_CODE(FILE_DEVICE_CONSOLE, 16, METHOD_BUFFERED, FILE_WRITE_PROPERTIES)
/* console output ioctls */ +#define IOCTL_CONDRV_READ_OUTPUT CTL_CODE(FILE_DEVICE_CONSOLE, 30, METHOD_BUFFERED, FILE_READ_DATA) #define IOCTL_CONDRV_WRITE_OUTPUT CTL_CODE(FILE_DEVICE_CONSOLE, 31, METHOD_BUFFERED, FILE_WRITE_DATA) #define IOCTL_CONDRV_GET_OUTPUT_INFO CTL_CODE(FILE_DEVICE_CONSOLE, 32, METHOD_BUFFERED, FILE_READ_PROPERTIES) #define IOCTL_CONDRV_SET_OUTPUT_INFO CTL_CODE(FILE_DEVICE_CONSOLE, 33, METHOD_BUFFERED, FILE_WRITE_PROPERTIES) @@ -83,7 +84,7 @@ struct condrv_input_info_params struct condrv_input_info info; /* input_info */ };
-/* IOCTL_CONDRV_WRITE_OUTPUT */ +/* IOCTL_CONDRV_WRITE_OUTPUT and IOCTL_CONDRV_READ_OUTPUT params */ struct condrv_output_params { unsigned int x; /* destination position */ diff --git a/server/console.c b/server/console.c index 14fbd67e22..207e333ec3 100644 --- a/server/console.c +++ b/server/console.c @@ -1248,6 +1248,73 @@ static struct fd *screen_buffer_get_fd( struct object *obj ) return NULL; }
+/* read data from a screen buffer */ +static void read_console_output( struct screen_buffer *screen_buffer, unsigned int x, unsigned int y, + enum char_info_mode mode, unsigned int width ) +{ + unsigned int i, count; + char_info_t *src; + + if (x >= screen_buffer->width || y >= screen_buffer->height) + { + if (width) set_error( STATUS_INVALID_PARAMETER ); + return; + } + src = screen_buffer->data + y * screen_buffer->width + x; + + switch(mode) + { + case CHAR_INFO_MODE_TEXT: + { + WCHAR *data; + count = min( screen_buffer->data + screen_buffer->height * screen_buffer->width - src, + get_reply_max_size() / sizeof(*data) ); + if ((data = set_reply_data_size( count * sizeof(*data) ))) + { + for (i = 0; i < count; i++) data[i] = src[i].ch; + } + } + break; + case CHAR_INFO_MODE_ATTR: + { + unsigned short *data; + count = min( screen_buffer->data + screen_buffer->height * screen_buffer->width - src, + get_reply_max_size() / sizeof(*data) ); + if ((data = set_reply_data_size( count * sizeof(*data) ))) + { + for (i = 0; i < count; i++) data[i] = src[i].attr; + } + } + break; + case CHAR_INFO_MODE_TEXTATTR: + { + char_info_t *data; + SMALL_RECT *region; + if (!width || get_reply_max_size() < sizeof(*region)) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + count = min( (get_reply_max_size() - sizeof(*region)) / (width * sizeof(*data)), screen_buffer->height - y ); + width = min( width, screen_buffer->width - x ); + if (!(region = set_reply_data_size( sizeof(*region) + width * count * sizeof(*data) ))) return; + region->Left = x; + region->Top = y; + region->Right = x + width - 1; + region->Bottom = y + count - 1; + data = (char_info_t *)(region + 1); + for (i = 0; i < count; i++) + { + memcpy( &data[i * width], &src[i * screen_buffer->width], width * sizeof(*data) ); + } + } + break; + default: + set_error( STATUS_INVALID_PARAMETER ); + break; + } +} + /* write data into a screen buffer */ static void write_console_output( struct screen_buffer *screen_buffer, const struct condrv_output_params *params, data_size_t size ) @@ -1378,8 +1445,8 @@ static int fill_console_output( struct screen_buffer *screen_buffer, char_info_t }
/* read data from a screen buffer */ -static void read_console_output( struct screen_buffer *screen_buffer, int x, int y, - enum char_info_mode mode, int wrap ) +static void read_console_output_req( struct screen_buffer *screen_buffer, int x, int y, + enum char_info_mode mode, int wrap ) { int i; char_info_t *end, *src = screen_buffer->data + y * screen_buffer->width + x; @@ -1676,6 +1743,23 @@ static int screen_buffer_ioctl( struct fd *fd, ioctl_code_t code, struct async * screen_buffer->mode = *(unsigned int *)get_req_data(); return 1;
+ case IOCTL_CONDRV_READ_OUTPUT: + { + const struct condrv_output_params *params = get_req_data(); + if (get_req_data_size() != sizeof(*params)) + { + set_error( STATUS_INVALID_PARAMETER ); + return 0; + } + if (console_input_is_bare( screen_buffer->input )) + { + set_error( STATUS_OBJECT_TYPE_MISMATCH ); + return 0; + } + read_console_output( screen_buffer, params->x, params->y, params->mode, params->width ); + return !get_error(); + } + case IOCTL_CONDRV_WRITE_OUTPUT: if (get_req_data_size() < sizeof(struct condrv_output_params) || (get_reply_max_size() != sizeof(SMALL_RECT) && get_reply_max_size() != sizeof(unsigned int))) @@ -2150,7 +2234,7 @@ DECL_HANDLER(read_console_output) release_object( screen_buffer ); return; } - read_console_output( screen_buffer, req->x, req->y, req->mode, req->wrap ); + read_console_output_req( screen_buffer, req->x, req->y, req->mode, req->wrap ); reply->width = screen_buffer->width; reply->height = screen_buffer->height; release_object( screen_buffer ); diff --git a/server/trace.c b/server/trace.c index 7cff5bf5f4..ab5a40bef8 100644 --- a/server/trace.c +++ b/server/trace.c @@ -124,6 +124,7 @@ static void dump_ioctl_code( const char *prefix, const ioctl_code_t *code ) CASE(IOCTL_CONDRV_GET_TITLE); CASE(IOCTL_CONDRV_PEEK); CASE(IOCTL_CONDRV_READ_INPUT); + CASE(IOCTL_CONDRV_READ_OUTPUT); CASE(IOCTL_CONDRV_SET_MODE); CASE(IOCTL_CONDRV_SET_OUTPUT_INFO); CASE(IOCTL_CONDRV_WRITE_INPUT);