Support the latest theory for mouse input, this is enabled/disabled with

SM/RM 1006 and is similar in style to SGR input: \033[<b;x;yM or
\033[b;x;ym. From Egmont Koblinger.
This commit is contained in:
Nicholas Marriott 2013-03-22 10:33:50 +00:00
parent ad760b3bf7
commit 67b4d5b609
5 changed files with 132 additions and 49 deletions

View File

@ -202,12 +202,25 @@ input_key(struct window_pane *wp, int key)
void void
input_mouse(struct window_pane *wp, struct session *s, struct mouse_event *m) input_mouse(struct window_pane *wp, struct session *s, struct mouse_event *m)
{ {
char buf[10]; char buf[40];
size_t len; size_t len;
struct paste_buffer *pb; struct paste_buffer *pb;
if (wp->screen->mode & ALL_MOUSE_MODES) { if (wp->screen->mode & ALL_MOUSE_MODES) {
if (wp->screen->mode & MODE_MOUSE_UTF8) { /*
* Use the SGR (1006) extension only if the application
* requested it and the underlying terminal also sent the event
* in this format (this is because an old style mouse release
* event cannot be converted into the new SGR format, since the
* released button is unknown). Otherwise pretend that tmux
* doesn't speak this extension, and fall back to the UTF-8
* (1005) extension if the application requested, or to the
* legacy format.
*/
if (m->sgr && (wp->screen->mode & MODE_MOUSE_SGR)) {
len = xsnprintf(buf, sizeof buf, "\033[<%d;%d;%d%c",
m->sgr_xb, m->x + 1, m->y + 1, m->sgr_rel ? 'm' : 'M');
} else if (wp->screen->mode & MODE_MOUSE_UTF8) {
len = xsnprintf(buf, sizeof buf, "\033[M"); len = xsnprintf(buf, sizeof buf, "\033[M");
len += utf8_split2(m->xb + 32, &buf[len]); len += utf8_split2(m->xb + 32, &buf[len]);
len += utf8_split2(m->x + 33, &buf[len]); len += utf8_split2(m->x + 33, &buf[len]);

View File

@ -1260,6 +1260,9 @@ input_csi_dispatch(struct input_ctx *ictx)
case 1005: case 1005:
screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_UTF8); screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_UTF8);
break; break;
case 1006:
screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_SGR);
break;
case 47: case 47:
case 1047: case 1047:
window_pane_alternate_off(wp, &ictx->cell, 0); window_pane_alternate_off(wp, &ictx->cell, 0);
@ -1320,6 +1323,9 @@ input_csi_dispatch(struct input_ctx *ictx)
case 1005: case 1005:
screen_write_mode_set(&ictx->ctx, MODE_MOUSE_UTF8); screen_write_mode_set(&ictx->ctx, MODE_MOUSE_UTF8);
break; break;
case 1006:
screen_write_mode_set(&ictx->ctx, MODE_MOUSE_SGR);
break;
case 47: case 47:
case 1047: case 1047:
window_pane_alternate_on(wp, &ictx->cell, 0); window_pane_alternate_on(wp, &ictx->cell, 0);

View File

@ -41,7 +41,6 @@ screen_write_start(
} }
/* Finish writing. */ /* Finish writing. */
/* ARGSUSED */
void void
screen_write_stop(unused struct screen_write_ctx *ctx) screen_write_stop(unused struct screen_write_ctx *ctx)
{ {
@ -56,7 +55,9 @@ screen_write_reset(struct screen_write_ctx *ctx)
screen_reset_tabs(s); screen_reset_tabs(s);
screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1); screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1);
s->mode &= ~(MODE_INSERT|MODE_KCURSOR|MODE_KKEYPAD|ALL_MOUSE_MODES);
s->mode &= ~(MODE_INSERT|MODE_KCURSOR|MODE_KKEYPAD);
s->mode &= ~(ALL_MOUSE_MODES|MODE_MOUSE_UTF8|MODE_MOUSE_SGR);
screen_write_clearscreen(ctx); screen_write_clearscreen(ctx);
screen_write_cursormove(ctx, 0, 0); screen_write_cursormove(ctx, 0, 0);

10
tmux.h
View File

@ -665,7 +665,8 @@ struct mode_key_table {
#define MODE_MOUSE_BUTTON 0x40 #define MODE_MOUSE_BUTTON 0x40
#define MODE_MOUSE_ANY 0x80 #define MODE_MOUSE_ANY 0x80
#define MODE_MOUSE_UTF8 0x100 #define MODE_MOUSE_UTF8 0x100
#define MODE_BRACKETPASTE 0x200 #define MODE_MOUSE_SGR 0x200
#define MODE_BRACKETPASTE 0x400
#define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ANY) #define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ANY)
@ -1153,6 +1154,9 @@ LIST_HEAD(tty_terms, tty_term);
* - bits 3, 4 and 5 are for keys * - bits 3, 4 and 5 are for keys
* - bit 6 is set for dragging * - bit 6 is set for dragging
* - bit 7 for buttons 4 and 5 * - bit 7 for buttons 4 and 5
*
* With the SGR 1006 extension the released button becomes known. Store these
* in separate fields and store the value converted to the old format in xb.
*/ */
struct mouse_event { struct mouse_event {
u_int xb; u_int xb;
@ -1165,6 +1169,10 @@ struct mouse_event {
u_int ly; u_int ly;
u_int sy; u_int sy;
u_int sgr; /* whether the input arrived in SGR format */
u_int sgr_xb; /* only for SGR: the unmangled button */
u_int sgr_rel; /* only for SGR: whether it is a release event */
u_int button; u_int button;
u_int clicks; u_int clicks;

View File

@ -364,8 +364,6 @@ tty_keys_build(struct tty *tty)
tty_keys_add(tty, s, tdkc->key); tty_keys_add(tty, s, tdkc->key);
} }
tty_keys_add(tty, "abc", 'x');
} }
/* Free the entire key tree. */ /* Free the entire key tree. */
@ -569,7 +567,6 @@ complete_key:
} }
/* Key timer callback. */ /* Key timer callback. */
/* ARGSUSED */
void void
tty_keys_callback(unused int fd, unused short events, void *data) tty_keys_callback(unused int fd, unused short events, void *data)
{ {
@ -590,20 +587,26 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
{ {
struct mouse_event *m = &tty->mouse; struct mouse_event *m = &tty->mouse;
struct utf8_data utf8data; struct utf8_data utf8data;
u_int i, value, x, y, b; u_int i, value, x, y, b, sgr, sgr_b, sgr_rel;
unsigned char c;
/* /*
* Standard mouse sequences are \033[M followed by three characters * Standard mouse sequences are \033[M followed by three characters
* indicating buttons, X and Y, all based at 32 with 1,1 top-left. * indicating button, X and Y, all based at 32 with 1,1 top-left.
* *
* UTF-8 mouse sequences are similar but the three are expressed as * UTF-8 mouse sequences are similar but the three are expressed as
* UTF-8 characters. * UTF-8 characters.
*
* SGR extended mouse sequences are \033[< followed by three numbers in
* decimal and separated by semicolons indicating button, X and Y. A
* trailing 'M' is click or scroll and trailing 'm' release. All are
* based at 0 with 1,1 top-left.
*/ */
*size = 0; *size = 0;
x = y = b = 0; x = y = b = sgr = sgr_b = sgr_rel = 0;
/* First three bytes are always \033[M. */ /* First two bytes are always \033[. */
if (buf[0] != '\033') if (buf[0] != '\033')
return (-1); return (-1);
if (len == 1) if (len == 1)
@ -612,15 +615,16 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
return (-1); return (-1);
if (len == 2) if (len == 2)
return (1); return (1);
if (buf[2] != 'M')
return (-1);
if (len == 3)
return (1);
/*
* Third byte is M in old standard and UTF-8 extension, < in SGR
* extension.
*/
if (buf[2] == 'M') {
/* Read the three inputs. */ /* Read the three inputs. */
*size = 3; *size = 3;
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
if (len < *size) if (len <= *size)
return (1); return (1);
if (tty->mode & MODE_MOUSE_UTF8) { if (tty->mode & MODE_MOUSE_UTF8) {
@ -628,15 +632,15 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
if (utf8data.size != 2) if (utf8data.size != 2)
return (-1); return (-1);
(*size)++; (*size)++;
if (len < *size) if (len <= *size)
return (1); return (1);
utf8_append(&utf8data, buf[*size]); utf8_append(&utf8data, buf[*size]);
value = utf8_combine(&utf8data); value = utf8_combine(&utf8data);
} else } else
value = (unsigned char)buf[*size]; value = (u_char) buf[*size];
(*size)++; (*size)++;
} else { } else {
value = (unsigned char)buf[*size]; value = (u_char) buf[*size];
(*size)++; (*size)++;
} }
@ -655,7 +659,55 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
b -= 32; b -= 32;
x -= 33; x -= 33;
y -= 33; y -= 33;
log_debug("mouse position: x=%u y=%u b=%u", x, y, b); } else if (buf[2] == '<') {
/* Read the three inputs. */
*size = 3;
while (1) {
if (len <= *size)
return (1);
c = (u_char)buf[(*size)++];
if (c == ';')
break;
if (c < '0' || c > '9')
return (-1);
sgr_b = 10 * sgr_b + (c - '0');
}
while (1) {
if (len <= *size)
return (1);
c = (u_char)buf[(*size)++];
if (c == ';')
break;
if (c < '0' || c > '9')
return (-1);
x = 10 * x + (c - '0');
}
while (1) {
if (len <= *size)
return (1);
c = (u_char) buf[(*size)++];
if (c == 'M' || c == 'm')
break;
if (c < '0' || c > '9')
return (-1);
y = 10 * y + (c - '0');
}
log_debug("mouse input (sgr): %.*s", (int) *size, buf);
/* Check and return the mouse input. */
if (x < 1 || y < 1)
return (-1);
x--;
y--;
sgr = 1;
sgr_rel = (c == 'm');
/* Figure out what b would be in old format. */
b = sgr_b;
if (sgr_rel)
b |= 3;
} else
return (-1);
/* Fill in mouse structure. */ /* Fill in mouse structure. */
if (~m->event & MOUSE_EVENT_WHEEL) { if (~m->event & MOUSE_EVENT_WHEEL) {
@ -663,6 +715,9 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
m->ly = m->y; m->ly = m->y;
} }
m->xb = b; m->xb = b;
m->sgr = sgr;
m->sgr_xb = sgr_b;
m->sgr_rel = sgr_rel;
if (b & 64) { /* wheel button */ if (b & 64) { /* wheel button */
b &= 3; b &= 3;
if (b == 0) if (b == 0)