Jacek Caban : conhost: Introduce IOCTL_CONDRV_WRITE_CONSOLE ioctl.

Alexandre Julliard julliard at winehq.org
Fri Sep 11 14:51:45 CDT 2020


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

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Fri Sep 11 14:30:50 2020 +0200

conhost: Introduce IOCTL_CONDRV_WRITE_CONSOLE ioctl.

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

---

 include/wine/condrv.h      |  15 +++---
 programs/conhost/conhost.c | 113 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 120 insertions(+), 8 deletions(-)

diff --git a/include/wine/condrv.h b/include/wine/condrv.h
index 7bc5e7f15b..4f92e2e096 100644
--- a/include/wine/condrv.h
+++ b/include/wine/condrv.h
@@ -39,13 +39,14 @@
 #define IOCTL_CONDRV_CTRL_EVENT            CTL_CODE(FILE_DEVICE_CONSOLE, 17, METHOD_BUFFERED, FILE_WRITE_ACCESS)
 
 /* console output ioctls */
-#define IOCTL_CONDRV_READ_OUTPUT           CTL_CODE(FILE_DEVICE_CONSOLE, 30, METHOD_BUFFERED, FILE_READ_ACCESS)
-#define IOCTL_CONDRV_WRITE_OUTPUT          CTL_CODE(FILE_DEVICE_CONSOLE, 31, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_CONDRV_GET_OUTPUT_INFO       CTL_CODE(FILE_DEVICE_CONSOLE, 32, METHOD_BUFFERED, FILE_READ_ACCESS)
-#define IOCTL_CONDRV_SET_OUTPUT_INFO       CTL_CODE(FILE_DEVICE_CONSOLE, 33, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_CONDRV_ACTIVATE              CTL_CODE(FILE_DEVICE_CONSOLE, 34, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_CONDRV_FILL_OUTPUT           CTL_CODE(FILE_DEVICE_CONSOLE, 35, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_CONDRV_SCROLL                CTL_CODE(FILE_DEVICE_CONSOLE, 36, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+#define IOCTL_CONDRV_WRITE_CONSOLE         CTL_CODE(FILE_DEVICE_CONSOLE, 30, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+#define IOCTL_CONDRV_READ_OUTPUT           CTL_CODE(FILE_DEVICE_CONSOLE, 31, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CONDRV_WRITE_OUTPUT          CTL_CODE(FILE_DEVICE_CONSOLE, 32, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+#define IOCTL_CONDRV_GET_OUTPUT_INFO       CTL_CODE(FILE_DEVICE_CONSOLE, 33, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CONDRV_SET_OUTPUT_INFO       CTL_CODE(FILE_DEVICE_CONSOLE, 34, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+#define IOCTL_CONDRV_ACTIVATE              CTL_CODE(FILE_DEVICE_CONSOLE, 35, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+#define IOCTL_CONDRV_FILL_OUTPUT           CTL_CODE(FILE_DEVICE_CONSOLE, 36, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+#define IOCTL_CONDRV_SCROLL                CTL_CODE(FILE_DEVICE_CONSOLE, 37, METHOD_BUFFERED, FILE_WRITE_ACCESS)
 
 /* console renderer ioctls */
 #define IOCTL_CONDRV_GET_RENDERER_EVENTS   CTL_CODE(FILE_DEVICE_CONSOLE, 70, METHOD_BUFFERED, FILE_READ_ACCESS)
diff --git a/programs/conhost/conhost.c b/programs/conhost/conhost.c
index 84a1c8ac7d..94a150205e 100644
--- a/programs/conhost/conhost.c
+++ b/programs/conhost/conhost.c
@@ -337,13 +337,19 @@ static void init_tty_output( struct console *console )
     console->tty_cursor_visible = TRUE;
 }
 
-static void update_output( struct screen_buffer *screen_buffer, const RECT *rect )
+static void empty_update_rect( struct screen_buffer *screen_buffer, RECT *rect )
+{
+    SetRect( rect, screen_buffer->width, screen_buffer->height, 0, 0 );
+}
+
+static void update_output( struct screen_buffer *screen_buffer, RECT *rect )
 {
     int x, y, size, trailing_spaces;
     char_info_t *ch;
     char buf[8];
 
     if (!is_active( screen_buffer ) || !screen_buffer->console->tty_output) return;
+    if (rect->top > rect->bottom || rect->right < rect->left) return;
     TRACE( "%s\n", wine_dbgstr_rect( rect ));
 
     hide_tty_cursor( screen_buffer->console );
@@ -374,6 +380,54 @@ static void update_output( struct screen_buffer *screen_buffer, const RECT *rect
             screen_buffer->console->tty_cursor_x++;
         }
     }
