From 39cf9c9d31954198ad73e2b6721a92fe782ee56c Mon Sep 17 00:00:00 2001 From: nicm <nicm> Date: Sat, 12 Dec 2015 18:19:00 +0000 Subject: [PATCH 1/3] Allow prefix and prefix2 to be set to None to disable (useful if you would rather bind the prefix in the root table). --- cmd-bind-key.c | 2 +- cmd-send-keys.c | 23 +++++++++++++---------- cmd-set-option.c | 3 ++- cmd-unbind-key.c | 8 ++++---- input-keys.c | 4 ++-- key-string.c | 40 ++++++++++++++++++++++++---------------- server-client.c | 14 +++++++------- tmux.1 | 11 +++++++++++ tmux.h | 1 + tty-keys.c | 8 ++++---- 10 files changed, 69 insertions(+), 45 deletions(-) diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 1867e814..b13409cb 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -62,7 +62,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq) } key = key_string_lookup_string(args->argv[0]); - if (key == KEYC_NONE) { + if (key == KEYC_NONE || key == KEYC_UNKNOWN) { cmdq_error(cmdq, "unknown key: %s", args->argv[0]); return (CMD_RETURN_ERROR); } diff --git a/cmd-send-keys.c b/cmd-send-keys.c index 73a308ae..1461baa9 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -52,8 +52,8 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq) struct mouse_event *m = &cmdq->item->mouse; struct window_pane *wp; struct session *s; - const u_char *str; - int i; + int i, literal; + const u_char *keystr; key_code key; if (args_has(args, 'M')) { @@ -82,14 +82,17 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq) input_reset(wp); for (i = 0; i < args->argc; i++) { - str = args->argv[i]; - - if (!args_has(args, 'l') && - (key = key_string_lookup_string(str)) != KEYC_NONE) { - window_pane_key(wp, NULL, s, key, NULL); - } else { - for (; *str != '\0'; str++) - window_pane_key(wp, NULL, s, *str, NULL); + literal = args_has(args, 'l'); + if (!literal) { + key = key_string_lookup_string(args->argv[i]); + if (key != KEYC_NONE && key != KEYC_UNKNOWN) + window_pane_key(wp, NULL, s, key, NULL); + else + literal = 1; + } + if (literal) { + for (keystr = args->argv[i]; *keystr != '\0'; keystr++) + window_pane_key(wp, NULL, s, *keystr, NULL); } } diff --git a/cmd-set-option.c b/cmd-set-option.c index 7de91aa2..e2a4768c 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -396,7 +396,8 @@ cmd_set_option_key(__unused struct cmd *self, struct cmd_q *cmdq, { key_code key; - if ((key = key_string_lookup_string(value)) == KEYC_NONE) { + key = key_string_lookup_string(value); + if (key == KEYC_UNKNOWN) { cmdq_error(cmdq, "bad key: %s", value); return (NULL); } diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index cec538c0..66a4525e 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -51,7 +51,7 @@ cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_ERROR); } key = key_string_lookup_string(args->argv[0]); - if (key == KEYC_NONE) { + if (key == KEYC_NONE || key == KEYC_UNKNOWN) { cmdq_error(cmdq, "unknown key: %s", args->argv[0]); return (CMD_RETURN_ERROR); } @@ -60,13 +60,13 @@ cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq) cmdq_error(cmdq, "key given with -a"); return (CMD_RETURN_ERROR); } - key = KEYC_NONE; + key = KEYC_UNKNOWN; } if (args_has(args, 't')) return (cmd_unbind_key_mode_table(self, cmdq, key)); - if (key == KEYC_NONE) { + if (key == KEYC_UNKNOWN) { tablename = args_get(args, 'T'); if (tablename == NULL) { key_bindings_remove_table("root"); @@ -109,7 +109,7 @@ cmd_unbind_key_mode_table(struct cmd *self, struct cmd_q *cmdq, key_code key) return (CMD_RETURN_ERROR); } - if (key == KEYC_NONE) { + if (key == KEYC_UNKNOWN) { while (!RB_EMPTY(mtab->tree)) { mbind = RB_ROOT(mtab->tree); RB_REMOVE(mode_key_tree, mtab->tree, mbind); diff --git a/input-keys.c b/input-keys.c index 2915cb45..3bc1f812 100644 --- a/input-keys.c +++ b/input-keys.c @@ -161,14 +161,14 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m) * if necessary. If it is a UTF-8 key, split it and send it. */ justkey = (key & ~KEYC_ESCAPE); - if (key != KEYC_NONE && justkey <= 0x7f) { + if (justkey <= 0x7f) { if (key & KEYC_ESCAPE) bufferevent_write(wp->event, "\033", 1); ud.data[0] = justkey; bufferevent_write(wp->event, &ud.data[0], 1); return; } - if (key != KEYC_NONE && justkey > 0x7f && justkey < KEYC_BASE) { + if (justkey > 0x7f && justkey < KEYC_BASE) { if (utf8_split(justkey, &ud) != UTF8_DONE) return; if (key & KEYC_ESCAPE) diff --git a/key-string.c b/key-string.c index 9a44892d..1ff3ca30 100644 --- a/key-string.c +++ b/key-string.c @@ -22,8 +22,8 @@ #include "tmux.h" -key_code key_string_search_table(const char *); -key_code key_string_get_modifiers(const char **); +static key_code key_string_search_table(const char *); +static key_code key_string_get_modifiers(const char **); const struct { const char *string; @@ -98,7 +98,7 @@ const struct { }; /* Find key string in table. */ -key_code +static key_code key_string_search_table(const char *string) { u_int i; @@ -107,11 +107,11 @@ key_string_search_table(const char *string) if (strcasecmp(string, key_string_table[i].string) == 0) return (key_string_table[i].key); } - return (KEYC_NONE); + return (KEYC_UNKNOWN); } /* Find modifiers. */ -key_code +static key_code key_string_get_modifiers(const char **string) { key_code modifiers; @@ -150,10 +150,14 @@ key_string_lookup_string(const char *string) u_int i; enum utf8_state more; + /* Is this no key? */ + if (strcasecmp(string, "None") == 0) + return (KEYC_NONE); + /* Is this a hexadecimal value? */ if (string[0] == '0' && string[1] == 'x') { if (sscanf(string + 2, "%hx%n", &u, &size) != 1 || size > 4) - return (KEYC_NONE); + return (KEYC_UNKNOWN); return (u); } @@ -165,30 +169,30 @@ key_string_lookup_string(const char *string) } modifiers |= key_string_get_modifiers(&string); if (string[0] == '\0') - return (KEYC_NONE); + return (KEYC_UNKNOWN); /* Is this a standard ASCII key? */ if (string[1] == '\0' && (u_char)string[0] <= 127) { key = (u_char)string[0]; if (key < 32 || key == 127) - return (KEYC_NONE); + return (KEYC_UNKNOWN); } else { /* Try as a UTF-8 key. */ if ((more = utf8_open(&ud, (u_char)*string)) == UTF8_MORE) { if (strlen(string) != ud.size) - return (KEYC_NONE); + return (KEYC_UNKNOWN); for (i = 1; i < ud.size; i++) more = utf8_append(&ud, (u_char)string[i]); if (more != UTF8_DONE) - return (KEYC_NONE); + return (KEYC_UNKNOWN); key = utf8_combine(&ud); return (key | modifiers); } /* Otherwise look the key up in the table. */ key = key_string_search_table(string); - if (key == KEYC_NONE) - return (KEYC_NONE); + if (key == KEYC_UNKNOWN) + return (KEYC_UNKNOWN); } /* Convert the standard control keys. */ @@ -202,7 +206,7 @@ key_string_lookup_string(const char *string) else if (key == 63) key = KEYC_BSPACE; else - return (KEYC_NONE); + return (KEYC_UNKNOWN); modifiers &= ~KEYC_CTRL; } @@ -222,9 +226,13 @@ key_string_lookup_key(key_code key) /* Handle no key. */ if (key == KEYC_NONE) - return ("<NONE>"); + return ("None"); + + /* Handle special keys. */ + if (key == KEYC_UNKNOWN) + return ("Unknown"); if (key == KEYC_MOUSE) - return ("<MOUSE>"); + return ("Mouse"); /* * Special case: display C-@ as C-Space. Could do this below in @@ -265,7 +273,7 @@ key_string_lookup_key(key_code key) /* Invalid keys are errors. */ if (key == 127 || key > 255) { - snprintf(out, sizeof out, "<INVALID#%llx>", key); + snprintf(out, sizeof out, "Invalid#%llx", key); return (out); } diff --git a/server-client.c b/server-client.c index 8b6be5d9..ed0eefdd 100644 --- a/server-client.c +++ b/server-client.c @@ -309,7 +309,7 @@ server_client_check_mouse(struct client *c) log_debug("down at %u,%u", x, y); } if (type == NOTYPE) - return (KEYC_NONE); + return (KEYC_UNKNOWN); /* Always save the session. */ m->s = s->id; @@ -319,7 +319,7 @@ server_client_check_mouse(struct client *c) if (m->statusat != -1 && y == (u_int)m->statusat) { w = status_get_window_at(c, x); if (w == NULL) - return (KEYC_NONE); + return (KEYC_UNKNOWN); m->w = w->id; where = STATUS; } else @@ -352,7 +352,7 @@ server_client_check_mouse(struct client *c) } } if (where == NOWHERE) - return (KEYC_NONE); + return (KEYC_UNKNOWN); m->wp = wp->id; m->w = wp->window->id; } else @@ -371,7 +371,7 @@ server_client_check_mouse(struct client *c) } /* Convert to a key binding. */ - key = KEYC_NONE; + key = KEYC_UNKNOWN; switch (type) { case NOTYPE: break; @@ -483,8 +483,8 @@ server_client_check_mouse(struct client *c) } break; } - if (key == KEYC_NONE) - return (KEYC_NONE); + if (key == KEYC_UNKNOWN) + return (KEYC_UNKNOWN); /* Apply modifiers if any. */ if (b & MOUSE_MASK_META) @@ -572,7 +572,7 @@ server_client_handle_key(struct client *c, key_code key) if (c->flags & CLIENT_READONLY) return; key = server_client_check_mouse(c); - if (key == KEYC_NONE) + if (key == KEYC_UNKNOWN) return; m->valid = 1; diff --git a/tmux.1 b/tmux.1 index 115050a6..b02237f1 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2664,8 +2664,19 @@ See the section for details. .It Ic prefix Ar key Set the key accepted as a prefix key. +In addition to the standard keys described under +.Sx KEY BINDINGS , +.Ic prefix +can be set to the special key +.Ql None +to set no prefix. .It Ic prefix2 Ar key Set a secondary key accepted as a prefix key. +Like +.Ic prefix , +.Ic prefix2 +can be set to +.Ql None . .It Xo Ic renumber-windows .Op Ic on | off .Xc diff --git a/tmux.h b/tmux.h index 60d16fe3..d5e5d822 100644 --- a/tmux.h +++ b/tmux.h @@ -85,6 +85,7 @@ struct tmuxproc; /* Special key codes. */ #define KEYC_NONE 0xffff00000000ULL +#define KEYC_UNKNOWN 0xfffe00000000ULL #define KEYC_BASE 0x100000000000ULL /* Key modifier bits. */ diff --git a/tty-keys.c b/tty-keys.c index b5e36f8e..86839a17 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -344,7 +344,7 @@ tty_keys_add1(struct tty_key **tkp, const char *s, key_code key) if (tk == NULL) { tk = *tkp = xcalloc(1, sizeof *tk); tk->ch = *s; - tk->key = KEYC_NONE; + tk->key = KEYC_UNKNOWN; } /* Find the next entry. */ @@ -444,7 +444,7 @@ tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size) (*size)++; /* At the end of the string, return the current node. */ - if (len == 0 || (tk->next == NULL && tk->key != KEYC_NONE)) + if (len == 0 || (tk->next == NULL && tk->key != KEYC_UNKNOWN)) return (tk); /* Move into the next tree for the following character. */ @@ -534,7 +534,7 @@ first_key: if (tk->next != NULL) goto partial_key; key = tk->key; - if (key != KEYC_NONE) + if (key != KEYC_UNKNOWN) key |= KEYC_ESCAPE; goto complete_key; } @@ -620,7 +620,7 @@ complete_key: } /* Fire the key. */ - if (key != KEYC_NONE) + if (key != KEYC_UNKNOWN) server_client_handle_key(tty->client, key); return (1); From 6a50cf89b40d472cd1f8b439913ca4caddbfd001 Mon Sep 17 00:00:00 2001 From: nicm <nicm> Date: Sat, 12 Dec 2015 18:28:47 +0000 Subject: [PATCH 2/3] Return after changing key table. --- cmd-switch-client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd-switch-client.c b/cmd-switch-client.c index edc0fd69..85cbce78 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -65,6 +65,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq) table->references++; key_bindings_unref_table(c->keytable); c->keytable = table; + return (CMD_RETURN_NORMAL); } tflag = args_get(args, 't'); From 5ed17e84faed0a7655ec1eb3de291b60839dcb12 Mon Sep 17 00:00:00 2001 From: nicm <nicm> Date: Sat, 12 Dec 2015 18:32:24 +0000 Subject: [PATCH 3/3] Add key-table option to set the default key table for a session, allows different key bindings for different sessions and a few other things. --- cmd-attach-session.c | 2 ++ cmd-new-session.c | 1 + cmd-set-option.c | 4 ++++ cmd-switch-client.c | 1 + format.c | 4 +++- options-table.c | 6 ++++++ server-client.c | 36 +++++++++++++++++++++++++++--------- server-fn.c | 1 + tmux.1 | 5 +++++ tmux.h | 2 ++ 10 files changed, 52 insertions(+), 10 deletions(-) diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 73c82248..00ced9df 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -119,6 +119,7 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, } c->session = s; + server_client_set_key_table(c, NULL); status_timer_start(c); notify_attached_session_changed(c); session_update_activity(s, NULL); @@ -150,6 +151,7 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, } c->session = s; + server_client_set_key_table(c, NULL); status_timer_start(c); notify_attached_session_changed(c); session_update_activity(s, NULL); diff --git a/cmd-new-session.c b/cmd-new-session.c index aee69e12..341399be 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -262,6 +262,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) } else if (c->session != NULL) c->last_session = c->session; c->session = s; + server_client_set_key_table(c, NULL); status_timer_start(c); notify_attached_session_changed(c); session_update_activity(s, NULL); diff --git a/cmd-set-option.c b/cmd-set-option.c index e2a4768c..daee62ac 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -183,6 +183,10 @@ cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq) w->active->flags |= PANE_CHANGED; } } + if (strcmp(oe->name, "key-table") == 0) { + TAILQ_FOREACH(c, &clients, entry) + server_client_set_key_table(c, NULL); + } if (strcmp(oe->name, "status") == 0 || strcmp(oe->name, "status-interval") == 0) status_timer_start_all(); diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 85cbce78..4746b15a 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -124,6 +124,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq) if (c->session != NULL && c->session != s) c->last_session = c->session; c->session = s; + server_client_set_key_table(c, NULL); status_timer_start(c); session_update_activity(s, NULL); gettimeofday(&s->last_attached_time, NULL); diff --git a/format.c b/format.c index 3e666330..79445936 100644 --- a/format.c +++ b/format.c @@ -1035,6 +1035,7 @@ void format_defaults_client(struct format_tree *ft, struct client *c) { struct session *s; + const char *name; if (ft->s == NULL) ft->s = c->session; @@ -1052,7 +1053,8 @@ format_defaults_client(struct format_tree *ft, struct client *c) format_add_tv(ft, "client_created", &c->creation_time); format_add_tv(ft, "client_activity", &c->activity_time); - if (strcmp(c->keytable->name, "root") == 0) + name = server_client_get_key_table(c); + if (strcmp(c->keytable->name, name) == 0) format_add(ft, "client_prefix", "%d", 0); else format_add(ft, "client_prefix", "%d", 1); diff --git a/options-table.c b/options-table.c index 0dab0c0e..63e7ab61 100644 --- a/options-table.c +++ b/options-table.c @@ -211,6 +211,12 @@ const struct options_table_entry options_table[] = { .default_num = 2000 }, + { .name = "key-table", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_SESSION, + .default_str = "root" + }, + { .name = "lock-after-time", .type = OPTIONS_TABLE_NUMBER, .scope = OPTIONS_TABLE_SESSION, diff --git a/server-client.c b/server-client.c index ed0eefdd..c2b43f38 100644 --- a/server-client.c +++ b/server-client.c @@ -32,7 +32,6 @@ #include "tmux.h" -void server_client_key_table(struct client *, const char *); void server_client_free(int, short, void *); void server_client_check_focus(struct window_pane *); void server_client_check_resize(struct window_pane *); @@ -72,13 +71,32 @@ server_client_check_nested(struct client *c) /* Set client key table. */ void -server_client_key_table(struct client *c, const char *name) +server_client_set_key_table(struct client *c, const char *name) { + if (name == NULL) + name = server_client_get_key_table(c); + key_bindings_unref_table(c->keytable); c->keytable = key_bindings_get_table(name, 1); c->keytable->references++; } +/* Get default key table. */ +const char * +server_client_get_key_table(struct client *c) +{ + struct session *s = c->session; + const char *name; + + if (s == NULL) + return ("root"); + + name = options_get_string(s->options, "key-table"); + if (*name == '\0') + return ("root"); + return (name); +} + /* Create a new client. */ void server_client_create(int fd) @@ -598,7 +616,7 @@ retry: * again in the root table. */ if ((c->flags & CLIENT_REPEAT) && !bd->can_repeat) { - server_client_key_table(c, "root"); + server_client_set_key_table(c, NULL); c->flags &= ~CLIENT_REPEAT; server_status_client(c); goto retry; @@ -625,7 +643,7 @@ retry: evtimer_add(&c->repeat_timer, &tv); } else { c->flags &= ~CLIENT_REPEAT; - server_client_key_table(c, "root"); + server_client_set_key_table(c, NULL); } server_status_client(c); @@ -640,15 +658,15 @@ retry: * root table and try again. */ if (c->flags & CLIENT_REPEAT) { - server_client_key_table(c, "root"); + server_client_set_key_table(c, NULL); c->flags &= ~CLIENT_REPEAT; server_status_client(c); goto retry; } /* If no match and we're not in the root table, that's it. */ - if (strcmp(c->keytable->name, "root") != 0) { - server_client_key_table(c, "root"); + if (strcmp(c->keytable->name, server_client_get_key_table(c)) != 0) { + server_client_set_key_table(c, NULL); server_status_client(c); return; } @@ -659,7 +677,7 @@ retry: */ if (key == (key_code)options_get_number(s->options, "prefix") || key == (key_code)options_get_number(s->options, "prefix2")) { - server_client_key_table(c, "prefix"); + server_client_set_key_table(c, "prefix"); server_status_client(c); return; } @@ -834,7 +852,7 @@ server_client_repeat_timer(__unused int fd, __unused short events, void *data) struct client *c = data; if (c->flags & CLIENT_REPEAT) { - server_client_key_table(c, "root"); + server_client_set_key_table(c, NULL); c->flags &= ~CLIENT_REPEAT; server_status_client(c); } diff --git a/server-fn.c b/server-fn.c index 07ade08c..a4c2dfea 100644 --- a/server-fn.c +++ b/server-fn.c @@ -384,6 +384,7 @@ server_destroy_session(struct session *s) } else { c->last_session = NULL; c->session = s_new; + server_client_set_key_table(c, NULL); status_timer_start(c); notify_attached_session_changed(c); session_update_activity(s_new, NULL); diff --git a/tmux.1 b/tmux.1 index b02237f1..39e9bd4b 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2572,6 +2572,11 @@ is in milliseconds. Set the maximum number of lines held in window history. This setting applies only to new windows - existing window histories are not resized and retain the limit at the point they were created. +.It Ic key-table Ar key-table +Set the default key table to +.Ar key-table +instead of +.Em root . .It Ic lock-after-time Ar number Lock the session (like the .Ic lock-session diff --git a/tmux.h b/tmux.h index d5e5d822..e10fbcdf 100644 --- a/tmux.h +++ b/tmux.h @@ -1800,6 +1800,8 @@ void server_update_socket(void); void server_add_accept(int); /* server-client.c */ +void server_client_set_key_table(struct client *, const char *); +const char *server_client_get_key_table(struct client *); int server_client_check_nested(struct client *); void server_client_handle_key(struct client *, key_code); void server_client_create(int);