summaryrefslogtreecommitdiffstats
path: root/server-client.c
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@openbsd.org>2009-11-05 08:45:08 +0000
committerNicholas Marriott <nicm@openbsd.org>2009-11-05 08:45:08 +0000
commitb58bf49e913e61a4991c35257dd82e5dd4c907a2 (patch)
tree41dda2e503fdbe3fa1e25273556bda7c837af9cf /server-client.c
parent80444436f36724cc8ef306391b5b18be604109c8 (diff)
Switch tty key input over to happen on a read event. This is a bit more
complicated because of escape input, but in that case instead of processing a key immediately, schedule a timer and reprocess the bufer when it expires. This currently assumes that keys will be atomic (ie that if eg F1 is pressed the entire sequence is present in the buffer). This is usually but not always true, a change in the tree format so it can differentiate potential (partial) key sequences will happens soon and will allow this to be fixed.
Diffstat (limited to 'server-client.c')
-rw-r--r--server-client.c280
1 files changed, 142 insertions, 138 deletions
diff --git a/server-client.c b/server-client.c
index 5c15d502..dd386001 100644
--- a/server-client.c
+++ b/server-client.c
@@ -27,10 +27,11 @@
#include "tmux.h"
-void server_client_handle_data(struct client *);
+void server_client_handle_key(int, struct mouse_event *, void *);
void server_client_repeat_timer(int, short, void *);
void server_client_check_redraw(struct client *);
void server_client_set_title(struct client *);
+void server_client_reset_state(struct client *);
int server_client_msg_dispatch(struct client *);
void server_client_msg_command(struct client *, struct msg_command_data *);
@@ -226,6 +227,127 @@ server_client_status_timer(void)
}
}
+/* Handle data key input from client. */
+void
+server_client_handle_key(int key, struct mouse_event *mouse, void *data)
+{
+ struct client *c = data;
+ struct session *s;
+ struct window *w;
+ struct window_pane *wp;
+ struct options *oo;
+ struct timeval tv;
+ struct key_binding *bd;
+ struct keylist *keylist;
+ int xtimeout, isprefix;
+ u_int i;
+
+ /* Check the client is good to accept input. */
+ if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
+ return;
+ if (c->session == NULL)
+ return;
+ s = c->session;
+
+ /* Update the activity timer. */
+ if (gettimeofday(&c->activity_time, NULL) != 0)
+ fatal("gettimeofday failed");
+ memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time);
+
+ w = c->session->curw->window;
+ wp = w->active;
+ oo = &c->session->options;
+
+ /* Special case: number keys jump to pane in identify mode. */
+ if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') {
+ wp = window_pane_at_index(w, key - '0');
+ if (wp != NULL && window_pane_visible(wp))
+ window_set_active_pane(w, wp);
+ server_clear_identify(c);
+ return;
+ }
+
+ /* Handle status line. */
+ status_message_clear(c);
+ server_clear_identify(c);
+ if (c->prompt_string != NULL) {
+ status_prompt_key(c, key);
+ return;
+ }
+
+ /* Check for mouse keys. */
+ if (key == KEYC_MOUSE) {
+ if (options_get_number(oo, "mouse-select-pane")) {
+ window_set_active_at(w, mouse->x, mouse->y);
+ wp = w->active;
+ }
+ window_pane_mouse(wp, c, mouse);
+ return;
+ }
+
+ /* Is this a prefix key? */
+ keylist = options_get_data(&c->session->options, "prefix");
+ isprefix = 0;
+ for (i = 0; i < ARRAY_LENGTH(keylist); i++) {
+ if (key == ARRAY_ITEM(keylist, i)) {
+ isprefix = 1;
+ break;
+ }
+ }
+
+ /* No previous prefix key. */
+ if (!(c->flags & CLIENT_PREFIX)) {
+ if (isprefix)
+ c->flags |= CLIENT_PREFIX;
+ else {
+ /* Try as a non-prefix key binding. */
+ if ((bd = key_bindings_lookup(key)) == NULL)
+ window_pane_key(wp, c, key);
+ else
+ key_bindings_dispatch(bd, c);
+ }
+ return;
+ }
+
+ /* Prefix key already pressed. Reset prefix and lookup key. */
+ c->flags &= ~CLIENT_PREFIX;
+ 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
+ window_pane_key(wp, c, key);
+ }
+ 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
+ window_pane_key(wp, c, key);
+ return;
+ }
+
+ /* If this key can repeat, reset the repeat flags and timer. */
+ xtimeout = options_get_number(&c->session->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);
+}
+
/* Client functions that need to happen every loop. */
void
server_client_loop(void)
@@ -240,9 +362,8 @@ server_client_loop(void)
if (c == NULL || c->session == NULL)
continue;
- server_client_handle_data(c);
- if (c->session != NULL)
- server_client_check_redraw(c);
+ server_client_check_redraw(c);
+ server_client_reset_state(c);
}
/*
@@ -260,143 +381,24 @@ server_client_loop(void)
}
}
-/* Handle data input or output from client. */
+/*
+ * Update cursor position and mode settings. The scroll region and attributes
+ * are cleared when idle (waiting for an event) as this is the most likely time
+ * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a
+ * compromise between excessive resets and likelihood of an interrupt.
+ *
+ * tty_region/tty_reset/tty_update_mode already take care of not resetting
+ * things that are already in their default state.
+ */
void
-server_client_handle_data(struct client *c)
+server_client_reset_state(struct client *c)
{
- struct window *w;
- struct window_pane *wp;
- struct screen *s;
- struct options *oo;
- struct timeval tv, tv_now;
- struct key_binding *bd;
- struct keylist *keylist;
- struct mouse_event mouse;
- int key, status, xtimeout, mode, isprefix;
- u_int i;
-
- /* Get the time for the activity timer. */
- if (gettimeofday(&tv_now, NULL) != 0)
- fatal("gettimeofday failed");
- xtimeout = options_get_number(&c->session->options, "repeat-time");
-
- /* Process keys. */
- keylist = options_get_data(&c->session->options, "prefix");
- while (tty_keys_next(&c->tty, &key, &mouse) == 0) {
- if (c->session == NULL)
- return;
- w = c->session->curw->window;
- wp = w->active; /* could die */
- oo = &c->session->options;
-
- /* Update activity timer. */
- memcpy(&c->activity_time, &tv_now, sizeof c->activity_time);
- memcpy(&c->session->activity_time,
- &tv_now, sizeof c->session->activity_time);
-
- /* Special case: number keys jump to pane in identify mode. */
- if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') {
- wp = window_pane_at_index(w, key - '0');
- if (wp != NULL && window_pane_visible(wp))
- window_set_active_pane(w, wp);
- server_clear_identify(c);
- continue;
- }
-
- status_message_clear(c);
- server_clear_identify(c);
- if (c->prompt_string != NULL) {
- status_prompt_key(c, key);
- continue;
- }
+ struct window *w = c->session->curw->window;
+ struct window_pane *wp = w->active;
+ struct screen *s = wp->screen;
+ struct options *oo = &c->session->options;
+ int status, mode;
- /* Check for mouse keys. */
- if (key == KEYC_MOUSE) {
- if (options_get_number(oo, "mouse-select-pane")) {
- window_set_active_at(w, mouse.x, mouse.y);
- wp = w->active;
- }
- window_pane_mouse(wp, c, &mouse);
- continue;
- }
-
- /* Is this a prefix key? */
- isprefix = 0;
- for (i = 0; i < ARRAY_LENGTH(keylist); i++) {
- if (key == ARRAY_ITEM(keylist, i)) {
- isprefix = 1;
- break;
- }
- }
-
- /* No previous prefix key. */
- if (!(c->flags & CLIENT_PREFIX)) {
- if (isprefix)
- c->flags |= CLIENT_PREFIX;
- else {
- /* Try as a non-prefix key binding. */
- if ((bd = key_bindings_lookup(key)) == NULL)
- window_pane_key(wp, c, key);
- else
- key_bindings_dispatch(bd, c);
- }
- continue;
- }
-
- /* Prefix key already pressed. Reset prefix and lookup key. */
- c->flags &= ~CLIENT_PREFIX;
- 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
- window_pane_key(wp, c, key);
- }
- continue;
- }
-
- /* 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
- window_pane_key(wp, c, key);
- continue;
- }
-
- /* If this key can repeat, reset the repeat flags and timer. */
- 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);
- }
- if (c->session == NULL)
- return;
- w = c->session->curw->window;
- wp = w->active;
- oo = &c->session->options;
- s = wp->screen;
-
- /*
- * Update cursor position and mode settings. The scroll region and
- * attributes are cleared across poll(2) as this is the most likely
- * time a user may interrupt tmux, for example with ~^Z in ssh(1). This
- * is a compromise between excessive resets and likelihood of an
- * interrupt.
- *
- * tty_region/tty_reset/tty_update_mode already take care of not
- * resetting things that are already in their default state.
- */
tty_region(&c->tty, 0, c->tty.sy - 1);
status = options_get_number(oo, "status");
@@ -715,6 +717,8 @@ server_client_msg_identify(
c->tty.term_flags |= TERM_256COLOURS;
else if (data->flags & IDENTIFY_88COLOURS)
c->tty.term_flags |= TERM_88COLOURS;
+ c->tty.key_callback = server_client_handle_key;
+ c->tty.key_data = c;
tty_resize(&c->tty);