+
+    empty_update_rect( screen_buffer, rect );
+}
+
+static void new_line( struct screen_buffer *screen_buffer, RECT *update_rect )
+{
+    unsigned int i;
+
+    assert( screen_buffer->cursor_y == screen_buffer->height );
+    screen_buffer->cursor_y--;
+
+    if (screen_buffer->console->tty_output)
+        update_output( screen_buffer, update_rect );
+    else
+        SetRect( update_rect, 0, 0, screen_buffer->width - 1, screen_buffer->height - 1 );
+
+    memmove( screen_buffer->data, screen_buffer->data + screen_buffer->width,
+             screen_buffer->width * (screen_buffer->height - 1) * sizeof(*screen_buffer->data) );
+    for (i = 0; i < screen_buffer->width; i++)
+        screen_buffer->data[screen_buffer->width * (screen_buffer->height - 1) + i] = empty_char_info;
+    if (is_active( screen_buffer ))
+    {
+        screen_buffer->console->tty_cursor_y--;
+        if (screen_buffer->console->tty_cursor_y != screen_buffer->height - 2)
+            set_tty_cursor( screen_buffer->console, 0, screen_buffer->height - 2 );
+        set_tty_cursor( screen_buffer->console, 0, screen_buffer->height - 1 );
+    }
+}
+
+static void write_char( struct screen_buffer *screen_buffer, WCHAR ch, RECT *update_rect )
+{
+    if (screen_buffer->cursor_x == screen_buffer->width)
+    {
+        screen_buffer->cursor_x = 0;
+        screen_buffer->cursor_y++;
+    }
+    if (screen_buffer->cursor_y == screen_buffer->height)
+    {
+        new_line( screen_buffer, update_rect );
+    }
+
+    screen_buffer->data[screen_buffer->cursor_y * screen_buffer->width + screen_buffer->cursor_x].ch = ch;
+    screen_buffer->data[screen_buffer->cursor_y * screen_buffer->width + screen_buffer->cursor_x].attr = screen_buffer->attr;
+    update_rect->left   = min( update_rect->left,   screen_buffer->cursor_x );
+    update_rect->top    = min( update_rect->top,    screen_buffer->cursor_y );
+    update_rect->right  = max( update_rect->right,  screen_buffer->cursor_x );
+    update_rect->bottom = max( update_rect->bottom, screen_buffer->cursor_y );
+    screen_buffer->cursor_x++;
 }
 
 static NTSTATUS read_console_input( struct console *console, size_t out_size )
@@ -923,6 +977,59 @@ static NTSTATUS set_output_info( struct screen_buffer *screen_buffer,
     return STATUS_SUCCESS;
 }
 
+static NTSTATUS write_console( struct screen_buffer *screen_buffer, const WCHAR *buffer, size_t len )
+{
+    RECT update_rect;
+    size_t i, j;
+
+    TRACE( "%s\n", debugstr_wn(buffer, len) );
+
+    empty_update_rect( screen_buffer, &update_rect );
+
+    for (i = 0; i < len; i++)
+    {
+        if (screen_buffer->mode & ENABLE_PROCESSED_OUTPUT)
+        {
+            switch (buffer[i])
+            {
+            case '\b':
+                if (screen_buffer->cursor_x) screen_buffer->cursor_x--;
+                continue;
+            case '\t':
+                j = min( screen_buffer->width - screen_buffer->cursor_x, 8 - (screen_buffer->cursor_x % 8) );
+                while (j--) write_char( screen_buffer, ' ', &update_rect );
+                continue;
+            case '\n':
+                screen_buffer->cursor_x = 0;
+                if (++screen_buffer->cursor_y == screen_buffer->height)
+                    new_line( screen_buffer, &update_rect );
+                else if (screen_buffer->mode & ENABLE_WRAP_AT_EOL_OUTPUT)
+                    update_output( screen_buffer, &update_rect );
+                continue;
+            case '\a':
+                FIXME( "beep\n" );
+                continue;
+            case '\r':
+                screen_buffer->cursor_x = 0;
+                continue;
+            }
+        }
+        if (screen_buffer->cursor_x == screen_buffer->width && !(screen_buffer->mode & ENABLE_WRAP_AT_EOL_OUTPUT))
+            screen_buffer->cursor_x = update_rect.left;
+        write_char( screen_buffer, buffer[i], &update_rect );
+    }
+
+    if (screen_buffer->cursor_x == screen_buffer->width)
+    {
+        if (screen_buffer->mode & ENABLE_WRAP_AT_EOL_OUTPUT) screen_buffer->cursor_x--;
+        else screen_buffer->cursor_x = update_rect.left;
+    }
+
+    update_output( screen_buffer, &update_rect );
+    tty_sync( screen_buffer->console );
+    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 )
 {
@@ -1328,6 +1435,10 @@ 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_CONSOLE:
+        if (in_size % sizeof(WCHAR) || *out_size) return STATUS_INVALID_PARAMETER;
+        return write_console( screen_buffer, in_data, in_size / sizeof(WCHAR) );
+
     case IOCTL_CONDRV_WRITE_OUTPUT:
         if ((*out_size != sizeof(DWORD) && *out_size != sizeof(SMALL_RECT)) ||
             in_size < sizeof(struct condrv_output_params))




More information about the wine-cvs mailing list