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