Instead of processing keys all together, put them up on the client

command queue so they are ordered correctly with the commands that they
execute.
pull/1731/head
nicm 2019-05-03 14:51:30 +00:00
parent 4bb48998e0
commit 33298d6df6
3 changed files with 85 additions and 51 deletions

View File

@ -35,7 +35,7 @@
static void server_client_free(int, short, void *); static void server_client_free(int, short, void *);
static void server_client_check_focus(struct window_pane *); static void server_client_check_focus(struct window_pane *);
static void server_client_check_resize(struct window_pane *); static void server_client_check_resize(struct window_pane *);
static key_code server_client_check_mouse(struct client *); static key_code server_client_check_mouse(struct client *, struct key_event *);
static void server_client_repeat_timer(int, short, void *); static void server_client_repeat_timer(int, short, void *);
static void server_client_click_timer(int, short, void *); static void server_client_click_timer(int, short, void *);
static void server_client_check_exit(struct client *); static void server_client_check_exit(struct client *);
@ -407,10 +407,10 @@ server_client_exec(struct client *c, const char *cmd)
/* Check for mouse keys. */ /* Check for mouse keys. */
static key_code static key_code
server_client_check_mouse(struct client *c) server_client_check_mouse(struct client *c, struct key_event *event)
{ {
struct mouse_event *m = &event->m;
struct session *s = c->session; struct session *s = c->session;
struct mouse_event *m = &c->tty.mouse;
struct winlink *wl; struct winlink *wl;
struct window_pane *wp; struct window_pane *wp;
u_int x, y, b, sx, sy, px, py; u_int x, y, b, sx, sy, px, py;
@ -419,7 +419,13 @@ server_client_check_mouse(struct client *c)
struct timeval tv; struct timeval tv;
struct style_range *sr; struct style_range *sr;
enum { NOTYPE, MOVE, DOWN, UP, DRAG, WHEEL, DOUBLE, TRIPLE } type; enum { NOTYPE, MOVE, DOWN, UP, DRAG, WHEEL, DOUBLE, TRIPLE } type;
enum { NOWHERE, PANE, STATUS, STATUS_LEFT, STATUS_RIGHT, STATUS_DEFAULT, BORDER } where; enum { NOWHERE,
PANE,
STATUS,
STATUS_LEFT,
STATUS_RIGHT,
STATUS_DEFAULT,
BORDER } where;
type = NOTYPE; type = NOTYPE;
where = NOWHERE; where = NOWHERE;
@ -976,11 +982,17 @@ server_client_assume_paste(struct session *s)
return (0); return (0);
} }
/* Handle data key input from client. */ /*
void * Handle data key input from client. This owns and can modify the key event it
server_client_handle_key(struct client *c, key_code key) * is given and is responsible for freeing it.
*/
enum cmd_retval
server_client_key_callback(struct cmdq_item *item, void *data)
{ {
struct mouse_event *m = &c->tty.mouse; struct client *c = item->client;
struct key_event *event = data;
key_code key = event->key;
struct mouse_event *m = &event->m;
struct session *s = c->session; struct session *s = c->session;
struct winlink *wl; struct winlink *wl;
struct window *w; struct window *w;
@ -995,7 +1007,7 @@ server_client_handle_key(struct client *c, key_code key)
/* Check the client is good to accept input. */ /* Check the client is good to accept input. */
if (s == NULL || (c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) if (s == NULL || (c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
return; goto out;
wl = s->curw; wl = s->curw;
w = wl->window; w = wl->window;
@ -1007,11 +1019,11 @@ server_client_handle_key(struct client *c, key_code key)
/* 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; goto out;
window_unzoom(w); window_unzoom(w);
wp = window_pane_at_index(w, key - '0'); wp = window_pane_at_index(w, key - '0');
server_client_clear_identify(c, wp); server_client_clear_identify(c, wp);
return; goto out;
} }
/* Handle status line. */ /* Handle status line. */
@ -1021,19 +1033,19 @@ server_client_handle_key(struct client *c, key_code key)
} }
if (c->prompt_string != NULL) { if (c->prompt_string != NULL) {
if (c->flags & CLIENT_READONLY) if (c->flags & CLIENT_READONLY)
return; goto out;
if (status_prompt_key(c, key) == 0) if (status_prompt_key(c, key) == 0)
return; goto out;
} }
/* Check for mouse keys. */ /* Check for mouse keys. */
m->valid = 0; m->valid = 0;
if (key == KEYC_MOUSE) { if (key == KEYC_MOUSE) {
if (c->flags & CLIENT_READONLY) if (c->flags & CLIENT_READONLY)
return; goto out;
key = server_client_check_mouse(c); key = server_client_check_mouse(c, event);
if (key == KEYC_UNKNOWN) if (key == KEYC_UNKNOWN)
return; goto out;
m->valid = 1; m->valid = 1;
m->key = key; m->key = key;
@ -1044,10 +1056,9 @@ server_client_handle_key(struct client *c, key_code key)
*/ */
if (key == KEYC_DRAGGING) { if (key == KEYC_DRAGGING) {
c->tty.mouse_drag_update(c, m); c->tty.mouse_drag_update(c, m);
return; goto out;
} }
} else }
m->valid = 0;
/* Find affected pane. */ /* Find affected pane. */
if (!KEYC_IS_MOUSE(key) || cmd_find_from_mouse(&fs, m, 0) != 0) if (!KEYC_IS_MOUSE(key) || cmd_find_from_mouse(&fs, m, 0) != 0)
@ -1086,7 +1097,7 @@ table_changed:
strcmp(table->name, "prefix") != 0) { strcmp(table->name, "prefix") != 0) {
server_client_set_key_table(c, "prefix"); server_client_set_key_table(c, "prefix");
server_status_client(c); server_status_client(c);
return; goto out;
} }
flags = c->flags; flags = c->flags;
@ -1144,9 +1155,9 @@ try_again:
server_status_client(c); server_status_client(c);
/* Execute the key binding. */ /* Execute the key binding. */
key_bindings_dispatch(bd, NULL, c, m, &fs); key_bindings_dispatch(bd, item, c, m, &fs);
key_bindings_unref_table(table); key_bindings_unref_table(table);
return; goto out;
} }
/* /*
@ -1181,14 +1192,18 @@ try_again:
if (first != table && (~flags & CLIENT_REPEAT)) { if (first != table && (~flags & CLIENT_REPEAT)) {
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
server_status_client(c); server_status_client(c);
return; goto out;
} }
forward_key: forward_key:
if (c->flags & CLIENT_READONLY) if (c->flags & CLIENT_READONLY)
return; goto out;
if (wp != NULL) if (wp != NULL)
window_pane_key(wp, c, s, wl, key, m); window_pane_key(wp, c, s, wl, key, m);
out:
free(event);
return (CMD_RETURN_NORMAL);
} }
/* Client functions that need to happen every loop. */ /* Client functions that need to happen every loop. */

