From 04eee2410df4a85005c9562db13a1fec93d7c2e4 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 13 Jan 2020 07:51:54 +0000 Subject: [PATCH 1/2] Treat plausible but invalid keys (like C-BSpace) as literal like any other unrecognised string passed to send-keys. Reported by Anthony Sottile in GitHub issue 2049. --- cmd-send-keys.c | 14 +++++++++++--- input-keys.c | 17 +++++++++-------- tmux.h | 4 ++-- window.c | 14 ++++++++------ 4 files changed, 30 insertions(+), 19 deletions(-) diff --git a/cmd-send-keys.c b/cmd-send-keys.c index ddbab6f7..cc04a73f 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -60,6 +60,9 @@ static struct cmdq_item * cmd_send_keys_inject_key(struct client *c, struct cmd_find_state *fs, struct cmdq_item *item, key_code key) { + struct session *s = fs->s; + struct winlink *wl = fs->wl; + struct window_pane *wp = fs->wp; struct window_mode_entry *wme; struct key_table *table; struct key_binding *bd; @@ -68,7 +71,8 @@ cmd_send_keys_inject_key(struct client *c, struct cmd_find_state *fs, if (wme == NULL || wme->mode->key_table == NULL) { if (options_get_number(fs->wp->window->options, "xterm-keys")) key |= KEYC_XTERM; - window_pane_key(fs->wp, item->client, fs->s, fs->wl, key, NULL); + if (window_pane_key(wp, item->client, s, wl, key, NULL) != 0) + return (NULL); return (item); } table = key_bindings_get_table(wme->mode->key_table(wme), 1); @@ -87,6 +91,7 @@ cmd_send_keys_inject_string(struct client *c, struct cmd_find_state *fs, struct cmdq_item *item, struct args *args, int i) { const char *s = args->argv[i]; + struct cmdq_item *new_item; struct utf8_data *ud, *uc; wchar_t wc; key_code key; @@ -104,8 +109,11 @@ cmd_send_keys_inject_string(struct client *c, struct cmd_find_state *fs, literal = args_has(args, 'l'); if (!literal) { key = key_string_lookup_string(s); - if (key != KEYC_NONE && key != KEYC_UNKNOWN) - return (cmd_send_keys_inject_key(c, fs, item, key)); + if (key != KEYC_NONE && key != KEYC_UNKNOWN) { + new_item = cmd_send_keys_inject_key(c, fs, item, key); + if (new_item != NULL) + return (new_item); + } literal = 1; } if (literal) { diff --git a/input-keys.c b/input-keys.c index 01f9ad9d..5c7e8b1f 100644 --- a/input-keys.c +++ b/input-keys.c @@ -150,7 +150,7 @@ input_split2(u_int c, u_char *dst) } /* Translate a key code into an output key sequence. */ -void +int input_key(struct window_pane *wp, key_code key, struct mouse_event *m) { const struct input_key_ent *ike; @@ -167,14 +167,14 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m) if (KEYC_IS_MOUSE(key)) { if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id) input_key_mouse(wp, m); - return; + return (0); } /* Literal keys go as themselves (can't be more than eight bits). */ if (key & KEYC_LITERAL) { ud.data[0] = (u_char)key; bufferevent_write(wp->event, &ud.data[0], 1); - return; + return (0); } /* Is this backspace? */ @@ -195,15 +195,15 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m) bufferevent_write(wp->event, "\033", 1); ud.data[0] = justkey; bufferevent_write(wp->event, &ud.data[0], 1); - return; + return (0); } if (justkey > 0x7f && justkey < KEYC_BASE) { if (utf8_split(justkey, &ud) != UTF8_DONE) - return; + return (-1); if (key & KEYC_ESCAPE) bufferevent_write(wp->event, "\033", 1); bufferevent_write(wp->event, ud.data, ud.size); - return; + return (0); } /* @@ -214,7 +214,7 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m) if ((out = xterm_keys_lookup(key)) != NULL) { bufferevent_write(wp->event, out, strlen(out)); free(out); - return; + return (0); } } key &= ~KEYC_XTERM; @@ -237,7 +237,7 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m) } if (i == nitems(input_keys)) { log_debug("key 0x%llx missing", key); - return; + return (-1); } dlen = strlen(ike->data); log_debug("found key 0x%llx: \"%s\"", key, ike->data); @@ -246,6 +246,7 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m) if (key & KEYC_ESCAPE) bufferevent_write(wp->event, "\033", 1); bufferevent_write(wp->event, ike->data, dlen); + return (0); } /* Translate mouse and output. */ diff --git a/tmux.h b/tmux.h index 7c7dcc99..75e483c5 100644 --- a/tmux.h +++ b/tmux.h @@ -2275,7 +2275,7 @@ void input_parse(struct window_pane *); void input_parse_buffer(struct window_pane *, u_char *, size_t); /* input-key.c */ -void input_key(struct window_pane *, key_code, struct mouse_event *); +int input_key(struct window_pane *, key_code, struct mouse_event *); /* xterm-keys.c */ char *xterm_keys_lookup(key_code); @@ -2498,7 +2498,7 @@ int window_pane_set_mode(struct window_pane *, struct args *); void window_pane_reset_mode(struct window_pane *); void window_pane_reset_mode_all(struct window_pane *); -void window_pane_key(struct window_pane *, struct client *, +int window_pane_key(struct window_pane *, struct client *, struct session *, struct winlink *, key_code, struct mouse_event *); int window_pane_visible(struct window_pane *); diff --git a/window.c b/window.c index 64c95855..bd25b5d1 100644 --- a/window.c +++ b/window.c @@ -1229,7 +1229,7 @@ window_pane_reset_mode_all(struct window_pane *wp) window_pane_reset_mode(wp); } -void +int window_pane_key(struct window_pane *wp, struct client *c, struct session *s, struct winlink *wl, key_code key, struct mouse_event *m) { @@ -1237,23 +1237,24 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s, struct window_pane *wp2; if (KEYC_IS_MOUSE(key) && m == NULL) - return; + return (-1); wme = TAILQ_FIRST(&wp->modes); if (wme != NULL) { wp->modelast = time(NULL); if (wme->mode->key != NULL) wme->mode->key(wme, c, s, wl, (key & ~KEYC_XTERM), m); - return; + return (0); } if (wp->fd == -1 || wp->flags & PANE_INPUTOFF) - return; + return (0); - input_key(wp, key, m); + if (input_key(wp, key, m) != 0) + return (-1); if (KEYC_IS_MOUSE(key)) - return; + return (0); if (options_get_number(wp->window->options, "synchronize-panes")) { TAILQ_FOREACH(wp2, &wp->window->panes, entry) { if (wp2 != wp && @@ -1264,6 +1265,7 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s, input_key(wp2, key, NULL); } } + return (0); } int From 835a6c0cf088437e318783c96b142c7dc26c290f Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 13 Jan 2020 08:12:53 +0000 Subject: [PATCH 2/2] Be more specific in the DSR we are looking for so it doesn't get confused with mouse sequences. Also set a flag and don't bother checking for it if we have already seen it (same for DA), and don't check if we never asked for it. --- tmux.h | 2 ++ tty-keys.c | 14 ++++++++++++++ tty.c | 5 +++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/tmux.h b/tmux.h index 75e483c5..adc1a240 100644 --- a/tmux.h +++ b/tmux.h @@ -1227,6 +1227,8 @@ struct tty { #define TTY_OPENED 0x20 #define TTY_FOCUS 0x40 #define TTY_BLOCK 0x80 +#define TTY_HAVEDA 0x100 +#define TTY_HAVEDSR 0x200 int flags; struct tty_term *term; diff --git a/tty-keys.c b/tty-keys.c index 5054c424..968f67ca 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1020,6 +1020,8 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len, int flags = 0; *size = 0; + if (tty->flags & TTY_HAVEDA) + return (-1); /* First three bytes are always \033[?. */ if (buf[0] != '\033') @@ -1064,7 +1066,10 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len, for (i = 1; i < n; i++) log_debug("%s: DA feature: %d", c->name, p[i]); log_debug("%s: received DA %.*s", c->name, (int)*size, buf); + tty_set_flags(tty, flags); + tty->flags |= TTY_HAVEDA; + return (0); } @@ -1082,6 +1087,8 @@ tty_keys_device_status_report(struct tty *tty, const char *buf, size_t len, int flags = 0; *size = 0; + if (tty->flags & TTY_HAVEDSR) + return (-1); /* First three bytes are always \033[. */ if (buf[0] != '\033') @@ -1092,6 +1099,10 @@ tty_keys_device_status_report(struct tty *tty, const char *buf, size_t len, return (-1); if (len == 2) return (1); + if (buf[2] != 'I') + return (-1); + if (len == 3) + return (1); /* Copy the rest up to a 'n'. */ for (i = 0; i < (sizeof tmp) - 1 && buf[2 + i] != 'n'; i++) { @@ -1108,6 +1119,9 @@ tty_keys_device_status_report(struct tty *tty, const char *buf, size_t len, if (strncmp(tmp, "ITERM2 ", 7) == 0) flags |= TERM_DECSLRM; log_debug("%s: received DSR %.*s", c->name, (int)*size, buf); + tty_set_flags(tty, flags); + tty->flags |= TTY_HAVEDSR; + return (0); } diff --git a/tty.c b/tty.c index 2d4b4cc0..a1324528 100644 --- a/tty.c +++ b/tty.c @@ -327,8 +327,9 @@ tty_start_tty(struct tty *tty) tty->flags |= TTY_FOCUS; tty_puts(tty, "\033[?1004h"); } - tty_puts(tty, "\033[c\033[1337n"); - } + tty_puts(tty, "\033[c\033[1337n"); /* DA and DSR */ + } else + tty->flags |= (TTY_HAVEDA|TTY_HAVEDSR); tty->flags |= TTY_STARTED; tty_invalidate(tty);