version 1.71, 2020/04/07 13:38:30 |
version 1.72, 2020/05/16 16:30:59 |
|
|
|
|
static void input_key_mouse(struct window_pane *, struct mouse_event *); |
static void input_key_mouse(struct window_pane *, struct mouse_event *); |
|
|
struct input_key_ent { |
/* Entry in the key tree. */ |
key_code key; |
struct input_key_entry { |
const char *data; |
key_code key; |
|
const char *data; |
|
|
int flags; |
RB_ENTRY(input_key_entry) entry; |
#define INPUTKEY_KEYPAD 0x1 /* keypad key */ |
|
#define INPUTKEY_CURSOR 0x2 /* cursor key */ |
|
}; |
}; |
|
RB_HEAD(input_key_tree, input_key_entry); |
|
|
static const struct input_key_ent input_keys[] = { |
/* Tree of input keys. */ |
|
static int input_key_cmp(struct input_key_entry *, |
|
struct input_key_entry *); |
|
RB_GENERATE_STATIC(input_key_tree, input_key_entry, entry, input_key_cmp); |
|
struct input_key_tree input_key_tree = RB_INITIALIZER(&input_key_tree); |
|
|
|
/* List of default keys, the tree is built from this. */ |
|
static struct input_key_entry input_key_defaults[] = { |
/* Paste keys. */ |
/* Paste keys. */ |
{ KEYC_PASTE_START, "\033[200~", 0 }, |
{ .key = KEYC_PASTE_START, |
{ KEYC_PASTE_END, "\033[201~", 0 }, |
.data = "\033[200~" |
|
}, |
|
{ .key = KEYC_PASTE_END, |
|
.data = "\033[201~" |
|
}, |
|
|
/* Function keys. */ |
/* Function keys. */ |
{ KEYC_F1, "\033OP", 0 }, |
{ .key = KEYC_F1, |
{ KEYC_F2, "\033OQ", 0 }, |
.data = "\033OP" |
{ KEYC_F3, "\033OR", 0 }, |
}, |
{ KEYC_F4, "\033OS", 0 }, |
{ .key = KEYC_F2, |
{ KEYC_F5, "\033[15~", 0 }, |
.data = "\033OQ" |
{ KEYC_F6, "\033[17~", 0 }, |
}, |
{ KEYC_F7, "\033[18~", 0 }, |
{ .key = KEYC_F3, |
{ KEYC_F8, "\033[19~", 0 }, |
.data = "\033OR" |
{ KEYC_F9, "\033[20~", 0 }, |
}, |
{ KEYC_F10, "\033[21~", 0 }, |
{ .key = KEYC_F4, |
{ KEYC_F11, "\033[23~", 0 }, |
.data = "\033OS" |
{ KEYC_F12, "\033[24~", 0 }, |
}, |
{ KEYC_F1|KEYC_SHIFT, "\033[25~", 0 }, |
{ .key = KEYC_F5, |
{ KEYC_F2|KEYC_SHIFT, "\033[26~", 0 }, |
.data = "\033[15~" |
{ KEYC_F3|KEYC_SHIFT, "\033[28~", 0 }, |
}, |
{ KEYC_F4|KEYC_SHIFT, "\033[29~", 0 }, |
{ .key = KEYC_F6, |
{ KEYC_F5|KEYC_SHIFT, "\033[31~", 0 }, |
.data = "\033[17~" |
{ KEYC_F6|KEYC_SHIFT, "\033[32~", 0 }, |
}, |
{ KEYC_F7|KEYC_SHIFT, "\033[33~", 0 }, |
{ .key = KEYC_F7, |
{ KEYC_F8|KEYC_SHIFT, "\033[34~", 0 }, |
.data = "\033[18~" |
{ KEYC_IC, "\033[2~", 0 }, |
}, |
{ KEYC_DC, "\033[3~", 0 }, |
{ .key = KEYC_F8, |
{ KEYC_HOME, "\033[1~", 0 }, |
.data = "\033[19~" |
{ KEYC_END, "\033[4~", 0 }, |
}, |
{ KEYC_NPAGE, "\033[6~", 0 }, |
{ .key = KEYC_F9, |
{ KEYC_PPAGE, "\033[5~", 0 }, |
.data = "\033[20~" |
{ KEYC_BTAB, "\033[Z", 0 }, |
}, |
|
{ .key = KEYC_F10, |
|
.data = "\033[21~" |
|
}, |
|
{ .key = KEYC_F11, |
|
.data = "\033[23~" |
|
}, |
|
{ .key = KEYC_F12, |
|
.data = "\033[24~" |
|
}, |
|
{ .key = KEYC_F1|KEYC_SHIFT, |
|
.data = "\033[25~" |
|
}, |
|
{ .key = KEYC_F2|KEYC_SHIFT, |
|
.data = "\033[26~" |
|
}, |
|
{ .key = KEYC_F3|KEYC_SHIFT, |
|
.data = "\033[28~" |
|
}, |
|
{ .key = KEYC_F4|KEYC_SHIFT, |
|
.data = "\033[29~" |
|
}, |
|
{ .key = KEYC_F5|KEYC_SHIFT, |
|
.data = "\033[31~" |
|
}, |
|
{ .key = KEYC_F6|KEYC_SHIFT, |
|
.data = "\033[32~" |
|
}, |
|
{ .key = KEYC_F7|KEYC_SHIFT, |
|
.data = "\033[33~" |
|
}, |
|
{ .key = KEYC_F8|KEYC_SHIFT, |
|
.data = "\033[34~" |
|
}, |
|
{ .key = KEYC_IC, |
|
.data = "\033[2~" |
|
}, |
|
{ .key = KEYC_DC, |
|
.data = "\033[3~" |
|
}, |
|
{ .key = KEYC_HOME, |
|
.data = "\033[1~" |
|
}, |
|
{ .key = KEYC_END, |
|
.data = "\033[4~" |
|
}, |
|
{ .key = KEYC_NPAGE, |
|
.data = "\033[6~" |
|
}, |
|
{ .key = KEYC_PPAGE, |
|
.data = "\033[5~" |
|
}, |
|
{ .key = KEYC_BTAB, |
|
.data = "\033[Z" |
|
}, |
|
|
/* |
/* Arrow keys. */ |
* Arrow keys. Cursor versions must come first. The codes are toggled |
{ .key = KEYC_UP|KEYC_CURSOR, |
* between CSI and SS3 versions when ctrl is pressed. |
.data = "\033OA" |
*/ |
}, |
{ KEYC_UP|KEYC_CTRL, "\033[A", INPUTKEY_CURSOR }, |
{ .key = KEYC_DOWN|KEYC_CURSOR, |
{ KEYC_DOWN|KEYC_CTRL, "\033[B", INPUTKEY_CURSOR }, |
.data = "\033OB" |
{ KEYC_RIGHT|KEYC_CTRL, "\033[C", INPUTKEY_CURSOR }, |
}, |
{ KEYC_LEFT|KEYC_CTRL, "\033[D", INPUTKEY_CURSOR }, |
{ .key = KEYC_RIGHT|KEYC_CURSOR, |
|
.data = "\033OC" |
|
}, |
|
{ .key = KEYC_LEFT|KEYC_CURSOR, |
|
.data = "\033OD" |
|
}, |
|
{ .key = KEYC_UP, |
|
.data = "\033[A" |
|
}, |
|
{ .key = KEYC_DOWN, |
|
.data = "\033[B" |
|
}, |
|
{ .key = KEYC_RIGHT, |
|
.data = "\033[C" |
|
}, |
|
{ .key = KEYC_LEFT, |
|
.data = "\033[D" |
|
}, |
|
|
{ KEYC_UP, "\033OA", INPUTKEY_CURSOR }, |
/* Keypad keys. */ |
{ KEYC_DOWN, "\033OB", INPUTKEY_CURSOR }, |
{ .key = KEYC_KP_SLASH|KEYC_KEYPAD, |
{ KEYC_RIGHT, "\033OC", INPUTKEY_CURSOR }, |
.data = "\033Oo" |
{ KEYC_LEFT, "\033OD", INPUTKEY_CURSOR }, |
}, |
|
{ .key = KEYC_KP_STAR|KEYC_KEYPAD, |
|
.data = "\033Oj" |
|
}, |
|
{ .key = KEYC_KP_MINUS|KEYC_KEYPAD, |
|
.data = "\033Om" |
|
}, |
|
{ .key = KEYC_KP_SEVEN|KEYC_KEYPAD, |
|
.data = "\033Ow" |
|
}, |
|
{ .key = KEYC_KP_EIGHT|KEYC_KEYPAD, |
|
.data = "\033Ox" |
|
}, |
|
{ .key = KEYC_KP_NINE|KEYC_KEYPAD, |
|
.data = "\033Oy" |
|
}, |
|
{ .key = KEYC_KP_PLUS|KEYC_KEYPAD, |
|
.data = "\033Ok" |
|
}, |
|
{ .key = KEYC_KP_FOUR|KEYC_KEYPAD, |
|
.data = "\033Ot" |
|
}, |
|
{ .key = KEYC_KP_FIVE|KEYC_KEYPAD, |
|
.data = "\033Ou" |
|
}, |
|
{ .key = KEYC_KP_SIX|KEYC_KEYPAD, |
|
.data = "\033Ov" |
|
}, |
|
{ .key = KEYC_KP_ONE|KEYC_KEYPAD, |
|
.data = "\033Oq" |
|
}, |
|
{ .key = KEYC_KP_TWO|KEYC_KEYPAD, |
|
.data = "\033Or" |
|
}, |
|
{ .key = KEYC_KP_THREE|KEYC_KEYPAD, |
|
.data = "\033Os" |
|
}, |
|
{ .key = KEYC_KP_ENTER|KEYC_KEYPAD, |
|
.data = "\033OM" |
|
}, |
|
{ .key = KEYC_KP_ZERO|KEYC_KEYPAD, |
|
.data = "\033Op" |
|
}, |
|
{ .key = KEYC_KP_PERIOD|KEYC_KEYPAD, |
|
.data = "\033On" |
|
}, |
|
{ .key = KEYC_KP_SLASH, |
|
.data = "/" |
|
}, |
|
{ .key = KEYC_KP_STAR, |
|
.data = "*" |
|
}, |
|
{ .key = KEYC_KP_MINUS, |
|
.data = "-" |
|
}, |
|
{ .key = KEYC_KP_SEVEN, |
|
.data = "7" |
|
}, |
|
{ .key = KEYC_KP_EIGHT, |
|
.data = "8" |
|
}, |
|
{ .key = KEYC_KP_NINE, |
|
.data = "9" |
|
}, |
|
{ .key = KEYC_KP_PLUS, |
|
.data = "+" |
|
}, |
|
{ .key = KEYC_KP_FOUR, |
|
.data = "4" |
|
}, |
|
{ .key = KEYC_KP_FIVE, |
|
.data = "5" |
|
}, |
|
{ .key = KEYC_KP_SIX, |
|
.data = "6" |
|
}, |
|
{ .key = KEYC_KP_ONE, |
|
.data = "1" |
|
}, |
|
{ .key = KEYC_KP_TWO, |
|
.data = "2" |
|
}, |
|
{ .key = KEYC_KP_THREE, |
|
.data = "3" |
|
}, |
|
{ .key = KEYC_KP_ENTER, |
|
.data = "\n" |
|
}, |
|
{ .key = KEYC_KP_ZERO, |
|
.data = "0" |
|
}, |
|
{ .key = KEYC_KP_PERIOD, |
|
.data = "." |
|
}, |
|
|
{ KEYC_UP|KEYC_CTRL, "\033OA", 0 }, |
/* Keys with an embedded modifier. */ |
{ KEYC_DOWN|KEYC_CTRL, "\033OB", 0 }, |
{ .key = KEYC_F1|KEYC_XTERM, |
{ KEYC_RIGHT|KEYC_CTRL, "\033OC", 0 }, |
.data = "\033[1;_P" |
{ KEYC_LEFT|KEYC_CTRL, "\033OD", 0 }, |
}, |
|
{ .key = KEYC_F2|KEYC_XTERM, |
{ KEYC_UP, "\033[A", 0 }, |
.data = "\033[1;_Q" |
{ KEYC_DOWN, "\033[B", 0 }, |
}, |
{ KEYC_RIGHT, "\033[C", 0 }, |
{ .key = KEYC_F3|KEYC_XTERM, |
{ KEYC_LEFT, "\033[D", 0 }, |
.data = "\033[1;_R" |
|
}, |
/* Keypad keys. Keypad versions must come first. */ |
{ .key = KEYC_F4|KEYC_XTERM, |
{ KEYC_KP_SLASH, "\033Oo", INPUTKEY_KEYPAD }, |
.data = "\033[1;_S" |
{ KEYC_KP_STAR, "\033Oj", INPUTKEY_KEYPAD }, |
}, |
{ KEYC_KP_MINUS, "\033Om", INPUTKEY_KEYPAD }, |
{ .key = KEYC_F5|KEYC_XTERM, |
{ KEYC_KP_SEVEN, "\033Ow", INPUTKEY_KEYPAD }, |
.data = "\033[15;_~" |
{ KEYC_KP_EIGHT, "\033Ox", INPUTKEY_KEYPAD }, |
}, |
{ KEYC_KP_NINE, "\033Oy", INPUTKEY_KEYPAD }, |
{ .key = KEYC_F6|KEYC_XTERM, |
{ KEYC_KP_PLUS, "\033Ok", INPUTKEY_KEYPAD }, |
.data = "\033[17;_~" |
{ KEYC_KP_FOUR, "\033Ot", INPUTKEY_KEYPAD }, |
}, |
{ KEYC_KP_FIVE, "\033Ou", INPUTKEY_KEYPAD }, |
{ .key = KEYC_F7|KEYC_XTERM, |
{ KEYC_KP_SIX, "\033Ov", INPUTKEY_KEYPAD }, |
.data = "\033[18;_~" |
{ KEYC_KP_ONE, "\033Oq", INPUTKEY_KEYPAD }, |
}, |
{ KEYC_KP_TWO, "\033Or", INPUTKEY_KEYPAD }, |
{ .key = KEYC_F8|KEYC_XTERM, |
{ KEYC_KP_THREE, "\033Os", INPUTKEY_KEYPAD }, |
.data = "\033[19;_~" |
{ KEYC_KP_ENTER, "\033OM", INPUTKEY_KEYPAD }, |
}, |
{ KEYC_KP_ZERO, "\033Op", INPUTKEY_KEYPAD }, |
{ .key = KEYC_F9|KEYC_XTERM, |
{ KEYC_KP_PERIOD, "\033On", INPUTKEY_KEYPAD }, |
.data = "\033[20;_~" |
|
}, |
{ KEYC_KP_SLASH, "/", 0 }, |
{ .key = KEYC_F10|KEYC_XTERM, |
{ KEYC_KP_STAR, "*", 0 }, |
.data = "\033[21;_~" |
{ KEYC_KP_MINUS, "-", 0 }, |
}, |
{ KEYC_KP_SEVEN, "7", 0 }, |
{ .key = KEYC_F11|KEYC_XTERM, |
{ KEYC_KP_EIGHT, "8", 0 }, |
.data = "\033[23;_~" |
{ KEYC_KP_NINE, "9", 0 }, |
}, |
{ KEYC_KP_PLUS, "+", 0 }, |
{ .key = KEYC_F12|KEYC_XTERM, |
{ KEYC_KP_FOUR, "4", 0 }, |
.data = "\033[24;_~" |
{ KEYC_KP_FIVE, "5", 0 }, |
}, |
{ KEYC_KP_SIX, "6", 0 }, |
{ .key = KEYC_UP|KEYC_XTERM, |
{ KEYC_KP_ONE, "1", 0 }, |
.data = "\033[1;_A" |
{ KEYC_KP_TWO, "2", 0 }, |
}, |
{ KEYC_KP_THREE, "3", 0 }, |
{ .key = KEYC_DOWN|KEYC_XTERM, |
{ KEYC_KP_ENTER, "\n", 0 }, |
.data = "\033[1;_B" |
{ KEYC_KP_ZERO, "0", 0 }, |
}, |
{ KEYC_KP_PERIOD, ".", 0 }, |
{ .key = KEYC_RIGHT|KEYC_XTERM, |
|
.data = "\033[1;_C" |
|
}, |
|
{ .key = KEYC_LEFT|KEYC_XTERM, |
|
.data = "\033[1;_D" |
|
}, |
|
{ .key = KEYC_HOME|KEYC_XTERM, |
|
.data = "\033[1;_H" |
|
}, |
|
{ .key = KEYC_END|KEYC_XTERM, |
|
.data = "\033[1;_F" |
|
}, |
|
{ .key = KEYC_PPAGE|KEYC_XTERM, |
|
.data = "\033[5;_~" |
|
}, |
|
{ .key = KEYC_NPAGE|KEYC_XTERM, |
|
.data = "\033[6;_~" |
|
}, |
|
{ .key = KEYC_IC|KEYC_XTERM, |
|
.data = "\033[2;_~" |
|
}, |
|
{ .key = KEYC_DC|KEYC_XTERM, |
|
.data = "\033[3;_~" } |
}; |
}; |
|
static const key_code input_key_modifiers[] = { |
|
0, |
|
0, |
|
KEYC_SHIFT|KEYC_XTERM, |
|
KEYC_ESCAPE|KEYC_XTERM, |
|
KEYC_SHIFT|KEYC_ESCAPE|KEYC_XTERM, |
|
KEYC_CTRL|KEYC_XTERM, |
|
KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM, |
|
KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM, |
|
KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM |
|
}; |
|
|
|
/* Input key comparison function. */ |
|
static int |
|
input_key_cmp(struct input_key_entry *ike1, struct input_key_entry *ike2) |
|
{ |
|
if (ike1->key < ike2->key) |
|
return (-1); |
|
if (ike1->key > ike2->key) |
|
return (1); |
|
return (0); |
|
} |
|
|
/* Split a character into two UTF-8 bytes. */ |
/* Split a character into two UTF-8 bytes. */ |
static size_t |
static size_t |
input_split2(u_int c, u_char *dst) |
input_key_split2(u_int c, u_char *dst) |
{ |
{ |
if (c > 0x7f) { |
if (c > 0x7f) { |
dst[0] = (c >> 6) | 0xc0; |
dst[0] = (c >> 6) | 0xc0; |
|
|
return (1); |
return (1); |
} |
} |
|
|
|
/* Build input key tree. */ |
|
void |
|
input_key_build(void) |
|
{ |
|
struct input_key_entry *ike, *new; |
|
u_int i, j; |
|
char *data; |
|
|
|
for (i = 0; i < nitems(input_key_defaults); i++) { |
|
ike = &input_key_defaults[i]; |
|
if (~ike->key & KEYC_XTERM) { |
|
RB_INSERT(input_key_tree, &input_key_tree, ike); |
|
continue; |
|
} |
|
|
|
for (j = 2; j < nitems(input_key_modifiers); j++) { |
|
data = xstrdup(ike->data); |
|
data[strcspn(data, "_")] = '0' + j; |
|
|
|
new = xcalloc(1, sizeof *new); |
|
new->key = ike->key|input_key_modifiers[j]; |
|
new->data = data; |
|
RB_INSERT(input_key_tree, &input_key_tree, new); |
|
} |
|
} |
|
|
|
RB_FOREACH(ike, input_key_tree, &input_key_tree) { |
|
log_debug("%s: 0x%llx (%s) is %s", __func__, ike->key, |
|
key_string_lookup_key(ike->key), ike->data); |
|
} |
|
} |
|
|
/* Translate a key code into an output key sequence for a pane. */ |
/* Translate a key code into an output key sequence for a pane. */ |
int |
int |
input_key_pane(struct window_pane *wp, key_code key, struct mouse_event *m) |
input_key_pane(struct window_pane *wp, key_code key, struct mouse_event *m) |
{ |
{ |
log_debug("writing key 0x%llx (%s) to %%%u", key, |
if (log_get_level() != 0) { |
key_string_lookup_key(key), wp->id); |
log_debug("writing key 0x%llx (%s) to %%%u", key, |
|
key_string_lookup_key(key), wp->id); |
|
} |
|
|
if (KEYC_IS_MOUSE(key)) { |
if (KEYC_IS_MOUSE(key)) { |
if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id) |
if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id) |
input_key_mouse(wp, m); |
input_key_mouse(wp, m); |
return (0); |
return (0); |
} |
} |
return (input_key(wp, wp->screen, wp->event, key)); |
return (input_key(wp->screen, wp->event, key)); |
} |
} |
|
|
/* Translate a key code into an output key sequence. */ |
/* Translate a key code into an output key sequence. */ |
int |
int |
input_key(struct window_pane *wp, struct screen *s, struct bufferevent *bev, |
input_key(struct screen *s, struct bufferevent *bev, key_code key) |
key_code key) |
|
{ |
{ |
const struct input_key_ent *ike; |
struct input_key_entry *ike, entry; |
u_int i; |
size_t datalen; |
size_t dlen; |
key_code justkey, newkey; |
char *out; |
struct utf8_data ud; |
key_code justkey, newkey; |
|
struct utf8_data ud; |
|
|
|
/* Mouse keys need a pane. */ |
/* Mouse keys need a pane. */ |
if (KEYC_IS_MOUSE(key)) |
if (KEYC_IS_MOUSE(key)) |
|
|
} |
} |
|
|
/* |
/* |
* Then try to look this up as an xterm key, if the flag to output them |
* Look up in the tree. If not in application keypad or cursor mode, |
* is set. |
* remove the flags from the key. |
*/ |
*/ |
if (wp == NULL || options_get_number(wp->window->options, "xterm-keys")) { |
if (~s->mode & MODE_KKEYPAD) |
if ((out = xterm_keys_lookup(key)) != NULL) { |
key &= ~KEYC_KEYPAD; |
bufferevent_write(bev, out, strlen(out)); |
if (~s->mode & MODE_KCURSOR) |
free(out); |
key &= ~KEYC_CURSOR; |
return (0); |
entry.key = key; |
} |
if ((ike = RB_FIND(input_key_tree, &input_key_tree, &entry)) == NULL) { |
} |
|
key &= ~KEYC_XTERM; |
|
|
|
/* Otherwise look the key up in the table. */ |
|
for (i = 0; i < nitems(input_keys); i++) { |
|
ike = &input_keys[i]; |
|
|
|
if ((ike->flags & INPUTKEY_KEYPAD) && (~s->mode & MODE_KKEYPAD)) |
|
continue; |
|
if ((ike->flags & INPUTKEY_CURSOR) && (~s->mode & MODE_KCURSOR)) |
|
continue; |
|
|
|
if ((key & KEYC_ESCAPE) && (ike->key | KEYC_ESCAPE) == key) |
|
break; |
|
if (ike->key == key) |
|
break; |
|
} |
|
if (i == nitems(input_keys)) { |
|
log_debug("key 0x%llx missing", key); |
log_debug("key 0x%llx missing", key); |
return (-1); |
return (-1); |
} |
} |
dlen = strlen(ike->data); |
datalen = strlen(ike->data); |
log_debug("found key 0x%llx: \"%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) |
bufferevent_write(bev, "\033", 1); |
bufferevent_write(bev, "\033", 1); |
bufferevent_write(bev, ike->data, dlen); |
bufferevent_write(bev, ike->data, datalen); |
return (0); |
return (0); |
} |
} |
|
|
|
|
if (m->b > 0x7ff - 32 || x > 0x7ff - 33 || y > 0x7ff - 33) |
if (m->b > 0x7ff - 32 || x > 0x7ff - 33 || y > 0x7ff - 33) |
return (0); |
return (0); |
len = xsnprintf(buf, sizeof buf, "\033[M"); |
len = xsnprintf(buf, sizeof buf, "\033[M"); |
len += input_split2(m->b + 32, &buf[len]); |
len += input_key_split2(m->b + 32, &buf[len]); |
len += input_split2(x + 33, &buf[len]); |
len += input_key_split2(x + 33, &buf[len]); |
len += input_split2(y + 33, &buf[len]); |
len += input_key_split2(y + 33, &buf[len]); |
} else { |
} else { |
if (m->b > 223) |
if (m->b > 223) |
return (0); |
return (0); |