=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/tmux/server-client.c,v retrieving revision 1.131 retrieving revision 1.132 diff -c -r1.131 -r1.132 *** src/usr.bin/tmux/server-client.c 2015/04/19 21:34:21 1.131 --- src/usr.bin/tmux/server-client.c 2015/04/20 15:34:56 1.132 *************** *** 1,4 **** ! /* $OpenBSD: server-client.c,v 1.131 2015/04/19 21:34:21 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott --- 1,4 ---- ! /* $OpenBSD: server-client.c,v 1.132 2015/04/20 15:34:56 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott *************** *** 30,35 **** --- 30,36 ---- #include "tmux.h" + void server_client_key_table(struct client *, const char *); void server_client_check_focus(struct window_pane *); void server_client_check_resize(struct window_pane *); int server_client_check_mouse(struct client *); *************** *** 45,50 **** --- 46,60 ---- void server_client_msg_identify(struct client *, struct imsg *); void server_client_msg_shell(struct client *); + /* Set client key table. */ + void + server_client_key_table(struct client *c, const char *name) + { + key_bindings_unref_table(c->keytable); + c->keytable = key_bindings_get_table(name, 1); + c->keytable->references++; + } + /* Create a new client. */ void server_client_create(int fd) *************** *** 93,98 **** --- 103,111 ---- c->flags |= CLIENT_FOCUSED; + c->keytable = key_bindings_get_table("root", 1); + c->keytable->references++; + evtimer_set(&c->repeat_timer, server_client_repeat_timer, c); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { *************** *** 164,169 **** --- 177,184 ---- evtimer_del(&c->repeat_timer); + key_bindings_unref_table(c->keytable); + if (event_initialized(&c->identify_timer)) evtimer_del(&c->identify_timer); *************** *** 527,542 **** server_client_handle_key(struct client *c, int key) { struct mouse_event *m = &c->tty.mouse; ! struct session *s; struct window *w; struct window_pane *wp; struct timeval tv; ! struct key_binding *bd; ! int xtimeout, isprefix, ispaste; /* Check the client is good to accept input. */ ! if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) return; /* No session, do nothing. */ if (c->session == NULL) --- 542,560 ---- server_client_handle_key(struct client *c, int key) { struct mouse_event *m = &c->tty.mouse; ! struct session *s = c->session; struct window *w; struct window_pane *wp; struct timeval tv; ! struct key_table *table = c->keytable; ! struct key_binding bd_find, *bd; ! int xtimeout; /* Check the client is good to accept input. */ ! if (s == NULL || (c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) return; + w = s->curw->window; + wp = w->active; /* No session, do nothing. */ if (c->session == NULL) *************** *** 552,558 **** sizeof s->last_activity_time); memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time); ! /* Special case: number keys jump to pane in identify mode. */ if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { if (c->flags & CLIENT_READONLY) return; --- 570,576 ---- sizeof s->last_activity_time); memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time); ! /* Number keys jump to pane in identify mode. */ if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { if (c->flags & CLIENT_READONLY) return; *************** *** 593,666 **** } else m->valid = 0; ! /* Is this a prefix key? */ ! if (key == options_get_number(&s->options, "prefix")) ! isprefix = 1; ! else if (key == options_get_number(&s->options, "prefix2")) ! isprefix = 1; ! else ! isprefix = 0; ! /* Treat prefix as a regular key when pasting is detected. */ ! ispaste = server_client_assume_paste(s); ! if (ispaste) ! isprefix = 0; ! ! /* No previous prefix key. */ ! if (!(c->flags & CLIENT_PREFIX)) { ! if (isprefix) { ! c->flags |= CLIENT_PREFIX; server_status_client(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, c, s, key, m); ! } else ! key_bindings_dispatch(bd, c, m); ! 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) { c->flags &= ~CLIENT_REPEAT; ! if (isprefix) ! c->flags |= CLIENT_PREFIX; ! else if (!(c->flags & CLIENT_READONLY)) ! window_pane_key(wp, c, s, key, m); } return; } ! /* 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, c, s, key, m); ! 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); } ! /* Dispatch the command. */ ! key_bindings_dispatch(bd, c, m); } /* Client functions that need to happen every loop. */ --- 611,698 ---- } else m->valid = 0; ! /* Treat everything as a regular key when pasting is detected. */ ! if (server_client_assume_paste(s)) { ! if (!(c->flags & CLIENT_READONLY)) ! window_pane_key(wp, c, s, key, m); ! return; ! } ! retry: ! /* Try to see if there is a key binding in the current table. */ ! bd_find.key = key; ! bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find); ! if (bd != NULL) { ! /* ! * Key was matched in this table. If currently repeating but a ! * non-repeating binding was found, stop repeating and try ! * again in the root table. ! */ ! if ((c->flags & CLIENT_REPEAT) && !bd->can_repeat) { ! server_client_key_table(c, "root"); ! c->flags &= ~CLIENT_REPEAT; server_status_client(c); ! goto retry; } ! /* ! * Take a reference to this table to make sure the key binding ! * doesn't disappear. ! */ ! table->references++; ! /* ! * If this is a repeating key, start the timer. Otherwise reset ! * the client back to the root table. ! */ ! xtimeout = options_get_number(&s->options, "repeat-time"); ! if (xtimeout != 0 && bd->can_repeat) { ! 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 { c->flags &= ~CLIENT_REPEAT; ! server_client_key_table(c, "root"); } + server_status_client(c); + + /* Dispatch the key binding. */ + key_bindings_dispatch(bd, c, m); + key_bindings_unref_table(table); return; } ! /* ! * No match in this table. If repeating, switch the client back to the ! * root table and try again. ! */ ! if (c->flags & CLIENT_REPEAT) { ! server_client_key_table(c, "root"); 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"); ! server_status_client(c); ! return; } ! /* ! * No match, but in the root table. Prefix switches to the prefix table ! * and everything else is passed through. ! */ ! if (key == options_get_number(&s->options, "prefix") || ! key == options_get_number(&s->options, "prefix2")) { ! server_client_key_table(c, "prefix"); ! server_status_client(c); ! } else if (!(c->flags & CLIENT_READONLY)) ! window_pane_key(wp, c, s, key, m); } /* Client functions that need to happen every loop. */ *************** *** 848,856 **** struct client *c = data; if (c->flags & CLIENT_REPEAT) { ! if (c->flags & CLIENT_PREFIX) ! server_status_client(c); ! c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); } } --- 880,888 ---- struct client *c = data; if (c->flags & CLIENT_REPEAT) { ! server_client_key_table(c, "root"); ! c->flags &= ~CLIENT_REPEAT; ! server_status_client(c); } }