1*0a6a1f1dSLionel Sambuc /* Id */
2eda6f593SDavid van Moolenbroek
3eda6f593SDavid van Moolenbroek /*
4eda6f593SDavid van Moolenbroek * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
5eda6f593SDavid van Moolenbroek *
6eda6f593SDavid van Moolenbroek * Permission to use, copy, modify, and distribute this software for any
7eda6f593SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
8eda6f593SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
9eda6f593SDavid van Moolenbroek *
10eda6f593SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11eda6f593SDavid van Moolenbroek * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12eda6f593SDavid van Moolenbroek * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13eda6f593SDavid van Moolenbroek * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14eda6f593SDavid van Moolenbroek * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15eda6f593SDavid van Moolenbroek * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16eda6f593SDavid van Moolenbroek * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17eda6f593SDavid van Moolenbroek */
18eda6f593SDavid van Moolenbroek
19eda6f593SDavid van Moolenbroek #include <sys/types.h>
20eda6f593SDavid van Moolenbroek
21eda6f593SDavid van Moolenbroek #include <stdlib.h>
22eda6f593SDavid van Moolenbroek #include <string.h>
23eda6f593SDavid van Moolenbroek
24eda6f593SDavid van Moolenbroek #include "tmux.h"
25eda6f593SDavid van Moolenbroek
26eda6f593SDavid van Moolenbroek /*
27eda6f593SDavid van Moolenbroek * This file is rather misleadingly named, it contains the code which takes a
28eda6f593SDavid van Moolenbroek * key code and translates it into something suitable to be sent to the
29eda6f593SDavid van Moolenbroek * application running in a pane (similar to input.c does in the other
30eda6f593SDavid van Moolenbroek * direction with output).
31eda6f593SDavid van Moolenbroek */
32eda6f593SDavid van Moolenbroek
33eda6f593SDavid van Moolenbroek struct input_key_ent {
34eda6f593SDavid van Moolenbroek int key;
35eda6f593SDavid van Moolenbroek const char *data;
36eda6f593SDavid van Moolenbroek
37eda6f593SDavid van Moolenbroek int flags;
38eda6f593SDavid van Moolenbroek #define INPUTKEY_KEYPAD 0x1 /* keypad key */
39eda6f593SDavid van Moolenbroek #define INPUTKEY_CURSOR 0x2 /* cursor key */
40eda6f593SDavid van Moolenbroek };
41eda6f593SDavid van Moolenbroek
42eda6f593SDavid van Moolenbroek const struct input_key_ent input_keys[] = {
43eda6f593SDavid van Moolenbroek /* Backspace key. */
44eda6f593SDavid van Moolenbroek { KEYC_BSPACE, "\177", 0 },
45eda6f593SDavid van Moolenbroek
46eda6f593SDavid van Moolenbroek /* Function keys. */
47eda6f593SDavid van Moolenbroek { KEYC_F1, "\033OP", 0 },
48eda6f593SDavid van Moolenbroek { KEYC_F2, "\033OQ", 0 },
49eda6f593SDavid van Moolenbroek { KEYC_F3, "\033OR", 0 },
50eda6f593SDavid van Moolenbroek { KEYC_F4, "\033OS", 0 },
51eda6f593SDavid van Moolenbroek { KEYC_F5, "\033[15~", 0 },
52eda6f593SDavid van Moolenbroek { KEYC_F6, "\033[17~", 0 },
53eda6f593SDavid van Moolenbroek { KEYC_F7, "\033[18~", 0 },
54eda6f593SDavid van Moolenbroek { KEYC_F8, "\033[19~", 0 },
55eda6f593SDavid van Moolenbroek { KEYC_F9, "\033[20~", 0 },
56eda6f593SDavid van Moolenbroek { KEYC_F10, "\033[21~", 0 },
57eda6f593SDavid van Moolenbroek { KEYC_F11, "\033[23~", 0 },
58eda6f593SDavid van Moolenbroek { KEYC_F12, "\033[24~", 0 },
59eda6f593SDavid van Moolenbroek { KEYC_F13, "\033[25~", 0 },
60eda6f593SDavid van Moolenbroek { KEYC_F14, "\033[26~", 0 },
61eda6f593SDavid van Moolenbroek { KEYC_F15, "\033[28~", 0 },
62eda6f593SDavid van Moolenbroek { KEYC_F16, "\033[29~", 0 },
63eda6f593SDavid van Moolenbroek { KEYC_F17, "\033[31~", 0 },
64eda6f593SDavid van Moolenbroek { KEYC_F18, "\033[32~", 0 },
65eda6f593SDavid van Moolenbroek { KEYC_F19, "\033[33~", 0 },
66eda6f593SDavid van Moolenbroek { KEYC_F20, "\033[34~", 0 },
67eda6f593SDavid van Moolenbroek { KEYC_IC, "\033[2~", 0 },
68eda6f593SDavid van Moolenbroek { KEYC_DC, "\033[3~", 0 },
69eda6f593SDavid van Moolenbroek { KEYC_HOME, "\033[1~", 0 },
70eda6f593SDavid van Moolenbroek { KEYC_END, "\033[4~", 0 },
71eda6f593SDavid van Moolenbroek { KEYC_NPAGE, "\033[6~", 0 },
72eda6f593SDavid van Moolenbroek { KEYC_PPAGE, "\033[5~", 0 },
73eda6f593SDavid van Moolenbroek { KEYC_BTAB, "\033[Z", 0 },
74eda6f593SDavid van Moolenbroek
75eda6f593SDavid van Moolenbroek /*
76eda6f593SDavid van Moolenbroek * Arrow keys. Cursor versions must come first. The codes are toggled
77eda6f593SDavid van Moolenbroek * between CSI and SS3 versions when ctrl is pressed.
78eda6f593SDavid van Moolenbroek */
79eda6f593SDavid van Moolenbroek { KEYC_UP|KEYC_CTRL, "\033[A", INPUTKEY_CURSOR },
80eda6f593SDavid van Moolenbroek { KEYC_DOWN|KEYC_CTRL, "\033[B", INPUTKEY_CURSOR },
81eda6f593SDavid van Moolenbroek { KEYC_RIGHT|KEYC_CTRL, "\033[C", INPUTKEY_CURSOR },
82eda6f593SDavid van Moolenbroek { KEYC_LEFT|KEYC_CTRL, "\033[D", INPUTKEY_CURSOR },
83eda6f593SDavid van Moolenbroek
84eda6f593SDavid van Moolenbroek { KEYC_UP, "\033OA", INPUTKEY_CURSOR },
85eda6f593SDavid van Moolenbroek { KEYC_DOWN, "\033OB", INPUTKEY_CURSOR },
86eda6f593SDavid van Moolenbroek { KEYC_RIGHT, "\033OC", INPUTKEY_CURSOR },
87eda6f593SDavid van Moolenbroek { KEYC_LEFT, "\033OD", INPUTKEY_CURSOR },
88eda6f593SDavid van Moolenbroek
89eda6f593SDavid van Moolenbroek { KEYC_UP|KEYC_CTRL, "\033OA", 0 },
90eda6f593SDavid van Moolenbroek { KEYC_DOWN|KEYC_CTRL, "\033OB", 0 },
91eda6f593SDavid van Moolenbroek { KEYC_RIGHT|KEYC_CTRL, "\033OC", 0 },
92eda6f593SDavid van Moolenbroek { KEYC_LEFT|KEYC_CTRL, "\033OD", 0 },
93eda6f593SDavid van Moolenbroek
94eda6f593SDavid van Moolenbroek { KEYC_UP, "\033[A", 0 },
95eda6f593SDavid van Moolenbroek { KEYC_DOWN, "\033[B", 0 },
96eda6f593SDavid van Moolenbroek { KEYC_RIGHT, "\033[C", 0 },
97eda6f593SDavid van Moolenbroek { KEYC_LEFT, "\033[D", 0 },
98eda6f593SDavid van Moolenbroek
99eda6f593SDavid van Moolenbroek /* Keypad keys. Keypad versions must come first. */
100eda6f593SDavid van Moolenbroek { KEYC_KP_SLASH, "\033Oo", INPUTKEY_KEYPAD },
101eda6f593SDavid van Moolenbroek { KEYC_KP_STAR, "\033Oj", INPUTKEY_KEYPAD },
102eda6f593SDavid van Moolenbroek { KEYC_KP_MINUS, "\033Om", INPUTKEY_KEYPAD },
103eda6f593SDavid van Moolenbroek { KEYC_KP_SEVEN, "\033Ow", INPUTKEY_KEYPAD },
104eda6f593SDavid van Moolenbroek { KEYC_KP_EIGHT, "\033Ox", INPUTKEY_KEYPAD },
105eda6f593SDavid van Moolenbroek { KEYC_KP_NINE, "\033Oy", INPUTKEY_KEYPAD },
106eda6f593SDavid van Moolenbroek { KEYC_KP_PLUS, "\033Ok", INPUTKEY_KEYPAD },
107eda6f593SDavid van Moolenbroek { KEYC_KP_FOUR, "\033Ot", INPUTKEY_KEYPAD },
108eda6f593SDavid van Moolenbroek { KEYC_KP_FIVE, "\033Ou", INPUTKEY_KEYPAD },
109eda6f593SDavid van Moolenbroek { KEYC_KP_SIX, "\033Ov", INPUTKEY_KEYPAD },
110eda6f593SDavid van Moolenbroek { KEYC_KP_ONE, "\033Oq", INPUTKEY_KEYPAD },
111eda6f593SDavid van Moolenbroek { KEYC_KP_TWO, "\033Or", INPUTKEY_KEYPAD },
112eda6f593SDavid van Moolenbroek { KEYC_KP_THREE, "\033Os", INPUTKEY_KEYPAD },
113eda6f593SDavid van Moolenbroek { KEYC_KP_ENTER, "\033OM", INPUTKEY_KEYPAD },
114eda6f593SDavid van Moolenbroek { KEYC_KP_ZERO, "\033Op", INPUTKEY_KEYPAD },
115eda6f593SDavid van Moolenbroek { KEYC_KP_PERIOD, "\033On", INPUTKEY_KEYPAD },
116eda6f593SDavid van Moolenbroek
117eda6f593SDavid van Moolenbroek { KEYC_KP_SLASH, "/", 0 },
118eda6f593SDavid van Moolenbroek { KEYC_KP_STAR, "*", 0 },
119eda6f593SDavid van Moolenbroek { KEYC_KP_MINUS, "-", 0 },
120eda6f593SDavid van Moolenbroek { KEYC_KP_SEVEN, "7", 0 },
121eda6f593SDavid van Moolenbroek { KEYC_KP_EIGHT, "8", 0 },
122eda6f593SDavid van Moolenbroek { KEYC_KP_NINE, "9", 0 },
123eda6f593SDavid van Moolenbroek { KEYC_KP_PLUS, "+", 0 },
124eda6f593SDavid van Moolenbroek { KEYC_KP_FOUR, "4", 0 },
125eda6f593SDavid van Moolenbroek { KEYC_KP_FIVE, "5", 0 },
126eda6f593SDavid van Moolenbroek { KEYC_KP_SIX, "6", 0 },
127eda6f593SDavid van Moolenbroek { KEYC_KP_ONE, "1", 0 },
128eda6f593SDavid van Moolenbroek { KEYC_KP_TWO, "2", 0 },
129eda6f593SDavid van Moolenbroek { KEYC_KP_THREE, "3", 0 },
130eda6f593SDavid van Moolenbroek { KEYC_KP_ENTER, "\n", 0 },
131eda6f593SDavid van Moolenbroek { KEYC_KP_ZERO, "0", 0 },
132eda6f593SDavid van Moolenbroek { KEYC_KP_PERIOD, ".", 0 },
133eda6f593SDavid van Moolenbroek };
134eda6f593SDavid van Moolenbroek
135eda6f593SDavid van Moolenbroek /* Translate a key code into an output key sequence. */
136eda6f593SDavid van Moolenbroek void
input_key(struct window_pane * wp,int key)137eda6f593SDavid van Moolenbroek input_key(struct window_pane *wp, int key)
138eda6f593SDavid van Moolenbroek {
139eda6f593SDavid van Moolenbroek const struct input_key_ent *ike;
140eda6f593SDavid van Moolenbroek u_int i;
141eda6f593SDavid van Moolenbroek size_t dlen;
142eda6f593SDavid van Moolenbroek char *out;
143eda6f593SDavid van Moolenbroek u_char ch;
144eda6f593SDavid van Moolenbroek
145eda6f593SDavid van Moolenbroek log_debug2("writing key 0x%x", key);
146eda6f593SDavid van Moolenbroek
147eda6f593SDavid van Moolenbroek /*
148eda6f593SDavid van Moolenbroek * If this is a normal 7-bit key, just send it, with a leading escape
149eda6f593SDavid van Moolenbroek * if necessary.
150eda6f593SDavid van Moolenbroek */
151eda6f593SDavid van Moolenbroek if (key != KEYC_NONE && (key & ~KEYC_ESCAPE) < 0x100) {
152eda6f593SDavid van Moolenbroek if (key & KEYC_ESCAPE)
153eda6f593SDavid van Moolenbroek bufferevent_write(wp->event, "\033", 1);
154eda6f593SDavid van Moolenbroek ch = key & ~KEYC_ESCAPE;
155eda6f593SDavid van Moolenbroek bufferevent_write(wp->event, &ch, 1);
156eda6f593SDavid van Moolenbroek return;
157eda6f593SDavid van Moolenbroek }
158eda6f593SDavid van Moolenbroek
159eda6f593SDavid van Moolenbroek /*
160eda6f593SDavid van Moolenbroek * Then try to look this up as an xterm key, if the flag to output them
161eda6f593SDavid van Moolenbroek * is set.
162eda6f593SDavid van Moolenbroek */
163eda6f593SDavid van Moolenbroek if (options_get_number(&wp->window->options, "xterm-keys")) {
164eda6f593SDavid van Moolenbroek if ((out = xterm_keys_lookup(key)) != NULL) {
165eda6f593SDavid van Moolenbroek bufferevent_write(wp->event, out, strlen(out));
166*0a6a1f1dSLionel Sambuc free(out);
167eda6f593SDavid van Moolenbroek return;
168eda6f593SDavid van Moolenbroek }
169eda6f593SDavid van Moolenbroek }
170eda6f593SDavid van Moolenbroek
171eda6f593SDavid van Moolenbroek /* Otherwise look the key up in the table. */
172eda6f593SDavid van Moolenbroek for (i = 0; i < nitems(input_keys); i++) {
173eda6f593SDavid van Moolenbroek ike = &input_keys[i];
174eda6f593SDavid van Moolenbroek
175eda6f593SDavid van Moolenbroek if ((ike->flags & INPUTKEY_KEYPAD) &&
176eda6f593SDavid van Moolenbroek !(wp->screen->mode & MODE_KKEYPAD))
177eda6f593SDavid van Moolenbroek continue;
178eda6f593SDavid van Moolenbroek if ((ike->flags & INPUTKEY_CURSOR) &&
179eda6f593SDavid van Moolenbroek !(wp->screen->mode & MODE_KCURSOR))
180eda6f593SDavid van Moolenbroek continue;
181eda6f593SDavid van Moolenbroek
182eda6f593SDavid van Moolenbroek if ((key & KEYC_ESCAPE) && (ike->key | KEYC_ESCAPE) == key)
183eda6f593SDavid van Moolenbroek break;
184eda6f593SDavid van Moolenbroek if (ike->key == key)
185eda6f593SDavid van Moolenbroek break;
186eda6f593SDavid van Moolenbroek }
187eda6f593SDavid van Moolenbroek if (i == nitems(input_keys)) {
188eda6f593SDavid van Moolenbroek log_debug2("key 0x%x missing", key);
189eda6f593SDavid van Moolenbroek return;
190eda6f593SDavid van Moolenbroek }
191eda6f593SDavid van Moolenbroek dlen = strlen(ike->data);
192eda6f593SDavid van Moolenbroek log_debug2("found key 0x%x: \"%s\"", key, ike->data);
193eda6f593SDavid van Moolenbroek
194eda6f593SDavid van Moolenbroek /* Prefix a \033 for escape. */
195eda6f593SDavid van Moolenbroek if (key & KEYC_ESCAPE)
196eda6f593SDavid van Moolenbroek bufferevent_write(wp->event, "\033", 1);
197eda6f593SDavid van Moolenbroek bufferevent_write(wp->event, ike->data, dlen);
198eda6f593SDavid van Moolenbroek }
199eda6f593SDavid van Moolenbroek
200eda6f593SDavid van Moolenbroek /* Translate mouse and output. */
201eda6f593SDavid van Moolenbroek void
input_mouse(struct window_pane * wp,struct session * s,struct mouse_event * m)202*0a6a1f1dSLionel Sambuc input_mouse(struct window_pane *wp, struct session *s, struct mouse_event *m)
203eda6f593SDavid van Moolenbroek {
204*0a6a1f1dSLionel Sambuc char buf[40];
205eda6f593SDavid van Moolenbroek size_t len;
206*0a6a1f1dSLionel Sambuc struct paste_buffer *pb;
207eda6f593SDavid van Moolenbroek
208eda6f593SDavid van Moolenbroek if (wp->screen->mode & ALL_MOUSE_MODES) {
209*0a6a1f1dSLionel Sambuc /*
210*0a6a1f1dSLionel Sambuc * Use the SGR (1006) extension only if the application
211*0a6a1f1dSLionel Sambuc * requested it and the underlying terminal also sent the event
212*0a6a1f1dSLionel Sambuc * in this format (this is because an old style mouse release
213*0a6a1f1dSLionel Sambuc * event cannot be converted into the new SGR format, since the
214*0a6a1f1dSLionel Sambuc * released button is unknown). Otherwise pretend that tmux
215*0a6a1f1dSLionel Sambuc * doesn't speak this extension, and fall back to the UTF-8
216*0a6a1f1dSLionel Sambuc * (1005) extension if the application requested, or to the
217*0a6a1f1dSLionel Sambuc * legacy format.
218*0a6a1f1dSLionel Sambuc */
219*0a6a1f1dSLionel Sambuc if (m->sgr && (wp->screen->mode & MODE_MOUSE_SGR)) {
220*0a6a1f1dSLionel Sambuc len = xsnprintf(buf, sizeof buf, "\033[<%d;%d;%d%c",
221*0a6a1f1dSLionel Sambuc m->sgr_xb, m->x + 1, m->y + 1,
222*0a6a1f1dSLionel Sambuc m->sgr_rel ? 'm' : 'M');
223*0a6a1f1dSLionel Sambuc } else if (wp->screen->mode & MODE_MOUSE_UTF8) {
224eda6f593SDavid van Moolenbroek len = xsnprintf(buf, sizeof buf, "\033[M");
225*0a6a1f1dSLionel Sambuc len += utf8_split2(m->xb + 32, (u_char *)&buf[len]);
226*0a6a1f1dSLionel Sambuc len += utf8_split2(m->x + 33, (u_char *)&buf[len]);
227*0a6a1f1dSLionel Sambuc len += utf8_split2(m->y + 33, (u_char *)&buf[len]);
228eda6f593SDavid van Moolenbroek } else {
229*0a6a1f1dSLionel Sambuc if (m->xb > 223)
230eda6f593SDavid van Moolenbroek return;
231eda6f593SDavid van Moolenbroek len = xsnprintf(buf, sizeof buf, "\033[M");
232*0a6a1f1dSLionel Sambuc buf[len++] = m->xb + 32;
233eda6f593SDavid van Moolenbroek buf[len++] = m->x + 33;
234eda6f593SDavid van Moolenbroek buf[len++] = m->y + 33;
235eda6f593SDavid van Moolenbroek }
236eda6f593SDavid van Moolenbroek bufferevent_write(wp->event, buf, len);
237*0a6a1f1dSLionel Sambuc return;
238*0a6a1f1dSLionel Sambuc }
239*0a6a1f1dSLionel Sambuc
240*0a6a1f1dSLionel Sambuc if (m->button == 1 && (m->event & MOUSE_EVENT_CLICK) &&
241*0a6a1f1dSLionel Sambuc options_get_number(&wp->window->options, "mode-mouse") == 1) {
242*0a6a1f1dSLionel Sambuc pb = paste_get_top(&global_buffers);
243*0a6a1f1dSLionel Sambuc if (pb != NULL) {
244*0a6a1f1dSLionel Sambuc paste_send_pane(pb, wp, "\r",
245*0a6a1f1dSLionel Sambuc wp->screen->mode & MODE_BRACKETPASTE);
246*0a6a1f1dSLionel Sambuc }
247*0a6a1f1dSLionel Sambuc } else if ((m->xb & 3) != 1 &&
248*0a6a1f1dSLionel Sambuc options_get_number(&wp->window->options, "mode-mouse") == 1) {
249*0a6a1f1dSLionel Sambuc if (window_pane_set_mode(wp, &window_copy_mode) == 0) {
250eda6f593SDavid van Moolenbroek window_copy_init_from_pane(wp);
251eda6f593SDavid van Moolenbroek if (wp->mode->mouse != NULL)
252*0a6a1f1dSLionel Sambuc wp->mode->mouse(wp, s, m);
253eda6f593SDavid van Moolenbroek }
254eda6f593SDavid van Moolenbroek }
255eda6f593SDavid van Moolenbroek }
256