version 1.131, 2015/04/19 21:34:21 |
version 1.132, 2015/04/20 15:34:56 |
|
|
|
|
#include "tmux.h" |
#include "tmux.h" |
|
|
|
void server_client_key_table(struct client *, const char *); |
void server_client_check_focus(struct window_pane *); |
void server_client_check_focus(struct window_pane *); |
void server_client_check_resize(struct window_pane *); |
void server_client_check_resize(struct window_pane *); |
int server_client_check_mouse(struct client *); |
int server_client_check_mouse(struct client *); |
|
|
void server_client_msg_identify(struct client *, struct imsg *); |
void server_client_msg_identify(struct client *, struct imsg *); |
void server_client_msg_shell(struct client *); |
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. */ |
/* Create a new client. */ |
void |
void |
server_client_create(int fd) |
server_client_create(int fd) |
|
|
|
|
c->flags |= CLIENT_FOCUSED; |
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); |
evtimer_set(&c->repeat_timer, server_client_repeat_timer, c); |
|
|
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { |
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { |
|
|
|
|
evtimer_del(&c->repeat_timer); |
evtimer_del(&c->repeat_timer); |
|
|
|
key_bindings_unref_table(c->keytable); |
|
|
if (event_initialized(&c->identify_timer)) |
if (event_initialized(&c->identify_timer)) |
evtimer_del(&c->identify_timer); |
evtimer_del(&c->identify_timer); |
|
|
|
|
server_client_handle_key(struct client *c, int key) |
server_client_handle_key(struct client *c, int key) |
{ |
{ |
struct mouse_event *m = &c->tty.mouse; |
struct mouse_event *m = &c->tty.mouse; |
struct session *s; |
struct session *s = c->session; |
struct window *w; |
struct window *w; |
struct window_pane *wp; |
struct window_pane *wp; |
struct timeval tv; |
struct timeval tv; |
struct key_binding *bd; |
struct key_table *table = c->keytable; |
int xtimeout, isprefix, ispaste; |
struct key_binding bd_find, *bd; |
|
int xtimeout; |
|
|
/* Check the client is good to accept input. */ |
/* Check the client is good to accept input. */ |
if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) |
if (s == NULL || (c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) |
return; |
return; |
|
w = s->curw->window; |
|
wp = w->active; |
|
|
/* No session, do nothing. */ |
/* No session, do nothing. */ |
if (c->session == NULL) |
if (c->session == NULL) |
|
|
sizeof s->last_activity_time); |
sizeof s->last_activity_time); |
memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time); |
memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time); |
|
|
/* Special case: number keys jump to pane in identify mode. */ |
/* Number keys jump to pane in identify mode. */ |
if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { |
if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { |
if (c->flags & CLIENT_READONLY) |
if (c->flags & CLIENT_READONLY) |
return; |
return; |
|
|
} else |
} else |
m->valid = 0; |
m->valid = 0; |
|
|
/* Is this a prefix key? */ |
/* Treat everything as a regular key when pasting is detected. */ |
if (key == options_get_number(&s->options, "prefix")) |
if (server_client_assume_paste(s)) { |
isprefix = 1; |
if (!(c->flags & CLIENT_READONLY)) |
else if (key == options_get_number(&s->options, "prefix2")) |
window_pane_key(wp, c, s, key, m); |
isprefix = 1; |
return; |
else |
} |
isprefix = 0; |
|
|
|
/* Treat prefix as a regular key when pasting is detected. */ |
retry: |
ispaste = server_client_assume_paste(s); |
/* Try to see if there is a key binding in the current table. */ |
if (ispaste) |
bd_find.key = key; |
isprefix = 0; |
bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find); |
|
if (bd != NULL) { |
/* No previous prefix key. */ |
/* |
if (!(c->flags & CLIENT_PREFIX)) { |
* Key was matched in this table. If currently repeating but a |
if (isprefix) { |
* non-repeating binding was found, stop repeating and try |
c->flags |= CLIENT_PREFIX; |
* 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); |
server_status_client(c); |
return; |
goto retry; |
} |
} |
|
|
/* Try as a non-prefix key binding. */ |
/* |
if (ispaste || (bd = key_bindings_lookup(key)) == NULL) { |
* Take a reference to this table to make sure the key binding |
if (!(c->flags & CLIENT_READONLY)) |
* doesn't disappear. |
window_pane_key(wp, c, s, key, m); |
*/ |
} else |
table->references++; |
key_bindings_dispatch(bd, c, m); |
|
return; |
|
} |
|
|
|
/* Prefix key already pressed. Reset prefix and lookup key. */ |
/* |
c->flags &= ~CLIENT_PREFIX; |
* If this is a repeating key, start the timer. Otherwise reset |
server_status_client(c); |
* the client back to the root table. |
if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) { |
*/ |
/* If repeating, treat this as a key, else ignore. */ |
xtimeout = options_get_number(&s->options, "repeat-time"); |
if (c->flags & CLIENT_REPEAT) { |
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; |
c->flags &= ~CLIENT_REPEAT; |
if (isprefix) |
server_client_key_table(c, "root"); |
c->flags |= CLIENT_PREFIX; |
|
else if (!(c->flags & CLIENT_READONLY)) |
|
window_pane_key(wp, c, s, key, m); |
|
} |
} |
|
server_status_client(c); |
|
|
|
/* Dispatch the key binding. */ |
|
key_bindings_dispatch(bd, c, m); |
|
key_bindings_unref_table(table); |
return; |
return; |
} |
} |
|
|
/* If already repeating, but this key can't repeat, skip it. */ |
/* |
if (c->flags & CLIENT_REPEAT && !bd->can_repeat) { |
* 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; |
c->flags &= ~CLIENT_REPEAT; |
if (isprefix) |
server_status_client(c); |
c->flags |= CLIENT_PREFIX; |
goto retry; |
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. */ |
/* If no match and we're not in the root table, that's it. */ |
xtimeout = options_get_number(&s->options, "repeat-time"); |
if (strcmp(c->keytable->name, "root") != 0) { |
if (xtimeout != 0 && bd->can_repeat) { |
server_client_key_table(c, "root"); |
c->flags |= CLIENT_PREFIX|CLIENT_REPEAT; |
server_status_client(c); |
|
return; |
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); |
* 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. */ |
/* Client functions that need to happen every loop. */ |
|
|
struct client *c = data; |
struct client *c = data; |
|
|
if (c->flags & CLIENT_REPEAT) { |
if (c->flags & CLIENT_REPEAT) { |
if (c->flags & CLIENT_PREFIX) |
server_client_key_table(c, "root"); |
server_status_client(c); |
c->flags &= ~CLIENT_REPEAT; |
c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); |
server_status_client(c); |
} |
} |
} |
} |
|
|