diff --git a/input-keys.c b/input-keys.c index 34296462..d18c4041 100644 --- a/input-keys.c +++ b/input-keys.c @@ -1,4 +1,4 @@ -/* $Id: input-keys.c,v 1.47 2011-01-03 23:32:04 tcunha Exp $ */ +/* $Id: input-keys.c,v 1.48 2011-01-07 14:34:45 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -201,11 +201,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); } } diff --git a/input.c b/input.c index 55e0e4f7..818033b8 100644 --- a/input.c +++ b/input.c @@ -1,4 +1,4 @@ -/* $Id: input.c,v 1.112 2010-12-30 22:27:38 tcunha Exp $ */ +/* $Id: input.c,v 1.113 2011-01-07 14:34:45 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -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; diff --git a/options-table.c b/options-table.c index e8021e32..e769db7a 100644 --- a/options-table.c +++ b/options-table.c @@ -1,4 +1,4 @@ -/* $Id: options-table.c,v 1.2 2011-01-03 23:55:30 tcunha Exp $ */ +/* $Id: options-table.c,v 1.3 2011-01-07 14:34:45 tcunha Exp $ */ /* * Copyright (c) 2011 Nicholas Marriott @@ -197,6 +197,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 diff --git a/screen-write.c b/screen-write.c index 38596153..beb58db8 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1,4 +1,4 @@ -/* $Id: screen-write.c,v 1.91 2010-12-30 22:27:38 tcunha Exp $ */ +/* $Id: screen-write.c,v 1.92 2011-01-07 14:34:45 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -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) diff --git a/server-client.c b/server-client.c index 046f9f51..d7d90969 100644 --- a/server-client.c +++ b/server-client.c @@ -1,4 +1,4 @@ -/* $Id: server-client.c,v 1.50 2011-01-03 23:27:54 tcunha Exp $ */ +/* $Id: server-client.c,v 1.51 2011-01-07 14:34:45 tcunha Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -450,6 +450,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); } diff --git a/tmux.1 b/tmux.1 index 99917589..6e411368 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1,4 +1,4 @@ -.\" $Id: tmux.1,v 1.285 2011-01-03 23:33:12 tcunha Exp $ +.\" $Id: tmux.1,v 1.286 2011-01-07 14:34:45 tcunha Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott .\" @@ -1810,6 +1810,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 diff --git a/tmux.c b/tmux.c index 0e6835c5..ca6956ff 100644 --- a/tmux.c +++ b/tmux.c @@ -1,4 +1,4 @@ -/* $Id: tmux.c,v 1.232 2011-01-03 23:52:38 tcunha Exp $ */ +/* $Id: tmux.c,v 1.233 2011-01-07 14:34:45 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -340,6 +340,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); } diff --git a/tmux.h b/tmux.h index 221164cd..65905e87 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.600 2011-01-03 23:52:38 tcunha Exp $ */ +/* $Id: tmux.h,v 1.601 2011-01-07 14:34:45 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -546,6 +546,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) @@ -1071,15 +1072,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. */ @@ -1813,6 +1814,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); @@ -2011,6 +2013,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 *); /* osdep-*.c */ char *osdep_get_name(int, char *); diff --git a/tty-keys.c b/tty-keys.c index fea7f266..5e827dc7 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1,4 +1,4 @@ -/* $Id: tty-keys.c,v 1.58 2011-01-03 23:29:49 tcunha Exp $ */ +/* $Id: tty-keys.c,v 1.59 2011-01-07 14:34:45 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -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); } diff --git a/tty.c b/tty.c index 4f6e882d..935ffd9c 100644 --- a/tty.c +++ b/tty.c @@ -1,4 +1,4 @@ -/* $Id: tty.c,v 1.198 2010-12-30 22:27:38 tcunha Exp $ */ +/* $Id: tty.c,v 1.199 2011-01-07 14:34:45 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -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) { diff --git a/utf8.c b/utf8.c index 182cd101..0244a065 100644 --- a/utf8.c +++ b/utf8.c @@ -1,4 +1,4 @@ -/* $Id: utf8.c,v 1.11 2009-10-23 17:21:34 tcunha Exp $ */ +/* $Id: utf8.c,v 1.12 2011-01-07 14:34:45 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -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)