From 69e0b8326ad0a983759518b90ed8632146341acf Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 12 Nov 2015 11:05:34 +0000 Subject: [PATCH] Support UTF-8 key bindings by expanding the key type from int to uint64_t and converting UTF-8 to Unicode on input and the reverse on output. (This allows key bindings, there are still omissions - the largest being that the various prompts do not accept UTF-8.) --- cmd-bind-key.c | 7 ++-- cmd-list-keys.c | 13 +++++--- cmd-send-keys.c | 3 +- cmd-set-option.c | 2 +- cmd-unbind-key.c | 9 +++--- input-keys.c | 38 ++++++++++++++-------- key-bindings.c | 10 ++++-- key-string.c | 63 ++++++++++++++++++++++++------------ mode-key.c | 16 ++++++--- server-client.c | 40 +++++++++++------------ status.c | 4 +-- tmux.h | 84 ++++++++++++++++++++++++++---------------------- tty-keys.c | 62 ++++++++++++++++++++++------------- utf8.c | 34 ++++++++++++++++++-- window-choose.c | 23 ++++++------- window-clock.c | 5 +-- window-copy.c | 12 +++---- window.c | 2 +- xterm-keys.c | 21 ++++++------ 19 files changed, 280 insertions(+), 168 deletions(-) diff --git a/cmd-bind-key.c b/cmd-bind-key.c index fda39efc..1867e814 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -29,7 +29,8 @@ enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmd_q *); -enum cmd_retval cmd_bind_key_mode_table(struct cmd *, struct cmd_q *, int); +enum cmd_retval cmd_bind_key_mode_table(struct cmd *, struct cmd_q *, + key_code); const struct cmd_entry cmd_bind_key_entry = { "bind-key", "bind", @@ -45,7 +46,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq) struct args *args = self->args; char *cause; struct cmd_list *cmdlist; - int key; + key_code key; const char *tablename; if (args_has(args, 't')) { @@ -89,7 +90,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq) } enum cmd_retval -cmd_bind_key_mode_table(struct cmd *self, struct cmd_q *cmdq, int key) +cmd_bind_key_mode_table(struct cmd *self, struct cmd_q *cmdq, key_code key) { struct args *args = self->args; const char *tablename; diff --git a/cmd-list-keys.c b/cmd-list-keys.c index d26486bd..c76f9f47 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -57,6 +57,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq) char tmp[BUFSIZ]; size_t used; int repeat, width, tablewidth, keywidth; + u_int i; if (self->entry == &cmd_list_commands_entry) return (cmd_list_keys_commands(self, cmdq)); @@ -83,8 +84,8 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq) width = strlen(table->name); if (width > tablewidth) - tablewidth =width; - width = strlen(key); + tablewidth = width; + width = utf8_cstrwidth(key); if (width > keywidth) keywidth = width; } @@ -102,8 +103,12 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq) r = "-r "; else r = " "; - used = xsnprintf(tmp, sizeof tmp, "%s-T %-*s %-*s ", r, - (int)tablewidth, table->name, (int)keywidth, key); + used = xsnprintf(tmp, sizeof tmp, "%s-T %-*s %s", r, + (int)tablewidth, table->name, key); + for (i = 0; i < keywidth - utf8_cstrwidth(key); i++) { + if (strlcat(tmp, " ", sizeof tmp) < sizeof tmp) + used++; + } if (used < sizeof tmp) { cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used); diff --git a/cmd-send-keys.c b/cmd-send-keys.c index dd796d60..73a308ae 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -53,7 +53,8 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq) struct window_pane *wp; struct session *s; const u_char *str; - int i, key; + int i; + key_code key; if (args_has(args, 'M')) { wp = cmd_mouse_pane(m, &s, NULL); diff --git a/cmd-set-option.c b/cmd-set-option.c index 6762e6ad..c5a77b45 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -394,7 +394,7 @@ cmd_set_option_key(unused struct cmd *self, struct cmd_q *cmdq, const struct options_table_entry *oe, struct options *oo, const char *value) { - int key; + key_code key; if ((key = key_string_lookup_string(value)) == KEYC_NONE) { cmdq_error(cmdq, "bad key: %s", value); diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index 493f6dde..cec538c0 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -26,8 +26,9 @@ * Unbind key from command. */ -enum cmd_retval cmd_unbind_key_exec(struct cmd *, struct cmd_q *); -enum cmd_retval cmd_unbind_key_mode_table(struct cmd *, struct cmd_q *, int); +enum cmd_retval cmd_unbind_key_exec(struct cmd *, struct cmd_q *); +enum cmd_retval cmd_unbind_key_mode_table(struct cmd *, struct cmd_q *, + key_code); const struct cmd_entry cmd_unbind_key_entry = { "unbind-key", "unbind", @@ -41,7 +42,7 @@ enum cmd_retval cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; - int key; + key_code key; const char *tablename; if (!args_has(args, 'a')) { @@ -95,7 +96,7 @@ cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq) } enum cmd_retval -cmd_unbind_key_mode_table(struct cmd *self, struct cmd_q *cmdq, int key) +cmd_unbind_key_mode_table(struct cmd *self, struct cmd_q *cmdq, key_code key) { struct args *args = self->args; const char *tablename; diff --git a/input-keys.c b/input-keys.c index 579c0f39..a761a088 100644 --- a/input-keys.c +++ b/input-keys.c @@ -34,7 +34,7 @@ void input_key_mouse(struct window_pane *, struct mouse_event *); struct input_key_ent { - int key; + key_code key; const char *data; int flags; @@ -137,15 +137,16 @@ const struct input_key_ent input_keys[] = { /* Translate a key code into an output key sequence. */ void -input_key(struct window_pane *wp, int key, struct mouse_event *m) +input_key(struct window_pane *wp, key_code key, struct mouse_event *m) { - const struct input_key_ent *ike; - u_int i; - size_t dlen; - char *out; - u_char ch; + const struct input_key_ent *ike; + u_int i; + size_t dlen; + char *out; + key_code justkey; + struct utf8_data utf8data; - log_debug("writing key 0x%x (%s) to %%%u", key, + log_debug("writing key 0x%llx (%s) to %%%u", key, key_string_lookup_key(key), wp->id); /* If this is a mouse key, pass off to mouse function. */ @@ -157,13 +158,22 @@ input_key(struct window_pane *wp, int key, struct mouse_event *m) /* * If this is a normal 7-bit key, just send it, with a leading escape - * if necessary. + * if necessary. If it is a UTF-8 key, split it and send it. */ - if (key != KEYC_NONE && (key & ~KEYC_ESCAPE) < 0x100) { + justkey = (key & ~KEYC_ESCAPE); + if (key != KEYC_NONE && justkey < 0x7f) { if (key & KEYC_ESCAPE) bufferevent_write(wp->event, "\033", 1); - ch = key & ~KEYC_ESCAPE; - bufferevent_write(wp->event, &ch, 1); + utf8data.data[0] = justkey; + bufferevent_write(wp->event, &utf8data.data[0], 1); + return; + } + if (key != KEYC_NONE && justkey > 0x7f && justkey < KEYC_BASE) { + if (utf8_split(justkey, &utf8data) != 0) + return; + if (key & KEYC_ESCAPE) + bufferevent_write(wp->event, "\033", 1); + bufferevent_write(wp->event, utf8data.data, utf8data.size); return; } @@ -196,11 +206,11 @@ input_key(struct window_pane *wp, int key, struct mouse_event *m) break; } if (i == nitems(input_keys)) { - log_debug("key 0x%x missing", key); + log_debug("key 0x%llx missing", key); return; } dlen = strlen(ike->data); - log_debug("found key 0x%x: \"%s\"", key, ike->data); + log_debug("found key 0x%llx: \"%s\"", key, ike->data); /* Prefix a \033 for escape. */ if (key & KEYC_ESCAPE) diff --git a/key-bindings.c b/key-bindings.c index 83b94ac1..47a7d867 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -37,7 +37,11 @@ key_table_cmp(struct key_table *e1, struct key_table *e2) int key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2) { - return (bd1->key - bd2->key); + if (bd1->key < bd2->key) + return (-1); + if (bd1->key > bd2->key) + return (1); + return (0); } struct key_table * @@ -80,7 +84,7 @@ key_bindings_unref_table(struct key_table *table) } void -key_bindings_add(const char *name, int key, int can_repeat, +key_bindings_add(const char *name, key_code key, int can_repeat, struct cmd_list *cmdlist) { struct key_table *table; @@ -105,7 +109,7 @@ key_bindings_add(const char *name, int key, int can_repeat, } void -key_bindings_remove(const char *name, int key) +key_bindings_remove(const char *name, key_code key) { struct key_table *table; struct key_binding bd_find, *bd; diff --git a/key-string.c b/key-string.c index 88cd2a32..4285e129 100644 --- a/key-string.c +++ b/key-string.c @@ -22,12 +22,12 @@ #include "tmux.h" -int key_string_search_table(const char *); -int key_string_get_modifiers(const char **); +key_code key_string_search_table(const char *); +key_code key_string_get_modifiers(const char **); const struct { const char *string; - int key; + key_code key; } key_string_table[] = { /* Function keys. */ { "F1", KEYC_F1 }, @@ -98,7 +98,7 @@ const struct { }; /* Find key string in table. */ -int +key_code key_string_search_table(const char *string) { u_int i; @@ -111,10 +111,10 @@ key_string_search_table(const char *string) } /* Find modifiers. */ -int +key_code key_string_get_modifiers(const char **string) { - int modifiers; + key_code modifiers; modifiers = 0; while (((*string)[0] != '\0') && (*string)[1] == '-') { @@ -138,13 +138,16 @@ key_string_get_modifiers(const char **string) } /* Lookup a string and convert to a key value. */ -int +key_code key_string_lookup_string(const char *string) { static const char *other = "!#()+,-.0123456789:;<=>?'\r\t"; - int key, modifiers; + key_code key; u_short u; int size; + key_code modifiers; + struct utf8_data utf8data; + u_int i; /* Is this a hexadecimal value? */ if (string[0] == '0' && string[1] == 'x') { @@ -164,11 +167,21 @@ key_string_lookup_string(const char *string) return (KEYC_NONE); /* Is this a standard ASCII key? */ - if (string[1] == '\0') { - key = (u_char) string[0]; - if (key < 32 || key == 127 || key > 255) + if (string[1] == '\0' && (u_char)string[0] <= 127) { + key = (u_char)string[0]; + if (key < 32 || key == 127) return (KEYC_NONE); } else { + /* Try as a UTF-8 key. */ + if (utf8_open(&utf8data, (u_char)*string)) { + if (strlen(string) != utf8data.size) + return (KEYC_NONE); + for (i = 1; i < utf8data.size; i++) + utf8_append(&utf8data, (u_char)string[i]); + key = utf8_combine(&utf8data); + return (key | modifiers); + } + /* Otherwise look the key up in the table. */ key = key_string_search_table(string); if (key == KEYC_NONE) @@ -195,11 +208,12 @@ key_string_lookup_string(const char *string) /* Convert a key code into string format, with prefix if necessary. */ const char * -key_string_lookup_key(int key) +key_string_lookup_key(key_code key) { - static char out[24]; - char tmp[8]; - u_int i; + static char out[24]; + char tmp[8]; + u_int i; + struct utf8_data utf8data; *out = '\0'; @@ -237,23 +251,32 @@ key_string_lookup_key(int key) return (out); } + /* Is this a UTF-8 key? */ + if (key > 127 && key < KEYC_BASE) { + if (utf8_split(key, &utf8data) == 0) { + memcpy(out, utf8data.data, utf8data.size); + out[utf8data.size] = '\0'; + return (out); + } + } + /* Invalid keys are errors. */ if (key == 127 || key > 255) { - snprintf(out, sizeof out, "", key); + snprintf(out, sizeof out, "", key); return (out); } /* Check for standard or control key. */ - if (key >= 0 && key <= 32) { + if (key <= 32) { if (key == 0 || key > 26) - xsnprintf(tmp, sizeof tmp, "C-%c", 64 + key); + xsnprintf(tmp, sizeof tmp, "C-%c", (int)(64 + key)); else - xsnprintf(tmp, sizeof tmp, "C-%c", 96 + key); + xsnprintf(tmp, sizeof tmp, "C-%c", (int)(96 + key)); } else if (key >= 32 && key <= 126) { tmp[0] = key; tmp[1] = '\0'; } else if (key >= 128) - xsnprintf(tmp, sizeof tmp, "\\%o", key); + xsnprintf(tmp, sizeof tmp, "\\%llo", key); strlcat(out, tmp, sizeof out); return (out); diff --git a/mode-key.c b/mode-key.c index 5ed45bd8..a47cda0b 100644 --- a/mode-key.c +++ b/mode-key.c @@ -40,7 +40,7 @@ /* Entry in the default mode key tables. */ struct mode_key_entry { - int key; + key_code key; /* * Editing mode for vi: 0 is edit mode, keys not in the table are @@ -523,9 +523,15 @@ RB_GENERATE(mode_key_tree, mode_key_binding, entry, mode_key_cmp); int mode_key_cmp(struct mode_key_binding *mbind1, struct mode_key_binding *mbind2) { - if (mbind1->mode != mbind2->mode) - return (mbind1->mode - mbind2->mode); - return (mbind1->key - mbind2->key); + if (mbind1->mode < mbind2->mode) + return (-1); + if (mbind1->mode > mbind2->mode) + return (1); + if (mbind1->key < mbind2->key) + return (-1); + if (mbind1->key > mbind2->key) + return (1); + return (0); } const char * @@ -588,7 +594,7 @@ mode_key_init(struct mode_key_data *mdata, struct mode_key_tree *mtree) } enum mode_key_cmd -mode_key_lookup(struct mode_key_data *mdata, int key, const char **arg) +mode_key_lookup(struct mode_key_data *mdata, key_code key, const char **arg) { struct mode_key_binding *mbind, mtmp; diff --git a/server-client.c b/server-client.c index 521f2737..fedc93bd 100644 --- a/server-client.c +++ b/server-client.c @@ -32,22 +32,22 @@ #include "tmux.h" -void server_client_key_table(struct client *, const char *); -void server_client_free(int, short, void *); -void server_client_check_focus(struct window_pane *); -void server_client_check_resize(struct window_pane *); -int server_client_check_mouse(struct client *); -void server_client_repeat_timer(int, short, void *); -void server_client_check_exit(struct client *); -void server_client_check_redraw(struct client *); -void server_client_set_title(struct client *); -void server_client_reset_state(struct client *); -int server_client_assume_paste(struct session *); +void server_client_key_table(struct client *, const char *); +void server_client_free(int, short, void *); +void server_client_check_focus(struct window_pane *); +void server_client_check_resize(struct window_pane *); +key_code server_client_check_mouse(struct client *); +void server_client_repeat_timer(int, short, void *); +void server_client_check_exit(struct client *); +void server_client_check_redraw(struct client *); +void server_client_set_title(struct client *); +void server_client_reset_state(struct client *); +int server_client_assume_paste(struct session *); -void server_client_dispatch(struct imsg *, void *); -void server_client_dispatch_command(struct client *, struct imsg *); -void server_client_dispatch_identify(struct client *, struct imsg *); -void server_client_dispatch_shell(struct client *); +void server_client_dispatch(struct imsg *, void *); +void server_client_dispatch_command(struct client *, struct imsg *); +void server_client_dispatch_identify(struct client *, struct imsg *); +void server_client_dispatch_shell(struct client *); /* Check if this client is inside this server. */ int @@ -257,7 +257,7 @@ server_client_free(unused int fd, unused short events, void *arg) } /* Check for mouse keys. */ -int +key_code server_client_check_mouse(struct client *c) { struct session *s = c->session; @@ -267,7 +267,7 @@ server_client_check_mouse(struct client *c) enum { NOTYPE, DOWN, UP, DRAG, WHEEL } type = NOTYPE; enum { NOWHERE, PANE, STATUS, BORDER } where = NOWHERE; u_int x, y, b; - int key; + key_code key; log_debug("mouse %02x at %u,%u (last %u,%u) (%d)", m->b, m->x, m->y, m->lx, m->ly, c->tty.mouse_drag_flag); @@ -501,7 +501,7 @@ server_client_assume_paste(struct session *s) /* Handle data key input from client. */ void -server_client_handle_key(struct client *c, int key) +server_client_handle_key(struct client *c, key_code key) { struct mouse_event *m = &c->tty.mouse; struct session *s = c->session; @@ -635,8 +635,8 @@ retry: * No match, but in the root table. Prefix switches to the prefix table * and everything else is passed through. */ - if (key == options_get_number(s->options, "prefix") || - key == options_get_number(s->options, "prefix2")) { + if (key == (key_code)options_get_number(s->options, "prefix") || + key == (key_code)options_get_number(s->options, "prefix2")) { server_client_key_table(c, "prefix"); server_status_client(c); return; diff --git a/status.c b/status.c index a2f46b95..df80d2b8 100644 --- a/status.c +++ b/status.c @@ -812,7 +812,7 @@ status_prompt_redraw(struct client *c) /* Handle keys in prompt. */ void -status_prompt_key(struct client *c, int key) +status_prompt_key(struct client *c, key_code key) { struct session *sess = c->session; struct options *oo = sess->options; @@ -1116,7 +1116,7 @@ status_prompt_key(struct client *c, int key) status_prompt_clear(c); break; case MODEKEY_OTHER: - if ((key & 0xff00) != 0 || key < 32 || key == 127) + if (key <= 0x1f || key >= 0x7f) break; c->prompt_buffer = xrealloc(c->prompt_buffer, size + 2); diff --git a/tmux.h b/tmux.h index 25b51350..51ceefd8 100644 --- a/tmux.h +++ b/tmux.h @@ -95,13 +95,13 @@ struct tmuxproc; #define BELL_OTHER 3 /* Special key codes. */ -#define KEYC_NONE 0xfff -#define KEYC_BASE 0x1000 +#define KEYC_NONE 0xffff00000000ULL +#define KEYC_BASE 0x100000000000ULL /* Key modifier bits. */ -#define KEYC_ESCAPE 0x2000 -#define KEYC_CTRL 0x4000 -#define KEYC_SHIFT 0x8000 +#define KEYC_ESCAPE 0x200000000000ULL +#define KEYC_CTRL 0x400000000000ULL +#define KEYC_SHIFT 0x800000000000ULL /* Mask to obtain key w/o modifiers. */ #define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT) @@ -121,8 +121,14 @@ struct tmuxproc; { #s "Status", KEYC_ ## name ## _STATUS }, \ { #s "Border", KEYC_ ## name ## _BORDER } +/* + * A single key. This can be ASCII or Unicode or one of the keys starting at + * KEYC_BASE. + */ +typedef uint64_t key_code; + /* Special key codes. */ -enum key_code { +enum { /* Focus events. */ KEYC_FOCUS_IN = KEYC_BASE, KEYC_FOCUS_OUT, @@ -570,7 +576,7 @@ struct mode_key_data { /* Binding between a key and a command. */ struct mode_key_binding { - int key; + key_code key; int mode; enum mode_key_cmd cmd; @@ -776,7 +782,7 @@ struct window_mode { void (*free)(struct window_pane *); void (*resize)(struct window_pane *, u_int, u_int); void (*key)(struct window_pane *, struct client *, struct session *, - int, struct mouse_event *); + key_code, struct mouse_event *); }; /* Structures for choose mode. */ @@ -1030,31 +1036,31 @@ RB_HEAD(sessions, session); /* Mouse input. */ struct mouse_event { - int valid; + int valid; - int key; - int statusat; + key_code key; + int statusat; - u_int x; - u_int y; - u_int b; + u_int x; + u_int y; + u_int b; - u_int lx; - u_int ly; - u_int lb; + u_int lx; + u_int ly; + u_int lb; - int s; - int w; - int wp; + int s; + int w; + int wp; - u_int sgr_type; - u_int sgr_b; + u_int sgr_type; + u_int sgr_b; }; /* TTY information. */ struct tty_key { char ch; - int key; + key_code key; struct tty_key *left; struct tty_key *right; @@ -1340,7 +1346,7 @@ struct cmd_entry { /* Key binding and key table. */ struct key_binding { - int key; + key_code key; struct cmd_list *cmdlist; int can_repeat; @@ -1488,7 +1494,8 @@ enum mode_key_cmd mode_key_fromstring(const struct mode_key_cmdstr *, const struct mode_key_table *mode_key_findtable(const char *); void mode_key_init_trees(void); void mode_key_init(struct mode_key_data *, struct mode_key_tree *); -enum mode_key_cmd mode_key_lookup(struct mode_key_data *, int, const char **); +enum mode_key_cmd mode_key_lookup(struct mode_key_data *, key_code, + const char **); /* notify.c */ void notify_enable(void); @@ -1632,9 +1639,9 @@ const char *tty_term_describe(struct tty_term *, enum tty_code_code); const char *tty_acs_get(struct tty *, u_char); /* tty-keys.c */ -void tty_keys_build(struct tty *); -void tty_keys_free(struct tty *); -int tty_keys_next(struct tty *); +void tty_keys_build(struct tty *); +void tty_keys_free(struct tty *); +key_code tty_keys_next(struct tty *); /* arguments.c */ int args_cmp(struct args_entry *, struct args_entry *); @@ -1720,16 +1727,16 @@ int key_table_cmp(struct key_table *, struct key_table *); int key_bindings_cmp(struct key_binding *, struct key_binding *); struct key_table *key_bindings_get_table(const char *, int); void key_bindings_unref_table(struct key_table *); -void key_bindings_add(const char *, int, int, struct cmd_list *); -void key_bindings_remove(const char *, int); +void key_bindings_add(const char *, key_code, int, struct cmd_list *); +void key_bindings_remove(const char *, key_code); void key_bindings_remove_table(const char *); void key_bindings_init(void); void key_bindings_dispatch(struct key_binding *, struct client *, struct mouse_event *); /* key-string.c */ -int key_string_lookup_string(const char *); -const char *key_string_lookup_key(int); +key_code key_string_lookup_string(const char *); +const char *key_string_lookup_key(key_code); /* alerts.c */ void alerts_reset_all(void); @@ -1753,7 +1760,7 @@ void server_add_accept(int); /* server-client.c */ int server_client_check_nested(struct client *); -void server_client_handle_key(struct client *, int); +void server_client_handle_key(struct client *, key_code); void server_client_create(int); int server_client_open(struct client *, char **); void server_client_unref(struct client *); @@ -1803,7 +1810,7 @@ void status_prompt_set(struct client *, const char *, const char *, int (*)(void *, const char *), void (*)(void *), void *, int); void status_prompt_clear(struct client *); int status_prompt_redraw(struct client *); -void status_prompt_key(struct client *, int); +void status_prompt_key(struct client *, key_code); void status_prompt_update(struct client *, const char *, const char *); void status_prompt_load_history(void); void status_prompt_save_history(void); @@ -1819,11 +1826,11 @@ struct evbuffer *input_pending(struct window_pane *); void input_parse(struct window_pane *); /* input-key.c */ -void input_key(struct window_pane *, int, struct mouse_event *); +void input_key(struct window_pane *, key_code, struct mouse_event *); /* xterm-keys.c */ -char *xterm_keys_lookup(int); -int xterm_keys_find(const char *, size_t, size_t *, int *); +char *xterm_keys_lookup(key_code); +int xterm_keys_find(const char *, size_t, size_t *, key_code *); /* colour.c */ int colour_find_rgb(u_char, u_char, u_char); @@ -2020,7 +2027,7 @@ int window_pane_set_mode( struct window_pane *, const struct window_mode *); void window_pane_reset_mode(struct window_pane *); void window_pane_key(struct window_pane *, struct client *, - struct session *, int, struct mouse_event *); + struct session *, key_code, struct mouse_event *); int window_pane_visible(struct window_pane *); char *window_pane_search( struct window_pane *, const char *, u_int *); @@ -2179,6 +2186,7 @@ void utf8_set(struct utf8_data *, u_char); int utf8_open(struct utf8_data *, u_char); int utf8_append(struct utf8_data *, u_char); u_int utf8_combine(const struct utf8_data *); +int utf8_split(u_int, struct utf8_data *); u_int utf8_split2(u_int, u_char *); int utf8_strvis(char *, const char *, size_t, int); struct utf8_data *utf8_fromcstr(const char *); diff --git a/tty-keys.c b/tty-keys.c index 309e8c04..31adf0f0 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -33,11 +33,11 @@ * into a ternary tree. */ -void tty_keys_add1(struct tty_key **, const char *, int); -void tty_keys_add(struct tty *, const char *, int); +void tty_keys_add1(struct tty_key **, const char *, key_code); +void tty_keys_add(struct tty *, const char *, key_code); void tty_keys_free1(struct tty_key *); -struct tty_key *tty_keys_find1( - struct tty_key *, const char *, size_t, size_t *); +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(struct tty *, const char *, size_t, size_t *); @@ -45,7 +45,7 @@ int tty_keys_mouse(struct tty *, const char *, size_t, size_t *); /* Default raw keys. */ struct tty_default_key_raw { const char *string; - int key; + key_code key; }; const struct tty_default_key_raw tty_default_raw_keys[] = { /* @@ -165,7 +165,7 @@ const struct tty_default_key_raw tty_default_raw_keys[] = { /* Default terminfo(5) keys. */ struct tty_default_key_code { enum tty_code_code code; - int key; + key_code key; }; const struct tty_default_key_code tty_default_code_keys[] = { /* Function keys. */ @@ -317,7 +317,7 @@ const struct tty_default_key_code tty_default_code_keys[] = { /* Add key to tree. */ void -tty_keys_add(struct tty *tty, const char *s, int key) +tty_keys_add(struct tty *tty, const char *s, key_code key) { struct tty_key *tk; size_t size; @@ -325,17 +325,17 @@ tty_keys_add(struct tty *tty, const char *s, int key) keystr = key_string_lookup_key(key); if ((tk = tty_keys_find(tty, s, strlen(s), &size)) == NULL) { - log_debug("new key %s: 0x%x (%s)", s, key, keystr); + log_debug("new key %s: 0x%llx (%s)", s, key, keystr); tty_keys_add1(&tty->key_tree, s, key); } else { - log_debug("replacing key %s: 0x%x (%s)", s, key, keystr); + log_debug("replacing key %s: 0x%llx (%s)", s, key, keystr); tk->key = key; } } /* Add next node to the tree. */ void -tty_keys_add1(struct tty_key **tkp, const char *s, int key) +tty_keys_add1(struct tty_key **tkp, const char *s, key_code key) { struct tty_key *tk; @@ -464,15 +464,18 @@ tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size) * Process at least one key in the buffer and invoke tty->key_callback. Return * 0 if there are no further keys, or 1 if there could be more in the buffer. */ -int +key_code tty_keys_next(struct tty *tty) { - struct tty_key *tk; - struct timeval tv; - const char *buf; - size_t len, size; - cc_t bspace; - int key, delay, expired = 0; + struct tty_key *tk; + struct timeval tv; + const char *buf; + size_t len, size; + cc_t bspace; + int delay, expired = 0; + key_code key; + struct utf8_data utf8data; + u_int i; /* Get key buffer. */ buf = EVBUFFER_DATA(tty->event->input); @@ -535,8 +538,23 @@ first_key: } } + /* Is this valid UTF-8? */ + if (utf8_open(&utf8data, (u_char)*buf)) { + size = utf8data.size; + if (len < size) { + if (expired) + goto discard_key; + goto partial_key; + } + for (i = 1; i < size; i++) + utf8_append(&utf8data, (u_char)buf[i]); + key = utf8_combine(&utf8data); + log_debug("UTF-8 key %.*s %#llx", (int)size, buf, key); + goto complete_key; + } + /* No key found, take first. */ - key = (u_char) *buf; + key = (u_char)*buf; size = 1; /* @@ -578,7 +596,7 @@ partial_key: return (0); complete_key: - log_debug("complete key %.*s %#x", (int) size, buf, key); + log_debug("complete key %.*s %#llx", (int)size, buf, key); /* Remove data from buffer. */ evbuffer_drain(tty->event->input, size); @@ -604,7 +622,7 @@ complete_key: return (1); discard_key: - log_debug("discard key %.*s %#x", (int) size, buf, key); + log_debug("discard key %.*s %#llx", (int)size, buf, key); /* Remove data from buffer. */ evbuffer_drain(tty->event->input, size); @@ -684,10 +702,10 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) utf8_append(&utf8data, buf[*size]); value = utf8_combine(&utf8data); } else - value = (u_char) buf[*size]; + value = (u_char)buf[*size]; (*size)++; } else { - value = (u_char) buf[*size]; + value = (u_char)buf[*size]; (*size)++; } diff --git a/utf8.c b/utf8.c index 9a06c186..e61bf996 100644 --- a/utf8.c +++ b/utf8.c @@ -394,6 +394,8 @@ utf8_open(struct utf8_data *utf8data, u_char ch) int utf8_append(struct utf8_data *utf8data, u_char ch) { + /* XXX this should do validity checks too! */ + if (utf8data->have >= utf8data->size) fatalx("UTF-8 character overflow"); if (utf8data->size > sizeof utf8data->data) @@ -467,18 +469,46 @@ utf8_combine(const struct utf8_data *utf8data) case 3: value = utf8data->data[2] & 0x3f; value |= (utf8data->data[1] & 0x3f) << 6; - value |= (utf8data->data[0] & 0x0f) << 12; + value |= (utf8data->data[0] & 0xf) << 12; break; case 4: value = utf8data->data[3] & 0x3f; value |= (utf8data->data[2] & 0x3f) << 6; value |= (utf8data->data[1] & 0x3f) << 12; - value |= (utf8data->data[0] & 0x07) << 18; + value |= (utf8data->data[0] & 0x7) << 18; break; } return (value); } +/* Split a UTF-8 character. */ +int +utf8_split(u_int uc, struct utf8_data *utf8data) +{ + if (uc < 0x7f) { + utf8data->size = 1; + utf8data->data[0] = uc; + } else if (uc < 0x7ff) { + utf8data->size = 2; + utf8data->data[0] = 0xc0 | ((uc >> 6) & 0x1f); + utf8data->data[1] = 0x80 | (uc & 0x3f); + } else if (uc < 0xffff) { + utf8data->size = 3; + utf8data->data[0] = 0xe0 | ((uc >> 12) & 0xf); + utf8data->data[1] = 0x80 | ((uc >> 6) & 0x3f); + utf8data->data[2] = 0x80 | (uc & 0x3f); + } else if (uc < 0x1fffff) { + utf8data->size = 4; + utf8data->data[0] = 0xf0 | ((uc >> 18) & 0x7); + utf8data->data[1] = 0x80 | ((uc >> 12) & 0x3f); + utf8data->data[2] = 0x80 | ((uc >> 6) & 0x3f); + utf8data->data[3] = 0x80 | (uc & 0x3f); + } else + return (-1); + utf8data->width = utf8_width(utf8data); + return (0); +} + /* Split a two-byte UTF-8 character. */ u_int utf8_split2(u_int uc, u_char *ptr) diff --git a/window-choose.c b/window-choose.c index f1c3f94a..fa0e95c8 100644 --- a/window-choose.c +++ b/window-choose.c @@ -29,11 +29,11 @@ struct screen *window_choose_init(struct window_pane *); void window_choose_free(struct window_pane *); void window_choose_resize(struct window_pane *, u_int, u_int); void window_choose_key(struct window_pane *, struct client *, - struct session *, int, struct mouse_event *); + struct session *, key_code, struct mouse_event *); void window_choose_default_callback(struct window_choose_data *); struct window_choose_mode_item *window_choose_get_item(struct window_pane *, - int, struct mouse_event *); + key_code, struct mouse_event *); void window_choose_fire_callback( struct window_pane *, struct window_choose_data *); @@ -86,9 +86,9 @@ struct window_choose_mode_data { void window_choose_free1(struct window_choose_mode_data *); int window_choose_key_index(struct window_choose_mode_data *, u_int); -int window_choose_index_key(struct window_choose_mode_data *, int); +int window_choose_index_key(struct window_choose_mode_data *, key_code); void window_choose_prompt_input(enum window_choose_input_type, - const char *, struct window_pane *, int); + const char *, struct window_pane *, key_code); void window_choose_reset_top(struct window_pane *, u_int); void @@ -314,7 +314,7 @@ window_choose_fire_callback( void window_choose_prompt_input(enum window_choose_input_type input_type, - const char *prompt, struct window_pane *wp, int key) + const char *prompt, struct window_pane *wp, key_code key) { struct window_choose_mode_data *data = wp->modedata; size_t input_len; @@ -490,7 +490,8 @@ window_choose_expand(struct window_pane *wp, struct session *s, u_int pos) } struct window_choose_mode_item * -window_choose_get_item(struct window_pane *wp, int key, struct mouse_event *m) +window_choose_get_item(struct window_pane *wp, key_code key, + struct mouse_event *m) { struct window_choose_mode_data *data = wp->modedata; u_int x, y, idx; @@ -509,7 +510,7 @@ window_choose_get_item(struct window_pane *wp, int key, struct mouse_event *m) void window_choose_key(struct window_pane *wp, unused struct client *c, - unused struct session *sess, int key, struct mouse_event *m) + unused struct session *sess, key_code key, struct mouse_event *m) { struct window_choose_mode_data *data = wp->modedata; struct screen *s = &data->screen; @@ -743,8 +744,8 @@ window_choose_key(struct window_pane *wp, unused struct client *c, } void -window_choose_write_line( - struct window_pane *wp, struct screen_write_ctx *ctx, u_int py) +window_choose_write_line(struct window_pane *wp, struct screen_write_ctx *ctx, + u_int py) { struct window_choose_mode_data *data = wp->modedata; struct window_choose_mode_item *item; @@ -821,7 +822,7 @@ window_choose_key_index(struct window_choose_mode_data *data, u_int idx) } int -window_choose_index_key(struct window_choose_mode_data *data, int key) +window_choose_index_key(struct window_choose_mode_data *data, key_code key) { static const char keys[] = "0123456789" "abcdefghijklmnopqrstuvwxyz" @@ -834,7 +835,7 @@ window_choose_index_key(struct window_choose_mode_data *data, int key) mkey = mode_key_lookup(&data->mdata, *ptr, NULL); if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER) continue; - if (key == *ptr) + if (key == (key_code)*ptr) return (idx); idx++; } diff --git a/window-clock.c b/window-clock.c index e366714b..51f97250 100644 --- a/window-clock.c +++ b/window-clock.c @@ -28,7 +28,7 @@ struct screen *window_clock_init(struct window_pane *); void window_clock_free(struct window_pane *); void window_clock_resize(struct window_pane *, u_int, u_int); void window_clock_key(struct window_pane *, struct client *, - struct session *, int, struct mouse_event *); + struct session *, key_code, struct mouse_event *); void window_clock_timer_callback(int, short, void *); void window_clock_draw_screen(struct window_pane *); @@ -186,7 +186,8 @@ window_clock_resize(struct window_pane *wp, u_int sx, u_int sy) void window_clock_key(struct window_pane *wp, unused struct client *c, - unused struct session *sess, unused int key, unused struct mouse_event *m) + unused struct session *sess, unused key_code key, + unused struct mouse_event *m) { window_pane_reset_mode(wp); } diff --git a/window-copy.c b/window-copy.c index c5c053bf..d3e5b7d9 100644 --- a/window-copy.c +++ b/window-copy.c @@ -28,9 +28,9 @@ struct screen *window_copy_init(struct window_pane *); void window_copy_free(struct window_pane *); void window_copy_resize(struct window_pane *, u_int, u_int); void window_copy_key(struct window_pane *, struct client *, struct session *, - int, struct mouse_event *); -int window_copy_key_input(struct window_pane *, int); -int window_copy_key_numeric_prefix(struct window_pane *, int); + key_code, struct mouse_event *); +int window_copy_key_input(struct window_pane *, key_code); +int window_copy_key_numeric_prefix(struct window_pane *, key_code); void window_copy_redraw_selection(struct window_pane *, u_int); void window_copy_redraw_lines(struct window_pane *, u_int, u_int); @@ -368,7 +368,7 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy) void window_copy_key(struct window_pane *wp, struct client *c, struct session *sess, - int key, struct mouse_event *m) + key_code key, struct mouse_event *m) { const char *word_separators; struct window_copy_mode_data *data = wp->modedata; @@ -800,7 +800,7 @@ input_off: } int -window_copy_key_input(struct window_pane *wp, int key) +window_copy_key_input(struct window_pane *wp, key_code key) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; @@ -897,7 +897,7 @@ window_copy_key_input(struct window_pane *wp, int key) } int -window_copy_key_numeric_prefix(struct window_pane *wp, int key) +window_copy_key_numeric_prefix(struct window_pane *wp, key_code key) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; diff --git a/window.c b/window.c index 49408297..c5f9f176 100644 --- a/window.c +++ b/window.c @@ -1102,7 +1102,7 @@ window_pane_reset_mode(struct window_pane *wp) void window_pane_key(struct window_pane *wp, struct client *c, struct session *s, - int key, struct mouse_event *m) + key_code key, struct mouse_event *m) { struct window_pane *wp2; diff --git a/xterm-keys.c b/xterm-keys.c index 10d51c78..f1490fcc 100644 --- a/xterm-keys.c +++ b/xterm-keys.c @@ -40,11 +40,12 @@ * We accept any but always output the latter (it comes first in the table). */ -int xterm_keys_match(const char *, const char *, size_t, size_t *, u_int *); -int xterm_keys_modifiers(const char *, size_t, size_t *, u_int *); +int xterm_keys_match(const char *, const char *, size_t, size_t *, + key_code *); +int xterm_keys_modifiers(const char *, size_t, size_t *, key_code *); struct xterm_keys_entry { - int key; + key_code key; const char *template; }; @@ -115,7 +116,7 @@ const struct xterm_keys_entry xterm_keys_table[] = { */ int xterm_keys_match(const char *template, const char *buf, size_t len, - size_t *size, u_int *modifiers) + size_t *size, key_code *modifiers) { size_t pos; int retval; @@ -148,7 +149,8 @@ xterm_keys_match(const char *template, const char *buf, size_t len, /* Find modifiers from buffer. */ int -xterm_keys_modifiers(const char *buf, size_t len, size_t *pos, u_int *modifiers) +xterm_keys_modifiers(const char *buf, size_t len, size_t *pos, + key_code *modifiers) { u_int flags; @@ -179,11 +181,12 @@ xterm_keys_modifiers(const char *buf, size_t len, size_t *pos, u_int *modifiers) * key), -1 for not found, 1 for partial match. */ int -xterm_keys_find(const char *buf, size_t len, size_t *size, int *key) +xterm_keys_find(const char *buf, size_t len, size_t *size, key_code *key) { const struct xterm_keys_entry *entry; - u_int i, modifiers; + u_int i; int matched; + key_code modifiers; for (i = 0; i < nitems(xterm_keys_table); i++) { entry = &xterm_keys_table[i]; @@ -201,11 +204,11 @@ xterm_keys_find(const char *buf, size_t len, size_t *size, int *key) /* Lookup a key number from the table. */ char * -xterm_keys_lookup(int key) +xterm_keys_lookup(key_code key) { const struct xterm_keys_entry *entry; u_int i; - int modifiers; + key_code modifiers; char *out; modifiers = 1;