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