Unzoom window at start of destroy so it doesn't happen later (when
[tmux-openbsd.git] / input-keys.c
blobf3281b0ec5dfaec45e33c9a7a80d99cde8462d90
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 <stdint.h>
22 #include <stdlib.h>
23 #include <string.h>
25 #include "tmux.h"
28 * This file is rather misleadingly named, it contains the code which takes a
29 * key code and translates it into something suitable to be sent to the
30 * application running in a pane (similar to input.c does in the other
31 * direction with output).
34 static void input_key_mouse(struct window_pane *, struct mouse_event *);
36 /* Entry in the key tree. */
37 struct input_key_entry {
38 key_code key;
39 const char *data;
41 RB_ENTRY(input_key_entry) entry;
43 RB_HEAD(input_key_tree, input_key_entry);
45 /* Tree of input keys. */
46 static int input_key_cmp(struct input_key_entry *,
47 struct input_key_entry *);
48 RB_GENERATE_STATIC(input_key_tree, input_key_entry, entry, input_key_cmp);
49 struct input_key_tree input_key_tree = RB_INITIALIZER(&input_key_tree);
51 /* List of default keys, the tree is built from this. */
52 static struct input_key_entry input_key_defaults[] = {
53 /* Paste keys. */
54 { .key = KEYC_PASTE_START,
55 .data = "\033[200~"
57 { .key = KEYC_PASTE_END,
58 .data = "\033[201~"
61 /* Function keys. */
62 { .key = KEYC_F1,
63 .data = "\033OP"
65 { .key = KEYC_F2,
66 .data = "\033OQ"
68 { .key = KEYC_F3,
69 .data = "\033OR"
71 { .key = KEYC_F4,
72 .data = "\033OS"
74 { .key = KEYC_F5,
75 .data = "\033[15~"
77 { .key = KEYC_F6,
78 .data = "\033[17~"
80 { .key = KEYC_F7,
81 .data = "\033[18~"
83 { .key = KEYC_F8,
84 .data = "\033[19~"
86 { .key = KEYC_F9,
87 .data = "\033[20~"
89 { .key = KEYC_F10,
90 .data = "\033[21~"
92 { .key = KEYC_F11,
93 .data = "\033[23~"
95 { .key = KEYC_F12,
96 .data = "\033[24~"
98 { .key = KEYC_IC,
99 .data = "\033[2~"
101 { .key = KEYC_DC,
102 .data = "\033[3~"
104 { .key = KEYC_HOME,
105 .data = "\033[1~"
107 { .key = KEYC_END,
108 .data = "\033[4~"
110 { .key = KEYC_NPAGE,
111 .data = "\033[6~"
113 { .key = KEYC_PPAGE,
114 .data = "\033[5~"
116 { .key = KEYC_BTAB,
117 .data = "\033[Z"
120 /* Arrow keys. */
121 { .key = KEYC_UP|KEYC_CURSOR,
122 .data = "\033OA"
124 { .key = KEYC_DOWN|KEYC_CURSOR,
125 .data = "\033OB"
127 { .key = KEYC_RIGHT|KEYC_CURSOR,
128 .data = "\033OC"
130 { .key = KEYC_LEFT|KEYC_CURSOR,
131 .data = "\033OD"
133 { .key = KEYC_UP,
134 .data = "\033[A"
136 { .key = KEYC_DOWN,
137 .data = "\033[B"
139 { .key = KEYC_RIGHT,
140 .data = "\033[C"
142 { .key = KEYC_LEFT,
143 .data = "\033[D"
146 /* Keypad keys. */
147 { .key = KEYC_KP_SLASH|KEYC_KEYPAD,
148 .data = "\033Oo"
150 { .key = KEYC_KP_STAR|KEYC_KEYPAD,
151 .data = "\033Oj"
153 { .key = KEYC_KP_MINUS|KEYC_KEYPAD,
154 .data = "\033Om"
156 { .key = KEYC_KP_SEVEN|KEYC_KEYPAD,
157 .data = "\033Ow"
159 { .key = KEYC_KP_EIGHT|KEYC_KEYPAD,
160 .data = "\033Ox"
162 { .key = KEYC_KP_NINE|KEYC_KEYPAD,
163 .data = "\033Oy"
165 { .key = KEYC_KP_PLUS|KEYC_KEYPAD,
166 .data = "\033Ok"
168 { .key = KEYC_KP_FOUR|KEYC_KEYPAD,
169 .data = "\033Ot"
171 { .key = KEYC_KP_FIVE|KEYC_KEYPAD,
172 .data = "\033Ou"
174 { .key = KEYC_KP_SIX|KEYC_KEYPAD,
175 .data = "\033Ov"
177 { .key = KEYC_KP_ONE|KEYC_KEYPAD,
178 .data = "\033Oq"
180 { .key = KEYC_KP_TWO|KEYC_KEYPAD,
181 .data = "\033Or"
183 { .key = KEYC_KP_THREE|KEYC_KEYPAD,
184 .data = "\033Os"
186 { .key = KEYC_KP_ENTER|KEYC_KEYPAD,
187 .data = "\033OM"
189 { .key = KEYC_KP_ZERO|KEYC_KEYPAD,
190 .data = "\033Op"
192 { .key = KEYC_KP_PERIOD|KEYC_KEYPAD,
193 .data = "\033On"
195 { .key = KEYC_KP_SLASH,
196 .data = "/"
198 { .key = KEYC_KP_STAR,
199 .data = "*"
201 { .key = KEYC_KP_MINUS,
202 .data = "-"
204 { .key = KEYC_KP_SEVEN,
205 .data = "7"
207 { .key = KEYC_KP_EIGHT,
208 .data = "8"
210 { .key = KEYC_KP_NINE,
211 .data = "9"
213 { .key = KEYC_KP_PLUS,
214 .data = "+"
216 { .key = KEYC_KP_FOUR,
217 .data = "4"
219 { .key = KEYC_KP_FIVE,
220 .data = "5"
222 { .key = KEYC_KP_SIX,
223 .data = "6"
225 { .key = KEYC_KP_ONE,
226 .data = "1"
228 { .key = KEYC_KP_TWO,
229 .data = "2"
231 { .key = KEYC_KP_THREE,
232 .data = "3"
234 { .key = KEYC_KP_ENTER,
235 .data = "\n"
237 { .key = KEYC_KP_ZERO,
238 .data = "0"
240 { .key = KEYC_KP_PERIOD,
241 .data = "."
244 /* Keys with an embedded modifier. */
245 { .key = KEYC_F1|KEYC_BUILD_MODIFIERS,
246 .data = "\033[1;_P"
248 { .key = KEYC_F2|KEYC_BUILD_MODIFIERS,
249 .data = "\033[1;_Q"
251 { .key = KEYC_F3|KEYC_BUILD_MODIFIERS,
252 .data = "\033[1;_R"
254 { .key = KEYC_F4|KEYC_BUILD_MODIFIERS,
255 .data = "\033[1;_S"
257 { .key = KEYC_F5|KEYC_BUILD_MODIFIERS,
258 .data = "\033[15;_~"
260 { .key = KEYC_F6|KEYC_BUILD_MODIFIERS,
261 .data = "\033[17;_~"
263 { .key = KEYC_F7|KEYC_BUILD_MODIFIERS,
264 .data = "\033[18;_~"
266 { .key = KEYC_F8|KEYC_BUILD_MODIFIERS,
267 .data = "\033[19;_~"
269 { .key = KEYC_F9|KEYC_BUILD_MODIFIERS,
270 .data = "\033[20;_~"
272 { .key = KEYC_F10|KEYC_BUILD_MODIFIERS,
273 .data = "\033[21;_~"
275 { .key = KEYC_F11|KEYC_BUILD_MODIFIERS,
276 .data = "\033[23;_~"
278 { .key = KEYC_F12|KEYC_BUILD_MODIFIERS,
279 .data = "\033[24;_~"
281 { .key = KEYC_UP|KEYC_BUILD_MODIFIERS,
282 .data = "\033[1;_A"
284 { .key = KEYC_DOWN|KEYC_BUILD_MODIFIERS,
285 .data = "\033[1;_B"
287 { .key = KEYC_RIGHT|KEYC_BUILD_MODIFIERS,
288 .data = "\033[1;_C"
290 { .key = KEYC_LEFT|KEYC_BUILD_MODIFIERS,
291 .data = "\033[1;_D"
293 { .key = KEYC_HOME|KEYC_BUILD_MODIFIERS,
294 .data = "\033[1;_H"
296 { .key = KEYC_END|KEYC_BUILD_MODIFIERS,
297 .data = "\033[1;_F"
299 { .key = KEYC_PPAGE|KEYC_BUILD_MODIFIERS,
300 .data = "\033[5;_~"
302 { .key = KEYC_NPAGE|KEYC_BUILD_MODIFIERS,
303 .data = "\033[6;_~"
305 { .key = KEYC_IC|KEYC_BUILD_MODIFIERS,
306 .data = "\033[2;_~"
308 { .key = KEYC_DC|KEYC_BUILD_MODIFIERS,
309 .data = "\033[3;_~"
312 /* Tab and modifiers. */
313 { .key = '\011'|KEYC_CTRL,
314 .data = "\011"
316 { .key = '\011'|KEYC_CTRL|KEYC_EXTENDED,
317 .data = "\033[9;5u"
319 { .key = '\011'|KEYC_CTRL|KEYC_SHIFT,
320 .data = "\033[Z"
322 { .key = '\011'|KEYC_CTRL|KEYC_SHIFT|KEYC_EXTENDED,
323 .data = "\033[1;5Z"
326 static const key_code input_key_modifiers[] = {
329 KEYC_SHIFT,
330 KEYC_META|KEYC_IMPLIED_META,
331 KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META,
332 KEYC_CTRL,
333 KEYC_SHIFT|KEYC_CTRL,
334 KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL,
335 KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL
338 /* Input key comparison function. */
339 static int
340 input_key_cmp(struct input_key_entry *ike1, struct input_key_entry *ike2)
342 if (ike1->key < ike2->key)
343 return (-1);
344 if (ike1->key > ike2->key)
345 return (1);
346 return (0);
349 /* Look for key in tree. */
350 static struct input_key_entry *
351 input_key_get(key_code key)
353 struct input_key_entry entry = { .key = key };
355 return (RB_FIND(input_key_tree, &input_key_tree, &entry));
358 /* Split a character into two UTF-8 bytes. */
359 static size_t
360 input_key_split2(u_int c, u_char *dst)
362 if (c > 0x7f) {
363 dst[0] = (c >> 6) | 0xc0;
364 dst[1] = (c & 0x3f) | 0x80;
365 return (2);
367 dst[0] = c;
368 return (1);
371 /* Build input key tree. */
372 void
373 input_key_build(void)
375 struct input_key_entry *ike, *new;
376 u_int i, j;
377 char *data;
378 key_code key;
380 for (i = 0; i < nitems(input_key_defaults); i++) {
381 ike = &input_key_defaults[i];
382 if (~ike->key & KEYC_BUILD_MODIFIERS) {
383 RB_INSERT(input_key_tree, &input_key_tree, ike);
384 continue;
387 for (j = 2; j < nitems(input_key_modifiers); j++) {
388 key = (ike->key & ~KEYC_BUILD_MODIFIERS);
389 data = xstrdup(ike->data);
390 data[strcspn(data, "_")] = '0' + j;
392 new = xcalloc(1, sizeof *new);
393 new->key = key|input_key_modifiers[j];
394 new->data = data;
395 RB_INSERT(input_key_tree, &input_key_tree, new);
399 RB_FOREACH(ike, input_key_tree, &input_key_tree) {
400 log_debug("%s: 0x%llx (%s) is %s", __func__, ike->key,
401 key_string_lookup_key(ike->key, 1), ike->data);
405 /* Translate a key code into an output key sequence for a pane. */
407 input_key_pane(struct window_pane *wp, key_code key, struct mouse_event *m)
409 if (log_get_level() != 0) {
410 log_debug("writing key 0x%llx (%s) to %%%u", key,
411 key_string_lookup_key(key, 1), wp->id);
414 if (KEYC_IS_MOUSE(key)) {
415 if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id)
416 input_key_mouse(wp, m);
417 return (0);
419 return (input_key(wp->screen, wp->event, key));
422 static void
423 input_key_write(const char *from, struct bufferevent *bev, const char *data,
424 size_t size)
426 log_debug("%s: %.*s", from, (int)size, data);
427 bufferevent_write(bev, data, size);
430 /* Translate a key code into an output key sequence. */
432 input_key(struct screen *s, struct bufferevent *bev, key_code key)
434 struct input_key_entry *ike = NULL;
435 key_code justkey, newkey, outkey, modifiers;
436 struct utf8_data ud;
437 char tmp[64], modifier;
439 /* Mouse keys need a pane. */
440 if (KEYC_IS_MOUSE(key))
441 return (0);
443 /* Literal keys go as themselves (can't be more than eight bits). */
444 if (key & KEYC_LITERAL) {
445 ud.data[0] = (u_char)key;
446 input_key_write(__func__, bev, &ud.data[0], 1);
447 return (0);
450 /* Is this backspace? */
451 if ((key & KEYC_MASK_KEY) == KEYC_BSPACE) {
452 newkey = options_get_number(global_options, "backspace");
453 if (newkey >= 0x7f)
454 newkey = '\177';
455 key = newkey|(key & (KEYC_MASK_MODIFIERS|KEYC_MASK_FLAGS));
459 * If this is a normal 7-bit key, just send it, with a leading escape
460 * if necessary. If it is a UTF-8 key, split it and send it.
462 justkey = (key & ~(KEYC_META|KEYC_IMPLIED_META));
463 if (justkey <= 0x7f) {
464 if (key & KEYC_META)
465 input_key_write(__func__, bev, "\033", 1);
466 ud.data[0] = justkey;
467 input_key_write(__func__, bev, &ud.data[0], 1);
468 return (0);
470 if (KEYC_IS_UNICODE(justkey)) {
471 if (key & KEYC_META)
472 input_key_write(__func__, bev, "\033", 1);
473 utf8_to_data(justkey, &ud);
474 input_key_write(__func__, bev, ud.data, ud.size);
475 return (0);
479 * Look up in the tree. If not in application keypad or cursor mode,
480 * remove the flags from the key.
482 if (~s->mode & MODE_KKEYPAD)
483 key &= ~KEYC_KEYPAD;
484 if (~s->mode & MODE_KCURSOR)
485 key &= ~KEYC_CURSOR;
486 if (s->mode & MODE_KEXTENDED)
487 ike = input_key_get(key|KEYC_EXTENDED);
488 if (ike == NULL)
489 ike = input_key_get(key);
490 if (ike == NULL && (key & KEYC_META) && (~key & KEYC_IMPLIED_META))
491 ike = input_key_get(key & ~KEYC_META);
492 if (ike == NULL && (key & KEYC_CURSOR))
493 ike = input_key_get(key & ~KEYC_CURSOR);
494 if (ike == NULL && (key & KEYC_KEYPAD))
495 ike = input_key_get(key & ~KEYC_KEYPAD);
496 if (ike == NULL && (key & KEYC_EXTENDED))
497 ike = input_key_get(key & ~KEYC_EXTENDED);
498 if (ike != NULL) {
499 log_debug("found key 0x%llx: \"%s\"", key, ike->data);
500 if ((key == KEYC_PASTE_START || key == KEYC_PASTE_END) &&
501 (~s->mode & MODE_BRACKETPASTE))
502 return (0);
503 if ((key & KEYC_META) && (~key & KEYC_IMPLIED_META))
504 input_key_write(__func__, bev, "\033", 1);
505 input_key_write(__func__, bev, ike->data, strlen(ike->data));
506 return (0);
509 /* No builtin key sequence; construct an extended key sequence. */
510 if (~s->mode & MODE_KEXTENDED) {
511 if ((key & KEYC_MASK_MODIFIERS) != KEYC_CTRL)
512 goto missing;
513 justkey = (key & KEYC_MASK_KEY);
514 switch (justkey) {
515 case ' ':
516 case '2':
517 key = 0|(key & ~KEYC_MASK_KEY);
518 break;
519 case '|':
520 key = 28|(key & ~KEYC_MASK_KEY);
521 break;
522 case '6':
523 key = 30|(key & ~KEYC_MASK_KEY);
524 break;
525 case '-':
526 case '/':
527 key = 31|(key & ~KEYC_MASK_KEY);
528 break;
529 case '?':
530 key = 127|(key & ~KEYC_MASK_KEY);
531 break;
532 default:
533 if (justkey >= 'A' && justkey <= '_')
534 key = (justkey - 'A')|(key & ~KEYC_MASK_KEY);
535 else if (justkey >= 'a' && justkey <= '~')
536 key = (justkey - 96)|(key & ~KEYC_MASK_KEY);
537 else
538 return (0);
539 break;
541 return (input_key(s, bev, key & ~KEYC_CTRL));
543 outkey = (key & KEYC_MASK_KEY);
544 modifiers = (key & KEYC_MASK_MODIFIERS);
545 if (outkey < 32 && outkey != 9 && outkey != 13 && outkey != 27) {
546 outkey = 64 + outkey;
547 modifiers |= KEYC_CTRL;
549 switch (modifiers) {
550 case KEYC_SHIFT:
551 modifier = '2';
552 break;
553 case KEYC_META:
554 modifier = '3';
555 break;
556 case KEYC_SHIFT|KEYC_META:
557 modifier = '4';
558 break;
559 case KEYC_CTRL:
560 modifier = '5';
561 break;
562 case KEYC_SHIFT|KEYC_CTRL:
563 modifier = '6';
564 break;
565 case KEYC_META|KEYC_CTRL:
566 modifier = '7';
567 break;
568 case KEYC_SHIFT|KEYC_META|KEYC_CTRL:
569 modifier = '8';
570 break;
571 default:
572 goto missing;
574 xsnprintf(tmp, sizeof tmp, "\033[%llu;%cu", outkey, modifier);
575 input_key_write(__func__, bev, tmp, strlen(tmp));
576 return (0);
578 missing:
579 log_debug("key 0x%llx missing", key);
580 return (-1);
583 /* Get mouse event string. */
585 input_key_get_mouse(struct screen *s, struct mouse_event *m, u_int x, u_int y,
586 const char **rbuf, size_t *rlen)
588 static char buf[40];
589 size_t len;
591 *rbuf = NULL;
592 *rlen = 0;
594 /* If this pane is not in button or all mode, discard motion events. */
595 if (MOUSE_DRAG(m->b) && (s->mode & MOTION_MOUSE_MODES) == 0)
596 return (0);
597 if ((s->mode & ALL_MOUSE_MODES) == 0)
598 return (0);
601 * If this event is a release event and not in all mode, discard it.
602 * In SGR mode we can tell absolutely because a release is normally
603 * shown by the last character. Without SGR, we check if the last
604 * buttons was also a release.
606 if (m->sgr_type != ' ') {
607 if (MOUSE_DRAG(m->sgr_b) &&
608 MOUSE_RELEASE(m->sgr_b) &&
609 (~s->mode & MODE_MOUSE_ALL))
610 return (0);
611 } else {
612 if (MOUSE_DRAG(m->b) &&
613 MOUSE_RELEASE(m->b) &&
614 MOUSE_RELEASE(m->lb) &&
615 (~s->mode & MODE_MOUSE_ALL))
616 return (0);
620 * Use the SGR (1006) extension only if the application requested it
621 * and the underlying terminal also sent the event in this format (this
622 * is because an old style mouse release event cannot be converted into
623 * the new SGR format, since the released button is unknown). Otherwise
624 * pretend that tmux doesn't speak this extension, and fall back to the
625 * UTF-8 (1005) extension if the application requested, or to the
626 * legacy format.
628 if (m->sgr_type != ' ' && (s->mode & MODE_MOUSE_SGR)) {
629 len = xsnprintf(buf, sizeof buf, "\033[<%u;%u;%u%c",
630 m->sgr_b, x + 1, y + 1, m->sgr_type);
631 } else if (s->mode & MODE_MOUSE_UTF8) {
632 if (m->b > MOUSE_PARAM_UTF8_MAX - MOUSE_PARAM_BTN_OFF ||
633 x > MOUSE_PARAM_UTF8_MAX - MOUSE_PARAM_POS_OFF ||
634 y > MOUSE_PARAM_UTF8_MAX - MOUSE_PARAM_POS_OFF)
635 return (0);
636 len = xsnprintf(buf, sizeof buf, "\033[M");
637 len += input_key_split2(m->b + MOUSE_PARAM_BTN_OFF, &buf[len]);
638 len += input_key_split2(x + MOUSE_PARAM_POS_OFF, &buf[len]);
639 len += input_key_split2(y + MOUSE_PARAM_POS_OFF, &buf[len]);
640 } else {
641 if (m->b + MOUSE_PARAM_BTN_OFF > MOUSE_PARAM_MAX)
642 return (0);
644 len = xsnprintf(buf, sizeof buf, "\033[M");
645 buf[len++] = m->b + MOUSE_PARAM_BTN_OFF;
648 * The incoming x and y may be out of the range which can be
649 * supported by the "normal" mouse protocol. Clamp the
650 * coordinates to the supported range.
652 if (x + MOUSE_PARAM_POS_OFF > MOUSE_PARAM_MAX)
653 buf[len++] = MOUSE_PARAM_MAX;
654 else
655 buf[len++] = x + MOUSE_PARAM_POS_OFF;
656 if (y + MOUSE_PARAM_POS_OFF > MOUSE_PARAM_MAX)
657 buf[len++] = MOUSE_PARAM_MAX;
658 else
659 buf[len++] = y + MOUSE_PARAM_POS_OFF;
662 *rbuf = buf;
663 *rlen = len;
664 return (1);
667 /* Translate mouse and output. */
668 static void
669 input_key_mouse(struct window_pane *wp, struct mouse_event *m)
671 struct screen *s = wp->screen;
672 u_int x, y;
673 const char *buf;
674 size_t len;
676 /* Ignore events if no mouse mode or the pane is not visible. */
677 if (m->ignore || (s->mode & ALL_MOUSE_MODES) == 0)
678 return;
679 if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
680 return;
681 if (!window_pane_visible(wp))
682 return;
683 if (!input_key_get_mouse(s, m, x, y, &buf, &len))
684 return;
685 log_debug("writing mouse %.*s to %%%u", (int)len, buf, wp->id);
686 input_key_write(__func__, wp->event, buf, len);