From: Thomas Csovcsity <thc.fr13nd@gmail.com> --- programs/conhost/conhost.c | 171 ++++++++++++++++++++++++++++++++++++- 1 file changed, 168 insertions(+), 3 deletions(-) diff --git a/programs/conhost/conhost.c b/programs/conhost/conhost.c index 6bf81f97407..2d4c7f1c011 100644 --- a/programs/conhost/conhost.c +++ b/programs/conhost/conhost.c @@ -2103,6 +2103,163 @@ 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, size_t len, unsigned int *arg) +{ + unsigned int i=0, value = 0; + TRACE("next SGR arg with %lld 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 i; +} + +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 seq_len = 0, value = 0, *arg = &value; + 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 %lld 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 ... 37: + { + len -= seq_len; + seq += seq_len; + info_params.info.attr = ( info_params.info.attr & 0xff00 ) | 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 & 0xff00 ) | 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 ... 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[%lld]\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[%lld]\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; @@ -2110,6 +2267,8 @@ static NTSTATUS write_console( struct screen_buffer *screen_buffer, const WCHAR enum { ST_START, ST_PARAM, ST_INTER, ST_FINAL } state; + const WCHAR *csi_start; + size_t csi_len = 0; TRACE( "%s\n", debugstr_wn(buffer, len) ); @@ -2149,8 +2308,9 @@ 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 @@ -2161,6 +2321,7 @@ static NTSTATUS write_console( struct screen_buffer *screen_buffer, const WCHAR /* intermediate bytes 0x30 - 0x3f (0-?) */ for (; i<len && (state == ST_PARAM); i++) { + csi_len++; switch (buffer[i]) { case 0x30 ... 0x3b: @@ -2170,6 +2331,7 @@ static NTSTATUS write_console( struct screen_buffer *screen_buffer, const WCHAR continue; default: state = ST_INTER; + csi_len--; break; } break; @@ -2177,12 +2339,14 @@ static NTSTATUS write_console( struct screen_buffer *screen_buffer, const WCHAR /* intermediate bytes 0x20 - 0x2f*/ for (; i<len && (state == ST_INTER || state == ST_PARAM); i++) { + csi_len++; switch (buffer[i]) { case 0x20 ... 0x2f: continue; default: state = ST_FINAL; + csi_len--; break; } break; @@ -2200,9 +2364,10 @@ static NTSTATUS write_console( struct screen_buffer *screen_buffer, const WCHAR ERR("This was no valid CSI sequence\n"); break; } - i++; - break; + csi_len++; + process_csi_sequence_console(screen_buffer, csi_start, csi_len); } + 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