summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornicm <nicm>2020-05-16 16:44:54 +0000
committernicm <nicm>2020-05-16 16:44:54 +0000
commit0ab82d95314e7a26a48452c77ad710f3aff97dd7 (patch)
tree8a7439d2a3007bb7de92f6c8c801bb5303754fae
parent292b335ca5b594729cf9ff79f0f4273c725537a4 (diff)
Add a terminal feature for enable/disable extended keys (supported by
xterm and mintty) and add an option to make tmux send it. Only forward extended keys if the application has requested them, even though we use the CSI u sequence and xterm uses CSI 27 ~ - this is what mintty does as well.
-rw-r--r--input-keys.c571
-rw-r--r--input.c19
-rw-r--r--options-table.c13
-rw-r--r--tmux.118
-rw-r--r--tty-features.c17
-rw-r--r--tty-keys.c484
-rw-r--r--tty-term.c2
-rw-r--r--tty.c21
8 files changed, 809 insertions, 336 deletions
diff --git a/input-keys.c b/input-keys.c
index e9c595b4..19134c1a 100644
--- a/input-keys.c
+++ b/input-keys.c
@@ -33,112 +33,340 @@
static void input_key_mouse(struct window_pane *, struct mouse_event *);
-struct input_key_ent {
- key_code key;
- const char *data;
+/* Entry in the key tree. */
+struct input_key_entry {
+ key_code key;
+ const char *data;
- int flags;
-#define INPUTKEY_KEYPAD 0x1 /* keypad key */
-#define INPUTKEY_CURSOR 0x2 /* cursor key */
+ RB_ENTRY(input_key_entry) entry;
};
+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. */
- { KEYC_PASTE_START, "\033[200~", 0 },
- { KEYC_PASTE_END, "\033[201~", 0 },
+ { .key = KEYC_PASTE_START,
+ .data = "\033[200~"
+ },
+ { .key = KEYC_PASTE_END,
+ .data = "\033[201~"
+ },
/* Function keys. */
- { KEYC_F1, "\033OP", 0 },
- { KEYC_F2, "\033OQ", 0 },
- { KEYC_F3, "\033OR", 0 },
- { KEYC_F4, "\033OS", 0 },
- { KEYC_F5, "\033[15~", 0 },
- { KEYC_F6, "\033[17~", 0 },
- { KEYC_F7, "\033[18~", 0 },
- { KEYC_F8, "\033[19~", 0 },
- { KEYC_F9, "\033[20~", 0 },
- { KEYC_F10, "\033[21~", 0 },
- { KEYC_F11, "\033[23~", 0 },
- { KEYC_F12, "\033[24~", 0 },
- { KEYC_F1|KEYC_SHIFT, "\033[25~", 0 },
- { KEYC_F2|KEYC_SHIFT, "\033[26~", 0 },
- { KEYC_F3|KEYC_SHIFT, "\033[28~", 0 },
- { KEYC_F4|KEYC_SHIFT, "\033[29~", 0 },
- { KEYC_F5|KEYC_SHIFT, "\033[31~", 0 },
- { KEYC_F6|KEYC_SHIFT, "\033[32~", 0 },
- { KEYC_F7|KEYC_SHIFT, "\033[33~", 0 },
- { KEYC_F8|KEYC_SHIFT, "\033[34~", 0 },
- { KEYC_IC, "\033[2~", 0 },
- { KEYC_DC, "\033[3~", 0 },
- { KEYC_HOME, "\033[1~", 0 },
- { KEYC_END, "\033[4~", 0 },
- { KEYC_NPAGE, "\033[6~", 0 },
- { KEYC_PPAGE, "\033[5~", 0 },
- { KEYC_BTAB, "\033[Z", 0 },
-
- /*
- * Arrow keys. Cursor versions must come first. The codes are toggled
- * between CSI and SS3 versions when ctrl is pressed.
- */
- { KEYC_UP|KEYC_CTRL, "\033[A", INPUTKEY_CURSOR },
- { KEYC_DOWN|KEYC_CTRL, "\033[B", INPUTKEY_CURSOR },
- { KEYC_RIGHT|KEYC_CTRL, "\033[C", INPUTKEY_CURSOR },
- { KEYC_LEFT|KEYC_CTRL, "\033[D", INPUTKEY_CURSOR },
-
- { KEYC_UP, "\033OA", INPUTKEY_CURSOR },
- { KEYC_DOWN, "\033OB", INPUTKEY_CURSOR },
- { KEYC_RIGHT, "\033OC", INPUTKEY_CURSOR },
- { KEYC_LEFT, "\033OD", INPUTKEY_CURSOR },
-
- { KEYC_UP|KEYC_CTRL, "\033OA", 0 },
- { KEYC_DOWN|KEYC_CTRL, "\033OB", 0 },
- { KEYC_RIGHT|KEYC_CTRL, "\033OC", 0 },
- { KEYC_LEFT|KEYC_CTRL, "\033OD", 0 },
-
- { KEYC_UP, "\033[A", 0 },
- { KEYC_DOWN, "\033[B", 0 },
- { KEYC_RIGHT, "\033[C", 0 },
- { KEYC_LEFT, "\033[D", 0 },
-
- /* Keypad keys. Keypad versions must come first. */
- { KEYC_KP_SLASH, "\033Oo", INPUTKEY_KEYPAD },
- { KEYC_KP_STAR, "\033Oj", INPUTKEY_KEYPAD },
- { KEYC_KP_MINUS, "\033Om", INPUTKEY_KEYPAD },
- { KEYC_KP_SEVEN, "\033Ow", INPUTKEY_KEYPAD },
- { KEYC_KP_EIGHT, "\033Ox", INPUTKEY_KEYPAD },
- { KEYC_KP_NINE, "\033Oy", INPUTKEY_KEYPAD },
- { KEYC_KP_PLUS, "\033Ok", INPUTKEY_KEYPAD },
- { KEYC_KP_FOUR, "\033Ot", INPUTKEY_KEYPAD },
- { KEYC_KP_FIVE, "\033Ou", INPUTKEY_KEYPAD },
- { KEYC_KP_SIX, "\033Ov", INPUTKEY_KEYPAD },
- { KEYC_KP_ONE, "\033Oq", INPUTKEY_KEYPAD },
- { KEYC_KP_TWO, "\033Or", INPUTKEY_KEYPAD },
- { KEYC_KP_THREE, "\033Os", INPUTKEY_KEYPAD },
- { KEYC_KP_ENTER, "\033OM", INPUTKEY_KEYPAD },
- { KEYC_KP_ZERO, "\033Op", INPUTKEY_KEYPAD },
- { KEYC_KP_PERIOD, "\033On", INPUTKEY_KEYPAD },
-
- { KEYC_KP_SLASH, "/", 0 },
- { KEYC_KP_STAR, "*", 0 },
- { KEYC_KP_MINUS, "-", 0 },
- { KEYC_KP_SEVEN, "7", 0 },
- { KEYC_KP_EIGHT, "8", 0 },
- { KEYC_KP_NINE, "9", 0 },
- { KEYC_KP_PLUS, "+", 0 },
- { KEYC_KP_FOUR, "4", 0 },
- { KEYC_KP_FIVE, "5", 0 },
- { KEYC_KP_SIX, "6", 0 },
- { KEYC_KP_ONE, "1", 0 },
- { KEYC_KP_TWO, "2", 0 },
- { KEYC_KP_THREE, "3", 0 },
- { KEYC_KP_ENTER, "\n", 0 },
- { KEYC_KP_ZERO, "0", 0 },
- { KEYC_KP_PERIOD, ".", 0 },
+ { .key = KEYC_F1,
+ .data = "\033OP"
+ },
+ { .key = KEYC_F2,
+ .data = "\033OQ"
+ },
+ { .key = KEYC_F3,
+ .data = "\033OR"
+ },
+ { .key = KEYC_F4,
+ .data = "\033OS"
+ },
+ { .key = KEYC_F5,
+ .data = "\033[15~"
+ },
+ { .key = KEYC_F6,
+ .data = "\033[17~"
+ },
+ { .key = KEYC_F7,
+ .data = "\033[18~"
+ },
+ { .key = KEYC_F8,
+ .data = "\033[19~"
+ },
+ { .key = KEYC_F9,
+ .data = "\033[20~"
+ },
+ { .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. */
+ { .key = KEYC_UP|KEYC_CURSOR,
+ .data = "\033OA"
+ },
+ { .key = KEYC_DOWN|KEYC_CURSOR,
+ .data = "\033OB"
+ },
+ { .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"
+ },
+
+ /* Keypad keys. */
+ { .key = KEYC_KP_SLASH|KEYC_KEYPAD,
+ .data = "\033Oo"
+ },
+ { .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 = "."
+ },
+
+ /* Keys with an embedded modifier. */
+ { .key = KEYC_F1|KEYC_BUILD_MODIFIERS,
+ .data = "\033[1;_P"
+ },
+ { .key = KEYC_F2|KEYC_BUILD_MODIFIERS,
+ .data = "\033[1;_Q"
+ },
+ { .key = KEYC_F3|KEYC_BUILD_MODIFIERS,
+ .data = "\033[1;_R"
+ },
+ { .key = KEYC_F4|KEYC_BUILD_MODIFIERS,
+ .data = "\033[1;_S"
+ },
+ { .key = KEYC_F5|KEYC_BUILD_MODIFIERS,
+ .data = "\033[15;_~"
+ },
+ { .key = KEYC_F6|KEYC_BUILD_MODIFIERS,
+ .data = "\033[17;_~"
+ },
+ { .key = KEYC_F7|KEYC_BUILD_MODIFIERS,
+ .data = "\033[18;_~"
+ },
+ { .key = KEYC_F8|KEYC_BUILD_MODIFIERS,
+ .data = "\033[19;_~"
+ },
+ { .key = KEYC_F9|KEYC_BUILD_MODIFIERS,
+ .data = "\033[20;_~"
+ },
+ { .key = KEYC_F10|KEYC_BUILD_MODIFIERS,
+ .data = "\033[21;_~"
+ },
+ { .key = KEYC_F11|KEYC_BUILD_MODIFIERS,
+ .data = "\033[23;_~"
+ },
+ { .key = KEYC_F12|KEYC_BUILD_MODIFIERS,
+ .data = "\033[24;_~"
+ },
+ { .key = KEYC_UP|KEYC_BUILD_MODIFIERS,
+ .data = "\033[1;_A"
+ },
+ { .key = KEYC_DOWN|KEYC_BUILD_MODIFIERS,
+ .data = "\033[1;_B"
+ },
+ { .key = KEYC_RIGHT|KEYC_BUILD_MODIFIERS,
+ .data = "\033[1;_C"
+ },
+ { .key = KEYC_LEFT|KEYC_BUILD_MODIFIERS,
+ .data = "\033[1;_D"
+ },
+ { .key = KEYC_HOME|KEYC_BUILD_MODIFIERS,
+ .data = "\033[1;_H"
+ },
+ { .key = KEYC_END|KEYC_BUILD_MODIFIERS,
+ .data = "\033[1;_F"
+ },
+ { .key = KEYC_PPAGE|KEYC_BUILD_MODIFIERS,
+ .data = "\033[5;_~"
+ },
+ { .key = KEYC_NPAGE|KEYC_BUILD_MODIFIERS,
+ .data = "\033[6;_~"
+ },
+ { .key = KEYC_IC|KEYC_BUILD_MODIFIERS,
+ .data = "\033[2;_~"
+ },
+ { .key = KEYC_DC|KEYC_BUILD_MODIFIERS,
+ .data = "\033[3;_~" }
+};
+static const key_code input_key_modifiers[] = {
+ 0,
+ 0,
+ KEYC_SHIFT,
+ KEYC_META|KEYC_IMPLIED_META,
+ KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META,
+ KEYC_CTRL,
+ KEYC_SHIFT|KEYC_CTRL,
+ KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL,
+ KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL
};
+/* 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);
+}
+
+/* Look for key in tree. */
+static struct input_key_entry *
+input_key_get (key_code key)
+{
+ struct input_key_entry entry = { .key = key };
+
+ return (RB_FIND(input_key_tree, &input_key_tree, &entry));
+}
+
/* Split a character into two UTF-8 bytes. */
static size_t
-input_split2(u_int c, u_char *dst)
+input_key_split2(u_int c, u_char *dst)
{
if (c > 0x7f) {
dst[0] = (c >> 6) | 0xc0;
@@ -149,32 +377,65 @@ input_split2(u_int c, u_char *dst)
return (1);
}
+/* Build input key tree. */
+void
+input_key_build(void)
+{
+ struct input_key_entry *ike, *new;
+ u_int i, j;
+ char *data;
+ key_code key;
+
+ for (i = 0; i < nitems(input_key_defaults); i++) {
+ ike = &input_key_defaults[i];
+ if (~ike->key & KEYC_BUILD_MODIFIERS) {
+ RB_INSERT(input_key_tree, &input_key_tree, ike);
+ continue;
+ }
+
+ for (j = 2; j < nitems(input_key_modifiers); j++) {
+ key = (ike->key & ~KEYC_BUILD_MODIFIERS);
+ data = xstrdup(ike->data);
+ data[strcspn(data, "_")] = '0' + j;
+
+ new = xcalloc(1, sizeof *new);
+ new->key = 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, 1), ike->data);
+ }
+}
+
/* Translate a key code into an output key sequence for a pane. */
int
input_key_pane(struct window_pane *wp, key_code key, struct mouse_event *m)
{
- log_debug("writing key 0x%llx (%s) to %%%u", key,
- key_string_lookup_key(key), wp->id);
+ if (log_get_level() != 0) {
+ log_debug("writing key 0x%llx (%s) to %%%u", key,
+ key_string_lookup_key(key, 1), wp->id);
+ }
if (KEYC_IS_MOUSE(key)) {
if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id)
input_key_mouse(wp, m);
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. */
int
-input_key(struct window_pane *wp, struct screen *s, struct bufferevent *bev,
- key_code key)
+input_key(struct screen *s, struct bufferevent *bev, key_code key)
{
- const struct input_key_ent *ike;
- u_int i;
- size_t dlen;
- char *out;
- key_code justkey, newkey;
- struct utf8_data ud;
+ struct input_key_entry *ike;
+ key_code justkey, newkey, outkey;
+ struct utf8_data ud;
+ char tmp[64], modifier;
/* Mouse keys need a pane. */
if (KEYC_IS_MOUSE(key))
@@ -192,16 +453,16 @@ input_key(struct window_pane *wp, struct screen *s, struct bufferevent *bev,
newkey = options_get_number(global_options, "backspace");
if (newkey >= 0x7f)
newkey = '\177';
- key = newkey|(key & KEYC_MASK_MOD);
+ key = newkey|(key & (KEYC_MASK_MODIFIERS|KEYC_MASK_FLAGS));
}
/*
* If this is a normal 7-bit key, just send it, with a leading escape
* if necessary. If it is a UTF-8 key, split it and send it.
*/
- justkey = (key & ~(KEYC_XTERM|KEYC_ESCAPE));
+ justkey = (key & ~(KEYC_META|KEYC_IMPLIED_META));
if (justkey <= 0x7f) {
- if (key & KEYC_ESCAPE)
+ if (key & KEYC_META)
bufferevent_write(bev, "\033", 1);
ud.data[0] = justkey;
bufferevent_write(bev, &ud.data[0], 1);
@@ -210,51 +471,69 @@ input_key(struct window_pane *wp, struct screen *s, struct bufferevent *bev,
if (justkey > 0x7f && justkey < KEYC_BASE) {
if (utf8_split(justkey, &ud) != UTF8_DONE)
return (-1);
- if (key & KEYC_ESCAPE)
+ if (key & KEYC_META)
bufferevent_write(bev, "\033", 1);
bufferevent_write(bev, ud.data, ud.size);
return (0);
}
/*
- * Then try to look this up as an xterm key, if the flag to output them
- * is set.
+ * Look up in the tree. If not in application keypad or cursor mode,
+ * remove the flags from the key.
*/
- if (wp == NULL || options_get_number(wp->window->options, "xterm-keys")) {
- if ((out = xterm_keys_lookup(key)) != NULL) {
- bufferevent_write(bev, out, strlen(out));
- free(out);
- return (0);
- }
+ if (~s->mode & MODE_KKEYPAD)
+ key &= ~KEYC_KEYPAD;
+ if (~s->mode & MODE_KCURSOR)
+ key &= ~KEYC_CURSOR;
+ ike = input_key_get(key);
+ if (ike == NULL && (key & KEYC_META) && (~key & KEYC_IMPLIED_META))
+ ike = input_key_get(key & ~KEYC_META);
+ if (ike != NULL) {
+ log_debug("found key 0x%llx: \"%s\"", key, ike->data);
+ if (key & KEYC_META && (~key & KEYC_IMPLIED_META))
+ bufferevent_write(bev, "\033", 1);
+ bufferevent_write(bev, ike->data, strlen(ike->data));
+ return (0);
}
- 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;
+ /* No builtin key sequence; construct an extended key sequence. */
+ if (~s->mode & MODE_KEXTENDED) {
+ if ((key & KEYC_MASK_MODIFIERS) == KEYC_CTRL &&
+ (key & KEYC_MASK_KEY) < KEYC_BASE)
+ return (input_key(s, bev, key & ~KEYC_CTRL));
+ goto missing;
}
- if (i == nitems(input_keys)) {
- log_debug("key 0x%llx missing", key);
- return (-1);
+ outkey = (key & KEYC_MASK_KEY);
+ switch (key & KEYC_MASK_MODIFIERS) {
+ case KEYC_SHIFT:
+ modifier = '2';
+ break;
+ case KEYC_META:
+ modifier = '3';
+ break;
+ case KEYC_SHIFT|KEYC_META:
+ modifier = '4';
+ break;
+ case KEYC_CTRL:
+ modifier = '5';
+ break;
+ case KEYC_SHIFT|KEYC_CTRL:
+ modifier = '6';
+ break;
+ case KEYC_META|KEYC_CTRL:
+ modifier = '7';
+ break;
+ case KEYC_SHIFT|KEYC_META|KEYC_CTRL:
+ modifier = '8';
+ break;
}
- dlen = strlen(ike->data);
- log_debug("found key 0x%llx: \"%s\"", key, ike->data);
-
- /* Prefix a \033 for escape. */
- if (key & KEYC_ESCAPE)
- bufferevent_write(bev, "\033", 1);
- bufferevent_write(bev, ike->data, dlen);
+ xsnprintf(tmp, sizeof tmp, "\033[%llu;%cu", outkey, modifier);
+ bufferevent_write(bev, tmp, strlen(tmp));
return (0);
+
+missing:
+ log_debug("key 0x%llx missing", key);
+ return (-1);
}
/* Get mouse event string. */
@@ -309,9 +588,9 @@ input_key_get_mouse(struct screen *s, struct mouse_event *m, u_int x, u_int y,
if (m->b > 0x7ff - 32 || x > 0x7ff - 33 || y > 0x7ff - 33)
return (0);
len = xsnprintf(buf, sizeof buf, "\033[M");
- len += input_split2(m->b + 32, &buf[len]);
- len += input_split2(x + 33, &buf[len]);
- len += input_split2(y + 33, &buf[len]);
+ len += input_key_split2(m->b + 32, &buf[len]);
+ len += input_key_split2(x + 33, &buf[len]);
+ len += input_key_split2(y + 33, &buf[len]);
} else {
if (m->b > 223)
return (0);
diff --git a/input.c b/input.c
index 03b81c69..44b1b948 100644
--- a/input.c
+++ b/input.c
@@ -241,6 +241,8 @@ enum input_csi_type {
INPUT_CSI_HPA,
INPUT_CSI_ICH,
INPUT_CSI_IL,
+ INPUT_CSI_MODOFF,
+ INPUT_CSI_MODSET,
INPUT_CSI_RCP,
INPUT_CSI_REP,
INPUT_CSI_RM,
@@ -289,7 +291,9 @@ static const struct input_table_entry input_csi_table[] = {
{ 'l', "", INPUT_CSI_RM },
{ 'l', "?", INPUT_CSI_RM_PRIVATE },
{ 'm', "", INPUT_CSI_SGR },
+ { 'm', ">", INPUT_CSI_MODSET },
{ 'n', "", INPUT_CSI_DSR },
+ { 'n', ">", INPUT_CSI_MODOFF },
{ 'q', " ", INPUT_CSI_DECSCUSR },
{ 'q', ">", INPUT_CSI_XDA },
{ 'r', "", INPUT_CSI_DECSTBM },
@@ -1380,6 +1384,19 @@ input_csi_dispatch(struct input_ctx *ictx)
if (n != -1 && m != -1)
screen_write_cursormove(sctx, m - 1, n - 1, 1);
break;
+ case INPUT_CSI_MODSET:
+ n = input_get(ictx, 0, 0, 0);
+ m = input_get(ictx, 1, 0, 0);
+ if (n == 0 || (n == 4 && m == 0))
+ screen_write_mode_clear(sctx, MODE_KEXTENDED);
+ else if (n == 4 && (m == 1 || m == 2))
+ screen_write_mode_set(sctx, MODE_KEXTENDED);
+ break;
+ case INPUT_CSI_MODOFF:
+ n = input_get(ictx, 0, 0, 0);
+ if (n == 4)
+ screen_write_mode_clear(sctx, MODE_KEXTENDED);
+ break;
case INPUT_CSI_WINOPS:
input_csi_dispatch_winops(ictx);
break;
@@ -1593,7 +1610,7 @@ input_csi_dispatch(struct input_ctx *ictx)
break;
case INPUT_CSI_XDA:
n = input_get(ictx, 0, 0, 0);
- if (n != 0)
+ if (n == 0)
input_reply(ictx, "\033P>|tmux %s\033\\", getversion());
break;
diff --git a/options-table.c b/options-table.c
index 4ac0d0c3..87670b12 100644
--- a/options-table.c
+++ b/options-table.c
@@ -252,6 +252,14 @@ const struct options_table_entry options_table[] = {
"clients."
},
+ { .name = "extended-keys",
+ .type = OPTIONS_TABLE_FLAG,
+ .scope = OPTIONS_TABLE_SERVER,
+ .default_num = 0,
+ .text = "Whether to request extended key sequences from terminals "
+ "that support it."
+ },
+
{ .name = "focus-events",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_SERVER,
@@ -1053,11 +1061,12 @@ const struct options_table_entry options_table[] = {
"bottom."
},
- { .name = "xterm-keys",
+ { .name = "xterm-keys", /* no longer used */
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 1,
- .text = "Whether xterm-style function key sequences should be sent."
+ .text = "Whether xterm-style function key sequences should be sent. "
+ "This option is no longer used."
},
/* Hook options. */
diff --git a/tmux.1 b/tmux.1
index 421f8889..9f687bd2 100644
--- a/tmux.1
+++ b/tmux.1
@@ -3225,6 +3225,12 @@ sessions.
.Op Ic on | off
.Xc
If enabled, the server will exit when there are no attached clients.
+.It Xo Ic extended-keys
+.Op Ic on | off
+.Xc
+When enabled, extended keys are requested from the terminal and if supported
+are recognised by
+.Nm .
.It Xo Ic focus-events
.Op Ic on | off
.Xc
@@ -4054,16 +4060,6 @@ option.
.Xc
If this option is set, searches will wrap around the end of the pane contents.
The default is on.
-.Pp
-.It Xo Ic xterm-keys
-.Op Ic on | off
-.Xc
-If this option is set,
-.Nm
-will generate
-.Xr xterm 1 -style
-function key sequences; these have a number included to indicate modifiers such
-as Shift, Alt or Ctrl.
.El
.Pp
Available pane options are:
@@ -5754,6 +5750,8 @@ Disable and enable bracketed paste.
These are set automatically if the
.Em XT
capability is present.
+.It Em \&Dseks , \&Eneks
+Disable and enable extended keys.
.It Em \&Dsfcs , \&Enfcs
Disable and enable focus reporting.
These are set automatically if the
diff --git a/tty-features.c b/tty-features.c
index 30d3d1a0..26344b90 100644
--- a/tty-features.c
+++ b/tty-features.c
@@ -190,6 +190,18 @@ static const struct tty_feature tty_feature_sync = {
0
};
+/* Terminal supports extended keys. */
+static const char *tty_feature_extkeys_capabilities[] = {
+ "Eneks=\\E[>4;1m",
+ "Dseks=\\E[>4m",
+ NULL
+};
+static const struct tty_feature tty_feature_extkeys = {
+ "extkeys",
+ tty_feature_extkeys_capabilities,
+ 0
+};
+
/* Terminal supports DECSLRM margins. */
static const char *tty_feature_margins_capabilities[] = {
"Enmg=\\E[?69h",
@@ -218,6 +230,7 @@ static const struct tty_feature *tty_features[] = {
&tty_feature_ccolour,
&tty_feature_clipboard,
&tty_feature_cstyle,
+ &tty_feature_extkeys,
&tty_feature_focus,
&tty_feature_margins,
&tty_feature_overline,
@@ -321,7 +334,7 @@ tty_default_features(int *feat, const char *name, u_int version)
} table[] = {
#define TTY_FEATURES_BASE_MODERN_XTERM "256,RGB,bpaste,clipboard,strikethrough,title"
{ .name = "mintty",
- .features = TTY_FEATURES_BASE_MODERN_XTERM ",ccolour,cstyle,margins,overline"
+ .features = TTY_FEATURES_BASE_MODERN_XTERM ",ccolour,cstyle,extkeys,margins,overline"
},
{ .name = "tmux",
.features = TTY_FEATURES_BASE_MODERN_XTERM ",ccolour,cstyle,focus,overline,usstyle"
@@ -333,7 +346,7 @@ tty_default_features(int *feat, const char *name, u_int version)
.features = TTY_FEATURES_BASE_MODERN_XTERM ",cstyle,margins,sync"
},
{ .name = "XTerm",
- .features = TTY_FEATURES_BASE_MODERN_XTERM ",ccolour,cstyle,focus,margins,rectfill"
+ .features = TTY_FEATURES_BASE_MODERN_XTERM ",ccolour,cstyle,extkeys,focus,margins,rectfill"
}
};
u_int i;
diff --git a/tty-keys.c b/tty-keys.c
index dc064a17..5a2b3817 100644
--- a/tty-keys.c
+++ b/tty-keys.c
@@ -21,6 +21,7 @@
#include <netinet/in.h>
+#include <ctype.h>
#include <limits.h>
#include <resolv.h>
#include <stdlib.h>
@@ -46,6 +47,8 @@ static struct tty_key *tty_keys_find(struct tty *, const char *, size_t,
static int tty_keys_next1(struct tty *, const char *, size_t, key_code *,
size_t *, int);
static void tty_keys_callback(int, short, void *);
+static int tty_keys_extended_key(struct tty *, const char *, size_t,
+ size_t *, key_code *);
static int tty_keys_mouse(struct tty *, const char *, size_t, size_t *,
struct mouse_event *);
static int tty_keys_clipboard(struct tty *, const char *, size_t,
@@ -69,33 +72,33 @@ static const struct tty_default_key_raw tty_default_raw_keys[] = {
* put the terminal into keypad_xmit mode. Translation of numbers
* mode/applications mode is done in input-keys.c.
*/
- { "\033Oo", KEYC_KP_SLASH },
- { "\033Oj", KEYC_KP_STAR },
- { "\033Om", KEYC_KP_MINUS },
- { "\033Ow", KEYC_KP_SEVEN },
- { "\033Ox", KEYC_KP_EIGHT },
- { "\033Oy", KEYC_KP_NINE },
- { "\033Ok", KEYC_KP_PLUS },
- { "\033Ot", KEYC_KP_FOUR },
- { "\033Ou", KEYC_KP_FIVE },
- { "\033Ov", KEYC_KP_SIX },
- { "\033Oq", KEYC_KP_ONE },
- { "\033Or", KEYC_KP_TWO },
- { "\033Os", KEYC_KP_THREE },
- { "\033OM", KEYC_KP_ENTER },
- { "\033Op", KEYC_KP_ZERO },
- { "\033On", KEYC_KP_PERIOD },
+ { "\033Oo", KEYC_KP_SLASH|KEYC_KEYPAD },
+ { "\033Oj", KEYC_KP_STAR|KEYC_KEYPAD },
+ { "\033Om", KEYC_KP_MINUS|KEYC_KEYPAD },
+ { "\033Ow", KEYC_KP_SEVEN|KEYC_KEYPAD },
+ { "\033Ox", KEYC_KP_EIGHT|KEYC_KEYPAD },
+ { "\033Oy", KEYC_KP_NINE|KEYC_KEYPAD },
+ { "\033Ok", KEYC_KP_PLUS|KEYC_KEYPAD },
+ { "\033Ot", KEYC_KP_FOUR|KEYC_KEYPAD },
+ { "\033Ou", KEYC_KP_FIVE|KEYC_KEYPAD },
+ { "\033Ov", KEYC_KP_SIX|KEYC_KEYPAD },
+ { "\033Oq", KEYC_KP_ONE|KEYC_KEYPAD },
+ { "\033Or", KEYC_KP_TWO|KEYC_KEYPAD },
+ { "\033Os", KEYC_KP_THREE|KEYC_KEYPAD },
+ { "\033OM", KEYC_KP_ENTER|KEYC_KEYPAD },
+ { "\033Op", KEYC_KP_ZERO|KEYC_KEYPAD },
+ { "\033On", KEYC_KP_PERIOD|KEYC_KEYPAD },
/* Arrow keys. */
- { "\033OA", KEYC_UP },
- { "\033OB", KEYC_DOWN },
- { "\033OC", KEYC_RIGHT },
- { "\033OD", KEYC_LEFT },
+ { "\033OA", KEYC_UP|KEYC_CURSOR },
+ { "\033OB", KEYC_DOWN|KEYC_CURSOR },
+ { "\033OC", KEYC_RIGHT|KEYC_CURSOR },
+ { "\033OD", KEYC_LEFT|KEYC_CURSOR },
- { "\033[A", KEYC_UP },
- { "\033[B", KEYC_DOWN },
- { "\033[C", KEYC_RIGHT },
- { "\033[D", KEYC_LEFT },
+ { "\033[A", KEYC_UP|KEYC_CURSOR },
+ { "\033[B", KEYC_DOWN|KEYC_CURSOR },
+ { "\033[C", KEYC_RIGHT|KEYC_CURSOR },
+ { "\033[D", KEYC_LEFT|KEYC_CURSOR },
/* Other (xterm) "cursor" keys. */
{ "\033OH", KEYC_HOME },
@@ -182,11 +185,59 @@ static const struct tty_default_key_raw tty_default_raw_keys[] = {
{ "\033[201~", KEYC_PASTE_END },
};
+/* Default xterm keys. */
+struct tty_default_key_xterm {
+ const char *template;
+ key_code key;
+};
+static const struct tty_default_key_xterm tty_default_xterm_keys[] = {
+ { "\033[1;_P", KEYC_F1 },
+ { "\033O1;_P", KEYC_F1 },
+ { "\033O_P", KEYC_F1 },
+ { "\033[1;_Q", KEYC_F2 },
+ { "\033O1;_Q", KEYC_F2 },
+ { "\033O_Q", KEYC_F2 },
+ { "\033[1;_R", KEYC_F3 },
+ { "\033O1;_R", KEYC_F3 },
+ { "\033O_R", KEYC_F3 },
+ { "\033[1;_S", KEYC_F4 },
+ { "\033O1;_S", KEYC_F4 },
+ { "\033O_S", KEYC_F4 },
+ { "\033[15;_~", KEYC_F5 },
+ { "\033[17;_~", KEYC_F6 },
+ { "\033[18;_~", KEYC_F7 },
+ { "\033[19;_~", KEYC_F8 },
+ { "\033[20;_~", KEYC_F9 },
+ { "\033[21;_~", KEYC_F10 },
+ { "\033[23;_~", KEYC_F11 },
+ { "\033[24;_~", KEYC_F12 },
+ { "\033[1;_A", KEYC_UP },
+ { "\033[1;_B", KEYC_DOWN },
+ { "\033[1;_C", KEYC_RIGHT },
+ { "\033[1;_D", KEYC_LEFT },
+ { "\033[1;_H", KEYC_HOME },
+ { "\033[1;_F", KEYC_END },
+ { "\033[5;_~", KEYC_PPAGE },
+ { "\033[6;_~", KEYC_NPAGE },
+ { "\033[2;_~", KEYC_IC },
+ { "\033[3;_~", KEYC_DC },
+};
+static const key_code tty_default_xterm_modifiers[] = {
+ 0,
+ 0,
+ KEYC_SHIFT,
+ KEYC_META|KEYC_IMPLIED_META,
+ KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META,
+ KEYC_CTRL,
+ KEYC_SHIFT|KEYC_CTRL,
+ KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL,
+ KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL
+};
+
/*
- * Default terminfo(5) keys. Any keys that have builtin modifiers
- * (that is, where the key itself contains the modifiers) has the
- * KEYC_XTERM flag set so a leading escape is not treated as meta (and
- * probably removed).
+ * Default terminfo(5) keys. Any keys that have builtin modifiers (that is,
+ * where the key itself contains the modifiers) has the KEYC_XTERM flag set so
+ * a leading escape is not treated as meta (and probably removed).
*/
struct tty_default_key_code {
enum tty_code_code code;
@@ -207,61 +258,61 @@ static const struct tty_default_key_code tty_default_code_keys[] = {
{ TTYC_KF11, KEYC_F11 },
{ TTYC_KF12, KEYC_F12 },
- { TTYC_KF13, KEYC_F1|KEYC_SHIFT|KEYC_XTERM },
- { TTYC_KF14, KEYC_F2|KEYC_SHIFT|KEYC_XTERM },
- { TTYC_KF15, KEYC_F3|KEYC_SHIFT|KEYC_XTERM },
- { TTYC_KF16, KEYC_F4|KEYC_SHIFT|KEYC_XTERM },
- { TTYC_KF17, KEYC_F5|KEYC_SHIFT|KEYC_XTERM },
- { TTYC_KF18, KEYC_F6|KEYC_SHIFT|KEYC_XTERM },
- { TTYC_KF19, KEYC_F7|KEYC_SHIFT|KEYC_XTERM },
- { TTYC_KF20, KEYC_F8|KEYC_SHIFT|KEYC_XTERM },
- { TTYC_KF21, KEYC_F9|KEYC_SHIFT|KEYC_XTERM },
- { TTYC_KF22, KEYC_F10|KEYC_SHIFT|KEYC_XTERM },
- { TTYC_KF23, KEYC_F11|KEYC_SHIFT|KEYC_XTERM },
- { TTYC_KF24, KEYC_F12|KEYC_SHIFT|KEYC_XTERM },
-
- { TTYC_KF25, KEYC_F1|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF26, KEYC_F2|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF27, KEYC_F3|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF28, KEYC_F4|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF29, KEYC_F5|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF30, KEYC_F6|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF31, KEYC_F7|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF32, KEYC_F8|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF33, KEYC_F9|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF34, KEYC_F10|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF35, KEYC_F11|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF36, KEYC_F12|KEYC_CTRL|KEYC_XTERM },
-
- { TTYC_KF37, KEYC_F1|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF38, KEYC_F2|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF39, KEYC_F3|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF40, KEYC_F4|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF41, KEYC_F5|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF42, KEYC_F6|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF43, KEYC_F7|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF44, KEYC_F8|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF45, KEYC_F9|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF46, KEYC_F10|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF47, KEYC_F11|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
- { TTYC_KF48, KEYC_F12|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
-
- { TTYC_KF49, KEYC_F1|KEYC_ESCAPE|KEYC_XTERM },
- { TTYC_KF50, KEYC_F2|KEYC_ESCAPE|KEYC_XTERM },
- { TTYC_KF51, KEYC_F3|KEYC_ESCAPE|KEYC_XTERM },
- { TTYC_KF52, KEYC_F4|KEYC_ESCAPE|KEYC_XTERM },
- { TTYC_KF53, KEYC_F5|KEYC_ESCAPE|KEYC_XTERM },
- { TTYC_KF54, KEYC_F6|KEYC_ESCAPE|KEYC_XTERM },
- { TTYC_KF55, KEYC_F7|KEYC_ESCAPE|KEYC_XTERM },
- { TTYC_KF56, KEYC_F8|KEYC_ESCAPE|KEYC_XTERM },
- { TTYC_KF57, KEYC_F9|KEYC_ESCAPE|KEYC_XTERM },
- { TTYC_KF58, KEYC_F10|KEYC_ESCAPE|KEYC_XTERM },
- { TTYC_KF59, KEYC_F11|KEYC_ESCAPE|KEYC_XTERM },
- { TTYC_KF60, KEYC_F12|KEYC_ESCAPE|KEYC_XTERM },
-
- { TTYC_KF61, KEYC_F1|KEYC_ESCAPE|KEYC_SHIFT|KEYC_XTERM },
- { TTYC_KF62, KEYC_F2|KEYC_ESCAPE|KEYC_SHIFT|KEYC_XTERM },
- { TTYC_KF63, KEYC_F3|KEYC_ESCAPE|KEYC_SHIFT|KEYC_XTERM },
+ { TTYC_KF13, KEYC_F1|KEYC_SHIFT },
+ { TTYC_KF14, KEYC_F2|KEYC_SHIFT },
+ { TTYC_KF15, KEYC_F3|KEYC_SHIFT },
+ { TTYC_KF16, KEYC_F4|KEYC_SHIFT },
+ { TTYC_KF17, KEYC_F5|KEYC_SHIFT },
+ { TTYC_KF18, KEYC_F6|KEYC_SHIFT },
+ { TTYC_KF19, KEYC_F7|KEYC_SHIFT },
+ { TTYC_KF20, KEYC_F8|KEYC_SHIFT },
+ { TTYC_KF21, KEYC_F9|KEYC_SHIFT },
+ { TTYC_KF22, KEYC_F10|KEYC_SHIFT },
+ { TTYC_KF23, KEYC_F11|KEYC_SHIFT },
+ { TTYC_KF24, KEYC_F12|KEYC_SHIFT },
+
+ { TTYC_KF25, KEYC_F1|KEYC_CTRL },
+ { TTYC_KF26, KEYC_F2|KEYC_CTRL },
+ { TTYC_KF27, KEYC_F3|KEYC_CTRL },
+ { TTYC_KF28, KEYC_F4|KEYC_CTRL },
+ { TTYC_KF29, KEYC_F5|KEYC_CTRL },
+ { TTYC_KF30, KEYC_F6|KEYC_CTRL },
+ { TTYC_KF31, KEYC_F7|KEYC_CTRL },
+ { TTYC_KF32, KEYC_F8|KEYC_CTRL },
+ { TTYC_KF33, KEYC_F9|KEYC_CTRL },
+ { TTYC_KF34, KEYC_F10|KEYC_CTRL },
+ { TTYC_KF35, KEYC_F11|KEYC_CTRL },
+ { TTYC_KF36, KEYC_F12|KEYC_CTRL },
+
+ { TTYC_KF37, KEYC_F1|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KF38, KEYC_F2|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KF39, KEYC_F3|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KF40, KEYC_F4|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KF41, KEYC_F5|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KF42, KEYC_F6|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KF43, KEYC_F7|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KF44, KEYC_F8|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KF45, KEYC_F9|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KF46, KEYC_F10|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KF47, KEYC_F11|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KF48, KEYC_F12|KEYC_SHIFT|KEYC_CTRL },
+
+ { TTYC_KF49, KEYC_F1|KEYC_META|KEYC_IMPLIED_META },
+ { TTYC_KF50, KEYC_F2|KEYC_META|KEYC_IMPLIED_META },
+ { TTYC_KF51, KEYC_F3|KEYC_META|KEYC_IMPLIED_META },
+ { TTYC_KF52, KEYC_F4|KEYC_META|KEYC_IMPLIED_META },
+ { TTYC_KF53, KEYC_F5|KEYC_META|KEYC_IMPLIED_META },
+ { TTYC_KF54, KEYC_F6|KEYC_META|KEYC_IMPLIED_META },
+ { TTYC_KF55, KEYC_F7|KEYC_META|KEYC_IMPLIED_META },
+ { TTYC_KF56, KEYC_F8|KEYC_META|KEYC_IMPLIED_META },
+ { TTYC_KF57, KEYC_F9|KEYC_META|KEYC_IMPLIED_META },
+ { TTYC_KF58, KEYC_F10|KEYC_META|KEYC_IMPLIED_META },
+ { TTYC_KF59, KEYC_F11|KEYC_META|KEYC_IMPLIED_META },
+ { TTYC_KF60, KEYC_F12|KEYC_META|KEYC_IMPLIED_META },
+
+ { TTYC_KF61, KEYC_F1|KEYC_META|KEYC_IMPLIED_META|KEYC_SHIFT },
+ { TTYC_KF62, KEYC_F2|KEYC_META|KEYC_IMPLIED_META|KEYC_SHIFT