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>
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
{
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
[] = {
54 { .key
= KEYC_PASTE_START
,
57 { .key
= KEYC_PASTE_END
,
121 { .key
= KEYC_UP
|KEYC_CURSOR
,
124 { .key
= KEYC_DOWN
|KEYC_CURSOR
,
127 { .key
= KEYC_RIGHT
|KEYC_CURSOR
,
130 { .key
= KEYC_LEFT
|KEYC_CURSOR
,
147 { .key
= KEYC_KP_SLASH
|KEYC_KEYPAD
,
150 { .key
= KEYC_KP_STAR
|KEYC_KEYPAD
,
153 { .key
= KEYC_KP_MINUS
|KEYC_KEYPAD
,
156 { .key
= KEYC_KP_SEVEN
|KEYC_KEYPAD
,
159 { .key
= KEYC_KP_EIGHT
|KEYC_KEYPAD
,
162 { .key
= KEYC_KP_NINE
|KEYC_KEYPAD
,
165 { .key
= KEYC_KP_PLUS
|KEYC_KEYPAD
,
168 { .key
= KEYC_KP_FOUR
|KEYC_KEYPAD
,
171 { .key
= KEYC_KP_FIVE
|KEYC_KEYPAD
,
174 { .key
= KEYC_KP_SIX
|KEYC_KEYPAD
,
177 { .key
= KEYC_KP_ONE
|KEYC_KEYPAD
,
180 { .key
= KEYC_KP_TWO
|KEYC_KEYPAD
,
183 { .key
= KEYC_KP_THREE
|KEYC_KEYPAD
,
186 { .key
= KEYC_KP_ENTER
|KEYC_KEYPAD
,
189 { .key
= KEYC_KP_ZERO
|KEYC_KEYPAD
,
192 { .key
= KEYC_KP_PERIOD
|KEYC_KEYPAD
,
195 { .key
= KEYC_KP_SLASH
,
198 { .key
= KEYC_KP_STAR
,
201 { .key
= KEYC_KP_MINUS
,
204 { .key
= KEYC_KP_SEVEN
,
207 { .key
= KEYC_KP_EIGHT
,
210 { .key
= KEYC_KP_NINE
,
213 { .key
= KEYC_KP_PLUS
,
216 { .key
= KEYC_KP_FOUR
,
219 { .key
= KEYC_KP_FIVE
,
222 { .key
= KEYC_KP_SIX
,
225 { .key
= KEYC_KP_ONE
,
228 { .key
= KEYC_KP_TWO
,
231 { .key
= KEYC_KP_THREE
,
234 { .key
= KEYC_KP_ENTER
,
237 { .key
= KEYC_KP_ZERO
,
240 { .key
= KEYC_KP_PERIOD
,
244 /* Keys with an embedded modifier. */
245 { .key
= KEYC_F1
|KEYC_BUILD_MODIFIERS
,
248 { .key
= KEYC_F2
|KEYC_BUILD_MODIFIERS
,
251 { .key
= KEYC_F3
|KEYC_BUILD_MODIFIERS
,
254 { .key
= KEYC_F4
|KEYC_BUILD_MODIFIERS
,
257 { .key
= KEYC_F5
|KEYC_BUILD_MODIFIERS
,
260 { .key
= KEYC_F6
|KEYC_BUILD_MODIFIERS
,
263 { .key
= KEYC_F7
|KEYC_BUILD_MODIFIERS
,
266 { .key
= KEYC_F8
|KEYC_BUILD_MODIFIERS
,
269 { .key
= KEYC_F9
|KEYC_BUILD_MODIFIERS
,
272 { .key
= KEYC_F10
|KEYC_BUILD_MODIFIERS
,
275 { .key
= KEYC_F11
|KEYC_BUILD_MODIFIERS
,
278 { .key
= KEYC_F12
|KEYC_BUILD_MODIFIERS
,
281 { .key
= KEYC_UP
|KEYC_BUILD_MODIFIERS
,
284 { .key
= KEYC_DOWN
|KEYC_BUILD_MODIFIERS
,
287 { .key
= KEYC_RIGHT
|KEYC_BUILD_MODIFIERS
,
290 { .key
= KEYC_LEFT
|KEYC_BUILD_MODIFIERS
,
293 { .key
= KEYC_HOME
|KEYC_BUILD_MODIFIERS
,
296 { .key
= KEYC_END
|KEYC_BUILD_MODIFIERS
,
299 { .key
= KEYC_PPAGE
|KEYC_BUILD_MODIFIERS
,
302 { .key
= KEYC_NPAGE
|KEYC_BUILD_MODIFIERS
,
305 { .key
= KEYC_IC
|KEYC_BUILD_MODIFIERS
,
308 { .key
= KEYC_DC
|KEYC_BUILD_MODIFIERS
,
312 /* Tab and modifiers. */
313 { .key
= '\011'|KEYC_CTRL
,
316 { .key
= '\011'|KEYC_CTRL
|KEYC_EXTENDED
,
319 { .key
= '\011'|KEYC_CTRL
|KEYC_SHIFT
,
322 { .key
= '\011'|KEYC_CTRL
|KEYC_SHIFT
|KEYC_EXTENDED
,
326 static const key_code input_key_modifiers
[] = {
330 KEYC_META
|KEYC_IMPLIED_META
,
331 KEYC_SHIFT
|KEYC_META
|KEYC_IMPLIED_META
,
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. */
340 input_key_cmp(struct input_key_entry
*ike1
, struct input_key_entry
*ike2
)
342 if (ike1
->key
< ike2
->key
)
344 if (ike1
->key
> ike2
->key
)
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. */
360 input_key_split2(u_int c
, u_char
*dst
)
363 dst
[0] = (c
>> 6) | 0xc0;
364 dst
[1] = (c
& 0x3f) | 0x80;
371 /* Build input key tree. */
373 input_key_build(void)
375 struct input_key_entry
*ike
, *new;
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
);
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
];
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
);
419 return (input_key(wp
->screen
, wp
->event
, key
));
423 input_key_write(const char *from
, struct bufferevent
*bev
, const char *data
,
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
;
437 char tmp
[64], modifier
;
439 /* Mouse keys need a pane. */
440 if (KEYC_IS_MOUSE(key
))
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);
450 /* Is this backspace? */
451 if ((key
& KEYC_MASK_KEY
) == KEYC_BSPACE
) {
452 newkey
= options_get_number(global_options
, "backspace");
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) {
465 input_key_write(__func__
, bev
, "\033", 1);
466 ud
.data
[0] = justkey
;
467 input_key_write(__func__
, bev
, &ud
.data
[0], 1);
470 if (KEYC_IS_UNICODE(justkey
)) {
472 input_key_write(__func__
, bev
, "\033", 1);
473 utf8_to_data(justkey
, &ud
);
474 input_key_write(__func__
, bev
, ud
.data
, ud
.size
);
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
)
484 if (~s
->mode
& MODE_KCURSOR
)
486 if (s
->mode
& MODE_KEXTENDED
)
487 ike
= input_key_get(key
|KEYC_EXTENDED
);
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
);
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
))
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
));
509 /* No builtin key sequence; construct an extended key sequence. */
510 if (~s
->mode
& MODE_KEXTENDED
) {
511 if ((key
& KEYC_MASK_MODIFIERS
) != KEYC_CTRL
)
513 justkey
= (key
& KEYC_MASK_KEY
);
517 key
= 0|(key
& ~KEYC_MASK_KEY
);
520 key
= 28|(key
& ~KEYC_MASK_KEY
);
523 key
= 30|(key
& ~KEYC_MASK_KEY
);
527 key
= 31|(key
& ~KEYC_MASK_KEY
);
530 key
= 127|(key
& ~KEYC_MASK_KEY
);
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
);
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
;
556 case KEYC_SHIFT
|KEYC_META
:
562 case KEYC_SHIFT
|KEYC_CTRL
:
565 case KEYC_META
|KEYC_CTRL
:
568 case KEYC_SHIFT
|KEYC_META
|KEYC_CTRL
:
574 xsnprintf(tmp
, sizeof tmp
, "\033[%llu;%cu", outkey
, modifier
);
575 input_key_write(__func__
, bev
, tmp
, strlen(tmp
));
579 log_debug("key 0x%llx missing", key
);
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
)
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)
597 if ((s
->mode
& ALL_MOUSE_MODES
) == 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
))
612 if (MOUSE_DRAG(m
->b
) &&
613 MOUSE_RELEASE(m
->b
) &&
614 MOUSE_RELEASE(m
->lb
) &&
615 (~s
->mode
& MODE_MOUSE_ALL
))
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
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
)
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
]);
641 if (m
->b
+ MOUSE_PARAM_BTN_OFF
> MOUSE_PARAM_MAX
)
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
;
655 buf
[len
++] = x
+ MOUSE_PARAM_POS_OFF
;
656 if (y
+ MOUSE_PARAM_POS_OFF
> MOUSE_PARAM_MAX
)
657 buf
[len
++] = MOUSE_PARAM_MAX
;
659 buf
[len
++] = y
+ MOUSE_PARAM_POS_OFF
;
667 /* Translate mouse and output. */
669 input_key_mouse(struct window_pane
*wp
, struct mouse_event
*m
)
671 struct screen
*s
= wp
->screen
;
676 /* Ignore events if no mouse mode or the pane is not visible. */
677 if (m
->ignore
|| (s
->mode
& ALL_MOUSE_MODES
) == 0)
679 if (cmd_mouse_at(wp
, m
, &x
, &y
, 0) != 0)
681 if (!window_pane_visible(wp
))
683 if (!input_key_get_mouse(s
, m
, x
, y
, &buf
, &len
))
685 log_debug("writing mouse %.*s to %%%u", (int)len
, buf
, wp
->id
);
686 input_key_write(__func__
, wp
->event
, buf
, len
);