Jacek Caban : server: Introduce IOCTL_CONDRV_WRITE_OUTPUT ioctl.

Alexandre Julliard julliard at winehq.org
Thu Jul 23 16:36:57 CDT 2020


Module: wine
Branch: master
Commit: 5b795b658d14bd85ba6783131c6f42a37cfcce27
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=5b795b658d14bd85ba6783131c6f42a37cfcce27

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Thu Jul 23 17:31:12 2020 +0200

server: Introduce IOCTL_CONDRV_WRITE_OUTPUT ioctl.

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 include/wine/condrv.h | 11 ++++++
 server/console.c      | 99 +++++++++++++++++++++++++++++++++++++++++++++++++--
 server/trace.c        |  1 +
 3 files changed, 108 insertions(+), 3 deletions(-)

diff --git a/include/wine/condrv.h b/include/wine/condrv.h
index 42ca77d382..add88d8885 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_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)
 #define IOCTL_CONDRV_ACTIVATE              CTL_CODE(FILE_DEVICE_CONSOLE, 34, METHOD_BUFFERED, FILE_WRITE_DATA)
@@ -82,6 +83,16 @@ struct condrv_input_info_params
     struct condrv_input_info info;    /* input_info */
 };
 
+/* IOCTL_CONDRV_WRITE_OUTPUT */
+struct condrv_write_output_params
+{
+    unsigned int  x;                  /* destination position */
+    unsigned int  y;
+    unsigned int  mode;               /* char info mode */
+    unsigned int  width;              /* width of output rectangle, 0 for wrapped mode */
+    /* followed by an array of data with type depending on mode */
+};
+
 /* IOCTL_CONDRV_GET_OUTPUT_INFO result */
 struct condrv_output_info
 {
diff --git a/server/console.c b/server/console.c
index 9f102968a1..9e61987e33 100644
--- a/server/console.c
+++ b/server/console.c
@@ -1249,7 +1249,85 @@ static struct fd *screen_buffer_get_fd( struct object *obj )
 }
 
 /* write data into a screen buffer */
-static int write_console_output( struct screen_buffer *screen_buffer, data_size_t size,
+static void write_console_output( struct screen_buffer *screen_buffer, const struct condrv_write_output_params *params,
+                                  data_size_t 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);
+    if (size % entry_size)
+    {
+        set_error( STATUS_INVALID_PARAMETER );
+        return;
+    }
+    if (params->x >= screen_buffer->width) return;
+    entry_cnt = size / entry_size;
+
+    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:
+            set_error( STATUS_INVALID_PARAMETER );
+            return;
+        }
+    }
+
+    if (i && screen_buffer == screen_buffer->input->active)
+    {
+        struct condrv_renderer_event evt;
+        evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
+        memset(&evt.u, 0, sizeof(evt.u));
+        evt.u.update.top    = params->y;
+        evt.u.update.bottom = params->width
+            ? min( params->y + entry_cnt / params->width, screen_buffer->height ) - 1
+            : params->y + (params->x + i - 1) / screen_buffer->width;
+        console_input_events_append( screen_buffer->input, &evt );
+    }
+
+    if (get_reply_max_size() == sizeof(SMALL_RECT))
+    {
+        SMALL_RECT region;
+        region.Left   = params->x;
+        region.Top    = params->y;
+        region.Right  = min( params->x + params->width, screen_buffer->width ) - 1;
+        region.Bottom = min( params->y + entry_cnt / params->width, screen_buffer->height ) - 1;
+        set_reply_data( &region, sizeof(region) );
+    }
+    else set_reply_data( &i, sizeof(i) );
+}
+
+/* write data into a screen buffer */
+static int write_console_output_req( struct screen_buffer *screen_buffer, data_size_t size,
                                  const void* data, enum char_info_mode mode,
                                  int x, int y, int wrap )
 {
@@ -1660,6 +1738,21 @@ 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_WRITE_OUTPUT:
+        if (get_req_data_size() < sizeof(struct condrv_write_output_params) ||
+            (get_reply_max_size() != sizeof(SMALL_RECT) && get_reply_max_size() != sizeof(unsigned int)))
+        {
+            set_error( STATUS_INVALID_PARAMETER );
+            return 0;
+        }
+        if (console_input_is_bare( screen_buffer->input ))
+        {
+            set_error( STATUS_OBJECT_TYPE_MISMATCH );
+            return 0;
+        }
+        write_console_output( screen_buffer, get_req_data(), get_req_data_size() - sizeof(struct condrv_write_output_params) );
+        return !get_error();
+
     case IOCTL_CONDRV_GET_OUTPUT_INFO:
         {
             struct condrv_output_info *info;
@@ -2140,8 +2233,8 @@ DECL_HANDLER(write_console_output)
             release_object( screen_buffer );
             return;
         }
-        reply->written = write_console_output( screen_buffer, get_req_data_size(), get_req_data(),
-                                               req->mode, req->x, req->y, req->wrap );
+        reply->written = write_console_output_req( screen_buffer, get_req_data_size(), get_req_data(),
+                                                   req->mode, req->x, req->y, 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 21468abd73..16bcc616a5 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -127,6 +127,7 @@ static void dump_ioctl_code( const char *prefix, const ioctl_code_t *code )
         CASE(IOCTL_CONDRV_SET_MODE);
         CASE(IOCTL_CONDRV_SET_OUTPUT_INFO);
         CASE(IOCTL_CONDRV_WRITE_INPUT);
+        CASE(IOCTL_CONDRV_WRITE_OUTPUT);
         CASE(FSCTL_DISMOUNT_VOLUME);
         CASE(FSCTL_PIPE_DISCONNECT);
         CASE(FSCTL_PIPE_LISTEN);




More information about the wine-cvs mailing list