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
34static void	 input_key_mouse(struct window_pane *, struct mouse_event *);
35
36/* Entry in the key tree. */
37struct input_key_entry {
38	key_code			 key;
39	const char			*data;
40
41	RB_ENTRY(input_key_entry)	 entry;
42};
43RB_HEAD(input_key_tree, input_key_entry);
44
45/* Tree of input keys. */
46static int	input_key_cmp(struct input_key_entry *,
47		    struct input_key_entry *);
48RB_GENERATE_STATIC(input_key_tree, input_key_entry, entry, input_key_cmp);
49struct input_key_tree input_key_tree = RB_INITIALIZER(&input_key_tree);
50
51/* List of default keys, the tree is built from this. */
52static 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};
326static 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. */
339static int
340input_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. */
350static struct input_key_entry *
351input_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. */
359static size_t
360input_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. */
372void
373input_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. */
406int
407input_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
422static void
423input_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. */
431int
432input_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
578missing:
579	log_debug("key 0x%llx missing", key);
580	return (-1);
581}
582
583/* Get mouse event string. */
584int
585input_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. */
668static void
669input_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