Change terminal-overrides to a server option (now that we have them), it
[tmux-openbsd.git] / input.c
blob58064ddda98f2583cc0b8b3692a32b8a731dd254
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_winops(struct input_ctx *);
78 void input_csi_dispatch_sgr(struct input_ctx *);
79 int input_dcs_dispatch(struct input_ctx *);
80 int input_utf8_open(struct input_ctx *);
81 int input_utf8_add(struct input_ctx *);
82 int input_utf8_close(struct input_ctx *);
84 /* Command table comparison function. */
85 int input_table_compare(const void *, const void *);
87 /* Command table entry. */
88 struct input_table_entry {
89 int ch;
90 const char *interm;
91 int type;
94 /* Escape commands. */
95 enum input_esc_type {
96 INPUT_ESC_DECALN,
97 INPUT_ESC_DECKPAM,
98 INPUT_ESC_DECKPNM,
99 INPUT_ESC_DECRC,
100 INPUT_ESC_DECSC,
101 INPUT_ESC_HTS,
102 INPUT_ESC_IND,
103 INPUT_ESC_NEL,
104 INPUT_ESC_RI,
105 INPUT_ESC_RIS,
106 INPUT_ESC_SCSOFF_G0,
107 INPUT_ESC_SCSON_G0,
110 /* Escape command table. */
111 const struct input_table_entry input_esc_table[] = {
112 { '0', "(", INPUT_ESC_SCSOFF_G0 },
113 { '7', "", INPUT_ESC_DECSC },
114 { '8', "", INPUT_ESC_DECRC },
115 { '8', "#", INPUT_ESC_DECALN },
116 { '=', "", INPUT_ESC_DECKPAM },
117 { '>', "", INPUT_ESC_DECKPNM },
118 { 'B', "(", INPUT_ESC_SCSON_G0 },
119 { 'D', "", INPUT_ESC_IND },
120 { 'E', "", INPUT_ESC_NEL },
121 { 'H', "", INPUT_ESC_HTS },
122 { 'M', "", INPUT_ESC_RI },
123 { 'c', "", INPUT_ESC_RIS },
126 /* Control (CSI) commands. */
127 enum input_csi_type {
128 INPUT_CSI_CBT,
129 INPUT_CSI_CNL,
130 INPUT_CSI_CPL,
131 INPUT_CSI_CUB,
132 INPUT_CSI_CUD,
133 INPUT_CSI_CUF,
134 INPUT_CSI_CUP,
135 INPUT_CSI_CUU,
136 INPUT_CSI_DA,
137 INPUT_CSI_DA_TWO,
138 INPUT_CSI_DCH,
139 INPUT_CSI_DECSCUSR,
140 INPUT_CSI_DECSTBM,
141 INPUT_CSI_DL,
142 INPUT_CSI_DSR,
143 INPUT_CSI_ECH,
144 INPUT_CSI_ED,
145 INPUT_CSI_EL,
146 INPUT_CSI_HPA,
147 INPUT_CSI_ICH,
148 INPUT_CSI_IL,
149 INPUT_CSI_RCP,
150 INPUT_CSI_RM,
151 INPUT_CSI_RM_PRIVATE,
152 INPUT_CSI_SCP,
153 INPUT_CSI_SGR,
154 INPUT_CSI_SM,
155 INPUT_CSI_SM_PRIVATE,
156 INPUT_CSI_TBC,
157 INPUT_CSI_VPA,
158 INPUT_CSI_WINOPS,
161 /* Control (CSI) command table. */
162 const struct input_table_entry input_csi_table[] = {
163 { '@', "", INPUT_CSI_ICH },
164 { 'A', "", INPUT_CSI_CUU },
165 { 'B', "", INPUT_CSI_CUD },
166 { 'C', "", INPUT_CSI_CUF },
167 { 'D', "", INPUT_CSI_CUB },
168 { 'E', "", INPUT_CSI_CNL },
169 { 'F', "", INPUT_CSI_CPL },
170 { 'G', "", INPUT_CSI_HPA },
171 { 'H', "", INPUT_CSI_CUP },
172 { 'J', "", INPUT_CSI_ED },
173 { 'K', "", INPUT_CSI_EL },
174 { 'L', "", INPUT_CSI_IL },
175 { 'M', "", INPUT_CSI_DL },
176 { 'P', "", INPUT_CSI_DCH },
177 { 'X', "", INPUT_CSI_ECH },
178 { 'Z', "", INPUT_CSI_CBT },
179 { 'c', "", INPUT_CSI_DA },
180 { 'c', ">", INPUT_CSI_DA_TWO },
181 { 'd', "", INPUT_CSI_VPA },
182 { 'f', "", INPUT_CSI_CUP },
183 { 'g', "", INPUT_CSI_TBC },
184 { 'h', "", INPUT_CSI_SM },
185 { 'h', "?", INPUT_CSI_SM_PRIVATE },
186 { 'l', "", INPUT_CSI_RM },
187 { 'l', "?", INPUT_CSI_RM_PRIVATE },
188 { 'm', "", INPUT_CSI_SGR },
189 { 'n', "", INPUT_CSI_DSR },
190 { 'q', " ", INPUT_CSI_DECSCUSR },
191 { 'r', "", INPUT_CSI_DECSTBM },
192 { 's', "", INPUT_CSI_SCP },
193 { 't', "", INPUT_CSI_WINOPS },
194 { 'u', "", INPUT_CSI_RCP },
197 /* Input transition. */
198 struct input_transition {
199 int first;
200 int last;
202 int (*handler)(struct input_ctx *);
203 const struct input_state *state;
206 /* Input state. */
207 struct input_state {
208 const char *name;
209 void (*enter)(struct input_ctx *);
210 void (*exit)(struct input_ctx *);
211 const struct input_transition *transitions;
214 /* State transitions available from all states. */
215 #define INPUT_STATE_ANYWHERE \
216 { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
217 { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
218 { 0x1b, 0x1b, NULL, &input_state_esc_enter }
220 /* Forward declarations of state tables. */
221 const struct input_transition input_state_ground_table[];
222 const struct input_transition input_state_esc_enter_table[];
223 const struct input_transition input_state_esc_intermediate_table[];
224 const struct input_transition input_state_csi_enter_table[];
225 const struct input_transition input_state_csi_parameter_table[];
226 const struct input_transition input_state_csi_intermediate_table[];
227 const struct input_transition input_state_csi_ignore_table[];
228 const struct input_transition input_state_dcs_enter_table[];
229 const struct input_transition input_state_dcs_parameter_table[];
230 const struct input_transition input_state_dcs_intermediate_table[];
231 const struct input_transition input_state_dcs_handler_table[];
232 const struct input_transition input_state_dcs_escape_table[];
233 const struct input_transition input_state_dcs_ignore_table[];
234 const struct input_transition input_state_osc_string_table[];
235 const struct input_transition input_state_apc_string_table[];
236 const struct input_transition input_state_rename_string_table[];
237 const struct input_transition input_state_consume_st_table[];
238 const struct input_transition input_state_utf8_three_table[];
239 const struct input_transition input_state_utf8_two_table[];
240 const struct input_transition input_state_utf8_one_table[];
242 /* ground state definition. */
243 const struct input_state input_state_ground = {
244 "ground",
245 NULL, NULL,
246 input_state_ground_table
249 /* esc_enter state definition. */
250 const struct input_state input_state_esc_enter = {
251 "esc_enter",
252 input_clear, NULL,
253 input_state_esc_enter_table
256 /* esc_intermediate state definition. */
257 const struct input_state input_state_esc_intermediate = {
258 "esc_intermediate",
259 NULL, NULL,
260 input_state_esc_intermediate_table
263 /* csi_enter state definition. */
264 const struct input_state input_state_csi_enter = {
265 "csi_enter",
266 input_clear, NULL,
267 input_state_csi_enter_table
270 /* csi_parameter state definition. */
271 const struct input_state input_state_csi_parameter = {
272 "csi_parameter",
273 NULL, NULL,
274 input_state_csi_parameter_table
277 /* csi_intermediate state definition. */
278 const struct input_state input_state_csi_intermediate = {
279 "csi_intermediate",
280 NULL, NULL,
281 input_state_csi_intermediate_table
284 /* csi_ignore state definition. */
285 const struct input_state input_state_csi_ignore = {
286 "csi_ignore",
287 NULL, NULL,
288 input_state_csi_ignore_table
291 /* dcs_enter state definition. */
292 const struct input_state input_state_dcs_enter = {
293 "dcs_enter",
294 input_clear, NULL,
295 input_state_dcs_enter_table
298 /* dcs_parameter state definition. */
299 const struct input_state input_state_dcs_parameter = {
300 "dcs_parameter",
301 NULL, NULL,
302 input_state_dcs_parameter_table
305 /* dcs_intermediate state definition. */
306 const struct input_state input_state_dcs_intermediate = {
307 "dcs_intermediate",
308 NULL, NULL,
309 input_state_dcs_intermediate_table
312 /* dcs_handler state definition. */
313 const struct input_state input_state_dcs_handler = {
314 "dcs_handler",
315 NULL, NULL,
316 input_state_dcs_handler_table
319 /* dcs_escape state definition. */
320 const struct input_state input_state_dcs_escape = {
321 "dcs_escape",
322 NULL, NULL,
323 input_state_dcs_escape_table
326 /* dcs_ignore state definition. */
327 const struct input_state input_state_dcs_ignore = {
328 "dcs_ignore",
329 NULL, NULL,
330 input_state_dcs_ignore_table
333 /* osc_string state definition. */
334 const struct input_state input_state_osc_string = {
335 "osc_string",
336 input_enter_osc, input_exit_osc,
337 input_state_osc_string_table
340 /* apc_string state definition. */
341 const struct input_state input_state_apc_string = {
342 "apc_string",
343 input_enter_apc, input_exit_apc,
344 input_state_apc_string_table
347 /* rename_string state definition. */
348 const struct input_state input_state_rename_string = {
349 "rename_string",
350 input_enter_rename, input_exit_rename,
351 input_state_rename_string_table
354 /* consume_st state definition. */
355 const struct input_state input_state_consume_st = {
356 "consume_st",
357 NULL, NULL,
358 input_state_consume_st_table
361 /* utf8_three state definition. */
362 const struct input_state input_state_utf8_three = {
363 "utf8_three",
364 NULL, NULL,
365 input_state_utf8_three_table
368 /* utf8_two state definition. */
369 const struct input_state input_state_utf8_two = {
370 "utf8_two",
371 NULL, NULL,
372 input_state_utf8_two_table
375 /* utf8_one state definition. */
376 const struct input_state input_state_utf8_one = {
377 "utf8_one",
378 NULL, NULL,
379 input_state_utf8_one_table
382 /* ground state table. */
383 const struct input_transition input_state_ground_table[] = {
384 INPUT_STATE_ANYWHERE,
386 { 0x00, 0x17, input_c0_dispatch, NULL },
387 { 0x19, 0x19, input_c0_dispatch, NULL },
388 { 0x1c, 0x1f, input_c0_dispatch, NULL },
389 { 0x20, 0x7e, input_print, NULL },
390 { 0x7f, 0x7f, NULL, NULL },
391 { 0x80, 0xc1, input_print, NULL },
392 { 0xc2, 0xdf, input_utf8_open, &input_state_utf8_one },
393 { 0xe0, 0xef, input_utf8_open, &input_state_utf8_two },
394 { 0xf0, 0xf4, input_utf8_open, &input_state_utf8_three },
395 { 0xf5, 0xff, input_print, NULL },
397 { -1, -1, NULL, NULL }
400 /* esc_enter state table. */
401 const struct input_transition input_state_esc_enter_table[] = {
402 INPUT_STATE_ANYWHERE,
404 { 0x00, 0x17, input_c0_dispatch, NULL },
405 { 0x19, 0x19, input_c0_dispatch, NULL },
406 { 0x1c, 0x1f, input_c0_dispatch, NULL },
407 { 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate },
408 { 0x30, 0x4f, input_esc_dispatch, &input_state_ground },
409 { 0x50, 0x50, NULL, &input_state_dcs_enter },
410 { 0x51, 0x57, input_esc_dispatch, &input_state_ground },
411 { 0x58, 0x58, NULL, &input_state_consume_st },
412 { 0x59, 0x59, input_esc_dispatch, &input_state_ground },
413 { 0x5a, 0x5a, input_esc_dispatch, &input_state_ground },
414 { 0x5b, 0x5b, NULL, &input_state_csi_enter },
415 { 0x5c, 0x5c, input_esc_dispatch, &input_state_ground },
416 { 0x5d, 0x5d, NULL, &input_state_osc_string },
417 { 0x5e, 0x5e, NULL, &input_state_consume_st },
418 { 0x5f, 0x5f, NULL, &input_state_apc_string },
419 { 0x60, 0x6a, input_esc_dispatch, &input_state_ground },
420 { 0x6b, 0x6b, NULL, &input_state_rename_string },
421 { 0x6c, 0x7e, input_esc_dispatch, &input_state_ground },
422 { 0x7f, 0xff, NULL, NULL },
424 { -1, -1, NULL, NULL }
427 /* esc_interm state table. */
428 const struct input_transition input_state_esc_intermediate_table[] = {
429 INPUT_STATE_ANYWHERE,
431 { 0x00, 0x17, input_c0_dispatch, NULL },
432 { 0x19, 0x19, input_c0_dispatch, NULL },
433 { 0x1c, 0x1f, input_c0_dispatch, NULL },
434 { 0x20, 0x2f, input_intermediate, NULL },
435 { 0x30, 0x7e, input_esc_dispatch, &input_state_ground },
436 { 0x7f, 0xff, NULL, NULL },
438 { -1, -1, NULL, NULL }
441 /* csi_enter state table. */
442 const struct input_transition input_state_csi_enter_table[] = {
443 INPUT_STATE_ANYWHERE,
445 { 0x00, 0x17, input_c0_dispatch, NULL },
446 { 0x19, 0x19, input_c0_dispatch, NULL },
447 { 0x1c, 0x1f, input_c0_dispatch, NULL },
448 { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
449 { 0x30, 0x39, input_parameter, &input_state_csi_parameter },
450 { 0x3a, 0x3a, NULL, &input_state_csi_ignore },
451 { 0x3b, 0x3b, input_parameter, &input_state_csi_parameter },
452 { 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter },
453 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
454 { 0x7f, 0xff, NULL, NULL },
456 { -1, -1, NULL, NULL }
459 /* csi_parameter state table. */
460 const struct input_transition input_state_csi_parameter_table[] = {
461 INPUT_STATE_ANYWHERE,
463 { 0x00, 0x17, input_c0_dispatch, NULL },
464 { 0x19, 0x19, input_c0_dispatch, NULL },
465 { 0x1c, 0x1f, input_c0_dispatch, NULL },
466 { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
467 { 0x30, 0x39, input_parameter, NULL },
468 { 0x3a, 0x3a, NULL, &input_state_csi_ignore },
469 { 0x3b, 0x3b, input_parameter, NULL },
470 { 0x3c, 0x3f, NULL, &input_state_csi_ignore },
471 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
472 { 0x7f, 0xff, NULL, NULL },
474 { -1, -1, NULL, NULL }
477 /* csi_intermediate state table. */
478 const struct input_transition input_state_csi_intermediate_table[] = {
479 INPUT_STATE_ANYWHERE,
481 { 0x00, 0x17, input_c0_dispatch, NULL },
482 { 0x19, 0x19, input_c0_dispatch, NULL },
483 { 0x1c, 0x1f, input_c0_dispatch, NULL },
484 { 0x20, 0x2f, input_intermediate, NULL },
485 { 0x30, 0x3f, NULL, &input_state_csi_ignore },
486 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
487 { 0x7f, 0xff, NULL, NULL },
489 { -1, -1, NULL, NULL }
492 /* csi_ignore state table. */
493 const struct input_transition input_state_csi_ignore_table[] = {
494 INPUT_STATE_ANYWHERE,
496 { 0x00, 0x17, input_c0_dispatch, NULL },
497 { 0x19, 0x19, input_c0_dispatch, NULL },
498 { 0x1c, 0x1f, input_c0_dispatch, NULL },
499 { 0x20, 0x3f, NULL, NULL },
500 { 0x40, 0x7e, NULL, &input_state_ground },
501 { 0x7f, 0xff, NULL, NULL },
503 { -1, -1, NULL, NULL }
506 /* dcs_enter state table. */
507 const struct input_transition input_state_dcs_enter_table[] = {
508 INPUT_STATE_ANYWHERE,
510 { 0x00, 0x17, NULL, NULL },
511 { 0x19, 0x19, NULL, NULL },
512 { 0x1c, 0x1f, NULL, NULL },
513 { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
514 { 0x30, 0x39, input_parameter, &input_state_dcs_parameter },
515 { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
516 { 0x3b, 0x3b, input_parameter, &input_state_dcs_parameter },
517 { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter },
518 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
519 { 0x7f, 0xff, NULL, NULL },
521 { -1, -1, NULL, NULL }
524 /* dcs_parameter state table. */
525 const struct input_transition input_state_dcs_parameter_table[] = {
526 INPUT_STATE_ANYWHERE,
528 { 0x00, 0x17, NULL, NULL },
529 { 0x19, 0x19, NULL, NULL },
530 { 0x1c, 0x1f, NULL, NULL },
531 { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
532 { 0x30, 0x39, input_parameter, NULL },
533 { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
534 { 0x3b, 0x3b, input_parameter, NULL },
535 { 0x3c, 0x3f, NULL, &input_state_dcs_ignore },
536 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
537 { 0x7f, 0xff, NULL, NULL },
539 { -1, -1, NULL, NULL }
542 /* dcs_interm state table. */
543 const struct input_transition input_state_dcs_intermediate_table[] = {
544 INPUT_STATE_ANYWHERE,
546 { 0x00, 0x17, NULL, NULL },
547 { 0x19, 0x19, NULL, NULL },
548 { 0x1c, 0x1f, NULL, NULL },
549 { 0x20, 0x2f, input_intermediate, NULL },
550 { 0x30, 0x3f, NULL, &input_state_dcs_ignore },
551 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
552 { 0x7f, 0xff, NULL, NULL },
554 { -1, -1, NULL, NULL }
557 /* dcs_handler state table. */
558 const struct input_transition input_state_dcs_handler_table[] = {
559 /* No INPUT_STATE_ANYWHERE */
561 { 0x00, 0x1a, input_input, NULL },
562 { 0x1b, 0x1b, NULL, &input_state_dcs_escape },
563 { 0x1c, 0xff, input_input, NULL },
565 { -1, -1, NULL, NULL }
568 /* dcs_escape state table. */
569 const struct input_transition input_state_dcs_escape_table[] = {
570 /* No INPUT_STATE_ANYWHERE */
572 { 0x00, 0x5b, input_input, &input_state_dcs_handler },
573 { 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground },
574 { 0x5d, 0xff, input_input, &input_state_dcs_handler },
576 { -1, -1, NULL, NULL }
579 /* dcs_ignore state table. */
580 const struct input_transition input_state_dcs_ignore_table[] = {
581 INPUT_STATE_ANYWHERE,
583 { 0x00, 0x17, NULL, NULL },
584 { 0x19, 0x19, NULL, NULL },
585 { 0x1c, 0x1f, NULL, NULL },
586 { 0x20, 0xff, NULL, NULL },
588 { -1, -1, NULL, NULL }
591 /* osc_string state table. */
592 const struct input_transition input_state_osc_string_table[] = {
593 INPUT_STATE_ANYWHERE,
595 { 0x00, 0x06, NULL, NULL },
596 { 0x07, 0x07, NULL, &input_state_ground },
597 { 0x08, 0x17, NULL, NULL },
598 { 0x19, 0x19, NULL, NULL },
599 { 0x1c, 0x1f, NULL, NULL },
600 { 0x20, 0xff, input_input, NULL },
602 { -1, -1, NULL, NULL }
605 /* apc_string state table. */
606 const struct input_transition input_state_apc_string_table[] = {
607 INPUT_STATE_ANYWHERE,
609 { 0x00, 0x17, NULL, NULL },
610 { 0x19, 0x19, NULL, NULL },
611 { 0x1c, 0x1f, NULL, NULL },
612 { 0x20, 0xff, input_input, NULL },
614 { -1, -1, NULL, NULL }
617 /* rename_string state table. */
618 const struct input_transition input_state_rename_string_table[] = {
619 INPUT_STATE_ANYWHERE,
621 { 0x00, 0x17, NULL, NULL },
622 { 0x19, 0x19, NULL, NULL },
623 { 0x1c, 0x1f, NULL, NULL },
624 { 0x20, 0xff, input_input, NULL },
626 { -1, -1, NULL, NULL }
629 /* consume_st state table. */
630 const struct input_transition input_state_consume_st_table[] = {
631 INPUT_STATE_ANYWHERE,
633 { 0x00, 0x17, NULL, NULL },
634 { 0x19, 0x19, NULL, NULL },
635 { 0x1c, 0x1f, NULL, NULL },
636 { 0x20, 0xff, NULL, NULL },
638 { -1, -1, NULL, NULL }
641 /* utf8_three state table. */
642 const struct input_transition input_state_utf8_three_table[] = {
643 /* No INPUT_STATE_ANYWHERE */
645 { 0x00, 0x7f, NULL, &input_state_ground },
646 { 0x80, 0xbf, input_utf8_add, &input_state_utf8_two },
647 { 0xc0, 0xff, NULL, &input_state_ground },
649 { -1, -1, NULL, NULL }
652 /* utf8_two state table. */
653 const struct input_transition input_state_utf8_two_table[] = {
654 /* No INPUT_STATE_ANYWHERE */
656 { 0x00, 0x7f, NULL, &input_state_ground },
657 { 0x80, 0xbf, input_utf8_add, &input_state_utf8_one },
658 { 0xc0, 0xff, NULL, &input_state_ground },
660 { -1, -1, NULL, NULL }
663 /* utf8_one state table. */
664 const struct input_transition input_state_utf8_one_table[] = {
665 /* No INPUT_STATE_ANYWHERE */
667 { 0x00, 0x7f, NULL, &input_state_ground },
668 { 0x80, 0xbf, input_utf8_close, &input_state_ground },
669 { 0xc0, 0xff, NULL, &input_state_ground },
671 { -1, -1, NULL, NULL }
674 /* Input table compare. */
676 input_table_compare(const void *key, const void *value)
678 const struct input_ctx *ictx = key;
679 const struct input_table_entry *entry = value;
681 if (ictx->ch != entry->ch)
682 return (ictx->ch - entry->ch);
683 return (strcmp(ictx->interm_buf, entry->interm));
686 /* Initialise input parser. */
687 void
688 input_init(struct window_pane *wp)
690 struct input_ctx *ictx = &wp->ictx;
692 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
694 memcpy(&ictx->old_cell, &grid_default_cell, sizeof ictx->old_cell);
695 ictx->old_cx = 0;
696 ictx->old_cy = 0;
698 *ictx->interm_buf = '\0';
699 ictx->interm_len = 0;
701 *ictx->param_buf = '\0';
702 ictx->param_len = 0;
704 ictx->state = &input_state_ground;
705 ictx->flags = 0;
707 ictx->since_ground = evbuffer_new();
710 /* Destroy input parser. */
711 void
712 input_free(struct window_pane *wp)
714 if (wp != NULL)
715 evbuffer_free(wp->ictx.since_ground);
718 /* Change input state. */
719 void
720 input_set_state(struct window_pane *wp, const struct input_transition *itr)
722 struct input_ctx *ictx = &wp->ictx;
723 struct evbuffer *ground_evb = ictx->since_ground;
725 if (ictx->state->exit != NULL)
726 ictx->state->exit(ictx);
728 if (itr->state == &input_state_ground)
729 evbuffer_drain(ground_evb, EVBUFFER_LENGTH(ground_evb));
731 ictx->state = itr->state;
732 if (ictx->state->enter != NULL)
733 ictx->state->enter(ictx);
736 /* Parse input. */
737 void
738 input_parse(struct window_pane *wp)
740 struct input_ctx *ictx = &wp->ictx;
741 const struct input_transition *itr;
742 struct evbuffer *evb = wp->event->input;
743 u_char *buf;
744 size_t len, off;
746 if (EVBUFFER_LENGTH(evb) == 0)
747 return;
749 wp->window->flags |= WINDOW_ACTIVITY;
750 wp->window->flags &= ~WINDOW_SILENCE;
753 * Open the screen. Use NULL wp if there is a mode set as don't want to
754 * update the tty.
756 if (wp->mode == NULL)
757 screen_write_start(&ictx->ctx, wp, &wp->base);
758 else
759 screen_write_start(&ictx->ctx, NULL, &wp->base);
760 ictx->wp = wp;
762 buf = EVBUFFER_DATA(evb);
763 len = EVBUFFER_LENGTH(evb);
764 notify_input(wp, evb);
765 off = 0;
767 /* Parse the input. */
768 while (off < len) {
769 ictx->ch = buf[off++];
770 log_debug("%s: '%c' %s", __func__, ictx->ch, ictx->state->name);
772 /* Find the transition. */
773 itr = ictx->state->transitions;
774 while (itr->first != -1 && itr->last != -1) {
775 if (ictx->ch >= itr->first && ictx->ch <= itr->last)
776 break;
777 itr++;
779 if (itr->first == -1 || itr->last == -1) {
780 /* No transition? Eh? */
781 fatalx("No transition from state!");
785 * Execute the handler, if any. Don't switch state if it
786 * returns non-zero.
788 if (itr->handler != NULL && itr->handler(ictx) != 0)
789 continue;
791 /* And switch state, if necessary. */
792 if (itr->state != NULL)
793 input_set_state(wp, itr);
795 /* If not in ground state, save input. */
796 if (ictx->state != &input_state_ground)
797 evbuffer_add(ictx->since_ground, &ictx->ch, 1);
800 /* Close the screen. */
801 screen_write_stop(&ictx->ctx);
803 evbuffer_drain(evb, len);
806 /* Split the parameter list (if any). */
808 input_split(struct input_ctx *ictx)
811 const char *errstr;
812 char *ptr, *out;
813 int n;
815 ictx->param_list_len = 0;
816 if (ictx->param_len == 0)
817 return (0);
819 ptr = ictx->param_buf;
820 while ((out = strsep(&ptr, ";")) != NULL) {
821 if (*out == '\0')
822 n = -1;
823 else {
824 n = strtonum(out, 0, INT_MAX, &errstr);
825 if (errstr != NULL)
826 return (-1);
829 ictx->param_list[ictx->param_list_len++] = n;
830 if (ictx->param_list_len == nitems(ictx->param_list))
831 return (-1);
834 return (0);
837 /* Get an argument or return default value. */
839 input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
841 int retval;
843 if (validx >= ictx->param_list_len)
844 return (defval);
846 retval = ictx->param_list[validx];
847 if (retval == -1)
848 return (defval);
849 if (retval < minval)
850 return (minval);
851 return (retval);
854 /* Reply to terminal query. */
855 void
856 input_reply(struct input_ctx *ictx, const char *fmt, ...)
858 va_list ap;
859 char *reply;
861 va_start(ap, fmt);
862 vasprintf(&reply, fmt, ap);
863 va_end(ap);
865 bufferevent_write(ictx->wp->event, reply, strlen(reply));
866 free(reply);
869 /* Clear saved state. */
870 void
871 input_clear(struct input_ctx *ictx)
873 *ictx->interm_buf = '\0';
874 ictx->interm_len = 0;
876 *ictx->param_buf = '\0';
877 ictx->param_len = 0;
879 *ictx->input_buf = '\0';
880 ictx->input_len = 0;
882 ictx->flags &= ~INPUT_DISCARD;
885 /* Output this character to the screen. */
887 input_print(struct input_ctx *ictx)
889 grid_cell_one(&ictx->cell, ictx->ch);
890 screen_write_cell(&ictx->ctx, &ictx->cell);
892 return (0);
895 /* Collect intermediate string. */
897 input_intermediate(struct input_ctx *ictx)
899 if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
900 ictx->flags |= INPUT_DISCARD;
901 else {
902 ictx->interm_buf[ictx->interm_len++] = ictx->ch;
903 ictx->interm_buf[ictx->interm_len] = '\0';
906 return (0);
909 /* Collect parameter string. */
911 input_parameter(struct input_ctx *ictx)
913 if (ictx->param_len == (sizeof ictx->param_buf) - 1)
914 ictx->flags |= INPUT_DISCARD;
915 else {
916 ictx->param_buf[ictx->param_len++] = ictx->ch;
917 ictx->param_buf[ictx->param_len] = '\0';
920 return (0);
923 /* Collect input string. */
925 input_input(struct input_ctx *ictx)
927 if (ictx->input_len == (sizeof ictx->input_buf) - 1)
928 ictx->flags |= INPUT_DISCARD;
929 else {
930 ictx->input_buf[ictx->input_len++] = ictx->ch;
931 ictx->input_buf[ictx->input_len] = '\0';
934 return (0);
937 /* Execute C0 control sequence. */
939 input_c0_dispatch(struct input_ctx *ictx)
941 struct screen_write_ctx *sctx = &ictx->ctx;
942 struct window_pane *wp = ictx->wp;
943 struct screen *s = sctx->s;
944 u_int trigger;
946 log_debug("%s: '%c", __func__, ictx->ch);
948 switch (ictx->ch) {
949 case '\000': /* NUL */
950 break;
951 case '\007': /* BEL */
952 wp->window->flags |= WINDOW_BELL;
953 break;
954 case '\010': /* BS */
955 screen_write_backspace(sctx);
956 goto count_c0;
957 case '\011': /* HT */
958 /* Don't tab beyond the end of the line. */
959 if (s->cx >= screen_size_x(s) - 1)
960 break;
962 /* Find the next tab point, or use the last column if none. */
963 do {
964 s->cx++;
965 if (bit_test(s->tabs, s->cx))
966 break;
967 } while (s->cx < screen_size_x(s) - 1);
968 break;
969 case '\012': /* LF */
970 case '\013': /* VT */
971 case '\014': /* FF */
972 screen_write_linefeed(sctx, 0);
973 goto count_c0;
974 case '\015': /* CR */
975 screen_write_carriagereturn(sctx);
976 goto count_c0;
977 case '\016': /* SO */
978 ictx->cell.attr |= GRID_ATTR_CHARSET;
979 break;
980 case '\017': /* SI */
981 ictx->cell.attr &= ~GRID_ATTR_CHARSET;
982 break;
983 default:
984 log_debug("%s: unknown '%c'", __func__, ictx->ch);
985 break;
988 return (0);
990 count_c0:
991 trigger = options_get_number(&wp->window->options, "c0-change-trigger");
992 if (++wp->changes == trigger) {
993 wp->flags |= PANE_DROP;
994 window_pane_timer_start(wp);
997 return (0);
1000 /* Execute escape sequence. */
1002 input_esc_dispatch(struct input_ctx *ictx)
1004 struct screen_write_ctx *sctx = &ictx->ctx;
1005 struct screen *s = sctx->s;
1006 struct input_table_entry *entry;
1008 if (ictx->flags & INPUT_DISCARD)
1009 return (0);
1010 log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
1012 entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
1013 sizeof input_esc_table[0], input_table_compare);
1014 if (entry == NULL) {
1015 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1016 return (0);
1019 switch (entry->type) {
1020 case INPUT_ESC_RIS:
1021 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
1022 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1023 ictx->old_cx = 0;
1024 ictx->old_cy = 0;
1026 screen_write_reset(sctx);
1027 break;
1028 case INPUT_ESC_IND:
1029 screen_write_linefeed(sctx, 0);
1030 break;
1031 case INPUT_ESC_NEL:
1032 screen_write_carriagereturn(sctx);
1033 screen_write_linefeed(sctx, 0);
1034 break;
1035 case INPUT_ESC_HTS:
1036 if (s->cx < screen_size_x(s))
1037 bit_set(s->tabs, s->cx);
1038 break;
1039 case INPUT_ESC_RI:
1040 screen_write_reverseindex(sctx);
1041 break;
1042 case INPUT_ESC_DECKPAM:
1043 screen_write_mode_set(sctx, MODE_KKEYPAD);
1044 break;
1045 case INPUT_ESC_DECKPNM:
1046 screen_write_mode_clear(sctx, MODE_KKEYPAD);
1047 break;
1048 case INPUT_ESC_DECSC:
1049 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1050 ictx->old_cx = s->cx;
1051 ictx->old_cy = s->cy;
1052 break;
1053 case INPUT_ESC_DECRC:
1054 memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
1055 screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
1056 break;
1057 case INPUT_ESC_DECALN:
1058 screen_write_alignmenttest(sctx);
1059 break;
1060 case INPUT_ESC_SCSON_G0:
1062 * Not really supported, but fake it up enough for those that
1063 * use it to switch character sets (by redefining G0 to
1064 * graphics set, rather than switching to G1).
1066 ictx->cell.attr &= ~GRID_ATTR_CHARSET;
1067 break;
1068 case INPUT_ESC_SCSOFF_G0:
1069 ictx->cell.attr |= GRID_ATTR_CHARSET;
1070 break;
1073 return (0);
1076 /* Execute control sequence. */
1078 input_csi_dispatch(struct input_ctx *ictx)
1080 struct screen_write_ctx *sctx = &ictx->ctx;
1081 struct screen *s = sctx->s;
1082 struct input_table_entry *entry;
1083 int n, m;
1085 if (ictx->flags & INPUT_DISCARD)
1086 return (0);
1087 if (input_split(ictx) != 0)
1088 return (0);
1089 log_debug("%s: '%c' \"%s\" \"%s\"",
1090 __func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
1092 entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
1093 sizeof input_csi_table[0], input_table_compare);
1094 if (entry == NULL) {
1095 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1096 return (0);
1099 switch (entry->type) {
1100 case INPUT_CSI_CBT:
1101 /* Find the previous tab point, n times. */
1102 n = input_get(ictx, 0, 1, 1);
1103 while (s->cx > 0 && n-- > 0) {
1105 s->cx--;
1106 while (s->cx > 0 && !bit_test(s->tabs, s->cx));
1108 break;
1109 case INPUT_CSI_CUB:
1110 screen_write_cursorleft(sctx, input_get(ictx, 0, 1, 1));
1111 break;
1112 case INPUT_CSI_CUD:
1113 screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
1114 break;
1115 case INPUT_CSI_CUF:
1116 screen_write_cursorright(sctx, input_get(ictx, 0, 1, 1));
1117 break;
1118 case INPUT_CSI_CUP:
1119 n = input_get(ictx, 0, 1, 1);
1120 m = input_get(ictx, 1, 1, 1);
1121 screen_write_cursormove(sctx, m - 1, n - 1);
1122 break;
1123 case INPUT_CSI_WINOPS:
1124 input_csi_dispatch_winops(ictx);
1125 break;
1126 case INPUT_CSI_CUU:
1127 screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
1128 break;
1129 case INPUT_CSI_CNL:
1130 screen_write_carriagereturn(sctx);
1131 screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
1132 break;
1133 case INPUT_CSI_CPL:
1134 screen_write_carriagereturn(sctx);
1135 screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
1136 break;
1137 case INPUT_CSI_DA:
1138 switch (input_get(ictx, 0, 0, 0)) {
1139 case 0:
1140 input_reply(ictx, "\033[?1;2c");
1141 break;
1142 default:
1143 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1144 break;
1146 break;
1147 case INPUT_CSI_DA_TWO:
1148 switch (input_get(ictx, 0, 0, 0)) {
1149 case 0:
1150 input_reply(ictx, "\033[>0;95;0c");
1151 break;
1152 default:
1153 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1154 break;
1156 break;
1157 case INPUT_CSI_ECH:
1158 screen_write_clearcharacter(sctx, input_get(ictx, 0, 1, 1));
1159 break;
1160 case INPUT_CSI_DCH:
1161 screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1));
1162 break;
1163 case INPUT_CSI_DECSTBM:
1164 n = input_get(ictx, 0, 1, 1);
1165 m = input_get(ictx, 1, 1, screen_size_y(s));
1166 screen_write_scrollregion(sctx, n - 1, m - 1);
1167 break;
1168 case INPUT_CSI_DL:
1169 screen_write_deleteline(sctx, input_get(ictx, 0, 1, 1));
1170 break;
1171 case INPUT_CSI_DSR:
1172 switch (input_get(ictx, 0, 0, 0)) {
1173 case 5:
1174 input_reply(ictx, "\033[0n");
1175 break;
1176 case 6:
1177 input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
1178 break;
1179 default:
1180 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1181 break;
1183 break;
1184 case INPUT_CSI_ED:
1185 switch (input_get(ictx, 0, 0, 0)) {
1186 case 0:
1187 screen_write_clearendofscreen(sctx);
1188 break;
1189 case 1:
1190 screen_write_clearstartofscreen(sctx);
1191 break;
1192 case 2:
1193 screen_write_clearscreen(sctx);
1194 break;
1195 case 3:
1196 switch (input_get(ictx, 1, 0, 0)) {
1197 case 0:
1199 * Linux console extension to clear history
1200 * (for example before locking the screen).
1202 screen_write_clearhistory(sctx);
1203 break;
1205 break;
1206 default:
1207 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1208 break;
1210 break;
1211 case INPUT_CSI_EL:
1212 switch (input_get(ictx, 0, 0, 0)) {
1213 case 0:
1214 screen_write_clearendofline(sctx);
1215 break;
1216 case 1:
1217 screen_write_clearstartofline(sctx);
1218 break;
1219 case 2:
1220 screen_write_clearline(sctx);
1221 break;
1222 default:
1223 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1224 break;
1226 break;
1227 case INPUT_CSI_HPA:
1228 n = input_get(ictx, 0, 1, 1);
1229 screen_write_cursormove(sctx, n - 1, s->cy);
1230 break;
1231 case INPUT_CSI_ICH:
1232 screen_write_insertcharacter(sctx, input_get(ictx, 0, 1, 1));
1233 break;
1234 case INPUT_CSI_IL:
1235 screen_write_insertline(sctx, input_get(ictx, 0, 1, 1));
1236 break;
1237 case INPUT_CSI_RCP:
1238 memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
1239 screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
1240 break;
1241 case INPUT_CSI_RM:
1242 input_csi_dispatch_rm(ictx);
1243 break;
1244 case INPUT_CSI_RM_PRIVATE:
1245 input_csi_dispatch_rm_private(ictx);
1246 break;
1247 case INPUT_CSI_SCP:
1248 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1249 ictx->old_cx = s->cx;
1250 ictx->old_cy = s->cy;
1251 break;
1252 case INPUT_CSI_SGR:
1253 input_csi_dispatch_sgr(ictx);
1254 break;
1255 case INPUT_CSI_SM:
1256 input_csi_dispatch_sm(ictx);
1257 break;
1258 case INPUT_CSI_SM_PRIVATE:
1259 input_csi_dispatch_sm_private(ictx);
1260 break;
1261 case INPUT_CSI_TBC:
1262 switch (input_get(ictx, 0, 0, 0)) {
1263 case 0:
1264 if (s->cx < screen_size_x(s))
1265 bit_clear(s->tabs, s->cx);
1266 break;
1267 case 3:
1268 bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1269 break;
1270 default:
1271 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1272 break;
1274 break;
1275 case INPUT_CSI_VPA:
1276 n = input_get(ictx, 0, 1, 1);
1277 screen_write_cursormove(sctx, s->cx, n - 1);
1278 break;
1279 case INPUT_CSI_DECSCUSR:
1280 n = input_get(ictx, 0, 0, 0);
1281 screen_set_cursor_style(s, n);
1282 break;
1285 return (0);
1288 /* Handle CSI RM. */
1289 void
1290 input_csi_dispatch_rm(struct input_ctx *ictx)
1292 u_int i;
1294 for (i = 0; i < ictx->param_list_len; i++) {
1295 switch (input_get(ictx, i, 0, -1)) {
1296 case 4: /* IRM */
1297 screen_write_mode_clear(&ictx->ctx, MODE_INSERT);
1298 break;
1299 default:
1300 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1301 break;
1306 /* Handle CSI private RM. */
1307 void
1308 input_csi_dispatch_rm_private(struct input_ctx *ictx)
1310 u_int i;
1312 for (i = 0; i < ictx->param_list_len; i++) {
1313 switch (input_get(ictx, i, 0, -1)) {
1314 case 1: /* DECCKM */
1315 screen_write_mode_clear(&ictx->ctx, MODE_KCURSOR);
1316 break;
1317 case 3: /* DECCOLM */
1318 screen_write_cursormove(&ictx->ctx, 0, 0);
1319 screen_write_clearscreen(&ictx->ctx);
1320 break;
1321 case 7: /* DECAWM */
1322 screen_write_mode_clear(&ictx->ctx, MODE_WRAP);
1323 break;
1324 case 25: /* TCEM */
1325 screen_write_mode_clear(&ictx->ctx, MODE_CURSOR);
1326 break;
1327 case 1000:
1328 case 1001:
1329 case 1002:
1330 case 1003:
1331 screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
1332 break;
1333 case 1004:
1334 screen_write_mode_clear(&ictx->ctx, MODE_FOCUSON);
1335 break;
1336 case 1005:
1337 screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_UTF8);
1338 break;
1339 case 1006:
1340 screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_SGR);
1341 break;
1342 case 47:
1343 case 1047:
1344 window_pane_alternate_off(ictx->wp, &ictx->cell, 0);
1345 break;
1346 case 1049:
1347 window_pane_alternate_off(ictx->wp, &ictx->cell, 1);
1348 break;
1349 case 2004:
1350 screen_write_mode_clear(&ictx->ctx, MODE_BRACKETPASTE);
1351 break;
1352 default:
1353 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1354 break;
1359 /* Handle CSI SM. */
1360 void
1361 input_csi_dispatch_sm(struct input_ctx *ictx)
1363 u_int i;
1365 for (i = 0; i < ictx->param_list_len; i++) {
1366 switch (input_get(ictx, i, 0, -1)) {
1367 case 4: /* IRM */
1368 screen_write_mode_set(&ictx->ctx, MODE_INSERT);
1369 break;
1370 default:
1371 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1372 break;
1377 /* Handle CSI private SM. */
1378 void
1379 input_csi_dispatch_sm_private(struct input_ctx *ictx)
1381 u_int i;
1383 for (i = 0; i < ictx->param_list_len; i++) {
1384 switch (input_get(ictx, i, 0, -1)) {
1385 case 1: /* DECCKM */
1386 screen_write_mode_set(&ictx->ctx, MODE_KCURSOR);
1387 break;
1388 case 3: /* DECCOLM */
1389 screen_write_cursormove(&ictx->ctx, 0, 0);
1390 screen_write_clearscreen(&ictx->ctx);
1391 break;
1392 case 7: /* DECAWM */
1393 screen_write_mode_set(&ictx->ctx, MODE_WRAP);
1394 break;
1395 case 25: /* TCEM */
1396 screen_write_mode_set(&ictx->ctx, MODE_CURSOR);
1397 break;
1398 case 1000:
1399 screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
1400 screen_write_mode_set(&ictx->ctx, MODE_MOUSE_STANDARD);
1401 break;
1402 case 1002:
1403 screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
1404 screen_write_mode_set(&ictx->ctx, MODE_MOUSE_BUTTON);
1405 break;
1406 case 1003:
1407 screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
1408 screen_write_mode_set(&ictx->ctx, MODE_MOUSE_ANY);
1409 break;
1410 case 1004:
1411 if (ictx->ctx.s->mode & MODE_FOCUSON)
1412 break;
1413 screen_write_mode_set(&ictx->ctx, MODE_FOCUSON);
1414 ictx->wp->flags |= PANE_FOCUSPUSH; /* force update */
1415 break;
1416 case 1005:
1417 screen_write_mode_set(&ictx->ctx, MODE_MOUSE_UTF8);
1418 break;
1419 case 1006:
1420 screen_write_mode_set(&ictx->ctx, MODE_MOUSE_SGR);
1421 break;
1422 case 47:
1423 case 1047:
1424 window_pane_alternate_on(ictx->wp, &ictx->cell, 0);
1425 break;
1426 case 1049:
1427 window_pane_alternate_on(ictx->wp, &ictx->cell, 1);
1428 break;
1429 case 2004:
1430 screen_write_mode_set(&ictx->ctx, MODE_BRACKETPASTE);
1431 break;
1432 default:
1433 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1434 break;
1439 /* Handle CSI window operations. */
1440 void
1441 input_csi_dispatch_winops(struct input_ctx *ictx)
1443 struct window_pane *wp = ictx->wp;
1444 int n, m;
1446 m = 0;
1447 while ((n = input_get(ictx, m, 0, -1)) != -1) {
1448 switch (n) {
1449 case 1:
1450 case 2:
1451 case 5:
1452 case 6:
1453 case 7:
1454 case 11:
1455 case 13:
1456 case 14:
1457 case 19:
1458 case 20:
1459 case 21:
1460 case 24:
1461 break;
1462 case 3:
1463 case 4:
1464 case 8:
1465 m++;
1466 if (input_get(ictx, m, 0, -1) == -1)
1467 return;
1468 /* FALLTHROUGH */
1469 case 9:
1470 case 10:
1471 case 22:
1472 case 23:
1473 m++;
1474 if (input_get(ictx, m, 0, -1) == -1)
1475 return;
1476 break;
1477 case 18:
1478 input_reply(ictx, "\033[8;%u;%u", wp->sy, wp->sx);
1479 break;
1480 default:
1481 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1482 break;
1484 m++;
1488 /* Handle CSI SGR. */
1489 void
1490 input_csi_dispatch_sgr(struct input_ctx *ictx)
1492 struct grid_cell *gc = &ictx->cell;
1493 u_int i;
1494 int n, m;
1495 u_char attr;
1497 if (ictx->param_list_len == 0) {
1498 attr = gc->attr;
1499 memcpy(gc, &grid_default_cell, sizeof *gc);
1500 gc->attr |= (attr & GRID_ATTR_CHARSET);
1501 return;
1504 for (i = 0; i < ictx->param_list_len; i++) {
1505 n = input_get(ictx, i, 0, 0);
1507 if (n == 38 || n == 48) {
1508 i++;
1509 if (input_get(ictx, i, 0, -1) != 5)
1510 continue;
1512 i++;
1513 m = input_get(ictx, i, 0, -1);
1514 if (m == -1) {
1515 if (n == 38) {
1516 gc->flags &= ~GRID_FLAG_FG256;
1517 gc->fg = 8;
1518 } else if (n == 48) {
1519 gc->flags &= ~GRID_FLAG_BG256;
1520 gc->bg = 8;
1523 } else {
1524 if (n == 38) {
1525 gc->flags |= GRID_FLAG_FG256;
1526 gc->fg = m;
1527 } else if (n == 48) {
1528 gc->flags |= GRID_FLAG_BG256;
1529 gc->bg = m;
1532 continue;
1535 switch (n) {
1536 case 0:
1537 case 10:
1538 attr = gc->attr;
1539 memcpy(gc, &grid_default_cell, sizeof *gc);
1540 gc->attr |= (attr & GRID_ATTR_CHARSET);
1541 break;
1542 case 1:
1543 gc->attr |= GRID_ATTR_BRIGHT;
1544 break;
1545 case 2:
1546 gc->attr |= GRID_ATTR_DIM;
1547 break;
1548 case 3:
1549 gc->attr |= GRID_ATTR_ITALICS;
1550 break;
1551 case 4:
1552 gc->attr |= GRID_ATTR_UNDERSCORE;
1553 break;
1554 case 5:
1555 gc->attr |= GRID_ATTR_BLINK;
1556 break;
1557 case 7:
1558 gc->attr |= GRID_ATTR_REVERSE;
1559 break;
1560 case 8:
1561 gc->attr |= GRID_ATTR_HIDDEN;
1562 break;
1563 case 22:
1564 gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
1565 break;
1566 case 23:
1567 gc->attr &= ~GRID_ATTR_ITALICS;
1568 break;
1569 case 24:
1570 gc->attr &= ~GRID_ATTR_UNDERSCORE;
1571 break;
1572 case 25:
1573 gc->attr &= ~GRID_ATTR_BLINK;
1574 break;
1575 case 27:
1576 gc->attr &= ~GRID_ATTR_REVERSE;
1577 break;
1578 case 30:
1579 case 31:
1580 case 32:
1581 case 33:
1582 case 34:
1583 case 35:
1584 case 36:
1585 case 37:
1586 gc->flags &= ~GRID_FLAG_FG256;
1587 gc->fg = n - 30;
1588 break;
1589 case 39:
1590 gc->flags &= ~GRID_FLAG_FG256;
1591 gc->fg = 8;
1592 break;
1593 case 40:
1594 case 41:
1595 case 42:
1596 case 43:
1597 case 44:
1598 case 45:
1599 case 46:
1600 case 47:
1601 gc->flags &= ~GRID_FLAG_BG256;
1602 gc->bg = n - 40;
1603 break;
1604 case 49:
1605 gc->flags &= ~GRID_FLAG_BG256;
1606 gc->bg = 8;
1607 break;
1608 case 90:
1609 case 91:
1610 case 92:
1611 case 93:
1612 case 94:
1613 case 95:
1614 case 96:
1615 case 97:
1616 gc->flags &= ~GRID_FLAG_FG256;
1617 gc->fg = n;
1618 break;
1619 case 100:
1620 case 101:
1621 case 102:
1622 case 103:
1623 case 104:
1624 case 105:
1625 case 106:
1626 case 107:
1627 gc->flags &= ~GRID_FLAG_BG256;
1628 gc->bg = n - 10;
1629 break;
1634 /* DCS terminator (ST) received. */
1636 input_dcs_dispatch(struct input_ctx *ictx)
1638 const char prefix[] = "tmux;";
1639 const u_int prefix_len = (sizeof prefix) - 1;
1641 if (ictx->flags & INPUT_DISCARD)
1642 return (0);
1644 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1646 /* Check for tmux prefix. */
1647 if (ictx->input_len >= prefix_len &&
1648 strncmp(ictx->input_buf, prefix, prefix_len) == 0) {
1649 screen_write_rawstring(&ictx->ctx,
1650 ictx->input_buf + prefix_len, ictx->input_len - prefix_len);
1653 return (0);
1656 /* OSC string started. */
1657 void
1658 input_enter_osc(struct input_ctx *ictx)
1660 log_debug("%s", __func__);
1662 input_clear(ictx);
1665 /* OSC terminator (ST) received. */
1666 void
1667 input_exit_osc(struct input_ctx *ictx)
1669 u_char *p = ictx->input_buf;
1670 int option;
1672 if (ictx->flags & INPUT_DISCARD)
1673 return;
1674 if (ictx->input_len < 1 || *p < '0' || *p > '9')
1675 return;
1677 log_debug("%s: \"%s\"", __func__, p);
1679 option = 0;
1680 while (*p >= '0' && *p <= '9')
1681 option = option * 10 + *p++ - '0';
1682 if (*p == ';')
1683 p++;
1685 switch (option) {
1686 case 0:
1687 case 2:
1688 screen_set_title(ictx->ctx.s, p);
1689 server_status_window(ictx->wp->window);
1690 break;
1691 case 12:
1692 if (*p != '?') /* ? is colour request */
1693 screen_set_cursor_colour(ictx->ctx.s, p);
1694 break;
1695 case 112:
1696 if (*p == '\0') /* no arguments allowed */
1697 screen_set_cursor_colour(ictx->ctx.s, "");
1698 break;
1699 default:
1700 log_debug("%s: unknown '%u'", __func__, option);
1701 break;
1705 /* APC string started. */
1706 void
1707 input_enter_apc(struct input_ctx *ictx)
1709 log_debug("%s", __func__);
1711 input_clear(ictx);
1714 /* APC terminator (ST) received. */
1715 void
1716 input_exit_apc(struct input_ctx *ictx)
1718 if (ictx->flags & INPUT_DISCARD)
1719 return;
1720 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1722 screen_set_title(ictx->ctx.s, ictx->input_buf);
1723 server_status_window(ictx->wp->window);
1726 /* Rename string started. */
1727 void
1728 input_enter_rename(struct input_ctx *ictx)
1730 log_debug("%s", __func__);
1732 input_clear(ictx);
1735 /* Rename terminator (ST) received. */
1736 void
1737 input_exit_rename(struct input_ctx *ictx)
1739 if (ictx->flags & INPUT_DISCARD)
1740 return;
1741 if (!options_get_number(&ictx->wp->window->options, "allow-rename"))
1742 return;
1743 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1745 window_set_name(ictx->wp->window, ictx->input_buf);
1746 options_set_number(&ictx->wp->window->options, "automatic-rename", 0);
1748 server_status_window(ictx->wp->window);
1751 /* Open UTF-8 character. */
1753 input_utf8_open(struct input_ctx *ictx)
1755 if (!options_get_number(&ictx->wp->window->options, "utf8")) {
1756 /* Print, and do not switch state. */
1757 input_print(ictx);
1758 return (-1);
1760 log_debug("%s", __func__);
1762 utf8_open(&ictx->utf8data, ictx->ch);
1763 return (0);
1766 /* Append to UTF-8 character. */
1768 input_utf8_add(struct input_ctx *ictx)
1770 log_debug("%s", __func__);
1772 utf8_append(&ictx->utf8data, ictx->ch);
1773 return (0);
1776 /* Close UTF-8 string. */
1778 input_utf8_close(struct input_ctx *ictx)
1780 log_debug("%s", __func__);
1782 utf8_append(&ictx->utf8data, ictx->ch);
1784 grid_cell_set(&ictx->cell, &ictx->utf8data);
1785 screen_write_cell(&ictx->ctx, &ictx->cell);
1787 return (0);