From ed1031b358967b9a3037a8c5c72caae17ce2961c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 9 Jan 2009 16:45:58 +0000 Subject: [PATCH] Update key handling code. Simplify, support ctrl properly and add a new window option (xterm-keys) to output xterm key codes including ctrl and, if available, alt and shift. --- CHANGES | 8 +- cmd-list-clients.c | 3 +- cmd-set-window-option.c | 3 +- input-keys.c | 150 +++++++++++++++++++-------- key-string.c | 41 ++++++-- mode-key.c | 8 +- tmux.c | 5 +- tmux.h | 30 ++++-- tty-keys.c | 217 +++++++++++++++++++++++++++------------- 9 files changed, 322 insertions(+), 143 deletions(-) diff --git a/CHANGES b/CHANGES index d7e7fa6c..9ad3dd95 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +09 January 2009 + +* Update key handling code. Simplify, support ctrl properly and add a new + window option (xterm-keys) to output xterm key codes including ctrl and, + if available, alt and shift. + 08 January 2009 * If built without DEBUG (the release versions), don't cause a fatal error if @@ -820,7 +826,7 @@ (including mutt, emacs). No status bar yet and no key remapping or other customisation. -$Id: CHANGES,v 1.183 2009-01-08 21:59:24 nicm Exp $ +$Id: CHANGES,v 1.184 2009-01-09 16:45:58 nicm Exp $ LocalWords: showw utf UTF fulvio ciriaco joshe OSC APC gettime abc DEF OA clr LocalWords: rivo nurges lscm Erdely eol smysession mysession ek dstname RB diff --git a/cmd-list-clients.c b/cmd-list-clients.c index 9d6d32e4..c9ab802d 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -1,4 +1,4 @@ -/* $Id: cmd-list-clients.c,v 1.9 2009-01-07 20:11:51 nicm Exp $ */ +/* $Id: cmd-list-clients.c,v 1.10 2009-01-09 16:45:58 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -47,7 +47,6 @@ cmd_list_clients_exec(unused struct cmd *self, struct cmd_ctx *ctx) { struct client *c; u_int i; - char options[256]; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c index c0684d18..9cc4530e 100644 --- a/cmd-set-window-option.c +++ b/cmd-set-window-option.c @@ -1,4 +1,4 @@ -/* $Id: cmd-set-window-option.c,v 1.16 2009-01-07 19:53:17 nicm Exp $ */ +/* $Id: cmd-set-window-option.c,v 1.17 2009-01-09 16:45:58 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -60,6 +60,7 @@ const struct set_option_entry set_window_option_table[NSETWINDOWOPTION] = { { "monitor-activity", SET_OPTION_FLAG, 0, 0, NULL }, { "remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, { "utf8", SET_OPTION_FLAG, 0, 0, NULL }, + { "xterm-keys", SET_OPTION_FLAG, 0, 0, NULL }, }; void diff --git a/input-keys.c b/input-keys.c index 19a42198..0c2e1f70 100644 --- a/input-keys.c +++ b/input-keys.c @@ -1,4 +1,4 @@ -/* $Id: input-keys.c,v 1.17 2009-01-08 22:28:02 nicm Exp $ */ +/* $Id: input-keys.c,v 1.18 2009-01-09 16:45:58 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -24,42 +24,47 @@ #include "tmux.h" -#define INPUTKEY_KEYPAD 0x1 -#define INPUTKEY_CURSOR 0x2 -struct { +struct input_key_ent { int key; const char *data; + int flags; -} input_keys[] = { +#define INPUTKEY_KEYPAD 0x1 /* keypad key */ +#define INPUTKEY_CURSOR 0x2 /* cursor key */ +#define INPUTKEY_MODIFIER 0x4 /* may be adjusted by modifiers */ +#define INPUTKEY_XTERM 0x4 /* may have xterm argument appended */ +}; + +struct input_key_ent input_keys[] = { /* Function keys. */ - { KEYC_F1, "\033OP", 0 }, - { KEYC_F2, "\033OQ", 0 }, - { KEYC_F3, "\033OR", 0 }, - { KEYC_F4, "\033OS", 0 }, - { KEYC_F5, "\033[15~", 0 }, - { KEYC_F6, "\033[17~", 0 }, - { KEYC_F7, "\033[18~", 0 }, - { KEYC_F8, "\033[19~", 0 }, - { KEYC_F9, "\033[20~", 0 }, - { KEYC_F10, "\033[21~", 0 }, - { KEYC_F11, "\033[23~", 0 }, - { KEYC_F12, "\033[24~", 0 }, - { KEYC_IC, "\033[2~", 0 }, - { KEYC_DC, "\033[3~", 0 }, - { KEYC_HOME, "\033[1~", 0 }, - { KEYC_END, "\033[4~", 0 }, - { KEYC_NPAGE, "\033[6~", 0 }, - { KEYC_PPAGE, "\033[5~", 0 }, + { KEYC_F1, "\033OP", INPUTKEY_MODIFIER|INPUTKEY_XTERM }, + { KEYC_F2, "\033OQ", INPUTKEY_MODIFIER|INPUTKEY_XTERM }, + { KEYC_F3, "\033OR", INPUTKEY_MODIFIER|INPUTKEY_XTERM }, + { KEYC_F4, "\033OS", INPUTKEY_MODIFIER|INPUTKEY_XTERM }, + { KEYC_F5, "\033[15~", INPUTKEY_MODIFIER|INPUTKEY_XTERM }, + { KEYC_F6, "\033[17~", INPUTKEY_MODIFIER|INPUTKEY_XTERM }, + { KEYC_F7, "\033[18~", INPUTKEY_MODIFIER|INPUTKEY_XTERM }, + { KEYC_F8, "\033[19~", INPUTKEY_MODIFIER|INPUTKEY_XTERM }, + { KEYC_F9, "\033[20~", INPUTKEY_MODIFIER|INPUTKEY_XTERM }, + { KEYC_F10, "\033[21~", INPUTKEY_MODIFIER|INPUTKEY_XTERM }, + { KEYC_F11, "\033[23~", INPUTKEY_MODIFIER|INPUTKEY_XTERM }, + { KEYC_F12, "\033[24~", INPUTKEY_MODIFIER|INPUTKEY_XTERM }, + { KEYC_IC, "\033[2~", INPUTKEY_MODIFIER|INPUTKEY_XTERM }, + { KEYC_DC, "\033[3~", INPUTKEY_MODIFIER|INPUTKEY_XTERM }, + { KEYC_HOME, "\033[1~", INPUTKEY_MODIFIER|INPUTKEY_XTERM }, + { KEYC_END, "\033[4~", INPUTKEY_MODIFIER|INPUTKEY_XTERM }, + { KEYC_NPAGE, "\033[6~", INPUTKEY_MODIFIER|INPUTKEY_XTERM }, + { KEYC_PPAGE, "\033[5~", INPUTKEY_MODIFIER|INPUTKEY_XTERM }, /* Arrow keys. Cursor versions must come first. */ - { KEYC_UP, "\033OA", INPUTKEY_CURSOR }, - { KEYC_DOWN, "\033OB", INPUTKEY_CURSOR }, - { KEYC_LEFT, "\033OD", INPUTKEY_CURSOR }, - { KEYC_RIGHT, "\033OC", INPUTKEY_CURSOR }, - { KEYC_UP, "\033[A", 0 }, - { KEYC_DOWN, "\033[B", 0 }, - { KEYC_LEFT, "\033[D", 0 }, - { KEYC_RIGHT, "\033[C", 0 }, + { KEYC_UP, "\033OA", INPUTKEY_MODIFIER|INPUTKEY_CURSOR }, + { KEYC_DOWN, "\033OB", INPUTKEY_MODIFIER|INPUTKEY_CURSOR }, + { KEYC_LEFT, "\033OD", INPUTKEY_MODIFIER|INPUTKEY_CURSOR }, + { KEYC_RIGHT, "\033OC", INPUTKEY_MODIFIER|INPUTKEY_CURSOR }, + { KEYC_UP, "\033[A", INPUTKEY_MODIFIER }, + { KEYC_DOWN, "\033[B", INPUTKEY_MODIFIER }, + { KEYC_LEFT, "\033[D", INPUTKEY_MODIFIER }, + { KEYC_RIGHT, "\033[C", INPUTKEY_MODIFIER }, /* Keypad keys. Keypad versions must come first. */ { KEYC_KP0_1, "/", INPUTKEY_KEYPAD }, @@ -100,35 +105,92 @@ struct { void input_key(struct window *w, int key) { - u_int i; + struct input_key_ent *ike; + u_int i; + char ch; + size_t dlen; log_debug2("writing key 0x%x", key); - if (KEYC_ISESCAPE(key)) { - buffer_write8(w->out, '\033'); - key = KEYC_REMOVEESCAPE(key); - } - - if (key != KEYC_NONE && key < KEYC_OFFSET) { - buffer_write8(w->out, (uint8_t) key); + if (key != KEYC_NONE && KEYC_REMOVEESC(key) < KEYC_OFFSET) { + if (KEYC_ISESC(key)) + buffer_write8(w->out, '\033'); + buffer_write8(w->out, (uint8_t) KEYC_REMOVEESC(key)); return; } for (i = 0; i < nitems(input_keys); i++) { - if ((input_keys[i].flags & INPUTKEY_KEYPAD) && + ike = &input_keys[i]; + + if ((ike->flags & INPUTKEY_KEYPAD) && !(w->screen->mode & MODE_KKEYPAD)) continue; - if ((input_keys[i].flags & INPUTKEY_CURSOR) && + if ((ike->flags & INPUTKEY_CURSOR) && !(w->screen->mode & MODE_KCURSOR)) continue; - if (input_keys[i].key == key) + + if (ike->flags & INPUTKEY_MODIFIER) { + if (KEYC_ISCTL(key) && KEYC_ADDCTL(ike->key) == key) + break; + if (KEYC_ISESC(key) && KEYC_ADDESC(ike->key) == key) + break; + if (KEYC_ISSFT(key) && KEYC_ADDSFT(ike->key) == key) + break; + } + if (ike->key == key) break; } if (i == nitems(input_keys)) { log_debug2("key 0x%x missing", key); return; } + dlen = strlen(ike->data); - log_debug2("found key 0x%x: \"%s\"", key, input_keys[i].data); - buffer_write(w->out, input_keys[i].data, strlen(input_keys[i].data)); + log_debug2("found key 0x%x: \"%s\"", key, ike->data); + + if (ike->flags & INPUTKEY_XTERM && + options_get_number(&w->options, "xterm-keys")) { + /* In xterm keys mode, append modifier argument. */ + ch = '\0'; + if (KEYC_ISSFT(key) && KEYC_ISESC(key) && KEYC_ISCTL(key)) + ch = '8'; + else if (KEYC_ISESC(key) && KEYC_ISCTL(key)) + ch = '7'; + else if (KEYC_ISSFT(key) && KEYC_ISCTL(key)) + ch = '6'; + else if (KEYC_ISCTL(key)) + ch = '5'; + else if (KEYC_ISSFT(key) && KEYC_ISESC(key)) + ch = '4'; + else if (KEYC_ISESC(key)) + ch = '3'; + else if (KEYC_ISSFT(key)) + ch = '2'; + if (ch != '\0') { + log_debug("output argument is: %c", ch); + buffer_write(w->out, ike->data, dlen - 1); + buffer_write8(w->out, ';'); + buffer_write8(w->out, ch); + buffer_write8(w->out, ike->data[dlen - 1]); + } else + buffer_write(w->out, ike->data, dlen); + return; + } + if (ike->flags & INPUTKEY_MODIFIER) { + /* + * If not in xterm keys or not an xterm key handle escape and + * control (shift not supported). + */ + if (KEYC_ISESC(key)) + buffer_write8(w->out, '\033'); + if (!KEYC_ISCTL(key)) { + buffer_write(w->out, ike->data, dlen); + return; + } + buffer_write(w->out, ike->data, dlen - 1); + buffer_write8(w->out, ike->data[dlen - 1] ^ 0x20); + return; + } + + buffer_write(w->out, ike->data, dlen); } diff --git a/key-string.c b/key-string.c index 7b4b330c..56c69e98 100644 --- a/key-string.c +++ b/key-string.c @@ -1,4 +1,4 @@ -/* $Id: key-string.c,v 1.10 2009-01-08 22:28:02 nicm Exp $ */ +/* $Id: key-string.c,v 1.11 2009-01-09 16:45:58 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -22,6 +22,8 @@ #include "tmux.h" +int key_string_search_table(const char *); + struct { const char *string; int key; @@ -71,6 +73,18 @@ struct { { "KP.", KEYC_KP4_2 }, }; +int +key_string_search_table(const char *string) +{ + u_int i; + + for (i = 0; i < nitems(key_string_table); i++) { + if (strcasecmp(string, key_string_table[i].string) == 0) + return (key_string_table[i].key); + } + return (KEYC_NONE); +} + int key_string_lookup_string(const char *string) { @@ -91,6 +105,9 @@ key_string_lookup_string(const char *string) return (string[2] - 64); if (string[2] >= 97 && string[2] <= 122) return (string[2] - 96); + key = key_string_search_table(string + 2); + if (key != KEYC_NONE) + return (KEYC_ADDCTL(key)); return (KEYC_NONE); } @@ -103,20 +120,19 @@ key_string_lookup_string(const char *string) return (string[1] - 64); if (string[1] >= 97 && string[1] <= 122) return (string[1] - 96); + key = key_string_search_table(string + 1); + if (key != KEYC_NONE) + return (KEYC_ADDCTL(key)); return (KEYC_NONE); } if (string[0] == 'M' && string[1] == '-') { if ((key = key_string_lookup_string(string + 2)) == KEYC_NONE) return (KEYC_NONE); - return (KEYC_ADDESCAPE(key)); + return (KEYC_ADDESC(key)); } - for (i = 0; i < nitems(key_string_table); i++) { - if (strcasecmp(string, key_string_table[i].string) == 0) - return (key_string_table[i].key); - } - return (KEYC_NONE); + return (key_string_search_table(string)); } const char * @@ -129,12 +145,19 @@ key_string_lookup_key(int key) if (key == 127) return (NULL); - if (KEYC_ISESCAPE(key)) { - if ((s = key_string_lookup_key(KEYC_REMOVEESCAPE(key))) == NULL) + if (KEYC_ISESC(key)) { + if ((s = key_string_lookup_key(KEYC_REMOVEESC(key))) == NULL) return (NULL); xsnprintf(tmp2, sizeof tmp2, "M-%s", s); return (tmp2); } + if (KEYC_ISCTL(key)) { + if ((s = key_string_lookup_key(KEYC_REMOVECTL(key))) == NULL) + return (NULL); + xsnprintf(tmp2, sizeof tmp2, "C-%s", s); + return (tmp2); + } + if (key >= 32 && key <= 255) { tmp[0] = key; diff --git a/mode-key.c b/mode-key.c index f33202a8..4526a6f4 100644 --- a/mode-key.c +++ b/mode-key.c @@ -1,4 +1,4 @@ -/* $Id: mode-key.c,v 1.4 2009-01-07 22:52:33 nicm Exp $ */ +/* $Id: mode-key.c,v 1.5 2009-01-09 16:45:58 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -53,15 +53,15 @@ const struct mode_key_entry mode_key_table_emacs[] = { { MODEKEY_BOL, '\001' }, { MODEKEY_CLEARSEL, '\007' }, { MODEKEY_COPYSEL, '\027' }, - { MODEKEY_COPYSEL, KEYC_ADDESCAPE('w') }, + { MODEKEY_COPYSEL, KEYC_ADDESC('w') }, { MODEKEY_DOWN, KEYC_DOWN }, { MODEKEY_EOL, '\005' }, { MODEKEY_LEFT, '\002' }, { MODEKEY_LEFT, KEYC_LEFT }, { MODEKEY_NPAGE, KEYC_NPAGE }, - { MODEKEY_NWORD, KEYC_ADDESCAPE('f') }, + { MODEKEY_NWORD, KEYC_ADDESC('f') }, { MODEKEY_PPAGE, KEYC_PPAGE }, - { MODEKEY_PWORD, KEYC_ADDESCAPE('b') }, + { MODEKEY_PWORD, KEYC_ADDESC('b') }, { MODEKEY_QUIT, '\033' }, { MODEKEY_QUIT, 'q' }, { MODEKEY_RIGHT, '\006' }, diff --git a/tmux.c b/tmux.c index e60d5a2e..f83fdb2f 100644 --- a/tmux.c +++ b/tmux.c @@ -1,4 +1,4 @@ -/* $Id: tmux.c,v 1.84 2008-12-10 20:25:41 nicm Exp $ */ +/* $Id: tmux.c,v 1.85 2009-01-09 16:45:58 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -236,7 +236,8 @@ main(int argc, char **argv) options_set_number(&global_options, "message-fg", 0); options_set_number(&global_options, "message-bg", 3); options_init(&global_window_options, NULL); - options_set_number(&global_window_options, "monitor-activity", 0); + options_set_number(&global_window_options, "xterm-keys", 0); + options_set_number(&global_window_options, "monitor-activity", 0); options_set_number(&global_window_options, "aggressive-resize", 0); options_set_number(&global_window_options, "remain-on-exit", 0); options_set_number(&global_window_options, "utf8", 0); diff --git a/tmux.h b/tmux.h index a60d8ecb..6be25ab9 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.210 2009-01-08 22:28:02 nicm Exp $ */ +/* $Id: tmux.h,v 1.211 2009-01-09 16:45:58 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -159,13 +159,23 @@ struct buffer { #define BELL_CURRENT 2 /* Key codes. ncurses defines KEY_*. Grrr. */ -#define KEYC_NONE 0x0ffff -#define KEYC_OFFSET 0x10000 -#define KEYC_ESCAPE 0x20000 +#define KEYC_NONE 0x00ffff +#define KEYC_OFFSET 0x010000 +#define KEYC_ESCAPE 0x020000 +#define KEYC_CONTROL 0x080000 +#define KEYC_SHIFT 0x100000 -#define KEYC_ADDESCAPE(k) ((k) | KEYC_ESCAPE) -#define KEYC_REMOVEESCAPE(k) ((k) & ~KEYC_ESCAPE) -#define KEYC_ISESCAPE(k) ((k) != KEYC_NONE && ((k) & KEYC_ESCAPE)) +#define KEYC_ADDESC(k) ((k) | KEYC_ESCAPE) +#define KEYC_REMOVEESC(k) ((k) & ~KEYC_ESCAPE) +#define KEYC_ISESC(k) ((k) != KEYC_NONE && ((k) & KEYC_ESCAPE)) + +#define KEYC_ADDCTL(k) ((k) | KEYC_CONTROL) +#define KEYC_REMOVECTL(k) ((k) & ~KEYC_CONTROL) +#define KEYC_ISCTL(k) ((k) != KEYC_NONE && ((k) & KEYC_CONTROL)) + +#define KEYC_ADDSFT(k) ((k) | KEYC_SHIFT) +#define KEYC_REMOVESFT(k) ((k) & ~KEYC_SHIFT) +#define KEYC_ISSFT(k) ((k) != KEYC_NONE && ((k) & KEYC_SHIFT)) /* Function keys. */ #define KEYC_F1 (KEYC_OFFSET + 0x01) @@ -550,6 +560,10 @@ struct tty_key { int code; char *string; + int flags; +#define TTYKEY_MODIFIER 0x1 +#define TTYKEY_RAW 0x2 + RB_ENTRY(tty_key) entry; }; @@ -743,7 +757,7 @@ struct set_option_entry { extern const struct set_option_entry set_option_table[]; extern const struct set_option_entry set_window_option_table[]; #define NSETOPTION 17 -#define NSETWINDOWOPTION 9 +#define NSETWINDOWOPTION 10 /* Edit keys. */ enum mode_key { diff --git a/tty-keys.c b/tty-keys.c index 29b0d9d2..44b83d60 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1,4 +1,4 @@ -/* $Id: tty-keys.c,v 1.13 2009-01-08 22:28:02 nicm Exp $ */ +/* $Id: tty-keys.c,v 1.14 2009-01-09 16:45:58 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -23,35 +23,41 @@ #include "tmux.h" -struct { +void tty_keys_add(struct tty *, const char *, int, int); + +struct tty_key_ent { const char *name; int code; -} tty_keys[] = { + + int flags; +}; + +struct tty_key_ent tty_keys[] = { /* Function keys. */ - { "kf1", KEYC_F1 }, - { "kf2", KEYC_F2 }, - { "kf3", KEYC_F3 }, - { "kf4", KEYC_F4 }, - { "kf5", KEYC_F5 }, - { "kf6", KEYC_F6 }, - { "kf7", KEYC_F7 }, - { "kf8", KEYC_F8 }, - { "kf9", KEYC_F9 }, - { "kf10", KEYC_F10 }, - { "kf11", KEYC_F11 }, - { "kf12", KEYC_F12 }, - { "kich1", KEYC_IC }, - { "kdch1", KEYC_DC }, - { "khome", KEYC_HOME }, - { "kend", KEYC_END }, - { "knp", KEYC_NPAGE }, - { "kpp", KEYC_PPAGE }, + { "kf1", KEYC_F1, TTYKEY_MODIFIER }, + { "kf2", KEYC_F2, TTYKEY_MODIFIER }, + { "kf3", KEYC_F3, TTYKEY_MODIFIER }, + { "kf4", KEYC_F4, TTYKEY_MODIFIER }, + { "kf5", KEYC_F5, TTYKEY_MODIFIER }, + { "kf6", KEYC_F6, TTYKEY_MODIFIER }, + { "kf7", KEYC_F7, TTYKEY_MODIFIER }, + { "kf8", KEYC_F8, TTYKEY_MODIFIER }, + { "kf9", KEYC_F9, TTYKEY_MODIFIER }, + { "kf10", KEYC_F10, TTYKEY_MODIFIER }, + { "kf11", KEYC_F11, TTYKEY_MODIFIER }, + { "kf12", KEYC_F12, TTYKEY_MODIFIER }, + { "kich1", KEYC_IC, TTYKEY_MODIFIER }, + { "kdch1", KEYC_DC, TTYKEY_MODIFIER }, + { "khome", KEYC_HOME, TTYKEY_MODIFIER }, + { "kend", KEYC_END, TTYKEY_MODIFIER }, + { "knp", KEYC_NPAGE, TTYKEY_MODIFIER }, + { "kpp", KEYC_PPAGE, TTYKEY_MODIFIER }, /* Arrow keys. */ - { "kcuu1", KEYC_UP }, - { "kcud1", KEYC_DOWN }, - { "kcub1", KEYC_LEFT }, - { "kcuf1", KEYC_RIGHT }, + { "kcuu1", KEYC_UP, TTYKEY_MODIFIER }, + { "kcud1", KEYC_DOWN, TTYKEY_MODIFIER }, + { "kcub1", KEYC_LEFT, TTYKEY_MODIFIER }, + { "kcuf1", KEYC_RIGHT, TTYKEY_MODIFIER }, /* * Numeric keypad. termcap and terminfo are totally confusing for this. @@ -63,22 +69,22 @@ struct { * mode. Translation of numbers mode/applications mode is done in * input-keys.c. */ - { "-\033Oo", KEYC_KP0_1 }, - { "-\033Oj", KEYC_KP0_2 }, - { "-\033Om", KEYC_KP0_3 }, - { "-\033Ow", KEYC_KP1_0 }, - { "-\033Ox", KEYC_KP1_1 }, - { "-\033Oy", KEYC_KP1_2 }, - { "-\033Ok", KEYC_KP1_3 }, - { "-\033Ot", KEYC_KP2_0 }, - { "-\033Ou", KEYC_KP2_1 }, - { "-\033Ov", KEYC_KP2_2 }, - { "-\033Oq", KEYC_KP3_0 }, - { "-\033Or", KEYC_KP3_1 }, - { "-\033Os", KEYC_KP3_2 }, - { "-\033OM", KEYC_KP3_3 }, - { "-\033Op", KEYC_KP4_0 }, - { "-\033On", KEYC_KP4_2 }, + { "\033Oo", KEYC_KP0_1, TTYKEY_RAW }, + { "\033Oj", KEYC_KP0_2, TTYKEY_RAW }, + { "\033Om", KEYC_KP0_3, TTYKEY_RAW }, + { "\033Ow", KEYC_KP1_0, TTYKEY_RAW }, + { "\033Ox", KEYC_KP1_1, TTYKEY_RAW }, + { "\033Oy", KEYC_KP1_2, TTYKEY_RAW }, + { "\033Ok", KEYC_KP1_3, TTYKEY_RAW }, + { "\033Ot", KEYC_KP2_0, TTYKEY_RAW }, + { "\033Ou", KEYC_KP2_1, TTYKEY_RAW }, + { "\033Ov", KEYC_KP2_2, TTYKEY_RAW }, + { "\033Oq", KEYC_KP3_0, TTYKEY_RAW }, + { "\033Or", KEYC_KP3_1, TTYKEY_RAW }, + { "\033Os", KEYC_KP3_2, TTYKEY_RAW }, + { "\033OM", KEYC_KP3_3, TTYKEY_RAW }, + { "\033Op", KEYC_KP4_0, TTYKEY_RAW }, + { "\033On", KEYC_KP4_2, TTYKEY_RAW }, }; RB_GENERATE(tty_keys, tty_key, entry, tty_keys_cmp); @@ -92,36 +98,54 @@ tty_keys_cmp(struct tty_key *k1, struct tty_key *k2) } void -tty_keys_init(struct tty *tty) +tty_keys_add(struct tty *tty, const char *s, int code, int flags) { struct tty_key *tk; - u_int i; - const char *s; + + tk = xmalloc(sizeof *tk); + tk->string = xstrdup(s); + tk->code = code; + tk->flags = flags; + + if (strlen(tk->string) > tty->ksize) + tty->ksize = strlen(tk->string); + RB_INSERT(tty_keys, &tty->ktree, tk); + + log_debug( + "new key %x: size now %zu (%s)", code, tty->ksize, tk->string); +} + +void +tty_keys_init(struct tty *tty) +{ + struct tty_key_ent *tke; + u_int i; + const char *s; + char tmp[64]; RB_INIT(&tty->ktree); tty->ksize = 0; for (i = 0; i < nitems(tty_keys); i++) { - if (*tty_keys[i].name == '-') - s = tty_keys[i].name + 1; + tke = &tty_keys[i]; + + if (tke->flags & TTYKEY_RAW) + s = tke->name; else { - s = tigetstr(tty_keys[i].name); + s = tigetstr(tke->name); if (s == (char *) -1 || s == (char *) 0) continue; + if (s[0] != '\033' || s[1] == '\0') + continue; } - if (s[0] != '\033' || s[1] == '\0') - continue; - tk = xmalloc(sizeof *tk); - tk->string = xstrdup(s + 1); - tk->code = tty_keys[i].code; - - if (strlen(tk->string) > tty->ksize) - tty->ksize = strlen(tk->string); - RB_INSERT(tty_keys, &tty->ktree, tk); - - log_debug("found key %x: size now %zu (%s)", - tk->code, tty->ksize, tk->string); + tty_keys_add(tty, s + 1, tke->code, tke->flags); + if (tke->flags & TTYKEY_MODIFIER) { + if (strlcpy(tmp, s, sizeof tmp) >= sizeof tmp) + continue; + tmp[strlen(tmp) - 1] ^= 0x20; + tty_keys_add(tty, tmp + 1, KEYC_ADDCTL(tke->code), 0); + } } } @@ -172,22 +196,24 @@ int tty_keys_next(struct tty *tty, int *code) { struct tty_key *tk; - size_t size; struct timeval tv; + char arg, *buf, tmp[32]; + size_t len, size; - size = BUFFER_USED(tty->in); - if (size == 0) + buf = BUFFER_OUT(tty->in); + len = BUFFER_USED(tty->in); + if (len == 0) return (1); - log_debug("keys are %zu (%.*s)", size, (int) size, BUFFER_OUT(tty->in)); + log_debug("keys are %zu (%.*s)", len, (int) len, buf); /* If a normal key, return it. */ - if (*BUFFER_OUT(tty->in) != '\033') { + if (*buf != '\033') { *code = buffer_read8(tty->in); return (0); } /* Look for matching key string and return if found. */ - tk = tty_keys_find(tty, BUFFER_OUT(tty->in) + 1, size - 1, &size); + tk = tty_keys_find(tty, buf + 1, len - 1, &size); if (tk != NULL) { *code = tk->code; buffer_remove(tty->in, size + 1); @@ -196,6 +222,52 @@ tty_keys_next(struct tty *tty, int *code) return (0); } + /* Not found. Look for an xterm argument and try again. */ + if (len < sizeof tmp && len > 4 && buf[len - 3] == ';') { + memcpy(tmp, buf, len); + arg = tmp[len - 2]; + tmp[len - 3] = tmp[len - 1]; /* restore last */ + log_debug("argument is: %c", arg); + + tk = tty_keys_find(tty, tmp + 1, len - 3, &size); + if (tk != NULL) { + *code = tk->code; + buffer_remove(tty->in, size + 3); + + switch (arg) { + case '8': + *code = KEYC_ADDSFT(*code); + *code = KEYC_ADDESC(*code); + *code = KEYC_ADDCTL(*code); + break; + case '7': + *code = KEYC_ADDESC(*code); + *code = KEYC_ADDCTL(*code); + break; + case '6': + *code = KEYC_ADDSFT(*code); + *code = KEYC_ADDCTL(*code); + break; + case '5': + *code = KEYC_ADDCTL(*code); + break; + case '4': + *code = KEYC_ADDSFT(*code); + *code = KEYC_ADDESC(*code); + break; + case '3': + *code = KEYC_ADDESC(*code); + break; + case '2': + *code = KEYC_ADDSFT(*code); + break; + } + + tty->flags &= ~TTY_ESCAPE; + return (0); + } + } + /* Escape but no key string. If the timer isn't started, start it. */ if (!(tty->flags & TTY_ESCAPE)) { tv.tv_sec = 0; @@ -217,30 +289,31 @@ tty_keys_next(struct tty *tty, int *code) /* Remove the leading escape. */ buffer_remove(tty->in, 1); - size = BUFFER_USED(tty->in); + buf = BUFFER_OUT(tty->in); + len = BUFFER_USED(tty->in); /* If we have no following data, return escape. */ - if (size == 0) { + if (len == 0) { *code = '\033'; return (0); } /* If a normal key follows, return it. */ - if (*BUFFER_OUT(tty->in) != '\033') { - *code = KEYC_ADDESCAPE(buffer_read8(tty->in)); + if (*buf != '\033') { + *code = KEYC_ADDESC(buffer_read8(tty->in)); return (0); } /* Try to look up the key. */ - tk = tty_keys_find(tty, BUFFER_OUT(tty->in) + 1, size - 1, &size); + tk = tty_keys_find(tty, buf + 1, len - 1, &size); if (tk != NULL) { - *code = KEYC_ADDESCAPE(tk->code); + *code = KEYC_ADDESC(tk->code); buffer_remove(tty->in, size + 1); return (0); } /* If not found, return escape-escape. */ - *code = KEYC_ADDESCAPE('\033'); + *code = KEYC_ADDESC('\033'); buffer_remove(tty->in, 1); return (0); }