xref: /netbsd-src/external/bsd/tmux/dist/input-keys.c (revision ccd9df534e375a4366c5b55f23782053c7a98d82)
1 /* $OpenBSD$ */
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 <stdlib.h>
22 #include <string.h>
23 
24 #include "tmux.h"
25 
26 /*
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).
31  */
32 
33 static void	 input_key_mouse(struct window_pane *, struct mouse_event *);
34 
35 /* Entry in the key tree. */
36 struct input_key_entry {
37 	key_code			 key;
38 	const char			*data;
39 
40 	RB_ENTRY(input_key_entry)	 entry;
41 };
42 RB_HEAD(input_key_tree, input_key_entry);
43 
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);
49 
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~"
55 	},
56 	{ .key = KEYC_PASTE_END,
57 	  .data = "\033[201~"
58 	},
59 
60 	/* Function keys. */
61 	{ .key = KEYC_F1,
62 	  .data = "\033OP"
63 	},
64 	{ .key = KEYC_F2,
65 	  .data = "\033OQ"
66 	},
67 	{ .key = KEYC_F3,
68 	  .data = "\033OR"
69 	},
70 	{ .key = KEYC_F4,
71 	  .data = "\033OS"
72 	},
73 	{ .key = KEYC_F5,
74 	  .data = "\033[15~"
75 	},
76 	{ .key = KEYC_F6,
77 	  .data = "\033[17~"
78 	},
79 	{ .key = KEYC_F7,
80 	  .data = "\033[18~"
81 	},
82 	{ .key = KEYC_F8,
83 	  .data = "\033[19~"
84 	},
85 	{ .key = KEYC_F9,
86 	  .data = "\033[20~"
87 	},
88 	{ .key = KEYC_F10,
89 	  .data = "\033[21~"
90 	},
91 	{ .key = KEYC_F11,
92 	  .data = "\033[23~"
93 	},
94 	{ .key = KEYC_F12,
95 	  .data = "\033[24~"
96 	},
97 	{ .key = KEYC_IC,
98 	  .data = "\033[2~"
99 	},
100 	{ .key = KEYC_DC,
101 	  .data = "\033[3~"
102 	},
103 	{ .key = KEYC_HOME,
104 	  .data = "\033[1~"
105 	},
106 	{ .key = KEYC_END,
107 	  .data = "\033[4~"
108 	},
109 	{ .key = KEYC_NPAGE,
110 	  .data = "\033[6~"
111 	},
112 	{ .key = KEYC_PPAGE,
113 	  .data = "\033[5~"
114 	},
115 	{ .key = KEYC_BTAB,
116 	  .data = "\033[Z"
117 	},
118 
119 	/* Arrow keys. */
120 	{ .key = KEYC_UP|KEYC_CURSOR,
121 	  .data = "\033OA"
122 	},
123 	{ .key = KEYC_DOWN|KEYC_CURSOR,
124 	  .data = "\033OB"
125 	},
126 	{ .key = KEYC_RIGHT|KEYC_CURSOR,
127 	  .data = "\033OC"
128 	},
129 	{ .key = KEYC_LEFT|KEYC_CURSOR,
130 	  .data = "\033OD"
131 	},
132 	{ .key = KEYC_UP,
133 	  .data = "\033[A"
134 	},
135 	{ .key = KEYC_DOWN,
136 	  .data = "\033[B"
137 	},
138 	{ .key = KEYC_RIGHT,
139 	  .data = "\033[C"
140 	},
141 	{ .key = KEYC_LEFT,
142 	  .data = "\033[D"
143 	},
144 
145 	/* Keypad keys. */
146 	{ .key = KEYC_KP_SLASH|KEYC_KEYPAD,
147 	  .data = "\033Oo"
148 	},
149 	{ .key = KEYC_KP_STAR|KEYC_KEYPAD,
150 	  .data = "\033Oj"
151 	},
152 	{ .key = KEYC_KP_MINUS|KEYC_KEYPAD,
153 	  .data = "\033Om"
154 	},
155 	{ .key = KEYC_KP_SEVEN|KEYC_KEYPAD,
156 	  .data = "\033Ow"
157 	},
158 	{ .key = KEYC_KP_EIGHT|KEYC_KEYPAD,
159 	  .data = "\033Ox"
160 	},
161 	{ .key = KEYC_KP_NINE|KEYC_KEYPAD,
162 	  .data = "\033Oy"
163 	},
164 	{ .key = KEYC_KP_PLUS|KEYC_KEYPAD,
165 	  .data = "\033Ok"
166 	},
167 	{ .key = KEYC_KP_FOUR|KEYC_KEYPAD,
168 	  .data = "\033Ot"
169 	},
170 	{ .key = KEYC_KP_FIVE|KEYC_KEYPAD,
171 	  .data = "\033Ou"
172 	},
173 	{ .key = KEYC_KP_SIX|KEYC_KEYPAD,
174 	  .data = "\033Ov"
175 	},
176 	{ .key = KEYC_KP_ONE|KEYC_KEYPAD,
177 	  .data = "\033Oq"
178 	},
179 	{ .key = KEYC_KP_TWO|KEYC_KEYPAD,
180 	  .data = "\033Or"
181 	},
182 	{ .key = KEYC_KP_THREE|KEYC_KEYPAD,
183 	  .data = "\033Os"
184 	},
185 	{ .key = KEYC_KP_ENTER|KEYC_KEYPAD,
186 	  .data = "\033OM"
187 	},
188 	{ .key = KEYC_KP_ZERO|KEYC_KEYPAD,
189 	  .data = "\033Op"
190 	},
191 	{ .key = KEYC_KP_PERIOD|KEYC_KEYPAD,
192 	  .data = "\033On"
193 	},
194 	{ .key = KEYC_KP_SLASH,
195 	  .data = "/"
196 	},
197 	{ .key = KEYC_KP_STAR,
198 	  .data = "*"
199 	},
200 	{ .key = KEYC_KP_MINUS,
201 	  .data = "-"
202 	},
203 	{ .key = KEYC_KP_SEVEN,
204 	  .data = "7"
205 	},
206 	{ .key = KEYC_KP_EIGHT,
207 	  .data = "8"
208 	},
209 	{ .key = KEYC_KP_NINE,
210 	  .data = "9"
211 	},
212 	{ .key = KEYC_KP_PLUS,
213 	  .data = "+"
214 	},
215 	{ .key = KEYC_KP_FOUR,
216 	  .data = "4"
217 	},
218 	{ .key = KEYC_KP_FIVE,
219 	  .data = "5"
220 	},
221 	{ .key = KEYC_KP_SIX,
222 	  .data = "6"
223 	},
224 	{ .key = KEYC_KP_ONE,
225 	  .data = "1"
226 	},
227 	{ .key = KEYC_KP_TWO,
228 	  .data = "2"
229 	},
230 	{ .key = KEYC_KP_THREE,
231 	  .data = "3"
232 	},
233 	{ .key = KEYC_KP_ENTER,
234 	  .data = "\n"
235 	},
236 	{ .key = KEYC_KP_ZERO,
237 	  .data = "0"
238 	},
239 	{ .key = KEYC_KP_PERIOD,
240 	  .data = "."
241 	},
242 
243 	/* Keys with an embedded modifier. */
244 	{ .key = KEYC_F1|KEYC_BUILD_MODIFIERS,
245 	  .data = "\033[1;_P"
246 	},
247 	{ .key = KEYC_F2|KEYC_BUILD_MODIFIERS,
248 	  .data = "\033[1;_Q"
249 	},
250 	{ .key = KEYC_F3|KEYC_BUILD_MODIFIERS,
251 	  .data = "\033[1;_R"
252 	},
253 	{ .key = KEYC_F4|KEYC_BUILD_MODIFIERS,
254 	  .data = "\033[1;_S"
255 	},
256 	{ .key = KEYC_F5|KEYC_BUILD_MODIFIERS,
257 	  .data = "\033[15;_~"
258 	},
259 	{ .key = KEYC_F6|KEYC_BUILD_MODIFIERS,
260 	  .data = "\033[17;_~"
261 	},
262 	{ .key = KEYC_F7|KEYC_BUILD_MODIFIERS,
263 	  .data = "\033[18;_~"
264 	},
265 	{ .key = KEYC_F8|KEYC_BUILD_MODIFIERS,
266 	  .data = "\033[19;_~"
267 	},
268 	{ .key = KEYC_F9|KEYC_BUILD_MODIFIERS,
269 	  .data = "\033[20;_~"
270 	},
271 	{ .key = KEYC_F10|KEYC_BUILD_MODIFIERS,
272 	  .data = "\033[21;_~"
273 	},
274 	{ .key = KEYC_F11|KEYC_BUILD_MODIFIERS,
275 	  .data = "\033[23;_~"
276 	},
277 	{ .key = KEYC_F12|KEYC_BUILD_MODIFIERS,
278 	  .data = "\033[24;_~"
279 	},
280 	{ .key = KEYC_UP|KEYC_BUILD_MODIFIERS,
281 	  .data = "\033[1;_A"
282 	},
283 	{ .key = KEYC_DOWN|KEYC_BUILD_MODIFIERS,
284 	  .data = "\033[1;_B"
285 	},
286 	{ .key = KEYC_RIGHT|KEYC_BUILD_MODIFIERS,
287 	  .data = "\033[1;_C"
288 	},
289 	{ .key = KEYC_LEFT|KEYC_BUILD_MODIFIERS,
290 	  .data = "\033[1;_D"
291 	},
292 	{ .key = KEYC_HOME|KEYC_BUILD_MODIFIERS,
293 	  .data = "\033[1;_H"
294 	},
295 	{ .key = KEYC_END|KEYC_BUILD_MODIFIERS,
296 	  .data = "\033[1;_F"
297 	},
298 	{ .key = KEYC_PPAGE|KEYC_BUILD_MODIFIERS,
299 	  .data = "\033[5;_~"
300 	},
301 	{ .key = KEYC_NPAGE|KEYC_BUILD_MODIFIERS,
302 	  .data = "\033[6;_~"
303 	},
304 	{ .key = KEYC_IC|KEYC_BUILD_MODIFIERS,
305 	  .data = "\033[2;_~"
306 	},
307 	{ .key = KEYC_DC|KEYC_BUILD_MODIFIERS,
308 	  .data = "\033[3;_~"
309 	},
310 
311 	/* Tab and modifiers. */
312 	{ .key = '\011'|KEYC_CTRL,
313 	  .data = "\011"
314 	},
315 	{ .key = '\011'|KEYC_CTRL|KEYC_EXTENDED,
316 	  .data = "\033[9;5u"
317 	},
318 	{ .key = '\011'|KEYC_CTRL|KEYC_SHIFT,
319 	  .data = "\033[Z"
320 	},
321 	{ .key = '\011'|KEYC_CTRL|KEYC_SHIFT|KEYC_EXTENDED,
322 	  .data = "\033[1;5Z"
323 	}
324 };
325 static const key_code input_key_modifiers[] = {
326 	0,
327 	0,
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
335 };
336 
337 /* Input key comparison function. */
338 static int
339 input_key_cmp(struct input_key_entry *ike1, struct input_key_entry *ike2)
340 {
341 	if (ike1->key < ike2->key)
342 		return (-1);
343 	if (ike1->key > ike2->key)
344 		return (1);
345 	return (0);
346 }
347 
348 /* Look for key in tree. */
349 static struct input_key_entry *
350 input_key_get(key_code key)
351 {
352 	struct input_key_entry	entry = { .key = key };
353 
354 	return (RB_FIND(input_key_tree, &input_key_tree, &entry));
355 }
356 
357 /* Split a character into two UTF-8 bytes. */
358 static size_t
359 input_key_split2(u_int c, char *dst)
360 {
361 	if (c > 0x7f) {
362 		dst[0] = (c >> 6) | 0xc0;
363 		dst[1] = (c & 0x3f) | 0x80;
364 		return (2);
365 	}
366 	dst[0] = c;
367 	return (1);
368 }
369 
370 /* Build input key tree. */
371 void
372 input_key_build(void)
373 {
374 	struct input_key_entry	*ike, *new;
375 	u_int			 i, j;
376 	char			*data;
377 	key_code		 key;
378 
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;
384 		}
385 
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;
390 
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);
395 		}
396 	}
397 
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);
401 	}
402 }
403 
404 /* Translate a key code into an output key sequence for a pane. */
405 int
406 input_key_pane(struct window_pane *wp, key_code key, struct mouse_event *m)
407 {
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);
411 	}
412 
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);
417 	}
418 	return (input_key(wp->screen, wp->event, key));
419 }
420 
421 static void
422 input_key_write(const char *from, struct bufferevent *bev, const char *data,
423     size_t size)
424 {
425 	log_debug("%s: %.*s", from, (int)size, (const char *)data);
426 	bufferevent_write(bev, data, size);
427 }
428 
429 /* Translate a key code into an output key sequence. */
430 int
431 input_key(struct screen *s, struct bufferevent *bev, key_code key)
432 {
433 	struct input_key_entry	*ike = NULL;
434 	key_code		 justkey, newkey, outkey, modifiers;
435 	struct utf8_data	 ud;
436 	char			 tmp[64], modifier;
437 
438 	/* Mouse keys need a pane. */
439 	if (KEYC_IS_MOUSE(key))
440 		return (0);
441 
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, (const char *)ud.data, 1);
446 		return (0);
447 	}
448 
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));
455 	}
456 
457 	/*
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.
460 	 */
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, (const char *)ud.data, 1);
467 		return (0);
468 	}
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, (const char *)ud.data, ud.size);
474 		return (0);
475 	}
476 
477 	/*
478 	 * Look up in the tree. If not in application keypad or cursor mode,
479 	 * remove the flags from the key.
480 	 */
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);
506 	}
507 
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;
539 		}
540 		return (input_key(s, bev, key & ~KEYC_CTRL));
541 	}
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;
547 	}
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;
572 	}
573 	xsnprintf(tmp, sizeof tmp, "\033[%llu;%cu", outkey, modifier);
574 	input_key_write(__func__, bev, tmp, strlen(tmp));
575 	return (0);
576 
577 missing:
578 	log_debug("key 0x%llx missing", key);
579 	return (-1);
580 }
581 
582 /* Get mouse event string. */
583 int
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)
586 {
587 	static char	 buf[40];
588 	size_t		 len;
589 
590 	*rbuf = NULL;
591 	*rlen = 0;
592 
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);
598 
599 	/*
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.
604 	 */
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);
616 	}
617 
618 	/*
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.
626 	 */
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);
642 
643 		len = xsnprintf(buf, sizeof buf, "\033[M");
644 		buf[len++] = m->b + MOUSE_PARAM_BTN_OFF;
645 
646 		/*
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.
650 		 */
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;
659 	}
660 
661 	*rbuf = buf;
662 	*rlen = len;
663 	return (1);
664 }
665 
666 /* Translate mouse and output. */
667 static void
668 input_key_mouse(struct window_pane *wp, struct mouse_event *m)
669 {
670 	struct screen	*s = wp->screen;
671 	u_int		 x, y;
672 	const char	*buf;
673 	size_t		 len;
674 
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);
686 }
687