13
tmux.h
View File

@ -1052,6 +1052,12 @@ struct mouse_event {
u_int sgr_b; u_int sgr_b;
}; };
/* Key event. */
struct key_event {
key_code key;
struct mouse_event m;
};
/* TTY information. */ /* TTY information. */
struct tty_key { struct tty_key {
char ch; char ch;
@ -1143,7 +1149,8 @@ struct tty {
TTY_UNKNOWN TTY_UNKNOWN
} term_type; } term_type;
struct mouse_event mouse; u_int mouse_last_x;
u_int mouse_last_y;
int mouse_drag_flag; int mouse_drag_flag;
void (*mouse_drag_update)(struct client *, void (*mouse_drag_update)(struct client *,
struct mouse_event *); struct mouse_event *);
@ -1864,7 +1871,7 @@ const char *tty_acs_get(struct tty *, u_char);
/* tty-keys.c */ /* tty-keys.c */
void tty_keys_build(struct tty *); void tty_keys_build(struct tty *);
void tty_keys_free(struct tty *); void tty_keys_free(struct tty *);
key_code tty_keys_next(struct tty *); int tty_keys_next(struct tty *);
/* arguments.c */ /* arguments.c */
void args_set(struct args *, u_char, const char *); void args_set(struct args *, u_char, const char *);
@ -2002,7 +2009,7 @@ void server_client_set_identify(struct client *, u_int);
void server_client_set_key_table(struct client *, const char *); void server_client_set_key_table(struct client *, const char *);
const char *server_client_get_key_table(struct client *); const char *server_client_get_key_table(struct client *);
int server_client_check_nested(struct client *); int server_client_check_nested(struct client *);
void server_client_handle_key(struct client *, key_code); enum cmd_retval server_client_key_callback(struct cmdq_item *, void *);
struct client *server_client_create(int); struct client *server_client_create(int);
int server_client_open(struct client *, char **); int server_client_open(struct client *, char **);
void server_client_unref(struct client *); void server_client_unref(struct client *);

View File

@ -46,7 +46,8 @@ static struct tty_key *tty_keys_find(struct tty *, const char *, size_t,
static int tty_keys_next1(struct tty *, const char *, size_t, key_code *, static int tty_keys_next1(struct tty *, const char *, size_t, key_code *,
size_t *, int); size_t *, int);
static void tty_keys_callback(int, short, void *); static void tty_keys_callback(int, short, void *);
static int tty_keys_mouse(struct tty *, const char *, size_t, size_t *); static int tty_keys_mouse(struct tty *, const char *, size_t, size_t *,
struct mouse_event *);
static int tty_keys_clipboard(struct tty *, const char *, size_t, static int tty_keys_clipboard(struct tty *, const char *, size_t,
size_t *); size_t *);
static int tty_keys_device_attributes(struct tty *, const char *, size_t, static int tty_keys_device_attributes(struct tty *, const char *, size_t,
@ -560,25 +561,26 @@ tty_keys_next1(struct tty *tty, const char *buf, size_t len, key_code *key,
return (-1); return (-1);
} }
/* /* Process at least one key in the buffer. Return 0 if no keys present. */
* Process at least one key in the buffer and invoke tty->key_callback. Return int
* 0 if there are no further keys, or 1 if there could be more in the buffer.
*/
key_code
tty_keys_next(struct tty *tty) tty_keys_next(struct tty *tty)
{ {
struct client *c = tty->client; struct client *c = tty->client;
struct timeval tv; struct timeval tv;
const char *buf; const char *buf;
size_t len, size; size_t len, size;
cc_t bspace; cc_t bspace;
int delay, expired = 0, n; int delay, expired = 0, n;
key_code key; key_code key;
struct cmdq_item *item;
struct mouse_event m = { 0 };
struct key_event *event;
gettimeofday(&tv, NULL);
/* Get key buffer. */ /* Get key buffer. */
buf = EVBUFFER_DATA(tty->in); buf = EVBUFFER_DATA(tty->in);
len = EVBUFFER_LENGTH(tty->in); len = EVBUFFER_LENGTH(tty->in);
if (len == 0) if (len == 0)
return (0); return (0);
log_debug("%s: keys are %zu (%.*s)", c->name, len, (int)len, buf); log_debug("%s: keys are %zu (%.*s)", c->name, len, (int)len, buf);
@ -606,7 +608,7 @@ tty_keys_next(struct tty *tty)
} }
/* Is this a mouse key press? */ /* Is this a mouse key press? */
switch (tty_keys_mouse(tty, buf, len, &size)) { switch (tty_keys_mouse(tty, buf, len, &size, &m)) {
case 0: /* yes */ case 0: /* yes */
key = KEYC_MOUSE; key = KEYC_MOUSE;
goto complete_key; goto complete_key;
@ -725,8 +727,14 @@ complete_key:
} }
/* Fire the key. */ /* Fire the key. */
if (key != KEYC_UNKNOWN) if (key != KEYC_UNKNOWN) {
server_client_handle_key(tty->client, key); event = xmalloc(sizeof *event);
event->key = key;
memcpy(&event->m, &m, sizeof event->m);
item = cmdq_get_callback(server_client_key_callback, event);
cmdq_append(c, item);
}
return (1); return (1);
@ -756,12 +764,12 @@ tty_keys_callback(__unused int fd, __unused short events, void *data)
* (probably a mouse sequence but need more data). * (probably a mouse sequence but need more data).
*/ */
static int static int
tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size,
struct mouse_event *m)
{ {
struct client *c = tty->client; struct client *c = tty->client;
struct mouse_event *m = &tty->mouse; u_int i, x, y, b, sgr_b;
u_int i, x, y, b, sgr_b; u_char sgr_type, ch;
u_char sgr_type, ch;
/* /*
* Standard mouse sequences are \033[M followed by three characters * Standard mouse sequences are \033[M followed by three characters
@ -882,15 +890,19 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
return (-1); return (-1);
/* Fill mouse event. */ /* Fill mouse event. */
m->lx = m->x; m->lx = tty->mouse_last_x;
m->x = x; m->x = x;
m->ly = m->y; m->ly = tty->mouse_last_y;
m->y = y; m->y = y;
m->lb = m->b; m->lb = m->b;
m->b = b; m->b = b;
m->sgr_type = sgr_type; m->sgr_type = sgr_type;
m->sgr_b = sgr_b; m->sgr_b = sgr_b;
/* Update last mouse state. */
tty->mouse_last_x = x;
tty->mouse_last_y = y;
return (0); return (0);
} }