Allow attach-session -t to accept a window and pane to select them on
[tmux-openbsd.git] / input.c
blobe27250edb41890ef33a3361fedc313b27a0035f3
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
21 #include <stdlib.h>
22 #include <string.h>
24 #include "tmux.h"
27 * Based on the description by Paul Williams at:
29 * http://vt100.net/emu/dec_ansi_parser
31 * With the following changes:
33 * - 7-bit only.
35 * - Support for UTF-8.
37 * - OSC (but not APC) may be terminated by \007 as well as ST.
39 * - A state for APC similar to OSC. Some terminals appear to use this to set
40 * the title.
42 * - A state for the screen \033k...\033\\ sequence to rename a window. This is
43 * pretty stupid but not supporting it is more trouble than it is worth.
45 * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to
46 * be passed to the underlying teminal(s).
49 /* Helper functions. */
50 struct input_transition;
51 int input_split(struct input_ctx *);
52 int input_get(struct input_ctx *, u_int, int, int);
53 void input_reply(struct input_ctx *, const char *, ...);
54 void input_set_state(struct window_pane *, const struct input_transition *);
56 /* Transition entry/exit handlers. */
57 void input_clear(struct input_ctx *);
58 void input_enter_osc(struct input_ctx *);
59 void input_exit_osc(struct input_ctx *);
60 void input_enter_apc(struct input_ctx *);
61 void input_exit_apc(struct input_ctx *);
62 void input_enter_rename(struct input_ctx *);
63 void input_exit_rename(struct input_ctx *);
65 /* Input state handlers. */
66 int input_print(struct input_ctx *);
67 int input_intermediate(struct input_ctx *);
68 int input_parameter(struct input_ctx *);
69 int input_input(struct input_ctx *);
70 int input_c0_dispatch(struct input_ctx *);
71 int input_esc_dispatch(struct input_ctx *);
72 int input_csi_dispatch(struct input_ctx *);
73 void input_csi_dispatch_rm(struct input_ctx *);
74 void input_csi_dispatch_rm_private(struct input_ctx *);
75 void input_csi_dispatch_sm(struct input_ctx *);
76 void input_csi_dispatch_sm_private(struct input_ctx *);
77 void input_csi_dispatch_sgr(struct input_ctx *);
78 int input_dcs_dispatch(struct input_ctx *);
79 int input_utf8_open(struct input_ctx *);
80 int input_utf8_add(struct input_ctx *);
81 int input_utf8_close(struct input_ctx *);
83 /* Command table comparison function. */
84 int input_table_compare(const void *, const void *);
86 /* Command table entry. */
87 struct input_table_entry {
88 int ch;
89 const char *interm;
90 int type;
93 /* Escape commands. */
94 enum input_esc_type {
95 INPUT_ESC_DECALN,
96 INPUT_ESC_DECKPAM,
97 INPUT_ESC_DECKPNM,
98 INPUT_ESC_DECRC,
99 INPUT_ESC_DECSC,
100 INPUT_ESC_HTS,
101 INPUT_ESC_IND,
102 INPUT_ESC_NEL,
103 INPUT_ESC_RI,
104 INPUT_ESC_RIS,
105 INPUT_ESC_SCSOFF_G0,
106 INPUT_ESC_SCSON_G0,
109 /* Escape command table. */
110 const struct input_table_entry input_esc_table[] = {
111 { '0', "(", INPUT_ESC_SCSOFF_G0 },
112 { '7', "", INPUT_ESC_DECSC },
113 { '8', "", INPUT_ESC_DECRC },
114 { '8', "#", INPUT_ESC_DECALN },
115 { '=', "", INPUT_ESC_DECKPAM },
116 { '>', "", INPUT_ESC_DECKPNM },
117 { 'B', "(", INPUT_ESC_SCSON_G0 },
118 { 'D', "", INPUT_ESC_IND },
119 { 'E', "", INPUT_ESC_NEL },
120 { 'H', "", INPUT_ESC_HTS },
121 { 'M', "", INPUT_ESC_RI },
122 { 'c', "", INPUT_ESC_RIS },
125 /* Control (CSI) commands. */
126 enum input_csi_type {
127 INPUT_CSI_CBT,
128 INPUT_CSI_CNL,
129 INPUT_CSI_CPL,
130 INPUT_CSI_CUB,
131 INPUT_CSI_CUD,
132 INPUT_CSI_CUF,
133 INPUT_CSI_CUP,
134 INPUT_CSI_CUU,
135 INPUT_CSI_DA,
136 INPUT_CSI_DA_TWO,
137 INPUT_CSI_DCH,
138 INPUT_CSI_DECSCUSR,
139 INPUT_CSI_DECSTBM,
140 INPUT_CSI_DL,
141 INPUT_CSI_DSR,
142 INPUT_CSI_ECH,
143 INPUT_CSI_ED,
144 INPUT_CSI_EL,
145 INPUT_CSI_HPA,
146 INPUT_CSI_ICH,
147 INPUT_CSI_IL,
148 INPUT_CSI_RCP,
149 INPUT_CSI_RM,
150 INPUT_CSI_RM_PRIVATE,
151 INPUT_CSI_SCP,
152 INPUT_CSI_SGR,
153 INPUT_CSI_SM,
154 INPUT_CSI_SM_PRIVATE,
155 INPUT_CSI_TBC,
156 INPUT_CSI_VPA,
159 /* Control (CSI) command table. */
160 const struct input_table_entry input_csi_table[] = {
161 { '@', "", INPUT_CSI_ICH },
162 { 'A', "", INPUT_CSI_CUU },
163 { 'B', "", INPUT_CSI_CUD },
164 { 'C', "", INPUT_CSI_CUF },
165 { 'D', "", INPUT_CSI_CUB },
166 { 'E', "", INPUT_CSI_CNL },
167 { 'F', "", INPUT_CSI_CPL },
168 { 'G', "", INPUT_CSI_HPA },
169 { 'H', "", INPUT_CSI_CUP },
170 { 'J', "", INPUT_CSI_ED },
171 { 'K', "", INPUT_CSI_EL },
172 { 'L', "", INPUT_CSI_IL },
173 { 'M', "", INPUT_CSI_DL },
174 { 'P', "", INPUT_CSI_DCH },
175 { 'X', "", INPUT_CSI_ECH },
176 { 'Z', "", INPUT_CSI_CBT },
177 { 'c', "", INPUT_CSI_DA },
178 { 'c', ">", INPUT_CSI_DA_TWO },
179 { 'd', "", INPUT_CSI_VPA },
180 { 'f', "", INPUT_CSI_CUP },
181 { 'g', "", INPUT_CSI_TBC },
182 { 'h', "", INPUT_CSI_SM },
183 { 'h', "?", INPUT_CSI_SM_PRIVATE },
184 { 'l', "", INPUT_CSI_RM },
185 { 'l', "?", INPUT_CSI_RM_PRIVATE },
186 { 'm', "", INPUT_CSI_SGR },
187 { 'n', "", INPUT_CSI_DSR },
188 { 'q', " ", INPUT_CSI_DECSCUSR },
189 { 'r', "", INPUT_CSI_DECSTBM },
190 { 's', "", INPUT_CSI_SCP },
191 { 'u', "", INPUT_CSI_RCP },
194 /* Input transition. */
195 struct input_transition {
196 int first;
197 int last;
199 int (*handler)(struct input_ctx *);
200 const struct input_state *state;
203 /* Input state. */
204 struct input_state {
205 const char *name;
206 void (*enter)(struct input_ctx *);
207 void (*exit)(struct input_ctx *);
208 const struct input_transition *transitions;
211 /* State transitions available from all states. */
212 #define INPUT_STATE_ANYWHERE \
213 { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
214 { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
215 { 0x1b, 0x1b, NULL, &input_state_esc_enter }
217 /* Forward declarations of state tables. */
218 const struct input_transition input_state_ground_table[];
219 const struct input_transition input_state_esc_enter_table[];
220 const struct input_transition input_state_esc_intermediate_table[];
221 const struct input_transition input_state_csi_enter_table[];
222 const struct input_transition input_state_csi_parameter_table[];
223 const struct input_transition input_state_csi_intermediate_table[];
224 const struct input_transition input_state_csi_ignore_table[];
225 const struct input_transition input_state_dcs_enter_table[];
226 const struct input_transition input_state_dcs_parameter_table[];
227 const struct input_transition input_state_dcs_intermediate_table[];
228 const struct input_transition input_state_dcs_handler_table[];
229 const struct input_transition input_state_dcs_escape_table[];
230 const struct input_transition input_state_dcs_ignore_table[];
231 const struct input_transition input_state_osc_string_table[];
232 const struct input_transition input_state_apc_string_table[];
233 const struct input_transition input_state_rename_string_table[];
234 const struct input_transition input_state_consume_st_table[];
235 const struct input_transition input_state_utf8_three_table[];
236 const struct input_transition input_state_utf8_two_table[];
237 const struct input_transition input_state_utf8_one_table[];
239 /* ground state definition. */
240 const struct input_state input_state_ground = {
241 "ground",
242 NULL, NULL,
243 input_state_ground_table
246 /* esc_enter state definition. */
247 const struct input_state input_state_esc_enter = {
248 "esc_enter",
249 input_clear, NULL,
250 input_state_esc_enter_table
253 /* esc_intermediate state definition. */
254 const struct input_state input_state_esc_intermediate = {
255 "esc_intermediate",
256 NULL, NULL,
257 input_state_esc_intermediate_table
260 /* csi_enter state definition. */
261 const struct input_state input_state_csi_enter = {
262 "csi_enter",
263 input_clear, NULL,
264 input_state_csi_enter_table
267 /* csi_parameter state definition. */
268 const struct input_state input_state_csi_parameter = {
269 "csi_parameter",
270 NULL, NULL,
271 input_state_csi_parameter_table
274 /* csi_intermediate state definition. */
275 const struct input_state input_state_csi_intermediate = {
276 "csi_intermediate",
277 NULL, NULL,
278 input_state_csi_intermediate_table
281 /* csi_ignore state definition. */
282 const struct input_state input_state_csi_ignore = {
283 "csi_ignore",
284 NULL, NULL,
285 input_state_csi_ignore_table
288 /* dcs_enter state definition. */
289 const struct input_state input_state_dcs_enter = {
290 "dcs_enter",
291 input_clear, NULL,
292 input_state_dcs_enter_table
295 /* dcs_parameter state definition. */
296 const struct input_state input_state_dcs_parameter = {
297 "dcs_parameter",
298 NULL, NULL,
299 input_state_dcs_parameter_table
302 /* dcs_intermediate state definition. */
303 const struct input_state input_state_dcs_intermediate = {
304 "dcs_intermediate",
305 NULL, NULL,
306 input_state_dcs_intermediate_table
309 /* dcs_handler state definition. */
310 const struct input_state input_state_dcs_handler = {
311 "dcs_handler",
312 NULL, NULL,
313 input_state_dcs_handler_table
316 /* dcs_escape state definition. */
317 const struct input_state input_state_dcs_escape = {
318 "dcs_escape",
319 NULL, NULL,
320 input_state_dcs_escape_table
323 /* dcs_ignore state definition. */
324 const struct input_state input_state_dcs_ignore = {
325 "dcs_ignore",
326 NULL, NULL,
327 input_state_dcs_ignore_table
330 /* osc_string state definition. */
331 const struct input_state input_state_osc_string = {
332 "osc_string",
333 input_enter_osc, input_exit_osc,
334 input_state_osc_string_table
337 /* apc_string state definition. */
338 const struct input_state input_state_apc_string = {
339 "apc_string",
340 input_enter_apc, input_exit_apc,
341 input_state_apc_string_table
344 /* rename_string state definition. */
345 const struct input_state input_state_rename_string = {
346 "rename_string",
347 input_enter_rename, input_exit_rename,
348 input_state_rename_string_table
351 /* consume_st state definition. */
352 const struct input_state input_state_consume_st = {
353 "consume_st",
354 NULL, NULL,
355 input_state_consume_st_table
358 /* utf8_three state definition. */
359 const struct input_state input_state_utf8_three = {
360 "utf8_three",
361 NULL, NULL,
362 input_state_utf8_three_table
365 /* utf8_two state definition. */
366 const struct input_state input_state_utf8_two = {
367 "utf8_two",
368 NULL, NULL,
369 input_state_utf8_two_table
372 /* utf8_one state definition. */
373 const struct input_state input_state_utf8_one = {
374 "utf8_one",
375 NULL, NULL,
376 input_state_utf8_one_table
379 /* ground state table. */
380 const struct input_transition input_state_ground_table[] = {
381 INPUT_STATE_ANYWHERE,
383 { 0x00, 0x17, input_c0_dispatch, NULL },
384 { 0x19, 0x19, input_c0_dispatch, NULL },
385 { 0x1c, 0x1f, input_c0_dispatch, NULL },
386 { 0x20, 0x7e, input_print, NULL },
387 { 0x7f, 0x7f, NULL, NULL },
388 { 0x80, 0xc1, input_print, NULL },
389 { 0xc2, 0xdf, input_utf8_open, &input_state_utf8_one },
390 { 0xe0, 0xef, input_utf8_open, &input_state_utf8_two },
391 { 0xf0, 0xf4, input_utf8_open, &input_state_utf8_three },
392 { 0xf5, 0xff, input_print, NULL },
394 { -1, -1, NULL, NULL }
397 /* esc_enter state table. */
398 const struct input_transition input_state_esc_enter_table[] = {
399 INPUT_STATE_ANYWHERE,
401 { 0x00, 0x17, input_c0_dispatch, NULL },
402 { 0x19, 0x19, input_c0_dispatch, NULL },
403 { 0x1c, 0x1f, input_c0_dispatch, NULL },
404 { 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate },
405 { 0x30, 0x4f, input_esc_dispatch, &input_state_ground },
406 { 0x50, 0x50, NULL, &input_state_dcs_enter },
407 { 0x51, 0x57, input_esc_dispatch, &input_state_ground },
408 { 0x58, 0x58, NULL, &input_state_consume_st },
409 { 0x59, 0x59, input_esc_dispatch, &input_state_ground },
410 { 0x5a, 0x5a, input_esc_dispatch, &input_state_ground },
411 { 0x5b, 0x5b, NULL, &input_state_csi_enter },
412 { 0x5c, 0x5c, input_esc_dispatch, &input_state_ground },
413 { 0x5d, 0x5d, NULL, &input_state_osc_string },
414 { 0x5e, 0x5e, NULL, &input_state_consume_st },
415 { 0x5f, 0x5f, NULL, &input_state_apc_string },
416 { 0x60, 0x6a, input_esc_dispatch, &input_state_ground },
417 { 0x6b, 0x6b, NULL, &input_state_rename_string },
418 { 0x6c, 0x7e, input_esc_dispatch, &input_state_ground },
419 { 0x7f, 0xff, NULL, NULL },
421 { -1, -1, NULL, NULL }
424 /* esc_interm state table. */
425 const struct input_transition input_state_esc_intermediate_table[] = {
426 INPUT_STATE_ANYWHERE,
428 { 0x00, 0x17, input_c0_dispatch, NULL },
429 { 0x19, 0x19, input_c0_dispatch, NULL },
430 { 0x1c, 0x1f, input_c0_dispatch, NULL },
431 { 0x20, 0x2f, input_intermediate, NULL },
432 { 0x30, 0x7e, input_esc_dispatch, &input_state_ground },
433 { 0x7f, 0xff, NULL, NULL },
435 { -1, -1, NULL, NULL }
438 /* csi_enter state table. */
439 const struct input_transition input_state_csi_enter_table[] = {
440 INPUT_STATE_ANYWHERE,
442 { 0x00, 0x17, input_c0_dispatch, NULL },
443 { 0x19, 0x19, input_c0_dispatch, NULL },
444 { 0x1c, 0x1f, input_c0_dispatch, NULL },
445 { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
446 { 0x30, 0x39, input_parameter, &input_state_csi_parameter },
447 { 0x3a, 0x3a, NULL, &input_state_csi_ignore },
448 { 0x3b, 0x3b, input_parameter, &input_state_csi_parameter },
449 { 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter },
450 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
451 { 0x7f, 0xff, NULL, NULL },
453 { -1, -1, NULL, NULL }
456 /* csi_parameter state table. */
457 const struct input_transition input_state_csi_parameter_table[] = {
458 INPUT_STATE_ANYWHERE,
460 { 0x00, 0x17, input_c0_dispatch, NULL },
461 { 0x19, 0x19, input_c0_dispatch, NULL },
462 { 0x1c, 0x1f, input_c0_dispatch, NULL },
463 { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
464 { 0x30, 0x39, input_parameter, NULL },
465 { 0x3a, 0x3a, NULL, &input_state_csi_ignore },
466 { 0x3b, 0x3b, input_parameter, NULL },
467 { 0x3c, 0x3f, NULL, &input_state_csi_ignore },
468 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
469 { 0x7f, 0xff, NULL, NULL },
471 { -1, -1, NULL, NULL }
474 /* csi_intermediate state table. */
475 const struct input_transition input_state_csi_intermediate_table[] = {
476 INPUT_STATE_ANYWHERE,
478 { 0x00, 0x17, input_c0_dispatch, NULL },
479 { 0x19, 0x19, input_c0_dispatch, NULL },
480 { 0x1c, 0x1f, input_c0_dispatch, NULL },
481 { 0x20, 0x2f, input_intermediate, NULL },
482 { 0x30, 0x3f, NULL, &input_state_csi_ignore },
483 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
484 { 0x7f, 0xff, NULL, NULL },
486 { -1, -1, NULL, NULL }
489 /* csi_ignore state table. */
490 const struct input_transition input_state_csi_ignore_table[] = {
491 INPUT_STATE_ANYWHERE,
493 { 0x00, 0x17, input_c0_dispatch, NULL },
494 { 0x19, 0x19, input_c0_dispatch, NULL },
495 { 0x1c, 0x1f, input_c0_dispatch, NULL },
496 { 0x20, 0x3f, NULL, NULL },
497 { 0x40, 0x7e, NULL, &input_state_ground },
498 { 0x7f, 0xff, NULL, NULL },
500 { -1, -1, NULL, NULL }
503 /* dcs_enter state table. */
504 const struct input_transition input_state_dcs_enter_table[] = {
505 INPUT_STATE_ANYWHERE,
507 { 0x00, 0x17, NULL, NULL },
508 { 0x19, 0x19, NULL, NULL },
509 { 0x1c, 0x1f, NULL, NULL },
510 { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
511 { 0x30, 0x39, input_parameter, &input_state_dcs_parameter },
512 { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
513 { 0x3b, 0x3b, input_parameter, &input_state_dcs_parameter },
514 { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter },
515 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
516 { 0x7f, 0xff, NULL, NULL },
518 { -1, -1, NULL, NULL }
521 /* dcs_parameter state table. */
522 const struct input_transition input_state_dcs_parameter_table[] = {
523 INPUT_STATE_ANYWHERE,
525 { 0x00, 0x17, NULL, NULL },
526 { 0x19, 0x19, NULL, NULL },
527 { 0x1c, 0x1f, NULL, NULL },
528 { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
529 { 0x30, 0x39, input_parameter, NULL },
530 { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
531 { 0x3b, 0x3b, input_parameter, NULL },
532 { 0x3c, 0x3f, NULL, &input_state_dcs_ignore },
533 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
534 { 0x7f, 0xff, NULL, NULL },
536 { -1, -1, NULL, NULL }
539 /* dcs_interm state table. */
540 const struct input_transition input_state_dcs_intermediate_table[] = {
541 INPUT_STATE_ANYWHERE,
543 { 0x00, 0x17, NULL, NULL },
544 { 0x19, 0x19, NULL, NULL },
545 { 0x1c, 0x1f, NULL, NULL },
546 { 0x20, 0x2f, input_intermediate, NULL },
547 { 0x30, 0x3f, NULL, &input_state_dcs_ignore },
548 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
549 { 0x7f, 0xff, NULL, NULL },
551 { -1, -1, NULL, NULL }
554 /* dcs_handler state table. */
555 const struct input_transition input_state_dcs_handler_table[] = {
556 /* No INPUT_STATE_ANYWHERE */
558 { 0x00, 0x1a, input_input, NULL },
559 { 0x1b, 0x1b, NULL, &input_state_dcs_escape },
560 { 0x1c, 0xff, input_input, NULL },
562 { -1, -1, NULL, NULL }
565 /* dcs_escape state table. */
566 const struct input_transition input_state_dcs_escape_table[] = {
567 /* No INPUT_STATE_ANYWHERE */
569 { 0x00, 0x5b, input_input, &input_state_dcs_handler },
570 { 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground },
571 { 0x5d, 0xff, input_input, &input_state_dcs_handler },
573 { -1, -1, NULL, NULL }
576 /* dcs_ignore state table. */
577 const struct input_transition input_state_dcs_ignore_table[] = {
578 INPUT_STATE_ANYWHERE,
580 { 0x00, 0x17, NULL, NULL },
581 { 0x19, 0x19, NULL, NULL },
582 { 0x1c, 0x1f, NULL, NULL },
583 { 0x20, 0xff, NULL, NULL },
585 { -1, -1, NULL, NULL }
588 /* osc_string state table. */
589 const struct input_transition input_state_osc_string_table[] = {
590 INPUT_STATE_ANYWHERE,
592 { 0x00, 0x06, NULL, NULL },
593 { 0x07, 0x07, NULL, &input_state_ground },
594 { 0x08, 0x17, NULL, NULL },
595 { 0x19, 0x19, NULL, NULL },
596 { 0x1c, 0x1f, NULL, NULL },
597 { 0x20, 0xff, input_input, NULL },
599 { -1, -1, NULL, NULL }
602 /* apc_string state table. */
603 const struct input_transition input_state_apc_string_table[] = {
604 INPUT_STATE_ANYWHERE,
606 { 0x00, 0x17, NULL, NULL },
607 { 0x19, 0x19, NULL, NULL },
608 { 0x1c, 0x1f, NULL, NULL },
609 { 0x20, 0xff, input_input, NULL },
611 { -1, -1, NULL, NULL }
614 /* rename_string state table. */
615 const struct input_transition input_state_rename_string_table[] = {
616 INPUT_STATE_ANYWHERE,
618 { 0x00, 0x17, NULL, NULL },
619 { 0x19, 0x19, NULL, NULL },
620 { 0x1c, 0x1f, NULL, NULL },
621 { 0x20, 0xff, input_input, NULL },
623 { -1, -1, NULL, NULL }
626 /* consume_st state table. */
627 const struct input_transition input_state_consume_st_table[] = {
628 INPUT_STATE_ANYWHERE,
630 { 0x00, 0x17, NULL, NULL },
631 { 0x19, 0x19, NULL, NULL },
632 { 0x1c, 0x1f, NULL, NULL },
633 { 0x20, 0xff, NULL, NULL },
635 { -1, -1, NULL, NULL }
638 /* utf8_three state table. */
639 const struct input_transition input_state_utf8_three_table[] = {
640 /* No INPUT_STATE_ANYWHERE */
642 { 0x00, 0x7f, NULL, &input_state_ground },
643 { 0x80, 0xbf, input_utf8_add, &input_state_utf8_two },
644 { 0xc0, 0xff, NULL, &input_state_ground },
646 { -1, -1, NULL, NULL }
649 /* utf8_two state table. */
650 const struct input_transition input_state_utf8_two_table[] = {
651 /* No INPUT_STATE_ANYWHERE */
653 { 0x00, 0x7f, NULL, &input_state_ground },
654 { 0x80, 0xbf, input_utf8_add, &input_state_utf8_one },
655 { 0xc0, 0xff, NULL, &input_state_ground },
657 { -1, -1, NULL, NULL }
660 /* utf8_one state table. */
661 const struct input_transition input_state_utf8_one_table[] = {
662 /* No INPUT_STATE_ANYWHERE */
664 { 0x00, 0x7f, NULL, &input_state_ground },
665 { 0x80, 0xbf, input_utf8_close, &input_state_ground },
666 { 0xc0, 0xff, NULL, &input_state_ground },
668 { -1, -1, NULL, NULL }
671 /* Input table compare. */
673 input_table_compare(const void *key, const void *value)
675 const struct input_ctx *ictx = key;
676 const struct input_table_entry *entry = value;
678 if (ictx->ch != entry->ch)
679 return (ictx->ch - entry->ch);
680 return (strcmp(ictx->interm_buf, entry->interm));
683 /* Initialise input parser. */
684 void
685 input_init(struct window_pane *wp)
687 struct input_ctx *ictx = &wp->ictx;
689 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
691 memcpy(&ictx->old_cell, &grid_default_cell, sizeof ictx->old_cell);
692 ictx->old_cx = 0;
693 ictx->old_cy = 0;
695 *ictx->interm_buf = '\0';
696 ictx->interm_len = 0;
698 *ictx->param_buf = '\0';
699 ictx->param_len = 0;
701 ictx->state = &input_state_ground;
702 ictx->flags = 0;
704 ictx->since_ground = evbuffer_new();
707 /* Destroy input parser. */
708 void
709 input_free(struct window_pane *wp)
711 if (wp != NULL)
712 evbuffer_free(wp->ictx.since_ground);
715 /* Change input state. */
716 void
717 input_set_state(struct window_pane *wp, const struct input_transition *itr)
719 struct input_ctx *ictx = &wp->ictx;
720 struct evbuffer *ground_evb = ictx->since_ground;
722 if (ictx->state->exit != NULL)
723 ictx->state->exit(ictx);
725 if (itr->state == &input_state_ground)
726 evbuffer_drain(ground_evb, EVBUFFER_LENGTH(ground_evb));
728 ictx->state = itr->state;
729 if (ictx->state->enter != NULL)
730 ictx->state->enter(ictx);
733 /* Parse input. */
734 void
735 input_parse(struct window_pane *wp)
737 struct input_ctx *ictx = &wp->ictx;
738 const struct input_transition *itr;
739 struct evbuffer *evb = wp->event->input;
740 u_char *buf;
741 size_t len, off;
743 if (EVBUFFER_LENGTH(evb) == 0)
744 return;
746 wp->window->flags |= WINDOW_ACTIVITY;
747 wp->window->flags &= ~WINDOW_SILENCE;
750 * Open the screen. Use NULL wp if there is a mode set as don't want to
751 * update the tty.
753 if (wp->mode == NULL)
754 screen_write_start(&ictx->ctx, wp, &wp->base);
755 else
756 screen_write_start(&ictx->ctx, NULL, &wp->base);
757 ictx->wp = wp;
759 buf = EVBUFFER_DATA(evb);
760 len = EVBUFFER_LENGTH(evb);
761 notify_input(wp, evb);
762 off = 0;
764 /* Parse the input. */
765 while (off < len) {
766 ictx->ch = buf[off++];
767 log_debug("%s: '%c' %s", __func__, ictx->ch, ictx->state->name);
769 /* Find the transition. */
770 itr = ictx->state->transitions;
771 while (itr->first != -1 && itr->last != -1) {
772 if (ictx->ch >= itr->first && ictx->ch <= itr->last)
773 break;
774 itr++;
776 if (itr->first == -1 || itr->last == -1) {
777 /* No transition? Eh? */
778 fatalx("No transition from state!");
782 * Execute the handler, if any. Don't switch state if it
783 * returns non-zero.
785 if (itr->handler != NULL && itr->handler(ictx) != 0)
786 continue;
788 /* And switch state, if necessary. */
789 if (itr->state != NULL)
790 input_set_state(wp, itr);
792 /* If not in ground state, save input. */
793 if (ictx->state != &input_state_ground)
794 evbuffer_add(ictx->since_ground, &ictx->ch, 1);
797 /* Close the screen. */
798 screen_write_stop(&ictx->ctx);
800 evbuffer_drain(evb, len);
803 /* Split the parameter list (if any). */
805 input_split(struct input_ctx *ictx)
808 const char *errstr;
809 char *ptr, *out;
810 int n;
812 ictx->param_list_len = 0;
813 if (ictx->param_len == 0)
814 return (0);
816 ptr = ictx->param_buf;
817 while ((out = strsep(&ptr, ";")) != NULL) {
818 if (*out == '\0')
819 n = -1;
820 else {
821 n = strtonum(out, 0, INT_MAX, &errstr);
822 if (errstr != NULL)
823 return (-1);
826 ictx->param_list[ictx->param_list_len++] = n;
827 if (ictx->param_list_len == nitems(ictx->param_list))
828 return (-1);
831 return (0);
834 /* Get an argument or return default value. */
836 input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
838 int retval;
840 if (validx >= ictx->param_list_len)
841 return (defval);
843 retval = ictx->param_list[validx];
844 if (retval == -1)
845 return (defval);
846 if (retval < minval)
847 return (minval);
848 return (retval);
851 /* Reply to terminal query. */
852 void
853 input_reply(struct input_ctx *ictx, const char *fmt, ...)
855 va_list ap;
856 char *reply;
858 va_start(ap, fmt);
859 vasprintf(&reply, fmt, ap);
860 va_end(ap);
862 bufferevent_write(ictx->wp->event, reply, strlen(reply));
863 free(reply);
866 /* Clear saved state. */
867 void
868 input_clear(struct input_ctx *ictx)
870 *ictx->interm_buf = '\0';
871 ictx->interm_len = 0;
873 *ictx->param_buf = '\0';
874 ictx->param_len = 0;
876 *ictx->input_buf = '\0';
877 ictx->input_len = 0;
879 ictx->flags &= ~INPUT_DISCARD;
882 /* Output this character to the screen. */
884 input_print(struct input_ctx *ictx)
886 grid_cell_one(&ictx->cell, ictx->ch);
887 screen_write_cell(&ictx->ctx, &ictx->cell);
889 return (0);
892 /* Collect intermediate string. */
894 input_intermediate(struct input_ctx *ictx)
896 if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
897 ictx->flags |= INPUT_DISCARD;
898 else {
899 ictx->interm_buf[ictx->interm_len++] = ictx->ch;
900 ictx->interm_buf[ictx->interm_len] = '\0';
903 return (0);
906 /* Collect parameter string. */
908 input_parameter(struct input_ctx *ictx)
910 if (ictx->param_len == (sizeof ictx->param_buf) - 1)
911 ictx->flags |= INPUT_DISCARD;
912 else {
913 ictx->param_buf[ictx->param_len++] = ictx->ch;
914 ictx->param_buf[ictx->param_len] = '\0';
917 return (0);
920 /* Collect input string. */
922 input_input(struct input_ctx *ictx)
924 if (ictx->input_len == (sizeof ictx->input_buf) - 1)
925 ictx->flags |= INPUT_DISCARD;
926 else {
927 ictx->input_buf[ictx->input_len++] = ictx->ch;
928 ictx->input_buf[ictx->input_len] = '\0';
931 return (0);
934 /* Execute C0 control sequence. */
936 input_c0_dispatch(struct input_ctx *ictx)
938 struct screen_write_ctx *sctx = &ictx->ctx;
939 struct window_pane *wp = ictx->wp;
940 struct screen *s = sctx->s;
941 u_int trigger;
943 log_debug("%s: '%c", __func__, ictx->ch);
945 switch (ictx->ch) {
946 case '\000': /* NUL */
947 break;
948 case '\007': /* BEL */
949 wp->window->flags |= WINDOW_BELL;
950 break;
951 case '\010': /* BS */
952 screen_write_backspace(sctx);
953 goto count_c0;
954 case '\011': /* HT */
955 /* Don't tab beyond the end of the line. */
956 if (s->cx >= screen_size_x(s) - 1)
957 break;
959 /* Find the next tab point, or use the last column if none. */
960 do {
961 s->cx++;
962 if (bit_test(s->tabs, s->cx))
963 break;
964 } while (s->cx < screen_size_x(s) - 1);
965 break;
966 case '\012': /* LF */
967 case '\013': /* VT */
968 case '\014': /* FF */
969 screen_write_linefeed(sctx, 0);
970 goto count_c0;
971 case '\015': /* CR */
972 screen_write_carriagereturn(sctx);
973 goto count_c0;
974 case '\016': /* SO */
975 ictx->cell.attr |= GRID_ATTR_CHARSET;
976 break;
977 case '\017': /* SI */
978 ictx->cell.attr &= ~GRID_ATTR_CHARSET;
979 break;
980 default:
981 log_debug("%s: unknown '%c'", __func__, ictx->ch);
982 break;
985 return (0);
987 count_c0:
988 trigger = options_get_number(&wp->window->options, "c0-change-trigger");
989 if (++wp->changes == trigger) {
990 wp->flags |= PANE_DROP;
991 window_pane_timer_start(wp);
994 return (0);
997 /* Execute escape sequence. */
999 input_esc_dispatch(struct input_ctx *ictx)
1001 struct screen_write_ctx *sctx = &ictx->ctx;
1002 struct screen *s = sctx->s;
1003 struct input_table_entry *entry;
1005 if (ictx->flags & INPUT_DISCARD)
1006 return (0);
1007 log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
1009 entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
1010 sizeof input_esc_table[0], input_table_compare);
1011 if (entry == NULL) {
1012 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1013 return (0);
1016 switch (entry->type) {
1017 case INPUT_ESC_RIS:
1018 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
1019 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1020 ictx->old_cx = 0;
1021 ictx->old_cy = 0;
1023 screen_write_reset(sctx);
1024 break;
1025 case INPUT_ESC_IND:
1026 screen_write_linefeed(sctx, 0);
1027 break;
1028 case INPUT_ESC_NEL:
1029 screen_write_carriagereturn(sctx);
1030 screen_write_linefeed(sctx, 0);
1031 break;
1032 case INPUT_ESC_HTS:
1033 if (s->cx < screen_size_x(s))
1034 bit_set(s->tabs, s->cx);
1035 break;
1036 case INPUT_ESC_RI:
1037 screen_write_reverseindex(sctx);
1038 break;
1039 case INPUT_ESC_DECKPAM:
1040 screen_write_mode_set(sctx, MODE_KKEYPAD);
1041 break;
1042 case INPUT_ESC_DECKPNM:
1043 screen_write_mode_clear(sctx, MODE_KKEYPAD);
1044 break;
1045 case INPUT_ESC_DECSC:
1046 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1047 ictx->old_cx = s->cx;
1048 ictx->old_cy = s->cy;
1049 break;
1050 case INPUT_ESC_DECRC:
1051 memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
1052 screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
1053 break;
1054 case INPUT_ESC_DECALN:
1055 screen_write_alignmenttest(sctx);
1056 break;
1057 case INPUT_ESC_SCSON_G0:
1059 * Not really supported, but fake it up enough for those that
1060 * use it to switch character sets (by redefining G0 to
1061 * graphics set, rather than switching to G1).
1063 ictx->cell.attr &= ~GRID_ATTR_CHARSET;
1064 break;
1065 case INPUT_ESC_SCSOFF_G0:
1066 ictx->cell.attr |= GRID_ATTR_CHARSET;
1067 break;
1070 return (0);
1073 /* Execute control sequence. */
1075 input_csi_dispatch(struct input_ctx *ictx)
1077 struct screen_write_ctx *sctx = &ictx->ctx;
1078 struct screen *s = sctx->s;
1079 struct input_table_entry *entry;
1080 int n, m;
1082 if (ictx->flags & INPUT_DISCARD)
1083 return (0);
1084 if (input_split(ictx) != 0)
1085 return (0);
1086 log_debug("%s: '%c' \"%s\" \"%s\"",
1087 __func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
1089 entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
1090 sizeof input_csi_table[0], input_table_compare);
1091 if (entry == NULL) {
1092 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1093 return (0);
1096 switch (entry->type) {
1097 case INPUT_CSI_CBT:
1098 /* Find the previous tab point, n times. */
1099 n = input_get(ictx, 0, 1, 1);
1100 while (s->cx > 0 && n-- > 0) {
1102 s->cx--;
1103 while (s->cx > 0 && !bit_test(s->tabs, s->cx));
1105 break;
1106 case INPUT_CSI_CUB:
1107 screen_write_cursorleft(sctx, input_get(ictx, 0, 1, 1));
1108 break;
1109 case INPUT_CSI_CUD:
1110 screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
1111 break;
1112 case INPUT_CSI_CUF:
1113 screen_write_cursorright(sctx, input_get(ictx, 0, 1, 1));
1114 break;
1115 case INPUT_CSI_CUP:
1116 n = input_get(ictx, 0, 1, 1);
1117 m = input_get(ictx, 1, 1, 1);
1118 screen_write_cursormove(sctx, m - 1, n - 1);
1119 break;
1120 case INPUT_CSI_CUU:
1121 screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
1122 break;
1123 case INPUT_CSI_CNL:
1124 screen_write_carriagereturn(sctx);
1125 screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
1126 break;
1127 case INPUT_CSI_CPL:
1128 screen_write_carriagereturn(sctx);
1129 screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
1130 break;
1131 case INPUT_CSI_DA:
1132 switch (input_get(ictx, 0, 0, 0)) {
1133 case 0:
1134 input_reply(ictx, "\033[?1;2c");
1135 break;
1136 default:
1137 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1138 break;
1140 break;
1141 case INPUT_CSI_DA_TWO:
1142 switch (input_get(ictx, 0, 0, 0)) {
1143 case 0:
1144 input_reply(ictx, "\033[>0;95;0c");
1145 break;
1146 default:
1147 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1148 break;
1150 break;
1151 case INPUT_CSI_ECH:
1152 screen_write_clearcharacter(sctx, input_get(ictx, 0, 1, 1));
1153 break;
1154 case INPUT_CSI_DCH:
1155 screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1));
1156 break;
1157 case INPUT_CSI_DECSTBM:
1158 n = input_get(ictx, 0, 1, 1);
1159 m = input_get(ictx, 1, 1, screen_size_y(s));
1160 screen_write_scrollregion(sctx, n - 1, m - 1);
1161 break;
1162 case INPUT_CSI_DL:
1163 screen_write_deleteline(sctx, input_get(ictx, 0, 1, 1));
1164 break;
1165 case INPUT_CSI_DSR:
1166 switch (input_get(ictx, 0, 0, 0)) {
1167 case 5:
1168 input_reply(ictx, "\033[0n");
1169 break;
1170 case 6:
1171 input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
1172 break;
1173 default:
1174 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1175 break;
1177 break;
1178 case INPUT_CSI_ED:
1179 switch (input_get(ictx, 0, 0, 0)) {
1180 case 0:
1181 screen_write_clearendofscreen(sctx);
1182 break;
1183 case 1:
1184 screen_write_clearstartofscreen(sctx);
1185 break;
1186 case 2:
1187 screen_write_clearscreen(sctx);
1188 break;
1189 case 3:
1190 switch (input_get(ictx, 1, 0, 0)) {
1191 case 0:
1193 * Linux console extension to clear history
1194 * (for example before locking the screen).
1196 screen_write_clearhistory(sctx);
1197 break;
1199 break;
1200 default:
1201 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1202 break;
1204 break;
1205 case INPUT_CSI_EL:
1206 switch (input_get(ictx, 0, 0, 0)) {
1207 case 0:
1208 screen_write_clearendofline(sctx);
1209 break;
1210 case 1:
1211 screen_write_clearstartofline(sctx);
1212 break;
1213 case 2:
1214 screen_write_clearline(sctx);
1215 break;
1216 default:
1217 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1218 break;
1220 break;
1221 case INPUT_CSI_HPA:
1222 n = input_get(ictx, 0, 1, 1);
1223 screen_write_cursormove(sctx, n - 1, s->cy);
1224 break;
1225 case INPUT_CSI_ICH:
1226 screen_write_insertcharacter(sctx, input_get(ictx, 0, 1, 1));
1227 break;
1228 case INPUT_CSI_IL:
1229 screen_write_insertline(sctx, input_get(ictx, 0, 1, 1));
1230 break;
1231 case INPUT_CSI_RCP:
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_CSI_RM:
1236 input_csi_dispatch_rm(ictx);
1237 break;
1238 case INPUT_CSI_RM_PRIVATE:
1239 input_csi_dispatch_rm_private(ictx);
1240 break;
1241 case INPUT_CSI_SCP:
1242 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1243 ictx->old_cx = s->cx;
1244 ictx->old_cy = s->cy;
1245 break;
1246 case INPUT_CSI_SGR:
1247 input_csi_dispatch_sgr(ictx);
1248 break;
1249 case INPUT_CSI_SM:
1250 input_csi_dispatch_sm(ictx);
1251 break;
1252 case INPUT_CSI_SM_PRIVATE:
1253 input_csi_dispatch_sm_private(ictx);
1254 break;
1255 case INPUT_CSI_TBC:
1256 switch (input_get(ictx, 0, 0, 0)) {
1257 case 0:
1258 if (s->cx < screen_size_x(s))
1259 bit_clear(s->tabs, s->cx);
1260 break;
1261 case 3:
1262 bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1263 break;
1264 default:
1265 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1266 break;
1268 break;
1269 case INPUT_CSI_VPA:
1270 n = input_get(ictx, 0, 1, 1);
1271 screen_write_cursormove(sctx, s->cx, n - 1);
1272 break;
1273 case INPUT_CSI_DECSCUSR:
1274 n = input_get(ictx, 0, 0, 0);
1275 screen_set_cursor_style(s, n);
1276 break;
1279 return (0);
1282 /* Handle CSI RM. */
1283 void
1284 input_csi_dispatch_rm(struct input_ctx *ictx)
1286 u_int i;
1288 for (i = 0; i < ictx->param_list_len; i++) {
1289 switch (input_get(ictx, i, 0, -1)) {
1290 case 4: /* IRM */
1291 screen_write_mode_clear(&ictx->ctx, MODE_INSERT);
1292 break;
1293 default:
1294 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1295 break;
1300 /* Handle CSI private RM. */
1301 void
1302 input_csi_dispatch_rm_private(struct input_ctx *ictx)
1304 u_int i;
1306 for (i = 0; i < ictx->param_list_len; i++) {
1307 switch (input_get(ictx, i, 0, -1)) {
1308 case 1: /* DECCKM */
1309 screen_write_mode_clear(&ictx->ctx, MODE_KCURSOR);
1310 break;
1311 case 3: /* DECCOLM */
1312 screen_write_cursormove(&ictx->ctx, 0, 0);
1313 screen_write_clearscreen(&ictx->ctx);
1314 break;
1315 case 7: /* DECAWM */
1316 screen_write_mode_clear(&ictx->ctx, MODE_WRAP);
1317 break;
1318 case 25: /* TCEM */
1319 screen_write_mode_clear(&ictx->ctx, MODE_CURSOR);
1320 break;
1321 case 1000:
1322 case 1001:
1323 case 1002:
1324 case 1003:
1325 screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
1326 break;
1327 case 1004:
1328 screen_write_mode_clear(&ictx->ctx, MODE_FOCUSON);
1329 break;
1330 case 1005:
1331 screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_UTF8);
1332 break;
1333 case 1006:
1334 screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_SGR);
1335 break;
1336 case 47:
1337 case 1047:
1338 window_pane_alternate_off(ictx->wp, &ictx->cell, 0);
1339 break;
1340 case 1049:
1341 window_pane_alternate_off(ictx->wp, &ictx->cell, 1);
1342 break;
1343 case 2004:
1344 screen_write_mode_clear(&ictx->ctx, MODE_BRACKETPASTE);
1345 break;
1346 default:
1347 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1348 break;
1353 /* Handle CSI SM. */
1354 void
1355 input_csi_dispatch_sm(struct input_ctx *ictx)
1357 u_int i;
1359 for (i = 0; i < ictx->param_list_len; i++) {
1360 switch (input_get(ictx, i, 0, -1)) {
1361 case 4: /* IRM */
1362 screen_write_mode_set(&ictx->ctx, MODE_INSERT);
1363 break;
1364 default:
1365 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1366 break;
1371 /* Handle CSI private SM. */
1372 void
1373 input_csi_dispatch_sm_private(struct input_ctx *ictx)
1375 u_int i;
1377 for (i = 0; i < ictx->param_list_len; i++) {
1378 switch (input_get(ictx, i, 0, -1)) {
1379 case 1: /* DECCKM */
1380 screen_write_mode_set(&ictx->ctx, MODE_KCURSOR);
1381 break;
1382 case 3: /* DECCOLM */
1383 screen_write_cursormove(&ictx->ctx, 0, 0);
1384 screen_write_clearscreen(&ictx->ctx);
1385 break;
1386 case 7: /* DECAWM */
1387 screen_write_mode_set(&ictx->ctx, MODE_WRAP);
1388 break;
1389 case 25: /* TCEM */
1390 screen_write_mode_set(&ictx->ctx, MODE_CURSOR);
1391 break;
1392 case 1000:
1393 screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
1394 screen_write_mode_set(&ictx->ctx, MODE_MOUSE_STANDARD);
1395 break;
1396 case 1002:
1397 screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
1398 screen_write_mode_set(&ictx->ctx, MODE_MOUSE_BUTTON);
1399 break;
1400 case 1003:
1401 screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
1402 screen_write_mode_set(&ictx->ctx, MODE_MOUSE_ANY);
1403 break;
1404 case 1004:
1405 if (ictx->ctx.s->mode & MODE_FOCUSON)
1406 break;
1407 screen_write_mode_set(&ictx->ctx, MODE_FOCUSON);
1408 ictx->wp->flags |= PANE_FOCUSPUSH; /* force update */
1409 break;
1410 case 1005:
1411 screen_write_mode_set(&ictx->ctx, MODE_MOUSE_UTF8);
1412 break;
1413 case 1006:
1414 screen_write_mode_set(&ictx->ctx, MODE_MOUSE_SGR);
1415 break;
1416 case 47:
1417 case 1047:
1418 window_pane_alternate_on(ictx->wp, &ictx->cell, 0);
1419 break;
1420 case 1049:
1421 window_pane_alternate_on(ictx->wp, &ictx->cell, 1);
1422 break;
1423 case 2004:
1424 screen_write_mode_set(&ictx->ctx, MODE_BRACKETPASTE);
1425 break;
1426 default:
1427 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1428 break;
1433 /* Handle CSI SGR. */
1434 void
1435 input_csi_dispatch_sgr(struct input_ctx *ictx)
1437 struct grid_cell *gc = &ictx->cell;
1438 u_int i;
1439 int n, m;
1440 u_char attr;
1442 if (ictx->param_list_len == 0) {
1443 attr = gc->attr;
1444 memcpy(gc, &grid_default_cell, sizeof *gc);
1445 gc->attr |= (attr & GRID_ATTR_CHARSET);
1446 return;
1449 for (i = 0; i < ictx->param_list_len; i++) {
1450 n = input_get(ictx, i, 0, 0);
1452 if (n == 38 || n == 48) {
1453 i++;
1454 if (input_get(ictx, i, 0, -1) != 5)
1455 continue;
1457 i++;
1458 m = input_get(ictx, i, 0, -1);
1459 if (m == -1) {
1460 if (n == 38) {
1461 gc->flags &= ~GRID_FLAG_FG256;
1462 gc->fg = 8;
1463 } else if (n == 48) {
1464 gc->flags &= ~GRID_FLAG_BG256;
1465 gc->bg = 8;
1468 } else {
1469 if (n == 38) {
1470 gc->flags |= GRID_FLAG_FG256;
1471 gc->fg = m;
1472 } else if (n == 48) {
1473 gc->flags |= GRID_FLAG_BG256;
1474 gc->bg = m;
1477 continue;
1480 switch (n) {
1481 case 0:
1482 case 10:
1483 attr = gc->attr;
1484 memcpy(gc, &grid_default_cell, sizeof *gc);
1485 gc->attr |= (attr & GRID_ATTR_CHARSET);
1486 break;
1487 case 1:
1488 gc->attr |= GRID_ATTR_BRIGHT;
1489 break;
1490 case 2:
1491 gc->attr |= GRID_ATTR_DIM;
1492 break;
1493 case 3:
1494 gc->attr |= GRID_ATTR_ITALICS;
1495 break;
1496 case 4:
1497 gc->attr |= GRID_ATTR_UNDERSCORE;
1498 break;
1499 case 5:
1500 gc->attr |= GRID_ATTR_BLINK;
1501 break;
1502 case 7:
1503 gc->attr |= GRID_ATTR_REVERSE;
1504 break;
1505 case 8:
1506 gc->attr |= GRID_ATTR_HIDDEN;
1507 break;
1508 case 22:
1509 gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
1510 break;
1511 case 23:
1512 gc->attr &= ~GRID_ATTR_ITALICS;
1513 break;
1514 case 24:
1515 gc->attr &= ~GRID_ATTR_UNDERSCORE;
1516 break;
1517 case 25:
1518 gc->attr &= ~GRID_ATTR_BLINK;
1519 break;
1520 case 27:
1521 gc->attr &= ~GRID_ATTR_REVERSE;
1522 break;
1523 case 30:
1524 case 31:
1525 case 32:
1526 case 33:
1527 case 34:
1528 case 35:
1529 case 36:
1530 case 37:
1531 gc->flags &= ~GRID_FLAG_FG256;
1532 gc->fg = n - 30;
1533 break;
1534 case 39:
1535 gc->flags &= ~GRID_FLAG_FG256;
1536 gc->fg = 8;
1537 break;
1538 case 40:
1539 case 41:
1540 case 42:
1541 case 43:
1542 case 44:
1543 case 45:
1544 case 46:
1545 case 47:
1546 gc->flags &= ~GRID_FLAG_BG256;
1547 gc->bg = n - 40;
1548 break;
1549 case 49:
1550 gc->flags &= ~GRID_FLAG_BG256;
1551 gc->bg = 8;
1552 break;
1553 case 90:
1554 case 91:
1555 case 92:
1556 case 93:
1557 case 94:
1558 case 95:
1559 case 96:
1560 case 97:
1561 gc->flags &= ~GRID_FLAG_FG256;
1562 gc->fg = n;
1563 break;
1564 case 100:
1565 case 101:
1566 case 102:
1567 case 103:
1568 case 104:
1569 case 105:
1570 case 106:
1571 case 107:
1572 gc->flags &= ~GRID_FLAG_BG256;
1573 gc->bg = n - 10;
1574 break;
1579 /* DCS terminator (ST) received. */
1581 input_dcs_dispatch(struct input_ctx *ictx)
1583 const char prefix[] = "tmux;";
1584 const u_int prefix_len = (sizeof prefix) - 1;
1586 if (ictx->flags & INPUT_DISCARD)
1587 return (0);
1589 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1591 /* Check for tmux prefix. */
1592 if (ictx->input_len >= prefix_len &&
1593 strncmp(ictx->input_buf, prefix, prefix_len) == 0) {
1594 screen_write_rawstring(&ictx->ctx,
1595 ictx->input_buf + prefix_len, ictx->input_len - prefix_len);
1598 return (0);
1601 /* OSC string started. */
1602 void
1603 input_enter_osc(struct input_ctx *ictx)
1605 log_debug("%s", __func__);
1607 input_clear(ictx);
1610 /* OSC terminator (ST) received. */
1611 void
1612 input_exit_osc(struct input_ctx *ictx)
1614 u_char *p = ictx->input_buf;
1615 int option;
1617 if (ictx->flags & INPUT_DISCARD)
1618 return;
1619 if (ictx->input_len < 1 || *p < '0' || *p > '9')
1620 return;
1622 log_debug("%s: \"%s\"", __func__, p);
1624 option = 0;
1625 while (*p >= '0' && *p <= '9')
1626 option = option * 10 + *p++ - '0';
1627 if (*p == ';')
1628 p++;
1630 switch (option) {
1631 case 0:
1632 case 2:
1633 screen_set_title(ictx->ctx.s, p);
1634 server_status_window(ictx->wp->window);
1635 break;
1636 case 12:
1637 if (*p != '?') /* ? is colour request */
1638 screen_set_cursor_colour(ictx->ctx.s, p);
1639 break;
1640 case 112:
1641 if (*p == '\0') /* no arguments allowed */
1642 screen_set_cursor_colour(ictx->ctx.s, "");
1643 break;
1644 default:
1645 log_debug("%s: unknown '%u'", __func__, option);
1646 break;
1650 /* APC string started. */
1651 void
1652 input_enter_apc(struct input_ctx *ictx)
1654 log_debug("%s", __func__);
1656 input_clear(ictx);
1659 /* APC terminator (ST) received. */
1660 void
1661 input_exit_apc(struct input_ctx *ictx)
1663 if (ictx->flags & INPUT_DISCARD)
1664 return;
1665 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1667 screen_set_title(ictx->ctx.s, ictx->input_buf);
1668 server_status_window(ictx->wp->window);
1671 /* Rename string started. */
1672 void
1673 input_enter_rename(struct input_ctx *ictx)
1675 log_debug("%s", __func__);
1677 input_clear(ictx);
1680 /* Rename terminator (ST) received. */
1681 void
1682 input_exit_rename(struct input_ctx *ictx)
1684 if (ictx->flags & INPUT_DISCARD)
1685 return;
1686 if (!options_get_number(&ictx->wp->window->options, "allow-rename"))
1687 return;
1688 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1690 window_set_name(ictx->wp->window, ictx->input_buf);
1691 options_set_number(&ictx->wp->window->options, "automatic-rename", 0);
1693 server_status_window(ictx->wp->window);
1696 /* Open UTF-8 character. */
1698 input_utf8_open(struct input_ctx *ictx)
1700 if (!options_get_number(&ictx->wp->window->options, "utf8")) {
1701 /* Print, and do not switch state. */
1702 input_print(ictx);
1703 return (-1);
1705 log_debug("%s", __func__);
1707 utf8_open(&ictx->utf8data, ictx->ch);
1708 return (0);
1711 /* Append to UTF-8 character. */
1713 input_utf8_add(struct input_ctx *ictx)
1715 log_debug("%s", __func__);
1717 utf8_append(&ictx->utf8data, ictx->ch);
1718 return (0);
1721 /* Close UTF-8 string. */
1723 input_utf8_close(struct input_ctx *ictx)
1725 log_debug("%s", __func__);
1727 utf8_append(&ictx->utf8data, ictx->ch);
1729 grid_cell_set(&ictx->cell, &ictx->utf8data);
1730 screen_write_cell(&ictx->ctx, &ictx->cell);
1732 return (0);