1 |
|
|
/* $OpenBSD: input.c,v 1.128 2017/09/10 08:01:23 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 |
|
|
|
21 |
|
|
#include <netinet/in.h> |
22 |
|
|
|
23 |
|
|
#include <resolv.h> |
24 |
|
|
#include <stdlib.h> |
25 |
|
|
#include <string.h> |
26 |
|
|
#include <time.h> |
27 |
|
|
|
28 |
|
|
#include "tmux.h" |
29 |
|
|
|
30 |
|
|
/* |
31 |
|
|
* Based on the description by Paul Williams at: |
32 |
|
|
* |
33 |
|
|
* http://vt100.net/emu/dec_ansi_parser |
34 |
|
|
* |
35 |
|
|
* With the following changes: |
36 |
|
|
* |
37 |
|
|
* - 7-bit only. |
38 |
|
|
* |
39 |
|
|
* - Support for UTF-8. |
40 |
|
|
* |
41 |
|
|
* - OSC (but not APC) may be terminated by \007 as well as ST. |
42 |
|
|
* |
43 |
|
|
* - A state for APC similar to OSC. Some terminals appear to use this to set |
44 |
|
|
* the title. |
45 |
|
|
* |
46 |
|
|
* - A state for the screen \033k...\033\\ sequence to rename a window. This is |
47 |
|
|
* pretty stupid but not supporting it is more trouble than it is worth. |
48 |
|
|
* |
49 |
|
|
* - Special handling for ESC inside a DCS to allow arbitrary byte sequences to |
50 |
|
|
* be passed to the underlying terminals. |
51 |
|
|
*/ |
52 |
|
|
|
53 |
|
|
/* Input parser cell. */ |
54 |
|
|
struct input_cell { |
55 |
|
|
struct grid_cell cell; |
56 |
|
|
int set; |
57 |
|
|
int g0set; /* 1 if ACS */ |
58 |
|
|
int g1set; /* 1 if ACS */ |
59 |
|
|
}; |
60 |
|
|
|
61 |
|
|
/* Input parser context. */ |
62 |
|
|
struct input_ctx { |
63 |
|
|
struct window_pane *wp; |
64 |
|
|
struct screen_write_ctx ctx; |
65 |
|
|
|
66 |
|
|
struct input_cell cell; |
67 |
|
|
|
68 |
|
|
struct input_cell old_cell; |
69 |
|
|
u_int old_cx; |
70 |
|
|
u_int old_cy; |
71 |
|
|
|
72 |
|
|
u_char interm_buf[4]; |
73 |
|
|
size_t interm_len; |
74 |
|
|
|
75 |
|
|
u_char param_buf[64]; |
76 |
|
|
size_t param_len; |
77 |
|
|
|
78 |
|
|
#define INPUT_BUF_START 32 |
79 |
|
|
#define INPUT_BUF_LIMIT 1048576 |
80 |
|
|
u_char *input_buf; |
81 |
|
|
size_t input_len; |
82 |
|
|
size_t input_space; |
83 |
|
|
|
84 |
|
|
int param_list[24]; /* -1 not present */ |
85 |
|
|
u_int param_list_len; |
86 |
|
|
|
87 |
|
|
struct utf8_data utf8data; |
88 |
|
|
|
89 |
|
|
int ch; |
90 |
|
|
int last; |
91 |
|
|
|
92 |
|
|
int flags; |
93 |
|
|
#define INPUT_DISCARD 0x1 |
94 |
|
|
|
95 |
|
|
const struct input_state *state; |
96 |
|
|
|
97 |
|
|
struct event timer; |
98 |
|
|
|
99 |
|
|
/* |
100 |
|
|
* All input received since we were last in the ground state. Sent to |
101 |
|
|
* control clients on connection. |
102 |
|
|
*/ |
103 |
|
|
struct evbuffer *since_ground; |
104 |
|
|
}; |
105 |
|
|
|
106 |
|
|
/* Helper functions. */ |
107 |
|
|
struct input_transition; |
108 |
|
|
static int input_split(struct input_ctx *); |
109 |
|
|
static int input_get(struct input_ctx *, u_int, int, int); |
110 |
|
|
static void printflike(2, 3) input_reply(struct input_ctx *, const char *, ...); |
111 |
|
|
static void input_set_state(struct window_pane *, |
112 |
|
|
const struct input_transition *); |
113 |
|
|
static void input_reset_cell(struct input_ctx *); |
114 |
|
|
|
115 |
|
|
static void input_osc_4(struct window_pane *, const char *); |
116 |
|
|
static void input_osc_10(struct window_pane *, const char *); |
117 |
|
|
static void input_osc_11(struct window_pane *, const char *); |
118 |
|
|
static void input_osc_52(struct window_pane *, const char *); |
119 |
|
|
static void input_osc_104(struct window_pane *, const char *); |
120 |
|
|
|
121 |
|
|
/* Transition entry/exit handlers. */ |
122 |
|
|
static void input_clear(struct input_ctx *); |
123 |
|
|
static void input_ground(struct input_ctx *); |
124 |
|
|
static void input_enter_dcs(struct input_ctx *); |
125 |
|
|
static void input_enter_osc(struct input_ctx *); |
126 |
|
|
static void input_exit_osc(struct input_ctx *); |
127 |
|
|
static void input_enter_apc(struct input_ctx *); |
128 |
|
|
static void input_exit_apc(struct input_ctx *); |
129 |
|
|
static void input_enter_rename(struct input_ctx *); |
130 |
|
|
static void input_exit_rename(struct input_ctx *); |
131 |
|
|
|
132 |
|
|
/* Input state handlers. */ |
133 |
|
|
static int input_print(struct input_ctx *); |
134 |
|
|
static int input_intermediate(struct input_ctx *); |
135 |
|
|
static int input_parameter(struct input_ctx *); |
136 |
|
|
static int input_input(struct input_ctx *); |
137 |
|
|
static int input_c0_dispatch(struct input_ctx *); |
138 |
|
|
static int input_esc_dispatch(struct input_ctx *); |
139 |
|
|
static int input_csi_dispatch(struct input_ctx *); |
140 |
|
|
static void input_csi_dispatch_rm(struct input_ctx *); |
141 |
|
|
static void input_csi_dispatch_rm_private(struct input_ctx *); |
142 |
|
|
static void input_csi_dispatch_sm(struct input_ctx *); |
143 |
|
|
static void input_csi_dispatch_sm_private(struct input_ctx *); |
144 |
|
|
static void input_csi_dispatch_winops(struct input_ctx *); |
145 |
|
|
static void input_csi_dispatch_sgr_256(struct input_ctx *, int, u_int *); |
146 |
|
|
static void input_csi_dispatch_sgr_rgb(struct input_ctx *, int, u_int *); |
147 |
|
|
static void input_csi_dispatch_sgr(struct input_ctx *); |
148 |
|
|
static int input_dcs_dispatch(struct input_ctx *); |
149 |
|
|
static int input_utf8_open(struct input_ctx *); |
150 |
|
|
static int input_utf8_add(struct input_ctx *); |
151 |
|
|
static int input_utf8_close(struct input_ctx *); |
152 |
|
|
|
153 |
|
|
/* Command table comparison function. */ |
154 |
|
|
static int input_table_compare(const void *, const void *); |
155 |
|
|
|
156 |
|
|
/* Command table entry. */ |
157 |
|
|
struct input_table_entry { |
158 |
|
|
int ch; |
159 |
|
|
const char *interm; |
160 |
|
|
int type; |
161 |
|
|
}; |
162 |
|
|
|
163 |
|
|
/* Escape commands. */ |
164 |
|
|
enum input_esc_type { |
165 |
|
|
INPUT_ESC_DECALN, |
166 |
|
|
INPUT_ESC_DECKPAM, |
167 |
|
|
INPUT_ESC_DECKPNM, |
168 |
|
|
INPUT_ESC_DECRC, |
169 |
|
|
INPUT_ESC_DECSC, |
170 |
|
|
INPUT_ESC_HTS, |
171 |
|
|
INPUT_ESC_IND, |
172 |
|
|
INPUT_ESC_NEL, |
173 |
|
|
INPUT_ESC_RI, |
174 |
|
|
INPUT_ESC_RIS, |
175 |
|
|
INPUT_ESC_SCSG0_OFF, |
176 |
|
|
INPUT_ESC_SCSG0_ON, |
177 |
|
|
INPUT_ESC_SCSG1_OFF, |
178 |
|
|
INPUT_ESC_SCSG1_ON, |
179 |
|
|
INPUT_ESC_ST, |
180 |
|
|
}; |
181 |
|
|
|
182 |
|
|
/* Escape command table. */ |
183 |
|
|
static const struct input_table_entry input_esc_table[] = { |
184 |
|
|
{ '0', "(", INPUT_ESC_SCSG0_ON }, |
185 |
|
|
{ '0', ")", INPUT_ESC_SCSG1_ON }, |
186 |
|
|
{ '7', "", INPUT_ESC_DECSC }, |
187 |
|
|
{ '8', "", INPUT_ESC_DECRC }, |
188 |
|
|
{ '8', "#", INPUT_ESC_DECALN }, |
189 |
|
|
{ '=', "", INPUT_ESC_DECKPAM }, |
190 |
|
|
{ '>', "", INPUT_ESC_DECKPNM }, |
191 |
|
|
{ 'B', "(", INPUT_ESC_SCSG0_OFF }, |
192 |
|
|
{ 'B', ")", INPUT_ESC_SCSG1_OFF }, |
193 |
|
|
{ 'D', "", INPUT_ESC_IND }, |
194 |
|
|
{ 'E', "", INPUT_ESC_NEL }, |
195 |
|
|
{ 'H', "", INPUT_ESC_HTS }, |
196 |
|
|
{ 'M', "", INPUT_ESC_RI }, |
197 |
|
|
{ '\\', "", INPUT_ESC_ST }, |
198 |
|
|
{ 'c', "", INPUT_ESC_RIS }, |
199 |
|
|
}; |
200 |
|
|
|
201 |
|
|
/* Control (CSI) commands. */ |
202 |
|
|
enum input_csi_type { |
203 |
|
|
INPUT_CSI_CBT, |
204 |
|
|
INPUT_CSI_CNL, |
205 |
|
|
INPUT_CSI_CPL, |
206 |
|
|
INPUT_CSI_CUB, |
207 |
|
|
INPUT_CSI_CUD, |
208 |
|
|
INPUT_CSI_CUF, |
209 |
|
|
INPUT_CSI_CUP, |
210 |
|
|
INPUT_CSI_CUU, |
211 |
|
|
INPUT_CSI_DA, |
212 |
|
|
INPUT_CSI_DA_TWO, |
213 |
|
|
INPUT_CSI_DCH, |
214 |
|
|
INPUT_CSI_DECSCUSR, |
215 |
|
|
INPUT_CSI_DECSTBM, |
216 |
|
|
INPUT_CSI_DL, |
217 |
|
|
INPUT_CSI_DSR, |
218 |
|
|
INPUT_CSI_ECH, |
219 |
|
|
INPUT_CSI_ED, |
220 |
|
|
INPUT_CSI_EL, |
221 |
|
|
INPUT_CSI_HPA, |
222 |
|
|
INPUT_CSI_ICH, |
223 |
|
|
INPUT_CSI_IL, |
224 |
|
|
INPUT_CSI_RCP, |
225 |
|
|
INPUT_CSI_REP, |
226 |
|
|
INPUT_CSI_RM, |
227 |
|
|
INPUT_CSI_RM_PRIVATE, |
228 |
|
|
INPUT_CSI_SCP, |
229 |
|
|
INPUT_CSI_SGR, |
230 |
|
|
INPUT_CSI_SM, |
231 |
|
|
INPUT_CSI_SM_PRIVATE, |
232 |
|
|
INPUT_CSI_SU, |
233 |
|
|
INPUT_CSI_TBC, |
234 |
|
|
INPUT_CSI_VPA, |
235 |
|
|
INPUT_CSI_WINOPS, |
236 |
|
|
}; |
237 |
|
|
|
238 |
|
|
/* Control (CSI) command table. */ |
239 |
|
|
static const struct input_table_entry input_csi_table[] = { |
240 |
|
|
{ '@', "", INPUT_CSI_ICH }, |
241 |
|
|
{ 'A', "", INPUT_CSI_CUU }, |
242 |
|
|
{ 'B', "", INPUT_CSI_CUD }, |
243 |
|
|
{ 'C', "", INPUT_CSI_CUF }, |
244 |
|
|
{ 'D', "", INPUT_CSI_CUB }, |
245 |
|
|
{ 'E', "", INPUT_CSI_CNL }, |
246 |
|
|
{ 'F', "", INPUT_CSI_CPL }, |
247 |
|
|
{ 'G', "", INPUT_CSI_HPA }, |
248 |
|
|
{ 'H', "", INPUT_CSI_CUP }, |
249 |
|
|
{ 'J', "", INPUT_CSI_ED }, |
250 |
|
|
{ 'K', "", INPUT_CSI_EL }, |
251 |
|
|
{ 'L', "", INPUT_CSI_IL }, |
252 |
|
|
{ 'M', "", INPUT_CSI_DL }, |
253 |
|
|
{ 'P', "", INPUT_CSI_DCH }, |
254 |
|
|
{ 'S', "", INPUT_CSI_SU }, |
255 |
|
|
{ 'X', "", INPUT_CSI_ECH }, |
256 |
|
|
{ 'Z', "", INPUT_CSI_CBT }, |
257 |
|
|
{ 'b', "", INPUT_CSI_REP }, |
258 |
|
|
{ 'c', "", INPUT_CSI_DA }, |
259 |
|
|
{ 'c', ">", INPUT_CSI_DA_TWO }, |
260 |
|
|
{ 'd', "", INPUT_CSI_VPA }, |
261 |
|
|
{ 'f', "", INPUT_CSI_CUP }, |
262 |
|
|
{ 'g', "", INPUT_CSI_TBC }, |
263 |
|
|
{ 'h', "", INPUT_CSI_SM }, |
264 |
|
|
{ 'h', "?", INPUT_CSI_SM_PRIVATE }, |
265 |
|
|
{ 'l', "", INPUT_CSI_RM }, |
266 |
|
|
{ 'l', "?", INPUT_CSI_RM_PRIVATE }, |
267 |
|
|
{ 'm', "", INPUT_CSI_SGR }, |
268 |
|
|
{ 'n', "", INPUT_CSI_DSR }, |
269 |
|
|
{ 'q', " ", INPUT_CSI_DECSCUSR }, |
270 |
|
|
{ 'r', "", INPUT_CSI_DECSTBM }, |
271 |
|
|
{ 's', "", INPUT_CSI_SCP }, |
272 |
|
|
{ 't', "", INPUT_CSI_WINOPS }, |
273 |
|
|
{ 'u', "", INPUT_CSI_RCP }, |
274 |
|
|
}; |
275 |
|
|
|
276 |
|
|
/* Input transition. */ |
277 |
|
|
struct input_transition { |
278 |
|
|
int first; |
279 |
|
|
int last; |
280 |
|
|
|
281 |
|
|
int (*handler)(struct input_ctx *); |
282 |
|
|
const struct input_state *state; |
283 |
|
|
}; |
284 |
|
|
|
285 |
|
|
/* Input state. */ |
286 |
|
|
struct input_state { |
287 |
|
|
const char *name; |
288 |
|
|
void (*enter)(struct input_ctx *); |
289 |
|
|
void (*exit)(struct input_ctx *); |
290 |
|
|
const struct input_transition *transitions; |
291 |
|
|
}; |
292 |
|
|
|
293 |
|
|
/* State transitions available from all states. */ |
294 |
|
|
#define INPUT_STATE_ANYWHERE \ |
295 |
|
|
{ 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \ |
296 |
|
|
{ 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \ |
297 |
|
|
{ 0x1b, 0x1b, NULL, &input_state_esc_enter } |
298 |
|
|
|
299 |
|
|
/* Forward declarations of state tables. */ |
300 |
|
|
static const struct input_transition input_state_ground_table[]; |
301 |
|
|
static const struct input_transition input_state_esc_enter_table[]; |
302 |
|
|
static const struct input_transition input_state_esc_intermediate_table[]; |
303 |
|
|
static const struct input_transition input_state_csi_enter_table[]; |
304 |
|
|
static const struct input_transition input_state_csi_parameter_table[]; |
305 |
|
|
static const struct input_transition input_state_csi_intermediate_table[]; |
306 |
|
|
static const struct input_transition input_state_csi_ignore_table[]; |
307 |
|
|
static const struct input_transition input_state_dcs_enter_table[]; |
308 |
|
|
static const struct input_transition input_state_dcs_parameter_table[]; |
309 |
|
|
static const struct input_transition input_state_dcs_intermediate_table[]; |
310 |
|
|
static const struct input_transition input_state_dcs_handler_table[]; |
311 |
|
|
static const struct input_transition input_state_dcs_escape_table[]; |
312 |
|
|
static const struct input_transition input_state_dcs_ignore_table[]; |
313 |
|
|
static const struct input_transition input_state_osc_string_table[]; |
314 |
|
|
static const struct input_transition input_state_apc_string_table[]; |
315 |
|
|
static const struct input_transition input_state_rename_string_table[]; |
316 |
|
|
static const struct input_transition input_state_consume_st_table[]; |
317 |
|
|
static const struct input_transition input_state_utf8_three_table[]; |
318 |
|
|
static const struct input_transition input_state_utf8_two_table[]; |
319 |
|
|
static const struct input_transition input_state_utf8_one_table[]; |
320 |
|
|
|
321 |
|
|
/* ground state definition. */ |
322 |
|
|
static const struct input_state input_state_ground = { |
323 |
|
|
"ground", |
324 |
|
|
input_ground, NULL, |
325 |
|
|
input_state_ground_table |
326 |
|
|
}; |
327 |
|
|
|
328 |
|
|
/* esc_enter state definition. */ |
329 |
|
|
static const struct input_state input_state_esc_enter = { |
330 |
|
|
"esc_enter", |
331 |
|
|
input_clear, NULL, |
332 |
|
|
input_state_esc_enter_table |
333 |
|
|
}; |
334 |
|
|
|
335 |
|
|
/* esc_intermediate state definition. */ |
336 |
|
|
static const struct input_state input_state_esc_intermediate = { |
337 |
|
|
"esc_intermediate", |
338 |
|
|
NULL, NULL, |
339 |
|
|
input_state_esc_intermediate_table |
340 |
|
|
}; |
341 |
|
|
|
342 |
|
|
/* csi_enter state definition. */ |
343 |
|
|
static const struct input_state input_state_csi_enter = { |
344 |
|
|
"csi_enter", |
345 |
|
|
input_clear, NULL, |
346 |
|
|
input_state_csi_enter_table |
347 |
|
|
}; |
348 |
|
|
|
349 |
|
|
/* csi_parameter state definition. */ |
350 |
|
|
static const struct input_state input_state_csi_parameter = { |
351 |
|
|
"csi_parameter", |
352 |
|
|
NULL, NULL, |
353 |
|
|
input_state_csi_parameter_table |
354 |
|
|
}; |
355 |
|
|
|
356 |
|
|
/* csi_intermediate state definition. */ |
357 |
|
|
static const struct input_state input_state_csi_intermediate = { |
358 |
|
|
"csi_intermediate", |
359 |
|
|
NULL, NULL, |
360 |
|
|
input_state_csi_intermediate_table |
361 |
|
|
}; |
362 |
|
|
|
363 |
|
|
/* csi_ignore state definition. */ |
364 |
|
|
static const struct input_state input_state_csi_ignore = { |
365 |
|
|
"csi_ignore", |
366 |
|
|
NULL, NULL, |
367 |
|
|
input_state_csi_ignore_table |
368 |
|
|
}; |
369 |
|
|
|
370 |
|
|
/* dcs_enter state definition. */ |
371 |
|
|
static const struct input_state input_state_dcs_enter = { |
372 |
|
|
"dcs_enter", |
373 |
|
|
input_enter_dcs, NULL, |
374 |
|
|
input_state_dcs_enter_table |
375 |
|
|
}; |
376 |
|
|
|
377 |
|
|
/* dcs_parameter state definition. */ |
378 |
|
|
static const struct input_state input_state_dcs_parameter = { |
379 |
|
|
"dcs_parameter", |
380 |
|
|
NULL, NULL, |
381 |
|
|
input_state_dcs_parameter_table |
382 |
|
|
}; |
383 |
|
|
|
384 |
|
|
/* dcs_intermediate state definition. */ |
385 |
|
|
static const struct input_state input_state_dcs_intermediate = { |
386 |
|
|
"dcs_intermediate", |
387 |
|
|
NULL, NULL, |
388 |
|
|
input_state_dcs_intermediate_table |
389 |
|
|
}; |
390 |
|
|
|
391 |
|
|
/* dcs_handler state definition. */ |
392 |
|
|
static const struct input_state input_state_dcs_handler = { |
393 |
|
|
"dcs_handler", |
394 |
|
|
NULL, NULL, |
395 |
|
|
input_state_dcs_handler_table |
396 |
|
|
}; |
397 |
|
|
|
398 |
|
|
/* dcs_escape state definition. */ |
399 |
|
|
static const struct input_state input_state_dcs_escape = { |
400 |
|
|
"dcs_escape", |
401 |
|
|
NULL, NULL, |
402 |
|
|
input_state_dcs_escape_table |
403 |
|
|
}; |
404 |
|
|
|
405 |
|
|
/* dcs_ignore state definition. */ |
406 |
|
|
static const struct input_state input_state_dcs_ignore = { |
407 |
|
|
"dcs_ignore", |
408 |
|
|
NULL, NULL, |
409 |
|
|
input_state_dcs_ignore_table |
410 |
|
|
}; |
411 |
|
|
|
412 |
|
|
/* osc_string state definition. */ |
413 |
|
|
static const struct input_state input_state_osc_string = { |
414 |
|
|
"osc_string", |
415 |
|
|
input_enter_osc, input_exit_osc, |
416 |
|
|
input_state_osc_string_table |
417 |
|
|
}; |
418 |
|
|
|
419 |
|
|
/* apc_string state definition. */ |
420 |
|
|
static const struct input_state input_state_apc_string = { |
421 |
|
|
"apc_string", |
422 |
|
|
input_enter_apc, input_exit_apc, |
423 |
|
|
input_state_apc_string_table |
424 |
|
|
}; |
425 |
|
|
|
426 |
|
|
/* rename_string state definition. */ |
427 |
|
|
static const struct input_state input_state_rename_string = { |
428 |
|
|
"rename_string", |
429 |
|
|
input_enter_rename, input_exit_rename, |
430 |
|
|
input_state_rename_string_table |
431 |
|
|
}; |
432 |
|
|
|
433 |
|
|
/* consume_st state definition. */ |
434 |
|
|
static const struct input_state input_state_consume_st = { |
435 |
|
|
"consume_st", |
436 |
|
|
input_enter_rename, NULL, /* rename also waits for ST */ |
437 |
|
|
input_state_consume_st_table |
438 |
|
|
}; |
439 |
|
|
|
440 |
|
|
/* utf8_three state definition. */ |
441 |
|
|
static const struct input_state input_state_utf8_three = { |
442 |
|
|
"utf8_three", |
443 |
|
|
NULL, NULL, |
444 |
|
|
input_state_utf8_three_table |
445 |
|
|
}; |
446 |
|
|
|
447 |
|
|
/* utf8_two state definition. */ |
448 |
|
|
static const struct input_state input_state_utf8_two = { |
449 |
|
|
"utf8_two", |
450 |
|
|
NULL, NULL, |
451 |
|
|
input_state_utf8_two_table |
452 |
|
|
}; |
453 |
|
|
|
454 |
|
|
/* utf8_one state definition. */ |
455 |
|
|
static const struct input_state input_state_utf8_one = { |
456 |
|
|
"utf8_one", |
457 |
|
|
NULL, NULL, |
458 |
|
|
input_state_utf8_one_table |
459 |
|
|
}; |
460 |
|
|
|
461 |
|
|
/* ground state table. */ |
462 |
|
|
static const struct input_transition input_state_ground_table[] = { |
463 |
|
|
INPUT_STATE_ANYWHERE, |
464 |
|
|
|
465 |
|
|
{ 0x00, 0x17, input_c0_dispatch, NULL }, |
466 |
|
|
{ 0x19, 0x19, input_c0_dispatch, NULL }, |
467 |
|
|
{ 0x1c, 0x1f, input_c0_dispatch, NULL }, |
468 |
|
|
{ 0x20, 0x7e, input_print, NULL }, |
469 |
|
|
{ 0x7f, 0x7f, NULL, NULL }, |
470 |
|
|
{ 0x80, 0xc1, NULL, NULL }, |
471 |
|
|
{ 0xc2, 0xdf, input_utf8_open, &input_state_utf8_one }, |
472 |
|
|
{ 0xe0, 0xef, input_utf8_open, &input_state_utf8_two }, |
473 |
|
|
{ 0xf0, 0xf4, input_utf8_open, &input_state_utf8_three }, |
474 |
|
|
{ 0xf5, 0xff, NULL, NULL }, |
475 |
|
|
|
476 |
|
|
{ -1, -1, NULL, NULL } |
477 |
|
|
}; |
478 |
|
|
|
479 |
|
|
/* esc_enter state table. */ |
480 |
|
|
static const struct input_transition input_state_esc_enter_table[] = { |
481 |
|
|
INPUT_STATE_ANYWHERE, |
482 |
|
|
|
483 |
|
|
{ 0x00, 0x17, input_c0_dispatch, NULL }, |
484 |
|
|
{ 0x19, 0x19, input_c0_dispatch, NULL }, |
485 |
|
|
{ 0x1c, 0x1f, input_c0_dispatch, NULL }, |
486 |
|
|
{ 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate }, |
487 |
|
|
{ 0x30, 0x4f, input_esc_dispatch, &input_state_ground }, |
488 |
|
|
{ 0x50, 0x50, NULL, &input_state_dcs_enter }, |
489 |
|
|
{ 0x51, 0x57, input_esc_dispatch, &input_state_ground }, |
490 |
|
|
{ 0x58, 0x58, NULL, &input_state_consume_st }, |
491 |
|
|
{ 0x59, 0x59, input_esc_dispatch, &input_state_ground }, |
492 |
|
|
{ 0x5a, 0x5a, input_esc_dispatch, &input_state_ground }, |
493 |
|
|
{ 0x5b, 0x5b, NULL, &input_state_csi_enter }, |
494 |
|
|
{ 0x5c, 0x5c, input_esc_dispatch, &input_state_ground }, |
495 |
|
|
{ 0x5d, 0x5d, NULL, &input_state_osc_string }, |
496 |
|
|
{ 0x5e, 0x5e, NULL, &input_state_consume_st }, |
497 |
|
|
{ 0x5f, 0x5f, NULL, &input_state_apc_string }, |
498 |
|
|
{ 0x60, 0x6a, input_esc_dispatch, &input_state_ground }, |
499 |
|
|
{ 0x6b, 0x6b, NULL, &input_state_rename_string }, |
500 |
|
|
{ 0x6c, 0x7e, input_esc_dispatch, &input_state_ground }, |
501 |
|
|
{ 0x7f, 0xff, NULL, NULL }, |
502 |
|
|
|
503 |
|
|
{ -1, -1, NULL, NULL } |
504 |
|
|
}; |
505 |
|
|
|
506 |
|
|
/* esc_interm state table. */ |
507 |
|
|
static const struct input_transition input_state_esc_intermediate_table[] = { |
508 |
|
|
INPUT_STATE_ANYWHERE, |
509 |
|
|
|
510 |
|
|
{ 0x00, 0x17, input_c0_dispatch, NULL }, |
511 |
|
|
{ 0x19, 0x19, input_c0_dispatch, NULL }, |
512 |
|
|
{ 0x1c, 0x1f, input_c0_dispatch, NULL }, |
513 |
|
|
{ 0x20, 0x2f, input_intermediate, NULL }, |
514 |
|
|
{ 0x30, 0x7e, input_esc_dispatch, &input_state_ground }, |
515 |
|
|
{ 0x7f, 0xff, NULL, NULL }, |
516 |
|
|
|
517 |
|
|
{ -1, -1, NULL, NULL } |
518 |
|
|
}; |
519 |
|
|
|
520 |
|
|
/* csi_enter state table. */ |
521 |
|
|
static const struct input_transition input_state_csi_enter_table[] = { |
522 |
|
|
INPUT_STATE_ANYWHERE, |
523 |
|
|
|
524 |
|
|
{ 0x00, 0x17, input_c0_dispatch, NULL }, |
525 |
|
|
{ 0x19, 0x19, input_c0_dispatch, NULL }, |
526 |
|
|
{ 0x1c, 0x1f, input_c0_dispatch, NULL }, |
527 |
|
|
{ 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate }, |
528 |
|
|
{ 0x30, 0x39, input_parameter, &input_state_csi_parameter }, |
529 |
|
|
{ 0x3a, 0x3a, NULL, &input_state_csi_ignore }, |
530 |
|
|
{ 0x3b, 0x3b, input_parameter, &input_state_csi_parameter }, |
531 |
|
|
{ 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter }, |
532 |
|
|
{ 0x40, 0x7e, input_csi_dispatch, &input_state_ground }, |
533 |
|
|
{ 0x7f, 0xff, NULL, NULL }, |
534 |
|
|
|
535 |
|
|
{ -1, -1, NULL, NULL } |
536 |
|
|
}; |
537 |
|
|
|
538 |
|
|
/* csi_parameter state table. */ |
539 |
|
|
static const struct input_transition input_state_csi_parameter_table[] = { |
540 |
|
|
INPUT_STATE_ANYWHERE, |
541 |
|
|
|
542 |
|
|
{ 0x00, 0x17, input_c0_dispatch, NULL }, |
543 |
|
|
{ 0x19, 0x19, input_c0_dispatch, NULL }, |
544 |
|
|
{ 0x1c, 0x1f, input_c0_dispatch, NULL }, |
545 |
|
|
{ 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate }, |
546 |
|
|
{ 0x30, 0x39, input_parameter, NULL }, |
547 |
|
|
{ 0x3a, 0x3a, NULL, &input_state_csi_ignore }, |
548 |
|
|
{ 0x3b, 0x3b, input_parameter, NULL }, |
549 |
|
|
{ 0x3c, 0x3f, NULL, &input_state_csi_ignore }, |
550 |
|
|
{ 0x40, 0x7e, input_csi_dispatch, &input_state_ground }, |
551 |
|
|
{ 0x7f, 0xff, NULL, NULL }, |
552 |
|
|
|
553 |
|
|
{ -1, -1, NULL, NULL } |
554 |
|
|
}; |
555 |
|
|
|
556 |
|
|
/* csi_intermediate state table. */ |
557 |
|
|
static const struct input_transition input_state_csi_intermediate_table[] = { |
558 |
|
|
INPUT_STATE_ANYWHERE, |
559 |
|
|
|
560 |
|
|
{ 0x00, 0x17, input_c0_dispatch, NULL }, |
561 |
|
|
{ 0x19, 0x19, input_c0_dispatch, NULL }, |
562 |
|
|
{ 0x1c, 0x1f, input_c0_dispatch, NULL }, |
563 |
|
|
{ 0x20, 0x2f, input_intermediate, NULL }, |
564 |
|
|
{ 0x30, 0x3f, NULL, &input_state_csi_ignore }, |
565 |
|
|
{ 0x40, 0x7e, input_csi_dispatch, &input_state_ground }, |
566 |
|
|
{ 0x7f, 0xff, NULL, NULL }, |
567 |
|
|
|
568 |
|
|
{ -1, -1, NULL, NULL } |
569 |
|
|
}; |
570 |
|
|
|
571 |
|
|
/* csi_ignore state table. */ |
572 |
|
|
static const struct input_transition input_state_csi_ignore_table[] = { |
573 |
|
|
INPUT_STATE_ANYWHERE, |
574 |
|
|
|
575 |
|
|
{ 0x00, 0x17, input_c0_dispatch, NULL }, |
576 |
|
|
{ 0x19, 0x19, input_c0_dispatch, NULL }, |
577 |
|
|
{ 0x1c, 0x1f, input_c0_dispatch, NULL }, |
578 |
|
|
{ 0x20, 0x3f, NULL, NULL }, |
579 |
|
|
{ 0x40, 0x7e, NULL, &input_state_ground }, |
580 |
|
|
{ 0x7f, 0xff, NULL, NULL }, |
581 |
|
|
|
582 |
|
|
{ -1, -1, NULL, NULL } |
583 |
|
|
}; |
584 |
|
|
|
585 |
|
|
/* dcs_enter state table. */ |
586 |
|
|
static const struct input_transition input_state_dcs_enter_table[] = { |
587 |
|
|
INPUT_STATE_ANYWHERE, |
588 |
|
|
|
589 |
|
|
{ 0x00, 0x17, NULL, NULL }, |
590 |
|
|
{ 0x19, 0x19, NULL, NULL }, |
591 |
|
|
{ 0x1c, 0x1f, NULL, NULL }, |
592 |
|
|
{ 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate }, |
593 |
|
|
{ 0x30, 0x39, input_parameter, &input_state_dcs_parameter }, |
594 |
|
|
{ 0x3a, 0x3a, NULL, &input_state_dcs_ignore }, |
595 |
|
|
{ 0x3b, 0x3b, input_parameter, &input_state_dcs_parameter }, |
596 |
|
|
{ 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter }, |
597 |
|
|
{ 0x40, 0x7e, input_input, &input_state_dcs_handler }, |
598 |
|
|
{ 0x7f, 0xff, NULL, NULL }, |
599 |
|
|
|
600 |
|
|
{ -1, -1, NULL, NULL } |
601 |
|
|
}; |
602 |
|
|
|
603 |
|
|
/* dcs_parameter state table. */ |
604 |
|
|
static const struct input_transition input_state_dcs_parameter_table[] = { |
605 |
|
|
INPUT_STATE_ANYWHERE, |
606 |
|
|
|
607 |
|
|
{ 0x00, 0x17, NULL, NULL }, |
608 |
|
|
{ 0x19, 0x19, NULL, NULL }, |
609 |
|
|
{ 0x1c, 0x1f, NULL, NULL }, |
610 |
|
|
{ 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate }, |
611 |
|
|
{ 0x30, 0x39, input_parameter, NULL }, |
612 |
|
|
{ 0x3a, 0x3a, NULL, &input_state_dcs_ignore }, |
613 |
|
|
{ 0x3b, 0x3b, input_parameter, NULL }, |
614 |
|
|
{ 0x3c, 0x3f, NULL, &input_state_dcs_ignore }, |
615 |
|
|
{ 0x40, 0x7e, input_input, &input_state_dcs_handler }, |
616 |
|
|
{ 0x7f, 0xff, NULL, NULL }, |
617 |
|
|
|
618 |
|
|
{ -1, -1, NULL, NULL } |
619 |
|
|
}; |
620 |
|
|
|
621 |
|
|
/* dcs_interm state table. */ |
622 |
|
|
static const struct input_transition input_state_dcs_intermediate_table[] = { |
623 |
|
|
INPUT_STATE_ANYWHERE, |
624 |
|
|
|
625 |
|
|
{ 0x00, 0x17, NULL, NULL }, |
626 |
|
|
{ 0x19, 0x19, NULL, NULL }, |
627 |
|
|
{ 0x1c, 0x1f, NULL, NULL }, |
628 |
|
|
{ 0x20, 0x2f, input_intermediate, NULL }, |
629 |
|
|
{ 0x30, 0x3f, NULL, &input_state_dcs_ignore }, |
630 |
|
|
{ 0x40, 0x7e, input_input, &input_state_dcs_handler }, |
631 |
|
|
{ 0x7f, 0xff, NULL, NULL }, |
632 |
|
|
|
633 |
|
|
{ -1, -1, NULL, NULL } |
634 |
|
|
}; |
635 |
|
|
|
636 |
|
|
/* dcs_handler state table. */ |
637 |
|
|
static const struct input_transition input_state_dcs_handler_table[] = { |
638 |
|
|
/* No INPUT_STATE_ANYWHERE */ |
639 |
|
|
|
640 |
|
|
{ 0x00, 0x1a, input_input, NULL }, |
641 |
|
|
{ 0x1b, 0x1b, NULL, &input_state_dcs_escape }, |
642 |
|
|
{ 0x1c, 0xff, input_input, NULL }, |
643 |
|
|
|
644 |
|
|
{ -1, -1, NULL, NULL } |
645 |
|
|
}; |
646 |
|
|
|
647 |
|
|
/* dcs_escape state table. */ |
648 |
|
|
static const struct input_transition input_state_dcs_escape_table[] = { |
649 |
|
|
/* No INPUT_STATE_ANYWHERE */ |
650 |
|
|
|
651 |
|
|
{ 0x00, 0x5b, input_input, &input_state_dcs_handler }, |
652 |
|
|
{ 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground }, |
653 |
|
|
{ 0x5d, 0xff, input_input, &input_state_dcs_handler }, |
654 |
|
|
|
655 |
|
|
{ -1, -1, NULL, NULL } |
656 |
|
|
}; |
657 |
|
|
|
658 |
|
|
/* dcs_ignore state table. */ |
659 |
|
|
static const struct input_transition input_state_dcs_ignore_table[] = { |
660 |
|
|
INPUT_STATE_ANYWHERE, |
661 |
|
|
|
662 |
|
|
{ 0x00, 0x17, NULL, NULL }, |
663 |
|
|
{ 0x19, 0x19, NULL, NULL }, |
664 |
|
|
{ 0x1c, 0x1f, NULL, NULL }, |
665 |
|
|
{ 0x20, 0xff, NULL, NULL }, |
666 |
|
|
|
667 |
|
|
{ -1, -1, NULL, NULL } |
668 |
|
|
}; |
669 |
|
|
|
670 |
|
|
/* osc_string state table. */ |
671 |
|
|
static const struct input_transition input_state_osc_string_table[] = { |
672 |
|
|
INPUT_STATE_ANYWHERE, |
673 |
|
|
|
674 |
|
|
{ 0x00, 0x06, NULL, NULL }, |
675 |
|
|
{ 0x07, 0x07, NULL, &input_state_ground }, |
676 |
|
|
{ 0x08, 0x17, NULL, NULL }, |
677 |
|
|
{ 0x19, 0x19, NULL, NULL }, |
678 |
|
|
{ 0x1c, 0x1f, NULL, NULL }, |
679 |
|
|
{ 0x20, 0xff, input_input, NULL }, |
680 |
|
|
|
681 |
|
|
{ -1, -1, NULL, NULL } |
682 |
|
|
}; |
683 |
|
|
|
684 |
|
|
/* apc_string state table. */ |
685 |
|
|
static const struct input_transition input_state_apc_string_table[] = { |
686 |
|
|
INPUT_STATE_ANYWHERE, |
687 |
|
|
|
688 |
|
|
{ 0x00, 0x17, NULL, NULL }, |
689 |
|
|
{ 0x19, 0x19, NULL, NULL }, |
690 |
|
|
{ 0x1c, 0x1f, NULL, NULL }, |
691 |
|
|
{ 0x20, 0xff, input_input, NULL }, |
692 |
|
|
|
693 |
|
|
{ -1, -1, NULL, NULL } |
694 |
|
|
}; |
695 |
|
|
|
696 |
|
|
/* rename_string state table. */ |
697 |
|
|
static const struct input_transition input_state_rename_string_table[] = { |
698 |
|
|
INPUT_STATE_ANYWHERE, |
699 |
|
|
|
700 |
|
|
{ 0x00, 0x17, NULL, NULL }, |
701 |
|
|
{ 0x19, 0x19, NULL, NULL }, |
702 |
|
|
{ 0x1c, 0x1f, NULL, NULL }, |
703 |
|
|
{ 0x20, 0xff, input_input, NULL }, |
704 |
|
|
|
705 |
|
|
{ -1, -1, NULL, NULL } |
706 |
|
|
}; |
707 |
|
|
|
708 |
|
|
/* consume_st state table. */ |
709 |
|
|
static const struct input_transition input_state_consume_st_table[] = { |
710 |
|
|
INPUT_STATE_ANYWHERE, |
711 |
|
|
|
712 |
|
|
{ 0x00, 0x17, NULL, NULL }, |
713 |
|
|
{ 0x19, 0x19, NULL, NULL }, |
714 |
|
|
{ 0x1c, 0x1f, NULL, NULL }, |
715 |
|
|
{ 0x20, 0xff, NULL, NULL }, |
716 |
|
|
|
717 |
|
|
{ -1, -1, NULL, NULL } |
718 |
|
|
}; |
719 |
|
|
|
720 |
|
|
/* utf8_three state table. */ |
721 |
|
|
static const struct input_transition input_state_utf8_three_table[] = { |
722 |
|
|
/* No INPUT_STATE_ANYWHERE */ |
723 |
|
|
|
724 |
|
|
{ 0x00, 0x7f, NULL, &input_state_ground }, |
725 |
|
|
{ 0x80, 0xbf, input_utf8_add, &input_state_utf8_two }, |
726 |
|
|
{ 0xc0, 0xff, NULL, &input_state_ground }, |
727 |
|
|
|
728 |
|
|
{ -1, -1, NULL, NULL } |
729 |
|
|
}; |
730 |
|
|
|
731 |
|
|
/* utf8_two state table. */ |
732 |
|
|
static const struct input_transition input_state_utf8_two_table[] = { |
733 |
|
|
/* No INPUT_STATE_ANYWHERE */ |
734 |
|
|
|
735 |
|
|
{ 0x00, 0x7f, NULL, &input_state_ground }, |
736 |
|
|
{ 0x80, 0xbf, input_utf8_add, &input_state_utf8_one }, |
737 |
|
|
{ 0xc0, 0xff, NULL, &input_state_ground }, |
738 |
|
|
|
739 |
|
|
{ -1, -1, NULL, NULL } |
740 |
|
|
}; |
741 |
|
|
|
742 |
|
|
/* utf8_one state table. */ |
743 |
|
|
static const struct input_transition input_state_utf8_one_table[] = { |
744 |
|
|
/* No INPUT_STATE_ANYWHERE */ |
745 |
|
|
|
746 |
|
|
{ 0x00, 0x7f, NULL, &input_state_ground }, |
747 |
|
|
{ 0x80, 0xbf, input_utf8_close, &input_state_ground }, |
748 |
|
|
{ 0xc0, 0xff, NULL, &input_state_ground }, |
749 |
|
|
|
750 |
|
|
{ -1, -1, NULL, NULL } |
751 |
|
|
}; |
752 |
|
|
|
753 |
|
|
/* Input table compare. */ |
754 |
|
|
static int |
755 |
|
|
input_table_compare(const void *key, const void *value) |
756 |
|
|
{ |
757 |
|
|
const struct input_ctx *ictx = key; |
758 |
|
|
const struct input_table_entry *entry = value; |
759 |
|
|
|
760 |
|
|
if (ictx->ch != entry->ch) |
761 |
|
|
return (ictx->ch - entry->ch); |
762 |
|
|
return (strcmp(ictx->interm_buf, entry->interm)); |
763 |
|
|
} |
764 |
|
|
|
765 |
|
|
/* |
766 |
|
|
* Timer - if this expires then have been waiting for a terminator for too |
767 |
|
|
* long, so reset to ground. |
768 |
|
|
*/ |
769 |
|
|
static void |
770 |
|
|
input_timer_callback(__unused int fd, __unused short events, void *arg) |
771 |
|
|
{ |
772 |
|
|
struct input_ctx *ictx = arg; |
773 |
|
|
struct window_pane *wp = ictx->wp; |
774 |
|
|
|
775 |
|
|
log_debug("%s: %%%u %s expired" , __func__, wp->id, ictx->state->name); |
776 |
|
|
input_reset(wp, 0); |
777 |
|
|
} |
778 |
|
|
|
779 |
|
|
/* Start the timer. */ |
780 |
|
|
static void |
781 |
|
|
input_start_timer(struct input_ctx *ictx) |
782 |
|
|
{ |
783 |
|
|
struct timeval tv = { .tv_usec = 100000 }; |
784 |
|
|
|
785 |
|
|
event_del(&ictx->timer); |
786 |
|
|
event_add(&ictx->timer, &tv); |
787 |
|
|
} |
788 |
|
|
|
789 |
|
|
/* Reset cell state to default. */ |
790 |
|
|
static void |
791 |
|
|
input_reset_cell(struct input_ctx *ictx) |
792 |
|
|
{ |
793 |
|
|
memcpy(&ictx->cell.cell, &grid_default_cell, sizeof ictx->cell.cell); |
794 |
|
|
ictx->cell.set = 0; |
795 |
|
|
ictx->cell.g0set = ictx->cell.g1set = 0; |
796 |
|
|
|
797 |
|
|
memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); |
798 |
|
|
ictx->old_cx = 0; |
799 |
|
|
ictx->old_cy = 0; |
800 |
|
|
} |
801 |
|
|
|
802 |
|
|
/* Initialise input parser. */ |
803 |
|
|
void |
804 |
|
|
input_init(struct window_pane *wp) |
805 |
|
|
{ |
806 |
|
|
struct input_ctx *ictx; |
807 |
|
|
|
808 |
|
|
ictx = wp->ictx = xcalloc(1, sizeof *ictx); |
809 |
|
|
|
810 |
|
|
ictx->input_space = INPUT_BUF_START; |
811 |
|
|
ictx->input_buf = xmalloc(INPUT_BUF_START); |
812 |
|
|
|
813 |
|
|
ictx->since_ground = evbuffer_new(); |
814 |
|
|
|
815 |
|
|
evtimer_set(&ictx->timer, input_timer_callback, ictx); |
816 |
|
|
|
817 |
|
|
input_reset(wp, 0); |
818 |
|
|
} |
819 |
|
|
|
820 |
|
|
/* Destroy input parser. */ |
821 |
|
|
void |
822 |
|
|
input_free(struct window_pane *wp) |
823 |
|
|
{ |
824 |
|
|
struct input_ctx *ictx = wp->ictx; |
825 |
|
|
|
826 |
|
|
event_del(&ictx->timer); |
827 |
|
|
|
828 |
|
|
free(ictx->input_buf); |
829 |
|
|
evbuffer_free(ictx->since_ground); |
830 |
|
|
|
831 |
|
|
free(ictx); |
832 |
|
|
wp->ictx = NULL; |
833 |
|
|
} |
834 |
|
|
|
835 |
|
|
/* Reset input state and clear screen. */ |
836 |
|
|
void |
837 |
|
|
input_reset(struct window_pane *wp, int clear) |
838 |
|
|
{ |
839 |
|
|
struct input_ctx *ictx = wp->ictx; |
840 |
|
|
|
841 |
|
|
input_reset_cell(ictx); |
842 |
|
|
|
843 |
|
|
if (clear) { |
844 |
|
|
if (wp->mode == NULL) |
845 |
|
|
screen_write_start(&ictx->ctx, wp, &wp->base); |
846 |
|
|
else |
847 |
|
|
screen_write_start(&ictx->ctx, NULL, &wp->base); |
848 |
|
|
screen_write_reset(&ictx->ctx); |
849 |
|
|
screen_write_stop(&ictx->ctx); |
850 |
|
|
} |
851 |
|
|
|
852 |
|
|
input_clear(ictx); |
853 |
|
|
|
854 |
|
|
ictx->last = -1; |
855 |
|
|
|
856 |
|
|
ictx->state = &input_state_ground; |
857 |
|
|
ictx->flags = 0; |
858 |
|
|
} |
859 |
|
|
|
860 |
|
|
/* Return pending data. */ |
861 |
|
|
struct evbuffer * |
862 |
|
|
input_pending(struct window_pane *wp) |
863 |
|
|
{ |
864 |
|
|
return (wp->ictx->since_ground); |
865 |
|
|
} |
866 |
|
|
|
867 |
|
|
/* Change input state. */ |
868 |
|
|
static void |
869 |
|
|
input_set_state(struct window_pane *wp, const struct input_transition *itr) |
870 |
|
|
{ |
871 |
|
|
struct input_ctx *ictx = wp->ictx; |
872 |
|
|
|
873 |
|
|
if (ictx->state->exit != NULL) |
874 |
|
|
ictx->state->exit(ictx); |
875 |
|
|
ictx->state = itr->state; |
876 |
|
|
if (ictx->state->enter != NULL) |
877 |
|
|
ictx->state->enter(ictx); |
878 |
|
|
} |
879 |
|
|
|
880 |
|
|
/* Parse input. */ |
881 |
|
|
void |
882 |
|
|
input_parse(struct window_pane *wp) |
883 |
|
|
{ |
884 |
|
|
struct input_ctx *ictx = wp->ictx; |
885 |
|
|
const struct input_transition *itr; |
886 |
|
|
struct evbuffer *evb = wp->event->input; |
887 |
|
|
u_char *buf; |
888 |
|
|
size_t len, off; |
889 |
|
|
|
890 |
|
|
if (EVBUFFER_LENGTH(evb) == 0) |
891 |
|
|
return; |
892 |
|
|
|
893 |
|
|
window_update_activity(wp->window); |
894 |
|
|
wp->flags |= PANE_CHANGED; |
895 |
|
|
|
896 |
|
|
/* |
897 |
|
|
* Open the screen. Use NULL wp if there is a mode set as don't want to |
898 |
|
|
* update the tty. |
899 |
|
|
*/ |
900 |
|
|
if (wp->mode == NULL) |
901 |
|
|
screen_write_start(&ictx->ctx, wp, &wp->base); |
902 |
|
|
else |
903 |
|
|
screen_write_start(&ictx->ctx, NULL, &wp->base); |
904 |
|
|
ictx->wp = wp; |
905 |
|
|
|
906 |
|
|
buf = EVBUFFER_DATA(evb); |
907 |
|
|
len = EVBUFFER_LENGTH(evb); |
908 |
|
|
off = 0; |
909 |
|
|
|
910 |
|
|
notify_input(wp, evb); |
911 |
|
|
|
912 |
|
|
log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id, |
913 |
|
|
ictx->state->name, len, (int)len, buf); |
914 |
|
|
|
915 |
|
|
/* Parse the input. */ |
916 |
|
|
while (off < len) { |
917 |
|
|
ictx->ch = buf[off++]; |
918 |
|
|
|
919 |
|
|
/* Find the transition. */ |
920 |
|
|
itr = ictx->state->transitions; |
921 |
|
|
while (itr->first != -1 && itr->last != -1) { |
922 |
|
|
if (ictx->ch >= itr->first && ictx->ch <= itr->last) |
923 |
|
|
break; |
924 |
|
|
itr++; |
925 |
|
|
} |
926 |
|
|
if (itr->first == -1 || itr->last == -1) { |
927 |
|
|
/* No transition? Eh? */ |
928 |
|
|
fatalx("no transition from state"); |
929 |
|
|
} |
930 |
|
|
|
931 |
|
|
/* |
932 |
|
|
* Any state except print stops the current collection. This is |
933 |
|
|
* an optimization to avoid checking if the attributes have |
934 |
|
|
* changed for every character. It will stop unnecessarily for |
935 |
|
|
* sequences that don't make a terminal change, but they should |
936 |
|
|
* be the minority. |
937 |
|
|
*/ |
938 |
|
|
if (itr->handler != input_print) |
939 |
|
|
screen_write_collect_end(&ictx->ctx); |
940 |
|
|
|
941 |
|
|
/* |
942 |
|
|
* Execute the handler, if any. Don't switch state if it |
943 |
|
|
* returns non-zero. |
944 |
|
|
*/ |
945 |
|
|
if (itr->handler != NULL && itr->handler(ictx) != 0) |
946 |
|
|
continue; |
947 |
|
|
|
948 |
|
|
/* And switch state, if necessary. */ |
949 |
|
|
if (itr->state != NULL) |
950 |
|
|
input_set_state(wp, itr); |
951 |
|
|
|
952 |
|
|
/* If not in ground state, save input. */ |
953 |
|
|
if (ictx->state != &input_state_ground) |
954 |
|
|
evbuffer_add(ictx->since_ground, &ictx->ch, 1); |
955 |
|
|
} |
956 |
|
|
|
957 |
|
|
/* Close the screen. */ |
958 |
|
|
screen_write_stop(&ictx->ctx); |
959 |
|
|
|
960 |
|
|
evbuffer_drain(evb, len); |
961 |
|
|
} |
962 |
|
|
|
963 |
|
|
/* Split the parameter list (if any). */ |
964 |
|
|
static int |
965 |
|
|
input_split(struct input_ctx *ictx) |
966 |
|
|
{ |
967 |
|
|
const char *errstr; |
968 |
|
|
char *ptr, *out; |
969 |
|
|
int n; |
970 |
|
|
|
971 |
|
|
ictx->param_list_len = 0; |
972 |
|
|
if (ictx->param_len == 0) |
973 |
|
|
return (0); |
974 |
|
|
|
975 |
|
|
ptr = ictx->param_buf; |
976 |
|
|
while ((out = strsep(&ptr, ";")) != NULL) { |
977 |
|
|
if (*out == '\0') |
978 |
|
|
n = -1; |
979 |
|
|
else { |
980 |
|
|
n = strtonum(out, 0, INT_MAX, &errstr); |
981 |
|
|
if (errstr != NULL) |
982 |
|
|
return (-1); |
983 |
|
|
} |
984 |
|
|
|
985 |
|
|
ictx->param_list[ictx->param_list_len++] = n; |
986 |
|
|
if (ictx->param_list_len == nitems(ictx->param_list)) |
987 |
|
|
return (-1); |
988 |
|
|
} |
989 |
|
|
|
990 |
|
|
return (0); |
991 |
|
|
} |
992 |
|
|
|
993 |
|
|
/* Get an argument or return default value. */ |
994 |
|
|
static int |
995 |
|
|
input_get(struct input_ctx *ictx, u_int validx, int minval, int defval) |
996 |
|
|
{ |
997 |
|
|
int retval; |
998 |
|
|
|
999 |
|
|
if (validx >= ictx->param_list_len) |
1000 |
|
|
return (defval); |
1001 |
|
|
|
1002 |
|
|
retval = ictx->param_list[validx]; |
1003 |
|
|
if (retval == -1) |
1004 |
|
|
return (defval); |
1005 |
|
|
if (retval < minval) |
1006 |
|
|
return (minval); |
1007 |
|
|
return (retval); |
1008 |
|
|
} |
1009 |
|
|
|
1010 |
|
|
/* Reply to terminal query. */ |
1011 |
|
|
static void |
1012 |
|
|
input_reply(struct input_ctx *ictx, const char *fmt, ...) |
1013 |
|
|
{ |
1014 |
|
|
va_list ap; |
1015 |
|
|
char *reply; |
1016 |
|
|
|
1017 |
|
|
va_start(ap, fmt); |
1018 |
|
|
xvasprintf(&reply, fmt, ap); |
1019 |
|
|
va_end(ap); |
1020 |
|
|
|
1021 |
|
|
bufferevent_write(ictx->wp->event, reply, strlen(reply)); |
1022 |
|
|
free(reply); |
1023 |
|
|
} |
1024 |
|
|
|
1025 |
|
|
/* Clear saved state. */ |
1026 |
|
|
static void |
1027 |
|
|
input_clear(struct input_ctx *ictx) |
1028 |
|
|
{ |
1029 |
|
|
event_del(&ictx->timer); |
1030 |
|
|
|
1031 |
|
|
*ictx->interm_buf = '\0'; |
1032 |
|
|
ictx->interm_len = 0; |
1033 |
|
|
|
1034 |
|
|
*ictx->param_buf = '\0'; |
1035 |
|
|
ictx->param_len = 0; |
1036 |
|
|
|
1037 |
|
|
*ictx->input_buf = '\0'; |
1038 |
|
|
ictx->input_len = 0; |
1039 |
|
|
|
1040 |
|
|
ictx->flags &= ~INPUT_DISCARD; |
1041 |
|
|
} |
1042 |
|
|
|
1043 |
|
|
/* Reset for ground state. */ |
1044 |
|
|
static void |
1045 |
|
|
input_ground(struct input_ctx *ictx) |
1046 |
|
|
{ |
1047 |
|
|
event_del(&ictx->timer); |
1048 |
|
|
evbuffer_drain(ictx->since_ground, EVBUFFER_LENGTH(ictx->since_ground)); |
1049 |
|
|
|
1050 |
|
|
if (ictx->input_space > INPUT_BUF_START) { |
1051 |
|
|
ictx->input_space = INPUT_BUF_START; |
1052 |
|
|
ictx->input_buf = xrealloc(ictx->input_buf, INPUT_BUF_START); |
1053 |
|
|
} |
1054 |
|
|
} |
1055 |
|
|
|
1056 |
|
|
/* Output this character to the screen. */ |
1057 |
|
|
static int |
1058 |
|
|
input_print(struct input_ctx *ictx) |
1059 |
|
|
{ |
1060 |
|
|
int set; |
1061 |
|
|
|
1062 |
|
|
set = ictx->cell.set == 0 ? ictx->cell.g0set : ictx->cell.g1set; |
1063 |
|
|
if (set == 1) |
1064 |
|
|
ictx->cell.cell.attr |= GRID_ATTR_CHARSET; |
1065 |
|
|
else |
1066 |
|
|
ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET; |
1067 |
|
|
|
1068 |
|
|
utf8_set(&ictx->cell.cell.data, ictx->ch); |
1069 |
|
|
screen_write_collect_add(&ictx->ctx, &ictx->cell.cell); |
1070 |
|
|
ictx->last = ictx->ch; |
1071 |
|
|
|
1072 |
|
|
ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET; |
1073 |
|
|
|
1074 |
|
|
return (0); |
1075 |
|
|
} |
1076 |
|
|
|
1077 |
|
|
/* Collect intermediate string. */ |
1078 |
|
|
static int |
1079 |
|
|
input_intermediate(struct input_ctx *ictx) |
1080 |
|
|
{ |
1081 |
|
|
if (ictx->interm_len == (sizeof ictx->interm_buf) - 1) |
1082 |
|
|
ictx->flags |= INPUT_DISCARD; |
1083 |
|
|
else { |
1084 |
|
|
ictx->interm_buf[ictx->interm_len++] = ictx->ch; |
1085 |
|
|
ictx->interm_buf[ictx->interm_len] = '\0'; |
1086 |
|
|
} |
1087 |
|
|
|
1088 |
|
|
return (0); |
1089 |
|
|
} |
1090 |
|
|
|
1091 |
|
|
/* Collect parameter string. */ |
1092 |
|
|
static int |
1093 |
|
|
input_parameter(struct input_ctx *ictx) |
1094 |
|
|
{ |
1095 |
|
|
if (ictx->param_len == (sizeof ictx->param_buf) - 1) |
1096 |
|
|
ictx->flags |= INPUT_DISCARD; |
1097 |
|
|
else { |
1098 |
|
|
ictx->param_buf[ictx->param_len++] = ictx->ch; |
1099 |
|
|
ictx->param_buf[ictx->param_len] = '\0'; |
1100 |
|
|
} |
1101 |
|
|
|
1102 |
|
|
return (0); |
1103 |
|
|
} |
1104 |
|
|
|
1105 |
|
|
/* Collect input string. */ |
1106 |
|
|
static int |
1107 |
|
|
input_input(struct input_ctx *ictx) |
1108 |
|
|
{ |
1109 |
|
|
size_t available; |
1110 |
|
|
|
1111 |
|
|
available = ictx->input_space; |
1112 |
|
|
while (ictx->input_len + 1 >= available) { |
1113 |
|
|
available *= 2; |
1114 |
|
|
if (available > INPUT_BUF_LIMIT) { |
1115 |
|
|
ictx->flags |= INPUT_DISCARD; |
1116 |
|
|
return (0); |
1117 |
|
|
} |
1118 |
|
|
ictx->input_buf = xrealloc(ictx->input_buf, available); |
1119 |
|
|
ictx->input_space = available; |
1120 |
|
|
} |
1121 |
|
|
ictx->input_buf[ictx->input_len++] = ictx->ch; |
1122 |
|
|
ictx->input_buf[ictx->input_len] = '\0'; |
1123 |
|
|
|
1124 |
|
|
return (0); |
1125 |
|
|
} |
1126 |
|
|
|
1127 |
|
|
/* Execute C0 control sequence. */ |
1128 |
|
|
static int |
1129 |
|
|
input_c0_dispatch(struct input_ctx *ictx) |
1130 |
|
|
{ |
1131 |
|
|
struct screen_write_ctx *sctx = &ictx->ctx; |
1132 |
|
|
struct window_pane *wp = ictx->wp; |
1133 |
|
|
struct screen *s = sctx->s; |
1134 |
|
|
|
1135 |
|
|
log_debug("%s: '%c'", __func__, ictx->ch); |
1136 |
|
|
|
1137 |
|
|
switch (ictx->ch) { |
1138 |
|
|
case '\000': /* NUL */ |
1139 |
|
|
break; |
1140 |
|
|
case '\007': /* BEL */ |
1141 |
|
|
alerts_queue(wp->window, WINDOW_BELL); |
1142 |
|
|
break; |
1143 |
|
|
case '\010': /* BS */ |
1144 |
|
|
screen_write_backspace(sctx); |
1145 |
|
|
break; |
1146 |
|
|
case '\011': /* HT */ |
1147 |
|
|
/* Don't tab beyond the end of the line. */ |
1148 |
|
|
if (s->cx >= screen_size_x(s) - 1) |
1149 |
|
|
break; |
1150 |
|
|
|
1151 |
|
|
/* Find the next tab point, or use the last column if none. */ |
1152 |
|
|
do { |
1153 |
|
|
s->cx++; |
1154 |
|
|
if (bit_test(s->tabs, s->cx)) |
1155 |
|
|
break; |
1156 |
|
|
} while (s->cx < screen_size_x(s) - 1); |
1157 |
|
|
break; |
1158 |
|
|
case '\012': /* LF */ |
1159 |
|
|
case '\013': /* VT */ |
1160 |
|
|
case '\014': /* FF */ |
1161 |
|
|
screen_write_linefeed(sctx, 0, ictx->cell.cell.bg); |
1162 |
|
|
break; |
1163 |
|
|
case '\015': /* CR */ |
1164 |
|
|
screen_write_carriagereturn(sctx); |
1165 |
|
|
break; |
1166 |
|
|
case '\016': /* SO */ |
1167 |
|
|
ictx->cell.set = 1; |
1168 |
|
|
break; |
1169 |
|
|
case '\017': /* SI */ |
1170 |
|
|
ictx->cell.set = 0; |
1171 |
|
|
break; |
1172 |
|
|
default: |
1173 |
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch); |
1174 |
|
|
break; |
1175 |
|
|
} |
1176 |
|
|
|
1177 |
|
|
ictx->last = -1; |
1178 |
|
|
return (0); |
1179 |
|
|
} |
1180 |
|
|
|
1181 |
|
|
/* Execute escape sequence. */ |
1182 |
|
|
static int |
1183 |
|
|
input_esc_dispatch(struct input_ctx *ictx) |
1184 |
|
|
{ |
1185 |
|
|
struct screen_write_ctx *sctx = &ictx->ctx; |
1186 |
|
|
struct screen *s = sctx->s; |
1187 |
|
|
struct input_table_entry *entry; |
1188 |
|
|
|
1189 |
|
|
if (ictx->flags & INPUT_DISCARD) |
1190 |
|
|
return (0); |
1191 |
|
|
log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf); |
1192 |
|
|
|
1193 |
|
|
entry = bsearch(ictx, input_esc_table, nitems(input_esc_table), |
1194 |
|
|
sizeof input_esc_table[0], input_table_compare); |
1195 |
|
|
if (entry == NULL) { |
1196 |
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch); |
1197 |
|
|
return (0); |
1198 |
|
|
} |
1199 |
|
|
|
1200 |
|
|
switch (entry->type) { |
1201 |
|
|
case INPUT_ESC_RIS: |
1202 |
|
|
window_pane_reset_palette(ictx->wp); |
1203 |
|
|
input_reset_cell(ictx); |
1204 |
|
|
screen_write_reset(sctx); |
1205 |
|
|
break; |
1206 |
|
|
case INPUT_ESC_IND: |
1207 |
|
|
screen_write_linefeed(sctx, 0, ictx->cell.cell.bg); |
1208 |
|
|
break; |
1209 |
|
|
case INPUT_ESC_NEL: |
1210 |
|
|
screen_write_carriagereturn(sctx); |
1211 |
|
|
screen_write_linefeed(sctx, 0, ictx->cell.cell.bg); |
1212 |
|
|
break; |
1213 |
|
|
case INPUT_ESC_HTS: |
1214 |
|
|
if (s->cx < screen_size_x(s)) |
1215 |
|
|
bit_set(s->tabs, s->cx); |
1216 |
|
|
break; |
1217 |
|
|
case INPUT_ESC_RI: |
1218 |
|
|
screen_write_reverseindex(sctx, ictx->cell.cell.bg); |
1219 |
|
|
break; |
1220 |
|
|
case INPUT_ESC_DECKPAM: |
1221 |
|
|
screen_write_mode_set(sctx, MODE_KKEYPAD); |
1222 |
|
|
break; |
1223 |
|
|
case INPUT_ESC_DECKPNM: |
1224 |
|
|
screen_write_mode_clear(sctx, MODE_KKEYPAD); |
1225 |
|
|
break; |
1226 |
|
|
case INPUT_ESC_DECSC: |
1227 |
|
|
memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); |
1228 |
|
|
ictx->old_cx = s->cx; |
1229 |
|
|
ictx->old_cy = s->cy; |
1230 |
|
|
break; |
1231 |
|
|
case INPUT_ESC_DECRC: |
1232 |
|
|
memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell); |
1233 |
|
|
screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy); |
1234 |
|
|
break; |
1235 |
|
|
case INPUT_ESC_DECALN: |
1236 |
|
|
screen_write_alignmenttest(sctx); |
1237 |
|
|
break; |
1238 |
|
|
case INPUT_ESC_SCSG0_ON: |
1239 |
|
|
ictx->cell.g0set = 1; |
1240 |
|
|
break; |
1241 |
|
|
case INPUT_ESC_SCSG0_OFF: |
1242 |
|
|
ictx->cell.g0set = 0; |
1243 |
|
|
break; |
1244 |
|
|
case INPUT_ESC_SCSG1_ON: |
1245 |
|
|
ictx->cell.g1set = 1; |
1246 |
|
|
break; |
1247 |
|
|
case INPUT_ESC_SCSG1_OFF: |
1248 |
|
|
ictx->cell.g1set = 0; |
1249 |
|
|
break; |
1250 |
|
|
case INPUT_ESC_ST: |
1251 |
|
|
/* ST terminates OSC but the state transition already did it. */ |
1252 |
|
|
break; |
1253 |
|
|
} |
1254 |
|
|
|
1255 |
|
|
ictx->last = -1; |
1256 |
|
|
return (0); |
1257 |
|
|
} |
1258 |
|
|
|
1259 |
|
|
/* Execute control sequence. */ |
1260 |
|
|
static int |
1261 |
|
|
input_csi_dispatch(struct input_ctx *ictx) |
1262 |
|
|
{ |
1263 |
|
|
struct screen_write_ctx *sctx = &ictx->ctx; |
1264 |
|
|
struct screen *s = sctx->s; |
1265 |
|
|
struct input_table_entry *entry; |
1266 |
|
|
int i, n, m; |
1267 |
|
|
u_int cx; |
1268 |
|
|
|
1269 |
|
|
if (ictx->flags & INPUT_DISCARD) |
1270 |
|
|
return (0); |
1271 |
|
|
|
1272 |
|
|
log_debug("%s: '%c' \"%s\" \"%s\"", |
1273 |
|
|
__func__, ictx->ch, ictx->interm_buf, ictx->param_buf); |
1274 |
|
|
|
1275 |
|
|
if (input_split(ictx) != 0) |
1276 |
|
|
return (0); |
1277 |
|
|
|
1278 |
|
|
entry = bsearch(ictx, input_csi_table, nitems(input_csi_table), |
1279 |
|
|
sizeof input_csi_table[0], input_table_compare); |
1280 |
|
|
if (entry == NULL) { |
1281 |
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch); |
1282 |
|
|
return (0); |
1283 |
|
|
} |
1284 |
|
|
|
1285 |
|
|
switch (entry->type) { |
1286 |
|
|
case INPUT_CSI_CBT: |
1287 |
|
|
/* Find the previous tab point, n times. */ |
1288 |
|
|
cx = s->cx; |
1289 |
|
|
if (cx > screen_size_x(s) - 1) |
1290 |
|
|
cx = screen_size_x(s) - 1; |
1291 |
|
|
n = input_get(ictx, 0, 1, 1); |
1292 |
|
|
while (cx > 0 && n-- > 0) { |
1293 |
|
|
do |
1294 |
|
|
cx--; |
1295 |
|
|
while (cx > 0 && !bit_test(s->tabs, cx)); |
1296 |
|
|
} |
1297 |
|
|
s->cx = cx; |
1298 |
|
|
break; |
1299 |
|
|
case INPUT_CSI_CUB: |
1300 |
|
|
screen_write_cursorleft(sctx, input_get(ictx, 0, 1, 1)); |
1301 |
|
|
break; |
1302 |
|
|
case INPUT_CSI_CUD: |
1303 |
|
|
screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1)); |
1304 |
|
|
break; |
1305 |
|
|
case INPUT_CSI_CUF: |
1306 |
|
|
screen_write_cursorright(sctx, input_get(ictx, 0, 1, 1)); |
1307 |
|
|
break; |
1308 |
|
|
case INPUT_CSI_CUP: |
1309 |
|
|
n = input_get(ictx, 0, 1, 1); |
1310 |
|
|
m = input_get(ictx, 1, 1, 1); |
1311 |
|
|
screen_write_cursormove(sctx, m - 1, n - 1); |
1312 |
|
|
break; |
1313 |
|
|
case INPUT_CSI_WINOPS: |
1314 |
|
|
input_csi_dispatch_winops(ictx); |
1315 |
|
|
break; |
1316 |
|
|
case INPUT_CSI_CUU: |
1317 |
|
|
screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1)); |
1318 |
|
|
break; |
1319 |
|
|
case INPUT_CSI_CNL: |
1320 |
|
|
screen_write_carriagereturn(sctx); |
1321 |
|
|
screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1)); |
1322 |
|
|
break; |
1323 |
|
|
case INPUT_CSI_CPL: |
1324 |
|
|
screen_write_carriagereturn(sctx); |
1325 |
|
|
screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1)); |
1326 |
|
|
break; |
1327 |
|
|
case INPUT_CSI_DA: |
1328 |
|
|
switch (input_get(ictx, 0, 0, 0)) { |
1329 |
|
|
case 0: |
1330 |
|
|
input_reply(ictx, "\033[?1;2c"); |
1331 |
|
|
break; |
1332 |
|
|
default: |
1333 |
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch); |
1334 |
|
|
break; |
1335 |
|
|
} |
1336 |
|
|
break; |
1337 |
|
|
case INPUT_CSI_DA_TWO: |
1338 |
|
|
switch (input_get(ictx, 0, 0, 0)) { |
1339 |
|
|
case 0: |
1340 |
|
|
input_reply(ictx, "\033[>84;0;0c"); |
1341 |
|
|
break; |
1342 |
|
|
default: |
1343 |
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch); |
1344 |
|
|
break; |
1345 |
|
|
} |
1346 |
|
|
break; |
1347 |
|
|
case INPUT_CSI_ECH: |
1348 |
|
|
screen_write_clearcharacter(sctx, input_get(ictx, 0, 1, 1), |
1349 |
|
|
ictx->cell.cell.bg); |
1350 |
|
|
break; |
1351 |
|
|
case INPUT_CSI_DCH: |
1352 |
|
|
screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1), |
1353 |
|
|
ictx->cell.cell.bg); |
1354 |
|
|
break; |
1355 |
|
|
case INPUT_CSI_DECSTBM: |
1356 |
|
|
n = input_get(ictx, 0, 1, 1); |
1357 |
|
|
m = input_get(ictx, 1, 1, screen_size_y(s)); |
1358 |
|
|
screen_write_scrollregion(sctx, n - 1, m - 1); |
1359 |
|
|
break; |
1360 |
|
|
case INPUT_CSI_DL: |
1361 |
|
|
screen_write_deleteline(sctx, input_get(ictx, 0, 1, 1), |
1362 |
|
|
ictx->cell.cell.bg); |
1363 |
|
|
break; |
1364 |
|
|
case INPUT_CSI_DSR: |
1365 |
|
|
switch (input_get(ictx, 0, 0, 0)) { |
1366 |
|
|
case 5: |
1367 |
|
|
input_reply(ictx, "\033[0n"); |
1368 |
|
|
break; |
1369 |
|
|
case 6: |
1370 |
|
|
input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1); |
1371 |
|
|
break; |
1372 |
|
|
default: |
1373 |
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch); |
1374 |
|
|
break; |
1375 |
|
|
} |
1376 |
|
|
break; |
1377 |
|
|
case INPUT_CSI_ED: |
1378 |
|
|
switch (input_get(ictx, 0, 0, 0)) { |
1379 |
|
|
case 0: |
1380 |
|
|
screen_write_clearendofscreen(sctx, ictx->cell.cell.bg); |
1381 |
|
|
break; |
1382 |
|
|
case 1: |
1383 |
|
|
screen_write_clearstartofscreen(sctx, ictx->cell.cell.bg); |
1384 |
|
|
break; |
1385 |
|
|
case 2: |
1386 |
|
|
screen_write_clearscreen(sctx, ictx->cell.cell.bg); |
1387 |
|
|
break; |
1388 |
|
|
case 3: |
1389 |
|
|
switch (input_get(ictx, 1, 0, 0)) { |
1390 |
|
|
case 0: |
1391 |
|
|
/* |
1392 |
|
|
* Linux console extension to clear history |
1393 |
|
|
* (for example before locking the screen). |
1394 |
|
|
*/ |
1395 |
|
|
screen_write_clearhistory(sctx); |
1396 |
|
|
break; |
1397 |
|
|
} |
1398 |
|
|
break; |
1399 |
|
|
default: |
1400 |
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch); |
1401 |
|
|
break; |
1402 |
|
|
} |
1403 |
|
|
break; |
1404 |
|
|
case INPUT_CSI_EL: |
1405 |
|
|
switch (input_get(ictx, 0, 0, 0)) { |
1406 |
|
|
case 0: |
1407 |
|
|
screen_write_clearendofline(sctx, ictx->cell.cell.bg); |
1408 |
|
|
break; |
1409 |
|
|
case 1: |
1410 |
|
|
screen_write_clearstartofline(sctx, ictx->cell.cell.bg); |
1411 |
|
|
break; |
1412 |
|
|
case 2: |
1413 |
|
|
screen_write_clearline(sctx, ictx->cell.cell.bg); |
1414 |
|
|
break; |
1415 |
|
|
default: |
1416 |
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch); |
1417 |
|
|
break; |
1418 |
|
|
} |
1419 |
|
|
break; |
1420 |
|
|
case INPUT_CSI_HPA: |
1421 |
|
|
n = input_get(ictx, 0, 1, 1); |
1422 |
|
|
screen_write_cursormove(sctx, n - 1, s->cy); |
1423 |
|
|
break; |
1424 |
|
|
case INPUT_CSI_ICH: |
1425 |
|
|
screen_write_insertcharacter(sctx, input_get(ictx, 0, 1, 1), |
1426 |
|
|
ictx->cell.cell.bg); |
1427 |
|
|
break; |
1428 |
|
|
case INPUT_CSI_IL: |
1429 |
|
|
screen_write_insertline(sctx, input_get(ictx, 0, 1, 1), |
1430 |
|
|
ictx->cell.cell.bg); |
1431 |
|
|
break; |
1432 |
|
|
case INPUT_CSI_REP: |
1433 |
|
|
if (ictx->last == -1) |
1434 |
|
|
break; |
1435 |
|
|
ictx->ch = ictx->last; |
1436 |
|
|
|
1437 |
|
|
n = input_get(ictx, 0, 1, 1); |
1438 |
|
|
for (i = 0; i < n; i++) |
1439 |
|
|
input_print(ictx); |
1440 |
|
|
break; |
1441 |
|
|
case INPUT_CSI_RCP: |
1442 |
|
|
memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell); |
1443 |
|
|
screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy); |
1444 |
|
|
break; |
1445 |
|
|
case INPUT_CSI_RM: |
1446 |
|
|
input_csi_dispatch_rm(ictx); |
1447 |
|
|
break; |
1448 |
|
|
case INPUT_CSI_RM_PRIVATE: |
1449 |
|
|
input_csi_dispatch_rm_private(ictx); |
1450 |
|
|
break; |
1451 |
|
|
case INPUT_CSI_SCP: |
1452 |
|
|
memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); |
1453 |
|
|
ictx->old_cx = s->cx; |
1454 |
|
|
ictx->old_cy = s->cy; |
1455 |
|
|
break; |
1456 |
|
|
case INPUT_CSI_SGR: |
1457 |
|
|
input_csi_dispatch_sgr(ictx); |
1458 |
|
|
break; |
1459 |
|
|
case INPUT_CSI_SM: |
1460 |
|
|
input_csi_dispatch_sm(ictx); |
1461 |
|
|
break; |
1462 |
|
|
case INPUT_CSI_SM_PRIVATE: |
1463 |
|
|
input_csi_dispatch_sm_private(ictx); |
1464 |
|
|
break; |
1465 |
|
|
case INPUT_CSI_SU: |
1466 |
|
|
screen_write_scrollup(sctx, input_get(ictx, 0, 1, 1), |
1467 |
|
|
ictx->cell.cell.bg); |
1468 |
|
|
break; |
1469 |
|
|
case INPUT_CSI_TBC: |
1470 |
|
|
switch (input_get(ictx, 0, 0, 0)) { |
1471 |
|
|
case 0: |
1472 |
|
|
if (s->cx < screen_size_x(s)) |
1473 |
|
|
bit_clear(s->tabs, s->cx); |
1474 |
|
|
break; |
1475 |
|
|
case 3: |
1476 |
|
|
bit_nclear(s->tabs, 0, screen_size_x(s) - 1); |
1477 |
|
|
break; |
1478 |
|
|
default: |
1479 |
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch); |
1480 |
|
|
break; |
1481 |
|
|
} |
1482 |
|
|
break; |
1483 |
|
|
case INPUT_CSI_VPA: |
1484 |
|
|
n = input_get(ictx, 0, 1, 1); |
1485 |
|
|
screen_write_cursormove(sctx, s->cx, n - 1); |
1486 |
|
|
break; |
1487 |
|
|
case INPUT_CSI_DECSCUSR: |
1488 |
|
|
n = input_get(ictx, 0, 0, 0); |
1489 |
|
|
screen_set_cursor_style(s, n); |
1490 |
|
|
break; |
1491 |
|
|
} |
1492 |
|
|
|
1493 |
|
|
ictx->last = -1; |
1494 |
|
|
return (0); |
1495 |
|
|
} |
1496 |
|
|
|
1497 |
|
|
/* Handle CSI RM. */ |
1498 |
|
|
static void |
1499 |
|
|
input_csi_dispatch_rm(struct input_ctx *ictx) |
1500 |
|
|
{ |
1501 |
|
|
u_int i; |
1502 |
|
|
|
1503 |
|
|
for (i = 0; i < ictx->param_list_len; i++) { |
1504 |
|
|
switch (input_get(ictx, i, 0, -1)) { |
1505 |
|
|
case 4: /* IRM */ |
1506 |
|
|
screen_write_mode_clear(&ictx->ctx, MODE_INSERT); |
1507 |
|
|
break; |
1508 |
|
|
case 34: |
1509 |
|
|
screen_write_mode_set(&ictx->ctx, MODE_BLINKING); |
1510 |
|
|
break; |
1511 |
|
|
default: |
1512 |
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch); |
1513 |
|
|
break; |
1514 |
|
|
} |
1515 |
|
|
} |
1516 |
|
|
} |
1517 |
|
|
|
1518 |
|
|
/* Handle CSI private RM. */ |
1519 |
|
|
static void |
1520 |
|
|
input_csi_dispatch_rm_private(struct input_ctx *ictx) |
1521 |
|
|
{ |
1522 |
|
|
struct window_pane *wp = ictx->wp; |
1523 |
|
|
u_int i; |
1524 |
|
|
|
1525 |
|
|
for (i = 0; i < ictx->param_list_len; i++) { |
1526 |
|
|
switch (input_get(ictx, i, 0, -1)) { |
1527 |
|
|
case 1: /* DECCKM */ |
1528 |
|
|
screen_write_mode_clear(&ictx->ctx, MODE_KCURSOR); |
1529 |
|
|
break; |
1530 |
|
|
case 3: /* DECCOLM */ |
1531 |
|
|
screen_write_cursormove(&ictx->ctx, 0, 0); |
1532 |
|
|
screen_write_clearscreen(&ictx->ctx, |
1533 |
|
|
ictx->cell.cell.bg); |
1534 |
|
|
break; |
1535 |
|
|
case 7: /* DECAWM */ |
1536 |
|
|
screen_write_mode_clear(&ictx->ctx, MODE_WRAP); |
1537 |
|
|
break; |
1538 |
|
|
case 12: |
1539 |
|
|
screen_write_mode_clear(&ictx->ctx, MODE_BLINKING); |
1540 |
|
|
break; |
1541 |
|
|
case 25: /* TCEM */ |
1542 |
|
|
screen_write_mode_clear(&ictx->ctx, MODE_CURSOR); |
1543 |
|
|
break; |
1544 |
|
|
case 1000: |
1545 |
|
|
case 1001: |
1546 |
|
|
case 1002: |
1547 |
|
|
case 1003: |
1548 |
|
|
screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES); |
1549 |
|
|
break; |
1550 |
|
|
case 1004: |
1551 |
|
|
screen_write_mode_clear(&ictx->ctx, MODE_FOCUSON); |
1552 |
|
|
break; |
1553 |
|
|
case 1005: |
1554 |
|
|
screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_UTF8); |
1555 |
|
|
break; |
1556 |
|
|
case 1006: |
1557 |
|
|
screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_SGR); |
1558 |
|
|
break; |
1559 |
|
|
case 47: |
1560 |
|
|
case 1047: |
1561 |
|
|
window_pane_alternate_off(wp, &ictx->cell.cell, 0); |
1562 |
|
|
break; |
1563 |
|
|
case 1049: |
1564 |
|
|
window_pane_alternate_off(wp, &ictx->cell.cell, 1); |
1565 |
|
|
break; |
1566 |
|
|
case 2004: |
1567 |
|
|
screen_write_mode_clear(&ictx->ctx, MODE_BRACKETPASTE); |
1568 |
|
|
break; |
1569 |
|
|
default: |
1570 |
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch); |
1571 |
|
|
break; |
1572 |
|
|
} |
1573 |
|
|
} |
1574 |
|
|
} |
1575 |
|
|
|
1576 |
|
|
/* Handle CSI SM. */ |
1577 |
|
|
static void |
1578 |
|
|
input_csi_dispatch_sm(struct input_ctx *ictx) |
1579 |
|
|
{ |
1580 |
|
|
u_int i; |
1581 |
|
|
|
1582 |
|
|
for (i = 0; i < ictx->param_list_len; i++) { |
1583 |
|
|
switch (input_get(ictx, i, 0, -1)) { |
1584 |
|
|
case 4: /* IRM */ |
1585 |
|
|
screen_write_mode_set(&ictx->ctx, MODE_INSERT); |
1586 |
|
|
break; |
1587 |
|
|
case 34: |
1588 |
|
|
screen_write_mode_clear(&ictx->ctx, MODE_BLINKING); |
1589 |
|
|
break; |
1590 |
|
|
default: |
1591 |
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch); |
1592 |
|
|
break; |
1593 |
|
|
} |
1594 |
|
|
} |
1595 |
|
|
} |
1596 |
|
|
|
1597 |
|
|
/* Handle CSI private SM. */ |
1598 |
|
|
static void |
1599 |
|
|
input_csi_dispatch_sm_private(struct input_ctx *ictx) |
1600 |
|
|
{ |
1601 |
|
|
struct window_pane *wp = ictx->wp; |
1602 |
|
|
u_int i; |
1603 |
|
|
|
1604 |
|
|
for (i = 0; i < ictx->param_list_len; i++) { |
1605 |
|
|
switch (input_get(ictx, i, 0, -1)) { |
1606 |
|
|
case 1: /* DECCKM */ |
1607 |
|
|
screen_write_mode_set(&ictx->ctx, MODE_KCURSOR); |
1608 |
|
|
break; |
1609 |
|
|
case 3: /* DECCOLM */ |
1610 |
|
|
screen_write_cursormove(&ictx->ctx, 0, 0); |
1611 |
|
|
screen_write_clearscreen(&ictx->ctx, |
1612 |
|
|
ictx->cell.cell.bg); |
1613 |
|
|
break; |
1614 |
|
|
case 7: /* DECAWM */ |
1615 |
|
|
screen_write_mode_set(&ictx->ctx, MODE_WRAP); |
1616 |
|
|
break; |
1617 |
|
|
case 12: |
1618 |
|
|
screen_write_mode_set(&ictx->ctx, MODE_BLINKING); |
1619 |
|
|
break; |
1620 |
|
|
case 25: /* TCEM */ |
1621 |
|
|
screen_write_mode_set(&ictx->ctx, MODE_CURSOR); |
1622 |
|
|
break; |
1623 |
|
|
case 1000: |
1624 |
|
|
screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES); |
1625 |
|
|
screen_write_mode_set(&ictx->ctx, MODE_MOUSE_STANDARD); |
1626 |
|
|
break; |
1627 |
|
|
case 1002: |
1628 |
|
|
screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES); |
1629 |
|
|
screen_write_mode_set(&ictx->ctx, MODE_MOUSE_BUTTON); |
1630 |
|
|
break; |
1631 |
|
|
case 1003: |
1632 |
|
|
screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES); |
1633 |
|
|
screen_write_mode_set(&ictx->ctx, MODE_MOUSE_ALL); |
1634 |
|
|
break; |
1635 |
|
|
case 1004: |
1636 |
|
|
if (ictx->ctx.s->mode & MODE_FOCUSON) |
1637 |
|
|
break; |
1638 |
|
|
screen_write_mode_set(&ictx->ctx, MODE_FOCUSON); |
1639 |
|
|
wp->flags |= PANE_FOCUSPUSH; /* force update */ |
1640 |
|
|
break; |
1641 |
|
|
case 1005: |
1642 |
|
|
screen_write_mode_set(&ictx->ctx, MODE_MOUSE_UTF8); |
1643 |
|
|
break; |
1644 |
|
|
case 1006: |
1645 |
|
|
screen_write_mode_set(&ictx->ctx, MODE_MOUSE_SGR); |
1646 |
|
|
break; |
1647 |
|
|
case 47: |
1648 |
|
|
case 1047: |
1649 |
|
|
window_pane_alternate_on(wp, &ictx->cell.cell, 0); |
1650 |
|
|
break; |
1651 |
|
|
case 1049: |
1652 |
|
|
window_pane_alternate_on(wp, &ictx->cell.cell, 1); |
1653 |
|
|
break; |
1654 |
|
|
case 2004: |
1655 |
|
|
screen_write_mode_set(&ictx->ctx, MODE_BRACKETPASTE); |
1656 |
|
|
break; |
1657 |
|
|
default: |
1658 |
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch); |
1659 |
|
|
break; |
1660 |
|
|
} |
1661 |
|
|
} |
1662 |
|
|
} |
1663 |
|
|
|
1664 |
|
|
/* Handle CSI window operations. */ |
1665 |
|
|
static void |
1666 |
|
|
input_csi_dispatch_winops(struct input_ctx *ictx) |
1667 |
|
|
{ |
1668 |
|
|
struct window_pane *wp = ictx->wp; |
1669 |
|
|
int n, m; |
1670 |
|
|
|
1671 |
|
|
m = 0; |
1672 |
|
|
while ((n = input_get(ictx, m, 0, -1)) != -1) { |
1673 |
|
|
switch (n) { |
1674 |
|
|
case 1: |
1675 |
|
|
case 2: |
1676 |
|
|
case 5: |
1677 |
|
|
case 6: |
1678 |
|
|
case 7: |
1679 |
|
|
case 11: |
1680 |
|
|
case 13: |
1681 |
|
|
case 14: |
1682 |
|
|
case 19: |
1683 |
|
|
case 20: |
1684 |
|
|
case 21: |
1685 |
|
|
case 24: |
1686 |
|
|
break; |
1687 |
|
|
case 3: |
1688 |
|
|
case 4: |
1689 |
|
|
case 8: |
1690 |
|
|
m++; |
1691 |
|
|
if (input_get(ictx, m, 0, -1) == -1) |
1692 |
|
|
return; |
1693 |
|
|
/* FALLTHROUGH */ |
1694 |
|
|
case 9: |
1695 |
|
|
case 10: |
1696 |
|
|
case 22: |
1697 |
|
|
case 23: |
1698 |
|
|
m++; |
1699 |
|
|
if (input_get(ictx, m, 0, -1) == -1) |
1700 |
|
|
return; |
1701 |
|
|
break; |
1702 |
|
|
case 18: |
1703 |
|
|
input_reply(ictx, "\033[8;%u;%ut", wp->sy, wp->sx); |
1704 |
|
|
break; |
1705 |
|
|
default: |
1706 |
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch); |
1707 |
|
|
break; |
1708 |
|
|
} |
1709 |
|
|
m++; |
1710 |
|
|
} |
1711 |
|
|
} |
1712 |
|
|
|
1713 |
|
|
/* Handle CSI SGR for 256 colours. */ |
1714 |
|
|
static void |
1715 |
|
|
input_csi_dispatch_sgr_256(struct input_ctx *ictx, int fgbg, u_int *i) |
1716 |
|
|
{ |
1717 |
|
|
struct grid_cell *gc = &ictx->cell.cell; |
1718 |
|
|
int c; |
1719 |
|
|
|
1720 |
|
|
(*i)++; |
1721 |
|
|
c = input_get(ictx, *i, 0, -1); |
1722 |
|
|
if (c == -1) { |
1723 |
|
|
if (fgbg == 38) |
1724 |
|
|
gc->fg = 8; |
1725 |
|
|
else if (fgbg == 48) |
1726 |
|
|
gc->bg = 8; |
1727 |
|
|
} else { |
1728 |
|
|
if (fgbg == 38) |
1729 |
|
|
gc->fg = c | COLOUR_FLAG_256; |
1730 |
|
|
else if (fgbg == 48) |
1731 |
|
|
gc->bg = c | COLOUR_FLAG_256; |
1732 |
|
|
} |
1733 |
|
|
} |
1734 |
|
|
|
1735 |
|
|
/* Handle CSI SGR for RGB colours. */ |
1736 |
|
|
static void |
1737 |
|
|
input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i) |
1738 |
|
|
{ |
1739 |
|
|
struct grid_cell *gc = &ictx->cell.cell; |
1740 |
|
|
int r, g, b; |
1741 |
|
|
|
1742 |
|
|
(*i)++; |
1743 |
|
|
r = input_get(ictx, *i, 0, -1); |
1744 |
|
|
if (r == -1 || r > 255) |
1745 |
|
|
return; |
1746 |
|
|
(*i)++; |
1747 |
|
|
g = input_get(ictx, *i, 0, -1); |
1748 |
|
|
if (g == -1 || g > 255) |
1749 |
|
|
return; |
1750 |
|
|
(*i)++; |
1751 |
|
|
b = input_get(ictx, *i, 0, -1); |
1752 |
|
|
if (b == -1 || b > 255) |
1753 |
|
|
return; |
1754 |
|
|
|
1755 |
|
|
if (fgbg == 38) |
1756 |
|
|
gc->fg = colour_join_rgb(r, g, b); |
1757 |
|
|
else if (fgbg == 48) |
1758 |
|
|
gc->bg = colour_join_rgb(r, g, b); |
1759 |
|
|
} |
1760 |
|
|
|
1761 |
|
|
/* Handle CSI SGR. */ |
1762 |
|
|
static void |
1763 |
|
|
input_csi_dispatch_sgr(struct input_ctx *ictx) |
1764 |
|
|
{ |
1765 |
|
|
struct grid_cell *gc = &ictx->cell.cell; |
1766 |
|
|
u_int i; |
1767 |
|
|
int n; |
1768 |
|
|
|
1769 |
|
|
if (ictx->param_list_len == 0) { |
1770 |
|
|
memcpy(gc, &grid_default_cell, sizeof *gc); |
1771 |
|
|
return; |
1772 |
|
|
} |
1773 |
|
|
|
1774 |
|
|
for (i = 0; i < ictx->param_list_len; i++) { |
1775 |
|
|
n = input_get(ictx, i, 0, 0); |
1776 |
|
|
|
1777 |
|
|
if (n == 38 || n == 48) { |
1778 |
|
|
i++; |
1779 |
|
|
switch (input_get(ictx, i, 0, -1)) { |
1780 |
|
|
case 2: |
1781 |
|
|
input_csi_dispatch_sgr_rgb(ictx, n, &i); |
1782 |
|
|
break; |
1783 |
|
|
case 5: |
1784 |
|
|
input_csi_dispatch_sgr_256(ictx, n, &i); |
1785 |
|
|
break; |
1786 |
|
|
} |
1787 |
|
|
continue; |
1788 |
|
|
} |
1789 |
|
|
|
1790 |
|
|
switch (n) { |
1791 |
|
|
case 0: |
1792 |
|
|
case 10: |
1793 |
|
|
memcpy(gc, &grid_default_cell, sizeof *gc); |
1794 |
|
|
break; |
1795 |
|
|
case 1: |
1796 |
|
|
gc->attr |= GRID_ATTR_BRIGHT; |
1797 |
|
|
break; |
1798 |
|
|
case 2: |
1799 |
|
|
gc->attr |= GRID_ATTR_DIM; |
1800 |
|
|
break; |
1801 |
|
|
case 3: |
1802 |
|
|
gc->attr |= GRID_ATTR_ITALICS; |
1803 |
|
|
break; |
1804 |
|
|
case 4: |
1805 |
|
|
gc->attr |= GRID_ATTR_UNDERSCORE; |
1806 |
|
|
break; |
1807 |
|
|
case 5: |
1808 |
|
|
gc->attr |= GRID_ATTR_BLINK; |
1809 |
|
|
break; |
1810 |
|
|
case 7: |
1811 |
|
|
gc->attr |= GRID_ATTR_REVERSE; |
1812 |
|
|
break; |
1813 |
|
|
case 8: |
1814 |
|
|
gc->attr |= GRID_ATTR_HIDDEN; |
1815 |
|
|
break; |
1816 |
|
|
case 9: |
1817 |
|
|
gc->attr |= GRID_ATTR_STRIKETHROUGH; |
1818 |
|
|
break; |
1819 |
|
|
case 22: |
1820 |
|
|
gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM); |
1821 |
|
|
break; |
1822 |
|
|
case 23: |
1823 |
|
|
gc->attr &= ~GRID_ATTR_ITALICS; |
1824 |
|
|
break; |
1825 |
|
|
case 24: |
1826 |
|
|
gc->attr &= ~GRID_ATTR_UNDERSCORE; |
1827 |
|
|
break; |
1828 |
|
|
case 25: |
1829 |
|
|
gc->attr &= ~GRID_ATTR_BLINK; |
1830 |
|
|
break; |
1831 |
|
|
case 27: |
1832 |
|
|
gc->attr &= ~GRID_ATTR_REVERSE; |
1833 |
|
|
break; |
1834 |
|
|
case 28: |
1835 |
|
|
gc->attr &= ~GRID_ATTR_HIDDEN; |
1836 |
|
|
break; |
1837 |
|
|
case 29: |
1838 |
|
|
gc->attr &= ~GRID_ATTR_STRIKETHROUGH; |
1839 |
|
|
break; |
1840 |
|
|
case 30: |
1841 |
|
|
case 31: |
1842 |
|
|
case 32: |
1843 |
|
|
case 33: |
1844 |
|
|
case 34: |
1845 |
|
|
case 35: |
1846 |
|
|
case 36: |
1847 |
|
|
case 37: |
1848 |
|
|
gc->fg = n - 30; |
1849 |
|
|
break; |
1850 |
|
|
case 39: |
1851 |
|
|
gc->fg = 8; |
1852 |
|
|
break; |
1853 |
|
|
case 40: |
1854 |
|
|
case 41: |
1855 |
|
|
case 42: |
1856 |
|
|
case 43: |
1857 |
|
|
case 44: |
1858 |
|
|
case 45: |
1859 |
|
|
case 46: |
1860 |
|
|
case 47: |
1861 |
|
|
gc->bg = n - 40; |
1862 |
|
|
break; |
1863 |
|
|
case 49: |
1864 |
|
|
gc->bg = 8; |
1865 |
|
|
break; |
1866 |
|
|
case 90: |
1867 |
|
|
case 91: |
1868 |
|
|
case 92: |
1869 |
|
|
case 93: |
1870 |
|
|
case 94: |
1871 |
|
|
case 95: |
1872 |
|
|
case 96: |
1873 |
|
|
case 97: |
1874 |
|
|
gc->fg = n; |
1875 |
|
|
break; |
1876 |
|
|
case 100: |
1877 |
|
|
case 101: |
1878 |
|
|
case 102: |
1879 |
|
|
case 103: |
1880 |
|
|
case 104: |
1881 |
|
|
case 105: |
1882 |
|
|
case 106: |
1883 |
|
|
case 107: |
1884 |
|
|
gc->bg = n - 10; |
1885 |
|
|
break; |
1886 |
|
|
} |
1887 |
|
|
} |
1888 |
|
|
} |
1889 |
|
|
|
1890 |
|
|
/* DCS string started. */ |
1891 |
|
|
static void |
1892 |
|
|
input_enter_dcs(struct input_ctx *ictx) |
1893 |
|
|
{ |
1894 |
|
|
log_debug("%s", __func__); |
1895 |
|
|
|
1896 |
|
|
input_clear(ictx); |
1897 |
|
|
input_start_timer(ictx); |
1898 |
|
|
ictx->last = -1; |
1899 |
|
|
} |
1900 |
|
|
|
1901 |
|
|
/* DCS terminator (ST) received. */ |
1902 |
|
|
static int |
1903 |
|
|
input_dcs_dispatch(struct input_ctx *ictx) |
1904 |
|
|
{ |
1905 |
|
|
const char prefix[] = "tmux;"; |
1906 |
|
|
const u_int prefix_len = (sizeof prefix) - 1; |
1907 |
|
|
|
1908 |
|
|
if (ictx->flags & INPUT_DISCARD) |
1909 |
|
|
return (0); |
1910 |
|
|
|
1911 |
|
|
log_debug("%s: \"%s\"", __func__, ictx->input_buf); |
1912 |
|
|
|
1913 |
|
|
/* Check for tmux prefix. */ |
1914 |
|
|
if (ictx->input_len >= prefix_len && |
1915 |
|
|
strncmp(ictx->input_buf, prefix, prefix_len) == 0) { |
1916 |
|
|
screen_write_rawstring(&ictx->ctx, |
1917 |
|
|
ictx->input_buf + prefix_len, ictx->input_len - prefix_len); |
1918 |
|
|
} |
1919 |
|
|
|
1920 |
|
|
return (0); |
1921 |
|
|
} |
1922 |
|
|
|
1923 |
|
|
/* OSC string started. */ |
1924 |
|
|
static void |
1925 |
|
|
input_enter_osc(struct input_ctx *ictx) |
1926 |
|
|
{ |
1927 |
|
|
log_debug("%s", __func__); |
1928 |
|
|
|
1929 |
|
|
input_clear(ictx); |
1930 |
|
|
input_start_timer(ictx); |
1931 |
|
|
ictx->last = -1; |
1932 |
|
|
} |
1933 |
|
|
|
1934 |
|
|
/* OSC terminator (ST) received. */ |
1935 |
|
|
static void |
1936 |
|
|
input_exit_osc(struct input_ctx *ictx) |
1937 |
|
|
{ |
1938 |
|
|
u_char *p = ictx->input_buf; |
1939 |
|
|
u_int option; |
1940 |
|
|
|
1941 |
|
|
if (ictx->flags & INPUT_DISCARD) |
1942 |
|
|
return; |
1943 |
|
|
if (ictx->input_len < 1 || *p < '0' || *p > '9') |
1944 |
|
|
return; |
1945 |
|
|
|
1946 |
|
|
log_debug("%s: \"%s\"", __func__, p); |
1947 |
|
|
|
1948 |
|
|
option = 0; |
1949 |
|
|
while (*p >= '0' && *p <= '9') |
1950 |
|
|
option = option * 10 + *p++ - '0'; |
1951 |
|
|
if (*p == ';') |
1952 |
|
|
p++; |
1953 |
|
|
|
1954 |
|
|
switch (option) { |
1955 |
|
|
case 0: |
1956 |
|
|
case 2: |
1957 |
|
|
if (utf8_isvalid(p)) { |
1958 |
|
|
screen_set_title(ictx->ctx.s, p); |
1959 |
|
|
server_status_window(ictx->wp->window); |
1960 |
|
|
} |
1961 |
|
|
break; |
1962 |
|
|
case 4: |
1963 |
|
|
input_osc_4(ictx->wp, p); |
1964 |
|
|
break; |
1965 |
|
|
case 10: |
1966 |
|
|
input_osc_10(ictx->wp, p); |
1967 |
|
|
break; |
1968 |
|
|
case 11: |
1969 |
|
|
input_osc_11(ictx->wp, p); |
1970 |
|
|
break; |
1971 |
|
|
case 12: |
1972 |
|
|
if (utf8_isvalid(p) && *p != '?') /* ? is colour request */ |
1973 |
|
|
screen_set_cursor_colour(ictx->ctx.s, p); |
1974 |
|
|
break; |
1975 |
|
|
case 52: |
1976 |
|
|
input_osc_52(ictx->wp, p); |
1977 |
|
|
break; |
1978 |
|
|
case 104: |
1979 |
|
|
input_osc_104(ictx->wp, p); |
1980 |
|
|
break; |
1981 |
|
|
case 112: |
1982 |
|
|
if (*p == '\0') /* no arguments allowed */ |
1983 |
|
|
screen_set_cursor_colour(ictx->ctx.s, ""); |
1984 |
|
|
break; |
1985 |
|
|
default: |
1986 |
|
|
log_debug("%s: unknown '%u'", __func__, option); |
1987 |
|
|
break; |
1988 |
|
|
} |
1989 |
|
|
} |
1990 |
|
|
|
1991 |
|
|
/* APC string started. */ |
1992 |
|
|
static void |
1993 |
|
|
input_enter_apc(struct input_ctx *ictx) |
1994 |
|
|
{ |
1995 |
|
|
log_debug("%s", __func__); |
1996 |
|
|
|
1997 |
|
|
input_clear(ictx); |
1998 |
|
|
input_start_timer(ictx); |
1999 |
|
|
ictx->last = -1; |
2000 |
|
|
} |
2001 |
|
|
|
2002 |
|
|
/* APC terminator (ST) received. */ |
2003 |
|
|
static void |
2004 |
|
|
input_exit_apc(struct input_ctx *ictx) |
2005 |
|
|
{ |
2006 |
|
|
if (ictx->flags & INPUT_DISCARD) |
2007 |
|
|
return; |
2008 |
|
|
log_debug("%s: \"%s\"", __func__, ictx->input_buf); |
2009 |
|
|
|
2010 |
|
|
if (!utf8_isvalid(ictx->input_buf)) |
2011 |
|
|
return; |
2012 |
|
|
screen_set_title(ictx->ctx.s, ictx->input_buf); |
2013 |
|
|
server_status_window(ictx->wp->window); |
2014 |
|
|
} |
2015 |
|
|
|
2016 |
|
|
/* Rename string started. */ |
2017 |
|
|
static void |
2018 |
|
|
input_enter_rename(struct input_ctx *ictx) |
2019 |
|
|
{ |
2020 |
|
|
log_debug("%s", __func__); |
2021 |
|
|
|
2022 |
|
|
input_clear(ictx); |
2023 |
|
|
input_start_timer(ictx); |
2024 |
|
|
ictx->last = -1; |
2025 |
|
|
} |
2026 |
|
|
|
2027 |
|
|
/* Rename terminator (ST) received. */ |
2028 |
|
|
static void |
2029 |
|
|
input_exit_rename(struct input_ctx *ictx) |
2030 |
|
|
{ |
2031 |
|
|
if (ictx->flags & INPUT_DISCARD) |
2032 |
|
|
return; |
2033 |
|
|
if (!options_get_number(ictx->wp->window->options, "allow-rename")) |
2034 |
|
|
return; |
2035 |
|
|
log_debug("%s: \"%s\"", __func__, ictx->input_buf); |
2036 |
|
|
|
2037 |
|
|
if (!utf8_isvalid(ictx->input_buf)) |
2038 |
|
|
return; |
2039 |
|
|
window_set_name(ictx->wp->window, ictx->input_buf); |
2040 |
|
|
options_set_number(ictx->wp->window->options, "automatic-rename", 0); |
2041 |
|
|
server_status_window(ictx->wp->window); |
2042 |
|
|
} |
2043 |
|
|
|
2044 |
|
|
/* Open UTF-8 character. */ |
2045 |
|
|
static int |
2046 |
|
|
input_utf8_open(struct input_ctx *ictx) |
2047 |
|
|
{ |
2048 |
|
|
struct utf8_data *ud = &ictx->utf8data; |
2049 |
|
|
|
2050 |
|
|
if (utf8_open(ud, ictx->ch) != UTF8_MORE) |
2051 |
|
|
fatalx("UTF-8 open invalid %#x", ictx->ch); |
2052 |
|
|
|
2053 |
|
|
log_debug("%s %hhu", __func__, ud->size); |
2054 |
|
|
ictx->last = -1; |
2055 |
|
|
|
2056 |
|
|
return (0); |
2057 |
|
|
} |
2058 |
|
|
|
2059 |
|
|
/* Append to UTF-8 character. */ |
2060 |
|
|
static int |
2061 |
|
|
input_utf8_add(struct input_ctx *ictx) |
2062 |
|
|
{ |
2063 |
|
|
struct utf8_data *ud = &ictx->utf8data; |
2064 |
|
|
|
2065 |
|
|
if (utf8_append(ud, ictx->ch) != UTF8_MORE) |
2066 |
|
|
fatalx("UTF-8 add invalid %#x", ictx->ch); |
2067 |
|
|
|
2068 |
|
|
log_debug("%s", __func__); |
2069 |
|
|
|
2070 |
|
|
return (0); |
2071 |
|
|
} |
2072 |
|
|
|
2073 |
|
|
/* Close UTF-8 string. */ |
2074 |
|
|
static int |
2075 |
|
|
input_utf8_close(struct input_ctx *ictx) |
2076 |
|
|
{ |
2077 |
|
|
struct utf8_data *ud = &ictx->utf8data; |
2078 |
|
|
|
2079 |
|
|
if (utf8_append(ud, ictx->ch) != UTF8_DONE) { |
2080 |
|
|
/* |
2081 |
|
|
* An error here could be invalid UTF-8 or it could be a |
2082 |
|
|
* nonprintable character for which we can't get the |
2083 |
|
|
* width. Drop it. |
2084 |
|
|
*/ |
2085 |
|
|
return (0); |
2086 |
|
|
} |
2087 |
|
|
|
2088 |
|
|
log_debug("%s %hhu '%*s' (width %hhu)", __func__, ud->size, |
2089 |
|
|
(int)ud->size, ud->data, ud->width); |
2090 |
|
|
|
2091 |
|
|
utf8_copy(&ictx->cell.cell.data, ud); |
2092 |
|
|
screen_write_collect_add(&ictx->ctx, &ictx->cell.cell); |
2093 |
|
|
|
2094 |
|
|
return (0); |
2095 |
|
|
} |
2096 |
|
|
|
2097 |
|
|
/* Handle the OSC 4 sequence for setting (multiple) palette entries. */ |
2098 |
|
|
static void |
2099 |
|
|
input_osc_4(struct window_pane *wp, const char *p) |
2100 |
|
|
{ |
2101 |
|
|
char *copy, *s, *next = NULL; |
2102 |
|
|
long idx; |
2103 |
|
|
u_int r, g, b; |
2104 |
|
|
|
2105 |
|
|
copy = s = xstrdup(p); |
2106 |
|
|
while (s != NULL && *s != '\0') { |
2107 |
|
|
idx = strtol(s, &next, 10); |
2108 |
|
|
if (*next++ != ';') |
2109 |
|
|
goto bad; |
2110 |
|
|
if (idx < 0 || idx >= 0x100) |
2111 |
|
|
goto bad; |
2112 |
|
|
|
2113 |
|
|
s = strsep(&next, ";"); |
2114 |
|
|
if (sscanf(s, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3) { |
2115 |
|
|
s = next; |
2116 |
|
|
continue; |
2117 |
|
|
} |
2118 |
|
|
|
2119 |
|
|
window_pane_set_palette(wp, idx, colour_join_rgb(r, g, b)); |
2120 |
|
|
s = next; |
2121 |
|
|
} |
2122 |
|
|
|
2123 |
|
|
free(copy); |
2124 |
|
|
return; |
2125 |
|
|
|
2126 |
|
|
bad: |
2127 |
|
|
log_debug("bad OSC 4: %s", p); |
2128 |
|
|
free(copy); |
2129 |
|
|
} |
2130 |
|
|
|
2131 |
|
|
/* Handle the OSC 10 sequence for setting background colour. */ |
2132 |
|
|
static void |
2133 |
|
|
input_osc_10(struct window_pane *wp, const char *p) |
2134 |
|
|
{ |
2135 |
|
|
u_int r, g, b; |
2136 |
|
|
|
2137 |
|
|
if (sscanf(p, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3) |
2138 |
|
|
goto bad; |
2139 |
|
|
|
2140 |
|
|
wp->colgc.fg = colour_join_rgb(r, g, b); |
2141 |
|
|
wp->flags |= PANE_REDRAW; |
2142 |
|
|
|
2143 |
|
|
return; |
2144 |
|
|
|
2145 |
|
|
bad: |
2146 |
|
|
log_debug("bad OSC 10: %s", p); |
2147 |
|
|
} |
2148 |
|
|
|
2149 |
|
|
/* Handle the OSC 11 sequence for setting background colour. */ |
2150 |
|
|
static void |
2151 |
|
|
input_osc_11(struct window_pane *wp, const char *p) |
2152 |
|
|
{ |
2153 |
|
|
u_int r, g, b; |
2154 |
|
|
|
2155 |
|
|
if (sscanf(p, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3) |
2156 |
|
|
goto bad; |
2157 |
|
|
|
2158 |
|
|
wp->colgc.bg = colour_join_rgb(r, g, b); |
2159 |
|
|
wp->flags |= PANE_REDRAW; |
2160 |
|
|
|
2161 |
|
|
return; |
2162 |
|
|
|
2163 |
|
|
bad: |
2164 |
|
|
log_debug("bad OSC 11: %s", p); |
2165 |
|
|
} |
2166 |
|
|
|
2167 |
|
|
/* Handle the OSC 52 sequence for setting the clipboard. */ |
2168 |
|
|
static void |
2169 |
|
|
input_osc_52(struct window_pane *wp, const char *p) |
2170 |
|
|
{ |
2171 |
|
|
char *end; |
2172 |
|
|
size_t len; |
2173 |
|
|
u_char *out; |
2174 |
|
|
int outlen, state; |
2175 |
|
|
struct screen_write_ctx ctx; |
2176 |
|
|
|
2177 |
|
|
state = options_get_number(global_options, "set-clipboard"); |
2178 |
|
|
if (state != 2) |
2179 |
|
|
return; |
2180 |
|
|
|
2181 |
|
|
if ((end = strchr(p, ';')) == NULL) |
2182 |
|
|
return; |
2183 |
|
|
end++; |
2184 |
|
|
if (*end == '\0') |
2185 |
|
|
return; |
2186 |
|
|
|
2187 |
|
|
len = (strlen(end) / 4) * 3; |
2188 |
|
|
if (len == 0) |
2189 |
|
|
return; |
2190 |
|
|
|
2191 |
|
|
out = xmalloc(len); |
2192 |
|
|
if ((outlen = b64_pton(end, out, len)) == -1) { |
2193 |
|
|
free(out); |
2194 |
|
|
return; |
2195 |
|
|
} |
2196 |
|
|
|
2197 |
|
|
screen_write_start(&ctx, wp, NULL); |
2198 |
|
|
screen_write_setselection(&ctx, out, outlen); |
2199 |
|
|
screen_write_stop(&ctx); |
2200 |
|
|
notify_pane("pane-set-clipboard", wp); |
2201 |
|
|
|
2202 |
|
|
paste_add(out, outlen); |
2203 |
|
|
} |
2204 |
|
|
|
2205 |
|
|
/* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */ |
2206 |
|
|
static void |
2207 |
|
|
input_osc_104(struct window_pane *wp, const char *p) |
2208 |
|
|
{ |
2209 |
|
|
char *copy, *s; |
2210 |
|
|
long idx; |
2211 |
|
|
|
2212 |
|
|
if (*p == '\0') { |
2213 |
|
|
window_pane_reset_palette(wp); |
2214 |
|
|
return; |
2215 |
|
|
} |
2216 |
|
|
|
2217 |
|
|
copy = s = xstrdup(p); |
2218 |
|
|
while (*s != '\0') { |
2219 |
|
|
idx = strtol(s, &s, 10); |
2220 |
|
|
if (*s != '\0' && *s != ';') |
2221 |
|
|
goto bad; |
2222 |
|
|
if (idx < 0 || idx >= 0x100) |
2223 |
|
|
goto bad; |
2224 |
|
|
|
2225 |
|
|
window_pane_unset_palette(wp, idx); |
2226 |
|
|
if (*s == ';') |
2227 |
|
|
s++; |
2228 |
|
|
} |
2229 |
|
|
free(copy); |
2230 |
|
|
return; |
2231 |
|
|
|
2232 |
|
|
bad: |
2233 |
|
|
log_debug("bad OSC 104: %s", p); |
2234 |
|
|
free(copy); |
2235 |
|
|
} |