mirror of https://github.com/tmux/tmux.git
Support for UTF-8 mouse input (\033[1005h). This was added in xterm 262
and supports larger terminals than the older way. If the new mouse-utf8 option is on, UTF-8 mouse input is enabled for all UTF-8 terminals. The option defaults to on if LANG etc are set in the same manner as the utf8 option. With help and based on code from hsim at gmx.li.pull/1/head
parent
5158dd9a8d
commit
ac3b78a841
20
input-keys.c
20
input-keys.c
|
@ -202,11 +202,23 @@ input_key(struct window_pane *wp, int key)
|
|||
void
|
||||
input_mouse(struct window_pane *wp, struct mouse_event *m)
|
||||
{
|
||||
char out[8];
|
||||
char buf[10];
|
||||
size_t len;
|
||||
|
||||
if (wp->screen->mode & ALL_MOUSE_MODES) {
|
||||
xsnprintf(out, sizeof out,
|
||||
"\033[M%c%c%c", m->b + 32, m->x + 33, m->y + 33);
|
||||
bufferevent_write(wp->event, out, strlen(out));
|
||||
if (wp->screen->mode & MODE_MOUSE_UTF8) {
|
||||
len = xsnprintf(buf, sizeof buf, "\033[M");
|
||||
len += utf8_split2(m->b + 32, &buf[len]);
|
||||
len += utf8_split2(m->x + 33, &buf[len]);
|
||||
len += utf8_split2(m->y + 33, &buf[len]);
|
||||
} else {
|
||||
if (m->b > 223 || m->x >= 222 || m->y > 222)
|
||||
return;
|
||||
len = xsnprintf(buf, sizeof buf, "\033[M");
|
||||
buf[len++] = m->b + 32;
|
||||
buf[len++] = m->x + 33;
|
||||
buf[len++] = m->y + 33;
|
||||
}
|
||||
bufferevent_write(wp->event, buf, len);
|
||||
}
|
||||
}
|
||||
|
|
6
input.c
6
input.c
|
@ -1161,6 +1161,9 @@ input_csi_dispatch(struct input_ctx *ictx)
|
|||
case 1003:
|
||||
screen_write_mousemode_off(&ictx->ctx);
|
||||
break;
|
||||
case 1005:
|
||||
screen_write_utf8mousemode(&ictx->ctx, 0);
|
||||
break;
|
||||
case 1049:
|
||||
window_pane_alternate_off(wp, &ictx->cell);
|
||||
break;
|
||||
|
@ -1209,6 +1212,9 @@ input_csi_dispatch(struct input_ctx *ictx)
|
|||
case 1003:
|
||||
screen_write_mousemode_on(&ictx->ctx, MODE_MOUSE_ANY);
|
||||
break;
|
||||
case 1005:
|
||||
screen_write_utf8mousemode(&ictx->ctx, 1);
|
||||
break;
|
||||
case 1049:
|
||||
window_pane_alternate_on(wp, &ictx->cell);
|
||||
break;
|
||||
|
|
|
@ -198,6 +198,11 @@ const struct options_table_entry session_options_table[] = {
|
|||
.default_num = 0
|
||||
},
|
||||
|
||||
{ .name = "mouse-utf8",
|
||||
.type = OPTIONS_TABLE_FLAG,
|
||||
.default_num = 0
|
||||
},
|
||||
|
||||
{ .name = "pane-active-border-bg",
|
||||
.type = OPTIONS_TABLE_COLOUR,
|
||||
.default_num = 8
|
||||
|
|
|
@ -829,6 +829,18 @@ screen_write_insertmode(struct screen_write_ctx *ctx, int state)
|
|||
s->mode &= ~MODE_INSERT;
|
||||
}
|
||||
|
||||
/* Set UTF-8 mouse mode. */
|
||||
void
|
||||
screen_write_utf8mousemode(struct screen_write_ctx *ctx, int state)
|
||||
{
|
||||
struct screen *s = ctx->s;
|
||||
|
||||
if (state)
|
||||
s->mode |= MODE_MOUSE_UTF8;
|
||||
else
|
||||
s->mode &= ~MODE_MOUSE_UTF8;
|
||||
}
|
||||
|
||||
/* Set mouse mode off. */
|
||||
void
|
||||
screen_write_mousemode_off(struct screen_write_ctx *ctx)
|
||||
|
|
|
@ -451,6 +451,21 @@ server_client_reset_state(struct client *c)
|
|||
if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL &&
|
||||
options_get_number(oo, "mouse-select-pane"))
|
||||
mode |= MODE_MOUSE_STANDARD;
|
||||
|
||||
/*
|
||||
* Set UTF-8 mouse input if required. If the terminal is UTF-8, the
|
||||
* user has set mouse-utf8 and any mouse mode is in effect, turn on
|
||||
* UTF-8 mouse input. If the receiving terminal hasn't requested it
|
||||
* (that is, it isn't in s->mode), then it'll be converted in
|
||||
* input_mouse.
|
||||
*/
|
||||
if ((c->tty.flags & TTY_UTF8) &&
|
||||
(mode & ALL_MOUSE_MODES) && options_get_number(oo, "mouse-utf8"))
|
||||
mode |= MODE_MOUSE_UTF8;
|
||||
else
|
||||
mode &= ~MODE_MOUSE_UTF8;
|
||||
|
||||
/* Set the terminal mode and reset attributes. */
|
||||
tty_update_mode(&c->tty, mode);
|
||||
tty_reset(&c->tty);
|
||||
}
|
||||
|
|
4
tmux.1
4
tmux.1
|
@ -1806,6 +1806,10 @@ flag to
|
|||
Repeat is enabled for the default keys bound to the
|
||||
.Ic resize-pane
|
||||
command.
|
||||
.It Xo Ic mouse-utf8
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
If enabled, request mouse input as UTF-8 on UTF-8 terminals.
|
||||
.It Xo Ic set-remain-on-exit
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
|
|
1
tmux.c
1
tmux.c
|
@ -334,6 +334,7 @@ main(int argc, char **argv)
|
|||
/* Enable UTF-8 if the first client is on UTF-8 terminal. */
|
||||
if (flags & IDENTIFY_UTF8) {
|
||||
options_set_number(&global_s_options, "status-utf8", 1);
|
||||
options_set_number(&global_s_options, "mouse-utf8", 1);
|
||||
options_set_number(&global_w_options, "utf8", 1);
|
||||
}
|
||||
|
||||
|
|
10
tmux.h
10
tmux.h
|
@ -550,6 +550,7 @@ struct mode_key_table {
|
|||
#define MODE_MOUSE_HIGHLIGHT 0x40
|
||||
#define MODE_MOUSE_BUTTON 0x80
|
||||
#define MODE_MOUSE_ANY 0x100
|
||||
#define MODE_MOUSE_UTF8 0x200
|
||||
|
||||
#define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD| \
|
||||
MODE_MOUSE_HIGHLIGHT|MODE_MOUSE_BUTTON|MODE_MOUSE_ANY)
|
||||
|
@ -1075,15 +1076,15 @@ struct tty_ctx {
|
|||
*/
|
||||
/* Mouse input. */
|
||||
struct mouse_event {
|
||||
u_char b;
|
||||
u_int b;
|
||||
#define MOUSE_1 0
|
||||
#define MOUSE_2 1
|
||||
#define MOUSE_3 2
|
||||
#define MOUSE_UP 3
|
||||
#define MOUSE_BUTTON 3
|
||||
#define MOUSE_45 64
|
||||
u_char x;
|
||||
u_char y;
|
||||
u_int x;
|
||||
u_int y;
|
||||
};
|
||||
|
||||
/* Saved message entry. */
|
||||
|
@ -1817,6 +1818,7 @@ void screen_write_cursormode(struct screen_write_ctx *, int);
|
|||
void screen_write_reverseindex(struct screen_write_ctx *);
|
||||
void screen_write_scrollregion(struct screen_write_ctx *, u_int, u_int);
|
||||
void screen_write_insertmode(struct screen_write_ctx *, int);
|
||||
void screen_write_utf8mousemode(struct screen_write_ctx *, int);
|
||||
void screen_write_mousemode_on(struct screen_write_ctx *, int);
|
||||
void screen_write_mousemode_off(struct screen_write_ctx *);
|
||||
void screen_write_linefeed(struct screen_write_ctx *, int);
|
||||
|
@ -2017,6 +2019,8 @@ void session_group_synchronize1(struct session *, struct session *);
|
|||
void utf8_build(void);
|
||||
int utf8_open(struct utf8_data *, u_char);
|
||||
int utf8_append(struct utf8_data *, u_char);
|
||||
u_int utf8_combine(const struct utf8_data *);
|
||||
u_int utf8_split2(u_int, u_char *);
|
||||
|
||||
/* procname.c */
|
||||
char *get_proc_name(int, char *);
|
||||
|
|
60
tty-keys.c
60
tty-keys.c
|
@ -38,7 +38,7 @@ struct tty_key *tty_keys_find1(
|
|||
struct tty_key *, const char *, size_t, size_t *);
|
||||
struct tty_key *tty_keys_find(struct tty *, const char *, size_t, size_t *);
|
||||
void tty_keys_callback(int, short, void *);
|
||||
int tty_keys_mouse(
|
||||
int tty_keys_mouse(struct tty *,
|
||||
const char *, size_t, size_t *, struct mouse_event *);
|
||||
|
||||
struct tty_key_ent {
|
||||
|
@ -462,7 +462,7 @@ tty_keys_next(struct tty *tty)
|
|||
}
|
||||
|
||||
/* Is this a mouse key press? */
|
||||
switch (tty_keys_mouse(buf, len, &size, &mouse)) {
|
||||
switch (tty_keys_mouse(tty, buf, len, &size, &mouse)) {
|
||||
case 0: /* yes */
|
||||
evbuffer_drain(tty->event->input, size);
|
||||
key = KEYC_MOUSE;
|
||||
|
@ -584,44 +584,74 @@ tty_keys_callback(unused int fd, unused short events, void *data)
|
|||
* (probably a mouse sequence but need more data).
|
||||
*/
|
||||
int
|
||||
tty_keys_mouse(const char *buf, size_t len, size_t *size, struct mouse_event *m)
|
||||
tty_keys_mouse(struct tty *tty,
|
||||
const char *buf, size_t len, size_t *size, struct mouse_event *m)
|
||||
{
|
||||
struct utf8_data utf8data;
|
||||
u_int i, value;
|
||||
|
||||
/*
|
||||
* Mouse sequences are \033[M followed by three characters indicating
|
||||
* buttons, X and Y, all based at 32 with 1,1 top-left.
|
||||
* Standard mouse sequences are \033[M followed by three characters
|
||||
* indicating buttons, 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.
|
||||
*/
|
||||
|
||||
*size = 0;
|
||||
|
||||
/* First three bytes are always \033[M. */
|
||||
if (buf[0] != '\033')
|
||||
return (-1);
|
||||
if (len == 1)
|
||||
return (1);
|
||||
|
||||
if (buf[1] != '[')
|
||||
return (-1);
|
||||
if (len == 2)
|
||||
return (1);
|
||||
|
||||
if (buf[2] != 'M')
|
||||
return (-1);
|
||||
if (len == 3)
|
||||
return (1);
|
||||
|
||||
if (len < 6)
|
||||
return (1);
|
||||
*size = 6;
|
||||
/* Read the three inputs. */
|
||||
*size = 3;
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (len < *size)
|
||||
return (1);
|
||||
|
||||
log_debug(
|
||||
"mouse input: %.6s (%hhu,%hhu/%hhu)", buf, buf[4], buf[5], buf[3]);
|
||||
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 = buf[*size];
|
||||
(*size)++;
|
||||
} else {
|
||||
value = buf[*size];
|
||||
(*size)++;
|
||||
}
|
||||
|
||||
m->b = buf[3];
|
||||
m->x = buf[4];
|
||||
m->y = buf[5];
|
||||
if (i == 0)
|
||||
m->b = value;
|
||||
else if (i == 1)
|
||||
m->x = value;
|
||||
else
|
||||
m->y = value;
|
||||
}
|
||||
log_debug("mouse input: %.*s", (int) *size, buf);
|
||||
|
||||
/* Check and return the mouse input. */
|
||||
if (m->b < 32 || m->x < 33 || m->y < 33)
|
||||
return (-1);
|
||||
m->b -= 32;
|
||||
m->x -= 33;
|
||||
m->y -= 33;
|
||||
log_debug("mouse position: x=%u y=%u b=%u", m->x, m->y, m->b);
|
||||
return (0);
|
||||
}
|
||||
|
|
4
tty.c
4
tty.c
|
@ -405,6 +405,8 @@ tty_update_mode(struct tty *tty, int mode)
|
|||
}
|
||||
if (changed & ALL_MOUSE_MODES) {
|
||||
if (mode & ALL_MOUSE_MODES) {
|
||||
if (mode & MODE_MOUSE_UTF8)
|
||||
tty_puts(tty, "\033[?1005h");
|
||||
if (mode & MODE_MOUSE_STANDARD)
|
||||
tty_puts(tty, "\033[?1000h");
|
||||
else if (mode & MODE_MOUSE_HIGHLIGHT)
|
||||
|
@ -422,6 +424,8 @@ tty_update_mode(struct tty *tty, int mode)
|
|||
tty_puts(tty, "\033[?1002l");
|
||||
else if (tty->mode & MODE_MOUSE_ANY)
|
||||
tty_puts(tty, "\033[?1003l");
|
||||
if (tty->mode & MODE_MOUSE_UTF8)
|
||||
tty_puts(tty, "\033[?1005l");
|
||||
}
|
||||
}
|
||||
if (changed & MODE_KKEYPAD) {
|
||||
|
|
13
utf8.c
13
utf8.c
|
@ -318,6 +318,19 @@ utf8_combine(const struct utf8_data *utf8data)
|
|||
return (value);
|
||||
}
|
||||
|
||||
/* Split a two-byte UTF-8 character. */
|
||||
u_int
|
||||
utf8_split2(u_int uc, u_char *ptr)
|
||||
{
|
||||
if (uc > 0x7f) {
|
||||
ptr[0] = (uc >> 6) | 0xc0;
|
||||
ptr[1] = (uc & 0x3f) | 0x80;
|
||||
return (2);
|
||||
}
|
||||
ptr[0] = uc;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Lookup width of UTF-8 data in tree. */
|
||||
u_int
|
||||
utf8_width(const struct utf8_data *utf8data)
|
||||
|
|
Loading…
Reference in New Issue