Annotation of src/usr.bin/tmux/input.c, Revision 1.129
1.129 ! nicm 1: /* $OpenBSD: input.c,v 1.128 2017/09/10 08:01:23 nicm Exp $ */
1.1 nicm 2:
3: /*
1.99 nicm 4: * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
1.1 nicm 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:
1.108 nicm 21: #include <netinet/in.h>
22:
23: #include <resolv.h>
1.1 nicm 24: #include <stdlib.h>
25: #include <string.h>
1.79 nicm 26: #include <time.h>
1.1 nicm 27:
28: #include "tmux.h"
29:
1.28 nicm 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.
1.37 nicm 48: *
49: * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to
1.77 nicm 50: * be passed to the underlying terminals.
1.28 nicm 51: */
52:
1.74 nicm 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;
1.127 nicm 90: int last;
1.112 nicm 91:
1.74 nicm 92: int flags;
93: #define INPUT_DISCARD 0x1
94:
95: const struct input_state *state;
96:
1.125 nicm 97: struct event timer;
98:
1.74 nicm 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:
1.28 nicm 106: /* Helper functions. */
1.52 nicm 107: struct input_transition;
1.104 nicm 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 *);
1.28 nicm 114:
1.107 nicm 115: static void input_osc_4(struct window_pane *, const char *);
1.122 nicm 116: static void input_osc_10(struct window_pane *, const char *);
117: static void input_osc_11(struct window_pane *, const char *);
1.108 nicm 118: static void input_osc_52(struct window_pane *, const char *);
1.107 nicm 119: static void input_osc_104(struct window_pane *, const char *);
120:
1.28 nicm 121: /* Transition entry/exit handlers. */
1.104 nicm 122: static void input_clear(struct input_ctx *);
123: static void input_ground(struct input_ctx *);
1.125 nicm 124: static void input_enter_dcs(struct input_ctx *);
1.104 nicm 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 *);
1.28 nicm 131:
132: /* Input state handlers. */
1.104 nicm 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 *);
1.28 nicm 152:
153: /* Command table comparison function. */
1.104 nicm 154: static int input_table_compare(const void *, const void *);
1.28 nicm 155:
156: /* Command table entry. */
157: struct input_table_entry {
158: int ch;
159: const char *interm;
160: int type;
1.1 nicm 161: };
162:
1.28 nicm 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,
1.69 nicm 175: INPUT_ESC_SCSG0_OFF,
176: INPUT_ESC_SCSG0_ON,
177: INPUT_ESC_SCSG1_OFF,
178: INPUT_ESC_SCSG1_ON,
1.107 nicm 179: INPUT_ESC_ST,
1.28 nicm 180: };
1.1 nicm 181:
1.28 nicm 182: /* Escape command table. */
1.104 nicm 183: static const struct input_table_entry input_esc_table[] = {
1.69 nicm 184: { '0', "(", INPUT_ESC_SCSG0_ON },
185: { '0', ")", INPUT_ESC_SCSG1_ON },
1.28 nicm 186: { '7', "", INPUT_ESC_DECSC },
187: { '8', "", INPUT_ESC_DECRC },
188: { '8', "#", INPUT_ESC_DECALN },
189: { '=', "", INPUT_ESC_DECKPAM },
190: { '>', "", INPUT_ESC_DECKPNM },
1.69 nicm 191: { 'B', "(", INPUT_ESC_SCSG0_OFF },
192: { 'B', ")", INPUT_ESC_SCSG1_OFF },
1.28 nicm 193: { 'D', "", INPUT_ESC_IND },
194: { 'E', "", INPUT_ESC_NEL },
195: { 'H', "", INPUT_ESC_HTS },
196: { 'M', "", INPUT_ESC_RI },
1.107 nicm 197: { '\\', "", INPUT_ESC_ST },
1.28 nicm 198: { 'c', "", INPUT_ESC_RIS },
199: };
1.1 nicm 200:
1.28 nicm 201: /* Control (CSI) commands. */
202: enum input_csi_type {
203: INPUT_CSI_CBT,
1.43 nicm 204: INPUT_CSI_CNL,
205: INPUT_CSI_CPL,
1.28 nicm 206: INPUT_CSI_CUB,
207: INPUT_CSI_CUD,
208: INPUT_CSI_CUF,
209: INPUT_CSI_CUP,
210: INPUT_CSI_CUU,
211: INPUT_CSI_DA,
1.50 nicm 212: INPUT_CSI_DA_TWO,
1.28 nicm 213: INPUT_CSI_DCH,
1.39 nicm 214: INPUT_CSI_DECSCUSR,
1.28 nicm 215: INPUT_CSI_DECSTBM,
216: INPUT_CSI_DL,
217: INPUT_CSI_DSR,
1.56 nicm 218: INPUT_CSI_ECH,
1.28 nicm 219: INPUT_CSI_ED,
220: INPUT_CSI_EL,
221: INPUT_CSI_HPA,
222: INPUT_CSI_ICH,
223: INPUT_CSI_IL,
1.42 nicm 224: INPUT_CSI_RCP,
1.127 nicm 225: INPUT_CSI_REP,
1.28 nicm 226: INPUT_CSI_RM,
227: INPUT_CSI_RM_PRIVATE,
1.42 nicm 228: INPUT_CSI_SCP,
1.28 nicm 229: INPUT_CSI_SGR,
230: INPUT_CSI_SM,
231: INPUT_CSI_SM_PRIVATE,
1.115 nicm 232: INPUT_CSI_SU,
1.28 nicm 233: INPUT_CSI_TBC,
234: INPUT_CSI_VPA,
1.65 nicm 235: INPUT_CSI_WINOPS,
1.28 nicm 236: };
1.1 nicm 237:
1.28 nicm 238: /* Control (CSI) command table. */
1.104 nicm 239: static const struct input_table_entry input_csi_table[] = {
1.28 nicm 240: { '@', "", INPUT_CSI_ICH },
241: { 'A', "", INPUT_CSI_CUU },
242: { 'B', "", INPUT_CSI_CUD },
243: { 'C', "", INPUT_CSI_CUF },
244: { 'D', "", INPUT_CSI_CUB },
1.43 nicm 245: { 'E', "", INPUT_CSI_CNL },
246: { 'F', "", INPUT_CSI_CPL },
1.28 nicm 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 },
1.115 nicm 254: { 'S', "", INPUT_CSI_SU },
1.56 nicm 255: { 'X', "", INPUT_CSI_ECH },
1.28 nicm 256: { 'Z', "", INPUT_CSI_CBT },
1.127 nicm 257: { 'b', "", INPUT_CSI_REP },
1.28 nicm 258: { 'c', "", INPUT_CSI_DA },
1.50 nicm 259: { 'c', ">", INPUT_CSI_DA_TWO },
1.28 nicm 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 },
1.39 nicm 269: { 'q', " ", INPUT_CSI_DECSCUSR },
1.28 nicm 270: { 'r', "", INPUT_CSI_DECSTBM },
1.42 nicm 271: { 's', "", INPUT_CSI_SCP },
1.65 nicm 272: { 't', "", INPUT_CSI_WINOPS },
1.42 nicm 273: { 'u', "", INPUT_CSI_RCP },
1.28 nicm 274: };
1.1 nicm 275:
1.28 nicm 276: /* Input transition. */
277: struct input_transition {
278: int first;
279: int last;
1.1 nicm 280:
1.28 nicm 281: int (*handler)(struct input_ctx *);
282: const struct input_state *state;
283: };
1.1 nicm 284:
1.28 nicm 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: };
1.1 nicm 292:
1.28 nicm 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. */
1.104 nicm 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[];
1.28 nicm 320:
321: /* ground state definition. */
1.104 nicm 322: static const struct input_state input_state_ground = {
1.28 nicm 323: "ground",
1.67 nicm 324: input_ground, NULL,
1.28 nicm 325: input_state_ground_table
326: };
1.1 nicm 327:
1.28 nicm 328: /* esc_enter state definition. */
1.104 nicm 329: static const struct input_state input_state_esc_enter = {
1.28 nicm 330: "esc_enter",
331: input_clear, NULL,
332: input_state_esc_enter_table
333: };
1.1 nicm 334:
1.28 nicm 335: /* esc_intermediate state definition. */
1.104 nicm 336: static const struct input_state input_state_esc_intermediate = {
1.28 nicm 337: "esc_intermediate",
338: NULL, NULL,
339: input_state_esc_intermediate_table
340: };
1.1 nicm 341:
1.28 nicm 342: /* csi_enter state definition. */
1.104 nicm 343: static const struct input_state input_state_csi_enter = {
1.28 nicm 344: "csi_enter",
345: input_clear, NULL,
346: input_state_csi_enter_table
347: };
1.1 nicm 348:
1.28 nicm 349: /* csi_parameter state definition. */
1.104 nicm 350: static const struct input_state input_state_csi_parameter = {
1.28 nicm 351: "csi_parameter",
352: NULL, NULL,
353: input_state_csi_parameter_table
354: };
1.1 nicm 355:
1.28 nicm 356: /* csi_intermediate state definition. */
1.104 nicm 357: static const struct input_state input_state_csi_intermediate = {
1.28 nicm 358: "csi_intermediate",
359: NULL, NULL,
360: input_state_csi_intermediate_table
361: };
1.1 nicm 362:
1.28 nicm 363: /* csi_ignore state definition. */
1.104 nicm 364: static const struct input_state input_state_csi_ignore = {
1.28 nicm 365: "csi_ignore",
366: NULL, NULL,
367: input_state_csi_ignore_table
368: };
1.1 nicm 369:
1.28 nicm 370: /* dcs_enter state definition. */
1.104 nicm 371: static const struct input_state input_state_dcs_enter = {
1.28 nicm 372: "dcs_enter",
1.125 nicm 373: input_enter_dcs, NULL,
1.28 nicm 374: input_state_dcs_enter_table
375: };
1.1 nicm 376:
1.28 nicm 377: /* dcs_parameter state definition. */
1.104 nicm 378: static const struct input_state input_state_dcs_parameter = {
1.28 nicm 379: "dcs_parameter",
380: NULL, NULL,
381: input_state_dcs_parameter_table
382: };
1.1 nicm 383:
1.28 nicm 384: /* dcs_intermediate state definition. */
1.104 nicm 385: static const struct input_state input_state_dcs_intermediate = {
1.28 nicm 386: "dcs_intermediate",
387: NULL, NULL,
388: input_state_dcs_intermediate_table
389: };
1.1 nicm 390:
1.28 nicm 391: /* dcs_handler state definition. */
1.104 nicm 392: static const struct input_state input_state_dcs_handler = {
1.28 nicm 393: "dcs_handler",
1.37 nicm 394: NULL, NULL,
1.28 nicm 395: input_state_dcs_handler_table
396: };
1.1 nicm 397:
1.37 nicm 398: /* dcs_escape state definition. */
1.104 nicm 399: static const struct input_state input_state_dcs_escape = {
1.37 nicm 400: "dcs_escape",
401: NULL, NULL,
402: input_state_dcs_escape_table
403: };
404:
1.28 nicm 405: /* dcs_ignore state definition. */
1.104 nicm 406: static const struct input_state input_state_dcs_ignore = {
1.28 nicm 407: "dcs_ignore",
408: NULL, NULL,
409: input_state_dcs_ignore_table
410: };
1.1 nicm 411:
1.28 nicm 412: /* osc_string state definition. */
1.104 nicm 413: static const struct input_state input_state_osc_string = {
1.28 nicm 414: "osc_string",
415: input_enter_osc, input_exit_osc,
416: input_state_osc_string_table
417: };
1.1 nicm 418:
1.28 nicm 419: /* apc_string state definition. */
1.104 nicm 420: static const struct input_state input_state_apc_string = {
1.28 nicm 421: "apc_string",
422: input_enter_apc, input_exit_apc,
423: input_state_apc_string_table
424: };
1.1 nicm 425:
1.28 nicm 426: /* rename_string state definition. */
1.104 nicm 427: static const struct input_state input_state_rename_string = {
1.28 nicm 428: "rename_string",
429: input_enter_rename, input_exit_rename,
430: input_state_rename_string_table
431: };
1.1 nicm 432:
1.28 nicm 433: /* consume_st state definition. */
1.104 nicm 434: static const struct input_state input_state_consume_st = {
1.28 nicm 435: "consume_st",
1.128 nicm 436: input_enter_rename, NULL, /* rename also waits for ST */
1.28 nicm 437: input_state_consume_st_table
438: };
1.1 nicm 439:
1.28 nicm 440: /* utf8_three state definition. */
1.104 nicm 441: static const struct input_state input_state_utf8_three = {
1.28 nicm 442: "utf8_three",
443: NULL, NULL,
444: input_state_utf8_three_table
445: };
1.1 nicm 446:
1.28 nicm 447: /* utf8_two state definition. */
1.104 nicm 448: static const struct input_state input_state_utf8_two = {
1.28 nicm 449: "utf8_two",
450: NULL, NULL,
451: input_state_utf8_two_table
452: };
1.1 nicm 453:
1.28 nicm 454: /* utf8_one state definition. */
1.104 nicm 455: static const struct input_state input_state_utf8_one = {
1.28 nicm 456: "utf8_one",
457: NULL, NULL,
458: input_state_utf8_one_table
459: };
1.1 nicm 460:
1.28 nicm 461: /* ground state table. */
1.104 nicm 462: static const struct input_transition input_state_ground_table[] = {
1.28 nicm 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 },
1.91 nicm 470: { 0x80, 0xc1, NULL, NULL },
1.28 nicm 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 },
1.91 nicm 474: { 0xf5, 0xff, NULL, NULL },
1.1 nicm 475:
1.28 nicm 476: { -1, -1, NULL, NULL }
477: };
1.13 nicm 478:
1.28 nicm 479: /* esc_enter state table. */
1.104 nicm 480: static const struct input_transition input_state_esc_enter_table[] = {
1.28 nicm 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 },
1.29 nicm 500: { 0x6c, 0x7e, input_esc_dispatch, &input_state_ground },
1.28 nicm 501: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 502:
1.28 nicm 503: { -1, -1, NULL, NULL }
504: };
1.1 nicm 505:
1.28 nicm 506: /* esc_interm state table. */
1.104 nicm 507: static const struct input_transition input_state_esc_intermediate_table[] = {
1.28 nicm 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 },
1.1 nicm 516:
1.28 nicm 517: { -1, -1, NULL, NULL }
518: };
1.1 nicm 519:
1.28 nicm 520: /* csi_enter state table. */
1.104 nicm 521: static const struct input_transition input_state_csi_enter_table[] = {
1.28 nicm 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 },
1.1 nicm 534:
1.28 nicm 535: { -1, -1, NULL, NULL }
536: };
1.1 nicm 537:
1.28 nicm 538: /* csi_parameter state table. */
1.104 nicm 539: static const struct input_transition input_state_csi_parameter_table[] = {
1.28 nicm 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 },
1.1 nicm 552:
1.28 nicm 553: { -1, -1, NULL, NULL }
554: };
1.1 nicm 555:
1.28 nicm 556: /* csi_intermediate state table. */
1.104 nicm 557: static const struct input_transition input_state_csi_intermediate_table[] = {
1.28 nicm 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 },
1.1 nicm 567:
1.28 nicm 568: { -1, -1, NULL, NULL }
569: };
1.1 nicm 570:
1.28 nicm 571: /* csi_ignore state table. */
1.104 nicm 572: static const struct input_transition input_state_csi_ignore_table[] = {
1.28 nicm 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 },
1.1 nicm 581:
1.28 nicm 582: { -1, -1, NULL, NULL }
583: };
1.1 nicm 584:
1.28 nicm 585: /* dcs_enter state table. */
1.104 nicm 586: static const struct input_transition input_state_dcs_enter_table[] = {
1.28 nicm 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 },
1.37 nicm 597: { 0x40, 0x7e, input_input, &input_state_dcs_handler },
1.28 nicm 598: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 599:
1.28 nicm 600: { -1, -1, NULL, NULL }
601: };
1.1 nicm 602:
1.28 nicm 603: /* dcs_parameter state table. */
1.104 nicm 604: static const struct input_transition input_state_dcs_parameter_table[] = {
1.28 nicm 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 },
1.37 nicm 615: { 0x40, 0x7e, input_input, &input_state_dcs_handler },
1.28 nicm 616: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 617:
1.28 nicm 618: { -1, -1, NULL, NULL }
619: };
1.1 nicm 620:
1.28 nicm 621: /* dcs_interm state table. */
1.104 nicm 622: static const struct input_transition input_state_dcs_intermediate_table[] = {
1.28 nicm 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 },
1.37 nicm 630: { 0x40, 0x7e, input_input, &input_state_dcs_handler },
1.28 nicm 631: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 632:
1.28 nicm 633: { -1, -1, NULL, NULL }
634: };
1.1 nicm 635:
1.28 nicm 636: /* dcs_handler state table. */
1.104 nicm 637: static const struct input_transition input_state_dcs_handler_table[] = {
1.37 nicm 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. */
1.104 nicm 648: static const struct input_transition input_state_dcs_escape_table[] = {
1.37 nicm 649: /* No INPUT_STATE_ANYWHERE */
1.28 nicm 650:
1.37 nicm 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 },
1.1 nicm 654:
1.28 nicm 655: { -1, -1, NULL, NULL }
656: };
1.1 nicm 657:
1.40 nicm 658: /* dcs_ignore state table. */
1.104 nicm 659: static const struct input_transition input_state_dcs_ignore_table[] = {
1.28 nicm 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 },
1.1 nicm 666:
1.28 nicm 667: { -1, -1, NULL, NULL }
668: };
1.1 nicm 669:
1.28 nicm 670: /* osc_string state table. */
1.104 nicm 671: static const struct input_transition input_state_osc_string_table[] = {
1.28 nicm 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 },
1.1 nicm 680:
1.28 nicm 681: { -1, -1, NULL, NULL }
682: };
1.1 nicm 683:
1.28 nicm 684: /* apc_string state table. */
1.104 nicm 685: static const struct input_transition input_state_apc_string_table[] = {
1.28 nicm 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 },
1.1 nicm 692:
1.28 nicm 693: { -1, -1, NULL, NULL }
694: };
1.1 nicm 695:
1.28 nicm 696: /* rename_string state table. */
1.104 nicm 697: static const struct input_transition input_state_rename_string_table[] = {
1.28 nicm 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 },
1.1 nicm 704:
1.28 nicm 705: { -1, -1, NULL, NULL }
706: };
1.1 nicm 707:
1.28 nicm 708: /* consume_st state table. */
1.104 nicm 709: static const struct input_transition input_state_consume_st_table[] = {
1.28 nicm 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 },
1.6 nicm 716:
1.28 nicm 717: { -1, -1, NULL, NULL }
718: };
1.6 nicm 719:
1.28 nicm 720: /* utf8_three state table. */
1.104 nicm 721: static const struct input_transition input_state_utf8_three_table[] = {
1.28 nicm 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 },
1.4 nicm 727:
1.28 nicm 728: { -1, -1, NULL, NULL }
729: };
1.1 nicm 730:
1.28 nicm 731: /* utf8_two state table. */
1.104 nicm 732: static const struct input_transition input_state_utf8_two_table[] = {
1.28 nicm 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 },
1.1 nicm 738:
1.28 nicm 739: { -1, -1, NULL, NULL }
740: };
1.1 nicm 741:
1.28 nicm 742: /* utf8_one state table. */
1.104 nicm 743: static const struct input_transition input_state_utf8_one_table[] = {
1.28 nicm 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 },
1.1 nicm 749:
1.28 nicm 750: { -1, -1, NULL, NULL }
751: };
1.1 nicm 752:
1.28 nicm 753: /* Input table compare. */
1.104 nicm 754: static int
1.28 nicm 755: input_table_compare(const void *key, const void *value)
1.1 nicm 756: {
1.28 nicm 757: const struct input_ctx *ictx = key;
758: const struct input_table_entry *entry = value;
1.1 nicm 759:
1.28 nicm 760: if (ictx->ch != entry->ch)
761: return (ictx->ch - entry->ch);
762: return (strcmp(ictx->interm_buf, entry->interm));
1.1 nicm 763: }
764:
1.125 nicm 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:
1.69 nicm 789: /* Reset cell state to default. */
1.104 nicm 790: static void
1.69 nicm 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:
1.28 nicm 802: /* Initialise input parser. */
1.1 nicm 803: void
1.28 nicm 804: input_init(struct window_pane *wp)
1.1 nicm 805: {
1.74 nicm 806: struct input_ctx *ictx;
807:
808: ictx = wp->ictx = xcalloc(1, sizeof *ictx);
1.1 nicm 809:
1.67 nicm 810: ictx->input_space = INPUT_BUF_START;
811: ictx->input_buf = xmalloc(INPUT_BUF_START);
812:
1.97 nicm 813: ictx->since_ground = evbuffer_new();
1.52 nicm 814:
1.125 nicm 815: evtimer_set(&ictx->timer, input_timer_callback, ictx);
816:
1.97 nicm 817: input_reset(wp, 0);
1.1 nicm 818: }
819:
1.28 nicm 820: /* Destroy input parser. */
1.1 nicm 821: void
1.52 nicm 822: input_free(struct window_pane *wp)
1.1 nicm 823: {
1.74 nicm 824: struct input_ctx *ictx = wp->ictx;
825:
1.125 nicm 826: event_del(&ictx->timer);
827:
1.74 nicm 828: free(ictx->input_buf);
829: evbuffer_free(ictx->since_ground);
830:
1.106 nicm 831: free(ictx);
1.74 nicm 832: wp->ictx = NULL;
833: }
834:
835: /* Reset input state and clear screen. */
836: void
1.97 nicm 837: input_reset(struct window_pane *wp, int clear)
1.74 nicm 838: {
839: struct input_ctx *ictx = wp->ictx;
1.67 nicm 840:
1.80 nicm 841: input_reset_cell(ictx);
1.74 nicm 842:
1.97 nicm 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:
1.125 nicm 852: input_clear(ictx);
1.97 nicm 853:
1.127 nicm 854: ictx->last = -1;
855:
1.97 nicm 856: ictx->state = &input_state_ground;
857: ictx->flags = 0;
1.74 nicm 858: }
859:
860: /* Return pending data. */
861: struct evbuffer *
862: input_pending(struct window_pane *wp)
863: {
864: return (wp->ictx->since_ground);
1.52 nicm 865: }
866:
867: /* Change input state. */
1.104 nicm 868: static void
1.52 nicm 869: input_set_state(struct window_pane *wp, const struct input_transition *itr)
870: {
1.74 nicm 871: struct input_ctx *ictx = wp->ictx;
1.52 nicm 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);
1.1 nicm 878: }
879:
1.28 nicm 880: /* Parse input. */
1.1 nicm 881: void
1.28 nicm 882: input_parse(struct window_pane *wp)
1.1 nicm 883: {
1.74 nicm 884: struct input_ctx *ictx = wp->ictx;
1.28 nicm 885: const struct input_transition *itr;
886: struct evbuffer *evb = wp->event->input;
887: u_char *buf;
888: size_t len, off;
1.1 nicm 889:
1.28 nicm 890: if (EVBUFFER_LENGTH(evb) == 0)
891: return;
1.82 nicm 892:
1.83 nicm 893: window_update_activity(wp->window);
1.82 nicm 894: wp->flags |= PANE_CHANGED;
1.30 nicm 895:
1.28 nicm 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;
1.7 nicm 905:
1.28 nicm 906: buf = EVBUFFER_DATA(evb);
907: len = EVBUFFER_LENGTH(evb);
1.110 nicm 908: off = 0;
909:
1.54 nicm 910: notify_input(wp, evb);
1.28 nicm 911:
1.86 nicm 912: log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id,
913: ictx->state->name, len, (int)len, buf);
1.84 nicm 914:
1.28 nicm 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)
1.7 nicm 923: break;
1.28 nicm 924: itr++;
1.1 nicm 925: }
1.28 nicm 926: if (itr->first == -1 || itr->last == -1) {
927: /* No transition? Eh? */
1.85 nicm 928: fatalx("no transition from state");
1.3 nicm 929: }
1.1 nicm 930:
931: /*
1.114 nicm 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: /*
1.28 nicm 942: * Execute the handler, if any. Don't switch state if it
943: * returns non-zero.
1.1 nicm 944: */
1.31 nicm 945: if (itr->handler != NULL && itr->handler(ictx) != 0)
1.28 nicm 946: continue;
947:
948: /* And switch state, if necessary. */
1.52 nicm 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);
1.1 nicm 955: }
956:
1.28 nicm 957: /* Close the screen. */
958: screen_write_stop(&ictx->ctx);
1.1 nicm 959:
1.28 nicm 960: evbuffer_drain(evb, len);
1.1 nicm 961: }
962:
1.28 nicm 963: /* Split the parameter list (if any). */
1.104 nicm 964: static int
1.28 nicm 965: input_split(struct input_ctx *ictx)
1.1 nicm 966: {
1.28 nicm 967: const char *errstr;
968: char *ptr, *out;
969: int n;
1.1 nicm 970:
1.28 nicm 971: ictx->param_list_len = 0;
972: if (ictx->param_len == 0)
973: return (0);
1.1 nicm 974:
1.28 nicm 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: }
1.1 nicm 984:
1.28 nicm 985: ictx->param_list[ictx->param_list_len++] = n;
986: if (ictx->param_list_len == nitems(ictx->param_list))
987: return (-1);
988: }
1.1 nicm 989:
1.28 nicm 990: return (0);
1.1 nicm 991: }
992:
1.40 nicm 993: /* Get an argument or return default value. */
1.104 nicm 994: static int
1.28 nicm 995: input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
1.1 nicm 996: {
1.28 nicm 997: int retval;
1.1 nicm 998:
1.28 nicm 999: if (validx >= ictx->param_list_len)
1000: return (defval);
1.1 nicm 1001:
1.28 nicm 1002: retval = ictx->param_list[validx];
1003: if (retval == -1)
1004: return (defval);
1005: if (retval < minval)
1006: return (minval);
1007: return (retval);
1.1 nicm 1008: }
1009:
1.28 nicm 1010: /* Reply to terminal query. */
1.104 nicm 1011: static void
1.28 nicm 1012: input_reply(struct input_ctx *ictx, const char *fmt, ...)
1.1 nicm 1013: {
1.28 nicm 1014: va_list ap;
1015: char *reply;
1.1 nicm 1016:
1.28 nicm 1017: va_start(ap, fmt);
1.103 nicm 1018: xvasprintf(&reply, fmt, ap);
1.28 nicm 1019: va_end(ap);
1.1 nicm 1020:
1.28 nicm 1021: bufferevent_write(ictx->wp->event, reply, strlen(reply));
1.53 nicm 1022: free(reply);
1.8 nicm 1023: }
1024:
1.28 nicm 1025: /* Clear saved state. */
1.104 nicm 1026: static void
1.28 nicm 1027: input_clear(struct input_ctx *ictx)
1.8 nicm 1028: {
1.125 nicm 1029: event_del(&ictx->timer);
1030:
1.28 nicm 1031: *ictx->interm_buf = '\0';
1032: ictx->interm_len = 0;
1.8 nicm 1033:
1.28 nicm 1034: *ictx->param_buf = '\0';
1035: ictx->param_len = 0;
1.8 nicm 1036:
1.35 nicm 1037: *ictx->input_buf = '\0';
1038: ictx->input_len = 0;
1039:
1.28 nicm 1040: ictx->flags &= ~INPUT_DISCARD;
1.14 nicm 1041: }
1042:
1.67 nicm 1043: /* Reset for ground state. */
1.104 nicm 1044: static void
1.67 nicm 1045: input_ground(struct input_ctx *ictx)
1046: {
1.125 nicm 1047: event_del(&ictx->timer);
1.67 nicm 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;
1.71 nicm 1052: ictx->input_buf = xrealloc(ictx->input_buf, INPUT_BUF_START);
1.67 nicm 1053: }
1054: }
1055:
1.28 nicm 1056: /* Output this character to the screen. */
1.104 nicm 1057: static int
1.28 nicm 1058: input_print(struct input_ctx *ictx)
1.14 nicm 1059: {
1.69 nicm 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:
1.89 nicm 1068: utf8_set(&ictx->cell.cell.data, ictx->ch);
1.114 nicm 1069: screen_write_collect_add(&ictx->ctx, &ictx->cell.cell);
1.127 nicm 1070: ictx->last = ictx->ch;
1.69 nicm 1071:
1072: ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
1.14 nicm 1073:
1.28 nicm 1074: return (0);
1.1 nicm 1075: }
1076:
1.28 nicm 1077: /* Collect intermediate string. */
1.104 nicm 1078: static int
1.28 nicm 1079: input_intermediate(struct input_ctx *ictx)
1.1 nicm 1080: {
1.28 nicm 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: }
1.1 nicm 1087:
1.28 nicm 1088: return (0);
1.1 nicm 1089: }
1090:
1.28 nicm 1091: /* Collect parameter string. */
1.104 nicm 1092: static int
1.28 nicm 1093: input_parameter(struct input_ctx *ictx)
1.1 nicm 1094: {
1.28 nicm 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: }
1.1 nicm 1101:
1.28 nicm 1102: return (0);
1.1 nicm 1103: }
1104:
1.28 nicm 1105: /* Collect input string. */
1.104 nicm 1106: static int
1.28 nicm 1107: input_input(struct input_ctx *ictx)
1.1 nicm 1108: {
1.67 nicm 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: }
1.71 nicm 1118: ictx->input_buf = xrealloc(ictx->input_buf, available);
1.67 nicm 1119: ictx->input_space = available;
1.28 nicm 1120: }
1.67 nicm 1121: ictx->input_buf[ictx->input_len++] = ictx->ch;
1122: ictx->input_buf[ictx->input_len] = '\0';
1.1 nicm 1123:
1.28 nicm 1124: return (0);
1.1 nicm 1125: }
1126:
1.28 nicm 1127: /* Execute C0 control sequence. */
1.104 nicm 1128: static int
1.28 nicm 1129: input_c0_dispatch(struct input_ctx *ictx)
1.1 nicm 1130: {
1.28 nicm 1131: struct screen_write_ctx *sctx = &ictx->ctx;
1132: struct window_pane *wp = ictx->wp;
1133: struct screen *s = sctx->s;
1.1 nicm 1134:
1.84 nicm 1135: log_debug("%s: '%c'", __func__, ictx->ch);
1.1 nicm 1136:
1.28 nicm 1137: switch (ictx->ch) {
1138: case '\000': /* NUL */
1139: break;
1140: case '\007': /* BEL */
1.83 nicm 1141: alerts_queue(wp->window, WINDOW_BELL);
1.28 nicm 1142: break;
1143: case '\010': /* BS */
1144: screen_write_backspace(sctx);
1.75 nicm 1145: break;
1.28 nicm 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;
1.1 nicm 1150:
1.28 nicm 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 */
1.121 nicm 1161: screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1.75 nicm 1162: break;
1.28 nicm 1163: case '\015': /* CR */
1164: screen_write_carriagereturn(sctx);
1.75 nicm 1165: break;
1.28 nicm 1166: case '\016': /* SO */
1.69 nicm 1167: ictx->cell.set = 1;
1.28 nicm 1168: break;
1169: case '\017': /* SI */
1.69 nicm 1170: ictx->cell.set = 0;
1.28 nicm 1171: break;
1172: default:
1173: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1174: break;
1175: }
1.1 nicm 1176:
1.127 nicm 1177: ictx->last = -1;
1.28 nicm 1178: return (0);
1.7 nicm 1179: }
1180:
1.28 nicm 1181: /* Execute escape sequence. */
1.104 nicm 1182: static int
1.28 nicm 1183: input_esc_dispatch(struct input_ctx *ictx)
1.7 nicm 1184: {
1.31 nicm 1185: struct screen_write_ctx *sctx = &ictx->ctx;
1186: struct screen *s = sctx->s;
1187: struct input_table_entry *entry;
1.7 nicm 1188:
1.28 nicm 1189: if (ictx->flags & INPUT_DISCARD)
1190: return (0);
1191: log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
1.7 nicm 1192:
1.28 nicm 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: }
1.7 nicm 1199:
1.28 nicm 1200: switch (entry->type) {
1201: case INPUT_ESC_RIS:
1.107 nicm 1202: window_pane_reset_palette(ictx->wp);
1.69 nicm 1203: input_reset_cell(ictx);
1.46 nicm 1204: screen_write_reset(sctx);
1.28 nicm 1205: break;
1206: case INPUT_ESC_IND:
1.121 nicm 1207: screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1.28 nicm 1208: break;
1209: case INPUT_ESC_NEL:
1210: screen_write_carriagereturn(sctx);
1.121 nicm 1211: screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1.28 nicm 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:
1.121 nicm 1218: screen_write_reverseindex(sctx, ictx->cell.cell.bg);
1.28 nicm 1219: break;
1220: case INPUT_ESC_DECKPAM:
1.59 nicm 1221: screen_write_mode_set(sctx, MODE_KKEYPAD);
1.28 nicm 1222: break;
1223: case INPUT_ESC_DECKPNM:
1.59 nicm 1224: screen_write_mode_clear(sctx, MODE_KKEYPAD);
1.1 nicm 1225: break;
1.28 nicm 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;
1.69 nicm 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;
1.1 nicm 1246: break;
1.69 nicm 1247: case INPUT_ESC_SCSG1_OFF:
1248: ictx->cell.g1set = 0;
1.1 nicm 1249: break;
1.107 nicm 1250: case INPUT_ESC_ST:
1251: /* ST terminates OSC but the state transition already did it. */
1252: break;
1.1 nicm 1253: }
1.28 nicm 1254:
1.127 nicm 1255: ictx->last = -1;
1.28 nicm 1256: return (0);
1.1 nicm 1257: }
1258:
1.28 nicm 1259: /* Execute control sequence. */
1.104 nicm 1260: static int
1.28 nicm 1261: input_csi_dispatch(struct input_ctx *ictx)
1.1 nicm 1262: {
1.28 nicm 1263: struct screen_write_ctx *sctx = &ictx->ctx;
1264: struct screen *s = sctx->s;
1265: struct input_table_entry *entry;
1.127 nicm 1266: int i, n, m;
1.81 nicm 1267: u_int cx;
1.1 nicm 1268:
1.28 nicm 1269: if (ictx->flags & INPUT_DISCARD)
1270: return (0);
1.110 nicm 1271:
1272: log_debug("%s: '%c' \"%s\" \"%s\"",
1273: __func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
1274:
1.28 nicm 1275: if (input_split(ictx) != 0)
1276: return (0);
1.1 nicm 1277:
1.28 nicm 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: }
1.1 nicm 1284:
1.28 nicm 1285: switch (entry->type) {
1286: case INPUT_CSI_CBT:
1287: /* Find the previous tab point, n times. */
1.81 nicm 1288: cx = s->cx;
1289: if (cx > screen_size_x(s) - 1)
1290: cx = screen_size_x(s) - 1;
1.28 nicm 1291: n = input_get(ictx, 0, 1, 1);
1.81 nicm 1292: while (cx > 0 && n-- > 0) {
1.28 nicm 1293: do
1.81 nicm 1294: cx--;
1295: while (cx > 0 && !bit_test(s->tabs, cx));
1.28 nicm 1296: }
1.81 nicm 1297: s->cx = cx;
1.28 nicm 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;
1.65 nicm 1313: case INPUT_CSI_WINOPS:
1314: input_csi_dispatch_winops(ictx);
1315: break;
1.28 nicm 1316: case INPUT_CSI_CUU:
1.43 nicm 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);
1.28 nicm 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");
1.50 nicm 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:
1.66 nicm 1340: input_reply(ictx, "\033[>84;0;0c");
1.28 nicm 1341: break;
1342: default:
1343: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1344: break;
1345: }
1.56 nicm 1346: break;
1347: case INPUT_CSI_ECH:
1.120 nicm 1348: screen_write_clearcharacter(sctx, input_get(ictx, 0, 1, 1),
1349: ictx->cell.cell.bg);
1.28 nicm 1350: break;
1351: case INPUT_CSI_DCH:
1.105 nicm 1352: screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1),
1353: ictx->cell.cell.bg);
1.28 nicm 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);
1.1 nicm 1359: break;
1.28 nicm 1360: case INPUT_CSI_DL:
1.105 nicm 1361: screen_write_deleteline(sctx, input_get(ictx, 0, 1, 1),
1362: ictx->cell.cell.bg);
1.1 nicm 1363: break;
1.28 nicm 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:
1.105 nicm 1380: screen_write_clearendofscreen(sctx, ictx->cell.cell.bg);
1.28 nicm 1381: break;
1382: case 1:
1.111 nicm 1383: screen_write_clearstartofscreen(sctx, ictx->cell.cell.bg);
1.28 nicm 1384: break;
1385: case 2:
1.105 nicm 1386: screen_write_clearscreen(sctx, ictx->cell.cell.bg);
1.41 nicm 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: }
1.28 nicm 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:
1.105 nicm 1407: screen_write_clearendofline(sctx, ictx->cell.cell.bg);
1.28 nicm 1408: break;
1409: case 1:
1.105 nicm 1410: screen_write_clearstartofline(sctx, ictx->cell.cell.bg);
1.28 nicm 1411: break;
1412: case 2:
1.105 nicm 1413: screen_write_clearline(sctx, ictx->cell.cell.bg);
1.28 nicm 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:
1.105 nicm 1425: screen_write_insertcharacter(sctx, input_get(ictx, 0, 1, 1),
1426: ictx->cell.cell.bg);
1.28 nicm 1427: break;
1428: case INPUT_CSI_IL:
1.105 nicm 1429: screen_write_insertline(sctx, input_get(ictx, 0, 1, 1),
1.116 nicm 1430: ictx->cell.cell.bg);
1.28 nicm 1431: break;
1.127 nicm 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;
1.42 nicm 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;
1.28 nicm 1445: case INPUT_CSI_RM:
1.64 nicm 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);
1.115 nicm 1464: break;
1465: case INPUT_CSI_SU:
1.121 nicm 1466: screen_write_scrollup(sctx, input_get(ictx, 0, 1, 1),
1467: ictx->cell.cell.bg);
1.64 nicm 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:
1.127 nicm 1493: ictx->last = -1;
1.64 nicm 1494: return (0);
1495: }
1496:
1497: /* Handle CSI RM. */
1.104 nicm 1498: static void
1.64 nicm 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)) {
1.28 nicm 1505: case 4: /* IRM */
1.59 nicm 1506: screen_write_mode_clear(&ictx->ctx, MODE_INSERT);
1.28 nicm 1507: break;
1.72 nicm 1508: case 34:
1509: screen_write_mode_set(&ictx->ctx, MODE_BLINKING);
1510: break;
1.28 nicm 1511: default:
1512: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1513: break;
1514: }
1.64 nicm 1515: }
1516: }
1517:
1518: /* Handle CSI private RM. */
1.104 nicm 1519: static void
1.64 nicm 1520: input_csi_dispatch_rm_private(struct input_ctx *ictx)
1521: {
1.69 nicm 1522: struct window_pane *wp = ictx->wp;
1523: u_int i;
1.64 nicm 1524:
1525: for (i = 0; i < ictx->param_list_len; i++) {
1526: switch (input_get(ictx, i, 0, -1)) {
1527: case 1: /* DECCKM */
1.59 nicm 1528: screen_write_mode_clear(&ictx->ctx, MODE_KCURSOR);
1.1 nicm 1529: break;
1.17 nicm 1530: case 3: /* DECCOLM */
1.24 nicm 1531: screen_write_cursormove(&ictx->ctx, 0, 0);
1.105 nicm 1532: screen_write_clearscreen(&ictx->ctx,
1533: ictx->cell.cell.bg);
1.17 nicm 1534: break;
1.61 nicm 1535: case 7: /* DECAWM */
1536: screen_write_mode_clear(&ictx->ctx, MODE_WRAP);
1537: break;
1.72 nicm 1538: case 12:
1539: screen_write_mode_clear(&ictx->ctx, MODE_BLINKING);
1540: break;
1.1 nicm 1541: case 25: /* TCEM */
1.59 nicm 1542: screen_write_mode_clear(&ictx->ctx, MODE_CURSOR);
1.1 nicm 1543: break;
1544: case 1000:
1.32 nicm 1545: case 1001:
1546: case 1002:
1.109 nicm 1547: case 1003:
1.59 nicm 1548: screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
1.1 nicm 1549: break;
1.62 nicm 1550: case 1004:
1551: screen_write_mode_clear(&ictx->ctx, MODE_FOCUSON);
1552: break;
1.96 nicm 1553: case 1005:
1554: screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_UTF8);
1555: break;
1.60 nicm 1556: case 1006:
1557: screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_SGR);
1558: break;
1.55 nicm 1559: case 47:
1560: case 1047:
1.69 nicm 1561: window_pane_alternate_off(wp, &ictx->cell.cell, 0);
1.55 nicm 1562: break;
1.9 nicm 1563: case 1049:
1.69 nicm 1564: window_pane_alternate_off(wp, &ictx->cell.cell, 1);
1.9 nicm 1565: break;
1.49 nicm 1566: case 2004:
1.59 nicm 1567: screen_write_mode_clear(&ictx->ctx, MODE_BRACKETPASTE);
1.49 nicm 1568: break;
1.1 nicm 1569: default:
1.28 nicm 1570: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1571: break;
1572: }
1.64 nicm 1573: }
1574: }
1575:
1576: /* Handle CSI SM. */
1.104 nicm 1577: static void
1.64 nicm 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)) {
1.1 nicm 1584: case 4: /* IRM */
1.59 nicm 1585: screen_write_mode_set(&ictx->ctx, MODE_INSERT);
1.1 nicm 1586: break;
1.72 nicm 1587: case 34:
1588: screen_write_mode_clear(&ictx->ctx, MODE_BLINKING);
1589: break;
1.1 nicm 1590: default:
1.28 nicm 1591: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1592: break;
1593: }
1.64 nicm 1594: }
1595: }
1596:
1597: /* Handle CSI private SM. */
1.104 nicm 1598: static void
1.64 nicm 1599: input_csi_dispatch_sm_private(struct input_ctx *ictx)
1600: {
1.69 nicm 1601: struct window_pane *wp = ictx->wp;
1602: u_int i;
1.64 nicm 1603:
1604: for (i = 0; i < ictx->param_list_len; i++) {
1605: switch (input_get(ictx, i, 0, -1)) {
1606: case 1: /* DECCKM */
1.59 nicm 1607: screen_write_mode_set(&ictx->ctx, MODE_KCURSOR);
1.17 nicm 1608: break;
1609: case 3: /* DECCOLM */
1.24 nicm 1610: screen_write_cursormove(&ictx->ctx, 0, 0);
1.105 nicm 1611: screen_write_clearscreen(&ictx->ctx,
1612: ictx->cell.cell.bg);
1.61 nicm 1613: break;
1614: case 7: /* DECAWM */
1615: screen_write_mode_set(&ictx->ctx, MODE_WRAP);
1.72 nicm 1616: break;
1617: case 12:
1618: screen_write_mode_set(&ictx->ctx, MODE_BLINKING);
1.1 nicm 1619: break;
1620: case 25: /* TCEM */
1.59 nicm 1621: screen_write_mode_set(&ictx->ctx, MODE_CURSOR);
1.1 nicm 1622: break;
1623: case 1000:
1.59 nicm 1624: screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
1625: screen_write_mode_set(&ictx->ctx, MODE_MOUSE_STANDARD);
1.32 nicm 1626: break;
1627: case 1002:
1.59 nicm 1628: screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
1629: screen_write_mode_set(&ictx->ctx, MODE_MOUSE_BUTTON);
1.109 nicm 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);
1.62 nicm 1634: break;
1635: case 1004:
1.64 nicm 1636: if (ictx->ctx.s->mode & MODE_FOCUSON)
1.62 nicm 1637: break;
1638: screen_write_mode_set(&ictx->ctx, MODE_FOCUSON);
1.69 nicm 1639: wp->flags |= PANE_FOCUSPUSH; /* force update */
1.96 nicm 1640: break;
1641: case 1005:
1642: screen_write_mode_set(&ictx->ctx, MODE_MOUSE_UTF8);
1.60 nicm 1643: break;
1644: case 1006:
1645: screen_write_mode_set(&ictx->ctx, MODE_MOUSE_SGR);
1.9 nicm 1646: break;
1.55 nicm 1647: case 47:
1648: case 1047:
1.69 nicm 1649: window_pane_alternate_on(wp, &ictx->cell.cell, 0);
1.55 nicm 1650: break;
1.9 nicm 1651: case 1049:
1.69 nicm 1652: window_pane_alternate_on(wp, &ictx->cell.cell, 1);
1.49 nicm 1653: break;
1654: case 2004:
1.59 nicm 1655: screen_write_mode_set(&ictx->ctx, MODE_BRACKETPASTE);
1.1 nicm 1656: break;
1657: default:
1.28 nicm 1658: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1659: break;
1660: }
1.65 nicm 1661: }
1662: }
1663:
1664: /* Handle CSI window operations. */
1.104 nicm 1665: static void
1.65 nicm 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:
1.129 ! nicm 1696: m++;
! 1697: if (input_get(ictx, m, 0, -1) == -1)
! 1698: return;
! 1699: break;
1.65 nicm 1700: case 22:
1.129 ! nicm 1701: m++;
! 1702: switch (input_get(ictx, m, 0, -1)) {
! 1703: case -1:
! 1704: return;
! 1705: case 0:
! 1706: case 2:
! 1707: screen_push_title(ictx->ctx.s);
! 1708: break;
! 1709: }
! 1710: break;
1.65 nicm 1711: case 23:
1712: m++;
1.129 ! nicm 1713: switch (input_get(ictx, m, 0, -1)) {
! 1714: case -1:
1.65 nicm 1715: return;
1.129 ! nicm 1716: case 0:
! 1717: case 2:
! 1718: screen_pop_title(ictx->ctx.s);
! 1719: server_status_window(ictx->wp->window);
! 1720: break;
! 1721: }
1.65 nicm 1722: break;
1723: case 18:
1.76 nicm 1724: input_reply(ictx, "\033[8;%u;%ut", wp->sy, wp->sx);
1.65 nicm 1725: break;
1726: default:
1727: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1728: break;
1729: }
1730: m++;
1.1 nicm 1731: }
1732: }
1733:
1.78 nicm 1734: /* Handle CSI SGR for 256 colours. */
1.104 nicm 1735: static void
1.78 nicm 1736: input_csi_dispatch_sgr_256(struct input_ctx *ictx, int fgbg, u_int *i)
1737: {
1738: struct grid_cell *gc = &ictx->cell.cell;
1739: int c;
1740:
1741: (*i)++;
1742: c = input_get(ictx, *i, 0, -1);
1743: if (c == -1) {
1.102 nicm 1744: if (fgbg == 38)
1.78 nicm 1745: gc->fg = 8;
1.102 nicm 1746: else if (fgbg == 48)
1.78 nicm 1747: gc->bg = 8;
1748: } else {
1.102 nicm 1749: if (fgbg == 38)
1750: gc->fg = c | COLOUR_FLAG_256;
1751: else if (fgbg == 48)
1752: gc->bg = c | COLOUR_FLAG_256;
1.78 nicm 1753: }
1754: }
1755:
1756: /* Handle CSI SGR for RGB colours. */
1.104 nicm 1757: static void
1.78 nicm 1758: input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i)
1759: {
1760: struct grid_cell *gc = &ictx->cell.cell;
1.100 nicm 1761: int r, g, b;
1.78 nicm 1762:
1763: (*i)++;
1764: r = input_get(ictx, *i, 0, -1);
1765: if (r == -1 || r > 255)
1766: return;
1767: (*i)++;
1768: g = input_get(ictx, *i, 0, -1);
1769: if (g == -1 || g > 255)
1770: return;
1771: (*i)++;
1772: b = input_get(ictx, *i, 0, -1);
1773: if (b == -1 || b > 255)
1774: return;
1775:
1.102 nicm 1776: if (fgbg == 38)
1777: gc->fg = colour_join_rgb(r, g, b);
1778: else if (fgbg == 48)
1779: gc->bg = colour_join_rgb(r, g, b);
1.78 nicm 1780: }
1781:
1.28 nicm 1782: /* Handle CSI SGR. */
1.104 nicm 1783: static void
1.28 nicm 1784: input_csi_dispatch_sgr(struct input_ctx *ictx)
1.1 nicm 1785: {
1.69 nicm 1786: struct grid_cell *gc = &ictx->cell.cell;
1.28 nicm 1787: u_int i;
1.78 nicm 1788: int n;
1.1 nicm 1789:
1.28 nicm 1790: if (ictx->param_list_len == 0) {
1.1 nicm 1791: memcpy(gc, &grid_default_cell, sizeof *gc);
1792: return;
1793: }
1794:
1.28 nicm 1795: for (i = 0; i < ictx->param_list_len; i++) {
1796: n = input_get(ictx, i, 0, 0);
1.1 nicm 1797:
1.28 nicm 1798: if (n == 38 || n == 48) {
1.1 nicm 1799: i++;
1.78 nicm 1800: switch (input_get(ictx, i, 0, -1)) {
1801: case 2:
1802: input_csi_dispatch_sgr_rgb(ictx, n, &i);
1803: break;
1804: case 5:
1805: input_csi_dispatch_sgr_256(ictx, n, &i);
1806: break;
1.1 nicm 1807: }
1808: continue;
1809: }
1810:
1.28 nicm 1811: switch (n) {
1.1 nicm 1812: case 0:
1813: case 10:
1814: memcpy(gc, &grid_default_cell, sizeof *gc);
1815: break;
1816: case 1:
1817: gc->attr |= GRID_ATTR_BRIGHT;
1818: break;
1819: case 2:
1820: gc->attr |= GRID_ATTR_DIM;
1821: break;
1822: case 3:
1823: gc->attr |= GRID_ATTR_ITALICS;
1824: break;
1825: case 4:
1826: gc->attr |= GRID_ATTR_UNDERSCORE;
1827: break;
1828: case 5:
1829: gc->attr |= GRID_ATTR_BLINK;
1830: break;
1831: case 7:
1832: gc->attr |= GRID_ATTR_REVERSE;
1833: break;
1834: case 8:
1835: gc->attr |= GRID_ATTR_HIDDEN;
1836: break;
1.118 nicm 1837: case 9:
1838: gc->attr |= GRID_ATTR_STRIKETHROUGH;
1839: break;
1.1 nicm 1840: case 22:
1841: gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
1842: break;
1843: case 23:
1844: gc->attr &= ~GRID_ATTR_ITALICS;
1845: break;
1846: case 24:
1847: gc->attr &= ~GRID_ATTR_UNDERSCORE;
1848: break;
1849: case 25:
1850: gc->attr &= ~GRID_ATTR_BLINK;
1851: break;
1852: case 27:
1853: gc->attr &= ~GRID_ATTR_REVERSE;
1.117 nicm 1854: break;
1855: case 28:
1856: gc->attr &= ~GRID_ATTR_HIDDEN;
1.118 nicm 1857: break;
1858: case 29:
1859: gc->attr &= ~GRID_ATTR_STRIKETHROUGH;
1.1 nicm 1860: break;
1861: case 30:
1862: case 31:
1863: case 32:
1864: case 33:
1865: case 34:
1866: case 35:
1867: case 36:
1868: case 37:
1.28 nicm 1869: gc->fg = n - 30;
1.1 nicm 1870: break;
1871: case 39:
1872: gc->fg = 8;
1873: break;
1874: case 40:
1875: case 41:
1876: case 42:
1877: case 43:
1878: case 44:
1879: case 45:
1880: case 46:
1881: case 47:
1.28 nicm 1882: gc->bg = n - 40;
1.1 nicm 1883: break;
1884: case 49:
1885: gc->bg = 8;
1.20 nicm 1886: break;
1887: case 90:
1888: case 91:
1889: case 92:
1890: case 93:
1891: case 94:
1892: case 95:
1893: case 96:
1894: case 97:
1.28 nicm 1895: gc->fg = n;
1.20 nicm 1896: break;
1897: case 100:
1898: case 101:
1899: case 102:
1900: case 103:
1901: case 104:
1902: case 105:
1903: case 106:
1904: case 107:
1.47 nicm 1905: gc->bg = n - 10;
1.1 nicm 1906: break;
1907: }
1908: }
1.28 nicm 1909: }
1910:
1.125 nicm 1911: /* DCS string started. */
1912: static void
1913: input_enter_dcs(struct input_ctx *ictx)
1914: {
1915: log_debug("%s", __func__);
1916:
1917: input_clear(ictx);
1918: input_start_timer(ictx);
1.127 nicm 1919: ictx->last = -1;
1.125 nicm 1920: }
1921:
1.37 nicm 1922: /* DCS terminator (ST) received. */
1.104 nicm 1923: static int
1.37 nicm 1924: input_dcs_dispatch(struct input_ctx *ictx)
1.28 nicm 1925: {
1.37 nicm 1926: const char prefix[] = "tmux;";
1927: const u_int prefix_len = (sizeof prefix) - 1;
1928:
1929: if (ictx->flags & INPUT_DISCARD)
1930: return (0);
1931:
1932: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1.28 nicm 1933:
1.37 nicm 1934: /* Check for tmux prefix. */
1935: if (ictx->input_len >= prefix_len &&
1936: strncmp(ictx->input_buf, prefix, prefix_len) == 0) {
1937: screen_write_rawstring(&ictx->ctx,
1938: ictx->input_buf + prefix_len, ictx->input_len - prefix_len);
1939: }
1.28 nicm 1940:
1.37 nicm 1941: return (0);
1.28 nicm 1942: }
1943:
1944: /* OSC string started. */
1.104 nicm 1945: static void
1.28 nicm 1946: input_enter_osc(struct input_ctx *ictx)
1947: {
1948: log_debug("%s", __func__);
1949:
1.35 nicm 1950: input_clear(ictx);
1.125 nicm 1951: input_start_timer(ictx);
1.127 nicm 1952: ictx->last = -1;
1.28 nicm 1953: }
1954:
1955: /* OSC terminator (ST) received. */
1.104 nicm 1956: static void
1.28 nicm 1957: input_exit_osc(struct input_ctx *ictx)
1958: {
1.67 nicm 1959: u_char *p = ictx->input_buf;
1.73 nicm 1960: u_int option;
1.38 nicm 1961:
1.28 nicm 1962: if (ictx->flags & INPUT_DISCARD)
1963: return;
1.38 nicm 1964: if (ictx->input_len < 1 || *p < '0' || *p > '9')
1965: return;
1.28 nicm 1966:
1.38 nicm 1967: log_debug("%s: \"%s\"", __func__, p);
1.28 nicm 1968:
1.38 nicm 1969: option = 0;
1970: while (*p >= '0' && *p <= '9')
1971: option = option * 10 + *p++ - '0';
1972: if (*p == ';')
1973: p++;
1974:
1975: switch (option) {
1976: case 0:
1977: case 2:
1.124 nicm 1978: if (utf8_isvalid(p)) {
1979: screen_set_title(ictx->ctx.s, p);
1980: server_status_window(ictx->wp->window);
1981: }
1.38 nicm 1982: break;
1.107 nicm 1983: case 4:
1984: input_osc_4(ictx->wp, p);
1985: break;
1.122 nicm 1986: case 10:
1987: input_osc_10(ictx->wp, p);
1988: break;
1989: case 11:
1990: input_osc_11(ictx->wp, p);
1.108 nicm 1991: break;
1.38 nicm 1992: case 12:
1.124 nicm 1993: if (utf8_isvalid(p) && *p != '?') /* ? is colour request */
1.57 nicm 1994: screen_set_cursor_colour(ictx->ctx.s, p);
1.38 nicm 1995: break;
1.122 nicm 1996: case 52:
1997: input_osc_52(ictx->wp, p);
1998: break;
1.107 nicm 1999: case 104:
2000: input_osc_104(ictx->wp, p);
2001: break;
1.38 nicm 2002: case 112:
1.57 nicm 2003: if (*p == '\0') /* no arguments allowed */
1.38 nicm 2004: screen_set_cursor_colour(ictx->ctx.s, "");
2005: break;
2006: default:
2007: log_debug("%s: unknown '%u'", __func__, option);
2008: break;
2009: }
1.28 nicm 2010: }
2011:
2012: /* APC string started. */
1.104 nicm 2013: static void
1.28 nicm 2014: input_enter_apc(struct input_ctx *ictx)
2015: {
2016: log_debug("%s", __func__);
2017:
1.35 nicm 2018: input_clear(ictx);
1.125 nicm 2019: input_start_timer(ictx);
1.127 nicm 2020: ictx->last = -1;
1.28 nicm 2021: }
2022:
2023: /* APC terminator (ST) received. */
1.104 nicm 2024: static void
1.28 nicm 2025: input_exit_apc(struct input_ctx *ictx)
2026: {
2027: if (ictx->flags & INPUT_DISCARD)
2028: return;
2029: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
2030:
1.124 nicm 2031: if (!utf8_isvalid(ictx->input_buf))
2032: return;
1.28 nicm 2033: screen_set_title(ictx->ctx.s, ictx->input_buf);
2034: server_status_window(ictx->wp->window);
2035: }
2036:
2037: /* Rename string started. */
1.104 nicm 2038: static void
1.28 nicm 2039: input_enter_rename(struct input_ctx *ictx)
2040: {
2041: log_debug("%s", __func__);
2042:
1.35 nicm 2043: input_clear(ictx);
1.125 nicm 2044: input_start_timer(ictx);
1.127 nicm 2045: ictx->last = -1;
1.28 nicm 2046: }
2047:
2048: /* Rename terminator (ST) received. */
1.104 nicm 2049: static void
1.28 nicm 2050: input_exit_rename(struct input_ctx *ictx)
2051: {
2052: if (ictx->flags & INPUT_DISCARD)
1.44 nicm 2053: return;
1.87 nicm 2054: if (!options_get_number(ictx->wp->window->options, "allow-rename"))
1.28 nicm 2055: return;
2056: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
2057:
1.124 nicm 2058: if (!utf8_isvalid(ictx->input_buf))
2059: return;
1.48 nicm 2060: window_set_name(ictx->wp->window, ictx->input_buf);
1.87 nicm 2061: options_set_number(ictx->wp->window->options, "automatic-rename", 0);
1.28 nicm 2062: server_status_window(ictx->wp->window);
2063: }
2064:
2065: /* Open UTF-8 character. */
1.104 nicm 2066: static int
1.28 nicm 2067: input_utf8_open(struct input_ctx *ictx)
2068: {
1.90 nicm 2069: struct utf8_data *ud = &ictx->utf8data;
2070:
1.92 nicm 2071: if (utf8_open(ud, ictx->ch) != UTF8_MORE)
1.94 nicm 2072: fatalx("UTF-8 open invalid %#x", ictx->ch);
1.90 nicm 2073:
2074: log_debug("%s %hhu", __func__, ud->size);
1.127 nicm 2075: ictx->last = -1;
1.28 nicm 2076:
2077: return (0);
2078: }
2079:
2080: /* Append to UTF-8 character. */
1.104 nicm 2081: static int
1.28 nicm 2082: input_utf8_add(struct input_ctx *ictx)
2083: {
1.90 nicm 2084: struct utf8_data *ud = &ictx->utf8data;
2085:
1.92 nicm 2086: if (utf8_append(ud, ictx->ch) != UTF8_MORE)
1.94 nicm 2087: fatalx("UTF-8 add invalid %#x", ictx->ch);
1.90 nicm 2088:
1.28 nicm 2089: log_debug("%s", __func__);
2090:
2091: return (0);
2092: }
2093:
2094: /* Close UTF-8 string. */
1.104 nicm 2095: static int
1.28 nicm 2096: input_utf8_close(struct input_ctx *ictx)
2097: {
1.90 nicm 2098: struct utf8_data *ud = &ictx->utf8data;
2099:
1.101 nicm 2100: if (utf8_append(ud, ictx->ch) != UTF8_DONE) {
2101: /*
2102: * An error here could be invalid UTF-8 or it could be a
2103: * nonprintable character for which we can't get the
2104: * width. Drop it.
2105: */
2106: return (0);
2107: }
1.28 nicm 2108:
1.90 nicm 2109: log_debug("%s %hhu '%*s' (width %hhu)", __func__, ud->size,
2110: (int)ud->size, ud->data, ud->width);
1.28 nicm 2111:
1.90 nicm 2112: utf8_copy(&ictx->cell.cell.data, ud);
1.119 nicm 2113: screen_write_collect_add(&ictx->ctx, &ictx->cell.cell);
1.28 nicm 2114:
2115: return (0);
1.107 nicm 2116: }
2117:
2118: /* Handle the OSC 4 sequence for setting (multiple) palette entries. */
2119: static void
2120: input_osc_4(struct window_pane *wp, const char *p)
2121: {
2122: char *copy, *s, *next = NULL;
2123: long idx;
2124: u_int r, g, b;
2125:
2126: copy = s = xstrdup(p);
2127: while (s != NULL && *s != '\0') {
2128: idx = strtol(s, &next, 10);
2129: if (*next++ != ';')
2130: goto bad;
2131: if (idx < 0 || idx >= 0x100)
2132: goto bad;
2133:
2134: s = strsep(&next, ";");
2135: if (sscanf(s, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3) {
2136: s = next;
2137: continue;
2138: }
2139:
2140: window_pane_set_palette(wp, idx, colour_join_rgb(r, g, b));
2141: s = next;
2142: }
2143:
2144: free(copy);
2145: return;
2146:
2147: bad:
2148: log_debug("bad OSC 4: %s", p);
2149: free(copy);
1.122 nicm 2150: }
2151:
2152: /* Handle the OSC 10 sequence for setting background colour. */
2153: static void
2154: input_osc_10(struct window_pane *wp, const char *p)
2155: {
2156: u_int r, g, b;
2157:
2158: if (sscanf(p, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3)
2159: goto bad;
2160:
2161: wp->colgc.fg = colour_join_rgb(r, g, b);
2162: wp->flags |= PANE_REDRAW;
2163:
2164: return;
2165:
2166: bad:
2167: log_debug("bad OSC 10: %s", p);
2168: }
2169:
2170: /* Handle the OSC 11 sequence for setting background colour. */
2171: static void
2172: input_osc_11(struct window_pane *wp, const char *p)
2173: {
2174: u_int r, g, b;
2175:
2176: if (sscanf(p, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3)
2177: goto bad;
2178:
2179: wp->colgc.bg = colour_join_rgb(r, g, b);
2180: wp->flags |= PANE_REDRAW;
2181:
2182: return;
2183:
2184: bad:
2185: log_debug("bad OSC 11: %s", p);
1.108 nicm 2186: }
2187:
2188: /* Handle the OSC 52 sequence for setting the clipboard. */
2189: static void
2190: input_osc_52(struct window_pane *wp, const char *p)
2191: {
2192: char *end;
2193: size_t len;
2194: u_char *out;
1.123 nicm 2195: int outlen, state;
1.108 nicm 2196: struct screen_write_ctx ctx;
2197:
1.123 nicm 2198: state = options_get_number(global_options, "set-clipboard");
2199: if (state != 2)
2200: return;
2201:
1.108 nicm 2202: if ((end = strchr(p, ';')) == NULL)
2203: return;
2204: end++;
2205: if (*end == '\0')
2206: return;
2207:
2208: len = (strlen(end) / 4) * 3;
2209: if (len == 0)
2210: return;
2211:
2212: out = xmalloc(len);
2213: if ((outlen = b64_pton(end, out, len)) == -1) {
2214: free(out);
2215: return;
2216: }
2217:
1.123 nicm 2218: screen_write_start(&ctx, wp, NULL);
2219: screen_write_setselection(&ctx, out, outlen);
2220: screen_write_stop(&ctx);
1.126 nicm 2221: notify_pane("pane-set-clipboard", wp);
1.123 nicm 2222:
1.108 nicm 2223: paste_add(out, outlen);
1.107 nicm 2224: }
2225:
2226: /* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */
2227: static void
2228: input_osc_104(struct window_pane *wp, const char *p)
2229: {
2230: char *copy, *s;
2231: long idx;
2232:
2233: if (*p == '\0') {
2234: window_pane_reset_palette(wp);
2235: return;
2236: }
2237:
2238: copy = s = xstrdup(p);
2239: while (*s != '\0') {
2240: idx = strtol(s, &s, 10);
2241: if (*s != '\0' && *s != ';')
2242: goto bad;
2243: if (idx < 0 || idx >= 0x100)
2244: goto bad;
2245:
2246: window_pane_unset_palette(wp, idx);
2247: if (*s == ';')
2248: s++;
2249: }
2250: free(copy);
2251: return;
2252:
2253: bad:
2254: log_debug("bad OSC 104: %s", p);
2255: free(copy);
1.1 nicm 2256: }