xref: /openbsd/usr.bin/tmux/input-keys.c (revision 4bdff4be)
1 /* $OpenBSD: input-keys.c,v 1.94 2023/01/12 18:49:11 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_IC,
99 	  .data = "\033[2~"
100 	},
101 	{ .key = KEYC_DC,
102 	  .data = "\033[3~"
103 	},
104 	{ .key = KEYC_HOME,
105 	  .data = "\033[1~"
106 	},
107 	{ .key = KEYC_END,
108 	  .data = "\033[4~"
109 	},
110 	{ .key = KEYC_NPAGE,
111 	  .data = "\033[6~"
112 	},
113 	{ .key = KEYC_PPAGE,
114 	  .data = "\033[5~"
115 	},
116 	{ .key = KEYC_BTAB,
117 	  .data = "\033[Z"
118 	},
119 
120 	/* Arrow keys. */
121 	{ .key = KEYC_UP|KEYC_CURSOR,
122 	  .data = "\033OA"
123 	},
124 	{ .key = KEYC_DOWN|KEYC_CURSOR,
125 	  .data = "\033OB"
126 	},
127 	{ .key = KEYC_RIGHT|KEYC_CURSOR,
128 	  .data = "\033OC"
129 	},
130 	{ .key = KEYC_LEFT|KEYC_CURSOR,
131 	  .data = "\033OD"
132 	},
133 	{ .key = KEYC_UP,
134 	  .data = "\033[A"
135 	},
136 	{ .key = KEYC_DOWN,
137 	  .data = "\033[B"
138 	},
139 	{ .key = KEYC_RIGHT,
140 	  .data = "\033[C"
141 	},
142 	{ .key = KEYC_LEFT,
143 	  .data = "\033[D"
144 	},
145 
146 	/* Keypad keys. */
147 	{ .key = KEYC_KP_SLASH|KEYC_KEYPAD,
148 	  .data = "\033Oo"
149 	},
150 	{ .key = KEYC_KP_STAR|KEYC_KEYPAD,
151 	  .data = "\033Oj"
152 	},
153 	{ .key = KEYC_KP_MINUS|KEYC_KEYPAD,
154 	  .data = "\033Om"
155 	},
156 	{ .key = KEYC_KP_SEVEN|KEYC_KEYPAD,
157 	  .data = "\033Ow"
158 	},
159 	{ .key = KEYC_KP_EIGHT|KEYC_KEYPAD,
160 	  .data = "\033Ox"
161 	},
162 	{ .key = KEYC_KP_NINE|KEYC_KEYPAD,
163 	  .data = "\033Oy"
164 	},
165 	{ .key = KEYC_KP_PLUS|KEYC_KEYPAD,
166 	  .data = "\033Ok"
167 	},
168 	{ .key = KEYC_KP_FOUR|KEYC_KEYPAD,
169 	  .data = "\033Ot"
170 	},
171 	{ .key = KEYC_KP_FIVE|KEYC_KEYPAD,
172 	  .data = "\033Ou"
173 	},
174 	{ .key = KEYC_KP_SIX|KEYC_KEYPAD,
175 	  .data = "\033Ov"
176 	},
177 	{ .key = KEYC_KP_ONE|KEYC_KEYPAD,
178 	  .data = "\033Oq"
179 	},
180 	{ .key = KEYC_KP_TWO|KEYC_KEYPAD,
181 	  .data = "\033Or"
182 	},
183 	{ .key = KEYC_KP_THREE|KEYC_KEYPAD,
184 	  .data = "\033Os"
185 	},
186 	{ .key = KEYC_KP_ENTER|KEYC_KEYPAD,
187 	  .data = "\033OM"
188 	},
189 	{ .key = KEYC_KP_ZERO|KEYC_KEYPAD,
190 	  .data = "\033Op"
191 	},
192 	{ .key = KEYC_KP_PERIOD|KEYC_KEYPAD,
193 	  .data = "\033On"
194 	},
195 	{ .key = KEYC_KP_SLASH,
196 	  .data = "/"
197 	},
198 	{ .key = KEYC_KP_STAR,
199 	  .data = "*"
200 	},
201 	{ .key = KEYC_KP_MINUS,
202 	  .data = "-"
203 	},
204 	{ .key = KEYC_KP_SEVEN,
205 	  .data = "7"
206 	},
207 	{ .key = KEYC_KP_EIGHT,
208 	  .data = "8"
209 	},
210 	{ .key = KEYC_KP_NINE,
211 	  .data = "9"
212 	},
213 	{ .key = KEYC_KP_PLUS,
214 	  .data = "+"
215 	},
216 	{ .key = KEYC_KP_FOUR,
217 	  .data = "4"
218 	},
219 	{ .key = KEYC_KP_FIVE,
220 	  .data = "5"
221 	},
222 	{ .key = KEYC_KP_SIX,
223 	  .data = "6"
224 	},
225 	{ .key = KEYC_KP_ONE,
226 	  .data = "1"
227 	},
228 	{ .key = KEYC_KP_TWO,
229 	  .data = "2"
230 	},
231 	{ .key = KEYC_KP_THREE,
232 	  .data = "3"
233 	},
234 	{ .key = KEYC_KP_ENTER,
235 	  .data = "\n"
236 	},
237 	{ .key = KEYC_KP_ZERO,
238 	  .data = "0"
239 	},
240 	{ .key = KEYC_KP_PERIOD,
241 	  .data = "."
242 	},
243 
244 	/* Keys with an embedded modifier. */
245 	{ .key = KEYC_F1|KEYC_BUILD_MODIFIERS,
246 	  .data = "\033[1;_P"
247 	},
248 	{ .key = KEYC_F2|KEYC_BUILD_MODIFIERS,
249 	  .data = "\033[1;_Q"
250 	},
251 	{ .key = KEYC_F3|KEYC_BUILD_MODIFIERS,
252 	  .data = "\033[1;_R"
253 	},
254 	{ .key = KEYC_F4|KEYC_BUILD_MODIFIERS,
255 	  .data = "\033[1;_S"
256 	},
257 	{ .key = KEYC_F5|KEYC_BUILD_MODIFIERS,
258 	  .data = "\033[15;_~"
259 	},
260 	{ .key = KEYC_F6|KEYC_BUILD_MODIFIERS,
261 	  .data = "\033[17;_~"
262 	},
263 	{ .key = KEYC_F7|KEYC_BUILD_MODIFIERS,
264 	  .data = "\033[18;_~"
265 	},
266 	{ .key = KEYC_F8|KEYC_BUILD_MODIFIERS,
267 	  .data = "\033[19;_~"
268 	},
269 	{ .key = KEYC_F9|KEYC_BUILD_MODIFIERS,
270 	  .data = "\033[20;_~"
271 	},
272 	{ .key = KEYC_F10|KEYC_BUILD_MODIFIERS,
273 	  .data = "\033[21;_~"
274 	},
275 	{ .key = KEYC_F11|KEYC_BUILD_MODIFIERS,
276 	  .data = "\033[23;_~"
277 	},
278 	{ .key = KEYC_F12|KEYC_BUILD_MODIFIERS,
279 	  .data = "\033[24;_~"
280 	},
281 	{ .key = KEYC_UP|KEYC_BUILD_MODIFIERS,
282 	  .data = "\033[1;_A"
283 	},
284 	{ .key = KEYC_DOWN|KEYC_BUILD_MODIFIERS,
285 	  .data = "\033[1;_B"
286 	},
287 	{ .key = KEYC_RIGHT|KEYC_BUILD_MODIFIERS,
288 	  .data = "\033[1;_C"
289 	},
290 	{ .key = KEYC_LEFT|KEYC_BUILD_MODIFIERS,
291 	  .data = "\033[1;_D"
292 	},
293 	{ .key = KEYC_HOME|KEYC_BUILD_MODIFIERS,
294 	  .data = "\033[1;_H"
295 	},
296 	{ .key = KEYC_END|KEYC_BUILD_MODIFIERS,
297 	  .data = "\033[1;_F"
298 	},
299 	{ .key = KEYC_PPAGE|KEYC_BUILD_MODIFIERS,
300 	  .data = "\033[5;_~"
301 	},
302 	{ .key = KEYC_NPAGE|KEYC_BUILD_MODIFIERS,
303 	  .data = "\033[6;_~"
304 	},
305 	{ .key = KEYC_IC|KEYC_BUILD_MODIFIERS,
306 	  .data = "\033[2;_~"
307 	},
308 	{ .key = KEYC_DC|KEYC_BUILD_MODIFIERS,
309 	  .data = "\033[3;_~"
310 	},
311 
312 	/* Tab and modifiers. */
313 	{ .key = '\011'|KEYC_CTRL,
314 	  .data = "\011"
315 	},
316 	{ .key = '\011'|KEYC_CTRL|KEYC_EXTENDED,
317 	  .data = "\033[9;5u"
318 	},
319 	{ .key = '\011'|KEYC_CTRL|KEYC_SHIFT,
320 	  .data = "\033[Z"
321 	},
322 	{ .key = '\011'|KEYC_CTRL|KEYC_SHIFT|KEYC_EXTENDED,
323 	  .data = "\033[1;5Z"
324 	}
325 };
326 static const key_code input_key_modifiers[] = {
327 	0,
328 	0,
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
336 };
337 
338 /* Input key comparison function. */
339 static int
340 input_key_cmp(struct input_key_entry *ike1, struct input_key_entry *ike2)
341 {
342 	if (ike1->key < ike2->key)
343 		return (-1);
344 	if (ike1->key > ike2->key)
345 		return (1);
346 	return (0);
347 }
348 
349 /* Look for key in tree. */
350 static struct input_key_entry *
351 input_key_get(key_code key)
352 {
353 	struct input_key_entry	entry = { .key = key };
354 
355 	return (RB_FIND(input_key_tree, &input_key_tree, &entry));
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 	key_code		 key;
379 
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;
385 		}
386 
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;
391 
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);
396 		}
397 	}
398 
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);
402 	}
403 }
404 
405 /* Translate a key code into an output key sequence for a pane. */
406 int
407 input_key_pane(struct window_pane *wp, key_code key, struct mouse_event *m)
408 {
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);
412 	}
413 
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);
418 	}
419 	return (input_key(wp->screen, wp->event, key));
420 }
421 
422 static void
423 input_key_write(const char *from, struct bufferevent *bev, const char *data,
424     size_t size)
425 {
426 	log_debug("%s: %.*s", from, (int)size, data);
427 	bufferevent_write(bev, data, size);
428 }
429 
430 /* Translate a key code into an output key sequence. */
431 int
432 input_key(struct screen *s, struct bufferevent *bev, key_code key)
433 {
434 	struct input_key_entry	*ike = NULL;
435 	key_code		 justkey, newkey, outkey, modifiers;
436 	struct utf8_data	 ud;
437 	char			 tmp[64], modifier;
438 
439 	/* Mouse keys need a pane. */
440 	if (KEYC_IS_MOUSE(key))
441 		return (0);
442 
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);
448 	}
449 
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));
456 	}
457 
458 	/*
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.
461 	 */
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);
469 	}
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);
476 	}
477 
478 	/*
479 	 * Look up in the tree. If not in application keypad or cursor mode,
480 	 * remove the flags from the key.
481 	 */
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);
507 	}
508 
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;
540 		}
541 		return (input_key(s, bev, key & ~KEYC_CTRL));
542 	}
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;
548 	}
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;
573 	}
574 	xsnprintf(tmp, sizeof tmp, "\033[%llu;%cu", outkey, modifier);
575 	input_key_write(__func__, bev, tmp, strlen(tmp));
576 	return (0);
577 
578 missing:
579 	log_debug("key 0x%llx missing", key);
580 	return (-1);
581 }
582 
583 /* Get mouse event string. */
584 int
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)
587 {
588 	static char	 buf[40];
589 	size_t		 len;
590 
591 	*rbuf = NULL;
592 	*rlen = 0;
593 
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);
599 
600 	/*
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.
605 	 */
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);
617 	}
618 
619 	/*
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.
627 	 */
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);
643 
644 		len = xsnprintf(buf, sizeof buf, "\033[M");
645 		buf[len++] = m->b + MOUSE_PARAM_BTN_OFF;
646 
647 		/*
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.
651 		 */
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;
660 	}
661 
662 	*rbuf = buf;
663 	*rlen = len;
664 	return (1);
665 }
666 
667 /* Translate mouse and output. */
668 static void
669 input_key_mouse(struct window_pane *wp, struct mouse_event *m)
670 {
671 	struct screen	*s = wp->screen;
672 	u_int		 x, y;
673 	const char	*buf;
674 	size_t		 len;
675 
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);
687 }
688