Line | Count | Source |
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 | | #include <sys/time.h> |
21 | | |
22 | | #include <netinet/in.h> |
23 | | |
24 | | #include <ctype.h> |
25 | | #include <limits.h> |
26 | | #include <resolv.h> |
27 | | #include <stdlib.h> |
28 | | #include <string.h> |
29 | | #include <termios.h> |
30 | | #include <unistd.h> |
31 | | |
32 | | #include "tmux.h" |
33 | | |
34 | | /* |
35 | | * Handle keys input from the outside terminal. tty_default_*_keys[] are a base |
36 | | * table of supported keys which are looked up in terminfo(5) and translated |
37 | | * into a ternary tree. |
38 | | */ |
39 | | |
40 | | static void tty_keys_add1(struct tty_key **, const char *, key_code); |
41 | | static void tty_keys_add(struct tty *, const char *, key_code); |
42 | | static void tty_keys_free1(struct tty_key *); |
43 | | static struct tty_key *tty_keys_find1(struct tty_key *, const char *, size_t, |
44 | | size_t *); |
45 | | static struct tty_key *tty_keys_find(struct tty *, const char *, size_t, |
46 | | size_t *); |
47 | | static int tty_keys_next1(struct tty *, const char *, size_t, key_code *, |
48 | | size_t *, int); |
49 | | static void tty_keys_callback(int, short, void *); |
50 | | static int tty_keys_extended_key(struct tty *, const char *, size_t, |
51 | | size_t *, key_code *); |
52 | | static int tty_keys_mouse(struct tty *, const char *, size_t, size_t *, |
53 | | struct mouse_event *); |
54 | | static int tty_keys_clipboard(struct tty *, const char *, size_t, |
55 | | size_t *); |
56 | | static int tty_keys_device_attributes(struct tty *, const char *, size_t, |
57 | | size_t *); |
58 | | static int tty_keys_device_attributes2(struct tty *, const char *, size_t, |
59 | | size_t *); |
60 | | static int tty_keys_extended_device_attributes(struct tty *, const char *, |
61 | | size_t, size_t *); |
62 | | static int tty_keys_palette(struct tty *, const char *, size_t, size_t *); |
63 | | |
64 | | /* A key tree entry. */ |
65 | | struct tty_key { |
66 | | char ch; |
67 | | key_code key; |
68 | | |
69 | | struct tty_key *left; |
70 | | struct tty_key *right; |
71 | | |
72 | | struct tty_key *next; |
73 | | }; |
74 | | |
75 | | /* Default raw keys. */ |
76 | | struct tty_default_key_raw { |
77 | | const char *string; |
78 | | key_code key; |
79 | | }; |
80 | | static const struct tty_default_key_raw tty_default_raw_keys[] = { |
81 | | /* Application escape. */ |
82 | | { "\033O[", '\033' }, |
83 | | |
84 | | /* |
85 | | * Numeric keypad. Just use the vt100 escape sequences here and always |
86 | | * put the terminal into keypad_xmit mode. Translation of numbers |
87 | | * mode/applications mode is done in input-keys.c. |
88 | | */ |
89 | | { "\033Oo", KEYC_KP_SLASH|KEYC_KEYPAD }, |
90 | | { "\033Oj", KEYC_KP_STAR|KEYC_KEYPAD }, |
91 | | { "\033Om", KEYC_KP_MINUS|KEYC_KEYPAD }, |
92 | | { "\033Ow", KEYC_KP_SEVEN|KEYC_KEYPAD }, |
93 | | { "\033Ox", KEYC_KP_EIGHT|KEYC_KEYPAD }, |
94 | | { "\033Oy", KEYC_KP_NINE|KEYC_KEYPAD }, |
95 | | { "\033Ok", KEYC_KP_PLUS|KEYC_KEYPAD }, |
96 | | { "\033Ot", KEYC_KP_FOUR|KEYC_KEYPAD }, |
97 | | { "\033Ou", KEYC_KP_FIVE|KEYC_KEYPAD }, |
98 | | { "\033Ov", KEYC_KP_SIX|KEYC_KEYPAD }, |
99 | | { "\033Oq", KEYC_KP_ONE|KEYC_KEYPAD }, |
100 | | { "\033Or", KEYC_KP_TWO|KEYC_KEYPAD }, |
101 | | { "\033Os", KEYC_KP_THREE|KEYC_KEYPAD }, |
102 | | { "\033OM", KEYC_KP_ENTER|KEYC_KEYPAD }, |
103 | | { "\033Op", KEYC_KP_ZERO|KEYC_KEYPAD }, |
104 | | { "\033On", KEYC_KP_PERIOD|KEYC_KEYPAD }, |
105 | | |
106 | | /* Arrow keys. */ |
107 | | { "\033OA", KEYC_UP|KEYC_CURSOR }, |
108 | | { "\033OB", KEYC_DOWN|KEYC_CURSOR }, |
109 | | { "\033OC", KEYC_RIGHT|KEYC_CURSOR }, |
110 | | { "\033OD", KEYC_LEFT|KEYC_CURSOR }, |
111 | | |
112 | | { "\033[A", KEYC_UP|KEYC_CURSOR }, |
113 | | { "\033[B", KEYC_DOWN|KEYC_CURSOR }, |
114 | | { "\033[C", KEYC_RIGHT|KEYC_CURSOR }, |
115 | | { "\033[D", KEYC_LEFT|KEYC_CURSOR }, |
116 | | |
117 | | /* |
118 | | * Meta arrow keys. These do not get the IMPLIED_META flag so they |
119 | | * don't match the xterm-style meta keys in the output tree - Escape+Up |
120 | | * should stay as Escape+Up and not become M-Up. |
121 | | */ |
122 | | { "\033\033OA", KEYC_UP|KEYC_CURSOR|KEYC_META }, |
123 | | { "\033\033OB", KEYC_DOWN|KEYC_CURSOR|KEYC_META }, |
124 | | { "\033\033OC", KEYC_RIGHT|KEYC_CURSOR|KEYC_META }, |
125 | | { "\033\033OD", KEYC_LEFT|KEYC_CURSOR|KEYC_META }, |
126 | | |
127 | | { "\033\033[A", KEYC_UP|KEYC_CURSOR|KEYC_META }, |
128 | | { "\033\033[B", KEYC_DOWN|KEYC_CURSOR|KEYC_META }, |
129 | | { "\033\033[C", KEYC_RIGHT|KEYC_CURSOR|KEYC_META }, |
130 | | { "\033\033[D", KEYC_LEFT|KEYC_CURSOR|KEYC_META }, |
131 | | |
132 | | /* Other xterm keys. */ |
133 | | { "\033OH", KEYC_HOME }, |
134 | | { "\033OF", KEYC_END }, |
135 | | |
136 | | { "\033\033OH", KEYC_HOME|KEYC_META|KEYC_IMPLIED_META }, |
137 | | { "\033\033OF", KEYC_END|KEYC_META|KEYC_IMPLIED_META }, |
138 | | |
139 | | { "\033[H", KEYC_HOME }, |
140 | | { "\033[F", KEYC_END }, |
141 | | |
142 | | { "\033\033[H", KEYC_HOME|KEYC_META|KEYC_IMPLIED_META }, |
143 | | { "\033\033[F", KEYC_END|KEYC_META|KEYC_IMPLIED_META }, |
144 | | |
145 | | /* rxvt arrow keys. */ |
146 | | { "\033Oa", KEYC_UP|KEYC_CTRL }, |
147 | | { "\033Ob", KEYC_DOWN|KEYC_CTRL }, |
148 | | { "\033Oc", KEYC_RIGHT|KEYC_CTRL }, |
149 | | { "\033Od", KEYC_LEFT|KEYC_CTRL }, |
150 | | |
151 | | { "\033[a", KEYC_UP|KEYC_SHIFT }, |
152 | | { "\033[b", KEYC_DOWN|KEYC_SHIFT }, |
153 | | { "\033[c", KEYC_RIGHT|KEYC_SHIFT }, |
154 | | { "\033[d", KEYC_LEFT|KEYC_SHIFT }, |
155 | | |
156 | | /* rxvt function keys. */ |
157 | | { "\033[11~", KEYC_F1 }, |
158 | | { "\033[12~", KEYC_F2 }, |
159 | | { "\033[13~", KEYC_F3 }, |
160 | | { "\033[14~", KEYC_F4 }, |
161 | | { "\033[15~", KEYC_F5 }, |
162 | | { "\033[17~", KEYC_F6 }, |
163 | | { "\033[18~", KEYC_F7 }, |
164 | | { "\033[19~", KEYC_F8 }, |
165 | | { "\033[20~", KEYC_F9 }, |
166 | | { "\033[21~", KEYC_F10 }, |
167 | | |
168 | | { "\033[23~", KEYC_F1|KEYC_SHIFT }, |
169 | | { "\033[24~", KEYC_F2|KEYC_SHIFT }, |
170 | | { "\033[25~", KEYC_F3|KEYC_SHIFT }, |
171 | | { "\033[26~", KEYC_F4|KEYC_SHIFT }, |
172 | | { "\033[28~", KEYC_F5|KEYC_SHIFT }, |
173 | | { "\033[29~", KEYC_F6|KEYC_SHIFT }, |
174 | | { "\033[31~", KEYC_F7|KEYC_SHIFT }, |
175 | | { "\033[32~", KEYC_F8|KEYC_SHIFT }, |
176 | | { "\033[33~", KEYC_F9|KEYC_SHIFT }, |
177 | | { "\033[34~", KEYC_F10|KEYC_SHIFT }, |
178 | | { "\033[23$", KEYC_F11|KEYC_SHIFT }, |
179 | | { "\033[24$", KEYC_F12|KEYC_SHIFT }, |
180 | | |
181 | | { "\033[11^", KEYC_F1|KEYC_CTRL }, |
182 | | { "\033[12^", KEYC_F2|KEYC_CTRL }, |
183 | | { "\033[13^", KEYC_F3|KEYC_CTRL }, |
184 | | { "\033[14^", KEYC_F4|KEYC_CTRL }, |
185 | | { "\033[15^", KEYC_F5|KEYC_CTRL }, |
186 | | { "\033[17^", KEYC_F6|KEYC_CTRL }, |
187 | | { "\033[18^", KEYC_F7|KEYC_CTRL }, |
188 | | { "\033[19^", KEYC_F8|KEYC_CTRL }, |
189 | | { "\033[20^", KEYC_F9|KEYC_CTRL }, |
190 | | { "\033[21^", KEYC_F10|KEYC_CTRL }, |
191 | | { "\033[23^", KEYC_F11|KEYC_CTRL }, |
192 | | { "\033[24^", KEYC_F12|KEYC_CTRL }, |
193 | | |
194 | | { "\033[11@", KEYC_F1|KEYC_CTRL|KEYC_SHIFT }, |
195 | | { "\033[12@", KEYC_F2|KEYC_CTRL|KEYC_SHIFT }, |
196 | | { "\033[13@", KEYC_F3|KEYC_CTRL|KEYC_SHIFT }, |
197 | | { "\033[14@", KEYC_F4|KEYC_CTRL|KEYC_SHIFT }, |
198 | | { "\033[15@", KEYC_F5|KEYC_CTRL|KEYC_SHIFT }, |
199 | | { "\033[17@", KEYC_F6|KEYC_CTRL|KEYC_SHIFT }, |
200 | | { "\033[18@", KEYC_F7|KEYC_CTRL|KEYC_SHIFT }, |
201 | | { "\033[19@", KEYC_F8|KEYC_CTRL|KEYC_SHIFT }, |
202 | | { "\033[20@", KEYC_F9|KEYC_CTRL|KEYC_SHIFT }, |
203 | | { "\033[21@", KEYC_F10|KEYC_CTRL|KEYC_SHIFT }, |
204 | | { "\033[23@", KEYC_F11|KEYC_CTRL|KEYC_SHIFT }, |
205 | | { "\033[24@", KEYC_F12|KEYC_CTRL|KEYC_SHIFT }, |
206 | | |
207 | | /* Focus tracking. */ |
208 | | { "\033[I", KEYC_FOCUS_IN }, |
209 | | { "\033[O", KEYC_FOCUS_OUT }, |
210 | | |
211 | | /* Paste keys. */ |
212 | | { "\033[200~", KEYC_PASTE_START|KEYC_IMPLIED_META }, |
213 | | { "\033[201~", KEYC_PASTE_END|KEYC_IMPLIED_META }, |
214 | | |
215 | | /* Extended keys. */ |
216 | | { "\033[1;5Z", '\011'|KEYC_CTRL|KEYC_SHIFT }, |
217 | | |
218 | | /* Theme reporting. */ |
219 | | { "\033[?997;1n", KEYC_REPORT_DARK_THEME }, |
220 | | { "\033[?997;2n", KEYC_REPORT_LIGHT_THEME }, |
221 | | }; |
222 | | |
223 | | /* Default xterm keys. */ |
224 | | struct tty_default_key_xterm { |
225 | | const char *template; |
226 | | key_code key; |
227 | | }; |
228 | | static const struct tty_default_key_xterm tty_default_xterm_keys[] = { |
229 | | { "\033[1;_P", KEYC_F1 }, |
230 | | { "\033O1;_P", KEYC_F1 }, |
231 | | { "\033O_P", KEYC_F1 }, |
232 | | { "\033[1;_Q", KEYC_F2 }, |
233 | | { "\033O1;_Q", KEYC_F2 }, |
234 | | { "\033O_Q", KEYC_F2 }, |
235 | | { "\033[1;_R", KEYC_F3 }, |
236 | | { "\033O1;_R", KEYC_F3 }, |
237 | | { "\033O_R", KEYC_F3 }, |
238 | | { "\033[1;_S", KEYC_F4 }, |
239 | | { "\033O1;_S", KEYC_F4 }, |
240 | | { "\033O_S", KEYC_F4 }, |
241 | | { "\033[15;_~", KEYC_F5 }, |
242 | | { "\033[17;_~", KEYC_F6 }, |
243 | | { "\033[18;_~", KEYC_F7 }, |
244 | | { "\033[19;_~", KEYC_F8 }, |
245 | | { "\033[20;_~", KEYC_F9 }, |
246 | | { "\033[21;_~", KEYC_F10 }, |
247 | | { "\033[23;_~", KEYC_F11 }, |
248 | | { "\033[24;_~", KEYC_F12 }, |
249 | | { "\033[1;_A", KEYC_UP }, |
250 | | { "\033[1;_B", KEYC_DOWN }, |
251 | | { "\033[1;_C", KEYC_RIGHT }, |
252 | | { "\033[1;_D", KEYC_LEFT }, |
253 | | { "\033[1;_H", KEYC_HOME }, |
254 | | { "\033[1;_F", KEYC_END }, |
255 | | { "\033[5;_~", KEYC_PPAGE }, |
256 | | { "\033[6;_~", KEYC_NPAGE }, |
257 | | { "\033[2;_~", KEYC_IC }, |
258 | | { "\033[3;_~", KEYC_DC }, |
259 | | }; |
260 | | static const key_code tty_default_xterm_modifiers[] = { |
261 | | 0, |
262 | | 0, |
263 | | KEYC_SHIFT, |
264 | | KEYC_META|KEYC_IMPLIED_META, |
265 | | KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META, |
266 | | KEYC_CTRL, |
267 | | KEYC_SHIFT|KEYC_CTRL, |
268 | | KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL, |
269 | | KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL, |
270 | | KEYC_META|KEYC_IMPLIED_META |
271 | | }; |
272 | | |
273 | | /* |
274 | | * Default terminfo(5) keys. Any keys that have builtin modifiers (that is, |
275 | | * where the key itself contains the modifiers) has the KEYC_XTERM flag set so |
276 | | * a leading escape is not treated as meta (and probably removed). |
277 | | */ |
278 | | struct tty_default_key_code { |
279 | | enum tty_code_code code; |
280 | | key_code key; |
281 | | }; |
282 | | static const struct tty_default_key_code tty_default_code_keys[] = { |
283 | | /* Function keys. */ |
284 | | { TTYC_KF1, KEYC_F1 }, |
285 | | { TTYC_KF2, KEYC_F2 }, |
286 | | { TTYC_KF3, KEYC_F3 }, |
287 | | { TTYC_KF4, KEYC_F4 }, |
288 | | { TTYC_KF5, KEYC_F5 }, |
289 | | { TTYC_KF6, KEYC_F6 }, |
290 | | { TTYC_KF7, KEYC_F7 }, |
291 | | { TTYC_KF8, KEYC_F8 }, |
292 | | { TTYC_KF9, KEYC_F9 }, |
293 | | { TTYC_KF10, KEYC_F10 }, |
294 | | { TTYC_KF11, KEYC_F11 }, |
295 | | { TTYC_KF12, KEYC_F12 }, |
296 | | |
297 | | { TTYC_KF13, KEYC_F1|KEYC_SHIFT }, |
298 | | { TTYC_KF14, KEYC_F2|KEYC_SHIFT }, |
299 | | { TTYC_KF15, KEYC_F3|KEYC_SHIFT }, |
300 | | { TTYC_KF16, KEYC_F4|KEYC_SHIFT }, |
301 | | { TTYC_KF17, KEYC_F5|KEYC_SHIFT }, |
302 | | { TTYC_KF18, KEYC_F6|KEYC_SHIFT }, |
303 | | { TTYC_KF19, KEYC_F7|KEYC_SHIFT }, |
304 | | { TTYC_KF20, KEYC_F8|KEYC_SHIFT }, |
305 | | { TTYC_KF21, KEYC_F9|KEYC_SHIFT }, |
306 | | { TTYC_KF22, KEYC_F10|KEYC_SHIFT }, |
307 | | { TTYC_KF23, KEYC_F11|KEYC_SHIFT }, |
308 | | { TTYC_KF24, KEYC_F12|KEYC_SHIFT }, |
309 | | |
310 | | { TTYC_KF25, KEYC_F1|KEYC_CTRL }, |
311 | | { TTYC_KF26, KEYC_F2|KEYC_CTRL }, |
312 | | { TTYC_KF27, KEYC_F3|KEYC_CTRL }, |
313 | | { TTYC_KF28, KEYC_F4|KEYC_CTRL }, |
314 | | { TTYC_KF29, KEYC_F5|KEYC_CTRL }, |
315 | | { TTYC_KF30, KEYC_F6|KEYC_CTRL }, |
316 | | { TTYC_KF31, KEYC_F7|KEYC_CTRL }, |
317 | | { TTYC_KF32, KEYC_F8|KEYC_CTRL }, |
318 | | { TTYC_KF33, KEYC_F9|KEYC_CTRL }, |
319 | | { TTYC_KF34, KEYC_F10|KEYC_CTRL }, |
320 | | { TTYC_KF35, KEYC_F11|KEYC_CTRL }, |
321 | | { TTYC_KF36, KEYC_F12|KEYC_CTRL }, |
322 | | |
323 | | { TTYC_KF37, KEYC_F1|KEYC_SHIFT|KEYC_CTRL }, |
324 | | { TTYC_KF38, KEYC_F2|KEYC_SHIFT|KEYC_CTRL }, |
325 | | { TTYC_KF39, KEYC_F3|KEYC_SHIFT|KEYC_CTRL }, |
326 | | { TTYC_KF40, KEYC_F4|KEYC_SHIFT|KEYC_CTRL }, |
327 | | { TTYC_KF41, KEYC_F5|KEYC_SHIFT|KEYC_CTRL }, |
328 | | { TTYC_KF42, KEYC_F6|KEYC_SHIFT|KEYC_CTRL }, |
329 | | { TTYC_KF43, KEYC_F7|KEYC_SHIFT|KEYC_CTRL }, |
330 | | { TTYC_KF44, KEYC_F8|KEYC_SHIFT|KEYC_CTRL }, |
331 | | { TTYC_KF45, KEYC_F9|KEYC_SHIFT|KEYC_CTRL }, |
332 | | { TTYC_KF46, KEYC_F10|KEYC_SHIFT|KEYC_CTRL }, |
333 | | { TTYC_KF47, KEYC_F11|KEYC_SHIFT|KEYC_CTRL }, |
334 | | { TTYC_KF48, KEYC_F12|KEYC_SHIFT|KEYC_CTRL }, |
335 | | |
336 | | { TTYC_KF49, KEYC_F1|KEYC_META|KEYC_IMPLIED_META }, |
337 | | { TTYC_KF50, KEYC_F2|KEYC_META|KEYC_IMPLIED_META }, |
338 | | { TTYC_KF51, KEYC_F3|KEYC_META|KEYC_IMPLIED_META }, |
339 | | { TTYC_KF52, KEYC_F4|KEYC_META|KEYC_IMPLIED_META }, |
340 | | { TTYC_KF53, KEYC_F5|KEYC_META|KEYC_IMPLIED_META }, |
341 | | { TTYC_KF54, KEYC_F6|KEYC_META|KEYC_IMPLIED_META }, |
342 | | { TTYC_KF55, KEYC_F7|KEYC_META|KEYC_IMPLIED_META }, |
343 | | { TTYC_KF56, KEYC_F8|KEYC_META|KEYC_IMPLIED_META }, |
344 | | { TTYC_KF57, KEYC_F9|KEYC_META|KEYC_IMPLIED_META }, |
345 | | { TTYC_KF58, KEYC_F10|KEYC_META|KEYC_IMPLIED_META }, |
346 | | { TTYC_KF59, KEYC_F11|KEYC_META|KEYC_IMPLIED_META }, |
347 | | { TTYC_KF60, KEYC_F12|KEYC_META|KEYC_IMPLIED_META }, |
348 | | |
349 | | { TTYC_KF61, KEYC_F1|KEYC_META|KEYC_IMPLIED_META|KEYC_SHIFT }, |
350 | | { TTYC_KF62, KEYC_F2|KEYC_META|KEYC_IMPLIED_META|KEYC_SHIFT }, |
351 | | { TTYC_KF63, KEYC_F3|KEYC_META|KEYC_IMPLIED_META|KEYC_SHIFT }, |
352 | | |
353 | | { TTYC_KICH1, KEYC_IC }, |
354 | | { TTYC_KDCH1, KEYC_DC }, |
355 | | { TTYC_KHOME, KEYC_HOME }, |
356 | | { TTYC_KEND, KEYC_END }, |
357 | | { TTYC_KNP, KEYC_NPAGE }, |
358 | | { TTYC_KPP, KEYC_PPAGE }, |
359 | | { TTYC_KCBT, KEYC_BTAB }, |
360 | | |
361 | | /* Arrow keys from terminfo. */ |
362 | | { TTYC_KCUU1, KEYC_UP|KEYC_CURSOR }, |
363 | | { TTYC_KCUD1, KEYC_DOWN|KEYC_CURSOR }, |
364 | | { TTYC_KCUB1, KEYC_LEFT|KEYC_CURSOR }, |
365 | | { TTYC_KCUF1, KEYC_RIGHT|KEYC_CURSOR }, |
366 | | |
367 | | /* Key and modifier capabilities. */ |
368 | | { TTYC_KDC2, KEYC_DC|KEYC_SHIFT }, |
369 | | { TTYC_KDC3, KEYC_DC|KEYC_META|KEYC_IMPLIED_META }, |
370 | | { TTYC_KDC4, KEYC_DC|KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META }, |
371 | | { TTYC_KDC5, KEYC_DC|KEYC_CTRL }, |
372 | | { TTYC_KDC6, KEYC_DC|KEYC_SHIFT|KEYC_CTRL }, |
373 | | { TTYC_KDC7, KEYC_DC|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL }, |
374 | | { TTYC_KIND, KEYC_DOWN|KEYC_SHIFT }, |
375 | | { TTYC_KDN2, KEYC_DOWN|KEYC_SHIFT }, |
376 | | { TTYC_KDN3, KEYC_DOWN|KEYC_META|KEYC_IMPLIED_META }, |
377 | | { TTYC_KDN4, KEYC_DOWN|KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META }, |
378 | | { TTYC_KDN5, KEYC_DOWN|KEYC_CTRL }, |
379 | | { TTYC_KDN6, KEYC_DOWN|KEYC_SHIFT|KEYC_CTRL }, |
380 | | { TTYC_KDN7, KEYC_DOWN|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL }, |
381 | | { TTYC_KEND2, KEYC_END|KEYC_SHIFT }, |
382 | | { TTYC_KEND3, KEYC_END|KEYC_META|KEYC_IMPLIED_META }, |
383 | | { TTYC_KEND4, KEYC_END|KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META }, |
384 | | { TTYC_KEND5, KEYC_END|KEYC_CTRL }, |
385 | | { TTYC_KEND6, KEYC_END|KEYC_SHIFT|KEYC_CTRL }, |
386 | | { TTYC_KEND7, KEYC_END|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL }, |
387 | | { TTYC_KHOM2, KEYC_HOME|KEYC_SHIFT }, |
388 | | { TTYC_KHOM3, KEYC_HOME|KEYC_META|KEYC_IMPLIED_META }, |
389 | | { TTYC_KHOM4, KEYC_HOME|KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META }, |
390 | | { TTYC_KHOM5, KEYC_HOME|KEYC_CTRL }, |
391 | | { TTYC_KHOM6, KEYC_HOME|KEYC_SHIFT|KEYC_CTRL }, |
392 | | { TTYC_KHOM7, KEYC_HOME|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL }, |
393 | | { TTYC_KIC2, KEYC_IC|KEYC_SHIFT }, |
394 | | { TTYC_KIC3, KEYC_IC|KEYC_META|KEYC_IMPLIED_META }, |
395 | | { TTYC_KIC4, KEYC_IC|KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META }, |
396 | | { TTYC_KIC5, KEYC_IC|KEYC_CTRL }, |
397 | | { TTYC_KIC6, KEYC_IC|KEYC_SHIFT|KEYC_CTRL }, |
398 | | { TTYC_KIC7, KEYC_IC|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL }, |
399 | | { TTYC_KLFT2, KEYC_LEFT|KEYC_SHIFT }, |
400 | | { TTYC_KLFT3, KEYC_LEFT|KEYC_META|KEYC_IMPLIED_META }, |
401 | | { TTYC_KLFT4, KEYC_LEFT|KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META }, |
402 | | { TTYC_KLFT5, KEYC_LEFT|KEYC_CTRL }, |
403 | | { TTYC_KLFT6, KEYC_LEFT|KEYC_SHIFT|KEYC_CTRL }, |
404 | | { TTYC_KLFT7, KEYC_LEFT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL }, |
405 | | { TTYC_KNXT2, KEYC_NPAGE|KEYC_SHIFT }, |
406 | | { TTYC_KNXT3, KEYC_NPAGE|KEYC_META|KEYC_IMPLIED_META }, |
407 | | { TTYC_KNXT4, KEYC_NPAGE|KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META }, |
408 | | { TTYC_KNXT5, KEYC_NPAGE|KEYC_CTRL }, |
409 | | { TTYC_KNXT6, KEYC_NPAGE|KEYC_SHIFT|KEYC_CTRL }, |
410 | | { TTYC_KNXT7, KEYC_NPAGE|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL }, |
411 | | { TTYC_KPRV2, KEYC_PPAGE|KEYC_SHIFT }, |
412 | | { TTYC_KPRV3, KEYC_PPAGE|KEYC_META|KEYC_IMPLIED_META }, |
413 | | { TTYC_KPRV4, KEYC_PPAGE|KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META }, |
414 | | { TTYC_KPRV5, KEYC_PPAGE|KEYC_CTRL }, |
415 | | { TTYC_KPRV6, KEYC_PPAGE|KEYC_SHIFT|KEYC_CTRL }, |
416 | | { TTYC_KPRV7, KEYC_PPAGE|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL }, |
417 | | { TTYC_KRIT2, KEYC_RIGHT|KEYC_SHIFT }, |
418 | | { TTYC_KRIT3, KEYC_RIGHT|KEYC_META|KEYC_IMPLIED_META }, |
419 | | { TTYC_KRIT4, KEYC_RIGHT|KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META }, |
420 | | { TTYC_KRIT5, KEYC_RIGHT|KEYC_CTRL }, |
421 | | { TTYC_KRIT6, KEYC_RIGHT|KEYC_SHIFT|KEYC_CTRL }, |
422 | | { TTYC_KRIT7, KEYC_RIGHT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL }, |
423 | | { TTYC_KRI, KEYC_UP|KEYC_SHIFT }, |
424 | | { TTYC_KUP2, KEYC_UP|KEYC_SHIFT }, |
425 | | { TTYC_KUP3, KEYC_UP|KEYC_META|KEYC_IMPLIED_META }, |
426 | | { TTYC_KUP4, KEYC_UP|KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META }, |
427 | | { TTYC_KUP5, KEYC_UP|KEYC_CTRL }, |
428 | | { TTYC_KUP6, KEYC_UP|KEYC_SHIFT|KEYC_CTRL }, |
429 | | { TTYC_KUP7, KEYC_UP|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL }, |
430 | | }; |
431 | | |
432 | | /* Add key to tree. */ |
433 | | static void |
434 | | tty_keys_add(struct tty *tty, const char *s, key_code key) |
435 | 0 | { |
436 | 0 | struct tty_key *tk; |
437 | 0 | size_t size; |
438 | 0 | const char *keystr; |
439 | |
|
440 | 0 | keystr = key_string_lookup_key(key, 1); |
441 | 0 | if ((tk = tty_keys_find(tty, s, strlen(s), &size)) == NULL) { |
442 | 0 | log_debug("new key %s: 0x%llx (%s)", s, key, keystr); |
443 | 0 | tty_keys_add1(&tty->key_tree, s, key); |
444 | 0 | } else { |
445 | 0 | log_debug("replacing key %s: 0x%llx (%s)", s, key, keystr); |
446 | 0 | tk->key = key; |
447 | 0 | } |
448 | 0 | } |
449 | | |
450 | | /* Add next node to the tree. */ |
451 | | static void |
452 | | tty_keys_add1(struct tty_key **tkp, const char *s, key_code key) |
453 | 0 | { |
454 | 0 | struct tty_key *tk; |
455 | | |
456 | | /* Allocate a tree entry if there isn't one already. */ |
457 | 0 | tk = *tkp; |
458 | 0 | if (tk == NULL) { |
459 | 0 | tk = *tkp = xcalloc(1, sizeof *tk); |
460 | 0 | tk->ch = *s; |
461 | 0 | tk->key = KEYC_UNKNOWN; |
462 | 0 | } |
463 | | |
464 | | /* Find the next entry. */ |
465 | 0 | if (*s == tk->ch) { |
466 | | /* Move forward in string. */ |
467 | 0 | s++; |
468 | | |
469 | | /* If this is the end of the string, no more is necessary. */ |
470 | 0 | if (*s == '\0') { |
471 | 0 | tk->key = key; |
472 | 0 | return; |
473 | 0 | } |
474 | | |
475 | | /* Use the child tree for the next character. */ |
476 | 0 | tkp = &tk->next; |
477 | 0 | } else { |
478 | 0 | if (*s < tk->ch) |
479 | 0 | tkp = &tk->left; |
480 | 0 | else if (*s > tk->ch) |
481 | 0 | tkp = &tk->right; |
482 | 0 | } |
483 | | |
484 | | /* And recurse to add it. */ |
485 | 0 | tty_keys_add1(tkp, s, key); |
486 | 0 | } |
487 | | |
488 | | /* Initialise a key tree from the table. */ |
489 | | void |
490 | | tty_keys_build(struct tty *tty) |
491 | 0 | { |
492 | 0 | const struct tty_default_key_raw *tdkr; |
493 | 0 | const struct tty_default_key_xterm *tdkx; |
494 | 0 | const struct tty_default_key_code *tdkc; |
495 | 0 | u_int i, j; |
496 | 0 | const char *s; |
497 | 0 | struct options_entry *o; |
498 | 0 | struct options_array_item *a; |
499 | 0 | union options_value *ov; |
500 | 0 | char copy[16]; |
501 | 0 | key_code key; |
502 | |
|
503 | 0 | if (tty->key_tree != NULL) |
504 | 0 | tty_keys_free(tty); |
505 | 0 | tty->key_tree = NULL; |
506 | |
|
507 | 0 | for (i = 0; i < nitems(tty_default_xterm_keys); i++) { |
508 | 0 | tdkx = &tty_default_xterm_keys[i]; |
509 | 0 | for (j = 2; j < nitems(tty_default_xterm_modifiers); j++) { |
510 | 0 | strlcpy(copy, tdkx->template, sizeof copy); |
511 | 0 | copy[strcspn(copy, "_")] = '0' + j; |
512 | |
|
513 | 0 | key = tdkx->key|tty_default_xterm_modifiers[j]; |
514 | 0 | tty_keys_add(tty, copy, key); |
515 | 0 | } |
516 | 0 | } |
517 | 0 | for (i = 0; i < nitems(tty_default_raw_keys); i++) { |
518 | 0 | tdkr = &tty_default_raw_keys[i]; |
519 | |
|
520 | 0 | s = tdkr->string; |
521 | 0 | if (*s != '\0') |
522 | 0 | tty_keys_add(tty, s, tdkr->key); |
523 | 0 | } |
524 | 0 | for (i = 0; i < nitems(tty_default_code_keys); i++) { |
525 | 0 | tdkc = &tty_default_code_keys[i]; |
526 | |
|
527 | 0 | s = tty_term_string(tty->term, tdkc->code); |
528 | 0 | if (*s != '\0') |
529 | 0 | tty_keys_add(tty, s, tdkc->key); |
530 | |
|
531 | 0 | } |
532 | |
|
533 | 0 | o = options_get(global_options, "user-keys"); |
534 | 0 | if (o != NULL) { |
535 | 0 | a = options_array_first(o); |
536 | 0 | while (a != NULL) { |
537 | 0 | i = options_array_item_index(a); |
538 | 0 | ov = options_array_item_value(a); |
539 | 0 | tty_keys_add(tty, ov->string, KEYC_USER + i); |
540 | 0 | a = options_array_next(a); |
541 | 0 | } |
542 | 0 | } |
543 | 0 | } |
544 | | |
545 | | /* Free the entire key tree. */ |
546 | | void |
547 | | tty_keys_free(struct tty *tty) |
548 | 0 | { |
549 | 0 | tty_keys_free1(tty->key_tree); |
550 | 0 | } |
551 | | |
552 | | /* Free a single key. */ |
553 | | static void |
554 | | tty_keys_free1(struct tty_key *tk) |
555 | 0 | { |
556 | 0 | if (tk->next != NULL) |
557 | 0 | tty_keys_free1(tk->next); |
558 | 0 | if (tk->left != NULL) |
559 | 0 | tty_keys_free1(tk->left); |
560 | 0 | if (tk->right != NULL) |
561 | 0 | tty_keys_free1(tk->right); |
562 | 0 | free(tk); |
563 | 0 | } |
564 | | |
565 | | /* Lookup a key in the tree. */ |
566 | | static struct tty_key * |
567 | | tty_keys_find(struct tty *tty, const char *buf, size_t len, size_t *size) |
568 | 0 | { |
569 | 0 | *size = 0; |
570 | 0 | return (tty_keys_find1(tty->key_tree, buf, len, size)); |
571 | 0 | } |
572 | | |
573 | | /* Find the next node. */ |
574 | | static struct tty_key * |
575 | | tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size) |
576 | 0 | { |
577 | | /* If no data, no match. */ |
578 | 0 | if (len == 0) |
579 | 0 | return (NULL); |
580 | | |
581 | | /* If the node is NULL, this is the end of the tree. No match. */ |
582 | 0 | if (tk == NULL) |
583 | 0 | return (NULL); |
584 | | |
585 | | /* Pick the next in the sequence. */ |
586 | 0 | if (tk->ch == *buf) { |
587 | | /* Move forward in the string. */ |
588 | 0 | buf++; len--; |
589 | 0 | (*size)++; |
590 | | |
591 | | /* At the end of the string, return the current node. */ |
592 | 0 | if (len == 0 || (tk->next == NULL && tk->key != KEYC_UNKNOWN)) |
593 | 0 | return (tk); |
594 | | |
595 | | /* Move into the next tree for the following character. */ |
596 | 0 | tk = tk->next; |
597 | 0 | } else { |
598 | 0 | if (*buf < tk->ch) |
599 | 0 | tk = tk->left; |
600 | 0 | else if (*buf > tk->ch) |
601 | 0 | tk = tk->right; |
602 | 0 | } |
603 | | |
604 | | /* Move to the next in the tree. */ |
605 | 0 | return (tty_keys_find1(tk, buf, len, size)); |
606 | 0 | } |
607 | | |
608 | | /* Look up part of the next key. */ |
609 | | static int |
610 | | tty_keys_next1(struct tty *tty, const char *buf, size_t len, key_code *key, |
611 | | size_t *size, int expired) |
612 | 0 | { |
613 | 0 | struct client *c = tty->client; |
614 | 0 | struct tty_key *tk, *tk1; |
615 | 0 | struct utf8_data ud; |
616 | 0 | enum utf8_state more; |
617 | 0 | utf8_char uc; |
618 | 0 | u_int i; |
619 | |
|
620 | 0 | log_debug("%s: next key is %zu (%.*s) (expired=%d)", c->name, len, |
621 | 0 | (int)len, buf, expired); |
622 | | |
623 | | /* Is this a known key? */ |
624 | 0 | tk = tty_keys_find(tty, buf, len, size); |
625 | 0 | if (tk != NULL && tk->key != KEYC_UNKNOWN) { |
626 | 0 | tk1 = tk; |
627 | 0 | do |
628 | 0 | log_debug("%s: keys in list: %#llx", c->name, tk1->key); |
629 | 0 | while ((tk1 = tk1->next) != NULL); |
630 | 0 | if (tk->next != NULL && !expired) |
631 | 0 | return (1); |
632 | 0 | *key = tk->key; |
633 | 0 | return (0); |
634 | 0 | } |
635 | | |
636 | | /* Is this valid UTF-8? */ |
637 | 0 | more = utf8_open(&ud, (u_char)*buf); |
638 | 0 | if (more == UTF8_MORE) { |
639 | 0 | *size = ud.size; |
640 | 0 | if (len < ud.size) { |
641 | 0 | if (!expired) |
642 | 0 | return (1); |
643 | 0 | return (-1); |
644 | 0 | } |
645 | 0 | for (i = 1; i < ud.size; i++) |
646 | 0 | more = utf8_append(&ud, (u_char)buf[i]); |
647 | 0 | if (more != UTF8_DONE) |
648 | 0 | return (-1); |
649 | | |
650 | 0 | if (utf8_from_data(&ud, &uc) != UTF8_DONE) |
651 | 0 | return (-1); |
652 | 0 | *key = uc; |
653 | |
|
654 | 0 | log_debug("%s: UTF-8 key %.*s %#llx", c->name, (int)ud.size, |
655 | 0 | ud.data, *key); |
656 | 0 | return (0); |
657 | 0 | } |
658 | | |
659 | 0 | return (-1); |
660 | 0 | } |
661 | | |
662 | | /* Process window size change escape sequences. */ |
663 | | static int |
664 | | tty_keys_winsz(struct tty *tty, const char *buf, size_t len, size_t *size) |
665 | 0 | { |
666 | 0 | struct client *c = tty->client; |
667 | 0 | size_t end; |
668 | 0 | char tmp[64]; |
669 | 0 | u_int sx, sy, xpixel, ypixel, char_x, char_y; |
670 | |
|
671 | 0 | *size = 0; |
672 | | |
673 | | /* If we did not request this, ignore it. */ |
674 | 0 | if (!(tty->flags & TTY_WINSIZEQUERY)) |
675 | 0 | return (-1); |
676 | | |
677 | | /* First two bytes are always \033[. */ |
678 | 0 | if (buf[0] != '\033') |
679 | 0 | return (-1); |
680 | 0 | if (len == 1) |
681 | 0 | return (1); |
682 | 0 | if (buf[1] != '[') |
683 | 0 | return (-1); |
684 | 0 | if (len == 2) |
685 | 0 | return (1); |
686 | | |
687 | | /* |
688 | | * Stop at either 't' or anything that isn't a |
689 | | * number or ';'. |
690 | | */ |
691 | 0 | for (end = 2; end < len && end != sizeof tmp; end++) { |
692 | 0 | if (buf[end] == 't') |
693 | 0 | break; |
694 | 0 | if (!isdigit((u_char)buf[end]) && buf[end] != ';') |
695 | 0 | break; |
696 | 0 | } |
697 | 0 | if (end == len) |
698 | 0 | return (1); |
699 | 0 | if (end == sizeof tmp || buf[end] != 't') |
700 | 0 | return (-1); |
701 | | |
702 | | /* Copy to the buffer. */ |
703 | 0 | memcpy(tmp, buf + 2, end - 2); |
704 | 0 | tmp[end - 2] = '\0'; |
705 | | |
706 | | /* Try to parse the window size sequence. */ |
707 | 0 | if (sscanf(tmp, "8;%u;%u", &sy, &sx) == 2) { |
708 | | /* Window size in characters. */ |
709 | 0 | tty_set_size(tty, sx, sy, tty->xpixel, tty->ypixel); |
710 | |
|
711 | 0 | *size = end + 1; |
712 | 0 | return (0); |
713 | 0 | } else if (sscanf(tmp, "4;%u;%u", &ypixel, &xpixel) == 2) { |
714 | | /* Window size in pixels. */ |
715 | 0 | char_x = (xpixel && tty->sx) ? xpixel / tty->sx : 0; |
716 | 0 | char_y = (ypixel && tty->sy) ? ypixel / tty->sy : 0; |
717 | 0 | tty_set_size(tty, tty->sx, tty->sy, char_x, char_y); |
718 | 0 | tty_invalidate(tty); |
719 | |
|
720 | 0 | tty->flags &= ~TTY_WINSIZEQUERY; |
721 | 0 | *size = end + 1; |
722 | 0 | return (0); |
723 | 0 | } |
724 | | |
725 | 0 | log_debug("%s: unrecognized window size sequence: %s", c->name, tmp); |
726 | 0 | return (-1); |
727 | 0 | } |
728 | | |
729 | | |
730 | | /* Process at least one key in the buffer. Return 0 if no keys present. */ |
731 | | int |
732 | | tty_keys_next(struct tty *tty) |
733 | 0 | { |
734 | 0 | struct client *c = tty->client; |
735 | 0 | struct timeval tv; |
736 | 0 | const char *buf; |
737 | 0 | size_t len, size; |
738 | 0 | cc_t bspace; |
739 | 0 | int delay, expired = 0, n; |
740 | 0 | key_code key, onlykey; |
741 | 0 | struct mouse_event m = { 0 }; |
742 | 0 | struct key_event *event; |
743 | | |
744 | | /* Get key buffer. */ |
745 | 0 | buf = EVBUFFER_DATA(tty->in); |
746 | 0 | len = EVBUFFER_LENGTH(tty->in); |
747 | 0 | if (len == 0) |
748 | 0 | return (0); |
749 | 0 | log_debug("%s: keys are %zu (%.*s)", c->name, len, (int)len, buf); |
750 | | |
751 | | /* Is this a clipboard response? */ |
752 | 0 | switch (tty_keys_clipboard(tty, buf, len, &size)) { |
753 | 0 | case 0: /* yes */ |
754 | 0 | key = KEYC_UNKNOWN; |
755 | 0 | goto complete_key; |
756 | 0 | case -1: /* no, or not valid */ |
757 | 0 | break; |
758 | 0 | case 1: /* partial */ |
759 | 0 | goto partial_key; |
760 | 0 | } |
761 | | |
762 | | /* Is this a primary device attributes response? */ |
763 | 0 | switch (tty_keys_device_attributes(tty, buf, len, &size)) { |
764 | 0 | case 0: /* yes */ |
765 | 0 | key = KEYC_UNKNOWN; |
766 | 0 | goto complete_key; |
767 | 0 | case -1: /* no, or not valid */ |
768 | 0 | break; |
769 | 0 | case 1: /* partial */ |
770 | 0 | goto partial_key; |
771 | 0 | } |
772 | | |
773 | | /* Is this a secondary device attributes response? */ |
774 | 0 | switch (tty_keys_device_attributes2(tty, buf, len, &size)) { |
775 | 0 | case 0: /* yes */ |
776 | 0 | key = KEYC_UNKNOWN; |
777 | 0 | goto complete_key; |
778 | 0 | case -1: /* no, or not valid */ |
779 | 0 | break; |
780 | 0 | case 1: /* partial */ |
781 | 0 | goto partial_key; |
782 | 0 | } |
783 | | |
784 | | /* Is this an extended device attributes response? */ |
785 | 0 | switch (tty_keys_extended_device_attributes(tty, buf, len, &size)) { |
786 | 0 | case 0: /* yes */ |
787 | 0 | key = KEYC_UNKNOWN; |
788 | 0 | goto complete_key; |
789 | 0 | case -1: /* no, or not valid */ |
790 | 0 | break; |
791 | 0 | case 1: /* partial */ |
792 | 0 | goto partial_key; |
793 | 0 | } |
794 | | |
795 | | /* Is this a colours response? */ |
796 | 0 | switch (tty_keys_colours(tty, buf, len, &size, &tty->fg, &tty->bg)) { |
797 | 0 | case 0: /* yes */ |
798 | 0 | key = KEYC_UNKNOWN; |
799 | 0 | session_theme_changed(c->session); |
800 | 0 | goto complete_key; |
801 | 0 | case -1: /* no, or not valid */ |
802 | 0 | break; |
803 | 0 | case 1: /* partial */ |
804 | 0 | session_theme_changed(c->session); |
805 | 0 | goto partial_key; |
806 | 0 | } |
807 | | |
808 | | /* Is this a palette response? */ |
809 | 0 | switch (tty_keys_palette(tty, buf, len, &size)) { |
810 | 0 | case 0: /* yes */ |
811 | 0 | key = KEYC_UNKNOWN; |
812 | 0 | goto complete_key; |
813 | 0 | case -1: /* no, or not valid */ |
814 | 0 | break; |
815 | 0 | case 1: /* partial */ |
816 | 0 | goto partial_key; |
817 | 0 | } |
818 | | |
819 | | /* Is this a mouse key press? */ |
820 | 0 | switch (tty_keys_mouse(tty, buf, len, &size, &m)) { |
821 | 0 | case 0: /* yes */ |
822 | 0 | key = KEYC_MOUSE; |
823 | 0 | goto complete_key; |
824 | 0 | case -1: /* no, or not valid */ |
825 | 0 | break; |
826 | 0 | case -2: /* yes, but we don't care. */ |
827 | 0 | key = KEYC_MOUSE; |
828 | 0 | goto discard_key; |
829 | 0 | case 1: /* partial */ |
830 | 0 | goto partial_key; |
831 | 0 | } |
832 | | |
833 | | /* Is this an extended key press? */ |
834 | 0 | switch (tty_keys_extended_key(tty, buf, len, &size, &key)) { |
835 | 0 | case 0: /* yes */ |
836 | 0 | goto complete_key; |
837 | 0 | case -1: /* no, or not valid */ |
838 | 0 | break; |
839 | 0 | case 1: /* partial */ |
840 | 0 | goto partial_key; |
841 | 0 | } |
842 | | |
843 | | /* Check for window size query */ |
844 | 0 | switch (tty_keys_winsz(tty, buf, len, &size)) { |
845 | 0 | case 0: /* yes */ |
846 | 0 | key = KEYC_UNKNOWN; |
847 | 0 | goto complete_key; |
848 | 0 | case -1: /* no, or not valid */ |
849 | 0 | break; |
850 | 0 | case 1: /* partial */ |
851 | 0 | goto partial_key; |
852 | 0 | } |
853 | | |
854 | 0 | first_key: |
855 | | /* Try to lookup complete key. */ |
856 | 0 | n = tty_keys_next1(tty, buf, len, &key, &size, expired); |
857 | 0 | if (n == 0) /* found */ |
858 | 0 | goto complete_key; |
859 | 0 | if (n == 1) |
860 | 0 | goto partial_key; |
861 | | |
862 | | /* |
863 | | * If not a complete key, look for key with an escape prefix (meta |
864 | | * modifier). |
865 | | */ |
866 | 0 | if (*buf == '\033' && len > 1) { |
867 | | /* Look for a key without the escape. */ |
868 | 0 | n = tty_keys_next1(tty, buf + 1, len - 1, &key, &size, expired); |
869 | 0 | if (n == 0) { /* found */ |
870 | 0 | if (key & KEYC_IMPLIED_META) { |
871 | | /* |
872 | | * We want the escape key as well as the xterm |
873 | | * key, because the xterm sequence implicitly |
874 | | * includes the escape (so if we see |
875 | | * \033\033[1;3D we know it is an Escape |
876 | | * followed by M-Left, not just M-Left). |
877 | | */ |
878 | 0 | key = '\033'; |
879 | 0 | size = 1; |
880 | 0 | goto complete_key; |
881 | 0 | } |
882 | 0 | key |= KEYC_META; |
883 | 0 | size++; |
884 | 0 | goto complete_key; |
885 | 0 | } |
886 | 0 | if (n == 1) /* partial */ |
887 | 0 | goto partial_key; |
888 | 0 | } |
889 | | |
890 | | /* |
891 | | * At this point, we know the key is not partial (with or without |
892 | | * escape). So pass it through even if the timer has not expired. |
893 | | */ |
894 | 0 | if (*buf == '\033' && len >= 2) { |
895 | 0 | key = (u_char)buf[1] | KEYC_META; |
896 | 0 | size = 2; |
897 | 0 | } else { |
898 | 0 | key = (u_char)buf[0]; |
899 | 0 | size = 1; |
900 | 0 | } |
901 | | |
902 | | /* C-Space is special. */ |
903 | 0 | if ((key & KEYC_MASK_KEY) == C0_NUL) |
904 | 0 | key = ' ' | KEYC_CTRL | (key & KEYC_META); |
905 | | |
906 | | /* |
907 | | * Check for backspace key using termios VERASE - the terminfo |
908 | | * kbs entry is extremely unreliable, so cannot be safely |
909 | | * used. termios should have a better idea. |
910 | | */ |
911 | 0 | bspace = tty->tio.c_cc[VERASE]; |
912 | 0 | if (bspace != _POSIX_VDISABLE) { |
913 | 0 | if (key == bspace) { |
914 | 0 | log_debug("%s: key %#llx is BSpace", c->name, key); |
915 | 0 | key = KEYC_BSPACE; |
916 | 0 | } |
917 | 0 | if (key == (bspace|KEYC_META)) { |
918 | 0 | log_debug("%s: key %#llx is M-BSpace", c->name, key); |
919 | 0 | key = KEYC_BSPACE|KEYC_META; |
920 | 0 | } |
921 | 0 | } |
922 | | |
923 | | /* |
924 | | * Fix up all C0 control codes that don't have a dedicated key into |
925 | | * corresponding Ctrl keys. Convert characters in the A-Z range into |
926 | | * lowercase, so ^A becomes a|CTRL. |
927 | | */ |
928 | 0 | onlykey = key & KEYC_MASK_KEY; |
929 | 0 | if (onlykey < 0x20 && |
930 | 0 | onlykey != C0_HT && |
931 | 0 | onlykey != C0_CR && |
932 | 0 | onlykey != C0_ESC) { |
933 | 0 | onlykey |= 0x40; |
934 | 0 | if (onlykey >= 'A' && onlykey <= 'Z') |
935 | 0 | onlykey |= 0x20; |
936 | 0 | key = onlykey | KEYC_CTRL | (key & KEYC_META); |
937 | 0 | } |
938 | |
|
939 | 0 | goto complete_key; |
940 | | |
941 | 0 | partial_key: |
942 | 0 | log_debug("%s: partial key %.*s", c->name, (int)len, buf); |
943 | | |
944 | | /* If timer is going, check for expiration. */ |
945 | 0 | if (tty->flags & TTY_TIMER) { |
946 | 0 | if (evtimer_initialized(&tty->key_timer) && |
947 | 0 | !evtimer_pending(&tty->key_timer, NULL)) { |
948 | 0 | expired = 1; |
949 | 0 | goto first_key; |
950 | 0 | } |
951 | 0 | return (0); |
952 | 0 | } |
953 | | |
954 | | /* Get the time period. */ |
955 | 0 | delay = options_get_number(global_options, "escape-time"); |
956 | 0 | if (delay == 0) |
957 | 0 | delay = 1; |
958 | 0 | if ((tty->flags & (TTY_WAITFG|TTY_WAITBG) || |
959 | 0 | (tty->flags & TTY_ALL_REQUEST_FLAGS) != TTY_ALL_REQUEST_FLAGS) || |
960 | 0 | !TAILQ_EMPTY(&c->input_requests)) { |
961 | 0 | log_debug("%s: increasing delay for active query", c->name); |
962 | 0 | if (delay < 500) |
963 | 0 | delay = 500; |
964 | 0 | } |
965 | 0 | tv.tv_sec = delay / 1000; |
966 | 0 | tv.tv_usec = (delay % 1000) * 1000L; |
967 | | |
968 | | /* Start the timer. */ |
969 | 0 | if (event_initialized(&tty->key_timer)) |
970 | 0 | evtimer_del(&tty->key_timer); |
971 | 0 | evtimer_set(&tty->key_timer, tty_keys_callback, tty); |
972 | 0 | evtimer_add(&tty->key_timer, &tv); |
973 | |
|
974 | 0 | tty->flags |= TTY_TIMER; |
975 | 0 | return (0); |
976 | | |
977 | 0 | complete_key: |
978 | 0 | log_debug("%s: complete key %.*s %#llx", c->name, (int)size, buf, key); |
979 | | |
980 | | /* Remove key timer. */ |
981 | 0 | if (event_initialized(&tty->key_timer)) |
982 | 0 | evtimer_del(&tty->key_timer); |
983 | 0 | tty->flags &= ~TTY_TIMER; |
984 | | |
985 | | /* Check for focus events. */ |
986 | 0 | if (key == KEYC_FOCUS_OUT) { |
987 | 0 | c->flags &= ~CLIENT_FOCUSED; |
988 | 0 | window_update_focus(c->session->curw->window); |
989 | 0 | notify_client("client-focus-out", c); |
990 | 0 | } else if (key == KEYC_FOCUS_IN) { |
991 | 0 | c->flags |= CLIENT_FOCUSED; |
992 | 0 | notify_client("client-focus-in", c); |
993 | 0 | window_update_focus(c->session->curw->window); |
994 | 0 | } |
995 | | |
996 | | /* Fire the key. */ |
997 | 0 | if (key != KEYC_UNKNOWN) { |
998 | 0 | event = xcalloc(1, sizeof *event); |
999 | 0 | event->key = key; |
1000 | 0 | memcpy(&event->m, &m, sizeof event->m); |
1001 | |
|
1002 | 0 | event->buf = xmalloc(size); |
1003 | 0 | event->len = size; |
1004 | 0 | memcpy (event->buf, buf, event->len); |
1005 | |
|
1006 | 0 | if (!server_client_handle_key(c, event)) { |
1007 | 0 | free(event->buf); |
1008 | 0 | free(event); |
1009 | 0 | } |
1010 | 0 | } |
1011 | | |
1012 | | /* Remove data from buffer. */ |
1013 | 0 | evbuffer_drain(tty->in, size); |
1014 | |
|
1015 | 0 | return (1); |
1016 | | |
1017 | 0 | discard_key: |
1018 | 0 | log_debug("%s: discard key %.*s %#llx", c->name, (int)size, buf, key); |
1019 | | |
1020 | | /* Remove data from buffer. */ |
1021 | 0 | evbuffer_drain(tty->in, size); |
1022 | |
|
1023 | 0 | return (1); |
1024 | 0 | } |
1025 | | |
1026 | | /* Key timer callback. */ |
1027 | | static void |
1028 | | tty_keys_callback(__unused int fd, __unused short events, void *data) |
1029 | 0 | { |
1030 | 0 | struct tty *tty = data; |
1031 | |
|
1032 | 0 | if (tty->flags & TTY_TIMER) { |
1033 | 0 | while (tty_keys_next(tty)) |
1034 | 0 | ; |
1035 | 0 | } |
1036 | 0 | } |
1037 | | |
1038 | | /* |
1039 | | * Handle extended key input. This has two forms: \033[27;m;k~ and \033[k;mu, |
1040 | | * where k is key as a number and m is a modifier. Returns 0 for success, -1 |
1041 | | * for failure, 1 for partial; |
1042 | | */ |
1043 | | static int |
1044 | | tty_keys_extended_key(struct tty *tty, const char *buf, size_t len, |
1045 | | size_t *size, key_code *key) |
1046 | 0 | { |
1047 | 0 | struct client *c = tty->client; |
1048 | 0 | size_t end; |
1049 | 0 | u_int number, modifiers; |
1050 | 0 | char tmp[64]; |
1051 | 0 | cc_t bspace; |
1052 | 0 | key_code nkey, onlykey; |
1053 | 0 | struct utf8_data ud; |
1054 | 0 | utf8_char uc; |
1055 | |
|
1056 | 0 | *size = 0; |
1057 | | |
1058 | | /* First two bytes are always \033[. */ |
1059 | 0 | if (buf[0] != '\033') |
1060 | 0 | return (-1); |
1061 | 0 | if (len == 1) |
1062 | 0 | return (1); |
1063 | 0 | if (buf[1] != '[') |
1064 | 0 | return (-1); |
1065 | 0 | if (len == 2) |
1066 | 0 | return (1); |
1067 | | |
1068 | | /* |
1069 | | * Look for a terminator. Stop at either '~' or anything that isn't a |
1070 | | * number or ';'. |
1071 | | */ |
1072 | 0 | for (end = 2; end < len && end != sizeof tmp; end++) { |
1073 | 0 | if (buf[end] == '~') |
1074 | 0 | break; |
1075 | 0 | if (!isdigit((u_char)buf[end]) && buf[end] != ';') |
1076 | 0 | break; |
1077 | 0 | } |
1078 | 0 | if (end == len) |
1079 | 0 | return (1); |
1080 | 0 | if (end == sizeof tmp || (buf[end] != '~' && buf[end] != 'u')) |
1081 | 0 | return (-1); |
1082 | | |
1083 | | /* Copy to the buffer. */ |
1084 | 0 | memcpy(tmp, buf + 2, end - 2); |
1085 | 0 | tmp[end - 2] = '\0'; |
1086 | | |
1087 | | /* Try to parse either form of key. */ |
1088 | 0 | if (buf[end] == '~') { |
1089 | 0 | if (sscanf(tmp, "27;%u;%u", &modifiers, &number) != 2) |
1090 | 0 | return (-1); |
1091 | 0 | } else { |
1092 | 0 | if (sscanf(tmp ,"%u;%u", &number, &modifiers) != 2) |
1093 | 0 | return (-1); |
1094 | 0 | } |
1095 | 0 | *size = end + 1; |
1096 | | |
1097 | | /* Store the key. */ |
1098 | 0 | bspace = tty->tio.c_cc[VERASE]; |
1099 | 0 | if (bspace != _POSIX_VDISABLE && number == bspace) |
1100 | 0 | nkey = KEYC_BSPACE; |
1101 | 0 | else |
1102 | 0 | nkey = number; |
1103 | | |
1104 | | /* Convert UTF-32 codepoint into internal representation. */ |
1105 | 0 | if (nkey != KEYC_BSPACE && nkey & ~0x7f) { |
1106 | 0 | if (utf8_fromwc(nkey, &ud) == UTF8_DONE && |
1107 | 0 | utf8_from_data(&ud, &uc) == UTF8_DONE) |
1108 | 0 | nkey = uc; |
1109 | 0 | else |
1110 | 0 | return (-1); |
1111 | 0 | } |
1112 | | |
1113 | | /* Update the modifiers. */ |
1114 | 0 | if (modifiers > 0) { |
1115 | 0 | modifiers--; |
1116 | 0 | if (modifiers & 1) |
1117 | 0 | nkey |= KEYC_SHIFT; |
1118 | 0 | if (modifiers & 2) |
1119 | 0 | nkey |= (KEYC_META|KEYC_IMPLIED_META); /* Alt */ |
1120 | 0 | if (modifiers & 4) |
1121 | 0 | nkey |= KEYC_CTRL; |
1122 | 0 | if (modifiers & 8) |
1123 | 0 | nkey |= (KEYC_META|KEYC_IMPLIED_META); /* Meta */ |
1124 | 0 | } |
1125 | | |
1126 | | /* Convert S-Tab into Backtab. */ |
1127 | 0 | if ((nkey & KEYC_MASK_KEY) == '\011' && (nkey & KEYC_SHIFT)) |
1128 | 0 | nkey = KEYC_BTAB | (nkey & ~KEYC_MASK_KEY & ~KEYC_SHIFT); |
1129 | | |
1130 | | /* |
1131 | | * Deal with the Shift modifier when present alone. The problem is that |
1132 | | * in mode 2 some terminals would report shifted keys, like S-a, as |
1133 | | * just A, and some as S-A. |
1134 | | * |
1135 | | * Because we need an unambiguous internal representation, and because |
1136 | | * restoring the Shift modifier when it's missing would require knowing |
1137 | | * the keyboard layout, and because S-A would cause a lot of issues |
1138 | | * downstream, we choose to lose the Shift for all printable |
1139 | | * characters. |
1140 | | * |
1141 | | * That still leaves some ambiguity, such as C-S-A vs. C-A, but that's |
1142 | | * OK, and applications can handle that. |
1143 | | */ |
1144 | 0 | onlykey = nkey & KEYC_MASK_KEY; |
1145 | 0 | if (((onlykey > 0x20 && onlykey < 0x7f) || |
1146 | 0 | KEYC_IS_UNICODE(nkey)) && |
1147 | 0 | (nkey & KEYC_MASK_MODIFIERS) == KEYC_SHIFT) |
1148 | 0 | nkey &= ~KEYC_SHIFT; |
1149 | |
|
1150 | 0 | if (log_get_level() != 0) { |
1151 | 0 | log_debug("%s: extended key %.*s is %llx (%s)", c->name, |
1152 | 0 | (int)*size, buf, nkey, key_string_lookup_key(nkey, 1)); |
1153 | 0 | } |
1154 | |
|
1155 | 0 | *key = nkey; |
1156 | 0 | return (0); |
1157 | 0 | } |
1158 | | |
1159 | | /* |
1160 | | * Handle mouse key input. Returns 0 for success, -1 for failure, 1 for partial |
1161 | | * (probably a mouse sequence but need more data), -2 if an invalid mouse |
1162 | | * sequence. |
1163 | | */ |
1164 | | static int |
1165 | | tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size, |
1166 | | struct mouse_event *m) |
1167 | 0 | { |
1168 | 0 | struct client *c = tty->client; |
1169 | 0 | u_int i, x, y, b, sgr_b; |
1170 | 0 | u_char sgr_type, ch; |
1171 | | |
1172 | | /* |
1173 | | * Standard mouse sequences are \033[M followed by three characters |
1174 | | * indicating button, X and Y, all based at 32 with 1,1 top-left. |
1175 | | * |
1176 | | * UTF-8 mouse sequences are similar but the three are expressed as |
1177 | | * UTF-8 characters. |
1178 | | * |
1179 | | * SGR extended mouse sequences are \033[< followed by three numbers in |
1180 | | * decimal and separated by semicolons indicating button, X and Y. A |
1181 | | * trailing 'M' is click or scroll and trailing 'm' release. All are |
1182 | | * based at 0 with 1,1 top-left. |
1183 | | */ |
1184 | |
|
1185 | 0 | *size = 0; |
1186 | 0 | x = y = b = sgr_b = 0; |
1187 | 0 | sgr_type = ' '; |
1188 | | |
1189 | | /* First two bytes are always \033[. */ |
1190 | 0 | if (buf[0] != '\033') |
1191 | 0 | return (-1); |
1192 | 0 | if (len == 1) |
1193 | 0 | return (1); |
1194 | 0 | if (buf[1] != '[') |
1195 | 0 | return (-1); |
1196 | 0 | if (len == 2) |
1197 | 0 | return (1); |
1198 | | |
1199 | | /* |
1200 | | * Third byte is M in old standard (and UTF-8 extension which we do not |
1201 | | * support), < in SGR extension. |
1202 | | */ |
1203 | 0 | if (buf[2] == 'M') { |
1204 | | /* Read the three inputs. */ |
1205 | 0 | *size = 3; |
1206 | 0 | for (i = 0; i < 3; i++) { |
1207 | 0 | if (len <= *size) |
1208 | 0 | return (1); |
1209 | 0 | ch = (u_char)buf[(*size)++]; |
1210 | 0 | if (i == 0) |
1211 | 0 | b = ch; |
1212 | 0 | else if (i == 1) |
1213 | 0 | x = ch; |
1214 | 0 | else |
1215 | 0 | y = ch; |
1216 | 0 | } |
1217 | 0 | log_debug("%s: mouse input: %.*s", c->name, (int)*size, buf); |
1218 | | |
1219 | | /* Check and return the mouse input. */ |
1220 | 0 | if (b < MOUSE_PARAM_BTN_OFF || |
1221 | 0 | x < MOUSE_PARAM_POS_OFF || |
1222 | 0 | y < MOUSE_PARAM_POS_OFF) |
1223 | 0 | return (-2); |
1224 | 0 | b -= MOUSE_PARAM_BTN_OFF; |
1225 | 0 | x -= MOUSE_PARAM_POS_OFF; |
1226 | 0 | y -= MOUSE_PARAM_POS_OFF; |
1227 | 0 | } else if (buf[2] == '<') { |
1228 | | /* Read the three inputs. */ |
1229 | 0 | *size = 3; |
1230 | 0 | while (1) { |
1231 | 0 | if (len <= *size) |
1232 | 0 | return (1); |
1233 | 0 | ch = (u_char)buf[(*size)++]; |
1234 | 0 | if (ch == ';') |
1235 | 0 | break; |
1236 | 0 | if (ch < '0' || ch > '9') |
1237 | 0 | return (-1); |
1238 | 0 | sgr_b = 10 * sgr_b + (ch - '0'); |
1239 | 0 | } |
1240 | 0 | while (1) { |
1241 | 0 | if (len <= *size) |
1242 | 0 | return (1); |
1243 | 0 | ch = (u_char)buf[(*size)++]; |
1244 | 0 | if (ch == ';') |
1245 | 0 | break; |
1246 | 0 | if (ch < '0' || ch > '9') |
1247 | 0 | return (-1); |
1248 | 0 | x = 10 * x + (ch - '0'); |
1249 | 0 | } |
1250 | 0 | while (1) { |
1251 | 0 | if (len <= *size) |
1252 | 0 | return (1); |
1253 | 0 | ch = (u_char)buf[(*size)++]; |
1254 | 0 | if (ch == 'M' || ch == 'm') |
1255 | 0 | break; |
1256 | 0 | if (ch < '0' || ch > '9') |
1257 | 0 | return (-1); |
1258 | 0 | y = 10 * y + (ch - '0'); |
1259 | 0 | } |
1260 | 0 | log_debug("%s: mouse input (SGR): %.*s", c->name, (int)*size, |
1261 | 0 | buf); |
1262 | | |
1263 | | /* Check and return the mouse input. */ |
1264 | 0 | if (x < 1 || y < 1) |
1265 | 0 | return (-2); |
1266 | 0 | x--; |
1267 | 0 | y--; |
1268 | 0 | b = sgr_b; |
1269 | | |
1270 | | /* Type is M for press, m for release. */ |
1271 | 0 | sgr_type = ch; |
1272 | 0 | if (sgr_type == 'm') |
1273 | 0 | b = 3; |
1274 | | |
1275 | | /* |
1276 | | * Some terminals (like PuTTY 0.63) mistakenly send |
1277 | | * button-release events for scroll-wheel button-press event. |
1278 | | * Discard it before it reaches any program running inside |
1279 | | * tmux. |
1280 | | */ |
1281 | 0 | if (sgr_type == 'm' && MOUSE_WHEEL(sgr_b)) |
1282 | 0 | return (-2); |
1283 | 0 | } else |
1284 | 0 | return (-1); |
1285 | | |
1286 | | /* Fill mouse event. */ |
1287 | 0 | m->lx = tty->mouse_last_x; |
1288 | 0 | m->x = x; |
1289 | 0 | m->ly = tty->mouse_last_y; |
1290 | 0 | m->y = y; |
1291 | 0 | m->lb = tty->mouse_last_b; |
1292 | 0 | m->b = b; |
1293 | 0 | m->sgr_type = sgr_type; |
1294 | 0 | m->sgr_b = sgr_b; |
1295 | | |
1296 | | /* Update last mouse state. */ |
1297 | 0 | tty->mouse_last_x = x; |
1298 | 0 | tty->mouse_last_y = y; |
1299 | 0 | tty->mouse_last_b = b; |
1300 | |
|
1301 | 0 | return (0); |
1302 | 0 | } |
1303 | | |
1304 | | /* |
1305 | | * Handle OSC 52 clipboard input. Returns 0 for success, -1 for failure, 1 for |
1306 | | * partial. |
1307 | | */ |
1308 | | static int |
1309 | | tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size) |
1310 | 0 | { |
1311 | 0 | struct client *c = tty->client; |
1312 | 0 | size_t end, terminator = 0, needed; |
1313 | 0 | char *copy, *out; |
1314 | 0 | int outlen; |
1315 | 0 | struct input_request_clipboard_data cd; |
1316 | |
|
1317 | 0 | *size = 0; |
1318 | | |
1319 | | /* First five bytes are always \033]52;. */ |
1320 | 0 | if (buf[0] != '\033') |
1321 | 0 | return (-1); |
1322 | 0 | if (len == 1) |
1323 | 0 | return (1); |
1324 | 0 | if (buf[1] != ']') |
1325 | 0 | return (-1); |
1326 | 0 | if (len == 2) |
1327 | 0 | return (1); |
1328 | 0 | if (buf[2] != '5') |
1329 | 0 | return (-1); |
1330 | 0 | if (len == 3) |
1331 | 0 | return (1); |
1332 | 0 | if (buf[3] != '2') |
1333 | 0 | return (-1); |
1334 | 0 | if (len == 4) |
1335 | 0 | return (1); |
1336 | 0 | if (buf[4] != ';') |
1337 | 0 | return (-1); |
1338 | 0 | if (len == 5) |
1339 | 0 | return (1); |
1340 | | |
1341 | | /* Find the terminator if any. */ |
1342 | 0 | for (end = 5; end < len; end++) { |
1343 | 0 | if (buf[end] == '\007') { |
1344 | 0 | terminator = 1; |
1345 | 0 | break; |
1346 | 0 | } |
1347 | 0 | if (end > 5 && buf[end - 1] == '\033' && buf[end] == '\\') { |
1348 | 0 | terminator = 2; |
1349 | 0 | break; |
1350 | 0 | } |
1351 | 0 | } |
1352 | 0 | if (end == len) |
1353 | 0 | return (1); |
1354 | 0 | *size = end + 1; |
1355 | | |
1356 | | /* Skip the initial part. */ |
1357 | 0 | buf += 5; |
1358 | 0 | end -= 5; |
1359 | | |
1360 | | /* Adjust end so that it points to the start of the terminator. */ |
1361 | 0 | end -= terminator - 1; |
1362 | | |
1363 | | /* Get the second argument. */ |
1364 | 0 | while (end != 0 && *buf != ';') { |
1365 | 0 | buf++; |
1366 | 0 | end--; |
1367 | 0 | } |
1368 | 0 | if (end == 0 || end == 1) |
1369 | 0 | return (0); |
1370 | 0 | buf++; |
1371 | 0 | end--; |
1372 | | |
1373 | | /* It has to be a string so copy it. */ |
1374 | 0 | copy = xmalloc(end + 1); |
1375 | 0 | memcpy(copy, buf, end); |
1376 | 0 | copy[end] = '\0'; |
1377 | | |
1378 | | /* Convert from base64. */ |
1379 | 0 | needed = (end / 4) * 3; |
1380 | 0 | out = xmalloc(needed); |
1381 | 0 | if ((outlen = b64_pton(copy, out, len)) == -1) { |
1382 | 0 | free(out); |
1383 | 0 | free(copy); |
1384 | 0 | return (0); |
1385 | 0 | } |
1386 | 0 | free(copy); |
1387 | 0 | log_debug("%s: %.*s", __func__, outlen, out); |
1388 | | |
1389 | | /* Set reply if any. */ |
1390 | 0 | cd.buf = out; |
1391 | 0 | cd.len = outlen; |
1392 | 0 | input_request_reply(c, INPUT_REQUEST_CLIPBOARD, &cd); |
1393 | | |
1394 | | /* Create a buffer if requested. */ |
1395 | 0 | if (tty->flags & TTY_OSC52QUERY) { |
1396 | 0 | paste_add(NULL, out, outlen); |
1397 | 0 | out = NULL; |
1398 | 0 | evtimer_del(&tty->clipboard_timer); |
1399 | 0 | tty->flags &= ~TTY_OSC52QUERY; |
1400 | 0 | } |
1401 | |
|
1402 | 0 | free(out); |
1403 | 0 | return (0); |
1404 | 0 | } |
1405 | | |
1406 | | /* |
1407 | | * Handle primary device attributes input. Returns 0 for success, -1 for |
1408 | | * failure, 1 for partial. |
1409 | | */ |
1410 | | static int |
1411 | | tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len, |
1412 | | size_t *size) |
1413 | 0 | { |
1414 | 0 | struct client *c = tty->client; |
1415 | 0 | int *features = &c->term_features; |
1416 | 0 | u_int i, n = 0; |
1417 | 0 | char tmp[128], *endptr, p[32] = { 0 }, *cp, *next; |
1418 | |
|
1419 | 0 | *size = 0; |
1420 | 0 | if (tty->flags & TTY_HAVEDA) |
1421 | 0 | return (-1); |
1422 | | |
1423 | | /* First three bytes are always \033[?. */ |
1424 | 0 | if (buf[0] != '\033') |
1425 | 0 | return (-1); |
1426 | 0 | if (len == 1) |
1427 | 0 | return (1); |
1428 | 0 | if (buf[1] != '[') |
1429 | 0 | return (-1); |
1430 | 0 | if (len == 2) |
1431 | 0 | return (1); |
1432 | 0 | if (buf[2] != '?') |
1433 | 0 | return (-1); |
1434 | 0 | if (len == 3) |
1435 | 0 | return (1); |
1436 | | |
1437 | | /* Copy the rest up to a c. */ |
1438 | 0 | for (i = 0; i < sizeof tmp; i++) { |
1439 | 0 | if (3 + i == len) |
1440 | 0 | return (1); |
1441 | 0 | if (buf[3 + i] >= 'a' && buf[3 + i] <= 'z') |
1442 | 0 | break; |
1443 | 0 | tmp[i] = buf[3 + i]; |
1444 | 0 | } |
1445 | 0 | if (i == sizeof tmp) |
1446 | 0 | return (-1); |
1447 | 0 | if (buf[3 + i] != 'c') |
1448 | 0 | return (-1); |
1449 | 0 | tmp[i] = '\0'; |
1450 | 0 | *size = 4 + i; |
1451 | | |
1452 | | /* Convert all arguments to numbers. */ |
1453 | 0 | cp = tmp; |
1454 | 0 | while ((next = strsep(&cp, ";")) != NULL) { |
1455 | 0 | p[n] = strtoul(next, &endptr, 10); |
1456 | 0 | if (*endptr != '\0') |
1457 | 0 | p[n] = 0; |
1458 | 0 | if (++n == nitems(p)) |
1459 | 0 | break; |
1460 | 0 | } |
1461 | | |
1462 | | /* Add terminal features. */ |
1463 | 0 | switch (p[0]) { |
1464 | 0 | case 61: /* level 1 */ |
1465 | 0 | case 62: /* level 2 */ |
1466 | 0 | case 63: /* level 3 */ |
1467 | 0 | case 64: /* level 4 */ |
1468 | 0 | case 65: /* level 5 */ |
1469 | 0 | for (i = 1; i < n; i++) { |
1470 | 0 | log_debug("%s: DA feature: %d", c->name, p[i]); |
1471 | 0 | if (p[i] == 4) |
1472 | 0 | tty_add_features(features, "sixel", ","); |
1473 | 0 | if (p[i] == 21) |
1474 | 0 | tty_add_features(features, "margins", ","); |
1475 | 0 | if (p[i] == 28) |
1476 | 0 | tty_add_features(features, "rectfill", ","); |
1477 | 0 | if (p[i] == 52) |
1478 | 0 | tty_add_features(features, "clipboard", ","); |
1479 | 0 | } |
1480 | 0 | break; |
1481 | 0 | } |
1482 | 0 | log_debug("%s: received primary DA %.*s", c->name, (int)*size, buf); |
1483 | |
|
1484 | 0 | tty_update_features(tty); |
1485 | 0 | tty->flags |= TTY_HAVEDA; |
1486 | |
|
1487 | 0 | return (0); |
1488 | 0 | } |
1489 | | |
1490 | | /* |
1491 | | * Handle secondary device attributes input. Returns 0 for success, -1 for |
1492 | | * failure, 1 for partial. |
1493 | | */ |
1494 | | static int |
1495 | | tty_keys_device_attributes2(struct tty *tty, const char *buf, size_t len, |
1496 | | size_t *size) |
1497 | 0 | { |
1498 | 0 | struct client *c = tty->client; |
1499 | 0 | int *features = &c->term_features; |
1500 | 0 | u_int i, n = 0; |
1501 | 0 | char tmp[128], *endptr, p[32] = { 0 }, *cp, *next; |
1502 | |
|
1503 | 0 | *size = 0; |
1504 | 0 | if (tty->flags & TTY_HAVEDA2) |
1505 | 0 | return (-1); |
1506 | | |
1507 | | /* First three bytes are always \033[>. */ |
1508 | 0 | if (buf[0] != '\033') |
1509 | 0 | return (-1); |
1510 | 0 | if (len == 1) |
1511 | 0 | return (1); |
1512 | 0 | if (buf[1] != '[') |
1513 | 0 | return (-1); |
1514 | 0 | if (len == 2) |
1515 | 0 | return (1); |
1516 | 0 | if (buf[2] != '>') |
1517 | 0 | return (-1); |
1518 | 0 | if (len == 3) |
1519 | 0 | return (1); |
1520 | | |
1521 | | /* Copy the rest up to a c. */ |
1522 | 0 | for (i = 0; i < sizeof tmp; i++) { |
1523 | 0 | if (3 + i == len) |
1524 | 0 | return (1); |
1525 | 0 | if (buf[3 + i] >= 'a' && buf[3 + i] <= 'z') |
1526 | 0 | break; |
1527 | 0 | tmp[i] = buf[3 + i]; |
1528 | 0 | } |
1529 | 0 | if (i == sizeof tmp) |
1530 | 0 | return (-1); |
1531 | 0 | if (buf[3 + i] != 'c') |
1532 | 0 | return (-1); |
1533 | 0 | tmp[i] = '\0'; |
1534 | 0 | *size = 4 + i; |
1535 | | |
1536 | | /* Convert all arguments to numbers. */ |
1537 | 0 | cp = tmp; |
1538 | 0 | while ((next = strsep(&cp, ";")) != NULL) { |
1539 | 0 | p[n] = strtoul(next, &endptr, 10); |
1540 | 0 | if (*endptr != '\0') |
1541 | 0 | p[n] = 0; |
1542 | 0 | if (++n == nitems(p)) |
1543 | 0 | break; |
1544 | 0 | } |
1545 | | |
1546 | | /* |
1547 | | * Add terminal features. We add DECSLRM and DECFRA for some |
1548 | | * identification codes here, notably 64 will catch VT520, even though |
1549 | | * we can't use level 5 from DA because of VTE. |
1550 | | */ |
1551 | 0 | switch (p[0]) { |
1552 | 0 | case 'M': /* mintty */ |
1553 | 0 | tty_default_features(features, "mintty", 0); |
1554 | 0 | break; |
1555 | 0 | case 'T': /* tmux */ |
1556 | 0 | tty_default_features(features, "tmux", 0); |
1557 | 0 | break; |
1558 | 0 | case 'U': /* rxvt-unicode */ |
1559 | 0 | tty_default_features(features, "rxvt-unicode", 0); |
1560 | 0 | break; |
1561 | 0 | } |
1562 | 0 | log_debug("%s: received secondary DA %.*s", c->name, (int)*size, buf); |
1563 | |
|
1564 | 0 | tty_update_features(tty); |
1565 | 0 | tty->flags |= TTY_HAVEDA2; |
1566 | |
|
1567 | 0 | return (0); |
1568 | 0 | } |
1569 | | |
1570 | | /* |
1571 | | * Handle extended device attributes input. Returns 0 for success, -1 for |
1572 | | * failure, 1 for partial. |
1573 | | */ |
1574 | | static int |
1575 | | tty_keys_extended_device_attributes(struct tty *tty, const char *buf, |
1576 | | size_t len, size_t *size) |
1577 | 0 | { |
1578 | 0 | struct client *c = tty->client; |
1579 | 0 | int *features = &c->term_features; |
1580 | 0 | u_int i; |
1581 | 0 | char tmp[128]; |
1582 | |
|
1583 | 0 | *size = 0; |
1584 | 0 | if (tty->flags & TTY_HAVEXDA) |
1585 | 0 | return (-1); |
1586 | | |
1587 | | /* First four bytes are always \033P>|. */ |
1588 | 0 | if (buf[0] != '\033') |
1589 | 0 | return (-1); |
1590 | 0 | if (len == 1) |
1591 | 0 | return (1); |
1592 | 0 | if (buf[1] != 'P') |
1593 | 0 | return (-1); |
1594 | 0 | if (len == 2) |
1595 | 0 | return (1); |
1596 | 0 | if (buf[2] != '>') |
1597 | 0 | return (-1); |
1598 | 0 | if (len == 3) |
1599 | 0 | return (1); |
1600 | 0 | if (buf[3] != '|') |
1601 | 0 | return (-1); |
1602 | 0 | if (len == 4) |
1603 | 0 | return (1); |
1604 | | |
1605 | | /* Copy the rest up to \033\. */ |
1606 | 0 | for (i = 0; i < (sizeof tmp) - 1; i++) { |
1607 | 0 | if (4 + i == len) |
1608 | 0 | return (1); |
1609 | 0 | if (buf[4 + i - 1] == '\033' && buf[4 + i] == '\\') |
1610 | 0 | break; |
1611 | 0 | tmp[i] = buf[4 + i]; |
1612 | 0 | } |
1613 | 0 | if (i == (sizeof tmp) - 1) |
1614 | 0 | return (-1); |
1615 | 0 | tmp[i - 1] = '\0'; |
1616 | 0 | *size = 5 + i; |
1617 | | |
1618 | | /* Add terminal features. */ |
1619 | 0 | if (strncmp(tmp, "iTerm2 ", 7) == 0) |
1620 | 0 | tty_default_features(features, "iTerm2", 0); |
1621 | 0 | else if (strncmp(tmp, "tmux ", 5) == 0) |
1622 | 0 | tty_default_features(features, "tmux", 0); |
1623 | 0 | else if (strncmp(tmp, "XTerm(", 6) == 0) |
1624 | 0 | tty_default_features(features, "XTerm", 0); |
1625 | 0 | else if (strncmp(tmp, "mintty ", 7) == 0) |
1626 | 0 | tty_default_features(features, "mintty", 0); |
1627 | 0 | else if (strncmp(tmp, "foot(", 5) == 0) |
1628 | 0 | tty_default_features(features, "foot", 0); |
1629 | 0 | log_debug("%s: received extended DA %.*s", c->name, (int)*size, buf); |
1630 | |
|
1631 | 0 | free(c->term_type); |
1632 | 0 | c->term_type = xstrdup(tmp); |
1633 | |
|
1634 | 0 | tty_update_features(tty); |
1635 | 0 | tty->flags |= TTY_HAVEXDA; |
1636 | |
|
1637 | 0 | return (0); |
1638 | 0 | } |
1639 | | |
1640 | | /* |
1641 | | * Handle foreground or background input. Returns 0 for success, -1 for |
1642 | | * failure, 1 for partial. |
1643 | | */ |
1644 | | int |
1645 | | tty_keys_colours(struct tty *tty, const char *buf, size_t len, size_t *size, |
1646 | | int *fg, int *bg) |
1647 | 0 | { |
1648 | 0 | struct client *c = tty->client; |
1649 | 0 | u_int i; |
1650 | 0 | char tmp[128]; |
1651 | 0 | int n; |
1652 | |
|
1653 | 0 | *size = 0; |
1654 | | |
1655 | | /* First four bytes are always \033]1 and 0 or 1 and ;. */ |
1656 | 0 | if (buf[0] != '\033') |
1657 | 0 | return (-1); |
1658 | 0 | if (len == 1) |
1659 | 0 | return (1); |
1660 | 0 | if (buf[1] != ']') |
1661 | 0 | return (-1); |
1662 | 0 | if (len == 2) |
1663 | 0 | return (1); |
1664 | 0 | if (buf[2] != '1') |
1665 | 0 | return (-1); |
1666 | 0 | if (len == 3) |
1667 | 0 | return (1); |
1668 | 0 | if (buf[3] != '0' && buf[3] != '1') |
1669 | 0 | return (-1); |
1670 | 0 | if (len == 4) |
1671 | 0 | return (1); |
1672 | 0 | if (buf[4] != ';') |
1673 | 0 | return (-1); |
1674 | 0 | if (len == 5) |
1675 | 0 | return (1); |
1676 | | |
1677 | | /* Copy the rest up to \033\ or \007. */ |
1678 | 0 | for (i = 0; i < (sizeof tmp) - 1; i++) { |
1679 | 0 | if (5 + i == len) |
1680 | 0 | return (1); |
1681 | 0 | if (buf[5 + i - 1] == '\033' && buf[5 + i] == '\\') |
1682 | 0 | break; |
1683 | 0 | if (buf[5 + i] == '\007') |
1684 | 0 | break; |
1685 | 0 | tmp[i] = buf[5 + i]; |
1686 | 0 | } |
1687 | 0 | if (i == (sizeof tmp) - 1) |
1688 | 0 | return (-1); |
1689 | 0 | if (tmp[i - 1] == '\033') |
1690 | 0 | tmp[i - 1] = '\0'; |
1691 | 0 | else |
1692 | 0 | tmp[i] = '\0'; |
1693 | 0 | *size = 6 + i; |
1694 | | |
1695 | | /* Work out the colour. */ |
1696 | 0 | n = colour_parseX11(tmp); |
1697 | 0 | if (n != -1 && buf[3] == '0') { |
1698 | 0 | if (c != NULL) |
1699 | 0 | log_debug("%s fg is %s", c->name, colour_tostring(n)); |
1700 | 0 | else |
1701 | 0 | log_debug("fg is %s", colour_tostring(n)); |
1702 | 0 | *fg = n; |
1703 | 0 | tty->flags &= ~TTY_WAITFG; |
1704 | 0 | } else if (n != -1) { |
1705 | 0 | if (c != NULL) |
1706 | 0 | log_debug("%s bg is %s", c->name, colour_tostring(n)); |
1707 | 0 | else |
1708 | 0 | log_debug("bg is %s", colour_tostring(n)); |
1709 | 0 | *bg = n; |
1710 | 0 | tty->flags &= ~TTY_WAITBG; |
1711 | 0 | } |
1712 | |
|
1713 | 0 | return (0); |
1714 | 0 | } |
1715 | | |
1716 | | /* Handle OSC 4 palette colour responses. */ |
1717 | | static int |
1718 | | tty_keys_palette(struct tty *tty, const char *buf, size_t len, size_t *size) |
1719 | 0 | { |
1720 | 0 | struct client *c = tty->client; |
1721 | 0 | u_int i; |
1722 | 0 | char tmp[128], *endptr; |
1723 | 0 | int idx; |
1724 | 0 | struct input_request_palette_data pd; |
1725 | |
|
1726 | 0 | *size = 0; |
1727 | | |
1728 | | /* First three bytes are always \033]4. */ |
1729 | 0 | if (buf[0] != '\033') |
1730 | 0 | return (-1); |
1731 | 0 | if (len == 1) |
1732 | 0 | return (1); |
1733 | 0 | if (buf[1] != ']') |
1734 | 0 | return (-1); |
1735 | 0 | if (len == 2) |
1736 | 0 | return (1); |
1737 | 0 | if (buf[2] != '4') |
1738 | 0 | return (-1); |
1739 | 0 | if (len == 3) |
1740 | 0 | return (1); |
1741 | 0 | if (buf[3] != ';') |
1742 | 0 | return (-1); |
1743 | 0 | if (len == 4) |
1744 | 0 | return (1); |
1745 | | |
1746 | | /* Copy the rest up to \033\ or \007. */ |
1747 | 0 | for (i = 0; i < (sizeof tmp) - 1; i++) { |
1748 | 0 | if (4 + i == len) |
1749 | 0 | return (1); |
1750 | 0 | if (buf[4 + i - 1] == '\033' && buf[4 + i] == '\\') |
1751 | 0 | break; |
1752 | 0 | if (buf[4 + i] == '\007') |
1753 | 0 | break; |
1754 | 0 | tmp[i] = buf[4 + i]; |
1755 | 0 | } |
1756 | 0 | if (i == (sizeof tmp) - 1) |
1757 | 0 | return (-1); |
1758 | 0 | if (tmp[i - 1] == '\033') |
1759 | 0 | tmp[i - 1] = '\0'; |
1760 | 0 | else |
1761 | 0 | tmp[i] = '\0'; |
1762 | 0 | *size = 5 + i; |
1763 | | |
1764 | | /* Parse index. */ |
1765 | 0 | idx = strtol(tmp, &endptr, 10); |
1766 | 0 | if (*endptr != ';') |
1767 | 0 | return (-1); |
1768 | 0 | if (idx < 0 || idx > 255) |
1769 | 0 | return (-1); |
1770 | | |
1771 | | /* Work out the colour. */ |
1772 | 0 | pd.c = colour_parseX11(endptr + 1); |
1773 | 0 | if (pd.c == -1) |
1774 | 0 | return (0); |
1775 | 0 | pd.idx = idx; |
1776 | 0 | input_request_reply(c, INPUT_REQUEST_PALETTE, &pd); |
1777 | |
|
1778 | 0 | return (0); |
1779 | 0 | } |