* fhandler_console.cc (write_console): Check for VT100

graphics mode and transform wide characters in ASCII small
	letter range to corresponding graphics.
	(__vt100_conv): Table to transform small ASCII letters to line
	drawing graphics for use in VT100 graphics mode.
	(write_normal): Check for SO/SI control characters to
	enable/disable VT100 graphics mode.
	(base_chars): Enable SO/SI control characters for detection.
	(write): Check for ESC ( 0 / ESC ( B escape sequences to
	enable/disable VT100 graphics mode. Also detect ">" while
	parsing ESC [ sequences to distinguish specific requests.
	(char_command): Distinguish Secondary from Primary Device Attribute
	request to report more details about cygwin console terminal version.
	* fhandler.h (vt100_graphics_mode_active): New flag to indicate mode.
	(saw_greater_than_sign): New parse flag for ESC [ > sequences.
	(gotparen, gotrparen): New state values to parse ESC ( / ) sequences.

	* fhandler_console.cc (read): Allow combined Alt-AltGr modifiers
	to also produce an ESC prefix like a plain Alt modifier, e.g. to make
	Alt-@ work on a keyboard where @ is AltGr-q.
This commit is contained in:
Corinna Vinschen 2009-12-19 15:37:10 +00:00
parent d954168ddb
commit 8fd4bd2bf1
3 changed files with 127 additions and 11 deletions

View File

@ -1,3 +1,26 @@
2009-12-19 Thomas Wolff <towo@towo.net>
* fhandler_console.cc (write_console): Check for VT100
graphics mode and transform wide characters in ASCII small
letter range to corresponding graphics.
(__vt100_conv): Table to transform small ASCII letters to line
drawing graphics for use in VT100 graphics mode.
(write_normal): Check for SO/SI control characters to
enable/disable VT100 graphics mode.
(base_chars): Enable SO/SI control characters for detection.
(write): Check for ESC ( 0 / ESC ( B escape sequences to
enable/disable VT100 graphics mode. Also detect ">" while
parsing ESC [ sequences to distinguish specific requests.
(char_command): Distinguish Secondary from Primary Device Attribute
request to report more details about cygwin console terminal version.
* fhandler.h (vt100_graphics_mode_active): New flag to indicate mode.
(saw_greater_than_sign): New parse flag for ESC [ > sequences.
(gotparen, gotrparen): New state values to parse ESC ( / ) sequences.
* fhandler_console.cc (read): Allow combined Alt-AltGr modifiers
to also produce an ESC prefix like a plain Alt modifier, e.g. to make
Alt-@ work on a keyboard where @ is AltGr-q.
2009-12-18 Eric Blake <ebb9@byu.net> 2009-12-18 Eric Blake <ebb9@byu.net>
* signal.cc (nanosleep): Fix bug in previous patch. * signal.cc (nanosleep): Fix bug in previous patch.

View File

@ -889,6 +889,8 @@ enum ansi_intensity
#define gotcommand 5 #define gotcommand 5
#define gettitle 6 #define gettitle 6
#define eattitle 7 #define eattitle 7
#define gotparen 8
#define gotrparen 9
#define MAXARGS 10 #define MAXARGS 10
class dev_console class dev_console
@ -904,6 +906,8 @@ class dev_console
int nargs_; int nargs_;
unsigned rarg; unsigned rarg;
bool saw_question_mark; bool saw_question_mark;
bool saw_greater_than_sign;
bool vt100_graphics_mode_active;
bool alternate_charset_active; bool alternate_charset_active;
bool metabit; bool metabit;

View File

@ -405,9 +405,12 @@ fhandler_console::read (void *pv, size_t& buflen)
/* Determine if the keystroke is modified by META. The tricky /* Determine if the keystroke is modified by META. The tricky
part is to distinguish whether the right Alt key should be part is to distinguish whether the right Alt key should be
recognized as Alt, or as AltGr. */ recognized as Alt, or as AltGr. */
bool meta; bool meta =
meta = (control_key_state & ALT_PRESSED) != 0 /* Alt but not AltGr (= left ctrl + right alt)? */
(control_key_state & ALT_PRESSED) != 0
&& ((control_key_state & CTRL_PRESSED) == 0 && ((control_key_state & CTRL_PRESSED) == 0
/* but also allow Alt-AltGr: */
|| (control_key_state & ALT_PRESSED) == ALT_PRESSED
|| (wch <= 0x1f || wch == 0x7f)); || (wch <= 0x1f || wch == 0x7f));
if (!meta) if (!meta)
{ {
@ -1113,9 +1116,50 @@ fhandler_console::cursor_get (int *x, int *y)
*x = dev_state->info.dwCursorPosition.X; *x = dev_state->info.dwCursorPosition.X;
} }
static wchar_t __vt100_conv [31] = {
/* VT100 line drawing graphics mode maps `abcdefghijklmnopqrstuvwxyz{|}~ to
graphical characters */
0x25C6, /* Black Diamond */
0x2592, /* Medium Shade */
0x2409, /* Symbol for Horizontal Tabulation */
0x240C, /* Symbol for Form Feed */
0x240D, /* Symbol for Carriage Return */
0x240A, /* Symbol for Line Feed */
0x00B0, /* Degree Sign */
0x00B1, /* Plus-Minus Sign */
0x2424, /* Symbol for Newline */
0x240B, /* Symbol for Vertical Tabulation */
0x2518, /* Box Drawings Light Up And Left */
0x2510, /* Box Drawings Light Down And Left */
0x250C, /* Box Drawings Light Down And Right */
0x2514, /* Box Drawings Light Up And Right */
0x253C, /* Box Drawings Light Vertical And Horizontal */
0x23BA, /* Horizontal Scan Line-1 */
0x23BB, /* Horizontal Scan Line-3 */
0x2500, /* Box Drawings Light Horizontal */
0x23BC, /* Horizontal Scan Line-7 */
0x23BD, /* Horizontal Scan Line-9 */
0x251C, /* Box Drawings Light Vertical And Right */
0x2524, /* Box Drawings Light Vertical And Left */
0x2534, /* Box Drawings Light Up And Horizontal */
0x252C, /* Box Drawings Light Down And Horizontal */
0x2502, /* Box Drawings Light Vertical */
0x2264, /* Less-Than Or Equal To */
0x2265, /* Greater-Than Or Equal To */
0x03C0, /* Greek Small Letter Pi */
0x2260, /* Not Equal To */
0x00A3, /* Pound Sign */
0x00B7, /* Middle Dot */
};
inline inline
bool fhandler_console::write_console (PWCHAR buf, DWORD len, DWORD& done) bool fhandler_console::write_console (PWCHAR buf, DWORD len, DWORD& done)
{ {
if (dev_state->vt100_graphics_mode_active)
for (DWORD i = 0; i < len; i ++)
if (buf[i] >= (unsigned char) '`' && buf[i] <= (unsigned char) '~')
buf[i] = __vt100_conv[buf[i] - (unsigned char) '`'];
while (len > 0) while (len > 0)
{ {
DWORD nbytes = len > MAX_WRITE_CHARS ? MAX_WRITE_CHARS : len; DWORD nbytes = len > MAX_WRITE_CHARS ? MAX_WRITE_CHARS : len;
@ -1144,11 +1188,13 @@ bool fhandler_console::write_console (PWCHAR buf, DWORD len, DWORD& done)
#define TAB 8 /* We should't let the console deal with these */ #define TAB 8 /* We should't let the console deal with these */
#define CR 13 #define CR 13
#define LF 10 #define LF 10
#define SO 14
#define SI 15
static const char base_chars[256] = static const char base_chars[256] =
{ {
/*00 01 02 03 04 05 06 07 */ IGN, ERR, ERR, NOR, NOR, NOR, NOR, BEL, /*00 01 02 03 04 05 06 07 */ IGN, ERR, ERR, NOR, NOR, NOR, NOR, BEL,
/*08 09 0A 0B 0C 0D 0E 0F */ BAK, TAB, DWN, ERR, ERR, CR, ERR, IGN, /*08 09 0A 0B 0C 0D 0E 0F */ BAK, TAB, DWN, ERR, ERR, CR, SO, SI,
/*10 11 12 13 14 15 16 17 */ NOR, NOR, ERR, ERR, ERR, ERR, ERR, ERR, /*10 11 12 13 14 15 16 17 */ NOR, NOR, ERR, ERR, ERR, ERR, ERR, ERR,
/*18 19 1A 1B 1C 1D 1E 1F */ NOR, NOR, ERR, ESC, ERR, ERR, ERR, ERR, /*18 19 1A 1B 1C 1D 1E 1F */ NOR, NOR, ERR, ESC, ERR, ERR, ERR, ERR,
/* ! " # $ % & ' */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, /* ! " # $ % & ' */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
@ -1497,7 +1543,16 @@ fhandler_console::char_command (char c)
WriteFile (get_output_handle (), &dev_state->args_[0], 1, (DWORD *) &x, 0); WriteFile (get_output_handle (), &dev_state->args_[0], 1, (DWORD *) &x, 0);
break; break;
case 'c': /* u9 - Terminal enquire string */ case 'c': /* u9 - Terminal enquire string */
strcpy (buf, "\033[?6c"); if (dev_state->saw_greater_than_sign)
/* Generate Secondary Device Attribute report, using 67 = ASCII 'C'
to indicate Cygwin (convention used by Rxvt, Urxvt, Screen, Mintty),
and cygwin version for terminal version. */
__small_sprintf (buf, "\033[>67;%d%02d;0c", CYGWIN_VERSION_DLL_MAJOR, CYGWIN_VERSION_DLL_MINOR);
else
strcpy (buf, "\033[?6c");
/* The generated report needs to be injected for read-ahead into the
fhandler_console object associated with standard input.
The current call does not work. */
puts_readahead (buf); puts_readahead (buf);
break; break;
case 'n': case 'n':
@ -1673,6 +1728,12 @@ fhandler_console::write_normal (const unsigned char *src,
int x, y; int x, y;
switch (base_chars[*found]) switch (base_chars[*found])
{ {
case SO:
dev_state->vt100_graphics_mode_active = true;
break;
case SI:
dev_state->vt100_graphics_mode_active = false;
break;
case BEL: case BEL:
beep (); beep ();
break; break;
@ -1763,45 +1824,54 @@ fhandler_console::write (const void *vsrc, size_t len)
return -1; return -1;
break; break;
case gotesc: case gotesc:
if (*src == '[') if (*src == '[') /* CSI Control Sequence Introducer */
{ {
dev_state->state_ = gotsquare; dev_state->state_ = gotsquare;
dev_state->saw_question_mark = false; dev_state->saw_question_mark = false;
dev_state->saw_greater_than_sign = false;
for (dev_state->nargs_ = 0; dev_state->nargs_ < MAXARGS; dev_state->nargs_++) for (dev_state->nargs_ = 0; dev_state->nargs_ < MAXARGS; dev_state->nargs_++)
dev_state->args_[dev_state->nargs_] = 0; dev_state->args_[dev_state->nargs_] = 0;
dev_state->nargs_ = 0; dev_state->nargs_ = 0;
} }
else if (*src == ']') else if (*src == ']') /* OSC Operating System Command */
{ {
dev_state->rarg = 0; dev_state->rarg = 0;
dev_state->my_title_buf[0] = '\0'; dev_state->my_title_buf[0] = '\0';
dev_state->state_ = gotrsquare; dev_state->state_ = gotrsquare;
} }
else if (*src == 'M') /* Reverse Index */ else if (*src == '(') /* Designate G0 character set */
{
dev_state->state_ = gotparen;
}
else if (*src == ')') /* Designate G1 character set */
{
dev_state->state_ = gotrparen;
}
else if (*src == 'M') /* Reverse Index (scroll down) */
{ {
dev_state->fillin_info (get_output_handle ()); dev_state->fillin_info (get_output_handle ());
scroll_screen (0, 0, -1, -1, 0, dev_state->info.winTop + 1); scroll_screen (0, 0, -1, -1, 0, dev_state->info.winTop + 1);
dev_state->state_ = normal; dev_state->state_ = normal;
} }
else if (*src == 'c') /* Reset Linux terminal */ else if (*src == 'c') /* RIS Full Reset */
{ {
dev_state->set_default_attr (); dev_state->set_default_attr ();
clear_screen (0, 0, -1, -1); clear_screen (0, 0, -1, -1);
cursor_set (true, 0, 0); cursor_set (true, 0, 0);
dev_state->state_ = normal; dev_state->state_ = normal;
} }
else if (*src == '8') /* Restore cursor position */ else if (*src == '8') /* DECRC Restore cursor position */
{ {
cursor_set (true, dev_state->savex, dev_state->savey); cursor_set (true, dev_state->savex, dev_state->savey);
dev_state->state_ = normal; dev_state->state_ = normal;
} }
else if (*src == '7') /* Save cursor position */ else if (*src == '7') /* DECSC Save cursor position */
{ {
cursor_get (&dev_state->savex, &dev_state->savey); cursor_get (&dev_state->savex, &dev_state->savey);
dev_state->savey -= dev_state->info.winTop; dev_state->savey -= dev_state->info.winTop;
dev_state->state_ = normal; dev_state->state_ = normal;
} }
else if (*src == 'R') else if (*src == 'R') /* ? */
dev_state->state_ = normal; dev_state->state_ = normal;
else else
{ {
@ -1875,12 +1945,31 @@ fhandler_console::write (const void *vsrc, size_t len)
{ {
if (*src == '?') if (*src == '?')
dev_state->saw_question_mark = true; dev_state->saw_question_mark = true;
else if (*src == '>')
dev_state->saw_greater_than_sign = true;
/* ignore any extra chars between [ and first arg or command */ /* ignore any extra chars between [ and first arg or command */
src++; src++;
} }
else else
dev_state->state_ = gotarg1; dev_state->state_ = gotarg1;
break; break;
case gotparen:
if (*src == '0')
dev_state->vt100_graphics_mode_active = true;
else
dev_state->vt100_graphics_mode_active = false;
dev_state->state_ = normal;
src++;
break;
case gotrparen:
/* This is not strictly needed, ^N/^O can just always be enabled */
if (*src == '0')
/*dev_state->vt100_graphics_mode_SOSI_enabled = true*/;
else
/*dev_state->vt100_graphics_mode_SOSI_enabled = false*/;
dev_state->state_ = normal;
src++;
break;
} }
} }