mirror of
https://github.com/tmux/tmux.git
synced 2024-12-13 01:48:47 +00:00
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:
parent
d8261019f1
commit
e5eee7de0c
1
TODO
1
TODO
@ -171,7 +171,6 @@ TERMINAL ISSUES
|
|||||||
- support for bce
|
- support for bce
|
||||||
- use screen-256color when started on 256 colour terminal??
|
- use screen-256color when started on 256 colour terminal??
|
||||||
- if-shell/run-shell should block further command execution in the same command
|
- if-shell/run-shell should block further command execution in the same command
|
||||||
- possibly support rxvt-unicode extended mouse input (1015)
|
|
||||||
- wrap/no wrap esc seq DEC CSI ? 7 h/l
|
- wrap/no wrap esc seq DEC CSI ? 7 h/l
|
||||||
* We need a tmux terminfo entry to document the extensions we are using in
|
* We need a tmux terminfo entry to document the extensions we are using in
|
||||||
upstream terminfo. Must NOT change (only add or remove) anything from
|
upstream terminfo. Must NOT change (only add or remove) anything from
|
||||||
|
17
input-keys.c
17
input-keys.c
@ -201,12 +201,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]);
|
||||||
|
6
input.c
6
input.c
@ -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);
|
||||||
|
@ -55,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
10
tmux.h
@ -661,7 +661,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)
|
||||||
|
|
||||||
@ -1149,6 +1150,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;
|
||||||
@ -1161,6 +1165,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;
|
||||||
|
|
||||||
|
84
tty-keys.c
84
tty-keys.c
@ -587,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)
|
||||||
@ -609,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) {
|
||||||
@ -625,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)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,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) {
|
||||||
@ -660,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)
|
||||||
|
15
tty.c
15
tty.c
@ -218,7 +218,7 @@ tty_start_tty(struct tty *tty)
|
|||||||
|
|
||||||
tty_putcode(tty, TTYC_CNORM);
|
tty_putcode(tty, TTYC_CNORM);
|
||||||
if (tty_term_has(tty->term, TTYC_KMOUS))
|
if (tty_term_has(tty->term, TTYC_KMOUS))
|
||||||
tty_puts(tty, "\033[?1000l");
|
tty_puts(tty, "\033[?1000l\033[?1006l\033[?1005l");
|
||||||
|
|
||||||
if (tty_term_has(tty->term, TTYC_XT))
|
if (tty_term_has(tty->term, TTYC_XT))
|
||||||
tty_puts(tty, "\033[c\033[>4;1m");
|
tty_puts(tty, "\033[c\033[>4;1m");
|
||||||
@ -281,7 +281,7 @@ tty_stop_tty(struct tty *tty)
|
|||||||
|
|
||||||
tty_raw(tty, tty_term_string(tty->term, TTYC_CNORM));
|
tty_raw(tty, tty_term_string(tty->term, TTYC_CNORM));
|
||||||
if (tty_term_has(tty->term, TTYC_KMOUS))
|
if (tty_term_has(tty->term, TTYC_KMOUS))
|
||||||
tty_raw(tty, "\033[?1000l");
|
tty_raw(tty, "\033[?1000l\033[?1006l\033[?1005l");
|
||||||
|
|
||||||
if (tty_term_has(tty->term, TTYC_XT))
|
if (tty_term_has(tty->term, TTYC_XT))
|
||||||
tty_puts(tty, "\033[>4m");
|
tty_puts(tty, "\033[>4m");
|
||||||
@ -491,8 +491,17 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s)
|
|||||||
}
|
}
|
||||||
if (changed & ALL_MOUSE_MODES) {
|
if (changed & ALL_MOUSE_MODES) {
|
||||||
if (mode & ALL_MOUSE_MODES) {
|
if (mode & ALL_MOUSE_MODES) {
|
||||||
|
/*
|
||||||
|
* Enable the UTF-8 (1005) extension if configured to.
|
||||||
|
* Enable the SGR (1006) extension unconditionally, as
|
||||||
|
* this is safe from misinterpretation. Do it in this
|
||||||
|
* order, because in some terminals it's the last one
|
||||||
|
* that takes effect and SGR is the preferred one.
|
||||||
|
*/
|
||||||
if (mode & MODE_MOUSE_UTF8)
|
if (mode & MODE_MOUSE_UTF8)
|
||||||
tty_puts(tty, "\033[?1005h");
|
tty_puts(tty, "\033[?1005h");
|
||||||
|
tty_puts(tty, "\033[?1006h");
|
||||||
|
|
||||||
if (mode & MODE_MOUSE_ANY)
|
if (mode & MODE_MOUSE_ANY)
|
||||||
tty_puts(tty, "\033[?1003h");
|
tty_puts(tty, "\033[?1003h");
|
||||||
else if (mode & MODE_MOUSE_BUTTON)
|
else if (mode & MODE_MOUSE_BUTTON)
|
||||||
@ -506,6 +515,8 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s)
|
|||||||
tty_puts(tty, "\033[?1002l");
|
tty_puts(tty, "\033[?1002l");
|
||||||
else if (tty->mode & MODE_MOUSE_STANDARD)
|
else if (tty->mode & MODE_MOUSE_STANDARD)
|
||||||
tty_puts(tty, "\033[?1000l");
|
tty_puts(tty, "\033[?1000l");
|
||||||
|
|
||||||
|
tty_puts(tty, "\033[?1006l");
|
||||||
if (tty->mode & MODE_MOUSE_UTF8)
|
if (tty->mode & MODE_MOUSE_UTF8)
|
||||||
tty_puts(tty, "\033[?1005l");
|
tty_puts(tty, "\033[?1005l");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user