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