xref: /openbsd-src/usr.bin/tmux/input-keys.c (revision 6a385b806c1d3aed7ff36d45d5052d902365e86a)
1 /* $OpenBSD: input-keys.c,v 1.73 2020/05/16 16:33:16 nicm Exp $ */
2 
3 /*
4  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
5  *
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.
9  *
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.
17  */
18 
19 #include <sys/types.h>
20 
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include "tmux.h"
26 
27 /*
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).
32  */
33 
34 static void	 input_key_mouse(struct window_pane *, struct mouse_event *);
35 
36 /* Entry in the key tree. */
37 struct input_key_entry {
38 	key_code			 key;
39 	const char			*data;
40 
41 	RB_ENTRY(input_key_entry)	 entry;
42 };
43 RB_HEAD(input_key_tree, input_key_entry);
44 
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);
50 
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~"
56 	},
57 	{ .key = KEYC_PASTE_END,
58 	  .data = "\033[201~"
59 	},
60 
61 	/* Function keys. */
62 	{ .key = KEYC_F1,
63 	  .data = "\033OP"
64 	},
65 	{ .key = KEYC_F2,
66 	  .data = "\033OQ"
67 	},
68 	{ .key = KEYC_F3,
69 	  .data = "\033OR"
70 	},
71 	{ .key = KEYC_F4,
72 	  .data = "\033OS"
73 	},
74 	{ .key = KEYC_F5,
75 	  .data = "\033[15~"
76 	},
77 	{ .key = KEYC_F6,
78 	  .data = "\033[17~"
79 	},
80 	{ .key = KEYC_F7,
81 	  .data = "\033[18~"
82 	},
83 	{ .key = KEYC_F8,
84 	  .data = "\033[19~"
85 	},
86 	{ .key = KEYC_F9,
87 	  .data = "\033[20~"
88 	},
89 	{ .key = KEYC_F10,
90 	  .data = "\033[21~"
91 	},
92 	{ .key = KEYC_F11,
93 	  .data = "\033[23~"
94 	},
95 	{ .key = KEYC_F12,
96 	  .data = "\033[24~"
97 	},
98 	{ .key = KEYC_F1|KEYC_SHIFT,
99 	  .data = "\033[25~"
100 	},
101 	{ .key = KEYC_F2|KEYC_SHIFT,
102 	  .data = "\033[26~"
103 	},
104 	{ .key = KEYC_F3|KEYC_SHIFT,
105 	  .data = "\033[28~"
106 	},
107 	{ .key = KEYC_F4|KEYC_SHIFT,
108 	  .data = "\033[29~"
109 	},
110 	{ .key = KEYC_F5|KEYC_SHIFT,
111 	  .data = "\033[31~"
112 	},
113 	{ .key = KEYC_F6|KEYC_SHIFT,
114 	  .data = "\033[32~"
115 	},
116 	{ .key = KEYC_F7|KEYC_SHIFT,
117 	  .data = "\033[33~"
118 	},
119 	{ .key = KEYC_F8|KEYC_SHIFT,
120 	  .data = "\033[34~"
121 	},
122 	{ .key = KEYC_IC,
123 	  .data = "\033[2~"
124 	},
125 	{ .key = KEYC_DC,
126 	  .data = "\033[3~"
127 	},
128 	{ .key = KEYC_HOME,
129 	  .data = "\033[1~"
130 	},
131 	{ .key = KEYC_END,
132 	  .data = "\033[4~"
133 	},
134 	{ .key = KEYC_NPAGE,
135 	  .data = "\033[6~"
136 	},
137 	{ .key = KEYC_PPAGE,
138 	  .data = "\033[5~"
139 	},
140 	{ .key = KEYC_BTAB,
141 	  .data = "\033[Z"
142 	},
143 
144 	/* Arrow keys. */
145 	{ .key = KEYC_UP|KEYC_CURSOR,
146 	  .data = "\033OA"
147 	},
148 	{ .key = KEYC_DOWN|KEYC_CURSOR,
149 	  .data = "\033OB"
150 	},
151 	{ .key = KEYC_RIGHT|KEYC_CURSOR,
152 	  .data = "\033OC"
153 	},
154 	{ .key = KEYC_LEFT|KEYC_CURSOR,
155 	  .data = "\033OD"
156 	},
157 	{ .key = KEYC_UP,
158 	  .data = "\033[A"
159 	},
160 	{ .key = KEYC_DOWN,
161 	  .data = "\033[B"
162 	},
163 	{ .key = KEYC_RIGHT,
164 	  .data = "\033[C"
165 	},
166 	{ .key = KEYC_LEFT,
167 	  .data = "\033[D"
168 	},
169 
170 	/* Keypad keys. */
171 	{ .key = KEYC_KP_SLASH|KEYC_KEYPAD,
172 	  .data = "\033Oo"
173 	},
174 	{ .key = KEYC_KP_STAR|KEYC_KEYPAD,
175 	  .data = "\033Oj"
176 	},
177 	{ .key = KEYC_KP_MINUS|KEYC_KEYPAD,
178 	  .data = "\033Om"
179 	},
180 	{ .key = KEYC_KP_SEVEN|KEYC_KEYPAD,
181 	  .data = "\033Ow"
182 	},
183 	{ .key = KEYC_KP_EIGHT|KEYC_KEYPAD,
184 	  .data = "\033Ox"
185 	},
186 	{ .key = KEYC_KP_NINE|KEYC_KEYPAD,
187 	  .data = "\033Oy"
188 	},
189 	{ .key = KEYC_KP_PLUS|KEYC_KEYPAD,
190 	  .data = "\033Ok"
191 	},
192 	{ .key = KEYC_KP_FOUR|KEYC_KEYPAD,
193 	  .data = "\033Ot"
194 	},
195 	{ .key = KEYC_KP_FIVE|KEYC_KEYPAD,
196 	  .data = "\033Ou"
197 	},
198 	{ .key = KEYC_KP_SIX|KEYC_KEYPAD,
199 	  .data = "\033Ov"
200 	},
201 	{ .key = KEYC_KP_ONE|KEYC_KEYPAD,
202 	  .data = "\033Oq"
203 	},
204 	{ .key = KEYC_KP_TWO|KEYC_KEYPAD,
205 	  .data = "\033Or"
206 	},
207 	{ .key = KEYC_KP_THREE|KEYC_KEYPAD,
208 	  .data = "\033Os"
209 	},
210 	{ .key = KEYC_KP_ENTER|KEYC_KEYPAD,
211 	  .data = "\033OM"
212 	},
213 	{ .key = KEYC_KP_ZERO|KEYC_KEYPAD,
214 	  .data = "\033Op"
215 	},
216 	{ .key = KEYC_KP_PERIOD|KEYC_KEYPAD,
217 	  .data = "\033On"
218 	},
219 	{ .key = KEYC_KP_SLASH,
220 	  .data = "/"
221 	},
222 	{ .key = KEYC_KP_STAR,
223 	  .data = "*"
224 	},
225 	{ .key = KEYC_KP_MINUS,
226 	  .data = "-"
227 	},
228 	{ .key = KEYC_KP_SEVEN,
229 	  .data = "7"
230 	},
231 	{ .key = KEYC_KP_EIGHT,
232 	  .data = "8"
233 	},
234 	{ .key = KEYC_KP_NINE,
235 	  .data = "9"
236 	},
237 	{ .key = KEYC_KP_PLUS,
238 	  .data = "+"
239 	},
240 	{ .key = KEYC_KP_FOUR,
241 	  .data = "4"
242 	},
243 	{ .key = KEYC_KP_FIVE,
244 	  .data = "5"
245 	},
246 	{ .key = KEYC_KP_SIX,
247 	  .data = "6"
248 	},
249 	{ .key = KEYC_KP_ONE,
250 	  .data = "1"
251 	},
252 	{ .key = KEYC_KP_TWO,
253 	  .data = "2"
254 	},
255 	{ .key = KEYC_KP_THREE,
256 	  .data = "3"
257 	},
258 	{ .key = KEYC_KP_ENTER,
259 	  .data = "\n"
260 	},
261 	{ .key = KEYC_KP_ZERO,
262 	  .data = "0"
263 	},
264 	{ .key = KEYC_KP_PERIOD,
265 	  .data = "."
266 	},
267 
268 	/* Keys with an embedded modifier. */
269 	{ .key = KEYC_F1|KEYC_XTERM,
270 	  .data = "\033[1;_P"
271 	},
272 	{ .key = KEYC_F2|KEYC_XTERM,
273 	  .data = "\033[1;_Q"
274 	},
275 	{ .key = KEYC_F3|KEYC_XTERM,
276 	  .data = "\033[1;_R"
277 	},
278 	{ .key = KEYC_F4|KEYC_XTERM,
279 	  .data = "\033[1;_S"
280 	},
281 	{ .key = KEYC_F5|KEYC_XTERM,
282 	  .data = "\033[15;_~"
283 	},
284 	{ .key = KEYC_F6|KEYC_XTERM,
285 	  .data = "\033[17;_~"
286 	},
287 	{ .key = KEYC_F7|KEYC_XTERM,
288 	  .data = "\033[18;_~"
289 	},
290 	{ .key = KEYC_F8|KEYC_XTERM,
291 	  .data = "\033[19;_~"
292 	},
293 	{ .key = KEYC_F9|KEYC_XTERM,
294 	  .data = "\033[20;_~"
295 	},
296 	{ .key = KEYC_F10|KEYC_XTERM,
297 	  .data = "\033[21;_~"
298 	},
299 	{ .key = KEYC_F11|KEYC_XTERM,
300 	  .data = "\033[23;_~"
301 	},
302 	{ .key = KEYC_F12|KEYC_XTERM,
303 	  .data = "\033[24;_~"
304 	},
305 	{ .key = KEYC_UP|KEYC_XTERM,
306 	  .data = "\033[1;_A"
307 	},
308 	{ .key = KEYC_DOWN|KEYC_XTERM,
309 	  .data = "\033[1;_B"
310 	},
311 	{ .key = KEYC_RIGHT|KEYC_XTERM,
312 	  .data = "\033[1;_C"
313 	},
314 	{ .key = KEYC_LEFT|KEYC_XTERM,
315 	  .data = "\033[1;_D"
316 	},
317 	{ .key = KEYC_HOME|KEYC_XTERM,
318 	  .data = "\033[1;_H"
319 	},
320 	{ .key = KEYC_END|KEYC_XTERM,
321 	  .data = "\033[1;_F"
322 	},
323 	{ .key = KEYC_PPAGE|KEYC_XTERM,
324 	  .data = "\033[5;_~"
325 	},
326 	{ .key = KEYC_NPAGE|KEYC_XTERM,
327 	  .data = "\033[6;_~"
328 	},
329 	{ .key = KEYC_IC|KEYC_XTERM,
330 	  .data = "\033[2;_~"
331 	},
332 	{ .key = KEYC_DC|KEYC_XTERM,
333 	  .data = "\033[3;_~" }
334 };
335 static const key_code input_key_modifiers[] = {
336 	0,
337 	0,
338 	KEYC_SHIFT|KEYC_XTERM,
339 	KEYC_META|KEYC_XTERM,
340 	KEYC_SHIFT|KEYC_META|KEYC_XTERM,
341 	KEYC_CTRL|KEYC_XTERM,
342 	KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM,
343 	KEYC_META|KEYC_CTRL|KEYC_XTERM,
344 	KEYC_SHIFT|KEYC_META|KEYC_CTRL|KEYC_XTERM
345 };
346 
347 /* Input key comparison function. */
348 static int
349 input_key_cmp(struct input_key_entry *ike1, struct input_key_entry *ike2)
350 {
351 	if (ike1->key < ike2->key)
352 		return (-1);
353 	if (ike1->key > ike2->key)
354 		return (1);
355 	return (0);
356 }
357 
358 /* Split a character into two UTF-8 bytes. */
359 static size_t
360 input_key_split2(u_int c, u_char *dst)
361 {
362 	if (c > 0x7f) {
363 		dst[0] = (c >> 6) | 0xc0;
364 		dst[1] = (c & 0x3f) | 0x80;
365 		return (2);
366 	}
367 	dst[0] = c;
368 	return (1);
369 }
370 
371 /* Build input key tree. */
372 void
373 input_key_build(void)
374 {
375 	struct input_key_entry	*ike, *new;
376 	u_int			 i, j;
377 	char			*data;
378 
379 	for (i = 0; i < nitems(input_key_defaults); i++) {
380 		ike = &input_key_defaults[i];
381 		if (~ike->key & KEYC_XTERM) {
382 			RB_INSERT(input_key_tree, &input_key_tree, ike);
383 			continue;
384 		}
385 
386 		for (j = 2; j < nitems(input_key_modifiers); j++) {
387 			data = xstrdup(ike->data);
388 			data[strcspn(data, "_")] = '0' + j;
389 
390 			new = xcalloc(1, sizeof *new);
391 			new->key = ike->key|input_key_modifiers[j];
392 			new->data = data;
393 			RB_INSERT(input_key_tree, &input_key_tree, new);
394 		}
395 	}
396 
397 	RB_FOREACH(ike, input_key_tree, &input_key_tree) {
398 		log_debug("%s: 0x%llx (%s) is %s", __func__, ike->key,
399 		    key_string_lookup_key(ike->key), ike->data);
400 	}
401 }
402 
403 /* Translate a key code into an output key sequence for a pane. */
404 int
405 input_key_pane(struct window_pane *wp, key_code key, struct mouse_event *m)
406 {
407 	if (log_get_level() != 0) {
408 		log_debug("writing key 0x%llx (%s) to %%%u", key,
409 		    key_string_lookup_key(key), wp->id);
410 	}
411 
412 	if (KEYC_IS_MOUSE(key)) {
413 		if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id)
414 			input_key_mouse(wp, m);
415 		return (0);
416 	}
417 	return (input_key(wp->screen, wp->event, key));
418 }
419 
420 /* Translate a key code into an output key sequence. */
421 int
422 input_key(struct screen *s, struct bufferevent *bev, key_code key)
423 {
424 	struct input_key_entry	*ike, entry;
425 	size_t			 datalen;
426 	key_code		 justkey, newkey;
427 	struct utf8_data	 ud;
428 
429 	/* Mouse keys need a pane. */
430 	if (KEYC_IS_MOUSE(key))
431 		return (0);
432 
433 	/* Literal keys go as themselves (can't be more than eight bits). */
434 	if (key & KEYC_LITERAL) {
435 		ud.data[0] = (u_char)key;
436 		bufferevent_write(bev, &ud.data[0], 1);
437 		return (0);
438 	}
439 
440 	/* Is this backspace? */
441 	if ((key & KEYC_MASK_KEY) == KEYC_BSPACE) {
442 		newkey = options_get_number(global_options, "backspace");
443 		if (newkey >= 0x7f)
444 			newkey = '\177';
445 		key = newkey|(key & KEYC_MASK_MOD);
446 	}
447 
448 	/*
449 	 * If this is a normal 7-bit key, just send it, with a leading escape
450 	 * if necessary. If it is a UTF-8 key, split it and send it.
451 	 */
452 	justkey = (key & ~(KEYC_XTERM|KEYC_META));
453 	if (justkey <= 0x7f) {
454 		if (key & KEYC_META)
455 			bufferevent_write(bev, "\033", 1);
456 		ud.data[0] = justkey;
457 		bufferevent_write(bev, &ud.data[0], 1);
458 		return (0);
459 	}
460 	if (justkey > 0x7f && justkey < KEYC_BASE) {
461 		if (utf8_split(justkey, &ud) != UTF8_DONE)
462 			return (-1);
463 		if (key & KEYC_META)
464 			bufferevent_write(bev, "\033", 1);
465 		bufferevent_write(bev, ud.data, ud.size);
466 		return (0);
467 	}
468 
469 	/*
470 	 * Look up in the tree. If not in application keypad or cursor mode,
471 	 * remove the flags from the key.
472 	 */
473 	if (~s->mode & MODE_KKEYPAD)
474 		key &= ~KEYC_KEYPAD;
475 	if (~s->mode & MODE_KCURSOR)
476 		key &= ~KEYC_CURSOR;
477 	entry.key = key;
478 	if ((ike = RB_FIND(input_key_tree, &input_key_tree, &entry)) == NULL) {
479 		log_debug("key 0x%llx missing", key);
480 		return (-1);
481 	}
482 	datalen = strlen(ike->data);
483 	log_debug("found key 0x%llx: \"%s\"", key, ike->data);
484 
485 	/* Prefix a \033 for escape. */
486 	if (key & KEYC_META)
487 		bufferevent_write(bev, "\033", 1);
488 	bufferevent_write(bev, ike->data, datalen);
489 	return (0);
490 }
491 
492 /* Get mouse event string. */
493 int
494 input_key_get_mouse(struct screen *s, struct mouse_event *m, u_int x, u_int y,
495     const char **rbuf, size_t *rlen)
496 {
497 	static char	 buf[40];
498 	size_t		 len;
499 
500 	*rbuf = NULL;
501 	*rlen = 0;
502 
503 	/* If this pane is not in button or all mode, discard motion events. */
504 	if (MOUSE_DRAG(m->b) && (s->mode & MOTION_MOUSE_MODES) == 0)
505 		return (0);
506 	if ((s->mode & ALL_MOUSE_MODES) == 0)
507 		return (0);
508 
509 	/*
510 	 * If this event is a release event and not in all mode, discard it.
511 	 * In SGR mode we can tell absolutely because a release is normally
512 	 * shown by the last character. Without SGR, we check if the last
513 	 * buttons was also a release.
514 	 */
515 	if (m->sgr_type != ' ') {
516 		if (MOUSE_DRAG(m->sgr_b) &&
517 		    MOUSE_BUTTONS(m->sgr_b) == 3 &&
518 		    (~s->mode & MODE_MOUSE_ALL))
519 			return (0);
520 	} else {
521 		if (MOUSE_DRAG(m->b) &&
522 		    MOUSE_BUTTONS(m->b) == 3 &&
523 		    MOUSE_BUTTONS(m->lb) == 3 &&
524 		    (~s->mode & MODE_MOUSE_ALL))
525 			return (0);
526 	}
527 
528 	/*
529 	 * Use the SGR (1006) extension only if the application requested it
530 	 * and the underlying terminal also sent the event in this format (this
531 	 * is because an old style mouse release event cannot be converted into
532 	 * the new SGR format, since the released button is unknown). Otherwise
533 	 * pretend that tmux doesn't speak this extension, and fall back to the
534 	 * UTF-8 (1005) extension if the application requested, or to the
535 	 * legacy format.
536 	 */
537 	if (m->sgr_type != ' ' && (s->mode & MODE_MOUSE_SGR)) {
538 		len = xsnprintf(buf, sizeof buf, "\033[<%u;%u;%u%c",
539 		    m->sgr_b, x + 1, y + 1, m->sgr_type);
540 	} else if (s->mode & MODE_MOUSE_UTF8) {
541 		if (m->b > 0x7ff - 32 || x > 0x7ff - 33 || y > 0x7ff - 33)
542 			return (0);
543 		len = xsnprintf(buf, sizeof buf, "\033[M");
544 		len += input_key_split2(m->b + 32, &buf[len]);
545 		len += input_key_split2(x + 33, &buf[len]);
546 		len += input_key_split2(y + 33, &buf[len]);
547 	} else {
548 		if (m->b > 223)
549 			return (0);
550 		len = xsnprintf(buf, sizeof buf, "\033[M");
551 		buf[len++] = m->b + 32;
552 		buf[len++] = x + 33;
553 		buf[len++] = y + 33;
554 	}
555 
556 	*rbuf = buf;
557 	*rlen = len;
558 	return (1);
559 }
560 
561 /* Translate mouse and output. */
562 static void
563 input_key_mouse(struct window_pane *wp, struct mouse_event *m)
564 {
565 	struct screen	*s = wp->screen;
566 	u_int		 x, y;
567 	const char	*buf;
568 	size_t		 len;
569 
570 	/* Ignore events if no mouse mode or the pane is not visible. */
571 	if (m->ignore || (s->mode & ALL_MOUSE_MODES) == 0)
572 		return;
573 	if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
574 		return;
575 	if (!window_pane_visible(wp))
576 		return;
577 	if (!input_key_get_mouse(s, m, x, y, &buf, &len))
578 		return;
579 	log_debug("writing mouse %.*s to %%%u", (int)len, buf, wp->id);
580 	bufferevent_write(wp->event, buf, len);
581 }
582