1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 09:27:59 +00:00

Centralise key escape sequences into terminal.c.

A long time ago, in commit 4d77b6567, I moved the generation of the
arrow-key escape sequences into a function format_arrow_key(). Mostly
the reason for that was a special purpose I had in mind at the time
which involved auto-generating the same sequences in response to
things other than a keypress, but I always thought it would be nice to
centralise a lot more of PuTTY's complicated keyboard handling in the
same way - at least the handling of the function keys and their
numerous static and dynamic config options.

In this year's general spirit of tidying up and refactoring, I think
it's finally time. So here I introduce three more centralised
functions for dealing with the numbered function keys, the small
keypad (Ins, Home, PgUp etc) and the numeric keypad. Lots of horrible
and duplicated code from the key handling functions in window.c and
gtkwin.c is now more sensibly centralised: each platform keyboard
handler concerns itself with the local format of a keyboard event and
platform-specific enumeration of key codes, and once it's decided what
the logical key press actually _is_, it hands off to the new functions
in terminal.c to generate the appropriate escape code.

Mostly this is intended to be a refactoring without functional change,
leaving the keyboard handling how it's always been. But in cases where
the Windows and GTK handlers were accidentally inconsistent, I've
fixed the inconsistency rather than carefully keeping both sides how
they were. Known consistency fixes:

 - swapping the arrow keys between normal (ESC [ A) and application
   (ESC O A) is now done by pressing Ctrl with them, and _not_ by
   pressing Shift. That was how it was always supposed to work, and
   how it's worked on GTK all along, but on Windows it's been done by
   Shift as well since 2010, due to a bug at the call site of
   format_arrow_key() introduced when I originally wrote that function.

 - in Xterm function key mode plus application keypad mode, the /*-
   keys on the numeric keypad now send ESC O {o,j,m} in place of ESC O
   {Q,R,S}. That's how the Windows keyboard handler has worked all
   along (it was a deliberate behaviour tweak for the Xterm-like
   function key mode, because in that mode ESC O {Q,R,S} are generated
   by F2-F4). But the GTK keyboard handler omitted that particular
   special case and was still sending ESC O {Q,R,S} for those keys in
   all application keypad modes.

 - also in Xterm function key mode plus app keypad mode, we only
   generates the app-keypad escape sequences if Num Lock is on; with
   Num Lock off, the numeric keypad becomes arrow keys and
   Home/End/etc, just as it would in non-app-keypad mode. Windows has
   done this all along, but again, GTK lacked that special case.
This commit is contained in:
Simon Tatham 2018-12-08 08:25:32 +00:00
parent 50b9448450
commit 41e1a586fb
4 changed files with 405 additions and 714 deletions

View File

@ -1533,7 +1533,15 @@ void term_set_focus(Terminal *term, bool has_focus);
char *term_get_ttymode(Terminal *term, const char *mode);
int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input);
typedef enum SmallKeypadKey {
SKK_HOME, SKK_END, SKK_INSERT, SKK_DELETE, SKK_PGUP, SKK_PGDN,
} SmallKeypadKey;
int format_arrow_key(char *buf, Terminal *term, int xkey, bool ctrl);
int format_function_key(char *buf, Terminal *term, int key_number,
bool shift, bool ctrl);
int format_small_keypad_key(char *buf, Terminal *term, SmallKeypadKey key);
int format_numeric_keypad_key(char *buf, Terminal *term, char key,
bool shift, bool ctrl);
/*
* Exports from logging.c.

View File

@ -6447,7 +6447,7 @@ int format_arrow_key(char *buf, Terminal *term, int xkey, bool ctrl)
char *p = buf;
if (term->vt52_mode)
p += sprintf((char *) p, "\x1B%c", xkey);
p += sprintf(p, "\x1B%c", xkey);
else {
bool app_flg = (term->app_cursor_keys && !term->no_applic_c);
#if 0
@ -6470,9 +6470,186 @@ int format_arrow_key(char *buf, Terminal *term, int xkey, bool ctrl)
app_flg = !app_flg;
if (app_flg)
p += sprintf((char *) p, "\x1BO%c", xkey);
p += sprintf(p, "\x1BO%c", xkey);
else
p += sprintf((char *) p, "\x1B[%c", xkey);
p += sprintf(p, "\x1B[%c", xkey);
}
return p - buf;
}
int format_function_key(char *buf, Terminal *term, int key_number,
bool shift, bool ctrl)
{
char *p = buf;
static const int key_number_to_tilde_code[] = {
-1, /* no such key as F0 */
11, 12, 13, 14, 15, /*gap*/ 17, 18, 19, 20, 21, /*gap*/
23, 24, 25, 26, /*gap*/ 28, 29, /*gap*/ 31, 32, 33, 34,
};
assert(key_number > 0);
assert(key_number < lenof(key_number_to_tilde_code));
int index = (shift && key_number <= 10) ? key_number + 10 : key_number;
int code = key_number_to_tilde_code[index];
if (term->funky_type == FUNKY_SCO) {
/* SCO function keys */
static const char sco_codes[] =
"MNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@[\\]^_`{";
index = (key_number >= 1 && key_number <= 12) ? key_number - 1 : 0;
if (shift) index += 12;
if (ctrl) index += 24;
p += sprintf(p, "\x1B[%c", sco_codes[index]);
} else if ((term->vt52_mode || term->funky_type == FUNKY_VT100P) &&
code >= 11 && code <= 24) {
int offt = 0;
if (code > 15)
offt++;
if (code > 21)
offt++;
if (term->vt52_mode)
p += sprintf(p, "\x1B%c", code + 'P' - 11 - offt);
else
p += sprintf(p, "\x1BO%c", code + 'P' - 11 - offt);
} else if (term->funky_type == FUNKY_LINUX && code >= 11 && code <= 15) {
p += sprintf(p, "\x1B[[%c", code + 'A' - 11);
} else if (term->funky_type == FUNKY_XTERM && code >= 11 && code <= 14) {
if (term->vt52_mode)
p += sprintf(p, "\x1B%c", code + 'P' - 11);
else
p += sprintf(p, "\x1BO%c", code + 'P' - 11);
} else {
p += sprintf(p, "\x1B[%d~", code);
}
return p - buf;
}
int format_small_keypad_key(char *buf, Terminal *term, SmallKeypadKey key)
{
char *p = buf;
int code;
switch (key) {
case SKK_HOME: code = 1; break;
case SKK_INSERT: code = 2; break;
case SKK_DELETE: code = 3; break;
case SKK_END: code = 4; break;
case SKK_PGUP: code = 5; break;
case SKK_PGDN: code = 6; break;
default: assert(false && "bad small keypad key enum value");
}
/* Reorder edit keys to physical order */
if (term->funky_type == FUNKY_VT400 && code <= 6)
code = "\0\2\1\4\5\3\6"[code];
if (term->vt52_mode && code > 0 && code <= 6) {
p += sprintf(p, "\x1B%c", " HLMEIG"[code]);
} else if (term->funky_type == FUNKY_SCO) {
static const char codes[] = "HL.FIG";
if (code == 3) {
*p++ = '\x7F';
} else {
p += sprintf(p, "\x1B[%c", codes[code-1]);
}
} else if ((code == 1 || code == 4) && term->rxvt_homeend) {
p += sprintf(p, code == 1 ? "\x1B[H" : "\x1BOw");
} else {
p += sprintf(p, "\x1B[%d~", code);
}
return p - buf;
}
int format_numeric_keypad_key(char *buf, Terminal *term, char key,
bool shift, bool ctrl)
{
char *p = buf;
bool app_keypad = (term->app_keypad_keys && !term->no_applic_k);
if (term->nethack_keypad && (key >= '1' && key <= '9')) {
static const char nh_base[] = "bjnh.lyku";
char c = nh_base[key - '1'];
if (ctrl && c != '.')
c &= 0x1F;
else if (shift && c != '.')
c += 'A'-'a';
*p++ = c;
} else {
int xkey = 0;
if (term->funky_type == FUNKY_VT400 ||
(term->funky_type <= FUNKY_LINUX && app_keypad)) {
switch (key) {
case 'G': xkey = 'P'; break;
case '/': xkey = 'Q'; break;
case '*': xkey = 'R'; break;
case '-': xkey = 'S'; break;
}
}
if (app_keypad) {
switch (key) {
case '0': xkey = 'p'; break;
case '1': xkey = 'q'; break;
case '2': xkey = 'r'; break;
case '3': xkey = 's'; break;
case '4': xkey = 't'; break;
case '5': xkey = 'u'; break;
case '6': xkey = 'v'; break;
case '7': xkey = 'w'; break;
case '8': xkey = 'x'; break;
case '9': xkey = 'y'; break;
case '.': xkey = 'n'; break;
case '\r': xkey = 'M'; break;
case '+':
/*
* Keypad + is tricky. It covers a space that would
* be taken up on the VT100 by _two_ keys; so we
* let Shift select between the two. Worse still,
* in xterm function key mode we change which two...
*/
if (term->funky_type == FUNKY_XTERM)
xkey = shift ? 'l' : 'k';
else
xkey = shift ? 'm' : 'l';
break;
case '/':
if (term->funky_type == FUNKY_XTERM)
xkey = 'o';
break;
case '*':
if (term->funky_type == FUNKY_XTERM)
xkey = 'j';
break;
case '-':
if (term->funky_type == FUNKY_XTERM)
xkey = 'm';
break;
}
}
if (xkey) {
if (term->vt52_mode) {
if (xkey >= 'P' && xkey <= 'S')
p += sprintf(p, "\x1B%c", xkey);
else
p += sprintf(p, "\x1B?%c", xkey);
} else
p += sprintf(p, "\x1BO%c", xkey);
}
}
if (p == buf && !app_keypad && key != 'G') {
/* Fallback: numeric keypad keys decode as their ASCII
* representation. */
p += sprintf(p, "%c", key);
}
return p - buf;

View File

@ -983,7 +983,9 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
int ucsval, start, end, output_charset;
bool special, use_ucsoutput;
bool nethack_mode, app_keypad_mode;
bool force_format_numeric_keypad = false;
bool generated_something = false;
char num_keypad_key = '\0';
#ifdef OSX_META_KEY_CONFIG
if (event->state & inst->system_mod_mask)
@ -1405,56 +1407,44 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
* numeric keypad presses if Num Lock is on, but we don't want
* it to.
*/
if (app_keypad_mode &&
(event->keyval == GDK_KEY_Num_Lock ||
event->keyval == GDK_KEY_KP_Divide ||
event->keyval == GDK_KEY_KP_Multiply ||
event->keyval == GDK_KEY_KP_Subtract ||
event->keyval == GDK_KEY_KP_Add ||
event->keyval == GDK_KEY_KP_Enter ||
event->keyval == GDK_KEY_KP_0 ||
event->keyval == GDK_KEY_KP_Insert ||
event->keyval == GDK_KEY_KP_1 ||
event->keyval == GDK_KEY_KP_End ||
event->keyval == GDK_KEY_KP_2 ||
event->keyval == GDK_KEY_KP_Down ||
event->keyval == GDK_KEY_KP_3 ||
event->keyval == GDK_KEY_KP_Page_Down ||
event->keyval == GDK_KEY_KP_4 ||
event->keyval == GDK_KEY_KP_Left ||
event->keyval == GDK_KEY_KP_5 ||
event->keyval == GDK_KEY_KP_Begin ||
event->keyval == GDK_KEY_KP_6 ||
event->keyval == GDK_KEY_KP_Right ||
event->keyval == GDK_KEY_KP_7 ||
event->keyval == GDK_KEY_KP_Home ||
event->keyval == GDK_KEY_KP_8 ||
event->keyval == GDK_KEY_KP_Up ||
event->keyval == GDK_KEY_KP_9 ||
event->keyval == GDK_KEY_KP_Page_Up ||
event->keyval == GDK_KEY_KP_Decimal ||
event->keyval == GDK_KEY_KP_Delete)) {
/* app keypad; do nothing */
} else if (nethack_mode &&
(event->keyval == GDK_KEY_KP_1 ||
event->keyval == GDK_KEY_KP_End ||
event->keyval == GDK_KEY_KP_2 ||
event->keyval == GDK_KEY_KP_Down ||
event->keyval == GDK_KEY_KP_3 ||
event->keyval == GDK_KEY_KP_Page_Down ||
event->keyval == GDK_KEY_KP_4 ||
event->keyval == GDK_KEY_KP_Left ||
event->keyval == GDK_KEY_KP_5 ||
event->keyval == GDK_KEY_KP_Begin ||
event->keyval == GDK_KEY_KP_6 ||
event->keyval == GDK_KEY_KP_Right ||
event->keyval == GDK_KEY_KP_7 ||
event->keyval == GDK_KEY_KP_Home ||
event->keyval == GDK_KEY_KP_8 ||
event->keyval == GDK_KEY_KP_Up ||
event->keyval == GDK_KEY_KP_9 ||
event->keyval == GDK_KEY_KP_Page_Up)) {
/* nethack mode; do nothing */
bool numeric = false;
switch (event->keyval) {
case GDK_KEY_Num_Lock: num_keypad_key = 'G'; break;
case GDK_KEY_KP_Divide: num_keypad_key = '/'; break;
case GDK_KEY_KP_Multiply: num_keypad_key = '*'; break;
case GDK_KEY_KP_Subtract: num_keypad_key = '-'; break;
case GDK_KEY_KP_Add: num_keypad_key = '+'; break;
case GDK_KEY_KP_Enter: num_keypad_key = '\r'; break;
case GDK_KEY_KP_0: num_keypad_key = '0'; numeric = true; break;
case GDK_KEY_KP_Insert: num_keypad_key = '0'; break;
case GDK_KEY_KP_1: num_keypad_key = '1'; numeric = true; break;
case GDK_KEY_KP_End: num_keypad_key = '1'; break;
case GDK_KEY_KP_2: num_keypad_key = '2'; numeric = true; break;
case GDK_KEY_KP_Down: num_keypad_key = '2'; break;
case GDK_KEY_KP_3: num_keypad_key = '3'; numeric = true; break;
case GDK_KEY_KP_Page_Down: num_keypad_key = '3'; break;
case GDK_KEY_KP_4: num_keypad_key = '4'; numeric = true; break;
case GDK_KEY_KP_Left: num_keypad_key = '4'; break;
case GDK_KEY_KP_5: num_keypad_key = '5'; numeric = true; break;
case GDK_KEY_KP_Begin: num_keypad_key = '5'; break;
case GDK_KEY_KP_6: num_keypad_key = '6'; numeric = true; break;
case GDK_KEY_KP_Right: num_keypad_key = '6'; break;
case GDK_KEY_KP_7: num_keypad_key = '7'; numeric = true; break;
case GDK_KEY_KP_Home: num_keypad_key = '7'; break;
case GDK_KEY_KP_8: num_keypad_key = '8'; numeric = true; break;
case GDK_KEY_KP_Up: num_keypad_key = '8'; break;
case GDK_KEY_KP_9: num_keypad_key = '9'; numeric = true; break;
case GDK_KEY_KP_Page_Up: num_keypad_key = '9'; break;
case GDK_KEY_KP_Decimal: num_keypad_key = '.'; numeric = true; break;
case GDK_KEY_KP_Delete: num_keypad_key = '.'; break;
}
if ((app_keypad_mode && num_keypad_key &&
(numeric || inst->term->funky_type != FUNKY_XTERM)) ||
(nethack_mode && num_keypad_key >= '1' && num_keypad_key <= '9')) {
/* In these modes, we override the keypad handling:
* regardless of Num Lock, the keys are handled by
* format_numeric_keypad_key below. */
force_format_numeric_keypad = true;
} else {
bool try_filter = true;
@ -1763,345 +1753,108 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
end = 2;
}
/*
* NetHack keypad mode.
*/
if (nethack_mode) {
const char *keys = NULL;
switch (event->keyval) {
case GDK_KEY_KP_1: case GDK_KEY_KP_End:
keys = "bB\002"; break;
case GDK_KEY_KP_2: case GDK_KEY_KP_Down:
keys = "jJ\012"; break;
case GDK_KEY_KP_3: case GDK_KEY_KP_Page_Down:
keys = "nN\016"; break;
case GDK_KEY_KP_4: case GDK_KEY_KP_Left:
keys = "hH\010"; break;
case GDK_KEY_KP_5: case GDK_KEY_KP_Begin:
keys = "..."; break;
case GDK_KEY_KP_6: case GDK_KEY_KP_Right:
keys = "lL\014"; break;
case GDK_KEY_KP_7: case GDK_KEY_KP_Home:
keys = "yY\031"; break;
case GDK_KEY_KP_8: case GDK_KEY_KP_Up:
keys = "kK\013"; break;
case GDK_KEY_KP_9: case GDK_KEY_KP_Page_Up:
keys = "uU\025"; break;
}
if (keys) {
end = 2;
if (event->state & GDK_CONTROL_MASK)
output[1] = keys[2];
else if (event->state & GDK_SHIFT_MASK)
output[1] = keys[1];
else
output[1] = keys[0];
if (num_keypad_key && force_format_numeric_keypad) {
end = 1 + format_numeric_keypad_key(
output+1, inst->term, num_keypad_key,
event->state & GDK_SHIFT_MASK,
event->state & GDK_CONTROL_MASK);
#ifdef KEY_EVENT_DIAGNOSTICS
debug((" - Nethack-mode key"));
debug((" - numeric keypad key"));
#endif
use_ucsoutput = false;
goto done;
}
use_ucsoutput = false;
goto done;
}
/*
* Application keypad mode.
*/
if (app_keypad_mode) {
int xkey = 0;
switch (event->keyval) {
case GDK_KEY_Num_Lock: xkey = 'P'; break;
case GDK_KEY_KP_Divide: xkey = 'Q'; break;
case GDK_KEY_KP_Multiply: xkey = 'R'; break;
case GDK_KEY_KP_Subtract: xkey = 'S'; break;
/*
* Keypad + is tricky. It covers a space that would
* be taken up on the VT100 by _two_ keys; so we
* let Shift select between the two. Worse still,
* in xterm function key mode we change which two...
*/
case GDK_KEY_KP_Add:
if (conf_get_int(inst->conf, CONF_funky_type) == FUNKY_XTERM) {
if (event->state & GDK_SHIFT_MASK)
xkey = 'l';
else
xkey = 'k';
} else if (event->state & GDK_SHIFT_MASK)
xkey = 'm';
else
xkey = 'l';
break;
case GDK_KEY_KP_Enter: xkey = 'M'; break;
case GDK_KEY_KP_0: case GDK_KEY_KP_Insert: xkey = 'p'; break;
case GDK_KEY_KP_1: case GDK_KEY_KP_End: xkey = 'q'; break;
case GDK_KEY_KP_2: case GDK_KEY_KP_Down: xkey = 'r'; break;
case GDK_KEY_KP_3: case GDK_KEY_KP_Page_Down: xkey = 's'; break;
case GDK_KEY_KP_4: case GDK_KEY_KP_Left: xkey = 't'; break;
case GDK_KEY_KP_5: case GDK_KEY_KP_Begin: xkey = 'u'; break;
case GDK_KEY_KP_6: case GDK_KEY_KP_Right: xkey = 'v'; break;
case GDK_KEY_KP_7: case GDK_KEY_KP_Home: xkey = 'w'; break;
case GDK_KEY_KP_8: case GDK_KEY_KP_Up: xkey = 'x'; break;
case GDK_KEY_KP_9: case GDK_KEY_KP_Page_Up: xkey = 'y'; break;
case GDK_KEY_KP_Decimal: case GDK_KEY_KP_Delete:
xkey = 'n'; break;
}
if (xkey) {
if (inst->term->vt52_mode) {
if (xkey >= 'P' && xkey <= 'S')
end = 1 + sprintf(output+1, "\033%c", xkey);
else
end = 1 + sprintf(output+1, "\033?%c", xkey);
} else
end = 1 + sprintf(output+1, "\033O%c", xkey);
use_ucsoutput = false;
switch (event->keyval) {
int fkey_number;
case GDK_KEY_F1: fkey_number = 1; goto numbered_function_key;
case GDK_KEY_F2: fkey_number = 2; goto numbered_function_key;
case GDK_KEY_F3: fkey_number = 3; goto numbered_function_key;
case GDK_KEY_F4: fkey_number = 4; goto numbered_function_key;
case GDK_KEY_F5: fkey_number = 5; goto numbered_function_key;
case GDK_KEY_F6: fkey_number = 6; goto numbered_function_key;
case GDK_KEY_F7: fkey_number = 7; goto numbered_function_key;
case GDK_KEY_F8: fkey_number = 8; goto numbered_function_key;
case GDK_KEY_F9: fkey_number = 9; goto numbered_function_key;
case GDK_KEY_F10: fkey_number = 10; goto numbered_function_key;
case GDK_KEY_F11: fkey_number = 11; goto numbered_function_key;
case GDK_KEY_F12: fkey_number = 12; goto numbered_function_key;
case GDK_KEY_F13: fkey_number = 13; goto numbered_function_key;
case GDK_KEY_F14: fkey_number = 14; goto numbered_function_key;
case GDK_KEY_F15: fkey_number = 15; goto numbered_function_key;
case GDK_KEY_F16: fkey_number = 16; goto numbered_function_key;
case GDK_KEY_F17: fkey_number = 17; goto numbered_function_key;
case GDK_KEY_F18: fkey_number = 18; goto numbered_function_key;
case GDK_KEY_F19: fkey_number = 19; goto numbered_function_key;
case GDK_KEY_F20: fkey_number = 20; goto numbered_function_key;
numbered_function_key:
end = 1 + format_function_key(output+1, inst->term, fkey_number,
event->state & GDK_SHIFT_MASK,
event->state & GDK_CONTROL_MASK);
#ifdef KEY_EVENT_DIAGNOSTICS
debug((" - Application keypad mode key"));
debug((" - function key F%d", fkey_number));
#endif
goto done;
}
use_ucsoutput = false;
goto done;
SmallKeypadKey sk_key;
case GDK_KEY_Home: case GDK_KEY_KP_Home:
sk_key = SKK_HOME; goto small_keypad_key;
case GDK_KEY_Insert: case GDK_KEY_KP_Insert:
sk_key = SKK_INSERT; goto small_keypad_key;
case GDK_KEY_Delete: case GDK_KEY_KP_Delete:
sk_key = SKK_DELETE; goto small_keypad_key;
case GDK_KEY_End: case GDK_KEY_KP_End:
sk_key = SKK_END; goto small_keypad_key;
case GDK_KEY_Page_Up: case GDK_KEY_KP_Page_Up:
sk_key = SKK_PGUP; goto small_keypad_key;
case GDK_KEY_Page_Down: case GDK_KEY_KP_Page_Down:
sk_key = SKK_PGDN; goto small_keypad_key;
small_keypad_key:
/* These keys don't generate terminal input with Ctrl */
if (event->state & GDK_CONTROL_MASK)
break;
end = 1 + format_small_keypad_key(output+1, inst->term, sk_key);
#ifdef KEY_EVENT_DIAGNOSTICS
debug((" - small keypad key"));
#endif
use_ucsoutput = false;
goto done;
int xkey;
case GDK_KEY_Up: case GDK_KEY_KP_Up:
xkey = 'A'; goto arrow_key;
case GDK_KEY_Down: case GDK_KEY_KP_Down:
xkey = 'B'; goto arrow_key;
case GDK_KEY_Right: case GDK_KEY_KP_Right:
xkey = 'C'; goto arrow_key;
case GDK_KEY_Left: case GDK_KEY_KP_Left:
xkey = 'D'; goto arrow_key;
case GDK_KEY_Begin: case GDK_KEY_KP_Begin:
xkey = 'G'; goto arrow_key;
arrow_key:
end = 1 + format_arrow_key(output+1, inst->term, xkey,
event->state & GDK_CONTROL_MASK);
#ifdef KEY_EVENT_DIAGNOSTICS
debug((" - arrow key"));
#endif
use_ucsoutput = false;
goto done;
}
/*
* Next, all the keys that do tilde codes. (ESC '[' nn '~',
* for integer decimal nn.)
*
* We also deal with the weird ones here. Linux VCs replace F1
* to F5 by ESC [ [ A to ESC [ [ E. rxvt doesn't do _that_, but
* does replace Home and End (1~ and 4~) by ESC [ H and ESC O w
* respectively.
*/
{
int code = 0;
int funky_type = conf_get_int(inst->conf, CONF_funky_type);
switch (event->keyval) {
case GDK_KEY_F1:
code = (event->state & GDK_SHIFT_MASK ? 23 : 11);
break;
case GDK_KEY_F2:
code = (event->state & GDK_SHIFT_MASK ? 24 : 12);
break;
case GDK_KEY_F3:
code = (event->state & GDK_SHIFT_MASK ? 25 : 13);
break;
case GDK_KEY_F4:
code = (event->state & GDK_SHIFT_MASK ? 26 : 14);
break;
case GDK_KEY_F5:
code = (event->state & GDK_SHIFT_MASK ? 28 : 15);
break;
case GDK_KEY_F6:
code = (event->state & GDK_SHIFT_MASK ? 29 : 17);
break;
case GDK_KEY_F7:
code = (event->state & GDK_SHIFT_MASK ? 31 : 18);
break;
case GDK_KEY_F8:
code = (event->state & GDK_SHIFT_MASK ? 32 : 19);
break;
case GDK_KEY_F9:
code = (event->state & GDK_SHIFT_MASK ? 33 : 20);
break;
case GDK_KEY_F10:
code = (event->state & GDK_SHIFT_MASK ? 34 : 21);
break;
case GDK_KEY_F11:
code = 23;
break;
case GDK_KEY_F12:
code = 24;
break;
case GDK_KEY_F13:
code = 25;
break;
case GDK_KEY_F14:
code = 26;
break;
case GDK_KEY_F15:
code = 28;
break;
case GDK_KEY_F16:
code = 29;
break;
case GDK_KEY_F17:
code = 31;
break;
case GDK_KEY_F18:
code = 32;
break;
case GDK_KEY_F19:
code = 33;
break;
case GDK_KEY_F20:
code = 34;
break;
}
if (!(event->state & GDK_CONTROL_MASK)) switch (event->keyval) {
case GDK_KEY_Home: case GDK_KEY_KP_Home:
code = 1;
break;
case GDK_KEY_Insert: case GDK_KEY_KP_Insert:
code = 2;
break;
case GDK_KEY_Delete: case GDK_KEY_KP_Delete:
code = 3;
break;
case GDK_KEY_End: case GDK_KEY_KP_End:
code = 4;
break;
case GDK_KEY_Page_Up: case GDK_KEY_KP_Page_Up:
code = 5;
break;
case GDK_KEY_Page_Down: case GDK_KEY_KP_Page_Down:
code = 6;
break;
}
/* Reorder edit keys to physical order */
if (funky_type == FUNKY_VT400 && code <= 6)
code = "\0\2\1\4\5\3\6"[code];
if (inst->term->vt52_mode && code > 0 && code <= 6) {
end = 1 + sprintf(output+1, "\x1B%c", " HLMEIG"[code]);
if (num_keypad_key) {
end = 1 + format_numeric_keypad_key(
output+1, inst->term, num_keypad_key,
event->state & GDK_SHIFT_MASK,
event->state & GDK_CONTROL_MASK);
#ifdef KEY_EVENT_DIAGNOSTICS
debug((" - VT52 mode small keypad key"));
debug((" - numeric keypad key"));
#endif
use_ucsoutput = false;
goto done;
}
if (funky_type == FUNKY_SCO && /* SCO function keys */
code >= 11 && code <= 34) {
char codes[] = "MNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@[\\]^_`{";
int index = 0;
switch (event->keyval) {
case GDK_KEY_F1: index = 0; break;
case GDK_KEY_F2: index = 1; break;
case GDK_KEY_F3: index = 2; break;
case GDK_KEY_F4: index = 3; break;
case GDK_KEY_F5: index = 4; break;
case GDK_KEY_F6: index = 5; break;
case GDK_KEY_F7: index = 6; break;
case GDK_KEY_F8: index = 7; break;
case GDK_KEY_F9: index = 8; break;
case GDK_KEY_F10: index = 9; break;
case GDK_KEY_F11: index = 10; break;
case GDK_KEY_F12: index = 11; break;
}
if (event->state & GDK_SHIFT_MASK) index += 12;
if (event->state & GDK_CONTROL_MASK) index += 24;
end = 1 + sprintf(output+1, "\x1B[%c", codes[index]);
#ifdef KEY_EVENT_DIAGNOSTICS
debug((" - SCO mode function key"));
#endif
use_ucsoutput = false;
goto done;
}
if (funky_type == FUNKY_SCO && /* SCO small keypad */
code >= 1 && code <= 6) {
char codes[] = "HL.FIG";
if (code == 3) {
output[1] = '\x7F';
end = 2;
} else {
end = 1 + sprintf(output+1, "\x1B[%c", codes[code-1]);
}
#ifdef KEY_EVENT_DIAGNOSTICS
debug((" - SCO mode small keypad key"));
#endif
use_ucsoutput = false;
goto done;
}
if ((inst->term->vt52_mode || funky_type == FUNKY_VT100P) &&
code >= 11 && code <= 24) {
int offt = 0;
if (code > 15)
offt++;
if (code > 21)
offt++;
if (inst->term->vt52_mode) {
#ifdef KEY_EVENT_DIAGNOSTICS
debug((" - VT52 mode function key"));
#endif
end = 1 + sprintf(output+1,
"\x1B%c", code + 'P' - 11 - offt);
} else {
#ifdef KEY_EVENT_DIAGNOSTICS
debug((" - VT100+ mode function key"));
#endif
end = 1 + sprintf(output+1,
"\x1BO%c", code + 'P' - 11 - offt);
}
use_ucsoutput = false;
goto done;
}
if (funky_type == FUNKY_LINUX && code >= 11 && code <= 15) {
end = 1 + sprintf(output+1, "\x1B[[%c", code + 'A' - 11);
#ifdef KEY_EVENT_DIAGNOSTICS
debug((" - Linux mode F1-F5 function key"));
#endif
use_ucsoutput = false;
goto done;
}
if (funky_type == FUNKY_XTERM && code >= 11 && code <= 14) {
if (inst->term->vt52_mode) {
#ifdef KEY_EVENT_DIAGNOSTICS
debug((" - VT52 mode (overriding xterm) F1-F4 function"
" key"));
#endif
end = 1 + sprintf(output+1, "\x1B%c", code + 'P' - 11);
} else {
#ifdef KEY_EVENT_DIAGNOSTICS
debug((" - xterm mode F1-F4 function key"));
#endif
end = 1 + sprintf(output+1, "\x1BO%c", code + 'P' - 11);
}
use_ucsoutput = false;
goto done;
}
if ((code == 1 || code == 4) &&
conf_get_bool(inst->conf, CONF_rxvt_homeend)) {
#ifdef KEY_EVENT_DIAGNOSTICS
debug((" - rxvt style Home/End"));
#endif
end = 1 + sprintf(output+1, code == 1 ? "\x1B[H" : "\x1BOw");
use_ucsoutput = false;
goto done;
}
if (code) {
#ifdef KEY_EVENT_DIAGNOSTICS
debug((" - ordinary function key encoding"));
#endif
end = 1 + sprintf(output+1, "\x1B[%d~", code);
use_ucsoutput = false;
goto done;
}
use_ucsoutput = false;
goto done;
}
/*
* Cursor keys. (This includes the numberpad cursor keys,
* if we haven't already done them due to app keypad mode.)
*
* Here we also process un-numlocked un-appkeypadded KP5,
* which sends ESC [ G.
*/
{
int xkey = 0;
switch (event->keyval) {
case GDK_KEY_Up: case GDK_KEY_KP_Up: xkey = 'A'; break;
case GDK_KEY_Down: case GDK_KEY_KP_Down: xkey = 'B'; break;
case GDK_KEY_Right: case GDK_KEY_KP_Right: xkey = 'C'; break;
case GDK_KEY_Left: case GDK_KEY_KP_Left: xkey = 'D'; break;
case GDK_KEY_Begin: case GDK_KEY_KP_Begin: xkey = 'G'; break;
}
if (xkey) {
end = 1 + format_arrow_key(output+1, inst->term, xkey,
event->state & GDK_CONTROL_MASK);
#ifdef KEY_EVENT_DIAGNOSTICS
debug((" - arrow key"));
#endif
use_ucsoutput = false;
goto done;
}
}
goto done;
}

View File

@ -4068,7 +4068,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
BYTE keystate[256];
int scan, shift_state;
bool left_alt = false, key_down;
int r, i, code;
int r, i;
unsigned char *p = output;
static int alt_sum = 0;
int funky_type = conf_get_int(conf, CONF_funky_type);
@ -4388,137 +4388,6 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
return 0;
}
/* Nethack keypad */
if (nethack_keypad && !left_alt) {
switch (wParam) {
case VK_NUMPAD1:
*p++ = "bB\002\002"[shift_state & 3];
return p - output;
case VK_NUMPAD2:
*p++ = "jJ\012\012"[shift_state & 3];
return p - output;
case VK_NUMPAD3:
*p++ = "nN\016\016"[shift_state & 3];
return p - output;
case VK_NUMPAD4:
*p++ = "hH\010\010"[shift_state & 3];
return p - output;
case VK_NUMPAD5:
*p++ = '.';
return p - output;
case VK_NUMPAD6:
*p++ = "lL\014\014"[shift_state & 3];
return p - output;
case VK_NUMPAD7:
*p++ = "yY\031\031"[shift_state & 3];
return p - output;
case VK_NUMPAD8:
*p++ = "kK\013\013"[shift_state & 3];
return p - output;
case VK_NUMPAD9:
*p++ = "uU\025\025"[shift_state & 3];
return p - output;
}
}
/* Application Keypad */
if (!left_alt) {
int xkey = 0;
if (funky_type == FUNKY_VT400 ||
(funky_type <= FUNKY_LINUX &&
term->app_keypad_keys && !no_applic_k)) switch (wParam) {
case VK_EXECUTE:
xkey = 'P';
break;
case VK_DIVIDE:
xkey = 'Q';
break;
case VK_MULTIPLY:
xkey = 'R';
break;
case VK_SUBTRACT:
xkey = 'S';
break;
}
if (term->app_keypad_keys && !no_applic_k)
switch (wParam) {
case VK_NUMPAD0:
xkey = 'p';
break;
case VK_NUMPAD1:
xkey = 'q';
break;
case VK_NUMPAD2:
xkey = 'r';
break;
case VK_NUMPAD3:
xkey = 's';
break;
case VK_NUMPAD4:
xkey = 't';
break;
case VK_NUMPAD5:
xkey = 'u';
break;
case VK_NUMPAD6:
xkey = 'v';
break;
case VK_NUMPAD7:
xkey = 'w';
break;
case VK_NUMPAD8:
xkey = 'x';
break;
case VK_NUMPAD9:
xkey = 'y';
break;
case VK_DECIMAL:
xkey = 'n';
break;
case VK_ADD:
if (funky_type == FUNKY_XTERM) {
if (shift_state)
xkey = 'l';
else
xkey = 'k';
} else if (shift_state)
xkey = 'm';
else
xkey = 'l';
break;
case VK_DIVIDE:
if (funky_type == FUNKY_XTERM)
xkey = 'o';
break;
case VK_MULTIPLY:
if (funky_type == FUNKY_XTERM)
xkey = 'j';
break;
case VK_SUBTRACT:
if (funky_type == FUNKY_XTERM)
xkey = 'm';
break;
case VK_RETURN:
if (HIWORD(lParam) & KF_EXTENDED)
xkey = 'M';
break;
}
if (xkey) {
if (term->vt52_mode) {
if (xkey >= 'P' && xkey <= 'S')
p += sprintf((char *) p, "\x1B%c", xkey);
else
p += sprintf((char *) p, "\x1B?%c", xkey);
} else
p += sprintf((char *) p, "\x1BO%c", xkey);
return p - output;
}
}
if (wParam == VK_BACK && shift_state == 0) { /* Backspace */
*p++ = (conf_get_bool(conf, CONF_bksp_is_delete) ? 0x7F : 0x08);
*p++ = 0;
@ -4577,217 +4446,101 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
return p - output;
}
/*
* Next, all the keys that do tilde codes. (ESC '[' nn '~',
* for integer decimal nn.)
*
* We also deal with the weird ones here. Linux VCs replace F1
* to F5 by ESC [ [ A to ESC [ [ E. rxvt doesn't do _that_, but
* does replace Home and End (1~ and 4~) by ESC [ H and ESC O w
* respectively.
*/
code = 0;
switch (wParam) {
case VK_F1:
code = (keystate[VK_SHIFT] & 0x80 ? 23 : 11);
break;
case VK_F2:
code = (keystate[VK_SHIFT] & 0x80 ? 24 : 12);
break;
case VK_F3:
code = (keystate[VK_SHIFT] & 0x80 ? 25 : 13);
break;
case VK_F4:
code = (keystate[VK_SHIFT] & 0x80 ? 26 : 14);
break;
case VK_F5:
code = (keystate[VK_SHIFT] & 0x80 ? 28 : 15);
break;
case VK_F6:
code = (keystate[VK_SHIFT] & 0x80 ? 29 : 17);
break;
case VK_F7:
code = (keystate[VK_SHIFT] & 0x80 ? 31 : 18);
break;
case VK_F8:
code = (keystate[VK_SHIFT] & 0x80 ? 32 : 19);
break;
case VK_F9:
code = (keystate[VK_SHIFT] & 0x80 ? 33 : 20);
break;
case VK_F10:
code = (keystate[VK_SHIFT] & 0x80 ? 34 : 21);
break;
case VK_F11:
code = 23;
break;
case VK_F12:
code = 24;
break;
case VK_F13:
code = 25;
break;
case VK_F14:
code = 26;
break;
case VK_F15:
code = 28;
break;
case VK_F16:
code = 29;
break;
case VK_F17:
code = 31;
break;
case VK_F18:
code = 32;
break;
case VK_F19:
code = 33;
break;
case VK_F20:
code = 34;
break;
}
if ((shift_state&2) == 0) switch (wParam) {
case VK_HOME:
code = 1;
break;
case VK_INSERT:
code = 2;
break;
case VK_DELETE:
code = 3;
break;
case VK_END:
code = 4;
break;
case VK_PRIOR:
code = 5;
break;
case VK_NEXT:
code = 6;
break;
}
/* Reorder edit keys to physical order */
if (funky_type == FUNKY_VT400 && code <= 6)
code = "\0\2\1\4\5\3\6"[code];
char keypad_key;
case VK_NUMPAD0: keypad_key = '0'; goto numeric_keypad;
case VK_NUMPAD1: keypad_key = '1'; goto numeric_keypad;
case VK_NUMPAD2: keypad_key = '2'; goto numeric_keypad;
case VK_NUMPAD3: keypad_key = '3'; goto numeric_keypad;
case VK_NUMPAD4: keypad_key = '4'; goto numeric_keypad;
case VK_NUMPAD5: keypad_key = '5'; goto numeric_keypad;
case VK_NUMPAD6: keypad_key = '6'; goto numeric_keypad;
case VK_NUMPAD7: keypad_key = '7'; goto numeric_keypad;
case VK_NUMPAD8: keypad_key = '8'; goto numeric_keypad;
case VK_NUMPAD9: keypad_key = '9'; goto numeric_keypad;
case VK_DECIMAL: keypad_key = '.'; goto numeric_keypad;
case VK_ADD: keypad_key = '+'; goto numeric_keypad;
case VK_SUBTRACT: keypad_key = '-'; goto numeric_keypad;
case VK_MULTIPLY: keypad_key = '*'; goto numeric_keypad;
case VK_DIVIDE: keypad_key = '/'; goto numeric_keypad;
case VK_EXECUTE: keypad_key = 'G'; goto numeric_keypad;
/* also the case for VK_RETURN below can sometimes come here */
numeric_keypad:
/* Left Alt overrides all numeric keypad usage to act as
* numeric character code input */
if (left_alt) {
if (keypad_key >= '0' && keypad_key <= '9')
alt_sum = alt_sum * 10 + keypad_key - '0';
else
alt_sum = 0;
break;
}
if (term->vt52_mode && code > 0 && code <= 6) {
p += sprintf((char *) p, "\x1B%c", " HLMEIG"[code]);
return p - output;
}
p += format_numeric_keypad_key(
(char *)p, term, keypad_key,
shift_state & 1, shift_state & 2);
return p - output;
if (funky_type == FUNKY_SCO && code >= 11 && code <= 34) {
/* SCO function keys */
char codes[] = "MNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@[\\]^_`{";
int index = 0;
switch (wParam) {
case VK_F1: index = 0; break;
case VK_F2: index = 1; break;
case VK_F3: index = 2; break;
case VK_F4: index = 3; break;
case VK_F5: index = 4; break;
case VK_F6: index = 5; break;
case VK_F7: index = 6; break;
case VK_F8: index = 7; break;
case VK_F9: index = 8; break;
case VK_F10: index = 9; break;
case VK_F11: index = 10; break;
case VK_F12: index = 11; break;
}
if (keystate[VK_SHIFT] & 0x80) index += 12;
if (keystate[VK_CONTROL] & 0x80) index += 24;
p += sprintf((char *) p, "\x1B[%c", codes[index]);
return p - output;
}
if (funky_type == FUNKY_SCO && /* SCO small keypad */
code >= 1 && code <= 6) {
char codes[] = "HL.FIG";
if (code == 3) {
*p++ = '\x7F';
} else {
p += sprintf((char *) p, "\x1B[%c", codes[code-1]);
}
return p - output;
}
if ((term->vt52_mode || funky_type == FUNKY_VT100P) && code >= 11 && code <= 24) {
int offt = 0;
if (code > 15)
offt++;
if (code > 21)
offt++;
if (term->vt52_mode)
p += sprintf((char *) p, "\x1B%c", code + 'P' - 11 - offt);
else
p +=
sprintf((char *) p, "\x1BO%c", code + 'P' - 11 - offt);
return p - output;
}
if (funky_type == FUNKY_LINUX && code >= 11 && code <= 15) {
p += sprintf((char *) p, "\x1B[[%c", code + 'A' - 11);
return p - output;
}
if (funky_type == FUNKY_XTERM && code >= 11 && code <= 14) {
if (term->vt52_mode)
p += sprintf((char *) p, "\x1B%c", code + 'P' - 11);
else
p += sprintf((char *) p, "\x1BO%c", code + 'P' - 11);
return p - output;
}
if ((code == 1 || code == 4) &&
conf_get_bool(conf, CONF_rxvt_homeend)) {
p += sprintf((char *) p, code == 1 ? "\x1B[H" : "\x1BOw");
return p - output;
}
if (code) {
p += sprintf((char *) p, "\x1B[%d~", code);
return p - output;
}
int fkey_number;
case VK_F1: fkey_number = 1; goto numbered_function_key;
case VK_F2: fkey_number = 2; goto numbered_function_key;
case VK_F3: fkey_number = 3; goto numbered_function_key;
case VK_F4: fkey_number = 4; goto numbered_function_key;
case VK_F5: fkey_number = 5; goto numbered_function_key;
case VK_F6: fkey_number = 6; goto numbered_function_key;
case VK_F7: fkey_number = 7; goto numbered_function_key;
case VK_F8: fkey_number = 8; goto numbered_function_key;
case VK_F9: fkey_number = 9; goto numbered_function_key;
case VK_F10: fkey_number = 10; goto numbered_function_key;
case VK_F11: fkey_number = 11; goto numbered_function_key;
case VK_F12: fkey_number = 12; goto numbered_function_key;
case VK_F13: fkey_number = 13; goto numbered_function_key;
case VK_F14: fkey_number = 14; goto numbered_function_key;
case VK_F15: fkey_number = 15; goto numbered_function_key;
case VK_F16: fkey_number = 16; goto numbered_function_key;
case VK_F17: fkey_number = 17; goto numbered_function_key;
case VK_F18: fkey_number = 18; goto numbered_function_key;
case VK_F19: fkey_number = 19; goto numbered_function_key;
case VK_F20: fkey_number = 20; goto numbered_function_key;
numbered_function_key:
p += format_function_key((char *)p, term, fkey_number,
shift_state & 1, shift_state & 2);
return p - output;
/*
* Now the remaining keys (arrows and Keypad 5. Keypad 5 for
* some reason seems to send VK_CLEAR to Windows...).
*/
{
char xkey = 0;
switch (wParam) {
case VK_UP:
xkey = 'A';
break;
case VK_DOWN:
xkey = 'B';
break;
case VK_RIGHT:
xkey = 'C';
break;
case VK_LEFT:
xkey = 'D';
break;
case VK_CLEAR:
xkey = 'G';
break;
}
if (xkey) {
p += format_arrow_key((char *)p, term, xkey, shift_state);
return p - output;
}
}
SmallKeypadKey sk_key;
case VK_HOME: sk_key = SKK_HOME; goto small_keypad_key;
case VK_END: sk_key = SKK_END; goto small_keypad_key;
case VK_INSERT: sk_key = SKK_INSERT; goto small_keypad_key;
case VK_DELETE: sk_key = SKK_DELETE; goto small_keypad_key;
case VK_PRIOR: sk_key = SKK_PGUP; goto small_keypad_key;
case VK_NEXT: sk_key = SKK_PGDN; goto small_keypad_key;
small_keypad_key:
/* These keys don't generate terminal input with Ctrl */
if (shift_state & 2)
break;
/*
* Finally, deal with Return ourselves. (Win95 seems to
* foul it up when Alt is pressed, for some reason.)
*/
if (wParam == VK_RETURN) { /* Return */
p += format_small_keypad_key((char *)p, term, sk_key);
return p - output;
char xkey;
case VK_UP: xkey = 'A'; goto arrow_key;
case VK_DOWN: xkey = 'B'; goto arrow_key;
case VK_RIGHT: xkey = 'C'; goto arrow_key;
case VK_LEFT: xkey = 'D'; goto arrow_key;
case VK_CLEAR: xkey = 'G'; goto arrow_key; /* close enough */
arrow_key:
p += format_arrow_key((char *)p, term, xkey, shift_state & 2);
return p - output;
case VK_RETURN:
if (HIWORD(lParam) & KF_EXTENDED) {
keypad_key = '\r';
goto numeric_keypad;
}
*p++ = 0x0D;
*p++ = 0;
return -2;
}
if (left_alt && wParam >= VK_NUMPAD0 && wParam <= VK_NUMPAD9)
alt_sum = alt_sum * 10 + wParam - VK_NUMPAD0;
else
alt_sum = 0;
}
/* Okay we've done everything interesting; let windows deal with