diff options
-rw-r--r-- | usr.bin/tmux/Makefile | 5 | ||||
-rw-r--r-- | usr.bin/tmux/input-keys.c | 510 | ||||
-rw-r--r-- | usr.bin/tmux/options-table.c | 7 | ||||
-rw-r--r-- | usr.bin/tmux/popup.c | 4 | ||||
-rw-r--r-- | usr.bin/tmux/server.c | 3 | ||||
-rw-r--r-- | usr.bin/tmux/tmux.1 | 12 | ||||
-rw-r--r-- | usr.bin/tmux/tmux.h | 12 | ||||
-rw-r--r-- | usr.bin/tmux/tty-keys.c | 137 | ||||
-rw-r--r-- | usr.bin/tmux/xterm-keys.c | 252 |
9 files changed, 482 insertions, 460 deletions
diff --git a/usr.bin/tmux/Makefile b/usr.bin/tmux/Makefile index d8ae81bdb36..1b47fc04c73 100644 --- a/usr.bin/tmux/Makefile +++ b/usr.bin/tmux/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.105 2020/05/16 16:02:24 nicm Exp $ +# $OpenBSD: Makefile,v 1.106 2020/05/16 16:30:59 nicm Exp $ PROG= tmux SRCS= alerts.c \ @@ -123,8 +123,7 @@ SRCS= alerts.c \ window-customize.c \ window-tree.c \ window.c \ - xmalloc.c \ - xterm-keys.c + xmalloc.c CDIAGFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2 CDIAGFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations diff --git a/usr.bin/tmux/input-keys.c b/usr.bin/tmux/input-keys.c index be7905a127c..78a0a4e031e 100644 --- a/usr.bin/tmux/input-keys.c +++ b/usr.bin/tmux/input-keys.c @@ -1,4 +1,4 @@ -/* $OpenBSD: input-keys.c,v 1.71 2020/04/07 13:38:30 nicm Exp $ */ +/* $OpenBSD: input-keys.c,v 1.72 2020/05/16 16:30:59 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -33,112 +33,331 @@ static void input_key_mouse(struct window_pane *, struct mouse_event *); -struct input_key_ent { - key_code key; - const char *data; +/* Entry in the key tree. */ +struct input_key_entry { + key_code key; + const char *data; - int flags; -#define INPUTKEY_KEYPAD 0x1 /* keypad key */ -#define INPUTKEY_CURSOR 0x2 /* cursor key */ + RB_ENTRY(input_key_entry) entry; }; +RB_HEAD(input_key_tree, input_key_entry); -static const struct input_key_ent input_keys[] = { +/* Tree of input keys. */ +static int input_key_cmp(struct input_key_entry *, + struct input_key_entry *); +RB_GENERATE_STATIC(input_key_tree, input_key_entry, entry, input_key_cmp); +struct input_key_tree input_key_tree = RB_INITIALIZER(&input_key_tree); + +/* List of default keys, the tree is built from this. */ +static struct input_key_entry input_key_defaults[] = { /* Paste keys. */ - { KEYC_PASTE_START, "\033[200~", 0 }, - { KEYC_PASTE_END, "\033[201~", 0 }, + { .key = KEYC_PASTE_START, + .data = "\033[200~" + }, + { .key = KEYC_PASTE_END, + .data = "\033[201~" + }, /* 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_F1|KEYC_SHIFT, "\033[25~", 0 }, - { KEYC_F2|KEYC_SHIFT, "\033[26~", 0 }, - { KEYC_F3|KEYC_SHIFT, "\033[28~", 0 }, - { KEYC_F4|KEYC_SHIFT, "\033[29~", 0 }, - { KEYC_F5|KEYC_SHIFT, "\033[31~", 0 }, - { KEYC_F6|KEYC_SHIFT, "\033[32~", 0 }, - { KEYC_F7|KEYC_SHIFT, "\033[33~", 0 }, - { KEYC_F8|KEYC_SHIFT, "\033[34~", 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_BTAB, "\033[Z", 0 }, - - /* - * Arrow keys. Cursor versions must come first. The codes are toggled - * between CSI and SS3 versions when ctrl is pressed. - */ - { KEYC_UP|KEYC_CTRL, "\033[A", INPUTKEY_CURSOR }, - { KEYC_DOWN|KEYC_CTRL, "\033[B", INPUTKEY_CURSOR }, - { KEYC_RIGHT|KEYC_CTRL, "\033[C", INPUTKEY_CURSOR }, - { KEYC_LEFT|KEYC_CTRL, "\033[D", INPUTKEY_CURSOR }, - - { KEYC_UP, "\033OA", INPUTKEY_CURSOR }, - { KEYC_DOWN, "\033OB", INPUTKEY_CURSOR }, - { KEYC_RIGHT, "\033OC", INPUTKEY_CURSOR }, - { KEYC_LEFT, "\033OD", INPUTKEY_CURSOR }, - - { KEYC_UP|KEYC_CTRL, "\033OA", 0 }, - { KEYC_DOWN|KEYC_CTRL, "\033OB", 0 }, - { KEYC_RIGHT|KEYC_CTRL, "\033OC", 0 }, - { KEYC_LEFT|KEYC_CTRL, "\033OD", 0 }, - - { KEYC_UP, "\033[A", 0 }, - { KEYC_DOWN, "\033[B", 0 }, - { KEYC_RIGHT, "\033[C", 0 }, - { KEYC_LEFT, "\033[D", 0 }, - - /* Keypad keys. Keypad versions must come first. */ - { KEYC_KP_SLASH, "\033Oo", INPUTKEY_KEYPAD }, - { KEYC_KP_STAR, "\033Oj", INPUTKEY_KEYPAD }, - { KEYC_KP_MINUS, "\033Om", INPUTKEY_KEYPAD }, - { KEYC_KP_SEVEN, "\033Ow", INPUTKEY_KEYPAD }, - { KEYC_KP_EIGHT, "\033Ox", INPUTKEY_KEYPAD }, - { KEYC_KP_NINE, "\033Oy", INPUTKEY_KEYPAD }, - { KEYC_KP_PLUS, "\033Ok", INPUTKEY_KEYPAD }, - { KEYC_KP_FOUR, "\033Ot", INPUTKEY_KEYPAD }, - { KEYC_KP_FIVE, "\033Ou", INPUTKEY_KEYPAD }, - { KEYC_KP_SIX, "\033Ov", INPUTKEY_KEYPAD }, - { KEYC_KP_ONE, "\033Oq", INPUTKEY_KEYPAD }, - { KEYC_KP_TWO, "\033Or", INPUTKEY_KEYPAD }, - { KEYC_KP_THREE, "\033Os", INPUTKEY_KEYPAD }, - { KEYC_KP_ENTER, "\033OM", INPUTKEY_KEYPAD }, - { KEYC_KP_ZERO, "\033Op", INPUTKEY_KEYPAD }, - { KEYC_KP_PERIOD, "\033On", INPUTKEY_KEYPAD }, - - { KEYC_KP_SLASH, "/", 0 }, - { KEYC_KP_STAR, "*", 0 }, - { KEYC_KP_MINUS, "-", 0 }, - { KEYC_KP_SEVEN, "7", 0 }, - { KEYC_KP_EIGHT, "8", 0 }, - { KEYC_KP_NINE, "9", 0 }, - { KEYC_KP_PLUS, "+", 0 }, - { KEYC_KP_FOUR, "4", 0 }, - { KEYC_KP_FIVE, "5", 0 }, - { KEYC_KP_SIX, "6", 0 }, - { KEYC_KP_ONE, "1", 0 }, - { KEYC_KP_TWO, "2", 0 }, - { KEYC_KP_THREE, "3", 0 }, - { KEYC_KP_ENTER, "\n", 0 }, - { KEYC_KP_ZERO, "0", 0 }, - { KEYC_KP_PERIOD, ".", 0 }, + { .key = KEYC_F1, + .data = "\033OP" + }, + { .key = KEYC_F2, + .data = "\033OQ" + }, + { .key = KEYC_F3, + .data = "\033OR" + }, + { .key = KEYC_F4, + .data = "\033OS" + }, + { .key = KEYC_F5, + .data = "\033[15~" + }, + { .key = KEYC_F6, + .data = "\033[17~" + }, + { .key = KEYC_F7, + .data = "\033[18~" + }, + { .key = KEYC_F8, + .data = "\033[19~" + }, + { .key = KEYC_F9, + .data = "\033[20~" + }, + { .key = KEYC_F10, + .data = "\033[21~" + }, + { .key = KEYC_F11, + .data = "\033[23~" + }, + { .key = KEYC_F12, + .data = "\033[24~" + }, + { .key = KEYC_F1|KEYC_SHIFT, + .data = "\033[25~" + }, + { .key = KEYC_F2|KEYC_SHIFT, + .data = "\033[26~" + }, + { .key = KEYC_F3|KEYC_SHIFT, + .data = "\033[28~" + }, + { .key = KEYC_F4|KEYC_SHIFT, + .data = "\033[29~" + }, + { .key = KEYC_F5|KEYC_SHIFT, + .data = "\033[31~" + }, + { .key = KEYC_F6|KEYC_SHIFT, + .data = "\033[32~" + }, + { .key = KEYC_F7|KEYC_SHIFT, + .data = "\033[33~" + }, + { .key = KEYC_F8|KEYC_SHIFT, + .data = "\033[34~" + }, + { .key = KEYC_IC, + .data = "\033[2~" + }, + { .key = KEYC_DC, + .data = "\033[3~" + }, + { .key = KEYC_HOME, + .data = "\033[1~" + }, + { .key = KEYC_END, + .data = "\033[4~" + }, + { .key = KEYC_NPAGE, + .data = "\033[6~" + }, + { .key = KEYC_PPAGE, + .data = "\033[5~" + }, + { .key = KEYC_BTAB, + .data = "\033[Z" + }, + + /* Arrow keys. */ + { .key = KEYC_UP|KEYC_CURSOR, + .data = "\033OA" + }, + { .key = KEYC_DOWN|KEYC_CURSOR, + .data = "\033OB" + }, + { .key = KEYC_RIGHT|KEYC_CURSOR, + .data = "\033OC" + }, + { .key = KEYC_LEFT|KEYC_CURSOR, + .data = "\033OD" + }, + { .key = KEYC_UP, + .data = "\033[A" + }, + { .key = KEYC_DOWN, + .data = "\033[B" + }, + { .key = KEYC_RIGHT, + .data = "\033[C" + }, + { .key = KEYC_LEFT, + .data = "\033[D" + }, + + /* Keypad keys. */ + { .key = KEYC_KP_SLASH|KEYC_KEYPAD, + .data = "\033Oo" + }, + { .key = KEYC_KP_STAR|KEYC_KEYPAD, + .data = "\033Oj" + }, + { .key = KEYC_KP_MINUS|KEYC_KEYPAD, + .data = "\033Om" + }, + { .key = KEYC_KP_SEVEN|KEYC_KEYPAD, + .data = "\033Ow" + }, + { .key = KEYC_KP_EIGHT|KEYC_KEYPAD, + .data = "\033Ox" + }, + { .key = KEYC_KP_NINE|KEYC_KEYPAD, + .data = "\033Oy" + }, + { .key = KEYC_KP_PLUS|KEYC_KEYPAD, + .data = "\033Ok" + }, + { .key = KEYC_KP_FOUR|KEYC_KEYPAD, + .data = "\033Ot" + }, + { .key = KEYC_KP_FIVE|KEYC_KEYPAD, + .data = "\033Ou" + }, + { .key = KEYC_KP_SIX|KEYC_KEYPAD, + .data = "\033Ov" + }, + { .key = KEYC_KP_ONE|KEYC_KEYPAD, + .data = "\033Oq" + }, + { .key = KEYC_KP_TWO|KEYC_KEYPAD, + .data = "\033Or" + }, + { .key = KEYC_KP_THREE|KEYC_KEYPAD, + .data = "\033Os" + }, + { .key = KEYC_KP_ENTER|KEYC_KEYPAD, + .data = "\033OM" + }, + { .key = KEYC_KP_ZERO|KEYC_KEYPAD, + .data = "\033Op" + }, + { .key = KEYC_KP_PERIOD|KEYC_KEYPAD, + .data = "\033On" + }, + { .key = KEYC_KP_SLASH, + .data = "/" + }, + { .key = KEYC_KP_STAR, + .data = "*" + }, + { .key = KEYC_KP_MINUS, + .data = "-" + }, + { .key = KEYC_KP_SEVEN, + .data = "7" + }, + { .key = KEYC_KP_EIGHT, + .data = "8" + }, + { .key = KEYC_KP_NINE, + .data = "9" + }, + { .key = KEYC_KP_PLUS, + .data = "+" + }, + { .key = KEYC_KP_FOUR, + .data = "4" + }, + { .key = KEYC_KP_FIVE, + .data = "5" + }, + { .key = KEYC_KP_SIX, + .data = "6" + }, + { .key = KEYC_KP_ONE, + .data = "1" + }, + { .key = KEYC_KP_TWO, + .data = "2" + }, + { .key = KEYC_KP_THREE, + .data = "3" + }, + { .key = KEYC_KP_ENTER, + .data = "\n" + }, + { .key = KEYC_KP_ZERO, + .data = "0" + }, + { .key = KEYC_KP_PERIOD, + .data = "." + }, + + /* Keys with an embedded modifier. */ + { .key = KEYC_F1|KEYC_XTERM, + .data = "\033[1;_P" + }, + { .key = KEYC_F2|KEYC_XTERM, + .data = "\033[1;_Q" + }, + { .key = KEYC_F3|KEYC_XTERM, + .data = "\033[1;_R" + }, + { .key = KEYC_F4|KEYC_XTERM, + .data = "\033[1;_S" + }, + { .key = KEYC_F5|KEYC_XTERM, + .data = "\033[15;_~" + }, + { .key = KEYC_F6|KEYC_XTERM, + .data = "\033[17;_~" + }, + { .key = KEYC_F7|KEYC_XTERM, + .data = "\033[18;_~" + }, + { .key = KEYC_F8|KEYC_XTERM, + .data = "\033[19;_~" + }, + { .key = KEYC_F9|KEYC_XTERM, + .data = "\033[20;_~" + }, + { .key = KEYC_F10|KEYC_XTERM, + .data = "\033[21;_~" + }, + { .key = KEYC_F11|KEYC_XTERM, + .data = "\033[23;_~" + }, + { .key = KEYC_F12|KEYC_XTERM, + .data = "\033[24;_~" + }, + { .key = KEYC_UP|KEYC_XTERM, + .data = "\033[1;_A" + }, + { .key = KEYC_DOWN|KEYC_XTERM, + .data = "\033[1;_B" + }, + { .key = KEYC_RIGHT|KEYC_XTERM, + .data = "\033[1;_C" + }, + { .key = KEYC_LEFT|KEYC_XTERM, + .data = "\033[1;_D" + }, + { .key = KEYC_HOME|KEYC_XTERM, + .data = "\033[1;_H" + }, + { .key = KEYC_END|KEYC_XTERM, + .data = "\033[1;_F" + }, + { .key = KEYC_PPAGE|KEYC_XTERM, + .data = "\033[5;_~" + }, + { .key = KEYC_NPAGE|KEYC_XTERM, + .data = "\033[6;_~" + }, + { .key = KEYC_IC|KEYC_XTERM, + .data = "\033[2;_~" + }, + { .key = KEYC_DC|KEYC_XTERM, + .data = "\033[3;_~" } }; +static const key_code input_key_modifiers[] = { + 0, + 0, + KEYC_SHIFT|KEYC_XTERM, + KEYC_ESCAPE|KEYC_XTERM, + KEYC_SHIFT|KEYC_ESCAPE|KEYC_XTERM, + KEYC_CTRL|KEYC_XTERM, + KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM, + KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM, + KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM +}; + +/* Input key comparison function. */ +static int +input_key_cmp(struct input_key_entry *ike1, struct input_key_entry *ike2) +{ + if (ike1->key < ike2->key) + return (-1); + if (ike1->key > ike2->key) + return (1); + return (0); +} /* Split a character into two UTF-8 bytes. */ static size_t -input_split2(u_int c, u_char *dst) +input_key_split2(u_int c, u_char *dst) { if (c > 0x7f) { dst[0] = (c >> 6) | 0xc0; @@ -149,32 +368,63 @@ input_split2(u_int c, u_char *dst) return (1); } +/* Build input key tree. */ +void +input_key_build(void) +{ + struct input_key_entry *ike, *new; + u_int i, j; + char *data; + + for (i = 0; i < nitems(input_key_defaults); i++) { + ike = &input_key_defaults[i]; + if (~ike->key & KEYC_XTERM) { + RB_INSERT(input_key_tree, &input_key_tree, ike); + continue; + } + + for (j = 2; j < nitems(input_key_modifiers); j++) { + data = xstrdup(ike->data); + data[strcspn(data, "_")] = '0' + j; + + new = xcalloc(1, sizeof *new); + new->key = ike->key|input_key_modifiers[j]; + new->data = data; + RB_INSERT(input_key_tree, &input_key_tree, new); + } + } + + RB_FOREACH(ike, input_key_tree, &input_key_tree) { + log_debug("%s: 0x%llx (%s) is %s", __func__, ike->key, + key_string_lookup_key(ike->key), ike->data); + } +} + /* Translate a key code into an output key sequence for a pane. */ int input_key_pane(struct window_pane *wp, key_code key, struct mouse_event *m) { - log_debug("writing key 0x%llx (%s) to %%%u", key, - key_string_lookup_key(key), wp->id); + if (log_get_level() != 0) { + log_debug("writing key 0x%llx (%s) to %%%u", key, + key_string_lookup_key(key), wp->id); + } if (KEYC_IS_MOUSE(key)) { if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id) input_key_mouse(wp, m); return (0); } - return (input_key(wp, wp->screen, wp->event, key)); + return (input_key(wp->screen, wp->event, key)); } /* Translate a key code into an output key sequence. */ int -input_key(struct window_pane *wp, struct screen *s, struct bufferevent *bev, - key_code key) +input_key(struct screen *s, struct bufferevent *bev, key_code key) { - const struct input_key_ent *ike; - u_int i; - size_t dlen; - char *out; - key_code justkey, newkey; - struct utf8_data ud; + struct input_key_entry *ike, entry; + size_t datalen; + key_code justkey, newkey; + struct utf8_data ud; /* Mouse keys need a pane. */ if (KEYC_IS_MOUSE(key)) @@ -217,43 +467,25 @@ input_key(struct window_pane *wp, struct screen *s, struct bufferevent *bev, } /* - * Then try to look this up as an xterm key, if the flag to output them - * is set. + * Look up in the tree. If not in application keypad or cursor mode, + * remove the flags from the key. */ - if (wp == NULL || options_get_number(wp->window->options, "xterm-keys")) { - if ((out = xterm_keys_lookup(key)) != NULL) { - bufferevent_write(bev, out, strlen(out)); - free(out); - return (0); - } - } - key &= ~KEYC_XTERM; - - /* Otherwise look the key up in the table. */ - for (i = 0; i < nitems(input_keys); i++) { - ike = &input_keys[i]; - - if ((ike->flags & INPUTKEY_KEYPAD) && (~s->mode & MODE_KKEYPAD)) - continue; - if ((ike->flags & INPUTKEY_CURSOR) && (~s->mode & MODE_KCURSOR)) - continue; - - if ((key & KEYC_ESCAPE) && (ike->key | KEYC_ESCAPE) == key) - break; - if (ike->key == key) - break; - } - if (i == nitems(input_keys)) { + if (~s->mode & MODE_KKEYPAD) + key &= ~KEYC_KEYPAD; + if (~s->mode & MODE_KCURSOR) + key &= ~KEYC_CURSOR; + entry.key = key; + if ((ike = RB_FIND(input_key_tree, &input_key_tree, &entry)) == NULL) { log_debug("key 0x%llx missing", key); return (-1); } - dlen = strlen(ike->data); + datalen = strlen(ike->data); log_debug("found key 0x%llx: \"%s\"", key, ike->data); /* Prefix a \033 for escape. */ if (key & KEYC_ESCAPE) bufferevent_write(bev, "\033", 1); - bufferevent_write(bev, ike->data, dlen); + bufferevent_write(bev, ike->data, datalen); return (0); } @@ -309,9 +541,9 @@ input_key_get_mouse(struct screen *s, struct mouse_event *m, u_int x, u_int y, if (m->b > 0x7ff - 32 || x > 0x7ff - 33 || y > 0x7ff - 33) return (0); len = xsnprintf(buf, sizeof buf, "\033[M"); - len += input_split2(m->b + 32, &buf[len]); - len += input_split2(x + 33, &buf[len]); - len += input_split2(y + 33, &buf[len]); + len += input_key_split2(m->b + 32, &buf[len]); + len += input_key_split2(x + 33, &buf[len]); + len += input_key_split2(y + 33, &buf[len]); } else { if (m->b > 223) return (0); diff --git a/usr.bin/tmux/options-table.c b/usr.bin/tmux/options-table.c index 51907ec4051..cfd4d304bb6 100644 --- a/usr.bin/tmux/options-table.c +++ b/usr.bin/tmux/options-table.c @@ -1,4 +1,4 @@ -/* $OpenBSD: options-table.c,v 1.129 2020/05/16 16:26:34 nicm Exp $ */ +/* $OpenBSD: options-table.c,v 1.130 2020/05/16 16:30:59 nicm Exp $ */ /* * Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -1053,11 +1053,12 @@ const struct options_table_entry options_table[] = { "bottom." }, - { .name = "xterm-keys", + { .name = "xterm-keys", /* no longer used */ .type = OPTIONS_TABLE_FLAG, .scope = OPTIONS_TABLE_WINDOW, .default_num = 1, - .text = "Whether xterm-style function key sequences should be sent." + .text = "Whether xterm-style function key sequences should be sent. " + "This option is no longer used." }, /* Hook options. */ diff --git a/usr.bin/tmux/popup.c b/usr.bin/tmux/popup.c index 20175b5dcfe..6966d8292f9 100644 --- a/usr.bin/tmux/popup.c +++ b/usr.bin/tmux/popup.c @@ -1,4 +1,4 @@ -/* $OpenBSD: popup.c,v 1.17 2020/05/16 16:13:09 nicm Exp $ */ +/* $OpenBSD: popup.c,v 1.18 2020/05/16 16:30:59 nicm Exp $ */ /* * Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -329,7 +329,7 @@ popup_key_cb(struct client *c, struct key_event *event) bufferevent_write(job_get_event(pd->job), buf, len); return (0); } - input_key(NULL, &pd->s, job_get_event(pd->job), event->key); + input_key(&pd->s, job_get_event(pd->job), event->key); return (0); } diff --git a/usr.bin/tmux/server.c b/usr.bin/tmux/server.c index 0cfbb5fce48..3ccba1652f5 100644 --- a/usr.bin/tmux/server.c +++ b/usr.bin/tmux/server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server.c,v 1.191 2020/05/16 16:07:55 nicm Exp $ */ +/* $OpenBSD: server.c,v 1.192 2020/05/16 16:30:59 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -199,6 +199,7 @@ server_start(struct tmuxproc *client, int flags, struct event_base *base, "tty ps", NULL) != 0) fatal("pledge failed"); + input_key_build(); RB_INIT(&windows); RB_INIT(&all_window_panes); TAILQ_INIT(&clients); diff --git a/usr.bin/tmux/tmux.1 b/usr.bin/tmux/tmux.1 index 7781f15bebc..972dec9dcef 100644 --- a/usr.bin/tmux/tmux.1 +++ b/usr.bin/tmux/tmux.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: tmux.1,v 1.770 2020/05/16 16:26:34 nicm Exp $ +.\" $OpenBSD: tmux.1,v 1.771 2020/05/16 16:30:59 nicm Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> .\" @@ -4054,16 +4054,6 @@ option. .Xc If this option is set, searches will wrap around the end of the pane contents. The default is on. -.Pp -.It Xo Ic xterm-keys -.Op Ic on | off -.Xc -If this option is set, -.Nm -will generate -.Xr xterm 1 -style -function key sequences; these have a number included to indicate modifiers such -as Shift, Alt or Ctrl. .El .Pp Available pane options are: diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h index ae5dde53643..a1fb1519853 100644 --- a/usr.bin/tmux/tmux.h +++ b/usr.bin/tmux/tmux.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.h,v 1.1043 2020/05/16 16:26:34 nicm Exp $ */ +/* $OpenBSD: tmux.h,v 1.1044 2020/05/16 16:30:59 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -123,6 +123,8 @@ struct winlink; #define KEYC_SHIFT 0x0400000000000ULL #define KEYC_XTERM 0x0800000000000ULL #define KEYC_LITERAL 0x1000000000000ULL +#define KEYC_KEYPAD 0x2000000000000ULL +#define KEYC_CURSOR 0x4000000000000ULL /* Available user keys. */ #define KEYC_NUSER 1000 @@ -2415,16 +2417,12 @@ void input_parse_screen(struct input_ctx *, struct screen *, screen_write_init_ctx_cb, void *, u_char *, size_t); /* input-key.c */ +void input_key_build(void); int input_key_pane(struct window_pane *, key_code, struct mouse_event *); -int input_key(struct window_pane *, struct screen *, struct bufferevent *, - key_code); +int input_key(struct screen *, struct bufferevent *, key_code); int input_key_get_mouse(struct screen *, struct mouse_event *, u_int, u_int, const char **, size_t *); -/* xterm-keys.c */ -char *xterm_keys_lookup(key_code); -int xterm_keys_find(const char *, size_t, size_t *, key_code *); - /* colour.c */ int colour_find_rgb(u_char, u_char, u_char); int colour_join_rgb(u_char, u_char, u_char); diff --git a/usr.bin/tmux/tty-keys.c b/usr.bin/tmux/tty-keys.c index c6191878cd1..c9b6af525a8 100644 --- a/usr.bin/tmux/tty-keys.c +++ b/usr.bin/tmux/tty-keys.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tty-keys.c,v 1.131 2020/05/16 15:41:54 nicm Exp $ */ +/* $OpenBSD: tty-keys.c,v 1.132 2020/05/16 16:30:59 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -69,33 +69,33 @@ static const struct tty_default_key_raw tty_default_raw_keys[] = { * put the terminal into keypad_xmit mode. Translation of numbers * mode/applications mode is done in input-keys.c. */ - { "\033Oo", KEYC_KP_SLASH }, - { "\033Oj", KEYC_KP_STAR }, - { "\033Om", KEYC_KP_MINUS }, - { "\033Ow", KEYC_KP_SEVEN }, - { "\033Ox", KEYC_KP_EIGHT }, - { "\033Oy", KEYC_KP_NINE }, - { "\033Ok", KEYC_KP_PLUS }, - { "\033Ot", KEYC_KP_FOUR }, - { "\033Ou", KEYC_KP_FIVE }, - { "\033Ov", KEYC_KP_SIX }, - { "\033Oq", KEYC_KP_ONE }, - { "\033Or", KEYC_KP_TWO }, - { "\033Os", KEYC_KP_THREE }, - { "\033OM", KEYC_KP_ENTER }, - { "\033Op", KEYC_KP_ZERO }, - { "\033On", KEYC_KP_PERIOD }, + { "\033Oo", KEYC_KP_SLASH|KEYC_KEYPAD }, + { "\033Oj", KEYC_KP_STAR|KEYC_KEYPAD }, + { "\033Om", KEYC_KP_MINUS|KEYC_KEYPAD }, + { "\033Ow", KEYC_KP_SEVEN|KEYC_KEYPAD }, + { "\033Ox", KEYC_KP_EIGHT|KEYC_KEYPAD }, + { "\033Oy", KEYC_KP_NINE|KEYC_KEYPAD }, + { "\033Ok", KEYC_KP_PLUS|KEYC_KEYPAD }, + { "\033Ot", KEYC_KP_FOUR|KEYC_KEYPAD }, + { "\033Ou", KEYC_KP_FIVE|KEYC_KEYPAD }, + { "\033Ov", KEYC_KP_SIX|KEYC_KEYPAD }, + { "\033Oq", KEYC_KP_ONE|KEYC_KEYPAD }, + { "\033Or", KEYC_KP_TWO|KEYC_KEYPAD }, + { "\033Os", KEYC_KP_THREE|KEYC_KEYPAD }, + { "\033OM", KEYC_KP_ENTER|KEYC_KEYPAD }, + { "\033Op", KEYC_KP_ZERO|KEYC_KEYPAD }, + { "\033On", KEYC_KP_PERIOD|KEYC_KEYPAD }, /* Arrow keys. */ - { "\033OA", KEYC_UP }, - { "\033OB", KEYC_DOWN }, - { "\033OC", KEYC_RIGHT }, - { "\033OD", KEYC_LEFT }, + { "\033OA", KEYC_UP|KEYC_CURSOR }, + { "\033OB", KEYC_DOWN|KEYC_CURSOR }, + { "\033OC", KEYC_RIGHT|KEYC_CURSOR }, + { "\033OD", KEYC_LEFT|KEYC_CURSOR }, - { "\033[A", KEYC_UP }, - { "\033[B", KEYC_DOWN }, - { "\033[C", KEYC_RIGHT }, - { "\033[D", KEYC_LEFT }, + { "\033[A", KEYC_UP|KEYC_CURSOR }, + { "\033[B", KEYC_DOWN|KEYC_CURSOR }, + { "\033[C", KEYC_RIGHT|KEYC_CURSOR }, + { "\033[D", KEYC_LEFT|KEYC_CURSOR }, /* Other (xterm) "cursor" keys. */ { "\033OH", KEYC_HOME }, @@ -182,11 +182,59 @@ static const struct tty_default_key_raw tty_default_raw_keys[] = { { "\033[201~", KEYC_PASTE_END }, }; +/* Default xterm keys. */ +struct tty_default_key_xterm { + const char *template; + key_code key; +}; +static const struct tty_default_key_xterm tty_default_xterm_keys[] = { + { "\033[1;_P", KEYC_F1 }, + { "\033O1;_P", KEYC_F1 }, + { "\033O_P", KEYC_F1 }, + { "\033[1;_Q", KEYC_F2 }, + { "\033O1;_Q", KEYC_F2 }, + { "\033O_Q", KEYC_F2 }, + { "\033[1;_R", KEYC_F3 }, + { "\033O1;_R", KEYC_F3 }, + { "\033O_R", KEYC_F3 }, + { "\033[1;_S", KEYC_F4 }, + { "\033O1;_S", KEYC_F4 }, + { "\033O_S", KEYC_F4 }, + { "\033[15;_~", KEYC_F5 }, + { "\033[17;_~", KEYC_F6 }, + { "\033[18;_~", KEYC_F7 }, + { "\033[19;_~", KEYC_F8 }, + { "\033[20;_~", KEYC_F9 }, + { "\033[21;_~", KEYC_F10 }, + { "\033[23;_~", KEYC_F11 }, + { "\033[24;_~", KEYC_F12 }, + { "\033[1;_A", KEYC_UP }, + { "\033[1;_B", KEYC_DOWN }, + { "\033[1;_C", KEYC_RIGHT }, + { "\033[1;_D", KEYC_LEFT }, + { "\033[1;_H", KEYC_HOME }, + { "\033[1;_F", KEYC_END }, + { "\033[5;_~", KEYC_PPAGE }, + { "\033[6;_~", KEYC_NPAGE }, + { "\033[2;_~", KEYC_IC }, + { "\033[3;_~", KEYC_DC }, +}; +static const key_code tty_default_xterm_modifiers[] = { + 0, + 0, + KEYC_SHIFT|KEYC_XTERM, + KEYC_ESCAPE|KEYC_XTERM, + KEYC_SHIFT|KEYC_ESCAPE|KEYC_XTERM, + KEYC_CTRL|KEYC_XTERM, + KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM, + KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM, + KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM +}; + /* - * Default terminfo(5) keys. Any keys that have builtin modifiers - * (that is, where the key itself contains the modifiers) has the - * KEYC_XTERM flag set so a leading escape is not treated as meta (and - * probably removed). + * Default terminfo(5) keys. Any keys that have builtin modifiers (that is, + * where the key itself contains the modifiers) has the KEYC_XTERM flag set so + * a leading escape is not treated as meta (and probably removed). */ struct tty_default_key_code { enum tty_code_code code; @@ -272,10 +320,10 @@ static const struct tty_default_key_code tty_default_code_keys[] = { { TTYC_KCBT, KEYC_BTAB }, /* Arrow keys from terminfo. */ - { TTYC_KCUU1, KEYC_UP }, - { TTYC_KCUD1, KEYC_DOWN }, - { TTYC_KCUB1, KEYC_LEFT }, - { TTYC_KCUF1, KEYC_RIGHT }, + { TTYC_KCUU1, KEYC_UP|KEYC_CURSOR }, + { TTYC_KCUD1, KEYC_DOWN|KEYC_CURSOR }, + { TTYC_KCUB1, KEYC_LEFT|KEYC_CURSOR }, + { TTYC_KCUF1, KEYC_RIGHT|KEYC_CURSOR }, /* Key and modifier capabilities. */ { TTYC_KDC2, KEYC_DC|KEYC_SHIFT|KEYC_XTERM }, @@ -403,17 +451,30 @@ void tty_keys_build(struct tty *tty) { const struct tty_default_key_raw *tdkr; + const struct tty_default_key_xterm *tdkx; const struct tty_default_key_code *tdkc; - u_int i; + u_int i, j; const char *s; struct options_entry *o; struct options_array_item *a; union options_value *ov; + char copy[16]; + key_code key; if (tty->key_tree != NULL) tty_keys_free(tty); tty->key_tree = NULL; + for (i = 0; i < nitems(tty_default_xterm_keys); i++) { + tdkx = &tty_default_xterm_keys[i]; + for (j = 2; j < nitems(tty_default_xterm_modifiers); j++) { + strlcpy(copy, tdkx->template, sizeof copy); + copy[strcspn(copy, "_")] = '0' + j; + + key = tdkx->key|tty_default_xterm_modifiers[j]; + tty_keys_add(tty, copy, key); + } + } for (i = 0; i < nitems(tty_default_raw_keys); i++) { tdkr = &tty_default_raw_keys[i]; @@ -516,7 +577,6 @@ tty_keys_next1(struct tty *tty, const char *buf, size_t len, key_code *key, enum utf8_state more; u_int i; wchar_t wc; - int n; log_debug("%s: next key is %zu (%.*s) (expired=%d)", c->name, len, (int)len, buf, expired); @@ -534,13 +594,6 @@ tty_keys_next1(struct tty *tty, const char *buf, size_t len, key_code *key, return (0); } - /* Is this an an xterm(1) key? */ - n = xterm_keys_find(buf, len, size, key); - if (n == 0) - return (0); - if (n == 1 && !expired) - return (1); - /* Is this valid UTF-8? */ more = utf8_open(&ud, (u_char)*buf); if (more == UTF8_MORE) { diff --git a/usr.bin/tmux/xterm-keys.c b/usr.bin/tmux/xterm-keys.c deleted file mode 100644 index 36e7542ba46..00000000000 --- a/usr.bin/tmux/xterm-keys.c +++ /dev/null @@ -1,252 +0,0 @@ -/* $OpenBSD: xterm-keys.c,v 1.22 2017/05/07 21:25:59 nicm Exp $ */ - -/* - * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <sys/types.h> - -#include <string.h> - -#include "tmux.h" - -/* - * xterm-style function keys append one of the following values before the last - * character: - * - * 2 Shift - * 3 Alt - * 4 Shift + Alt - * 5 Ctrl - * 6 Shift + Ctrl - * 7 Alt + Ctrl - * 8 Shift + Alt + Ctrl - * - * Rather than parsing them, just match against a table. - * - * There are three forms for F1-F4 (\\033O_P and \\033O1;_P and \\033[1;_P). - * We accept any but always output the latter (it comes first in the table). - */ - -static int xterm_keys_match(const char *, const char *, size_t, size_t *, - key_code *); -static int xterm_keys_modifiers(const char *, size_t, size_t *, - key_code *); - -struct xterm_keys_entry { - key_code key; - const char *template; -}; - -static const struct xterm_keys_entry xterm_keys_table[] = { - { KEYC_F1, "\033[1;_P" }, - { KEYC_F1, "\033O1;_P" }, - { KEYC_F1, "\033O_P" }, - { KEYC_F2, "\033[1;_Q" }, - { KEYC_F2, "\033O1;_Q" }, - { KEYC_F2, "\033O_Q" }, - { KEYC_F3, "\033[1;_R" }, - { KEYC_F3, "\033O1;_R" }, - { KEYC_F3, "\033O_R" }, - { KEYC_F4, "\033[1;_S" }, - { KEYC_F4, "\033O1;_S" }, - { KEYC_F4, "\033O_S" }, - { KEYC_F5, "\033[15;_~" }, - { KEYC_F6, "\033[17;_~" }, - { KEYC_F7, "\033[18;_~" }, - { KEYC_F8, "\033[19;_~" }, - { KEYC_F9, "\033[20;_~" }, - { KEYC_F10, "\033[21;_~" }, - { KEYC_F11, "\033[23;_~" }, - { KEYC_F12, "\033[24;_~" }, - { KEYC_UP, "\033[1;_A" }, - { KEYC_DOWN, "\033[1;_B" }, - { KEYC_RIGHT, "\033[1;_C" }, - { KEYC_LEFT, "\033[1;_D" }, - { KEYC_HOME, "\033[1;_H" }, - { KEYC_END, "\033[1;_F" }, - { KEYC_PPAGE, "\033[5;_~" }, - { KEYC_NPAGE, "\033[6;_~" }, - { KEYC_IC, "\033[2;_~" }, - { KEYC_DC, "\033[3;_~" }, - - { '!', "\033[27;_;33~" }, - { '#', "\033[27;_;35~" }, - { '(', "\033[27;_;40~" }, - { ')', "\033[27;_;41~" }, - { '+', "\033[27;_;43~" }, - { ',', "\033[27;_;44~" }, - { '-', "\033[27;_;45~" }, - { '.', "\033[27;_;46~" }, - { '0', "\033[27;_;48~" }, - { '1', "\033[27;_;49~" }, - { '2', "\033[27;_;50~" }, - { '3', "\033[27;_;51~" }, - { '4', "\033[27;_;52~" }, - { '5', "\033[27;_;53~" }, - { '6', "\033[27;_;54~" }, - { '7', "\033[27;_;55~" }, - { '8', "\033[27;_;56~" }, - { '9', "\033[27;_;57~" }, - { ':', "\033[27;_;58~" }, - { ';', "\033[27;_;59~" }, - { '<', "\033[27;_;60~" }, - { '=', "\033[27;_;61~" }, - { '>', "\033[27;_;62~" }, - { '?', "\033[27;_;63~" }, - { '\'', "\033[27;_;39~" }, - { '\r', "\033[27;_;13~" }, - { '\t', "\033[27;_;9~" }, -}; - -/* - * Match key against buffer, treating _ as a wildcard. Return -1 for no match, - * 0 for match, 1 if the end of the buffer is reached (need more data). - */ -static int -xterm_keys_match(const char *template, const char *buf, size_t len, - size_t *size, key_code *modifiers) -{ - size_t pos; - int retval; - - *modifiers = 0; - - if (len == 0) - return (0); - - pos = 0; - do { - if (*template == '_') { - retval = xterm_keys_modifiers(buf, len, &pos, - modifiers); - if (retval != 0) - return (retval); - continue; - } - if (buf[pos] != *template) - return (-1); - pos++; - } while (*++template != '\0' && pos != len); - - if (*template != '\0') /* partial */ - return (1); - - *size = pos; - return (0); -} - -/* Find modifiers from buffer. */ -static int -xterm_keys_modifiers(const char *buf, size_t len, size_t *pos, - key_code *modifiers) -{ - u_int flags; - - if (len - *pos < 2) - return (1); - - if (buf[*pos] < '0' || buf[*pos] > '9') - return (-1); - flags = buf[(*pos)++] - '0'; - if (buf[*pos] >= '0' && buf[*pos] <= '9') - flags = (flags * 10) + (buf[(*pos)++] - '0'); - flags -= 1; - - *modifiers = 0; - if (flags & 1) - *modifiers |= KEYC_SHIFT; - if (flags & 2) - *modifiers |= KEYC_ESCAPE; - if (flags & 4) - *modifiers |= KEYC_CTRL; - if (flags & 8) - *modifiers |= KEYC_ESCAPE; - return (0); -} - -/* - * Lookup key from a buffer against the table. Returns 0 for found (and the - * key), -1 for not found, 1 for partial match. - */ -int -xterm_keys_find(const char *buf, size_t len, size_t *size, key_code *key) -{ - const struct xterm_keys_entry *entry; - u_int i; - int matched; - key_code modifiers; - - for (i = 0; i < nitems(xterm_keys_table); i++) { - entry = &xterm_keys_table[i]; - - matched = xterm_keys_match(entry->template, buf, len, size, - &modifiers); - if (matched == -1) - continue; - if (matched == 0) - *key = (entry->key|modifiers|KEYC_XTERM); - return (matched); - } - return (-1); -} - -/* Lookup a key number from the table. */ -char * -xterm_keys_lookup(key_code key) -{ - const struct xterm_keys_entry *entry; - u_int i; - key_code modifiers; - char *out; - - modifiers = 1; - if (key & KEYC_SHIFT) - modifiers += 1; - if (key & KEYC_ESCAPE) - modifiers += 2; - if (key & KEYC_CTRL) - modifiers += 4; - - /* - * If the key has no modifiers, return NULL and let it fall through to - * the normal lookup. - */ - if (modifiers == 1) - return (NULL); - - /* - * If this has the escape modifier, but was not originally an xterm - * key, it may be a genuine escape + key. So don't pass it through as - * an xterm key or programs like vi may be confused. - */ - if ((key & (KEYC_ESCAPE|KEYC_XTERM)) == KEYC_ESCAPE) - return (NULL); - - /* Otherwise, find the key in the table. */ - key &= KEYC_MASK_KEY; - for (i = 0; i < nitems(xterm_keys_table); i++) { - entry = &xterm_keys_table[i]; - if (key == entry->key) - break; - } - if (i == nitems(xterm_keys_table)) - return (NULL); - - /* Copy the template and replace the modifier. */ - out = xstrdup(entry->template); - out[strcspn(out, "_")] = '0' + modifiers; - return (out); -} |