[PATCH v3 0/4] MR9973: Draft: conhost: add basic VT control sequence
This is a minimal approach to running MC in wineconsole and addresses https://bugs.winehq.org/show_bug.cgi?id=49780. Wineconsole thus supports basic CSI control sequences for: - SGR (Select Graphic Rendition) and - CUP (Cursor Position) {width=900 height=507} -- v3: conhost: add basic CUP color handling conhost: improve basic SGR color handling conhost: add basic SGR color handling conhost: add basic VT control sequence parsing https://gitlab.winehq.org/wine/wine/-/merge_requests/9973
From: Thomas Csovcsity <thc.fr13nd@gmail.com> Remove Control Sequence Introducer(CSI) commands avoids console scrambling --- programs/conhost/conhost.c | 50 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/programs/conhost/conhost.c b/programs/conhost/conhost.c index 8298743553f..ed7eb9c34ee 100644 --- a/programs/conhost/conhost.c +++ b/programs/conhost/conhost.c @@ -2107,6 +2107,9 @@ static NTSTATUS write_console( struct screen_buffer *screen_buffer, const WCHAR { RECT update_rect; size_t i, j; + enum { + ST_START, ST_PARAM, ST_INTER, ST_FINAL + } state; TRACE( "%s\n", debugstr_wn(buffer, len) ); @@ -2143,6 +2146,53 @@ static NTSTATUS write_console( struct screen_buffer *screen_buffer, const WCHAR case '\r': screen_buffer->cursor_x = 0; continue; + case '\e': + if (buffer[i+1] == '[') + { + FIXME( "CSI sequences not supported fully yet, only skipping control sequences\n" ); + state = ST_PARAM; + i+=2; + } + else + { + ERR("Invalid CSI start sequence\n"); + break; + } + /* intermediate bytes 0x30 - 0x3f (0-?) */ + for (; i<len && (state == ST_PARAM); i++) + { + if (buffer[i] >= 0x30 && buffer[i] <= 0x3b) + continue; + else if (buffer[i] >= 0x3c && buffer[i] <= 0x3f) + { + WARN( "This is a private -terminal manufacturer only- CSI sequence\n" ); + continue; + } + else + { + state = ST_INTER; + break; + } + } + /* intermediate bytes 0x20 - 0x2f*/ + for (; i<len && (state == ST_INTER || state == ST_PARAM); i++) + { + if (buffer[i] >= 0x20 && buffer[i] <= 0x2f) + continue; + else + { + state = ST_FINAL; + break; + } + } + if (state == ST_START || state == ST_FINAL) + { + if (buffer[i] >= 0x70 && buffer[i] <= 0x7e) + WARN("This is a private -terminal manufacturer only- CSI sequence\n"); + else if (!(buffer[i] >= 0x40 && buffer[i] <= 0x6f)) + ERR("This was no valid CSI sequence\n"); + } + continue; } } if (screen_buffer->cursor_x == screen_buffer->width && !(screen_buffer->mode & ENABLE_WRAP_AT_EOL_OUTPUT)) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9973
From: Thomas Csovcsity <thc.fr13nd@gmail.com> --- programs/conhost/conhost.c | 188 ++++++++++++++++++++++++++++++++++++- 1 file changed, 185 insertions(+), 3 deletions(-) diff --git a/programs/conhost/conhost.c b/programs/conhost/conhost.c index ed7eb9c34ee..d8256542643 100644 --- a/programs/conhost/conhost.c +++ b/programs/conhost/conhost.c @@ -2103,13 +2103,186 @@ static NTSTATUS set_output_info( struct screen_buffer *screen_buffer, return STATUS_SUCCESS; } +#define BLACK 0x0000 +#define BLUE 0x0001 +#define GREEN 0x0002 +#define CYAN BLUE | GREEN +#define RED 0x0004 +#define MAGENTA BLUE | RED +#define YELLOW GREEN | RED +#define WHITE BLUE | GREEN | RED + +static unsigned int next_csi_sgr_argument( const WCHAR *seq, unsigned int len, unsigned int *arg ) +{ + unsigned int i=0, value = 0; + TRACE( "next SGR arg with %d length and [%s] as sequence! seq_p %p\n",len, debugstr_wn( seq, len ), seq ); + for (i=0; i<len; i++) + { + if ((seq[i] == ';') || (seq[i]=='m')) + { + *arg = value; + return i+1; + } + value = 10 * value + seq[i]-'0'; + } + return 0; +} + +static void process_csi_sequence_console( struct screen_buffer *screen_buffer, const WCHAR *seq, size_t len ) +{ + unsigned int colors[] = {BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE}; + unsigned int value = 0, *arg = &value; + size_t seq_len = 0; + unsigned int r = 0, g = 0, b = 0; + struct condrv_output_info_params info_params; + + switch (seq[len-1]) + { + case 'm': /* Select Graphic Rendition (SGR) */ + while (len > 0) + { + TRACE( "This is an SGR seq with %Iu length and [%s] as payload! seq_p %p\n",len, debugstr_wn( seq, len ), seq ); + seq_len = next_csi_sgr_argument(seq, len, arg); + switch (value) + { + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + { + len -= seq_len; + seq += seq_len; + info_params.info.attr = ( info_params.info.attr & 0xf0 ) | colors[*arg-30]; + break; + } + case 38: + { + len -= seq_len; + seq += seq_len; + seq_len = next_csi_sgr_argument( seq, len, arg ); + if (*arg == 2) + { + len -= seq_len; + seq += seq_len; + seq_len = next_csi_sgr_argument(seq, len, &r); + len -= seq_len; + seq += seq_len; + seq_len = next_csi_sgr_argument(seq, len, &g); + len -= seq_len; + seq += seq_len; + seq_len = next_csi_sgr_argument(seq, len, &b); + len -= seq_len; + seq += seq_len; + FIXME( "24bit rgb is not supported yet for foreground r[%d]g[%d]b[%d]\n", r, g, b ); + info_params.info.attr = ( BLACK < 8 ) | ( WHITE ); /* Fixme set correct color */ + } + if (*arg == 5) + { + len -= seq_len; + seq += seq_len; + seq_len = next_csi_sgr_argument( seq, len, arg ); + len -= seq_len; + seq += seq_len; + info_params.info.attr = ( info_params.info.attr & 0xf0 ) | colors[*arg]; + } + break; + } + case 39: + { + len -= seq_len; + seq += seq_len; + info_params.info.attr = ( info_params.info.attr & 0xf0 ) | ( WHITE ); /* default white fg */ + break; + } + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + { + len -= seq_len; + seq += seq_len; + info_params.info.attr = ( info_params.info.attr & 0x0f ) | ( colors[*arg-40] << 4 ); + break; + } + case 48: + { + len -= seq_len; + seq += seq_len; + seq_len = next_csi_sgr_argument( seq, len, arg ); + if (*arg == 2) + { + len -= seq_len; + seq += seq_len; + seq_len = next_csi_sgr_argument( seq, len, &r ); + len -= seq_len; + seq += seq_len; + seq_len = next_csi_sgr_argument( seq, len, &g ); + len -= seq_len; + seq += seq_len; + seq_len = next_csi_sgr_argument( seq, len, &b ); + len -= seq_len; + seq += seq_len; + FIXME( "24bit rgb is not supported yet for background r[%d]g[%d]b[%d]\n", r, g, b ); + info_params.info.attr = ( BLACK < 4 ) | ( WHITE ); /* Fixme set correct color */ + } + if (*arg == 5) + { + len -= seq_len; + seq += seq_len; + seq_len = next_csi_sgr_argument( seq, len, arg ); + len -= seq_len; + seq += seq_len; + info_params.info.attr = ( info_params.info.attr & 0xf0 ) | colors[*arg]; + } + break; + } + case 49: + { + len -= seq_len; + seq += seq_len; + info_params.info.attr = ( info_params.info.attr & 0x000f ) | ( BLACK < 4 ); /* default black bg */ + break; + } + case 0: + { + len -= seq_len; + seq += seq_len; + info_params.info.attr = ( BLACK < 4 ) | ( WHITE ); /* white on black */ + break; + } + default: + FIXME( "unhandled sgr sequence %s len[%Iu]\n", debugstr_wn( seq, len ), len ); + info_params.info.attr = ( BLACK < 4 ) | ( WHITE ); /* white on black */ + len = 0; + break; + + } + info_params.mask = SET_CONSOLE_OUTPUT_INFO_ATTR; + set_output_info( screen_buffer, &info_params, sizeof(info_params) ); + } + break; + default: + FIXME( "unhandled sequence %s switch char [%s] len[%Iu]\n", debugstr_wn( seq, len ), debugstr_wn( &seq[len], 1 ), len ); + break; + } +} + static NTSTATUS write_console( struct screen_buffer *screen_buffer, const WCHAR *buffer, size_t len ) { RECT update_rect; - size_t i, j; + size_t csi_len = 0, i, j; enum { ST_START, ST_PARAM, ST_INTER, ST_FINAL } state; + const WCHAR *csi_start; TRACE( "%s\n", debugstr_wn(buffer, len) ); @@ -2149,18 +2322,21 @@ static NTSTATUS write_console( struct screen_buffer *screen_buffer, const WCHAR case '\e': if (buffer[i+1] == '[') { - FIXME( "CSI sequences not supported fully yet, only skipping control sequences\n" ); state = ST_PARAM; + csi_start = &buffer[i+2]; + csi_len = 0; i+=2; } else { - ERR("Invalid CSI start sequence\n"); + ERR( "Invalid CSI start sequence\n" ); + ERR( "%s\n", debugstr_wn(buffer, len) ); break; } /* intermediate bytes 0x30 - 0x3f (0-?) */ for (; i<len && (state == ST_PARAM); i++) { + csi_len++; if (buffer[i] >= 0x30 && buffer[i] <= 0x3b) continue; else if (buffer[i] >= 0x3c && buffer[i] <= 0x3f) @@ -2171,17 +2347,20 @@ static NTSTATUS write_console( struct screen_buffer *screen_buffer, const WCHAR else { state = ST_INTER; + csi_len--; break; } } /* intermediate bytes 0x20 - 0x2f*/ for (; i<len && (state == ST_INTER || state == ST_PARAM); i++) { + csi_len++; if (buffer[i] >= 0x20 && buffer[i] <= 0x2f) continue; else { state = ST_FINAL; + csi_len--; break; } } @@ -2191,6 +2370,9 @@ static NTSTATUS write_console( struct screen_buffer *screen_buffer, const WCHAR WARN("This is a private -terminal manufacturer only- CSI sequence\n"); else if (!(buffer[i] >= 0x40 && buffer[i] <= 0x6f)) ERR("This was no valid CSI sequence\n"); + + csi_len++; + process_csi_sequence_console(screen_buffer, csi_start, csi_len); } continue; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9973
From: Thomas Csovcsity <thc.fr13nd@gmail.com> add simple RGB24 to 3bit RGB --- programs/conhost/conhost.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/programs/conhost/conhost.c b/programs/conhost/conhost.c index d8256542643..41c2f158a32 100644 --- a/programs/conhost/conhost.c +++ b/programs/conhost/conhost.c @@ -2166,6 +2166,7 @@ static void process_csi_sequence_console( struct screen_buffer *screen_buffer, c seq_len = next_csi_sgr_argument( seq, len, arg ); if (*arg == 2) { + int color = BLACK; len -= seq_len; seq += seq_len; seq_len = next_csi_sgr_argument(seq, len, &r); @@ -2177,8 +2178,14 @@ static void process_csi_sequence_console( struct screen_buffer *screen_buffer, c seq_len = next_csi_sgr_argument(seq, len, &b); len -= seq_len; seq += seq_len; - FIXME( "24bit rgb is not supported yet for foreground r[%d]g[%d]b[%d]\n", r, g, b ); - info_params.info.attr = ( BLACK < 8 ) | ( WHITE ); /* Fixme set correct color */ + /* a simple color mapping for basic support */ + if ( r > 127 ) + color |= RED; + if ( g > 127 ) + color |= GREEN; + if ( b > 127 ) + color |= BLUE; + info_params.info.attr = ( info_params.info.attr & 0xf0 ) | color; } if (*arg == 5) { @@ -2219,6 +2226,7 @@ static void process_csi_sequence_console( struct screen_buffer *screen_buffer, c seq_len = next_csi_sgr_argument( seq, len, arg ); if (*arg == 2) { + int color = BLACK; len -= seq_len; seq += seq_len; seq_len = next_csi_sgr_argument( seq, len, &r ); @@ -2230,8 +2238,15 @@ static void process_csi_sequence_console( struct screen_buffer *screen_buffer, c seq_len = next_csi_sgr_argument( seq, len, &b ); len -= seq_len; seq += seq_len; - FIXME( "24bit rgb is not supported yet for background r[%d]g[%d]b[%d]\n", r, g, b ); - info_params.info.attr = ( BLACK < 4 ) | ( WHITE ); /* Fixme set correct color */ + /* a simple color mapping for basic support */ + if ( r > 127 ) + color |= RED; + if ( g > 127 ) + color |= GREEN; + if ( b > 127 ) + color |= BLUE; + info_params.info.attr = ( info_params.info.attr & 0x0f ) | ( color << 4 ); + } if (*arg == 5) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9973
From: Thomas Csovcsity <thc.fr13nd@gmail.com> --- programs/conhost/conhost.c | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/programs/conhost/conhost.c b/programs/conhost/conhost.c index 41c2f158a32..2e7fe68f24e 100644 --- a/programs/conhost/conhost.c +++ b/programs/conhost/conhost.c @@ -2284,6 +2284,46 @@ static void process_csi_sequence_console( struct screen_buffer *screen_buffer, c set_output_info( screen_buffer, &info_params, sizeof(info_params) ); } break; + case 'H': + unsigned int x = 0, y = 0, value = 0, i; + TRACE( "This is an CUP seq with %Iu length and [%s] as payload! seq_p %p\n",len, debugstr_wn( seq, len ), seq ); + + for (i = 0; i < len; i++) + { + if (seq[i] != ';' && seq[i] != 'H') + value = 10 * value + seq[i] - '0'; + else if (seq[i] == ';') + { + if (value != 0) + { + y = value; + value = 0; + } + else + y = 1; + } + else if (seq[i] == 'H') + { + if (y == 0 && value == 0) + { + x = 1; + y = 1; + } else if (y == 0 && value != 0) + { + y = value; + x = 1; + } else /* (y != 0 && value != 0) */ + x = value; + } + else + { + ERR( "CSI CUP parsing failed, this should not happen!\n" ); + break; + } + } + screen_buffer->cursor_x = x-1; + screen_buffer->cursor_y = y-1; + break; default: FIXME( "unhandled sequence %s switch char [%s] len[%Iu]\n", debugstr_wn( seq, len ), debugstr_wn( &seq[len], 1 ), len ); break; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9973
participants (2)
-
Thomas Csovcsity -
Thomas Csovcsity (@thc13)