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.)
This commit is contained in:
nicm 2015-11-12 11:05:34 +00:00
parent 7062b0e65d
commit 69e0b8326a
19 changed files with 280 additions and 168 deletions

View File

@ -29,7 +29,8 @@
enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmd_q *); 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 = { const struct cmd_entry cmd_bind_key_entry = {
"bind-key", "bind", "bind-key", "bind",
@ -45,7 +46,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq)
struct args *args = self->args; struct args *args = self->args;
char *cause; char *cause;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
int key; key_code key;
const char *tablename; const char *tablename;
if (args_has(args, 't')) { if (args_has(args, 't')) {
@ -89,7 +90,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq)
} }
enum cmd_retval 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; struct args *args = self->args;
const char *tablename; const char *tablename;

View File

@ -57,6 +57,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
char tmp[BUFSIZ]; char tmp[BUFSIZ];
size_t used; size_t used;
int repeat, width, tablewidth, keywidth; int repeat, width, tablewidth, keywidth;
u_int i;
if (self->entry == &cmd_list_commands_entry) if (self->entry == &cmd_list_commands_entry)
return (cmd_list_keys_commands(self, cmdq)); return (cmd_list_keys_commands(self, cmdq));
@ -84,7 +85,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
width = strlen(table->name); width = strlen(table->name);
if (width > tablewidth) if (width > tablewidth)
tablewidth = width; tablewidth = width;
width = strlen(key); width = utf8_cstrwidth(key);
if (width > keywidth) if (width > keywidth)
keywidth = width; keywidth = width;
} }
@ -102,8 +103,12 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
r = "-r "; r = "-r ";
else else
r = " "; r = " ";
used = xsnprintf(tmp, sizeof tmp, "%s-T %-*s %-*s ", r, used = xsnprintf(tmp, sizeof tmp, "%s-T %-*s %s", r,
(int)tablewidth, table->name, (int)keywidth, key); (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) { if (used < sizeof tmp) {
cmd_list_print(bd->cmdlist, tmp + used, cmd_list_print(bd->cmdlist, tmp + used,
(sizeof tmp) - used); (sizeof tmp) - used);

View File

@ -53,7 +53,8 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq)
struct window_pane *wp; struct window_pane *wp;
struct session *s; struct session *s;
const u_char *str; const u_char *str;
int i, key; int i;
key_code key;
if (args_has(args, 'M')) { if (args_has(args, 'M')) {
wp = cmd_mouse_pane(m, &s, NULL); wp = cmd_mouse_pane(m, &s, NULL);

View File

@ -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 struct options_table_entry *oe, struct options *oo,
const char *value) const char *value)
{ {
int key; key_code key;
if ((key = key_string_lookup_string(value)) == KEYC_NONE) { if ((key = key_string_lookup_string(value)) == KEYC_NONE) {
cmdq_error(cmdq, "bad key: %s", value); cmdq_error(cmdq, "bad key: %s", value);

View File

@ -27,7 +27,8 @@
*/ */
enum cmd_retval cmd_unbind_key_exec(struct cmd *, struct cmd_q *); 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_mode_table(struct cmd *, struct cmd_q *,
key_code);
const struct cmd_entry cmd_unbind_key_entry = { const struct cmd_entry cmd_unbind_key_entry = {
"unbind-key", "unbind", "unbind-key", "unbind",
@ -41,7 +42,7 @@ enum cmd_retval
cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq) cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
int key; key_code key;
const char *tablename; const char *tablename;
if (!args_has(args, 'a')) { if (!args_has(args, 'a')) {
@ -95,7 +96,7 @@ cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq)
} }
enum cmd_retval 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; struct args *args = self->args;
const char *tablename; const char *tablename;

View File

@ -34,7 +34,7 @@
void input_key_mouse(struct window_pane *, struct mouse_event *); void input_key_mouse(struct window_pane *, struct mouse_event *);
struct input_key_ent { struct input_key_ent {
int key; key_code key;
const char *data; const char *data;
int flags; int flags;
@ -137,15 +137,16 @@ const struct input_key_ent input_keys[] = {
/* Translate a key code into an output key sequence. */ /* Translate a key code into an output key sequence. */
void 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; const struct input_key_ent *ike;
u_int i; u_int i;
size_t dlen; size_t dlen;
char *out; char *out;
u_char ch; 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); key_string_lookup_key(key), wp->id);
/* If this is a mouse key, pass off to mouse function. */ /* 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 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) if (key & KEYC_ESCAPE)
bufferevent_write(wp->event, "\033", 1); bufferevent_write(wp->event, "\033", 1);
ch = key & ~KEYC_ESCAPE; utf8data.data[0] = justkey;
bufferevent_write(wp->event, &ch, 1); 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; return;
} }
@ -196,11 +206,11 @@ input_key(struct window_pane *wp, int key, struct mouse_event *m)
break; break;
} }
if (i == nitems(input_keys)) { if (i == nitems(input_keys)) {
log_debug("key 0x%x missing", key); log_debug("key 0x%llx missing", key);
return; return;
} }
dlen = strlen(ike->data); 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. */ /* Prefix a \033 for escape. */
if (key & KEYC_ESCAPE) if (key & KEYC_ESCAPE)

View File

@ -37,7 +37,11 @@ key_table_cmp(struct key_table *e1, struct key_table *e2)
int int
key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2) 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 * struct key_table *
@ -80,7 +84,7 @@ key_bindings_unref_table(struct key_table *table)
} }
void 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 cmd_list *cmdlist)
{ {
struct key_table *table; struct key_table *table;
@ -105,7 +109,7 @@ key_bindings_add(const char *name, int key, int can_repeat,
} }
void void
key_bindings_remove(const char *name, int key) key_bindings_remove(const char *name, key_code key)
{ {
struct key_table *table; struct key_table *table;
struct key_binding bd_find, *bd; struct key_binding bd_find, *bd;

View File

@ -22,12 +22,12 @@
#include "tmux.h" #include "tmux.h"
int key_string_search_table(const char *); key_code key_string_search_table(const char *);
int key_string_get_modifiers(const char **); key_code key_string_get_modifiers(const char **);
const struct { const struct {
const char *string; const char *string;
int key; key_code key;
} key_string_table[] = { } key_string_table[] = {
/* Function keys. */ /* Function keys. */
{ "F1", KEYC_F1 }, { "F1", KEYC_F1 },
@ -98,7 +98,7 @@ const struct {
}; };
/* Find key string in table. */ /* Find key string in table. */
int key_code
key_string_search_table(const char *string) key_string_search_table(const char *string)
{ {
u_int i; u_int i;
@ -111,10 +111,10 @@ key_string_search_table(const char *string)
} }
/* Find modifiers. */ /* Find modifiers. */
int key_code
key_string_get_modifiers(const char **string) key_string_get_modifiers(const char **string)
{ {
int modifiers; key_code modifiers;
modifiers = 0; modifiers = 0;
while (((*string)[0] != '\0') && (*string)[1] == '-') { 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. */ /* Lookup a string and convert to a key value. */
int key_code
key_string_lookup_string(const char *string) key_string_lookup_string(const char *string)
{ {
static const char *other = "!#()+,-.0123456789:;<=>?'\r\t"; static const char *other = "!#()+,-.0123456789:;<=>?'\r\t";
int key, modifiers; key_code key;
u_short u; u_short u;
int size; int size;
key_code modifiers;
struct utf8_data utf8data;
u_int i;
/* Is this a hexadecimal value? */ /* Is this a hexadecimal value? */
if (string[0] == '0' && string[1] == 'x') { if (string[0] == '0' && string[1] == 'x') {
@ -164,11 +167,21 @@ key_string_lookup_string(const char *string)
return (KEYC_NONE); return (KEYC_NONE);
/* Is this a standard ASCII key? */ /* Is this a standard ASCII key? */
if (string[1] == '\0') { if (string[1] == '\0' && (u_char)string[0] <= 127) {
key = (u_char)string[0]; key = (u_char)string[0];
if (key < 32 || key == 127 || key > 255) if (key < 32 || key == 127)
return (KEYC_NONE); return (KEYC_NONE);
} else { } 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. */ /* Otherwise look the key up in the table. */
key = key_string_search_table(string); key = key_string_search_table(string);
if (key == KEYC_NONE) 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. */ /* Convert a key code into string format, with prefix if necessary. */
const char * const char *
key_string_lookup_key(int key) key_string_lookup_key(key_code key)
{ {
static char out[24]; static char out[24];
char tmp[8]; char tmp[8];
u_int i; u_int i;
struct utf8_data utf8data;
*out = '\0'; *out = '\0';
@ -237,23 +251,32 @@ key_string_lookup_key(int key)
return (out); 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. */ /* Invalid keys are errors. */
if (key == 127 || key > 255) { if (key == 127 || key > 255) {
snprintf(out, sizeof out, "<INVALID#%04x>", key); snprintf(out, sizeof out, "<INVALID#%llx>", key);
return (out); return (out);
} }
/* Check for standard or control key. */ /* Check for standard or control key. */
if (key >= 0 && key <= 32) { if (key <= 32) {
if (key == 0 || key > 26) if (key == 0 || key > 26)
xsnprintf(tmp, sizeof tmp, "C-%c", 64 + key); xsnprintf(tmp, sizeof tmp, "C-%c", (int)(64 + key));
else else
xsnprintf(tmp, sizeof tmp, "C-%c", 96 + key); xsnprintf(tmp, sizeof tmp, "C-%c", (int)(96 + key));
} else if (key >= 32 && key <= 126) { } else if (key >= 32 && key <= 126) {
tmp[0] = key; tmp[0] = key;
tmp[1] = '\0'; tmp[1] = '\0';
} else if (key >= 128) } else if (key >= 128)
xsnprintf(tmp, sizeof tmp, "\\%o", key); xsnprintf(tmp, sizeof tmp, "\\%llo", key);
strlcat(out, tmp, sizeof out); strlcat(out, tmp, sizeof out);
return (out); return (out);

View File

@ -40,7 +40,7 @@
/* Entry in the default mode key tables. */ /* Entry in the default mode key tables. */
struct mode_key_entry { struct mode_key_entry {
int key; key_code key;
/* /*
* Editing mode for vi: 0 is edit mode, keys not in the table are * 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 int
mode_key_cmp(struct mode_key_binding *mbind1, struct mode_key_binding *mbind2) mode_key_cmp(struct mode_key_binding *mbind1, struct mode_key_binding *mbind2)
{ {
if (mbind1->mode != mbind2->mode) if (mbind1->mode < mbind2->mode)
return (mbind1->mode - mbind2->mode); return (-1);
return (mbind1->key - mbind2->key); 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 * const char *
@ -588,7 +594,7 @@ mode_key_init(struct mode_key_data *mdata, struct mode_key_tree *mtree)
} }
enum mode_key_cmd 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; struct mode_key_binding *mbind, mtmp;

View File

@ -36,7 +36,7 @@ void server_client_key_table(struct client *, const char *);
void server_client_free(int, short, void *); void server_client_free(int, short, void *);
void server_client_check_focus(struct window_pane *); void server_client_check_focus(struct window_pane *);
void server_client_check_resize(struct window_pane *); void server_client_check_resize(struct window_pane *);
int server_client_check_mouse(struct client *); key_code server_client_check_mouse(struct client *);
void server_client_repeat_timer(int, short, void *); void server_client_repeat_timer(int, short, void *);
void server_client_check_exit(struct client *); void server_client_check_exit(struct client *);
void server_client_check_redraw(struct client *); void server_client_check_redraw(struct client *);
@ -257,7 +257,7 @@ server_client_free(unused int fd, unused short events, void *arg)
} }
/* Check for mouse keys. */ /* Check for mouse keys. */
int key_code
server_client_check_mouse(struct client *c) server_client_check_mouse(struct client *c)
{ {
struct session *s = c->session; 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 { NOTYPE, DOWN, UP, DRAG, WHEEL } type = NOTYPE;
enum { NOWHERE, PANE, STATUS, BORDER } where = NOWHERE; enum { NOWHERE, PANE, STATUS, BORDER } where = NOWHERE;
u_int x, y, b; 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, 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); 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. */ /* Handle data key input from client. */
void 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 mouse_event *m = &c->tty.mouse;
struct session *s = c->session; struct session *s = c->session;
@ -635,8 +635,8 @@ retry:
* No match, but in the root table. Prefix switches to the prefix table * No match, but in the root table. Prefix switches to the prefix table
* and everything else is passed through. * and everything else is passed through.
*/ */
if (key == options_get_number(s->options, "prefix") || if (key == (key_code)options_get_number(s->options, "prefix") ||
key == options_get_number(s->options, "prefix2")) { key == (key_code)options_get_number(s->options, "prefix2")) {
server_client_key_table(c, "prefix"); server_client_key_table(c, "prefix");
server_status_client(c); server_status_client(c);
return; return;

View File

@ -812,7 +812,7 @@ status_prompt_redraw(struct client *c)
/* Handle keys in prompt. */ /* Handle keys in prompt. */
void void
status_prompt_key(struct client *c, int key) status_prompt_key(struct client *c, key_code key)
{ {
struct session *sess = c->session; struct session *sess = c->session;
struct options *oo = sess->options; struct options *oo = sess->options;
@ -1116,7 +1116,7 @@ status_prompt_key(struct client *c, int key)
status_prompt_clear(c); status_prompt_clear(c);
break; break;
case MODEKEY_OTHER: case MODEKEY_OTHER:
if ((key & 0xff00) != 0 || key < 32 || key == 127) if (key <= 0x1f || key >= 0x7f)
break; break;
c->prompt_buffer = xrealloc(c->prompt_buffer, size + 2); c->prompt_buffer = xrealloc(c->prompt_buffer, size + 2);

54
tmux.h
View File

@ -95,13 +95,13 @@ struct tmuxproc;
#define BELL_OTHER 3 #define BELL_OTHER 3
/* Special key codes. */ /* Special key codes. */
#define KEYC_NONE 0xfff #define KEYC_NONE 0xffff00000000ULL
#define KEYC_BASE 0x1000 #define KEYC_BASE 0x100000000000ULL
/* Key modifier bits. */ /* Key modifier bits. */
#define KEYC_ESCAPE 0x2000 #define KEYC_ESCAPE 0x200000000000ULL
#define KEYC_CTRL 0x4000 #define KEYC_CTRL 0x400000000000ULL
#define KEYC_SHIFT 0x8000 #define KEYC_SHIFT 0x800000000000ULL
/* Mask to obtain key w/o modifiers. */ /* Mask to obtain key w/o modifiers. */
#define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT) #define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT)
@ -121,8 +121,14 @@ struct tmuxproc;
{ #s "Status", KEYC_ ## name ## _STATUS }, \ { #s "Status", KEYC_ ## name ## _STATUS }, \
{ #s "Border", KEYC_ ## name ## _BORDER } { #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. */ /* Special key codes. */
enum key_code { enum {
/* Focus events. */ /* Focus events. */
KEYC_FOCUS_IN = KEYC_BASE, KEYC_FOCUS_IN = KEYC_BASE,
KEYC_FOCUS_OUT, KEYC_FOCUS_OUT,
@ -570,7 +576,7 @@ struct mode_key_data {
/* Binding between a key and a command. */ /* Binding between a key and a command. */
struct mode_key_binding { struct mode_key_binding {
int key; key_code key;
int mode; int mode;
enum mode_key_cmd cmd; enum mode_key_cmd cmd;
@ -776,7 +782,7 @@ struct window_mode {
void (*free)(struct window_pane *); void (*free)(struct window_pane *);
void (*resize)(struct window_pane *, u_int, u_int); void (*resize)(struct window_pane *, u_int, u_int);
void (*key)(struct window_pane *, struct client *, struct session *, void (*key)(struct window_pane *, struct client *, struct session *,
int, struct mouse_event *); key_code, struct mouse_event *);
}; };
/* Structures for choose mode. */ /* Structures for choose mode. */
@ -1032,7 +1038,7 @@ RB_HEAD(sessions, session);
struct mouse_event { struct mouse_event {
int valid; int valid;
int key; key_code key;
int statusat; int statusat;
u_int x; u_int x;
@ -1054,7 +1060,7 @@ struct mouse_event {
/* TTY information. */ /* TTY information. */
struct tty_key { struct tty_key {
char ch; char ch;
int key; key_code key;
struct tty_key *left; struct tty_key *left;
struct tty_key *right; struct tty_key *right;
@ -1340,7 +1346,7 @@ struct cmd_entry {
/* Key binding and key table. */ /* Key binding and key table. */
struct key_binding { struct key_binding {
int key; key_code key;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
int can_repeat; 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 *); const struct mode_key_table *mode_key_findtable(const char *);
void mode_key_init_trees(void); void mode_key_init_trees(void);
void mode_key_init(struct mode_key_data *, struct mode_key_tree *); 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 */ /* notify.c */
void notify_enable(void); void notify_enable(void);
@ -1634,7 +1641,7 @@ const char *tty_acs_get(struct tty *, u_char);
/* tty-keys.c */ /* tty-keys.c */
void tty_keys_build(struct tty *); void tty_keys_build(struct tty *);
void tty_keys_free(struct tty *); void tty_keys_free(struct tty *);
int tty_keys_next(struct tty *); key_code tty_keys_next(struct tty *);
/* arguments.c */ /* arguments.c */
int args_cmp(struct args_entry *, struct args_entry *); 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 *); int key_bindings_cmp(struct key_binding *, struct key_binding *);
struct key_table *key_bindings_get_table(const char *, int); struct key_table *key_bindings_get_table(const char *, int);
void key_bindings_unref_table(struct key_table *); void key_bindings_unref_table(struct key_table *);
void key_bindings_add(const char *, int, int, struct cmd_list *); void key_bindings_add(const char *, key_code, int, struct cmd_list *);
void key_bindings_remove(const char *, int); void key_bindings_remove(const char *, key_code);
void key_bindings_remove_table(const char *); void key_bindings_remove_table(const char *);
void key_bindings_init(void); void key_bindings_init(void);
void key_bindings_dispatch(struct key_binding *, struct client *, void key_bindings_dispatch(struct key_binding *, struct client *,
struct mouse_event *); struct mouse_event *);
/* key-string.c */ /* key-string.c */
int key_string_lookup_string(const char *); key_code key_string_lookup_string(const char *);
const char *key_string_lookup_key(int); const char *key_string_lookup_key(key_code);
/* alerts.c */ /* alerts.c */
void alerts_reset_all(void); void alerts_reset_all(void);
@ -1753,7 +1760,7 @@ void server_add_accept(int);
/* server-client.c */ /* server-client.c */
int server_client_check_nested(struct client *); 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); void server_client_create(int);
int server_client_open(struct client *, char **); int server_client_open(struct client *, char **);
void server_client_unref(struct client *); 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); int (*)(void *, const char *), void (*)(void *), void *, int);
void status_prompt_clear(struct client *); void status_prompt_clear(struct client *);
int status_prompt_redraw(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_update(struct client *, const char *, const char *);
void status_prompt_load_history(void); void status_prompt_load_history(void);
void status_prompt_save_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 *); void input_parse(struct window_pane *);
/* input-key.c */ /* 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 */ /* xterm-keys.c */
char *xterm_keys_lookup(int); char *xterm_keys_lookup(key_code);
int xterm_keys_find(const char *, size_t, size_t *, int *); int xterm_keys_find(const char *, size_t, size_t *, key_code *);
/* colour.c */ /* colour.c */
int colour_find_rgb(u_char, u_char, u_char); 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 *); struct window_pane *, const struct window_mode *);
void window_pane_reset_mode(struct window_pane *); void window_pane_reset_mode(struct window_pane *);
void window_pane_key(struct window_pane *, struct client *, 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 *); int window_pane_visible(struct window_pane *);
char *window_pane_search( char *window_pane_search(
struct window_pane *, const char *, u_int *); 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_open(struct utf8_data *, u_char);
int utf8_append(struct utf8_data *, u_char); int utf8_append(struct utf8_data *, u_char);
u_int utf8_combine(const struct utf8_data *); u_int utf8_combine(const struct utf8_data *);
int utf8_split(u_int, struct utf8_data *);
u_int utf8_split2(u_int, u_char *); u_int utf8_split2(u_int, u_char *);
int utf8_strvis(char *, const char *, size_t, int); int utf8_strvis(char *, const char *, size_t, int);
struct utf8_data *utf8_fromcstr(const char *); struct utf8_data *utf8_fromcstr(const char *);

View File

@ -33,11 +33,11 @@
* into a ternary tree. * into a ternary tree.
*/ */
void tty_keys_add1(struct tty_key **, const char *, int); void tty_keys_add1(struct tty_key **, const char *, key_code);
void tty_keys_add(struct tty *, const char *, int); void tty_keys_add(struct tty *, const char *, key_code);
void tty_keys_free1(struct tty_key *); void tty_keys_free1(struct tty_key *);
struct tty_key *tty_keys_find1( struct tty_key *tty_keys_find1(struct tty_key *, const char *, size_t,
struct tty_key *, const char *, size_t, size_t *); size_t *);
struct tty_key *tty_keys_find(struct tty *, 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 *); void tty_keys_callback(int, short, void *);
int tty_keys_mouse(struct tty *, const char *, size_t, size_t *); 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. */ /* Default raw keys. */
struct tty_default_key_raw { struct tty_default_key_raw {
const char *string; const char *string;
int key; key_code key;
}; };
const struct tty_default_key_raw tty_default_raw_keys[] = { 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. */ /* Default terminfo(5) keys. */
struct tty_default_key_code { struct tty_default_key_code {
enum tty_code_code code; enum tty_code_code code;
int key; key_code key;
}; };
const struct tty_default_key_code tty_default_code_keys[] = { const struct tty_default_key_code tty_default_code_keys[] = {
/* Function keys. */ /* Function keys. */
@ -317,7 +317,7 @@ const struct tty_default_key_code tty_default_code_keys[] = {
/* Add key to tree. */ /* Add key to tree. */
void 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; struct tty_key *tk;
size_t size; size_t size;
@ -325,17 +325,17 @@ tty_keys_add(struct tty *tty, const char *s, int key)
keystr = key_string_lookup_key(key); keystr = key_string_lookup_key(key);
if ((tk = tty_keys_find(tty, s, strlen(s), &size)) == NULL) { 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); tty_keys_add1(&tty->key_tree, s, key);
} else { } 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; tk->key = key;
} }
} }
/* Add next node to the tree. */ /* Add next node to the tree. */
void 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; struct tty_key *tk;
@ -464,7 +464,7 @@ 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 * 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. * 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) tty_keys_next(struct tty *tty)
{ {
struct tty_key *tk; struct tty_key *tk;
@ -472,7 +472,10 @@ tty_keys_next(struct tty *tty)
const char *buf; const char *buf;
size_t len, size; size_t len, size;
cc_t bspace; cc_t bspace;
int key, delay, expired = 0; int delay, expired = 0;
key_code key;
struct utf8_data utf8data;
u_int i;
/* Get key buffer. */ /* Get key buffer. */
buf = EVBUFFER_DATA(tty->event->input); buf = EVBUFFER_DATA(tty->event->input);
@ -535,6 +538,21 @@ 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. */ /* No key found, take first. */
key = (u_char)*buf; key = (u_char)*buf;
size = 1; size = 1;
@ -578,7 +596,7 @@ partial_key:
return (0); return (0);
complete_key: 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. */ /* Remove data from buffer. */
evbuffer_drain(tty->event->input, size); evbuffer_drain(tty->event->input, size);
@ -604,7 +622,7 @@ complete_key:
return (1); return (1);
discard_key: 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. */ /* Remove data from buffer. */
evbuffer_drain(tty->event->input, size); evbuffer_drain(tty->event->input, size);

34
utf8.c
View File

@ -394,6 +394,8 @@ utf8_open(struct utf8_data *utf8data, u_char ch)
int int
utf8_append(struct utf8_data *utf8data, u_char ch) utf8_append(struct utf8_data *utf8data, u_char ch)
{ {
/* XXX this should do validity checks too! */
if (utf8data->have >= utf8data->size) if (utf8data->have >= utf8data->size)
fatalx("UTF-8 character overflow"); fatalx("UTF-8 character overflow");
if (utf8data->size > sizeof utf8data->data) if (utf8data->size > sizeof utf8data->data)
@ -467,18 +469,46 @@ utf8_combine(const struct utf8_data *utf8data)
case 3: case 3:
value = utf8data->data[2] & 0x3f; value = utf8data->data[2] & 0x3f;
value |= (utf8data->data[1] & 0x3f) << 6; value |= (utf8data->data[1] & 0x3f) << 6;
value |= (utf8data->data[0] & 0x0f) << 12; value |= (utf8data->data[0] & 0xf) << 12;
break; break;
case 4: case 4:
value = utf8data->data[3] & 0x3f; value = utf8data->data[3] & 0x3f;
value |= (utf8data->data[2] & 0x3f) << 6; value |= (utf8data->data[2] & 0x3f) << 6;
value |= (utf8data->data[1] & 0x3f) << 12; value |= (utf8data->data[1] & 0x3f) << 12;
value |= (utf8data->data[0] & 0x07) << 18; value |= (utf8data->data[0] & 0x7) << 18;
break; break;
} }
return (value); 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. */ /* Split a two-byte UTF-8 character. */
u_int u_int
utf8_split2(u_int uc, u_char *ptr) utf8_split2(u_int uc, u_char *ptr)

View File

@ -29,11 +29,11 @@ struct screen *window_choose_init(struct window_pane *);
void window_choose_free(struct window_pane *); void window_choose_free(struct window_pane *);
void window_choose_resize(struct window_pane *, u_int, u_int); void window_choose_resize(struct window_pane *, u_int, u_int);
void window_choose_key(struct window_pane *, struct client *, 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 *); void window_choose_default_callback(struct window_choose_data *);
struct window_choose_mode_item *window_choose_get_item(struct window_pane *, 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( void window_choose_fire_callback(
struct window_pane *, struct window_choose_data *); 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 *); void window_choose_free1(struct window_choose_mode_data *);
int window_choose_key_index(struct window_choose_mode_data *, u_int); 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, 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 window_choose_reset_top(struct window_pane *, u_int);
void void
@ -314,7 +314,7 @@ window_choose_fire_callback(
void void
window_choose_prompt_input(enum window_choose_input_type input_type, 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; struct window_choose_mode_data *data = wp->modedata;
size_t input_len; 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 * 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; struct window_choose_mode_data *data = wp->modedata;
u_int x, y, idx; u_int x, y, idx;
@ -509,7 +510,7 @@ window_choose_get_item(struct window_pane *wp, int key, struct mouse_event *m)
void void
window_choose_key(struct window_pane *wp, unused struct client *c, 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 window_choose_mode_data *data = wp->modedata;
struct screen *s = &data->screen; struct screen *s = &data->screen;
@ -743,8 +744,8 @@ window_choose_key(struct window_pane *wp, unused struct client *c,
} }
void void
window_choose_write_line( window_choose_write_line(struct window_pane *wp, struct screen_write_ctx *ctx,
struct window_pane *wp, struct screen_write_ctx *ctx, u_int py) u_int py)
{ {
struct window_choose_mode_data *data = wp->modedata; struct window_choose_mode_data *data = wp->modedata;
struct window_choose_mode_item *item; struct window_choose_mode_item *item;
@ -821,7 +822,7 @@ window_choose_key_index(struct window_choose_mode_data *data, u_int idx)
} }
int 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" static const char keys[] = "0123456789"
"abcdefghijklmnopqrstuvwxyz" "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); mkey = mode_key_lookup(&data->mdata, *ptr, NULL);
if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER) if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
continue; continue;
if (key == *ptr) if (key == (key_code)*ptr)
return (idx); return (idx);
idx++; idx++;
} }

View File

@ -28,7 +28,7 @@ struct screen *window_clock_init(struct window_pane *);
void window_clock_free(struct window_pane *); void window_clock_free(struct window_pane *);
void window_clock_resize(struct window_pane *, u_int, u_int); void window_clock_resize(struct window_pane *, u_int, u_int);
void window_clock_key(struct window_pane *, struct client *, 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_timer_callback(int, short, void *);
void window_clock_draw_screen(struct window_pane *); 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 void
window_clock_key(struct window_pane *wp, unused struct client *c, 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); window_pane_reset_mode(wp);
} }

View File

@ -28,9 +28,9 @@ struct screen *window_copy_init(struct window_pane *);
void window_copy_free(struct window_pane *); void window_copy_free(struct window_pane *);
void window_copy_resize(struct window_pane *, u_int, u_int); void window_copy_resize(struct window_pane *, u_int, u_int);
void window_copy_key(struct window_pane *, struct client *, struct session *, void window_copy_key(struct window_pane *, struct client *, struct session *,
int, struct mouse_event *); key_code, struct mouse_event *);
int window_copy_key_input(struct window_pane *, int); int window_copy_key_input(struct window_pane *, key_code);
int window_copy_key_numeric_prefix(struct window_pane *, int); 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_selection(struct window_pane *, u_int);
void window_copy_redraw_lines(struct window_pane *, u_int, 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 void
window_copy_key(struct window_pane *wp, struct client *c, struct session *sess, 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; const char *word_separators;
struct window_copy_mode_data *data = wp->modedata; struct window_copy_mode_data *data = wp->modedata;
@ -800,7 +800,7 @@ input_off:
} }
int 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 window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen; struct screen *s = &data->screen;
@ -897,7 +897,7 @@ window_copy_key_input(struct window_pane *wp, int key)
} }
int 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 window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen; struct screen *s = &data->screen;

View File

@ -1102,7 +1102,7 @@ window_pane_reset_mode(struct window_pane *wp)
void void
window_pane_key(struct window_pane *wp, struct client *c, struct session *s, 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; struct window_pane *wp2;

View File

@ -40,11 +40,12 @@
* We accept any but always output the latter (it comes first in the table). * 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_match(const char *, const char *, size_t, size_t *,
int xterm_keys_modifiers(const char *, size_t, size_t *, u_int *); key_code *);
int xterm_keys_modifiers(const char *, size_t, size_t *, key_code *);
struct xterm_keys_entry { struct xterm_keys_entry {
int key; key_code key;
const char *template; const char *template;
}; };
@ -115,7 +116,7 @@ const struct xterm_keys_entry xterm_keys_table[] = {
*/ */
int int
xterm_keys_match(const char *template, const char *buf, size_t len, 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; size_t pos;
int retval; int retval;
@ -148,7 +149,8 @@ xterm_keys_match(const char *template, const char *buf, size_t len,
/* Find modifiers from buffer. */ /* Find modifiers from buffer. */
int 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; 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. * key), -1 for not found, 1 for partial match.
*/ */
int 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; const struct xterm_keys_entry *entry;
u_int i, modifiers; u_int i;
int matched; int matched;
key_code modifiers;
for (i = 0; i < nitems(xterm_keys_table); i++) { for (i = 0; i < nitems(xterm_keys_table); i++) {
entry = &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. */ /* Lookup a key number from the table. */
char * char *
xterm_keys_lookup(int key) xterm_keys_lookup(key_code key)
{ {
const struct xterm_keys_entry *entry; const struct xterm_keys_entry *entry;
u_int i; u_int i;
int modifiers; key_code modifiers;
char *out; char *out;
modifiers = 1; modifiers = 1;