Merge branch 'obsd-master'
[tmux.git] / input-keys.c
blob0451b9687cd6a3c2a8e3987eb8b6d57de75b8c90
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
21 #include <stdlib.h>
22 #include <string.h>
24 #include "tmux.h"
27 * This file is rather misleadingly named, it contains the code which takes a
28 * key code and translates it into something suitable to be sent to the
29 * application running in a pane (similar to input.c does in the other
30 * direction with output).
33 static void input_key_mouse(struct window_pane *, struct mouse_event *);
35 /* Entry in the key tree. */
36 struct input_key_entry {
37 key_code key;
38 const char *data;
40 RB_ENTRY(input_key_entry) entry;
42 RB_HEAD(input_key_tree, input_key_entry);
44 /* Tree of input keys. */
45 static int input_key_cmp(struct input_key_entry *,
46 struct input_key_entry *);
47 RB_GENERATE_STATIC(input_key_tree, input_key_entry, entry, input_key_cmp);
48 struct input_key_tree input_key_tree = RB_INITIALIZER(&input_key_tree);
50 /* List of default keys, the tree is built from this. */
51 static struct input_key_entry input_key_defaults[] = {
52 /* Paste keys. */
53 { .key = KEYC_PASTE_START,
54 .data = "\033[200~"
56 { .key = KEYC_PASTE_END,
57 .data = "\033[201~"
60 /* Function keys. */
61 { .key = KEYC_F1,
62 .data = "\033OP"
64 { .key = KEYC_F2,
65 .data = "\033OQ"
67 { .key = KEYC_F3,
68 .data = "\033OR"
70 { .key = KEYC_F4,
71 .data = "\033OS"
73 { .key = KEYC_F5,
74 .data = "\033[15~"
76 { .key = KEYC_F6,
77 .data = "\033[17~"
79 { .key = KEYC_F7,
80 .data = "\033[18~"
82 { .key = KEYC_F8,
83 .data = "\033[19~"
85 { .key = KEYC_F9,
86 .data = "\033[20~"
88 { .key = KEYC_F10,
89 .data = "\033[21~"
91 { .key = KEYC_F11,
92 .data = "\033[23~"
94 { .key = KEYC_F12,
95 .data = "\033[24~"
97 { .key = KEYC_IC,
98 .data = "\033[2~"
100 { .key = KEYC_DC,
101 .data = "\033[3~"
103 { .key = KEYC_HOME,
104 .data = "\033[1~"
106 { .key = KEYC_END,
107 .data = "\033[4~"
109 { .key = KEYC_NPAGE,
110 .data = "\033[6~"
112 { .key = KEYC_PPAGE,
113 .data = "\033[5~"
115 { .key = KEYC_BTAB,
116 .data = "\033[Z"
119 /* Arrow keys. */
120 { .key = KEYC_UP|KEYC_CURSOR,
121 .data = "\033OA"
123 { .key = KEYC_DOWN|KEYC_CURSOR,
124 .data = "\033OB"
126 { .key = KEYC_RIGHT|KEYC_CURSOR,
127 .data = "\033OC"
129 { .key = KEYC_LEFT|KEYC_CURSOR,
130 .data = "\033OD"
132 { .key = KEYC_UP,
133 .data = "\033[A"
135 { .key = KEYC_DOWN,
136 .data = "\033[B"
138 { .key = KEYC_RIGHT,
139 .data = "\033[C"
141 { .key = KEYC_LEFT,
142 .data = "\033[D"
145 /* Keypad keys. */
146 { .key = KEYC_KP_SLASH|KEYC_KEYPAD,
147 .data = "\033Oo"
149 { .key = KEYC_KP_STAR|KEYC_KEYPAD,
150 .data = "\033Oj"
152 { .key = KEYC_KP_MINUS|KEYC_KEYPAD,
153 .data = "\033Om"
155 { .key = KEYC_KP_SEVEN|KEYC_KEYPAD,
156 .data = "\033Ow"
158 { .key = KEYC_KP_EIGHT|KEYC_KEYPAD,
159 .data = "\033Ox"
161 { .key = KEYC_KP_NINE|KEYC_KEYPAD,
162 .data = "\033Oy"
164 { .key = KEYC_KP_PLUS|KEYC_KEYPAD,
165 .data = "\033Ok"
167 { .key = KEYC_KP_FOUR|KEYC_KEYPAD,
168 .data = "\033Ot"
170 { .key = KEYC_KP_FIVE|KEYC_KEYPAD,
171 .data = "\033Ou"
173 { .key = KEYC_KP_SIX|KEYC_KEYPAD,
174 .data = "\033Ov"
176 { .key = KEYC_KP_ONE|KEYC_KEYPAD,
177 .data = "\033Oq"
179 { .key = KEYC_KP_TWO|KEYC_KEYPAD,
180 .data = "\033Or"
182 { .key = KEYC_KP_THREE|KEYC_KEYPAD,
183 .data = "\033Os"
185 { .key = KEYC_KP_ENTER|KEYC_KEYPAD,
186 .data = "\033OM"
188 { .key = KEYC_KP_ZERO|KEYC_KEYPAD,
189 .data = "\033Op"
191 { .key = KEYC_KP_PERIOD|KEYC_KEYPAD,
192 .data = "\033On"
194 { .key = KEYC_KP_SLASH,
195 .data = "/"
197 { .key = KEYC_KP_STAR,
198 .data = "*"
200 { .key = KEYC_KP_MINUS,
201 .data = "-"
203 { .key = KEYC_KP_SEVEN,
204 .data = "7"
206 { .key = KEYC_KP_EIGHT,
207 .data = "8"
209 { .key = KEYC_KP_NINE,
210 .data = "9"
212 { .key = KEYC_KP_PLUS,
213 .data = "+"
215 { .key = KEYC_KP_FOUR,
216 .data = "4"
218 { .key = KEYC_KP_FIVE,
219 .data = "5"
221 { .key = KEYC_KP_SIX,
222 .data = "6"
224 { .key = KEYC_KP_ONE,
225 .data = "1"
227 { .key = KEYC_KP_TWO,
228 .data = "2"
230 { .key = KEYC_KP_THREE,
231 .data = "3"
233 { .key = KEYC_KP_ENTER,
234 .data = "\n"
236 { .key = KEYC_KP_ZERO,
237 .data = "0"
239 { .key = KEYC_KP_PERIOD,
240 .data = "."
243 /* Keys with an embedded modifier. */
244 { .key = KEYC_F1|KEYC_BUILD_MODIFIERS,
245 .data = "\033[1;_P"
247 { .key = KEYC_F2|KEYC_BUILD_MODIFIERS,
248 .data = "\033[1;_Q"
250 { .key = KEYC_F3|KEYC_BUILD_MODIFIERS,
251 .data = "\033[1;_R"
253 { .key = KEYC_F4|KEYC_BUILD_MODIFIERS,
254 .data = "\033[1;_S"
256 { .key = KEYC_F5|KEYC_BUILD_MODIFIERS,
257 .data = "\033[15;_~"
259 { .key = KEYC_F6|KEYC_BUILD_MODIFIERS,
260 .data = "\033[17;_~"
262 { .key = KEYC_F7|KEYC_BUILD_MODIFIERS,
263 .data = "\033[18;_~"
265 { .key = KEYC_F8|KEYC_BUILD_MODIFIERS,
266 .data = "\033[19;_~"
268 { .key = KEYC_F9|KEYC_BUILD_MODIFIERS,
269 .data = "\033[20;_~"
271 { .key = KEYC_F10|KEYC_BUILD_MODIFIERS,
272 .data = "\033[21;_~"
274 { .key = KEYC_F11|KEYC_BUILD_MODIFIERS,
275 .data = "\033[23;_~"
277 { .key = KEYC_F12|KEYC_BUILD_MODIFIERS,
278 .data = "\033[24;_~"
280 { .key = KEYC_UP|KEYC_BUILD_MODIFIERS,
281 .data = "\033[1;_A"
283 { .key = KEYC_DOWN|KEYC_BUILD_MODIFIERS,
284 .data = "\033[1;_B"
286 { .key = KEYC_RIGHT|KEYC_BUILD_MODIFIERS,
287 .data = "\033[1;_C"
289 { .key = KEYC_LEFT|KEYC_BUILD_MODIFIERS,
290 .data = "\033[1;_D"
292 { .key = KEYC_HOME|KEYC_BUILD_MODIFIERS,
293 .data = "\033[1;_H"
295 { .key = KEYC_END|KEYC_BUILD_MODIFIERS,
296 .data = "\033[1;_F"
298 { .key = KEYC_PPAGE|KEYC_BUILD_MODIFIERS,
299 .data = "\033[5;_~"
301 { .key = KEYC_NPAGE|KEYC_BUILD_MODIFIERS,
302 .data = "\033[6;_~"
304 { .key = KEYC_IC|KEYC_BUILD_MODIFIERS,
305 .data = "\033[2;_~"
307 { .key = KEYC_DC|KEYC_BUILD_MODIFIERS,
308 .data = "\033[3;_~"
311 /* Tab and modifiers. */
312 { .key = '\011'|KEYC_CTRL,
313 .data = "\011"
315 { .key = '\011'|KEYC_CTRL|KEYC_EXTENDED,
316 .data = "\033[9;5u"
318 { .key = '\011'|KEYC_CTRL|KEYC_SHIFT,
319 .data = "\033[Z"
321 { .key = '\011'|KEYC_CTRL|KEYC_SHIFT|KEYC_EXTENDED,
322 .data = "\033[1;5Z"
325 static const key_code input_key_modifiers[] = {
328 KEYC_SHIFT,
329 KEYC_META|KEYC_IMPLIED_META,
330 KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META,
331 KEYC_CTRL,
332 KEYC_SHIFT|KEYC_CTRL,
333 KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL,
334 KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL
337 /* Input key comparison function. */
338 static int
339 input_key_cmp(struct input_key_entry *ike1, struct input_key_entry *ike2)
341 if (ike1->key < ike2->key)
342 return (-1);
343 if (ike1->key > ike2->key)
344 return (1);
345 return (0);
348 /* Look for key in tree. */
349 static struct input_key_entry *
350 input_key_get(key_code key)
352 struct input_key_entry entry = { .key = key };
354 return (RB_FIND(input_key_tree, &input_key_tree, &entry));
357 /* Split a character into two UTF-8 bytes. */
358 static size_t
359 input_key_split2(u_int c, u_char *dst)
361 if (c > 0x7f) {
362 dst[0] = (c >> 6) | 0xc0;
363 dst[1] = (c & 0x3f) | 0x80;
364 return (2);
366 dst[0] = c;
367 return (1);
370 /* Build input key tree. */
371 void
372 input_key_build(void)
374 struct input_key_entry *ike, *new;
375 u_int i, j;
376 char *data;
377 key_code key;
379 for (i = 0; i < nitems(input_key_defaults); i++) {
380 ike = &input_key_defaults[i];
381 if (~ike->key & KEYC_BUILD_MODIFIERS) {
382 RB_INSERT(input_key_tree, &input_key_tree, ike);
383 continue;
386 for (j = 2; j < nitems(input_key_modifiers); j++) {
387 key = (ike->key & ~KEYC_BUILD_MODIFIERS);
388 data = xstrdup(ike->data);
389 data[strcspn(data, "_")] = '0' + j;
391 new = xcalloc(1, sizeof *new);
392 new->key = key|input_key_modifiers[j];
393 new->data = data;
394 RB_INSERT(input_key_tree, &input_key_tree, new);
398 RB_FOREACH(ike, input_key_tree, &input_key_tree) {
399 log_debug("%s: 0x%llx (%s) is %s", __func__, ike->key,
400 key_string_lookup_key(ike->key, 1), ike->data);
404 /* Translate a key code into an output key sequence for a pane. */
406 input_key_pane(struct window_pane *wp, key_code key, struct mouse_event *m)
408 if (log_get_level() != 0) {
409 log_debug("writing key 0x%llx (%s) to %%%u", key,
410 key_string_lookup_key(key, 1), wp->id);
413 if (KEYC_IS_MOUSE(key)) {
414 if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id)
415 input_key_mouse(wp, m);
416 return (0);
418 return (input_key(wp->screen, wp->event, key));
421 static void
422 input_key_write(const char *from, struct bufferevent *bev, const char *data,
423 size_t size)
425 log_debug("%s: %.*s", from, (int)size, data);
426 bufferevent_write(bev, data, size);
429 /* Translate a key code into an output key sequence. */
431 input_key(struct screen *s, struct bufferevent *bev, key_code key)
433 struct input_key_entry *ike = NULL;
434 key_code justkey, newkey, outkey, modifiers;
435 struct utf8_data ud;
436 char tmp[64], modifier;
438 /* Mouse keys need a pane. */
439 if (KEYC_IS_MOUSE(key))
440 return (0);
442 /* Literal keys go as themselves (can't be more than eight bits). */
443 if (key & KEYC_LITERAL) {
444 ud.data[0] = (u_char)key;
445 input_key_write(__func__, bev, &ud.data[0], 1);
446 return (0);
449 /* Is this backspace? */
450 if ((key & KEYC_MASK_KEY) == KEYC_BSPACE) {
451 newkey = options_get_number(global_options, "backspace");
452 if (newkey >= 0x7f)
453 newkey = '\177';
454 key = newkey|(key & (KEYC_MASK_MODIFIERS|KEYC_MASK_FLAGS));
458 * If this is a normal 7-bit key, just send it, with a leading escape
459 * if necessary. If it is a UTF-8 key, split it and send it.
461 justkey = (key & ~(KEYC_META|KEYC_IMPLIED_META));
462 if (justkey <= 0x7f) {
463 if (key & KEYC_META)
464 input_key_write(__func__, bev, "\033", 1);
465 ud.data[0] = justkey;
466 input_key_write(__func__, bev, &ud.data[0], 1);
467 return (0);
469 if (KEYC_IS_UNICODE(justkey)) {
470 if (key & KEYC_META)
471 input_key_write(__func__, bev, "\033", 1);
472 utf8_to_data(justkey, &ud);
473 input_key_write(__func__, bev, ud.data, ud.size);
474 return (0);
478 * Look up in the tree. If not in application keypad or cursor mode,
479 * remove the flags from the key.
481 if (~s->mode & MODE_KKEYPAD)
482 key &= ~KEYC_KEYPAD;
483 if (~s->mode & MODE_KCURSOR)
484 key &= ~KEYC_CURSOR;
485 if (s->mode & MODE_KEXTENDED)
486 ike = input_key_get(key|KEYC_EXTENDED);
487 if (ike == NULL)
488 ike = input_key_get(key);
489 if (ike == NULL && (key & KEYC_META) && (~key & KEYC_IMPLIED_META))
490 ike = input_key_get(key & ~KEYC_META);
491 if (ike == NULL && (key & KEYC_CURSOR))
492 ike = input_key_get(key & ~KEYC_CURSOR);
493 if (ike == NULL && (key & KEYC_KEYPAD))
494 ike = input_key_get(key & ~KEYC_KEYPAD);
495 if (ike == NULL && (key & KEYC_EXTENDED))
496 ike = input_key_get(key & ~KEYC_EXTENDED);
497 if (ike != NULL) {
498 log_debug("found key 0x%llx: \"%s\"", key, ike->data);
499 if ((key == KEYC_PASTE_START || key == KEYC_PASTE_END) &&
500 (~s->mode & MODE_BRACKETPASTE))
501 return (0);
502 if ((key & KEYC_META) && (~key & KEYC_IMPLIED_META))
503 input_key_write(__func__, bev, "\033", 1);
504 input_key_write(__func__, bev, ike->data, strlen(ike->data));
505 return (0);
508 /* No builtin key sequence; construct an extended key sequence. */
509 if (~s->mode & MODE_KEXTENDED) {
510 if ((key & KEYC_MASK_MODIFIERS) != KEYC_CTRL)
511 goto missing;
512 justkey = (key & KEYC_MASK_KEY);
513 switch (justkey) {
514 case ' ':
515 case '2':
516 key = 0|(key & ~KEYC_MASK_KEY);
517 break;
518 case '|':
519 key = 28|(key & ~KEYC_MASK_KEY);
520 break;
521 case '6':
522 key = 30|(key & ~KEYC_MASK_KEY);
523 break;
524 case '-':
525 case '/':
526 key = 31|(key & ~KEYC_MASK_KEY);
527 break;
528 case '?':
529 key = 127|(key & ~KEYC_MASK_KEY);
530 break;
531 default:
532 if (justkey >= 'A' && justkey <= '_')
533 key = (justkey - 'A')|(key & ~KEYC_MASK_KEY);
534 else if (justkey >= 'a' && justkey <= '~')
535 key = (justkey - 96)|(key & ~KEYC_MASK_KEY);
536 else
537 return (0);
538 break;
540 return (input_key(s, bev, key & ~KEYC_CTRL));
542 outkey = (key & KEYC_MASK_KEY);
543 modifiers = (key & KEYC_MASK_MODIFIERS);
544 if (outkey < 32 && outkey != 9 && outkey != 13 && outkey != 27) {
545 outkey = 64 + outkey;
546 modifiers |= KEYC_CTRL;
548 switch (modifiers) {
549 case KEYC_SHIFT:
550 modifier = '2';
551 break;
552 case KEYC_META:
553 modifier = '3';
554 break;
555 case KEYC_SHIFT|KEYC_META:
556 modifier = '4';
557 break;
558 case KEYC_CTRL:
559 modifier = '5';
560 break;
561 case KEYC_SHIFT|KEYC_CTRL:
562 modifier = '6';
563 break;
564 case KEYC_META|KEYC_CTRL:
565 modifier = '7';
566 break;
567 case KEYC_SHIFT|KEYC_META|KEYC_CTRL:
568 modifier = '8';
569 break;
570 default:
571 goto missing;
573 xsnprintf(tmp, sizeof tmp, "\033[%llu;%cu", outkey, modifier);
574 input_key_write(__func__, bev, tmp, strlen(tmp));
575 return (0);
577 missing:
578 log_debug("key 0x%llx missing", key);
579 return (-1);
582 /* Get mouse event string. */
584 input_key_get_mouse(struct screen *s, struct mouse_event *m, u_int x, u_int y,
585 const char **rbuf, size_t *rlen)
587 static char buf[40];
588 size_t len;
590 *rbuf = NULL;
591 *rlen = 0;
593 /* If this pane is not in button or all mode, discard motion events. */
594 if (MOUSE_DRAG(m->b) && (s->mode & MOTION_MOUSE_MODES) == 0)
595 return (0);
596 if ((s->mode & ALL_MOUSE_MODES) == 0)
597 return (0);
600 * If this event is a release event and not in all mode, discard it.
601 * In SGR mode we can tell absolutely because a release is normally
602 * shown by the last character. Without SGR, we check if the last
603 * buttons was also a release.
605 if (m->sgr_type != ' ') {
606 if (MOUSE_DRAG(m->sgr_b) &&
607 MOUSE_RELEASE(m->sgr_b) &&
608 (~s->mode & MODE_MOUSE_ALL))
609 return (0);
610 } else {
611 if (MOUSE_DRAG(m->b) &&
612 MOUSE_RELEASE(m->b) &&
613 MOUSE_RELEASE(m->lb) &&
614 (~s->mode & MODE_MOUSE_ALL))
615 return (0);
619 * Use the SGR (1006) extension only if the application requested it
620 * and the underlying terminal also sent the event in this format (this
621 * is because an old style mouse release event cannot be converted into
622 * the new SGR format, since the released button is unknown). Otherwise
623 * pretend that tmux doesn't speak this extension, and fall back to the
624 * UTF-8 (1005) extension if the application requested, or to the
625 * legacy format.
627 if (m->sgr_type != ' ' && (s->mode & MODE_MOUSE_SGR)) {
628 len = xsnprintf(buf, sizeof buf, "\033[<%u;%u;%u%c",
629 m->sgr_b, x + 1, y + 1, m->sgr_type);
630 } else if (s->mode & MODE_MOUSE_UTF8) {
631 if (m->b > MOUSE_PARAM_UTF8_MAX - MOUSE_PARAM_BTN_OFF ||
632 x > MOUSE_PARAM_UTF8_MAX - MOUSE_PARAM_POS_OFF ||
633 y > MOUSE_PARAM_UTF8_MAX - MOUSE_PARAM_POS_OFF)
634 return (0);
635 len = xsnprintf(buf, sizeof buf, "\033[M");
636 len += input_key_split2(m->b + MOUSE_PARAM_BTN_OFF, &buf[len]);
637 len += input_key_split2(x + MOUSE_PARAM_POS_OFF, &buf[len]);
638 len += input_key_split2(y + MOUSE_PARAM_POS_OFF, &buf[len]);
639 } else {
640 if (m->b + MOUSE_PARAM_BTN_OFF > MOUSE_PARAM_MAX)
641 return (0);
643 len = xsnprintf(buf, sizeof buf, "\033[M");
644 buf[len++] = m->b + MOUSE_PARAM_BTN_OFF;
647 * The incoming x and y may be out of the range which can be
648 * supported by the "normal" mouse protocol. Clamp the
649 * coordinates to the supported range.
651 if (x + MOUSE_PARAM_POS_OFF > MOUSE_PARAM_MAX)
652 buf[len++] = MOUSE_PARAM_MAX;
653 else
654 buf[len++] = x + MOUSE_PARAM_POS_OFF;
655 if (y + MOUSE_PARAM_POS_OFF > MOUSE_PARAM_MAX)
656 buf[len++] = MOUSE_PARAM_MAX;
657 else
658 buf[len++] = y + MOUSE_PARAM_POS_OFF;
661 *rbuf = buf;
662 *rlen = len;
663 return (1);
666 /* Translate mouse and output. */
667 static void
668 input_key_mouse(struct window_pane *wp, struct mouse_event *m)
670 struct screen *s = wp->screen;
671 u_int x, y;
672 const char *buf;
673 size_t len;
675 /* Ignore events if no mouse mode or the pane is not visible. */
676 if (m->ignore || (s->mode & ALL_MOUSE_MODES) == 0)
677 return;
678 if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
679 return;
680 if (!window_pane_visible(wp))
681 return;
682 if (!input_key_get_mouse(s, m, x, y, &buf, &len))
683 return;
684 log_debug("writing mouse %.*s to %%%u", (int)len, buf, wp->id);
685 input_key_write(__func__, wp->event, buf, len);