summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@openbsd.org>2013-03-22 10:33:50 +0000
committerNicholas Marriott <nicm@openbsd.org>2013-03-22 10:33:50 +0000
commit67b4d5b6094c8845af344d1386bb3fed86f54b5a (patch)
treee199e17567f0ee470f202006cfc699bdc8134712
parentad760b3bf702801eaa121715f2a283526d614913 (diff)
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.
-rw-r--r--input-keys.c17
-rw-r--r--input.c6
-rw-r--r--screen-write.c5
-rw-r--r--tmux.h10
-rw-r--r--tty-keys.c149
5 files changed, 135 insertions, 52 deletions
diff --git a/input-keys.c b/input-keys.c
index 2111f5f3..23549e32 100644
--- a/input-keys.c
+++ b/input-keys.c
@@ -202,12 +202,25 @@ input_key(struct window_pane *wp, int key)
void
input_mouse(struct window_pane *wp, struct session *s, struct mouse_event *m)
{
- char buf[10];
+ char buf[40];
size_t len;
struct paste_buffer *pb;
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 += utf8_split2(m->xb + 32, &buf[len]);
len += utf8_split2(m->x + 33, &buf[len]);
diff --git a/input.c b/input.c
index f44f602c..30f4f95d 100644
--- a/input.c
+++ b/input.c
@@ -1260,6 +1260,9 @@ input_csi_dispatch(struct input_ctx *ictx)
case 1005:
screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_UTF8);
break;
+ case 1006:
+ screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_SGR);
+ break;
case 47:
case 1047:
window_pane_alternate_off(wp, &ictx->cell, 0);
@@ -1320,6 +1323,9 @@ input_csi_dispatch(struct input_ctx *ictx)
case 1005:
screen_write_mode_set(&ictx->ctx, MODE_MOUSE_UTF8);
break;
+ case 1006:
+ screen_write_mode_set(&ictx->ctx, MODE_MOUSE_SGR);
+ break;
case 47:
case 1047:
window_pane_alternate_on(wp, &ictx->cell, 0);
diff --git a/screen-write.c b/screen-write.c
index 9cbb5bb9..bee6f6d7 100644
--- a/screen-write.c
+++ b/screen-write.c
@@ -41,7 +41,6 @@ screen_write_start(
}
/* Finish writing. */
-/* ARGSUSED */
void
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_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_cursormove(ctx, 0, 0);
diff --git a/tmux.h b/tmux.h
index afe55560..192a386f 100644
--- a/tmux.h
+++ b/tmux.h
@@ -665,7 +665,8 @@ struct mode_key_table {
#define MODE_MOUSE_BUTTON 0x40
#define MODE_MOUSE_ANY 0x80
#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)
@@ -1153,6 +1154,9 @@ LIST_HEAD(tty_terms, tty_term);
* - bits 3, 4 and 5 are for keys
* - bit 6 is set for dragging
* - 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 {
u_int xb;
@@ -1165,6 +1169,10 @@ struct mouse_event {
u_int ly;
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 clicks;
diff --git a/tty-keys.c b/tty-keys.c
index 7fb96786..cb34df93 100644
--- a/tty-keys.c
+++ b/tty-keys.c
@@ -364,8 +364,6 @@ tty_keys_build(struct tty *tty)
tty_keys_add(tty, s, tdkc->key);
}
-
- tty_keys_add(tty, "abc", 'x');
}
/* Free the entire key tree. */
@@ -569,7 +567,6 @@ complete_key:
}
/* Key timer callback. */
-/* ARGSUSED */
void
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 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
- * 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 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;
- 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')
return (-1);
if (len == 1)
@@ -612,50 +615,99 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
return (-1);
if (len == 2)
return (1);
- if (buf[2] != 'M')
- return (-1);
- if (len == 3)
- return (1);
- /* Read the three inputs. */
- *size = 3;
- for (i = 0; i < 3; i++) {
- if (len < *size)
- return (1);
-
- if (tty->mode & MODE_MOUSE_UTF8) {
- if (utf8_open(&utf8data, buf[*size])) {
- if (utf8data.size != 2)
- return (-1);
+ /*
+ * Third byte is M in old standard and UTF-8 extension, < in SGR
+ * extension.
+ */
+ if (buf[2] == 'M') {
+ /* Read the three inputs. */
+ *size = 3;
+ for (i = 0; i < 3; i++) {
+ if (len <= *size)
+ return (1);
+
+ if (tty->mode & MODE_MOUSE_UTF8) {
+ if (utf8_open(&utf8data, buf[*size])) {
+ if (utf8data.size != 2)
+ return (-1);
+ (*size)++;
+ if (len <= *size)
+ return (1);
+ utf8_append(&utf8data, buf[*size]);
+ value = utf8_combine(&utf8data);
+ } else
+ value = (u_char) buf[*size];
(*size)++;
- if (len < *size)
- return (1);
- utf8_append(&utf8data, buf[*size]);
- value = utf8_combine(&utf8data);
- } else
- value = (unsigned char)buf[*size];
- (*size)++;
- } else {
- value = (unsigned char)buf[*size];
- (*size)++;
- }
-
- if (i == 0)
- b = value;
- else if (i == 1)
- x = value;
- else
- y = value;
- }
- log_debug("mouse input: %.*s", (int) *size, buf);
+ } else {
+ value = (u_char) buf[*size];
+ (*size)++;
+ }
- /* Check and return the mouse input. */
- if (b < 32 || x < 33 || y < 33)
+ if (i == 0)
+ b = value;
+ else if (i == 1)
+ x = value;
+ else
+ y = value;
+ }
+ log_debug("mouse input: %.*s", (int) *size, buf);
+
+ /* Check and return the mouse input. */
+ if (b < 32 || x < 33 || y < 33)
+ return (-1);
+ b -= 32;
+ x -= 33;
+ y -= 33;
+ } 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);
- b -= 32;
- x -= 33;
- y -= 33;
- log_debug("mouse position: x=%u y=%u b=%u", x, y, b);
/* Fill in mouse structure. */
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->xb = b;
+ m->sgr = sgr;
+ m->sgr_xb = sgr_b;
+ m->sgr_rel = sgr_rel;
if (b & 64) { /* wheel button */
b &= 3;
if (b == 0)