Sorry if this isn't formatted as expected, I'm not at all familiar with the operation of git's e-mail tools.
Keith --- Makefile.am | 1 + cmd-bind-key.c | 52 ++++++++++++++++--------- cmd-list-keys.c | 80 +++++++++++++++++++------------------- cmd-set-keytable.c | 44 +++++++++++++++++++++ cmd-unbind-key.c | 48 +++++++++++++++++------ cmd.c | 1 + format.c | 3 +- key-bindings.c | 95 ++++++++++++++++++++++++++++----------------- server-client.c | 110 +++++++++++++++++++++++++++++++---------------------- server.c | 1 - tmux.1 | 46 ++++++++++++++++++++-- tmux.h | 26 +++++++++---- 12 files changed, 341 insertions(+), 166 deletions(-) create mode 100644 cmd-set-keytable.c diff --git a/Makefile.am b/Makefile.am index 5502de86d276..eb9fc9ed60bb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -123,6 +123,7 @@ dist_tmux_SOURCES = \ cmd-send-keys.c \ cmd-set-buffer.c \ cmd-set-environment.c \ + cmd-set-keytable.c \ cmd-set-option.c \ cmd-show-environment.c \ cmd-show-messages.c \ diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 4ff3ac8431bc..e472a5a067dc 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -29,12 +29,14 @@ enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmd_q *); -enum cmd_retval cmd_bind_key_table(struct cmd *, struct cmd_q *, int); +enum cmd_retval cmd_bind_mode_key_table(struct cmd *, struct cmd_q *, int); + +enum cmd_retval cmd_bind_key_table(struct cmd *, const char *, struct cmd_q *, int); const struct cmd_entry cmd_bind_key_entry = { "bind-key", "bind", - "cnrt:", 1, -1, - "[-cnr] [-t key-table] key command [arguments]", + "cnrt:T:", 1, -1, + "[-cnr] [-t mode-key-table] [-T key-table] key command [arguments]", 0, NULL, cmd_bind_key_exec @@ -44,11 +46,9 @@ enum cmd_retval cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; - char *cause; - struct cmd_list *cmdlist; int key; - if (args_has(args, 't')) { + if (args_has(args, 't') || args_has(args, 'T')) { if (args->argc != 2 && args->argc != 3) { cmdq_error(cmdq, "not enough arguments"); return (CMD_RETURN_ERROR); @@ -67,24 +67,19 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq) } if (args_has(args, 't')) - return (cmd_bind_key_table(self, cmdq, key)); + return (cmd_bind_mode_key_table(self, cmdq, key)); - cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, NULL, 0, - &cause); - if (cmdlist == NULL) { - cmdq_error(cmdq, "%s", cause); - free(cause); - return (CMD_RETURN_ERROR); - } + if (args_has(args, 'T')) + return (cmd_bind_key_table(self, args_get(args, 'T'), cmdq, key)); - if (!args_has(args, 'n')) - key |= KEYC_PREFIX; - key_bindings_add(key, args_has(args, 'r'), cmdlist); - return (CMD_RETURN_NORMAL); + if (args_has(args, 'n')) + return (cmd_bind_key_table(self, "ROOT", cmdq, key)); + + return (cmd_bind_key_table(self, "PREFIX", cmdq, key)); } enum cmd_retval -cmd_bind_key_table(struct cmd *self, struct cmd_q *cmdq, int key) +cmd_bind_mode_key_table(struct cmd *self, struct cmd_q *cmdq, int key) { struct args *args = self->args; const char *tablename; @@ -131,3 +126,22 @@ cmd_bind_key_table(struct cmd *self, struct cmd_q *cmdq, int key) mbind->arg = arg != NULL ? xstrdup(arg) : NULL; return (CMD_RETURN_NORMAL); } + +enum cmd_retval +cmd_bind_key_table(struct cmd *self, const char *tablename, struct cmd_q *cmdq, int key) +{ + struct args *args = self->args; + char *cause; + struct cmd_list *cmdlist; + + cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, NULL, 0, + &cause); + if (cmdlist == NULL) { + cmdq_error(cmdq, "%s", cause); + free(cause); + return (CMD_RETURN_ERROR); + } + + key_bindings_add(tablename, key, args_has(args, 'r'), cmdlist); + return (CMD_RETURN_NORMAL); +} diff --git a/cmd-list-keys.c b/cmd-list-keys.c index 615c5ce1fe67..20fc386286e9 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -41,56 +41,56 @@ const struct cmd_entry cmd_list_keys_entry = { enum cmd_retval cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq) { - struct args *args = self->args; - struct key_binding *bd; - const char *key; - char tmp[BUFSIZ], flags[8]; - size_t used; - int width, keywidth; + struct args *args = self->args; + struct key_binding_map_entry *e; + struct key_binding *bd; + const char *key; + char tmp[BUFSIZ]; + size_t used; + int hasrepeat, maxtablewidth, tablewidth, maxkeywidth, keywidth; if (args_has(args, 't')) return (cmd_list_keys_table(self, cmdq)); - width = 0; + hasrepeat = 0; + maxtablewidth = 0; + maxkeywidth = 0; - RB_FOREACH(bd, key_bindings, &key_bindings) { - key = key_string_lookup_key(bd->key & ~KEYC_PREFIX); - if (key == NULL) - continue; + RB_FOREACH(e, key_binding_map, &key_binding_map) { + RB_FOREACH(bd, key_bindings, &(e->key_bindings)) { + key = key_string_lookup_key(bd->key); + if (key == NULL) + continue; - keywidth = strlen(key); - if (!(bd->key & KEYC_PREFIX)) { if (bd->can_repeat) - keywidth += 4; - else - keywidth += 3; - } else if (bd->can_repeat) - keywidth += 3; - if (keywidth > width) - width = keywidth; - } + hasrepeat = 1; - RB_FOREACH(bd, key_bindings, &key_bindings) { - key = key_string_lookup_key(bd->key & ~KEYC_PREFIX); - if (key == NULL) - continue; + tablewidth = strlen(e->name); + if (tablewidth > maxtablewidth) + maxtablewidth = tablewidth; - *flags = '\0'; - if (!(bd->key & KEYC_PREFIX)) { - if (bd->can_repeat) - xsnprintf(flags, sizeof flags, "-rn "); - else - xsnprintf(flags, sizeof flags, "-n "); - } else if (bd->can_repeat) - xsnprintf(flags, sizeof flags, "-r "); - - used = xsnprintf(tmp, sizeof tmp, "%s%*s ", - flags, (int) (width - strlen(flags)), key); - if (used >= sizeof tmp) - continue; + keywidth = strlen(key); + if (keywidth > maxkeywidth) + maxkeywidth = keywidth; + } + } - cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used); - cmdq_print(cmdq, "bind-key %s", tmp); + RB_FOREACH(e, key_binding_map, &key_binding_map) { + RB_FOREACH(bd, key_bindings, &(e->key_bindings)) { + key = key_string_lookup_key(bd->key); + if (key == NULL) + continue; + + used = xsnprintf(tmp, sizeof tmp, "%s-T %-*s %-*s ", + (hasrepeat ? (bd->can_repeat ? "-r " : " ") : ""), + (int) maxtablewidth, e->name, + (int) maxkeywidth, key); + if (used >= sizeof tmp) + continue; + + cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used); + cmdq_print(cmdq, "bind-key %s", tmp); + } } return (CMD_RETURN_NORMAL); diff --git a/cmd-set-keytable.c b/cmd-set-keytable.c new file mode 100644 index 000000000000..b009233101b4 --- /dev/null +++ b/cmd-set-keytable.c @@ -0,0 +1,44 @@ +/* $Id$ */ + +/* + * Copyright (c) 2007 Nicholas Marriott <n...@users.sourceforge.net> + * + * 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 <stdlib.h> +#include <string.h> + +#include "tmux.h" + +void cmd_set_keytable_key_binding(struct cmd *, int); +enum cmd_retval cmd_set_keytable_exec(struct cmd *, struct cmd_q *); + +const struct cmd_entry cmd_set_keytable_entry = { + "set-keytable", "setkt", + "", 1, 1, + "table", + 0, + NULL, + cmd_set_keytable_exec +}; + +enum cmd_retval +cmd_set_keytable_exec(struct cmd *self, struct cmd_q *cmdq) +{ + free(cmdq->client->keytablename); + cmdq->client->keytablename = xstrdup(self->args->argv[0]); + return (CMD_RETURN_NORMAL); +} diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index cf6ad506195f..cbc4743f3265 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -27,12 +27,13 @@ */ enum cmd_retval cmd_unbind_key_exec(struct cmd *, struct cmd_q *); -enum cmd_retval cmd_unbind_key_table(struct cmd *, struct cmd_q *, int); +enum cmd_retval cmd_unbind_mode_key_table(struct cmd *, struct cmd_q *, int); +void cmd_unbind_key_wipe(const char *); const struct cmd_entry cmd_unbind_key_entry = { "unbind-key", "unbind", - "acnt:", 0, 1, - "[-acn] [-t key-table] key", + "acnt:T:", 0, 1, + "[-acn] [-t mode-key-table] [-T key-table] key", 0, NULL, cmd_unbind_key_exec @@ -42,7 +43,6 @@ enum cmd_retval cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; - struct key_binding *bd; int key; if (!args_has(args, 'a')) { @@ -64,24 +64,34 @@ cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq) } if (args_has(args, 't')) - return (cmd_unbind_key_table(self, cmdq, key)); + return (cmd_unbind_mode_key_table(self, cmdq, key)); if (key == KEYC_NONE) { - while (!RB_EMPTY(&key_bindings)) { - bd = RB_ROOT(&key_bindings); - key_bindings_remove(bd->key); + if (args_has(args, 'T')) { + cmd_unbind_key_wipe(args_get(args, 't')); + return (CMD_RETURN_NORMAL); } + cmd_unbind_key_wipe("ROOT"); + cmd_unbind_key_wipe("PREFIX"); + return (CMD_RETURN_NORMAL); + } + + if (args_has(args, 'T')) { + key_bindings_remove(args_get(args, 'T'), key); + return (CMD_RETURN_NORMAL); + } + + if (args_has(args, 'n')) { + key_bindings_remove("PREFIX", key); return (CMD_RETURN_NORMAL); } - if (!args_has(args, 'n')) - key |= KEYC_PREFIX; - key_bindings_remove(key); + key_bindings_remove("ROOT", key); return (CMD_RETURN_NORMAL); } enum cmd_retval -cmd_unbind_key_table(struct cmd *self, struct cmd_q *cmdq, int key) +cmd_unbind_mode_key_table(struct cmd *self, struct cmd_q *cmdq, int key) { struct args *args = self->args; const char *tablename; @@ -111,3 +121,17 @@ cmd_unbind_key_table(struct cmd *self, struct cmd_q *cmdq, int key) } return (CMD_RETURN_NORMAL); } + +void +cmd_unbind_key_wipe(const char *tablename) { + struct key_bindings *key_bindings; + struct key_binding *bd; + + while (1) { + key_bindings = key_bindings_lookup_table(tablename, 0); + if (key_bindings == NULL) + return; + bd = RB_ROOT(key_bindings); + key_bindings_remove(tablename, bd->key); + } +} diff --git a/cmd.c b/cmd.c index f2d88c050637..0c11a84766f7 100644 --- a/cmd.c +++ b/cmd.c @@ -95,6 +95,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_server_info_entry, &cmd_set_buffer_entry, &cmd_set_environment_entry, + &cmd_set_keytable_entry, &cmd_set_option_entry, &cmd_set_window_option_entry, &cmd_show_buffer_entry, diff --git a/format.c b/format.c index 6f988b9ac2cc..4d3fc057f246 100644 --- a/format.c +++ b/format.c @@ -435,7 +435,8 @@ format_client(struct format_tree *ft, struct client *c) *strchr(tim, '\n') = '\0'; format_add(ft, "client_activity_string", "%s", tim); - format_add(ft, "client_prefix", "%d", !!(c->flags & CLIENT_PREFIX)); + format_add(ft, "client_prefix", strcmp(c->keytablename, "ROOT") ? "1": "0"); + format_add(ft, "client_keytablename", "%s", c->keytablename); if (c->tty.flags & TTY_UTF8) format_add(ft, "client_utf8", "%d", 1); diff --git a/key-bindings.c b/key-bindings.c index f725508bce62..e5da8c97cd1d 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -25,72 +25,97 @@ #include "tmux.h" RB_GENERATE(key_bindings, key_binding, entry, key_bindings_cmp); +RB_GENERATE(key_binding_map, key_binding_map_entry, entry, key_binding_map_entry_cmp); -struct key_bindings key_bindings; -struct key_bindings dead_key_bindings; +struct key_binding_map key_binding_map; + +int +key_binding_map_entry_cmp(struct key_binding_map_entry *e1, struct key_binding_map_entry *e2) +{ + return strcmp(e1->name, e2->name); +} int key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2) { - int key1, key2; - - key1 = bd1->key & ~KEYC_PREFIX; - key2 = bd2->key & ~KEYC_PREFIX; - if (key1 != key2) - return (key1 - key2); - - if (bd1->key & KEYC_PREFIX && !(bd2->key & KEYC_PREFIX)) - return (-1); - if (bd2->key & KEYC_PREFIX && !(bd1->key & KEYC_PREFIX)) - return (1); - return (0); + return (bd1->key - bd2->key); +} + +struct key_bindings * +key_bindings_lookup_table(const char *name, int create) +{ + struct key_binding_map_entry e; + struct key_binding_map_entry *e_found; + + e.name = name; + e_found = RB_FIND(key_binding_map, &key_binding_map, &e); + if (e_found) + return &(e_found->key_bindings); + + if (!create) + return NULL; + + e_found = xmalloc(sizeof *e_found); + e_found->name = xstrdup(name); + RB_INIT(&(e_found->key_bindings)); + RB_INSERT(key_binding_map, &key_binding_map, e_found); + + return &(e_found->key_bindings); } struct key_binding * -key_bindings_lookup(int key) +key_bindings_lookup(const char *name, int key) { + struct key_bindings *key_bindings; struct key_binding bd; + key_bindings = key_bindings_lookup_table(name, 0); + if (!key_bindings) + return NULL; + bd.key = key; - return (RB_FIND(key_bindings, &key_bindings, &bd)); + return (RB_FIND(key_bindings, key_bindings, &bd)); } void -key_bindings_add(int key, int can_repeat, struct cmd_list *cmdlist) +key_bindings_add(const char *name, int key, int can_repeat, struct cmd_list *cmdlist) { + struct key_bindings *key_bindings; struct key_binding *bd; - key_bindings_remove(key); + key_bindings_remove(name, key); + + key_bindings = key_bindings_lookup_table(name, 1); bd = xmalloc(sizeof *bd); bd->key = key; - RB_INSERT(key_bindings, &key_bindings, bd); + RB_INSERT(key_bindings, key_bindings, bd); bd->can_repeat = can_repeat; bd->cmdlist = cmdlist; } void -key_bindings_remove(int key) +key_bindings_remove(const char *name, int key) { + struct key_binding_map_entry e; + struct key_bindings *key_bindings; struct key_binding *bd; - if ((bd = key_bindings_lookup(key)) == NULL) + if ((bd = key_bindings_lookup(name, key)) == NULL) return; - RB_REMOVE(key_bindings, &key_bindings, bd); - RB_INSERT(key_bindings, &dead_key_bindings, bd); -} -void -key_bindings_clean(void) -{ - struct key_binding *bd; + key_bindings = key_bindings_lookup_table(name, 0); + if (!key_bindings) + return; + + RB_REMOVE(key_bindings, key_bindings, bd); + cmd_list_free(bd->cmdlist); + free(bd); - while (!RB_EMPTY(&dead_key_bindings)) { - bd = RB_ROOT(&dead_key_bindings); - RB_REMOVE(key_bindings, &dead_key_bindings, bd); - cmd_list_free(bd->cmdlist); - free(bd); + if (RB_EMPTY(key_bindings)) { + e.name = name; + RB_REMOVE(key_binding_map, &key_binding_map, &e); } } @@ -180,7 +205,7 @@ key_bindings_init(void) struct cmd *cmd; struct cmd_list *cmdlist; - RB_INIT(&key_bindings); + RB_INIT(&key_binding_map); for (i = 0; i < nitems(table); i++) { cmdlist = xcalloc(1, sizeof *cmdlist); @@ -196,7 +221,7 @@ key_bindings_init(void) TAILQ_INSERT_HEAD(&cmdlist->list, cmd, qentry); key_bindings_add( - table[i].key | KEYC_PREFIX, table[i].can_repeat, cmdlist); + "PREFIX", table[i].key, table[i].can_repeat, cmdlist); } } diff --git a/server-client.c b/server-client.c index e225de309b5f..c853712d3f10 100644 --- a/server-client.c +++ b/server-client.c @@ -98,6 +98,7 @@ server_client_create(int fd) c->tty.mouse.flags = 0; c->flags |= CLIENT_FOCUSED; + c->keytablename = xstrdup("ROOT"); evtimer_set(&c->repeat_timer, server_client_repeat_timer, c); @@ -170,6 +171,8 @@ server_client_lost(struct client *c) evtimer_del(&c->repeat_timer); + free(c->keytablename); + if (event_initialized(&c->identify_timer)) evtimer_del(&c->identify_timer); @@ -427,64 +430,78 @@ server_client_handle_key(struct client *c, int key) /* Treat prefix as a regular key when pasting is detected. */ ispaste = server_client_assume_paste(s); - if (ispaste) - isprefix = 0; + if (ispaste) { + if (!(c->flags & CLIENT_READONLY)) + window_pane_key(wp, s, key); + return; + } - /* No previous prefix key. */ - if (!(c->flags & CLIENT_PREFIX)) { - if (isprefix) { - c->flags |= CLIENT_PREFIX; + /* Try to see if we hit a key binding. */ + while (1) { + if ((bd = key_bindings_lookup(c->keytablename, key)) != NULL) { + if ((c->flags & CLIENT_REPEAT) && !bd->can_repeat) { + /* We don't honor repeating into a non-repeat binding, fall back to ROOT and try again */ + free(c->keytablename); + c->keytablename = xstrdup("ROOT"); + c->flags &= ~CLIENT_REPEAT; + server_status_client(c); + continue; + } + xtimeout = options_get_number(&s->options, "repeat-time"); + if (xtimeout != 0 && bd->can_repeat) { + /* Now repeating in same keytable */ + c->flags |= CLIENT_REPEAT; + + tv.tv_sec = xtimeout / 1000; + tv.tv_usec = (xtimeout % 1000) * 1000L; + evtimer_del(&c->repeat_timer); + evtimer_add(&c->repeat_timer, &tv); + } + else { + /* "Stop" (or don't start) repeating */ + c->flags &= ~CLIENT_REPEAT; + free(c->keytablename); + c->keytablename = xstrdup("ROOT"); + } server_status_client(c); + key_bindings_dispatch(bd, c); return; } - /* Try as a non-prefix key binding. */ - if (ispaste || (bd = key_bindings_lookup(key)) == NULL) { - if (!(c->flags & CLIENT_READONLY)) - window_pane_key(wp, s, key); - } else - key_bindings_dispatch(bd, c); - return; - } - - /* Prefix key already pressed. Reset prefix and lookup key. */ - c->flags &= ~CLIENT_PREFIX; - server_status_client(c); - if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) { - /* If repeating, treat this as a key, else ignore. */ if (c->flags & CLIENT_REPEAT) { + /* We missed, but we were in repeat, fall back to ROOT and try again */ + free(c->keytablename); + c->keytablename = xstrdup("ROOT"); c->flags &= ~CLIENT_REPEAT; - if (isprefix) - c->flags |= CLIENT_PREFIX; - else if (!(c->flags & CLIENT_READONLY)) - window_pane_key(wp, s, key); + server_status_client(c); + continue; } - return; + + /* Actual miss */ + break; } - /* If already repeating, but this key can't repeat, skip it. */ - if (c->flags & CLIENT_REPEAT && !bd->can_repeat) { - c->flags &= ~CLIENT_REPEAT; - if (isprefix) - c->flags |= CLIENT_PREFIX; - else if (!(c->flags & CLIENT_READONLY)) - window_pane_key(wp, s, key); + /* A miss in a non-ROOT keytable fails out to ROOT */ + if (strcmp(c->keytablename, "ROOT")) { + free(c->keytablename); + c->keytablename = xstrdup("ROOT"); + server_status_client(c); return; } - /* If this key can repeat, reset the repeat flags and timer. */ - xtimeout = options_get_number(&s->options, "repeat-time"); - if (xtimeout != 0 && bd->can_repeat) { - c->flags |= CLIENT_PREFIX|CLIENT_REPEAT; - - tv.tv_sec = xtimeout / 1000; - tv.tv_usec = (xtimeout % 1000) * 1000L; - evtimer_del(&c->repeat_timer); - evtimer_add(&c->repeat_timer, &tv); + /* A prefix miss in ROOT switched to PREFIX */ + if (isprefix) { + /* Prefix key switches to PREFIX table */ + free(c->keytablename); + c->keytablename = xstrdup("PREFIX"); + server_status_client(c); + return; } - /* Dispatch the command. */ - key_bindings_dispatch(bd, c); + /* Anything else in ROOT is straight through */ + if (!(c->flags & CLIENT_READONLY)) { + window_pane_key(wp, s, key); + } } /* Client functions that need to happen every loop. */ @@ -700,9 +717,10 @@ server_client_repeat_timer(unused int fd, unused short events, void *data) struct client *c = data; if (c->flags & CLIENT_REPEAT) { - if (c->flags & CLIENT_PREFIX) - server_status_client(c); - c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); + free(c->keytablename); + c->keytablename = xstrdup("ROOT"); + c->flags &= ~CLIENT_REPEAT; + server_status_client(c); } } diff --git a/server.c b/server.c index d3ac0f8b0cdd..5ae44df23eff 100644 --- a/server.c +++ b/server.c @@ -209,7 +209,6 @@ server_loop(void) server_window_loop(); server_client_loop(); - key_bindings_clean(); server_clean_dead(); } } diff --git a/tmux.1 b/tmux.1 index c05eacfdbc53..3a89e26c20d3 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1842,7 +1842,8 @@ Commands related to key bindings are as follows: .Bl -tag -width Ds .It Xo Ic bind-key .Op Fl cnr -.Op Fl t Ar key-table +.Op Fl t Ar mode-key-table +.Op Fl T Ar key-table .Ar key Ar command Op Ar arguments .Xc .D1 (alias: Ic bind ) @@ -1871,13 +1872,28 @@ If is present, .Ar key is bound in -.Ar key-table : +.Ar mode-key-table : the binding for command mode with .Fl c or for normal mode without. To view the default bindings and possible commands, see the .Ic list-keys command. +.Pp +If +.Fl T +is present, +.Ar key +is bound in +.Ar key-table : +.Em PREFIX +corresponds to the default, +.Em ROOT +corresponds to +.Fl n , +and custom values may be used with the +.Ic set-keytable +command. .It Ic list-keys Op Fl t Ar key-table .D1 (alias: Ic lsk ) List all key bindings. @@ -1927,9 +1943,15 @@ flag causes the terminal state to be reset. Send the prefix key, or with .Fl 2 the secondary prefix key, to a window as if it was pressed. +.It Xo Ic set-keytable +.Ar key-table +.Xc +Set the client's key table. The next key from the client will be interpretted from +.Ar key-table . .It Xo Ic unbind-key .Op Fl acn -.Op Fl t Ar key-table +.Op Fl t Ar mode-key-table +.Op Fl T Ar key-table .Ar key .Xc .D1 (alias: Ic unbind ) @@ -1951,10 +1973,26 @@ If is present, .Ar key in -.Ar key-table +.Ar mode-key-table is unbound: the binding for command mode with .Fl c or for normal mode without. +.Pp +If +.Fl T +is present, +.Ar key +in +.Ar key-table +is unbound: +.Em PREFIX +corresponds to the default, +.Em ROOT +corresponds to +.Fl n , +and custom values may be used with the +.Ic set-keytable +command. .El .Sh OPTIONS The appearance and behaviour of diff --git a/tmux.h b/tmux.h index fde94afc47b3..55463fcacce0 100644 --- a/tmux.h +++ b/tmux.h @@ -164,10 +164,9 @@ extern char **environ; #define KEYC_ESCAPE 0x2000 #define KEYC_CTRL 0x4000 #define KEYC_SHIFT 0x8000 -#define KEYC_PREFIX 0x10000 /* Mask to obtain key w/o modifiers. */ -#define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT|KEYC_PREFIX) +#define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT) #define KEYC_MASK_KEY (~KEYC_MASK_MOD) /* Other key codes. */ @@ -1298,7 +1297,7 @@ struct client { struct screen status; #define CLIENT_TERMINAL 0x1 -#define CLIENT_PREFIX 0x2 +/* replaced by keytablename: #define CLIENT_PREFIX 0x2 */ #define CLIENT_EXIT 0x4 #define CLIENT_REDRAW 0x8 #define CLIENT_STATUS 0x10 @@ -1317,6 +1316,7 @@ struct client { #define CLIENT_256COLOURS 0x20000 #define CLIENT_IDENTIFIED 0x40000 int flags; + char *keytablename; struct event identify_timer; @@ -1444,6 +1444,13 @@ struct key_binding { RB_ENTRY(key_binding) entry; }; RB_HEAD(key_bindings, key_binding); +struct key_binding_map_entry { + const char *name; + struct key_bindings key_bindings; + + RB_ENTRY(key_binding_map_entry) entry; +}; +RB_HEAD(key_binding_map, key_binding_map_entry); /* * Option table entries. The option table is the user-visible part of the @@ -1818,6 +1825,7 @@ extern const struct cmd_entry cmd_send_prefix_entry; extern const struct cmd_entry cmd_server_info_entry; extern const struct cmd_entry cmd_set_buffer_entry; extern const struct cmd_entry cmd_set_environment_entry; +extern const struct cmd_entry cmd_set_keytable_entry; extern const struct cmd_entry cmd_set_option_entry; extern const struct cmd_entry cmd_set_window_option_entry; extern const struct cmd_entry cmd_show_buffer_entry; @@ -1865,13 +1873,15 @@ int cmd_string_parse(const char *, struct cmd_list **, const char *, int client_main(int, char **, int); /* key-bindings.c */ -extern struct key_bindings key_bindings; +extern struct key_binding_map key_binding_map; +int key_binding_map_entry_cmp(struct key_binding_map_entry *, struct key_binding_map_entry *); int key_bindings_cmp(struct key_binding *, struct key_binding *); RB_PROTOTYPE(key_bindings, key_binding, entry, key_bindings_cmp); -struct key_binding *key_bindings_lookup(int); -void key_bindings_add(int, int, struct cmd_list *); -void key_bindings_remove(int); -void key_bindings_clean(void); +RB_PROTOTYPE(key_binding_map, key_binding_map_entry, entry, key_binding_map_entry_cmp); +struct key_bindings *key_bindings_lookup_table(const char *, int); +struct key_binding *key_bindings_lookup(const char *, int); +void key_bindings_add(const char *, int, int, struct cmd_list *); +void key_bindings_remove(const char *, int); void key_bindings_init(void); void key_bindings_dispatch(struct key_binding *, struct client *); -- 1.9.1 ------------------------------------------------------------------------------ "Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE Instantly run your Selenium tests across 300+ browser/OS combos. Get unparalleled scalability from the best Selenium testing platform available Simple to use. Nothing to install. Get started now for free." http://p.sf.net/sfu/SauceLabs _______________________________________________ tmux-users mailing list tmux-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tmux-users