From a88eba380552a4e9692e96577cbe006380da55c3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 12 Jan 2009 22:48:00 +0000 Subject: [PATCH] More hacks for key handling. --- CHANGES | 4 +- input-keys.c | 85 ++++++++++++------------ tmux.h | 4 +- tty-keys.c | 179 ++++++++++++++++++++++++++++++--------------------- 4 files changed, 150 insertions(+), 122 deletions(-) diff --git a/CHANGES b/CHANGES index 764342d2..6e4e9c8f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,6 @@ 12 January 2009 -* More hacks for key handling. +* Yet more hacks for key handling. Think it is just about working now. * Two commands, resize-pane-up and resize-pane-down to resize a pane. * Make the window pane code handle panes of different sizes, and add a -l and -p arguments to split-window to specify the new window size in lines @@ -884,7 +884,7 @@ (including mutt, emacs). No status bar yet and no key remapping or other customisation. -$Id: CHANGES,v 1.197 2009-01-12 21:47:03 nicm Exp $ +$Id: CHANGES,v 1.198 2009-01-12 22:48:00 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/input-keys.c b/input-keys.c index 26ab8b92..a0100c79 100644 --- a/input-keys.c +++ b/input-keys.c @@ -1,4 +1,4 @@ -/* $Id: input-keys.c,v 1.22 2009-01-12 21:47:03 nicm Exp $ */ +/* $Id: input-keys.c,v 1.23 2009-01-12 22:48:00 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -31,31 +31,31 @@ struct input_key_ent { int flags; #define INPUTKEY_KEYPAD 0x1 /* keypad key */ #define INPUTKEY_CURSOR 0x2 /* cursor key */ -#define INPUTKEY_MODIFIER 0x4 /* may be adjusted by modifiers */ +#define INPUTKEY_CTRL 0x4 /* may be modified with ctrl */ #define INPUTKEY_XTERM 0x4 /* may have xterm argument appended */ }; struct input_key_ent input_keys[] = { /* Function keys. */ - { 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 }, - { KEYC_BTAB, "\033[Z", INPUTKEY_MODIFIER }, + { KEYC_F1, "\033OP", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F2, "\033OQ", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F3, "\033OR", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F4, "\033OS", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F5, "\033[15~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F6, "\033[17~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F7, "\033[18~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F8, "\033[19~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F9, "\033[20~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F10, "\033[21~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F11, "\033[23~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F12, "\033[24~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_IC, "\033[2~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_DC, "\033[3~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_HOME, "\033[1~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_END, "\033[4~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_NPAGE, "\033[6~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_PPAGE, "\033[5~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_BTAB, "\033[Z", INPUTKEY_CTRL }, /* Arrow keys. Cursor versions must come first. */ { KEYC_UP, "\033OA", INPUTKEY_CURSOR }, @@ -121,6 +121,7 @@ input_key(struct window_pane *wp, int key) u_int i; char ch; size_t dlen; + int xterm_keys; log_debug2("writing key 0x%x", key); @@ -141,12 +142,12 @@ input_key(struct window_pane *wp, int key) !(wp->screen->mode & MODE_KCURSOR)) continue; - 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) + if (KEYC_ISESC(key) && KEYC_ADDESC(ike->key) == key) + break; + if (KEYC_ISSFT(key) && KEYC_ADDSFT(ike->key) == key) + break; + if (KEYC_ISCTL(key) && KEYC_ADDCTL(ike->key) == key) { + if (ike->flags & INPUTKEY_CTRL) break; } if (ike->key == key) @@ -160,9 +161,12 @@ input_key(struct window_pane *wp, int key) log_debug2("found key 0x%x: \"%s\"", key, ike->data); - if (ike->flags & INPUTKEY_XTERM && - options_get_number(&wp->window->options, "xterm-keys")) { - /* In xterm keys mode, append modifier argument. */ + /* + * If in xterm keys mode, work out and append the modifier as an + * argument. + */ + xterm_keys = options_get_number(&wp->window->options, "xterm-keys"); + if (xterm_keys && ike->flags & INPUTKEY_XTERM) { ch = '\0'; if (KEYC_ISSFT(key) && KEYC_ISESC(key) && KEYC_ISCTL(key)) ch = '8'; @@ -179,7 +183,6 @@ input_key(struct window_pane *wp, int key) else if (KEYC_ISSFT(key)) ch = '2'; if (ch != '\0') { - log_debug("output argument is: %c", ch); buffer_write(wp->out, ike->data, dlen - 1); buffer_write8(wp->out, ';'); buffer_write8(wp->out, ch); @@ -188,21 +191,17 @@ input_key(struct window_pane *wp, int key) buffer_write(wp->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(wp->out, '\033'); - if (!KEYC_ISCTL(key)) { - buffer_write(wp->out, ike->data, dlen); - return; - } + + /* + * Not in xterm mode. Prefix a \033 for escape, and set bit 5 of the + * last byte for ctrl. + */ + if (KEYC_ISESC(key)) + buffer_write8(wp->out, '\033'); + if (KEYC_ISCTL(key) && ike->flags & INPUTKEY_CTRL) { buffer_write(wp->out, ike->data, dlen - 1); buffer_write8(wp->out, ike->data[dlen - 1] ^ 0x20); return; } - buffer_write(wp->out, ike->data, dlen); } diff --git a/tmux.h b/tmux.h index f7724f52..dbc7abcc 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.226 2009-01-12 19:23:14 nicm Exp $ */ +/* $Id: tmux.h,v 1.227 2009-01-12 22:48:00 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -670,7 +670,7 @@ struct tty_key { char *string; int flags; -#define TTYKEY_MODIFIER 0x1 +#define TTYKEY_CTRL 0x1 #define TTYKEY_RAW 0x2 RB_ENTRY(tty_key) entry; diff --git a/tty-keys.c b/tty-keys.c index 187c949d..6e57462a 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1,4 +1,4 @@ -/* $Id: tty-keys.c,v 1.19 2009-01-12 21:47:03 nicm Exp $ */ +/* $Id: tty-keys.c,v 1.20 2009-01-12 22:48:00 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -24,6 +24,7 @@ #include "tmux.h" void tty_keys_add(struct tty *, const char *, int, int); +int tty_keys_parse_xterm(struct tty *, char *, size_t, size_t *); struct tty_key_ent { enum tty_code_code code; @@ -35,25 +36,25 @@ struct tty_key_ent { struct tty_key_ent tty_keys[] = { /* Function keys. */ - { TTYC_KF1, NULL, KEYC_F1, TTYKEY_MODIFIER }, - { TTYC_KF2, NULL, KEYC_F2, TTYKEY_MODIFIER }, - { TTYC_KF3, NULL, KEYC_F3, TTYKEY_MODIFIER }, - { TTYC_KF4, NULL, KEYC_F4, TTYKEY_MODIFIER }, - { TTYC_KF5, NULL, KEYC_F5, TTYKEY_MODIFIER }, - { TTYC_KF6, NULL, KEYC_F6, TTYKEY_MODIFIER }, - { TTYC_KF7, NULL, KEYC_F7, TTYKEY_MODIFIER }, - { TTYC_KF8, NULL, KEYC_F8, TTYKEY_MODIFIER }, - { TTYC_KF9, NULL, KEYC_F9, TTYKEY_MODIFIER }, - { TTYC_KF10, NULL, KEYC_F10, TTYKEY_MODIFIER }, - { TTYC_KF11, NULL, KEYC_F11, TTYKEY_MODIFIER }, - { TTYC_KF12, NULL, KEYC_F12, TTYKEY_MODIFIER }, - { TTYC_KICH1, NULL, KEYC_IC, TTYKEY_MODIFIER }, - { TTYC_KDCH1, NULL, KEYC_DC, TTYKEY_MODIFIER }, - { TTYC_KHOME, NULL, KEYC_HOME, TTYKEY_MODIFIER }, - { TTYC_KEND, NULL, KEYC_END, TTYKEY_MODIFIER }, - { TTYC_KNP, NULL, KEYC_NPAGE, TTYKEY_MODIFIER }, - { TTYC_KPP, NULL, KEYC_PPAGE, TTYKEY_MODIFIER }, - { TTYC_KCBT, NULL, KEYC_BTAB, TTYKEY_MODIFIER }, + { TTYC_KF1, NULL, KEYC_F1, TTYKEY_CTRL }, + { TTYC_KF2, NULL, KEYC_F2, TTYKEY_CTRL }, + { TTYC_KF3, NULL, KEYC_F3, TTYKEY_CTRL }, + { TTYC_KF4, NULL, KEYC_F4, TTYKEY_CTRL }, + { TTYC_KF5, NULL, KEYC_F5, TTYKEY_CTRL }, + { TTYC_KF6, NULL, KEYC_F6, TTYKEY_CTRL }, + { TTYC_KF7, NULL, KEYC_F7, TTYKEY_CTRL }, + { TTYC_KF8, NULL, KEYC_F8, TTYKEY_CTRL }, + { TTYC_KF9, NULL, KEYC_F9, TTYKEY_CTRL }, + { TTYC_KF10, NULL, KEYC_F10, TTYKEY_CTRL }, + { TTYC_KF11, NULL, KEYC_F11, TTYKEY_CTRL }, + { TTYC_KF12, NULL, KEYC_F12, TTYKEY_CTRL }, + { TTYC_KICH1, NULL, KEYC_IC, TTYKEY_CTRL }, + { TTYC_KDCH1, NULL, KEYC_DC, TTYKEY_CTRL }, + { TTYC_KHOME, NULL, KEYC_HOME, TTYKEY_CTRL }, + { TTYC_KEND, NULL, KEYC_END, TTYKEY_CTRL }, + { TTYC_KNP, NULL, KEYC_NPAGE, TTYKEY_CTRL }, + { TTYC_KPP, NULL, KEYC_PPAGE, TTYKEY_CTRL }, + { TTYC_KCBT, NULL, KEYC_BTAB, TTYKEY_CTRL }, /* Arrow keys. */ { 0, "\033OA", KEYC_UP, TTYKEY_RAW }, @@ -70,16 +71,15 @@ struct tty_key_ent tty_keys[] = { { 0, "\033Ob", KEYC_ADDCTL(KEYC_DOWN), TTYKEY_RAW }, { 0, "\033Oc", KEYC_ADDCTL(KEYC_RIGHT), TTYKEY_RAW }, { 0, "\033Od", KEYC_ADDCTL(KEYC_LEFT), TTYKEY_RAW }, - { 0, "\033[a", KEYC_ADDSFT(KEYC_UP), TTYKEY_RAW }, { 0, "\033[b", KEYC_ADDSFT(KEYC_DOWN), TTYKEY_RAW }, { 0, "\033[c", KEYC_ADDSFT(KEYC_RIGHT), TTYKEY_RAW }, { 0, "\033[d", KEYC_ADDSFT(KEYC_LEFT), TTYKEY_RAW }, - { TTYC_KCUU1, NULL, KEYC_UP, TTYKEY_MODIFIER }, - { TTYC_KCUD1, NULL, KEYC_DOWN, TTYKEY_MODIFIER }, - { TTYC_KCUB1, NULL, KEYC_LEFT, TTYKEY_MODIFIER }, - { TTYC_KCUF1, NULL, KEYC_RIGHT, TTYKEY_MODIFIER }, + { TTYC_KCUU1, NULL, KEYC_UP, TTYKEY_CTRL }, + { TTYC_KCUD1, NULL, KEYC_DOWN, TTYKEY_CTRL }, + { TTYC_KCUB1, NULL, KEYC_LEFT, TTYKEY_CTRL }, + { TTYC_KCUF1, NULL, KEYC_RIGHT, TTYKEY_CTRL }, /* * Numeric keypad. termcap and terminfo are totally confusing for this. @@ -161,7 +161,7 @@ tty_keys_init(struct tty *tty) } tty_keys_add(tty, s + 1, tke->key, tke->flags); - if (tke->flags & TTYKEY_MODIFIER) { + if (tke->flags & TTYKEY_CTRL) { if (strlcpy(tmp, s, sizeof tmp) >= sizeof tmp) continue; tmp[strlen(tmp) - 1] ^= 0x20; @@ -204,6 +204,7 @@ tty_keys_find(struct tty *tty, char *buf, size_t len, size_t *size) tl.string = s; tk = RB_FIND(tty_keys, &tty->ktree, &tl); if (tk != NULL) { + log_debug2("got key: 0x%x", tk->key); xfree(s); return (tk); } @@ -218,7 +219,7 @@ tty_keys_next(struct tty *tty, int *key) { struct tty_key *tk; struct timeval tv; - char arg, *buf, tmp[32]; + char *buf; size_t len, size; buf = BUFFER_OUT(tty->in); @@ -243,55 +244,13 @@ tty_keys_next(struct tty *tty, int *key) return (0); } - /* Not found. Look xterm-style function keys with an argument. */ - if (len < sizeof tmp && len > 4 && buf[len - 3] == ';') { - memcpy(tmp, buf, len); - log_debug("xterm key in: %s", tmp); - arg = tmp[len - 2]; - tmp[3] = tmp[len - 1]; /* move last */ - tmp[4] = '\0'; - log_debug("xterm key out: %s", tmp); - log_debug("argument is: %c", arg); - - tk = tty_keys_find(tty, tmp + 1, len - 3, &size); - if (tk != NULL) { - *key = tk->key; - buffer_remove(tty->in, size + 3); - - switch (arg) { - case '8': - *key = KEYC_ADDSFT(*key); - *key = KEYC_ADDESC(*key); - *key = KEYC_ADDCTL(*key); - break; - case '7': - *key = KEYC_ADDESC(*key); - *key = KEYC_ADDCTL(*key); - break; - case '6': - *key = KEYC_ADDSFT(*key); - *key = KEYC_ADDCTL(*key); - break; - case '5': - *key = KEYC_ADDCTL(*key); - break; - case '4': - *key = KEYC_ADDSFT(*key); - *key = KEYC_ADDESC(*key); - break; - case '3': - *key = KEYC_ADDESC(*key); - break; - case '2': - *key = KEYC_ADDSFT(*key); - break; - } - - tty->flags &= ~TTY_ESCAPE; - return (0); - } + /* Not found. Try to parse xterm-type arguments. */ + if ((*key = tty_keys_parse_xterm(tty, buf, len, &size)) != KEYC_NONE) { + buffer_remove(tty->in, size); + 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; @@ -341,3 +300,73 @@ tty_keys_next(struct tty *tty, int *key) buffer_remove(tty->in, 1); return (0); } + +int +tty_keys_parse_xterm(struct tty *tty, char *buf, size_t len, size_t *size) +{ + struct tty_key *tk; + char tmp[5]; + size_t tmplen; + int key; + + /* + * xterm sequences with modifier keys are of the form: + * + * ^[[1;xD becomes ^[[D + * ^[[5;x~ becomes ^[[5~ + * + * This function is a bit of a hack. Need to figure out what exact + * format and meaning xterm outputs and fix it. XXX + */ + + log_debug("xterm input is: %.*s", (int) len, buf); + if (len != 6 || memcmp(buf, "\033[1;", 4) != 0) + return (KEYC_NONE); + *size = 6; + + tmplen = 0; + tmp[tmplen++] = '['; + if (buf[5] == '~') { + tmp[tmplen++] = buf[2]; + tmp[tmplen++] = '~'; + } else + tmp[tmplen++] = buf[5]; + log_debug("xterm output is: %.*s", (int) tmplen, tmp); + + tk = tty_keys_find(tty, tmp, tmplen, size); + if (tk == NULL) + return (KEYC_NONE); + key = tk->key; + + switch (buf[4]) { + case '8': + key = KEYC_ADDSFT(key); + key = KEYC_ADDESC(key); + key = KEYC_ADDCTL(key); + break; + case '7': + key = KEYC_ADDESC(key); + key = KEYC_ADDCTL(key); + break; + case '6': + key = KEYC_ADDSFT(key); + key = KEYC_ADDCTL(key); + break; + case '5': + key = KEYC_ADDCTL(key); + break; + case '4': + key = KEYC_ADDSFT(key); + key = KEYC_ADDESC(key); + break; + case '3': + key = KEYC_ADDESC(key); + break; + case '2': + key = KEYC_ADDSFT(key); + break; + } + + *size = 6; + return (key); +}