Annotation of src/usr.bin/tmux/input.c, Revision 1.192
1.192 ! nicm 1: /* $OpenBSD: input.c,v 1.191 2021/08/13 06:52:51 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:
1.168 nicm 23: #include <ctype.h>
1.108 nicm 24: #include <resolv.h>
1.1 nicm 25: #include <stdlib.h>
26: #include <string.h>
1.79 nicm 27: #include <time.h>
1.1 nicm 28:
29: #include "tmux.h"
30:
1.28 nicm 31: /*
32: * Based on the description by Paul Williams at:
33: *
1.133 nicm 34: * https://vt100.net/emu/dec_ansi_parser
1.28 nicm 35: *
36: * With the following changes:
37: *
38: * - 7-bit only.
39: *
40: * - Support for UTF-8.
41: *
42: * - OSC (but not APC) may be terminated by \007 as well as ST.
43: *
44: * - A state for APC similar to OSC. Some terminals appear to use this to set
45: * the title.
46: *
47: * - A state for the screen \033k...\033\\ sequence to rename a window. This is
48: * pretty stupid but not supporting it is more trouble than it is worth.
1.37 nicm 49: *
50: * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to
1.77 nicm 51: * be passed to the underlying terminals.
1.28 nicm 52: */
53:
1.74 nicm 54: /* Input parser cell. */
55: struct input_cell {
56: struct grid_cell cell;
57: int set;
58: int g0set; /* 1 if ACS */
59: int g1set; /* 1 if ACS */
60: };
61:
1.131 nicm 62: /* Input parser argument. */
63: struct input_param {
64: enum {
65: INPUT_MISSING,
66: INPUT_NUMBER,
67: INPUT_STRING
1.183 nicm 68: } type;
1.131 nicm 69: union {
70: int num;
71: char *str;
72: };
73: };
74:
1.74 nicm 75: /* Input parser context. */
76: struct input_ctx {
77: struct window_pane *wp;
1.172 nicm 78: struct bufferevent *event;
1.74 nicm 79: struct screen_write_ctx ctx;
1.190 nicm 80: struct colour_palette *palette;
1.74 nicm 81:
82: struct input_cell cell;
83:
84: struct input_cell old_cell;
1.183 nicm 85: u_int old_cx;
1.74 nicm 86: u_int old_cy;
1.146 nicm 87: int old_mode;
1.74 nicm 88:
89: u_char interm_buf[4];
90: size_t interm_len;
91:
92: u_char param_buf[64];
93: size_t param_len;
94:
95: #define INPUT_BUF_START 32
96: #define INPUT_BUF_LIMIT 1048576
97: u_char *input_buf;
98: size_t input_len;
99: size_t input_space;
1.138 nicm 100: enum {
101: INPUT_END_ST,
102: INPUT_END_BEL
103: } input_end;
1.74 nicm 104:
1.131 nicm 105: struct input_param param_list[24];
1.74 nicm 106: u_int param_list_len;
107:
108: struct utf8_data utf8data;
1.130 nicm 109: int utf8started;
1.74 nicm 110:
111: int ch;
1.127 nicm 112: int last;
1.112 nicm 113:
1.74 nicm 114: int flags;
115: #define INPUT_DISCARD 0x1
116:
117: const struct input_state *state;
118:
1.125 nicm 119: struct event timer;
120:
1.74 nicm 121: /*
122: * All input received since we were last in the ground state. Sent to
123: * control clients on connection.
124: */
1.183 nicm 125: struct evbuffer *since_ground;
1.74 nicm 126: };
127:
1.28 nicm 128: /* Helper functions. */
1.52 nicm 129: struct input_transition;
1.104 nicm 130: static int input_split(struct input_ctx *);
131: static int input_get(struct input_ctx *, u_int, int, int);
132: static void printflike(2, 3) input_reply(struct input_ctx *, const char *, ...);
1.171 nicm 133: static void input_set_state(struct input_ctx *,
1.104 nicm 134: const struct input_transition *);
135: static void input_reset_cell(struct input_ctx *);
1.28 nicm 136:
1.138 nicm 137: static void input_osc_4(struct input_ctx *, const char *);
138: static void input_osc_10(struct input_ctx *, const char *);
139: static void input_osc_11(struct input_ctx *, const char *);
140: static void input_osc_52(struct input_ctx *, const char *);
141: static void input_osc_104(struct input_ctx *, const char *);
1.186 nicm 142: static void input_osc_110(struct input_ctx *, const char *);
143: static void input_osc_111(struct input_ctx *, const char *);
1.107 nicm 144:
1.28 nicm 145: /* Transition entry/exit handlers. */
1.104 nicm 146: static void input_clear(struct input_ctx *);
147: static void input_ground(struct input_ctx *);
1.125 nicm 148: static void input_enter_dcs(struct input_ctx *);
1.104 nicm 149: static void input_enter_osc(struct input_ctx *);
150: static void input_exit_osc(struct input_ctx *);
151: static void input_enter_apc(struct input_ctx *);
152: static void input_exit_apc(struct input_ctx *);
153: static void input_enter_rename(struct input_ctx *);
154: static void input_exit_rename(struct input_ctx *);
1.28 nicm 155:
156: /* Input state handlers. */
1.104 nicm 157: static int input_print(struct input_ctx *);
158: static int input_intermediate(struct input_ctx *);
159: static int input_parameter(struct input_ctx *);
160: static int input_input(struct input_ctx *);
161: static int input_c0_dispatch(struct input_ctx *);
162: static int input_esc_dispatch(struct input_ctx *);
163: static int input_csi_dispatch(struct input_ctx *);
164: static void input_csi_dispatch_rm(struct input_ctx *);
165: static void input_csi_dispatch_rm_private(struct input_ctx *);
166: static void input_csi_dispatch_sm(struct input_ctx *);
167: static void input_csi_dispatch_sm_private(struct input_ctx *);
168: static void input_csi_dispatch_winops(struct input_ctx *);
169: static void input_csi_dispatch_sgr_256(struct input_ctx *, int, u_int *);
170: static void input_csi_dispatch_sgr_rgb(struct input_ctx *, int, u_int *);
171: static void input_csi_dispatch_sgr(struct input_ctx *);
172: static int input_dcs_dispatch(struct input_ctx *);
1.130 nicm 173: static int input_top_bit_set(struct input_ctx *);
1.138 nicm 174: static int input_end_bel(struct input_ctx *);
1.28 nicm 175:
176: /* Command table comparison function. */
1.104 nicm 177: static int input_table_compare(const void *, const void *);
1.28 nicm 178:
179: /* Command table entry. */
180: struct input_table_entry {
181: int ch;
182: const char *interm;
183: int type;
1.1 nicm 184: };
185:
1.28 nicm 186: /* Escape commands. */
187: enum input_esc_type {
188: INPUT_ESC_DECALN,
189: INPUT_ESC_DECKPAM,
190: INPUT_ESC_DECKPNM,
191: INPUT_ESC_DECRC,
192: INPUT_ESC_DECSC,
193: INPUT_ESC_HTS,
194: INPUT_ESC_IND,
195: INPUT_ESC_NEL,
196: INPUT_ESC_RI,
197: INPUT_ESC_RIS,
1.69 nicm 198: INPUT_ESC_SCSG0_OFF,
199: INPUT_ESC_SCSG0_ON,
200: INPUT_ESC_SCSG1_OFF,
201: INPUT_ESC_SCSG1_ON,
1.107 nicm 202: INPUT_ESC_ST,
1.28 nicm 203: };
1.1 nicm 204:
1.28 nicm 205: /* Escape command table. */
1.104 nicm 206: static const struct input_table_entry input_esc_table[] = {
1.69 nicm 207: { '0', "(", INPUT_ESC_SCSG0_ON },
208: { '0', ")", INPUT_ESC_SCSG1_ON },
1.28 nicm 209: { '7', "", INPUT_ESC_DECSC },
210: { '8', "", INPUT_ESC_DECRC },
211: { '8', "#", INPUT_ESC_DECALN },
212: { '=', "", INPUT_ESC_DECKPAM },
213: { '>', "", INPUT_ESC_DECKPNM },
1.69 nicm 214: { 'B', "(", INPUT_ESC_SCSG0_OFF },
215: { 'B', ")", INPUT_ESC_SCSG1_OFF },
1.28 nicm 216: { 'D', "", INPUT_ESC_IND },
217: { 'E', "", INPUT_ESC_NEL },
218: { 'H', "", INPUT_ESC_HTS },
219: { 'M', "", INPUT_ESC_RI },
1.107 nicm 220: { '\\', "", INPUT_ESC_ST },
1.28 nicm 221: { 'c', "", INPUT_ESC_RIS },
222: };
1.1 nicm 223:
1.28 nicm 224: /* Control (CSI) commands. */
225: enum input_csi_type {
226: INPUT_CSI_CBT,
1.43 nicm 227: INPUT_CSI_CNL,
228: INPUT_CSI_CPL,
1.28 nicm 229: INPUT_CSI_CUB,
230: INPUT_CSI_CUD,
231: INPUT_CSI_CUF,
232: INPUT_CSI_CUP,
233: INPUT_CSI_CUU,
234: INPUT_CSI_DA,
1.50 nicm 235: INPUT_CSI_DA_TWO,
1.28 nicm 236: INPUT_CSI_DCH,
1.39 nicm 237: INPUT_CSI_DECSCUSR,
1.28 nicm 238: INPUT_CSI_DECSTBM,
239: INPUT_CSI_DL,
240: INPUT_CSI_DSR,
1.56 nicm 241: INPUT_CSI_ECH,
1.28 nicm 242: INPUT_CSI_ED,
243: INPUT_CSI_EL,
244: INPUT_CSI_HPA,
245: INPUT_CSI_ICH,
246: INPUT_CSI_IL,
1.178 nicm 247: INPUT_CSI_MODOFF,
248: INPUT_CSI_MODSET,
1.42 nicm 249: INPUT_CSI_RCP,
1.127 nicm 250: INPUT_CSI_REP,
1.28 nicm 251: INPUT_CSI_RM,
252: INPUT_CSI_RM_PRIVATE,
1.42 nicm 253: INPUT_CSI_SCP,
1.159 nicm 254: INPUT_CSI_SD,
1.28 nicm 255: INPUT_CSI_SGR,
256: INPUT_CSI_SM,
257: INPUT_CSI_SM_PRIVATE,
1.115 nicm 258: INPUT_CSI_SU,
1.28 nicm 259: INPUT_CSI_TBC,
260: INPUT_CSI_VPA,
1.65 nicm 261: INPUT_CSI_WINOPS,
1.175 nicm 262: INPUT_CSI_XDA,
1.28 nicm 263: };
1.1 nicm 264:
1.28 nicm 265: /* Control (CSI) command table. */
1.104 nicm 266: static const struct input_table_entry input_csi_table[] = {
1.28 nicm 267: { '@', "", INPUT_CSI_ICH },
268: { 'A', "", INPUT_CSI_CUU },
269: { 'B', "", INPUT_CSI_CUD },
270: { 'C', "", INPUT_CSI_CUF },
271: { 'D', "", INPUT_CSI_CUB },
1.43 nicm 272: { 'E', "", INPUT_CSI_CNL },
273: { 'F', "", INPUT_CSI_CPL },
1.28 nicm 274: { 'G', "", INPUT_CSI_HPA },
275: { 'H', "", INPUT_CSI_CUP },
276: { 'J', "", INPUT_CSI_ED },
277: { 'K', "", INPUT_CSI_EL },
278: { 'L', "", INPUT_CSI_IL },
279: { 'M', "", INPUT_CSI_DL },
280: { 'P', "", INPUT_CSI_DCH },
1.115 nicm 281: { 'S', "", INPUT_CSI_SU },
1.159 nicm 282: { 'T', "", INPUT_CSI_SD },
1.56 nicm 283: { 'X', "", INPUT_CSI_ECH },
1.28 nicm 284: { 'Z', "", INPUT_CSI_CBT },
1.148 nicm 285: { '`', "", INPUT_CSI_HPA },
1.127 nicm 286: { 'b', "", INPUT_CSI_REP },
1.28 nicm 287: { 'c', "", INPUT_CSI_DA },
1.50 nicm 288: { 'c', ">", INPUT_CSI_DA_TWO },
1.28 nicm 289: { 'd', "", INPUT_CSI_VPA },
290: { 'f', "", INPUT_CSI_CUP },
291: { 'g', "", INPUT_CSI_TBC },
292: { 'h', "", INPUT_CSI_SM },
293: { 'h', "?", INPUT_CSI_SM_PRIVATE },
294: { 'l', "", INPUT_CSI_RM },
295: { 'l', "?", INPUT_CSI_RM_PRIVATE },
296: { 'm', "", INPUT_CSI_SGR },
1.178 nicm 297: { 'm', ">", INPUT_CSI_MODSET },
1.28 nicm 298: { 'n', "", INPUT_CSI_DSR },
1.178 nicm 299: { 'n', ">", INPUT_CSI_MODOFF },
1.39 nicm 300: { 'q', " ", INPUT_CSI_DECSCUSR },
1.175 nicm 301: { 'q', ">", INPUT_CSI_XDA },
1.28 nicm 302: { 'r', "", INPUT_CSI_DECSTBM },
1.42 nicm 303: { 's', "", INPUT_CSI_SCP },
1.65 nicm 304: { 't', "", INPUT_CSI_WINOPS },
1.42 nicm 305: { 'u', "", INPUT_CSI_RCP },
1.28 nicm 306: };
1.1 nicm 307:
1.28 nicm 308: /* Input transition. */
309: struct input_transition {
310: int first;
311: int last;
1.1 nicm 312:
1.28 nicm 313: int (*handler)(struct input_ctx *);
314: const struct input_state *state;
315: };
1.1 nicm 316:
1.28 nicm 317: /* Input state. */
318: struct input_state {
319: const char *name;
320: void (*enter)(struct input_ctx *);
321: void (*exit)(struct input_ctx *);
322: const struct input_transition *transitions;
323: };
1.1 nicm 324:
1.28 nicm 325: /* State transitions available from all states. */
326: #define INPUT_STATE_ANYWHERE \
327: { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
328: { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
329: { 0x1b, 0x1b, NULL, &input_state_esc_enter }
330:
331: /* Forward declarations of state tables. */
1.104 nicm 332: static const struct input_transition input_state_ground_table[];
333: static const struct input_transition input_state_esc_enter_table[];
334: static const struct input_transition input_state_esc_intermediate_table[];
335: static const struct input_transition input_state_csi_enter_table[];
336: static const struct input_transition input_state_csi_parameter_table[];
337: static const struct input_transition input_state_csi_intermediate_table[];
338: static const struct input_transition input_state_csi_ignore_table[];
339: static const struct input_transition input_state_dcs_enter_table[];
340: static const struct input_transition input_state_dcs_parameter_table[];
341: static const struct input_transition input_state_dcs_intermediate_table[];
342: static const struct input_transition input_state_dcs_handler_table[];
343: static const struct input_transition input_state_dcs_escape_table[];
344: static const struct input_transition input_state_dcs_ignore_table[];
345: static const struct input_transition input_state_osc_string_table[];
346: static const struct input_transition input_state_apc_string_table[];
347: static const struct input_transition input_state_rename_string_table[];
348: static const struct input_transition input_state_consume_st_table[];
1.28 nicm 349:
350: /* ground state definition. */
1.104 nicm 351: static const struct input_state input_state_ground = {
1.28 nicm 352: "ground",
1.67 nicm 353: input_ground, NULL,
1.28 nicm 354: input_state_ground_table
355: };
1.1 nicm 356:
1.28 nicm 357: /* esc_enter state definition. */
1.104 nicm 358: static const struct input_state input_state_esc_enter = {
1.28 nicm 359: "esc_enter",
360: input_clear, NULL,
361: input_state_esc_enter_table
362: };
1.1 nicm 363:
1.28 nicm 364: /* esc_intermediate state definition. */
1.104 nicm 365: static const struct input_state input_state_esc_intermediate = {
1.28 nicm 366: "esc_intermediate",
367: NULL, NULL,
368: input_state_esc_intermediate_table
369: };
1.1 nicm 370:
1.28 nicm 371: /* csi_enter state definition. */
1.104 nicm 372: static const struct input_state input_state_csi_enter = {
1.28 nicm 373: "csi_enter",
374: input_clear, NULL,
375: input_state_csi_enter_table
376: };
1.1 nicm 377:
1.28 nicm 378: /* csi_parameter state definition. */
1.104 nicm 379: static const struct input_state input_state_csi_parameter = {
1.28 nicm 380: "csi_parameter",
381: NULL, NULL,
382: input_state_csi_parameter_table
383: };
1.1 nicm 384:
1.28 nicm 385: /* csi_intermediate state definition. */
1.104 nicm 386: static const struct input_state input_state_csi_intermediate = {
1.28 nicm 387: "csi_intermediate",
388: NULL, NULL,
389: input_state_csi_intermediate_table
390: };
1.1 nicm 391:
1.28 nicm 392: /* csi_ignore state definition. */
1.104 nicm 393: static const struct input_state input_state_csi_ignore = {
1.28 nicm 394: "csi_ignore",
395: NULL, NULL,
396: input_state_csi_ignore_table
397: };
1.1 nicm 398:
1.28 nicm 399: /* dcs_enter state definition. */
1.104 nicm 400: static const struct input_state input_state_dcs_enter = {
1.28 nicm 401: "dcs_enter",
1.125 nicm 402: input_enter_dcs, NULL,
1.28 nicm 403: input_state_dcs_enter_table
404: };
1.1 nicm 405:
1.28 nicm 406: /* dcs_parameter state definition. */
1.104 nicm 407: static const struct input_state input_state_dcs_parameter = {
1.28 nicm 408: "dcs_parameter",
409: NULL, NULL,
410: input_state_dcs_parameter_table
411: };
1.1 nicm 412:
1.28 nicm 413: /* dcs_intermediate state definition. */
1.104 nicm 414: static const struct input_state input_state_dcs_intermediate = {
1.28 nicm 415: "dcs_intermediate",
416: NULL, NULL,
417: input_state_dcs_intermediate_table
418: };
1.1 nicm 419:
1.28 nicm 420: /* dcs_handler state definition. */
1.104 nicm 421: static const struct input_state input_state_dcs_handler = {
1.28 nicm 422: "dcs_handler",
1.37 nicm 423: NULL, NULL,
1.28 nicm 424: input_state_dcs_handler_table
425: };
1.1 nicm 426:
1.37 nicm 427: /* dcs_escape state definition. */
1.104 nicm 428: static const struct input_state input_state_dcs_escape = {
1.37 nicm 429: "dcs_escape",
430: NULL, NULL,
431: input_state_dcs_escape_table
432: };
433:
1.28 nicm 434: /* dcs_ignore state definition. */
1.104 nicm 435: static const struct input_state input_state_dcs_ignore = {
1.28 nicm 436: "dcs_ignore",
437: NULL, NULL,
438: input_state_dcs_ignore_table
439: };
1.1 nicm 440:
1.28 nicm 441: /* osc_string state definition. */
1.104 nicm 442: static const struct input_state input_state_osc_string = {
1.28 nicm 443: "osc_string",
444: input_enter_osc, input_exit_osc,
445: input_state_osc_string_table
446: };
1.1 nicm 447:
1.28 nicm 448: /* apc_string state definition. */
1.104 nicm 449: static const struct input_state input_state_apc_string = {
1.28 nicm 450: "apc_string",
451: input_enter_apc, input_exit_apc,
452: input_state_apc_string_table
453: };
1.1 nicm 454:
1.28 nicm 455: /* rename_string state definition. */
1.104 nicm 456: static const struct input_state input_state_rename_string = {
1.28 nicm 457: "rename_string",
458: input_enter_rename, input_exit_rename,
459: input_state_rename_string_table
460: };
1.1 nicm 461:
1.28 nicm 462: /* consume_st state definition. */
1.104 nicm 463: static const struct input_state input_state_consume_st = {
1.28 nicm 464: "consume_st",
1.128 nicm 465: input_enter_rename, NULL, /* rename also waits for ST */
1.28 nicm 466: input_state_consume_st_table
467: };
1.1 nicm 468:
1.28 nicm 469: /* ground state table. */
1.104 nicm 470: static const struct input_transition input_state_ground_table[] = {
1.28 nicm 471: INPUT_STATE_ANYWHERE,
472:
473: { 0x00, 0x17, input_c0_dispatch, NULL },
474: { 0x19, 0x19, input_c0_dispatch, NULL },
475: { 0x1c, 0x1f, input_c0_dispatch, NULL },
476: { 0x20, 0x7e, input_print, NULL },
477: { 0x7f, 0x7f, NULL, NULL },
1.130 nicm 478: { 0x80, 0xff, input_top_bit_set, NULL },
1.1 nicm 479:
1.28 nicm 480: { -1, -1, NULL, NULL }
481: };
1.13 nicm 482:
1.28 nicm 483: /* esc_enter state table. */
1.104 nicm 484: static const struct input_transition input_state_esc_enter_table[] = {
1.28 nicm 485: INPUT_STATE_ANYWHERE,
486:
487: { 0x00, 0x17, input_c0_dispatch, NULL },
488: { 0x19, 0x19, input_c0_dispatch, NULL },
489: { 0x1c, 0x1f, input_c0_dispatch, NULL },
490: { 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate },
491: { 0x30, 0x4f, input_esc_dispatch, &input_state_ground },
492: { 0x50, 0x50, NULL, &input_state_dcs_enter },
493: { 0x51, 0x57, input_esc_dispatch, &input_state_ground },
494: { 0x58, 0x58, NULL, &input_state_consume_st },
495: { 0x59, 0x59, input_esc_dispatch, &input_state_ground },
496: { 0x5a, 0x5a, input_esc_dispatch, &input_state_ground },
497: { 0x5b, 0x5b, NULL, &input_state_csi_enter },
498: { 0x5c, 0x5c, input_esc_dispatch, &input_state_ground },
499: { 0x5d, 0x5d, NULL, &input_state_osc_string },
500: { 0x5e, 0x5e, NULL, &input_state_consume_st },
501: { 0x5f, 0x5f, NULL, &input_state_apc_string },
502: { 0x60, 0x6a, input_esc_dispatch, &input_state_ground },
503: { 0x6b, 0x6b, NULL, &input_state_rename_string },
1.29 nicm 504: { 0x6c, 0x7e, input_esc_dispatch, &input_state_ground },
1.28 nicm 505: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 506:
1.28 nicm 507: { -1, -1, NULL, NULL }
508: };
1.1 nicm 509:
1.138 nicm 510: /* esc_intermediate state table. */
1.104 nicm 511: static const struct input_transition input_state_esc_intermediate_table[] = {
1.28 nicm 512: INPUT_STATE_ANYWHERE,
513:
514: { 0x00, 0x17, input_c0_dispatch, NULL },
515: { 0x19, 0x19, input_c0_dispatch, NULL },
516: { 0x1c, 0x1f, input_c0_dispatch, NULL },
517: { 0x20, 0x2f, input_intermediate, NULL },
518: { 0x30, 0x7e, input_esc_dispatch, &input_state_ground },
519: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 520:
1.28 nicm 521: { -1, -1, NULL, NULL }
522: };
1.1 nicm 523:
1.28 nicm 524: /* csi_enter state table. */
1.104 nicm 525: static const struct input_transition input_state_csi_enter_table[] = {
1.28 nicm 526: INPUT_STATE_ANYWHERE,
527:
528: { 0x00, 0x17, input_c0_dispatch, NULL },
529: { 0x19, 0x19, input_c0_dispatch, NULL },
530: { 0x1c, 0x1f, input_c0_dispatch, NULL },
531: { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
532: { 0x30, 0x39, input_parameter, &input_state_csi_parameter },
1.131 nicm 533: { 0x3a, 0x3a, input_parameter, &input_state_csi_parameter },
1.28 nicm 534: { 0x3b, 0x3b, input_parameter, &input_state_csi_parameter },
535: { 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter },
536: { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
537: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 538:
1.28 nicm 539: { -1, -1, NULL, NULL }
540: };
1.1 nicm 541:
1.28 nicm 542: /* csi_parameter state table. */
1.104 nicm 543: static const struct input_transition input_state_csi_parameter_table[] = {
1.28 nicm 544: INPUT_STATE_ANYWHERE,
545:
546: { 0x00, 0x17, input_c0_dispatch, NULL },
547: { 0x19, 0x19, input_c0_dispatch, NULL },
548: { 0x1c, 0x1f, input_c0_dispatch, NULL },
549: { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
550: { 0x30, 0x39, input_parameter, NULL },
1.131 nicm 551: { 0x3a, 0x3a, input_parameter, NULL },
1.28 nicm 552: { 0x3b, 0x3b, input_parameter, NULL },
553: { 0x3c, 0x3f, NULL, &input_state_csi_ignore },
554: { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
555: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 556:
1.28 nicm 557: { -1, -1, NULL, NULL }
558: };
1.1 nicm 559:
1.28 nicm 560: /* csi_intermediate state table. */
1.104 nicm 561: static const struct input_transition input_state_csi_intermediate_table[] = {
1.28 nicm 562: INPUT_STATE_ANYWHERE,
563:
564: { 0x00, 0x17, input_c0_dispatch, NULL },
565: { 0x19, 0x19, input_c0_dispatch, NULL },
566: { 0x1c, 0x1f, input_c0_dispatch, NULL },
567: { 0x20, 0x2f, input_intermediate, NULL },
568: { 0x30, 0x3f, NULL, &input_state_csi_ignore },
569: { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
570: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 571:
1.28 nicm 572: { -1, -1, NULL, NULL }
573: };
1.1 nicm 574:
1.28 nicm 575: /* csi_ignore state table. */
1.104 nicm 576: static const struct input_transition input_state_csi_ignore_table[] = {
1.28 nicm 577: INPUT_STATE_ANYWHERE,
578:
579: { 0x00, 0x17, input_c0_dispatch, NULL },
580: { 0x19, 0x19, input_c0_dispatch, NULL },
581: { 0x1c, 0x1f, input_c0_dispatch, NULL },
582: { 0x20, 0x3f, NULL, NULL },
583: { 0x40, 0x7e, NULL, &input_state_ground },
584: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 585:
1.28 nicm 586: { -1, -1, NULL, NULL }
587: };
1.1 nicm 588:
1.28 nicm 589: /* dcs_enter state table. */
1.104 nicm 590: static const struct input_transition input_state_dcs_enter_table[] = {
1.28 nicm 591: INPUT_STATE_ANYWHERE,
592:
593: { 0x00, 0x17, NULL, NULL },
594: { 0x19, 0x19, NULL, NULL },
595: { 0x1c, 0x1f, NULL, NULL },
596: { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
597: { 0x30, 0x39, input_parameter, &input_state_dcs_parameter },
598: { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
599: { 0x3b, 0x3b, input_parameter, &input_state_dcs_parameter },
600: { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter },
1.37 nicm 601: { 0x40, 0x7e, input_input, &input_state_dcs_handler },
1.28 nicm 602: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 603:
1.28 nicm 604: { -1, -1, NULL, NULL }
605: };
1.1 nicm 606:
1.28 nicm 607: /* dcs_parameter state table. */
1.104 nicm 608: static const struct input_transition input_state_dcs_parameter_table[] = {
1.28 nicm 609: INPUT_STATE_ANYWHERE,
610:
611: { 0x00, 0x17, NULL, NULL },
612: { 0x19, 0x19, NULL, NULL },
613: { 0x1c, 0x1f, NULL, NULL },
614: { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
615: { 0x30, 0x39, input_parameter, NULL },
616: { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
617: { 0x3b, 0x3b, input_parameter, NULL },
618: { 0x3c, 0x3f, NULL, &input_state_dcs_ignore },
1.37 nicm 619: { 0x40, 0x7e, input_input, &input_state_dcs_handler },
1.28 nicm 620: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 621:
1.28 nicm 622: { -1, -1, NULL, NULL }
623: };
1.1 nicm 624:
1.138 nicm 625: /* dcs_intermediate state table. */
1.104 nicm 626: static const struct input_transition input_state_dcs_intermediate_table[] = {
1.28 nicm 627: INPUT_STATE_ANYWHERE,
628:
629: { 0x00, 0x17, NULL, NULL },
630: { 0x19, 0x19, NULL, NULL },
631: { 0x1c, 0x1f, NULL, NULL },
632: { 0x20, 0x2f, input_intermediate, NULL },
633: { 0x30, 0x3f, NULL, &input_state_dcs_ignore },
1.37 nicm 634: { 0x40, 0x7e, input_input, &input_state_dcs_handler },
1.28 nicm 635: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 636:
1.28 nicm 637: { -1, -1, NULL, NULL }
638: };
1.1 nicm 639:
1.28 nicm 640: /* dcs_handler state table. */
1.104 nicm 641: static const struct input_transition input_state_dcs_handler_table[] = {
1.37 nicm 642: /* No INPUT_STATE_ANYWHERE */
643:
644: { 0x00, 0x1a, input_input, NULL },
645: { 0x1b, 0x1b, NULL, &input_state_dcs_escape },
646: { 0x1c, 0xff, input_input, NULL },
647:
648: { -1, -1, NULL, NULL }
649: };
650:
651: /* dcs_escape state table. */
1.104 nicm 652: static const struct input_transition input_state_dcs_escape_table[] = {
1.37 nicm 653: /* No INPUT_STATE_ANYWHERE */
1.28 nicm 654:
1.37 nicm 655: { 0x00, 0x5b, input_input, &input_state_dcs_handler },
656: { 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground },
657: { 0x5d, 0xff, input_input, &input_state_dcs_handler },
1.1 nicm 658:
1.28 nicm 659: { -1, -1, NULL, NULL }
660: };
1.1 nicm 661:
1.40 nicm 662: /* dcs_ignore state table. */
1.104 nicm 663: static const struct input_transition input_state_dcs_ignore_table[] = {
1.28 nicm 664: INPUT_STATE_ANYWHERE,
665:
666: { 0x00, 0x17, NULL, NULL },
667: { 0x19, 0x19, NULL, NULL },
668: { 0x1c, 0x1f, NULL, NULL },
669: { 0x20, 0xff, NULL, NULL },
1.1 nicm 670:
1.28 nicm 671: { -1, -1, NULL, NULL }
672: };
1.1 nicm 673:
1.28 nicm 674: /* osc_string state table. */
1.104 nicm 675: static const struct input_transition input_state_osc_string_table[] = {
1.28 nicm 676: INPUT_STATE_ANYWHERE,
677:
1.138 nicm 678: { 0x00, 0x06, NULL, NULL },
679: { 0x07, 0x07, input_end_bel, &input_state_ground },
680: { 0x08, 0x17, NULL, NULL },
681: { 0x19, 0x19, NULL, NULL },
682: { 0x1c, 0x1f, NULL, NULL },
683: { 0x20, 0xff, input_input, NULL },
1.1 nicm 684:
1.28 nicm 685: { -1, -1, NULL, NULL }
686: };
1.1 nicm 687:
1.28 nicm 688: /* apc_string state table. */
1.104 nicm 689: static const struct input_transition input_state_apc_string_table[] = {
1.28 nicm 690: INPUT_STATE_ANYWHERE,
691:
692: { 0x00, 0x17, NULL, NULL },
693: { 0x19, 0x19, NULL, NULL },
694: { 0x1c, 0x1f, NULL, NULL },
695: { 0x20, 0xff, input_input, NULL },
1.1 nicm 696:
1.28 nicm 697: { -1, -1, NULL, NULL }
698: };
1.1 nicm 699:
1.28 nicm 700: /* rename_string state table. */
1.104 nicm 701: static const struct input_transition input_state_rename_string_table[] = {
1.28 nicm 702: INPUT_STATE_ANYWHERE,
703:
704: { 0x00, 0x17, NULL, NULL },
705: { 0x19, 0x19, NULL, NULL },
706: { 0x1c, 0x1f, NULL, NULL },
707: { 0x20, 0xff, input_input, NULL },
1.1 nicm 708:
1.28 nicm 709: { -1, -1, NULL, NULL }
710: };
1.1 nicm 711:
1.28 nicm 712: /* consume_st state table. */
1.104 nicm 713: static const struct input_transition input_state_consume_st_table[] = {
1.28 nicm 714: INPUT_STATE_ANYWHERE,
715:
716: { 0x00, 0x17, NULL, NULL },
717: { 0x19, 0x19, NULL, NULL },
718: { 0x1c, 0x1f, NULL, NULL },
719: { 0x20, 0xff, NULL, NULL },
1.6 nicm 720:
1.28 nicm 721: { -1, -1, NULL, NULL }
722: };
1.6 nicm 723:
1.28 nicm 724: /* Input table compare. */
1.104 nicm 725: static int
1.28 nicm 726: input_table_compare(const void *key, const void *value)
1.1 nicm 727: {
1.28 nicm 728: const struct input_ctx *ictx = key;
729: const struct input_table_entry *entry = value;
1.1 nicm 730:
1.28 nicm 731: if (ictx->ch != entry->ch)
732: return (ictx->ch - entry->ch);
733: return (strcmp(ictx->interm_buf, entry->interm));
1.1 nicm 734: }
735:
1.125 nicm 736: /*
737: * Timer - if this expires then have been waiting for a terminator for too
738: * long, so reset to ground.
739: */
740: static void
741: input_timer_callback(__unused int fd, __unused short events, void *arg)
742: {
743: struct input_ctx *ictx = arg;
744:
1.171 nicm 745: log_debug("%s: %s expired" , __func__, ictx->state->name);
746: input_reset(ictx, 0);
1.125 nicm 747: }
748:
749: /* Start the timer. */
750: static void
751: input_start_timer(struct input_ctx *ictx)
752: {
1.167 nicm 753: struct timeval tv = { .tv_sec = 5, .tv_usec = 0 };
1.125 nicm 754:
755: event_del(&ictx->timer);
756: event_add(&ictx->timer, &tv);
757: }
758:
1.69 nicm 759: /* Reset cell state to default. */
1.104 nicm 760: static void
1.69 nicm 761: input_reset_cell(struct input_ctx *ictx)
762: {
763: memcpy(&ictx->cell.cell, &grid_default_cell, sizeof ictx->cell.cell);
764: ictx->cell.set = 0;
765: ictx->cell.g0set = ictx->cell.g1set = 0;
766:
767: memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
768: ictx->old_cx = 0;
769: ictx->old_cy = 0;
770: }
771:
1.146 nicm 772: /* Save screen state. */
773: static void
774: input_save_state(struct input_ctx *ictx)
775: {
776: struct screen_write_ctx *sctx = &ictx->ctx;
777: struct screen *s = sctx->s;
778:
779: memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
780: ictx->old_cx = s->cx;
781: ictx->old_cy = s->cy;
782: ictx->old_mode = s->mode;
783: }
784:
1.169 nicm 785: /* Restore screen state. */
1.146 nicm 786: static void
787: input_restore_state(struct input_ctx *ictx)
788: {
789: struct screen_write_ctx *sctx = &ictx->ctx;
790:
791: memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
792: if (ictx->old_mode & MODE_ORIGIN)
793: screen_write_mode_set(sctx, MODE_ORIGIN);
794: else
795: screen_write_mode_clear(sctx, MODE_ORIGIN);
796: screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy, 0);
797: }
798:
1.28 nicm 799: /* Initialise input parser. */
1.171 nicm 800: struct input_ctx *
1.190 nicm 801: input_init(struct window_pane *wp, struct bufferevent *bev,
802: struct colour_palette *palette)
1.1 nicm 803: {
1.74 nicm 804: struct input_ctx *ictx;
805:
1.171 nicm 806: ictx = xcalloc(1, sizeof *ictx);
807: ictx->wp = wp;
1.172 nicm 808: ictx->event = bev;
1.190 nicm 809: ictx->palette = palette;
1.1 nicm 810:
1.67 nicm 811: ictx->input_space = INPUT_BUF_START;
812: ictx->input_buf = xmalloc(INPUT_BUF_START);
813:
1.97 nicm 814: ictx->since_ground = evbuffer_new();
1.139 nicm 815: if (ictx->since_ground == NULL)
816: fatalx("out of memory");
1.52 nicm 817:
1.125 nicm 818: evtimer_set(&ictx->timer, input_timer_callback, ictx);
819:
1.171 nicm 820: input_reset(ictx, 0);
821: return (ictx);
1.1 nicm 822: }
823:
1.28 nicm 824: /* Destroy input parser. */
1.1 nicm 825: void
1.171 nicm 826: input_free(struct input_ctx *ictx)
1.1 nicm 827: {
1.171 nicm 828: u_int i;
1.131 nicm 829:
830: for (i = 0; i < ictx->param_list_len; i++) {
831: if (ictx->param_list[i].type == INPUT_STRING)
832: free(ictx->param_list[i].str);
833: }
1.74 nicm 834:
1.125 nicm 835: event_del(&ictx->timer);
836:
1.74 nicm 837: free(ictx->input_buf);
838: evbuffer_free(ictx->since_ground);
839:
1.106 nicm 840: free(ictx);
1.74 nicm 841: }
842:
843: /* Reset input state and clear screen. */
844: void
1.171 nicm 845: input_reset(struct input_ctx *ictx, int clear)
1.74 nicm 846: {
1.144 nicm 847: struct screen_write_ctx *sctx = &ictx->ctx;
1.171 nicm 848: struct window_pane *wp = ictx->wp;
1.67 nicm 849:
1.80 nicm 850: input_reset_cell(ictx);
1.74 nicm 851:
1.171 nicm 852: if (clear && wp != NULL) {
1.142 nicm 853: if (TAILQ_EMPTY(&wp->modes))
1.177 nicm 854: screen_write_start_pane(sctx, wp, &wp->base);
1.97 nicm 855: else
1.177 nicm 856: screen_write_start(sctx, &wp->base);
1.144 nicm 857: screen_write_reset(sctx);
858: screen_write_stop(sctx);
1.97 nicm 859: }
860:
1.125 nicm 861: input_clear(ictx);
1.97 nicm 862:
1.127 nicm 863: ictx->last = -1;
864:
1.97 nicm 865: ictx->state = &input_state_ground;
866: ictx->flags = 0;
1.74 nicm 867: }
868:
869: /* Return pending data. */
870: struct evbuffer *
1.171 nicm 871: input_pending(struct input_ctx *ictx)
1.74 nicm 872: {
1.171 nicm 873: return (ictx->since_ground);
1.52 nicm 874: }
875:
876: /* Change input state. */
1.104 nicm 877: static void
1.171 nicm 878: input_set_state(struct input_ctx *ictx, const struct input_transition *itr)
1.52 nicm 879: {
880: if (ictx->state->exit != NULL)
881: ictx->state->exit(ictx);
882: ictx->state = itr->state;
883: if (ictx->state->enter != NULL)
884: ictx->state->enter(ictx);
1.1 nicm 885: }
886:
1.171 nicm 887: /* Parse data. */
888: static void
889: input_parse(struct input_ctx *ictx, u_char *buf, size_t len)
1.1 nicm 890: {
1.144 nicm 891: struct screen_write_ctx *sctx = &ictx->ctx;
1.160 nicm 892: const struct input_state *state = NULL;
893: const struct input_transition *itr = NULL;
1.152 nicm 894: size_t off = 0;
1.1 nicm 895:
1.28 nicm 896: /* Parse the input. */
897: while (off < len) {
898: ictx->ch = buf[off++];
899:
900: /* Find the transition. */
1.160 nicm 901: if (ictx->state != state ||
902: itr == NULL ||
903: ictx->ch < itr->first ||
904: ictx->ch > itr->last) {
905: itr = ictx->state->transitions;
906: while (itr->first != -1 && itr->last != -1) {
1.161 nicm 907: if (ictx->ch >= itr->first &&
908: ictx->ch <= itr->last)
1.160 nicm 909: break;
910: itr++;
911: }
912: if (itr->first == -1 || itr->last == -1) {
913: /* No transition? Eh? */
914: fatalx("no transition from state");
915: }
1.3 nicm 916: }
1.160 nicm 917: state = ictx->state;
1.1 nicm 918:
919: /*
1.114 nicm 920: * Any state except print stops the current collection. This is
921: * an optimization to avoid checking if the attributes have
922: * changed for every character. It will stop unnecessarily for
923: * sequences that don't make a terminal change, but they should
924: * be the minority.
925: */
926: if (itr->handler != input_print)
1.144 nicm 927: screen_write_collect_end(sctx);
1.114 nicm 928:
929: /*
1.28 nicm 930: * Execute the handler, if any. Don't switch state if it
931: * returns non-zero.
1.1 nicm 932: */
1.31 nicm 933: if (itr->handler != NULL && itr->handler(ictx) != 0)
1.28 nicm 934: continue;
935:
936: /* And switch state, if necessary. */
1.52 nicm 937: if (itr->state != NULL)
1.171 nicm 938: input_set_state(ictx, itr);
1.52 nicm 939:
940: /* If not in ground state, save input. */
941: if (ictx->state != &input_state_ground)
942: evbuffer_add(ictx->since_ground, &ictx->ch, 1);
1.1 nicm 943: }
1.171 nicm 944: }
945:
946: /* Parse input from pane. */
947: void
948: input_parse_pane(struct window_pane *wp)
949: {
1.179 nicm 950: void *new_data;
951: size_t new_size;
1.171 nicm 952:
1.179 nicm 953: new_data = window_pane_get_new_data(wp, &wp->offset, &new_size);
954: input_parse_buffer(wp, new_data, new_size);
1.180 nicm 955: window_pane_update_used_data(wp, &wp->offset, new_size);
1.171 nicm 956: }
957:
958: /* Parse given input. */
959: void
960: input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len)
961: {
962: struct input_ctx *ictx = wp->ictx;
963: struct screen_write_ctx *sctx = &ictx->ctx;
964:
965: if (len == 0)
966: return;
967:
968: window_update_activity(wp->window);
969: wp->flags |= PANE_CHANGED;
1.1 nicm 970:
1.171 nicm 971: /* NULL wp if there is a mode set as don't want to update the tty. */
972: if (TAILQ_EMPTY(&wp->modes))
1.177 nicm 973: screen_write_start_pane(sctx, wp, &wp->base);
1.171 nicm 974: else
1.177 nicm 975: screen_write_start(sctx, &wp->base);
1.171 nicm 976:
977: log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id,
978: ictx->state->name, len, (int)len, buf);
979:
980: input_parse(ictx, buf, len);
981: screen_write_stop(sctx);
982: }
983:
984: /* Parse given input for screen. */
985: void
1.177 nicm 986: input_parse_screen(struct input_ctx *ictx, struct screen *s,
987: screen_write_init_ctx_cb cb, void *arg, u_char *buf, size_t len)
1.171 nicm 988: {
989: struct screen_write_ctx *sctx = &ictx->ctx;
990:
991: if (len == 0)
992: return;
993:
1.177 nicm 994: screen_write_start_callback(sctx, s, cb, arg);
1.171 nicm 995: input_parse(ictx, buf, len);
1.144 nicm 996: screen_write_stop(sctx);
1.1 nicm 997: }
998:
1.28 nicm 999: /* Split the parameter list (if any). */
1.104 nicm 1000: static int
1.28 nicm 1001: input_split(struct input_ctx *ictx)
1.1 nicm 1002: {
1.131 nicm 1003: const char *errstr;
1004: char *ptr, *out;
1005: struct input_param *ip;
1006: u_int i;
1.1 nicm 1007:
1.131 nicm 1008: for (i = 0; i < ictx->param_list_len; i++) {
1009: if (ictx->param_list[i].type == INPUT_STRING)
1010: free(ictx->param_list[i].str);
1011: }
1.28 nicm 1012: ictx->param_list_len = 0;
1.131 nicm 1013:
1.28 nicm 1014: if (ictx->param_len == 0)
1015: return (0);
1.131 nicm 1016: ip = &ictx->param_list[0];
1.1 nicm 1017:
1.28 nicm 1018: ptr = ictx->param_buf;
1019: while ((out = strsep(&ptr, ";")) != NULL) {
1020: if (*out == '\0')
1.131 nicm 1021: ip->type = INPUT_MISSING;
1.28 nicm 1022: else {
1.131 nicm 1023: if (strchr(out, ':') != NULL) {
1024: ip->type = INPUT_STRING;
1025: ip->str = xstrdup(out);
1026: } else {
1027: ip->type = INPUT_NUMBER;
1028: ip->num = strtonum(out, 0, INT_MAX, &errstr);
1029: if (errstr != NULL)
1030: return (-1);
1031: }
1.28 nicm 1032: }
1.131 nicm 1033: ip = &ictx->param_list[++ictx->param_list_len];
1.28 nicm 1034: if (ictx->param_list_len == nitems(ictx->param_list))
1035: return (-1);
1036: }
1.1 nicm 1037:
1.131 nicm 1038: for (i = 0; i < ictx->param_list_len; i++) {
1039: ip = &ictx->param_list[i];
1040: if (ip->type == INPUT_MISSING)
1041: log_debug("parameter %u: missing", i);
1042: else if (ip->type == INPUT_STRING)
1043: log_debug("parameter %u: string %s", i, ip->str);
1044: else if (ip->type == INPUT_NUMBER)
1045: log_debug("parameter %u: number %d", i, ip->num);
1046: }
1047:
1.28 nicm 1048: return (0);
1.1 nicm 1049: }
1050:
1.40 nicm 1051: /* Get an argument or return default value. */
1.104 nicm 1052: static int
1.28 nicm 1053: input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
1.1 nicm 1054: {
1.131 nicm 1055: struct input_param *ip;
1056: int retval;
1.1 nicm 1057:
1.28 nicm 1058: if (validx >= ictx->param_list_len)
1059: return (defval);
1.131 nicm 1060: ip = &ictx->param_list[validx];
1061: if (ip->type == INPUT_MISSING)
1.28 nicm 1062: return (defval);
1.131 nicm 1063: if (ip->type == INPUT_STRING)
1064: return (-1);
1065: retval = ip->num;
1.28 nicm 1066: if (retval < minval)
1067: return (minval);
1068: return (retval);
1.1 nicm 1069: }
1070:
1.28 nicm 1071: /* Reply to terminal query. */
1.104 nicm 1072: static void
1.28 nicm 1073: input_reply(struct input_ctx *ictx, const char *fmt, ...)
1.1 nicm 1074: {
1.172 nicm 1075: struct bufferevent *bev = ictx->event;
1.171 nicm 1076: va_list ap;
1077: char *reply;
1078:
1.28 nicm 1079: va_start(ap, fmt);
1.103 nicm 1080: xvasprintf(&reply, fmt, ap);
1.28 nicm 1081: va_end(ap);
1.1 nicm 1082:
1.172 nicm 1083: bufferevent_write(bev, reply, strlen(reply));
1.53 nicm 1084: free(reply);
1.8 nicm 1085: }
1086:
1.28 nicm 1087: /* Clear saved state. */
1.104 nicm 1088: static void
1.28 nicm 1089: input_clear(struct input_ctx *ictx)
1.8 nicm 1090: {
1.125 nicm 1091: event_del(&ictx->timer);
1092:
1.28 nicm 1093: *ictx->interm_buf = '\0';
1094: ictx->interm_len = 0;
1.8 nicm 1095:
1.28 nicm 1096: *ictx->param_buf = '\0';
1097: ictx->param_len = 0;
1.8 nicm 1098:
1.35 nicm 1099: *ictx->input_buf = '\0';
1100: ictx->input_len = 0;
1101:
1.138 nicm 1102: ictx->input_end = INPUT_END_ST;
1103:
1.28 nicm 1104: ictx->flags &= ~INPUT_DISCARD;
1.14 nicm 1105: }
1106:
1.67 nicm 1107: /* Reset for ground state. */
1.104 nicm 1108: static void
1.67 nicm 1109: input_ground(struct input_ctx *ictx)
1110: {
1.125 nicm 1111: event_del(&ictx->timer);
1.67 nicm 1112: evbuffer_drain(ictx->since_ground, EVBUFFER_LENGTH(ictx->since_ground));
1113:
1114: if (ictx->input_space > INPUT_BUF_START) {
1115: ictx->input_space = INPUT_BUF_START;
1.71 nicm 1116: ictx->input_buf = xrealloc(ictx->input_buf, INPUT_BUF_START);
1.67 nicm 1117: }
1118: }
1119:
1.28 nicm 1120: /* Output this character to the screen. */
1.104 nicm 1121: static int
1.28 nicm 1122: input_print(struct input_ctx *ictx)
1.14 nicm 1123: {
1.144 nicm 1124: struct screen_write_ctx *sctx = &ictx->ctx;
1125: int set;
1.69 nicm 1126:
1.130 nicm 1127: ictx->utf8started = 0; /* can't be valid UTF-8 */
1128:
1.69 nicm 1129: set = ictx->cell.set == 0 ? ictx->cell.g0set : ictx->cell.g1set;
1130: if (set == 1)
1131: ictx->cell.cell.attr |= GRID_ATTR_CHARSET;
1132: else
1133: ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
1134:
1.89 nicm 1135: utf8_set(&ictx->cell.cell.data, ictx->ch);
1.144 nicm 1136: screen_write_collect_add(sctx, &ictx->cell.cell);
1.127 nicm 1137: ictx->last = ictx->ch;
1.69 nicm 1138:
1139: ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
1.14 nicm 1140:
1.28 nicm 1141: return (0);
1.1 nicm 1142: }
1143:
1.28 nicm 1144: /* Collect intermediate string. */
1.104 nicm 1145: static int
1.28 nicm 1146: input_intermediate(struct input_ctx *ictx)
1.1 nicm 1147: {
1.28 nicm 1148: if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
1149: ictx->flags |= INPUT_DISCARD;
1150: else {
1151: ictx->interm_buf[ictx->interm_len++] = ictx->ch;
1152: ictx->interm_buf[ictx->interm_len] = '\0';
1153: }
1.1 nicm 1154:
1.28 nicm 1155: return (0);
1.1 nicm 1156: }
1157:
1.28 nicm 1158: /* Collect parameter string. */
1.104 nicm 1159: static int
1.28 nicm 1160: input_parameter(struct input_ctx *ictx)
1.1 nicm 1161: {
1.28 nicm 1162: if (ictx->param_len == (sizeof ictx->param_buf) - 1)
1163: ictx->flags |= INPUT_DISCARD;
1164: else {
1165: ictx->param_buf[ictx->param_len++] = ictx->ch;
1166: ictx->param_buf[ictx->param_len] = '\0';
1167: }
1.1 nicm 1168:
1.28 nicm 1169: return (0);
1.1 nicm 1170: }
1171:
1.28 nicm 1172: /* Collect input string. */
1.104 nicm 1173: static int
1.28 nicm 1174: input_input(struct input_ctx *ictx)
1.1 nicm 1175: {
1.67 nicm 1176: size_t available;
1177:
1178: available = ictx->input_space;
1179: while (ictx->input_len + 1 >= available) {
1180: available *= 2;
1181: if (available > INPUT_BUF_LIMIT) {
1182: ictx->flags |= INPUT_DISCARD;
1183: return (0);
1184: }
1.71 nicm 1185: ictx->input_buf = xrealloc(ictx->input_buf, available);
1.67 nicm 1186: ictx->input_space = available;
1.28 nicm 1187: }
1.67 nicm 1188: ictx->input_buf[ictx->input_len++] = ictx->ch;
1189: ictx->input_buf[ictx->input_len] = '\0';
1.1 nicm 1190:
1.28 nicm 1191: return (0);
1.1 nicm 1192: }
1193:
1.28 nicm 1194: /* Execute C0 control sequence. */
1.104 nicm 1195: static int
1.28 nicm 1196: input_c0_dispatch(struct input_ctx *ictx)
1.1 nicm 1197: {
1.28 nicm 1198: struct screen_write_ctx *sctx = &ictx->ctx;
1199: struct window_pane *wp = ictx->wp;
1200: struct screen *s = sctx->s;
1.1 nicm 1201:
1.130 nicm 1202: ictx->utf8started = 0; /* can't be valid UTF-8 */
1203:
1.84 nicm 1204: log_debug("%s: '%c'", __func__, ictx->ch);
1.1 nicm 1205:
1.28 nicm 1206: switch (ictx->ch) {
1207: case '\000': /* NUL */
1208: break;
1209: case '\007': /* BEL */
1.171 nicm 1210: if (wp != NULL)
1211: alerts_queue(wp->window, WINDOW_BELL);
1.28 nicm 1212: break;
1213: case '\010': /* BS */
1214: screen_write_backspace(sctx);
1.75 nicm 1215: break;
1.28 nicm 1216: case '\011': /* HT */
1217: /* Don't tab beyond the end of the line. */
1218: if (s->cx >= screen_size_x(s) - 1)
1219: break;
1.1 nicm 1220:
1.28 nicm 1221: /* Find the next tab point, or use the last column if none. */
1222: do {
1223: s->cx++;
1224: if (bit_test(s->tabs, s->cx))
1225: break;
1226: } while (s->cx < screen_size_x(s) - 1);
1227: break;
1228: case '\012': /* LF */
1229: case '\013': /* VT */
1230: case '\014': /* FF */
1.121 nicm 1231: screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1.151 nicm 1232: if (s->mode & MODE_CRLF)
1233: screen_write_carriagereturn(sctx);
1.75 nicm 1234: break;
1.28 nicm 1235: case '\015': /* CR */
1236: screen_write_carriagereturn(sctx);
1.75 nicm 1237: break;
1.28 nicm 1238: case '\016': /* SO */
1.69 nicm 1239: ictx->cell.set = 1;
1.28 nicm 1240: break;
1241: case '\017': /* SI */
1.69 nicm 1242: ictx->cell.set = 0;
1.28 nicm 1243: break;
1244: default:
1245: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1246: break;
1247: }
1.1 nicm 1248:
1.127 nicm 1249: ictx->last = -1;
1.28 nicm 1250: return (0);
1.7 nicm 1251: }
1252:
1.28 nicm 1253: /* Execute escape sequence. */
1.104 nicm 1254: static int
1.28 nicm 1255: input_esc_dispatch(struct input_ctx *ictx)
1.7 nicm 1256: {
1.31 nicm 1257: struct screen_write_ctx *sctx = &ictx->ctx;
1258: struct screen *s = sctx->s;
1259: struct input_table_entry *entry;
1.7 nicm 1260:
1.28 nicm 1261: if (ictx->flags & INPUT_DISCARD)
1262: return (0);
1263: log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
1.7 nicm 1264:
1.28 nicm 1265: entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
1266: sizeof input_esc_table[0], input_table_compare);
1267: if (entry == NULL) {
1268: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1269: return (0);
1270: }
1.7 nicm 1271:
1.28 nicm 1272: switch (entry->type) {
1273: case INPUT_ESC_RIS:
1.190 nicm 1274: colour_palette_clear(ictx->palette);
1.69 nicm 1275: input_reset_cell(ictx);
1.46 nicm 1276: screen_write_reset(sctx);
1.190 nicm 1277: screen_write_fullredraw(sctx);
1.28 nicm 1278: break;
1279: case INPUT_ESC_IND:
1.121 nicm 1280: screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1.28 nicm 1281: break;
1282: case INPUT_ESC_NEL:
1283: screen_write_carriagereturn(sctx);
1.121 nicm 1284: screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1.28 nicm 1285: break;
1286: case INPUT_ESC_HTS:
1287: if (s->cx < screen_size_x(s))
1288: bit_set(s->tabs, s->cx);
1289: break;
1290: case INPUT_ESC_RI:
1.121 nicm 1291: screen_write_reverseindex(sctx, ictx->cell.cell.bg);
1.28 nicm 1292: break;
1293: case INPUT_ESC_DECKPAM:
1.59 nicm 1294: screen_write_mode_set(sctx, MODE_KKEYPAD);
1.28 nicm 1295: break;
1296: case INPUT_ESC_DECKPNM:
1.59 nicm 1297: screen_write_mode_clear(sctx, MODE_KKEYPAD);
1.1 nicm 1298: break;
1.28 nicm 1299: case INPUT_ESC_DECSC:
1.146 nicm 1300: input_save_state(ictx);
1.28 nicm 1301: break;
1302: case INPUT_ESC_DECRC:
1.146 nicm 1303: input_restore_state(ictx);
1.28 nicm 1304: break;
1305: case INPUT_ESC_DECALN:
1306: screen_write_alignmenttest(sctx);
1307: break;
1.69 nicm 1308: case INPUT_ESC_SCSG0_ON:
1309: ictx->cell.g0set = 1;
1310: break;
1311: case INPUT_ESC_SCSG0_OFF:
1312: ictx->cell.g0set = 0;
1313: break;
1314: case INPUT_ESC_SCSG1_ON:
1315: ictx->cell.g1set = 1;
1.1 nicm 1316: break;
1.69 nicm 1317: case INPUT_ESC_SCSG1_OFF:
1318: ictx->cell.g1set = 0;
1.1 nicm 1319: break;
1.107 nicm 1320: case INPUT_ESC_ST:
1321: /* ST terminates OSC but the state transition already did it. */
1322: break;
1.1 nicm 1323: }
1.28 nicm 1324:
1.127 nicm 1325: ictx->last = -1;
1.28 nicm 1326: return (0);
1.1 nicm 1327: }
1328:
1.28 nicm 1329: /* Execute control sequence. */
1.104 nicm 1330: static int
1.28 nicm 1331: input_csi_dispatch(struct input_ctx *ictx)
1.1 nicm 1332: {
1.28 nicm 1333: struct screen_write_ctx *sctx = &ictx->ctx;
1334: struct screen *s = sctx->s;
1335: struct input_table_entry *entry;
1.127 nicm 1336: int i, n, m;
1.131 nicm 1337: u_int cx, bg = ictx->cell.cell.bg;
1.1 nicm 1338:
1.28 nicm 1339: if (ictx->flags & INPUT_DISCARD)
1340: return (0);
1.110 nicm 1341:
1342: log_debug("%s: '%c' \"%s\" \"%s\"",
1343: __func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
1344:
1.28 nicm 1345: if (input_split(ictx) != 0)
1346: return (0);
1.1 nicm 1347:
1.28 nicm 1348: entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
1349: sizeof input_csi_table[0], input_table_compare);
1350: if (entry == NULL) {
1351: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1352: return (0);
1353: }
1.1 nicm 1354:
1.28 nicm 1355: switch (entry->type) {
1356: case INPUT_CSI_CBT:
1357: /* Find the previous tab point, n times. */
1.81 nicm 1358: cx = s->cx;
1359: if (cx > screen_size_x(s) - 1)
1360: cx = screen_size_x(s) - 1;
1.28 nicm 1361: n = input_get(ictx, 0, 1, 1);
1.131 nicm 1362: if (n == -1)
1363: break;
1.81 nicm 1364: while (cx > 0 && n-- > 0) {
1.28 nicm 1365: do
1.81 nicm 1366: cx--;
1367: while (cx > 0 && !bit_test(s->tabs, cx));
1.28 nicm 1368: }
1.81 nicm 1369: s->cx = cx;
1.28 nicm 1370: break;
1371: case INPUT_CSI_CUB:
1.131 nicm 1372: n = input_get(ictx, 0, 1, 1);
1373: if (n != -1)
1374: screen_write_cursorleft(sctx, n);
1.28 nicm 1375: break;
1376: case INPUT_CSI_CUD:
1.131 nicm 1377: n = input_get(ictx, 0, 1, 1);
1378: if (n != -1)
1379: screen_write_cursordown(sctx, n);
1.28 nicm 1380: break;
1381: case INPUT_CSI_CUF:
1.131 nicm 1382: n = input_get(ictx, 0, 1, 1);
1383: if (n != -1)
1384: screen_write_cursorright(sctx, n);
1.28 nicm 1385: break;
1386: case INPUT_CSI_CUP:
1387: n = input_get(ictx, 0, 1, 1);
1388: m = input_get(ictx, 1, 1, 1);
1.131 nicm 1389: if (n != -1 && m != -1)
1.146 nicm 1390: screen_write_cursormove(sctx, m - 1, n - 1, 1);
1.28 nicm 1391: break;
1.178 nicm 1392: case INPUT_CSI_MODSET:
1393: n = input_get(ictx, 0, 0, 0);
1394: m = input_get(ictx, 1, 0, 0);
1.189 nicm 1395: if (options_get_number(global_options, "extended-keys") == 2)
1396: break;
1.178 nicm 1397: if (n == 0 || (n == 4 && m == 0))
1398: screen_write_mode_clear(sctx, MODE_KEXTENDED);
1399: else if (n == 4 && (m == 1 || m == 2))
1400: screen_write_mode_set(sctx, MODE_KEXTENDED);
1401: break;
1402: case INPUT_CSI_MODOFF:
1403: n = input_get(ictx, 0, 0, 0);
1404: if (n == 4)
1405: screen_write_mode_clear(sctx, MODE_KEXTENDED);
1406: break;
1.65 nicm 1407: case INPUT_CSI_WINOPS:
1408: input_csi_dispatch_winops(ictx);
1409: break;
1.28 nicm 1410: case INPUT_CSI_CUU:
1.131 nicm 1411: n = input_get(ictx, 0, 1, 1);
1412: if (n != -1)
1413: screen_write_cursorup(sctx, n);
1.43 nicm 1414: break;
1415: case INPUT_CSI_CNL:
1.131 nicm 1416: n = input_get(ictx, 0, 1, 1);
1417: if (n != -1) {
1418: screen_write_carriagereturn(sctx);
1419: screen_write_cursordown(sctx, n);
1420: }
1.43 nicm 1421: break;
1422: case INPUT_CSI_CPL:
1.131 nicm 1423: n = input_get(ictx, 0, 1, 1);
1424: if (n != -1) {
1425: screen_write_carriagereturn(sctx);
1426: screen_write_cursorup(sctx, n);
1427: }
1.28 nicm 1428: break;
1429: case INPUT_CSI_DA:
1430: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1431: case -1:
1432: break;
1.28 nicm 1433: case 0:
1434: input_reply(ictx, "\033[?1;2c");
1.50 nicm 1435: break;
1436: default:
1437: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1438: break;
1439: }
1440: break;
1441: case INPUT_CSI_DA_TWO:
1442: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1443: case -1:
1444: break;
1.50 nicm 1445: case 0:
1.66 nicm 1446: input_reply(ictx, "\033[>84;0;0c");
1.28 nicm 1447: break;
1448: default:
1449: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1450: break;
1451: }
1.56 nicm 1452: break;
1453: case INPUT_CSI_ECH:
1.131 nicm 1454: n = input_get(ictx, 0, 1, 1);
1455: if (n != -1)
1456: screen_write_clearcharacter(sctx, n, bg);
1.28 nicm 1457: break;
1458: case INPUT_CSI_DCH:
1.131 nicm 1459: n = input_get(ictx, 0, 1, 1);
1460: if (n != -1)
1461: screen_write_deletecharacter(sctx, n, bg);
1.28 nicm 1462: break;
1463: case INPUT_CSI_DECSTBM:
1464: n = input_get(ictx, 0, 1, 1);
1465: m = input_get(ictx, 1, 1, screen_size_y(s));
1.131 nicm 1466: if (n != -1 && m != -1)
1467: screen_write_scrollregion(sctx, n - 1, m - 1);
1.1 nicm 1468: break;
1.28 nicm 1469: case INPUT_CSI_DL:
1.131 nicm 1470: n = input_get(ictx, 0, 1, 1);
1471: if (n != -1)
1472: screen_write_deleteline(sctx, n, bg);
1.1 nicm 1473: break;
1.28 nicm 1474: case INPUT_CSI_DSR:
1475: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1476: case -1:
1477: break;
1.28 nicm 1478: case 5:
1479: input_reply(ictx, "\033[0n");
1480: break;
1481: case 6:
1482: input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
1.168 nicm 1483: break;
1.28 nicm 1484: default:
1485: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1486: break;
1487: }
1488: break;
1489: case INPUT_CSI_ED:
1490: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1491: case -1:
1492: break;
1.28 nicm 1493: case 0:
1.131 nicm 1494: screen_write_clearendofscreen(sctx, bg);
1.28 nicm 1495: break;
1496: case 1:
1.131 nicm 1497: screen_write_clearstartofscreen(sctx, bg);
1.28 nicm 1498: break;
1499: case 2:
1.131 nicm 1500: screen_write_clearscreen(sctx, bg);
1.41 nicm 1501: break;
1502: case 3:
1.131 nicm 1503: if (input_get(ictx, 1, 0, 0) == 0) {
1.41 nicm 1504: /*
1505: * Linux console extension to clear history
1506: * (for example before locking the screen).
1507: */
1508: screen_write_clearhistory(sctx);
1509: }
1.28 nicm 1510: break;
1511: default:
1512: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1513: break;
1514: }
1515: break;
1516: case INPUT_CSI_EL:
1517: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1518: case -1:
1519: break;
1.28 nicm 1520: case 0:
1.131 nicm 1521: screen_write_clearendofline(sctx, bg);
1.28 nicm 1522: break;
1523: case 1:
1.131 nicm 1524: screen_write_clearstartofline(sctx, bg);
1.28 nicm 1525: break;
1526: case 2:
1.131 nicm 1527: screen_write_clearline(sctx, bg);
1.28 nicm 1528: break;
1529: default:
1530: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1531: break;
1532: }
1533: break;
1534: case INPUT_CSI_HPA:
1535: n = input_get(ictx, 0, 1, 1);
1.131 nicm 1536: if (n != -1)
1.148 nicm 1537: screen_write_cursormove(sctx, n - 1, -1, 1);
1.28 nicm 1538: break;
1539: case INPUT_CSI_ICH:
1.131 nicm 1540: n = input_get(ictx, 0, 1, 1);
1541: if (n != -1)
1542: screen_write_insertcharacter(sctx, n, bg);
1.28 nicm 1543: break;
1544: case INPUT_CSI_IL:
1.131 nicm 1545: n = input_get(ictx, 0, 1, 1);
1546: if (n != -1)
1547: screen_write_insertline(sctx, n, bg);
1.28 nicm 1548: break;
1.127 nicm 1549: case INPUT_CSI_REP:
1.131 nicm 1550: n = input_get(ictx, 0, 1, 1);
1551: if (n == -1)
1552: break;
1.185 nicm 1553:
1554: m = screen_size_x(s) - s->cx;
1555: if (n > m)
1556: n = m;
1.131 nicm 1557:
1.127 nicm 1558: if (ictx->last == -1)
1559: break;
1560: ictx->ch = ictx->last;
1561:
1562: for (i = 0; i < n; i++)
1563: input_print(ictx);
1564: break;
1.42 nicm 1565: case INPUT_CSI_RCP:
1.146 nicm 1566: input_restore_state(ictx);
1.42 nicm 1567: break;
1.28 nicm 1568: case INPUT_CSI_RM:
1.64 nicm 1569: input_csi_dispatch_rm(ictx);
1570: break;
1571: case INPUT_CSI_RM_PRIVATE:
1572: input_csi_dispatch_rm_private(ictx);
1573: break;
1574: case INPUT_CSI_SCP:
1.146 nicm 1575: input_save_state(ictx);
1.64 nicm 1576: break;
1577: case INPUT_CSI_SGR:
1578: input_csi_dispatch_sgr(ictx);
1579: break;
1580: case INPUT_CSI_SM:
1581: input_csi_dispatch_sm(ictx);
1582: break;
1583: case INPUT_CSI_SM_PRIVATE:
1584: input_csi_dispatch_sm_private(ictx);
1.115 nicm 1585: break;
1586: case INPUT_CSI_SU:
1.131 nicm 1587: n = input_get(ictx, 0, 1, 1);
1588: if (n != -1)
1589: screen_write_scrollup(sctx, n, bg);
1.159 nicm 1590: break;
1591: case INPUT_CSI_SD:
1592: n = input_get(ictx, 0, 1, 1);
1593: if (n != -1)
1594: screen_write_scrolldown(sctx, n, bg);
1.64 nicm 1595: break;
1596: case INPUT_CSI_TBC:
1597: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1598: case -1:
1599: break;
1.64 nicm 1600: case 0:
1601: if (s->cx < screen_size_x(s))
1602: bit_clear(s->tabs, s->cx);
1603: break;
1604: case 3:
1605: bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1606: break;
1607: default:
1608: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1609: break;
1610: }
1611: break;
1612: case INPUT_CSI_VPA:
1613: n = input_get(ictx, 0, 1, 1);
1.131 nicm 1614: if (n != -1)
1.148 nicm 1615: screen_write_cursormove(sctx, -1, n - 1, 1);
1.64 nicm 1616: break;
1617: case INPUT_CSI_DECSCUSR:
1618: n = input_get(ictx, 0, 0, 0);
1.131 nicm 1619: if (n != -1)
1620: screen_set_cursor_style(s, n);
1.64 nicm 1621: break;
1.175 nicm 1622: case INPUT_CSI_XDA:
1623: n = input_get(ictx, 0, 0, 0);
1.178 nicm 1624: if (n == 0)
1.175 nicm 1625: input_reply(ictx, "\033P>|tmux %s\033\\", getversion());
1626: break;
1627:
1.64 nicm 1628: }
1629:
1.127 nicm 1630: ictx->last = -1;
1.64 nicm 1631: return (0);
1632: }
1633:
1634: /* Handle CSI RM. */
1.104 nicm 1635: static void
1.64 nicm 1636: input_csi_dispatch_rm(struct input_ctx *ictx)
1637: {
1.144 nicm 1638: struct screen_write_ctx *sctx = &ictx->ctx;
1639: u_int i;
1.64 nicm 1640:
1641: for (i = 0; i < ictx->param_list_len; i++) {
1642: switch (input_get(ictx, i, 0, -1)) {
1.131 nicm 1643: case -1:
1644: break;
1.28 nicm 1645: case 4: /* IRM */
1.144 nicm 1646: screen_write_mode_clear(sctx, MODE_INSERT);
1.28 nicm 1647: break;
1.72 nicm 1648: case 34:
1.144 nicm 1649: screen_write_mode_set(sctx, MODE_BLINKING);
1.72 nicm 1650: break;
1.28 nicm 1651: default:
1652: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1653: break;
1654: }
1.64 nicm 1655: }
1656: }
1657:
1658: /* Handle CSI private RM. */
1.104 nicm 1659: static void
1.64 nicm 1660: input_csi_dispatch_rm_private(struct input_ctx *ictx)
1661: {
1.144 nicm 1662: struct screen_write_ctx *sctx = &ictx->ctx;
1.171 nicm 1663: struct grid_cell *gc = &ictx->cell.cell;
1.69 nicm 1664: u_int i;
1.64 nicm 1665:
1666: for (i = 0; i < ictx->param_list_len; i++) {
1667: switch (input_get(ictx, i, 0, -1)) {
1.131 nicm 1668: case -1:
1669: break;
1.64 nicm 1670: case 1: /* DECCKM */
1.144 nicm 1671: screen_write_mode_clear(sctx, MODE_KCURSOR);
1.1 nicm 1672: break;
1.17 nicm 1673: case 3: /* DECCOLM */
1.146 nicm 1674: screen_write_cursormove(sctx, 0, 0, 1);
1.171 nicm 1675: screen_write_clearscreen(sctx, gc->bg);
1.17 nicm 1676: break;
1.141 nicm 1677: case 6: /* DECOM */
1.144 nicm 1678: screen_write_mode_clear(sctx, MODE_ORIGIN);
1.146 nicm 1679: screen_write_cursormove(sctx, 0, 0, 1);
1.141 nicm 1680: break;
1.61 nicm 1681: case 7: /* DECAWM */
1.144 nicm 1682: screen_write_mode_clear(sctx, MODE_WRAP);
1.61 nicm 1683: break;
1.72 nicm 1684: case 12:
1.144 nicm 1685: screen_write_mode_clear(sctx, MODE_BLINKING);
1.72 nicm 1686: break;
1.1 nicm 1687: case 25: /* TCEM */
1.144 nicm 1688: screen_write_mode_clear(sctx, MODE_CURSOR);
1.1 nicm 1689: break;
1690: case 1000:
1.32 nicm 1691: case 1001:
1692: case 1002:
1.109 nicm 1693: case 1003:
1.144 nicm 1694: screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1.1 nicm 1695: break;
1.62 nicm 1696: case 1004:
1.144 nicm 1697: screen_write_mode_clear(sctx, MODE_FOCUSON);
1.62 nicm 1698: break;
1.96 nicm 1699: case 1005:
1.144 nicm 1700: screen_write_mode_clear(sctx, MODE_MOUSE_UTF8);
1.96 nicm 1701: break;
1.60 nicm 1702: case 1006:
1.144 nicm 1703: screen_write_mode_clear(sctx, MODE_MOUSE_SGR);
1.60 nicm 1704: break;
1.55 nicm 1705: case 47:
1706: case 1047:
1.177 nicm 1707: screen_write_alternateoff(sctx, gc, 0);
1.55 nicm 1708: break;
1.9 nicm 1709: case 1049:
1.177 nicm 1710: screen_write_alternateoff(sctx, gc, 1);
1.9 nicm 1711: break;
1.49 nicm 1712: case 2004:
1.144 nicm 1713: screen_write_mode_clear(sctx, MODE_BRACKETPASTE);
1.49 nicm 1714: break;
1.1 nicm 1715: default:
1.28 nicm 1716: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1717: break;
1718: }
1.64 nicm 1719: }
1720: }
1721:
1722: /* Handle CSI SM. */
1.104 nicm 1723: static void
1.64 nicm 1724: input_csi_dispatch_sm(struct input_ctx *ictx)
1725: {
1.144 nicm 1726: struct screen_write_ctx *sctx = &ictx->ctx;
1727: u_int i;
1.64 nicm 1728:
1729: for (i = 0; i < ictx->param_list_len; i++) {
1730: switch (input_get(ictx, i, 0, -1)) {
1.131 nicm 1731: case -1:
1732: break;
1.1 nicm 1733: case 4: /* IRM */
1.144 nicm 1734: screen_write_mode_set(sctx, MODE_INSERT);
1.1 nicm 1735: break;
1.72 nicm 1736: case 34:
1.144 nicm 1737: screen_write_mode_clear(sctx, MODE_BLINKING);
1.72 nicm 1738: break;
1.1 nicm 1739: default:
1.28 nicm 1740: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1741: break;
1742: }
1.64 nicm 1743: }
1744: }
1745:
1746: /* Handle CSI private SM. */
1.104 nicm 1747: static void
1.64 nicm 1748: input_csi_dispatch_sm_private(struct input_ctx *ictx)
1749: {
1.144 nicm 1750: struct screen_write_ctx *sctx = &ictx->ctx;
1.69 nicm 1751: struct window_pane *wp = ictx->wp;
1.171 nicm 1752: struct grid_cell *gc = &ictx->cell.cell;
1.69 nicm 1753: u_int i;
1.64 nicm 1754:
1755: for (i = 0; i < ictx->param_list_len; i++) {
1756: switch (input_get(ictx, i, 0, -1)) {
1.131 nicm 1757: case -1:
1758: break;
1.64 nicm 1759: case 1: /* DECCKM */
1.144 nicm 1760: screen_write_mode_set(sctx, MODE_KCURSOR);
1.17 nicm 1761: break;
1762: case 3: /* DECCOLM */
1.146 nicm 1763: screen_write_cursormove(sctx, 0, 0, 1);
1.144 nicm 1764: screen_write_clearscreen(sctx, ictx->cell.cell.bg);
1.141 nicm 1765: break;
1766: case 6: /* DECOM */
1.144 nicm 1767: screen_write_mode_set(sctx, MODE_ORIGIN);
1.146 nicm 1768: screen_write_cursormove(sctx, 0, 0, 1);
1.61 nicm 1769: break;
1770: case 7: /* DECAWM */
1.144 nicm 1771: screen_write_mode_set(sctx, MODE_WRAP);
1.72 nicm 1772: break;
1773: case 12:
1.144 nicm 1774: screen_write_mode_set(sctx, MODE_BLINKING);
1.1 nicm 1775: break;
1776: case 25: /* TCEM */
1.144 nicm 1777: screen_write_mode_set(sctx, MODE_CURSOR);
1.1 nicm 1778: break;
1779: case 1000:
1.144 nicm 1780: screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1781: screen_write_mode_set(sctx, MODE_MOUSE_STANDARD);
1.32 nicm 1782: break;
1783: case 1002:
1.144 nicm 1784: screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1785: screen_write_mode_set(sctx, MODE_MOUSE_BUTTON);
1.109 nicm 1786: break;
1787: case 1003:
1.144 nicm 1788: screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1789: screen_write_mode_set(sctx, MODE_MOUSE_ALL);
1.62 nicm 1790: break;
1791: case 1004:
1.144 nicm 1792: if (sctx->s->mode & MODE_FOCUSON)
1.62 nicm 1793: break;
1.144 nicm 1794: screen_write_mode_set(sctx, MODE_FOCUSON);
1.191 nicm 1795: if (wp == NULL)
1796: break;
1797: if (wp->flags & PANE_FOCUSED)
1798: bufferevent_write(wp->event, "\033[I", 3);
1799: else
1800: bufferevent_write(wp->event, "\033[O", 3);
1.96 nicm 1801: break;
1802: case 1005:
1.144 nicm 1803: screen_write_mode_set(sctx, MODE_MOUSE_UTF8);
1.60 nicm 1804: break;
1805: case 1006:
1.144 nicm 1806: screen_write_mode_set(sctx, MODE_MOUSE_SGR);
1.9 nicm 1807: break;
1.55 nicm 1808: case 47:
1809: case 1047:
1.177 nicm 1810: screen_write_alternateon(sctx, gc, 0);
1.55 nicm 1811: break;
1.9 nicm 1812: case 1049:
1.177 nicm 1813: screen_write_alternateon(sctx, gc, 1);
1.49 nicm 1814: break;
1815: case 2004:
1.144 nicm 1816: screen_write_mode_set(sctx, MODE_BRACKETPASTE);
1.1 nicm 1817: break;
1818: default:
1.28 nicm 1819: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1820: break;
1821: }
1.65 nicm 1822: }
1823: }
1824:
1825: /* Handle CSI window operations. */
1.104 nicm 1826: static void
1.65 nicm 1827: input_csi_dispatch_winops(struct input_ctx *ictx)
1828: {
1.144 nicm 1829: struct screen_write_ctx *sctx = &ictx->ctx;
1.172 nicm 1830: struct screen *s = sctx->s;
1.65 nicm 1831: struct window_pane *wp = ictx->wp;
1.172 nicm 1832: u_int x = screen_size_x(s), y = screen_size_y(s);
1.65 nicm 1833: int n, m;
1834:
1835: m = 0;
1836: while ((n = input_get(ictx, m, 0, -1)) != -1) {
1837: switch (n) {
1838: case 1:
1839: case 2:
1840: case 5:
1841: case 6:
1842: case 7:
1843: case 11:
1844: case 13:
1845: case 14:
1846: case 19:
1847: case 20:
1848: case 21:
1849: case 24:
1850: break;
1851: case 3:
1852: case 4:
1853: case 8:
1854: m++;
1855: if (input_get(ictx, m, 0, -1) == -1)
1856: return;
1857: /* FALLTHROUGH */
1858: case 9:
1859: case 10:
1.129 nicm 1860: m++;
1861: if (input_get(ictx, m, 0, -1) == -1)
1862: return;
1863: break;
1.65 nicm 1864: case 22:
1.129 nicm 1865: m++;
1866: switch (input_get(ictx, m, 0, -1)) {
1867: case -1:
1868: return;
1869: case 0:
1870: case 2:
1.144 nicm 1871: screen_push_title(sctx->s);
1.129 nicm 1872: break;
1873: }
1874: break;
1.65 nicm 1875: case 23:
1876: m++;
1.129 nicm 1877: switch (input_get(ictx, m, 0, -1)) {
1878: case -1:
1.65 nicm 1879: return;
1.129 nicm 1880: case 0:
1881: case 2:
1.144 nicm 1882: screen_pop_title(sctx->s);
1.190 nicm 1883: if (wp == NULL)
1884: break;
1885: notify_pane("pane-title-changed", wp);
1886: server_redraw_window_borders(wp->window);
1887: server_status_window(wp->window);
1.129 nicm 1888: break;
1889: }
1.65 nicm 1890: break;
1891: case 18:
1.172 nicm 1892: input_reply(ictx, "\033[8;%u;%ut", x, y);
1.65 nicm 1893: break;
1894: default:
1895: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1896: break;
1897: }
1898: m++;
1.1 nicm 1899: }
1900: }
1901:
1.131 nicm 1902: /* Helper for 256 colour SGR. */
1903: static int
1904: input_csi_dispatch_sgr_256_do(struct input_ctx *ictx, int fgbg, int c)
1.78 nicm 1905: {
1906: struct grid_cell *gc = &ictx->cell.cell;
1907:
1.131 nicm 1908: if (c == -1 || c > 255) {
1.102 nicm 1909: if (fgbg == 38)
1.78 nicm 1910: gc->fg = 8;
1.102 nicm 1911: else if (fgbg == 48)
1.78 nicm 1912: gc->bg = 8;
1913: } else {
1.102 nicm 1914: if (fgbg == 38)
1915: gc->fg = c | COLOUR_FLAG_256;
1916: else if (fgbg == 48)
1917: gc->bg = c | COLOUR_FLAG_256;
1.158 nicm 1918: else if (fgbg == 58)
1919: gc->us = c | COLOUR_FLAG_256;
1.78 nicm 1920: }
1.131 nicm 1921: return (1);
1.78 nicm 1922: }
1923:
1.131 nicm 1924: /* Handle CSI SGR for 256 colours. */
1.104 nicm 1925: static void
1.131 nicm 1926: input_csi_dispatch_sgr_256(struct input_ctx *ictx, int fgbg, u_int *i)
1927: {
1928: int c;
1929:
1930: c = input_get(ictx, (*i) + 1, 0, -1);
1931: if (input_csi_dispatch_sgr_256_do(ictx, fgbg, c))
1932: (*i)++;
1933: }
1934:
1935: /* Helper for RGB colour SGR. */
1936: static int
1937: input_csi_dispatch_sgr_rgb_do(struct input_ctx *ictx, int fgbg, int r, int g,
1938: int b)
1.78 nicm 1939: {
1940: struct grid_cell *gc = &ictx->cell.cell;
1941:
1942: if (r == -1 || r > 255)
1.131 nicm 1943: return (0);
1.78 nicm 1944: if (g == -1 || g > 255)
1.131 nicm 1945: return (0);
1.78 nicm 1946: if (b == -1 || b > 255)
1.131 nicm 1947: return (0);
1.78 nicm 1948:
1.102 nicm 1949: if (fgbg == 38)
1950: gc->fg = colour_join_rgb(r, g, b);
1951: else if (fgbg == 48)
1952: gc->bg = colour_join_rgb(r, g, b);
1.158 nicm 1953: else if (fgbg == 58)
1954: gc->us = colour_join_rgb(r, g, b);
1.131 nicm 1955: return (1);
1956: }
1957:
1958: /* Handle CSI SGR for RGB colours. */
1959: static void
1960: input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i)
1961: {
1962: int r, g, b;
1963:
1964: r = input_get(ictx, (*i) + 1, 0, -1);
1965: g = input_get(ictx, (*i) + 2, 0, -1);
1966: b = input_get(ictx, (*i) + 3, 0, -1);
1967: if (input_csi_dispatch_sgr_rgb_do(ictx, fgbg, r, g, b))
1968: (*i) += 3;
1969: }
1970:
1971: /* Handle CSI SGR with a ISO parameter. */
1972: static void
1973: input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i)
1974: {
1.137 nicm 1975: struct grid_cell *gc = &ictx->cell.cell;
1976: char *s = ictx->param_list[i].str, *copy, *ptr, *out;
1977: int p[8];
1978: u_int n;
1979: const char *errstr;
1.131 nicm 1980:
1981: for (n = 0; n < nitems(p); n++)
1982: p[n] = -1;
1983: n = 0;
1984:
1985: ptr = copy = xstrdup(s);
1986: while ((out = strsep(&ptr, ":")) != NULL) {
1.134 nicm 1987: if (*out != '\0') {
1988: p[n++] = strtonum(out, 0, INT_MAX, &errstr);
1989: if (errstr != NULL || n == nitems(p)) {
1990: free(copy);
1991: return;
1992: }
1.184 nicm 1993: } else {
1.140 nicm 1994: n++;
1.184 nicm 1995: if (n == nitems(p)) {
1996: free(copy);
1997: return;
1998: }
1999: }
1.131 nicm 2000: log_debug("%s: %u = %d", __func__, n - 1, p[n - 1]);
2001: }
2002: free(copy);
2003:
1.137 nicm 2004: if (n == 0)
2005: return;
2006: if (p[0] == 4) {
2007: if (n != 2)
2008: return;
2009: switch (p[1]) {
2010: case 0:
2011: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2012: break;
2013: case 1:
2014: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2015: gc->attr |= GRID_ATTR_UNDERSCORE;
2016: break;
2017: case 2:
2018: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2019: gc->attr |= GRID_ATTR_UNDERSCORE_2;
2020: break;
2021: case 3:
2022: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2023: gc->attr |= GRID_ATTR_UNDERSCORE_3;
2024: break;
2025: case 4:
2026: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2027: gc->attr |= GRID_ATTR_UNDERSCORE_4;
2028: break;
2029: case 5:
2030: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2031: gc->attr |= GRID_ATTR_UNDERSCORE_5;
2032: break;
2033: }
2034: return;
2035: }
1.158 nicm 2036: if (n < 2 || (p[0] != 38 && p[0] != 48 && p[0] != 58))
1.131 nicm 2037: return;
1.154 nicm 2038: switch (p[1]) {
1.131 nicm 2039: case 2:
1.154 nicm 2040: if (n < 3)
2041: break;
2042: if (n == 5)
2043: i = 2;
2044: else
2045: i = 3;
2046: if (n < i + 3)
1.131 nicm 2047: break;
1.154 nicm 2048: input_csi_dispatch_sgr_rgb_do(ictx, p[0], p[i], p[i + 1],
2049: p[i + 2]);
1.131 nicm 2050: break;
2051: case 5:
1.154 nicm 2052: if (n < 3)
1.131 nicm 2053: break;
1.154 nicm 2054: input_csi_dispatch_sgr_256_do(ictx, p[0], p[2]);
1.131 nicm 2055: break;
2056: }
1.78 nicm 2057: }
2058:
1.28 nicm 2059: /* Handle CSI SGR. */
1.104 nicm 2060: static void
1.28 nicm 2061: input_csi_dispatch_sgr(struct input_ctx *ictx)
1.1 nicm 2062: {
1.69 nicm 2063: struct grid_cell *gc = &ictx->cell.cell;
1.28 nicm 2064: u_int i;
1.78 nicm 2065: int n;
1.1 nicm 2066:
1.28 nicm 2067: if (ictx->param_list_len == 0) {
1.1 nicm 2068: memcpy(gc, &grid_default_cell, sizeof *gc);
2069: return;
2070: }
2071:
1.28 nicm 2072: for (i = 0; i < ictx->param_list_len; i++) {
1.131 nicm 2073: if (ictx->param_list[i].type == INPUT_STRING) {
2074: input_csi_dispatch_sgr_colon(ictx, i);
2075: continue;
2076: }
1.28 nicm 2077: n = input_get(ictx, i, 0, 0);
1.131 nicm 2078: if (n == -1)
2079: continue;
1.1 nicm 2080:
1.158 nicm 2081: if (n == 38 || n == 48 || n == 58) {
1.1 nicm 2082: i++;
1.78 nicm 2083: switch (input_get(ictx, i, 0, -1)) {
2084: case 2:
2085: input_csi_dispatch_sgr_rgb(ictx, n, &i);
2086: break;
2087: case 5:
2088: input_csi_dispatch_sgr_256(ictx, n, &i);
2089: break;
1.1 nicm 2090: }
2091: continue;
2092: }
2093:
1.28 nicm 2094: switch (n) {
1.1 nicm 2095: case 0:
2096: memcpy(gc, &grid_default_cell, sizeof *gc);
2097: break;
2098: case 1:
2099: gc->attr |= GRID_ATTR_BRIGHT;
2100: break;
2101: case 2:
2102: gc->attr |= GRID_ATTR_DIM;
2103: break;
2104: case 3:
2105: gc->attr |= GRID_ATTR_ITALICS;
2106: break;
2107: case 4:
1.137 nicm 2108: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1.1 nicm 2109: gc->attr |= GRID_ATTR_UNDERSCORE;
2110: break;
2111: case 5:
1.187 nicm 2112: case 6:
1.1 nicm 2113: gc->attr |= GRID_ATTR_BLINK;
2114: break;
2115: case 7:
2116: gc->attr |= GRID_ATTR_REVERSE;
2117: break;
2118: case 8:
2119: gc->attr |= GRID_ATTR_HIDDEN;
2120: break;
1.118 nicm 2121: case 9:
2122: gc->attr |= GRID_ATTR_STRIKETHROUGH;
1.187 nicm 2123: break;
2124: case 21:
2125: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2126: gc->attr |= GRID_ATTR_UNDERSCORE_2;
1.118 nicm 2127: break;
1.1 nicm 2128: case 22:
2129: gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
2130: break;
2131: case 23:
2132: gc->attr &= ~GRID_ATTR_ITALICS;
2133: break;
2134: case 24:
1.137 nicm 2135: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1.1 nicm 2136: break;
2137: case 25:
2138: gc->attr &= ~GRID_ATTR_BLINK;
2139: break;
2140: case 27:
2141: gc->attr &= ~GRID_ATTR_REVERSE;
1.117 nicm 2142: break;
2143: case 28:
2144: gc->attr &= ~GRID_ATTR_HIDDEN;
1.118 nicm 2145: break;
2146: case 29:
2147: gc->attr &= ~GRID_ATTR_STRIKETHROUGH;
1.1 nicm 2148: break;
2149: case 30:
2150: case 31:
2151: case 32:
2152: case 33:
2153: case 34:
2154: case 35:
2155: case 36:
2156: case 37:
1.28 nicm 2157: gc->fg = n - 30;
1.1 nicm 2158: break;
2159: case 39:
2160: gc->fg = 8;
2161: break;
2162: case 40:
2163: case 41:
2164: case 42:
2165: case 43:
2166: case 44:
2167: case 45:
2168: case 46:
2169: case 47:
1.28 nicm 2170: gc->bg = n - 40;
1.1 nicm 2171: break;
2172: case 49:
2173: gc->bg = 8;
1.153 nicm 2174: break;
2175: case 53:
2176: gc->attr |= GRID_ATTR_OVERLINE;
2177: break;
2178: case 55:
2179: gc->attr &= ~GRID_ATTR_OVERLINE;
1.158 nicm 2180: break;
2181: case 59:
2182: gc->us = 0;
1.20 nicm 2183: break;
2184: case 90:
2185: case 91:
2186: case 92:
2187: case 93:
2188: case 94:
2189: case 95:
2190: case 96:
2191: case 97:
1.28 nicm 2192: gc->fg = n;
1.20 nicm 2193: break;
2194: case 100:
2195: case 101:
2196: case 102:
2197: case 103:
2198: case 104:
2199: case 105:
2200: case 106:
2201: case 107:
1.47 nicm 2202: gc->bg = n - 10;
1.1 nicm 2203: break;
2204: }
2205: }
1.28 nicm 2206: }
2207:
1.138 nicm 2208: /* End of input with BEL. */
2209: static int
2210: input_end_bel(struct input_ctx *ictx)
2211: {
2212: log_debug("%s", __func__);
2213:
2214: ictx->input_end = INPUT_END_BEL;
2215:
2216: return (0);
2217: }
2218:
1.125 nicm 2219: /* DCS string started. */
2220: static void
2221: input_enter_dcs(struct input_ctx *ictx)
2222: {
2223: log_debug("%s", __func__);
2224:
2225: input_clear(ictx);
2226: input_start_timer(ictx);
1.127 nicm 2227: ictx->last = -1;
1.125 nicm 2228: }
2229:
1.37 nicm 2230: /* DCS terminator (ST) received. */
1.104 nicm 2231: static int
1.37 nicm 2232: input_dcs_dispatch(struct input_ctx *ictx)
1.28 nicm 2233: {
1.144 nicm 2234: struct screen_write_ctx *sctx = &ictx->ctx;
2235: u_char *buf = ictx->input_buf;
2236: size_t len = ictx->input_len;
2237: const char prefix[] = "tmux;";
2238: const u_int prefixlen = (sizeof prefix) - 1;
1.37 nicm 2239:
2240: if (ictx->flags & INPUT_DISCARD)
2241: return (0);
2242:
1.144 nicm 2243: log_debug("%s: \"%s\"", __func__, buf);
1.28 nicm 2244:
1.144 nicm 2245: if (len >= prefixlen && strncmp(buf, prefix, prefixlen) == 0)
2246: screen_write_rawstring(sctx, buf + prefixlen, len - prefixlen);
1.28 nicm 2247:
1.37 nicm 2248: return (0);
1.28 nicm 2249: }
2250:
2251: /* OSC string started. */
1.104 nicm 2252: static void
1.28 nicm 2253: input_enter_osc(struct input_ctx *ictx)
2254: {
2255: log_debug("%s", __func__);
2256:
1.35 nicm 2257: input_clear(ictx);
1.125 nicm 2258: input_start_timer(ictx);
1.127 nicm 2259: ictx->last = -1;
1.28 nicm 2260: }
2261:
2262: /* OSC terminator (ST) received. */
1.104 nicm 2263: static void
1.28 nicm 2264: input_exit_osc(struct input_ctx *ictx)
2265: {
1.144 nicm 2266: struct screen_write_ctx *sctx = &ictx->ctx;
1.171 nicm 2267: struct window_pane *wp = ictx->wp;
1.144 nicm 2268: u_char *p = ictx->input_buf;
2269: u_int option;
1.38 nicm 2270:
1.28 nicm 2271: if (ictx->flags & INPUT_DISCARD)
2272: return;
1.38 nicm 2273: if (ictx->input_len < 1 || *p < '0' || *p > '9')
2274: return;
1.28 nicm 2275:
1.138 nicm 2276: log_debug("%s: \"%s\" (end %s)", __func__, p,
2277: ictx->input_end == INPUT_END_ST ? "ST" : "BEL");
1.28 nicm 2278:
1.38 nicm 2279: option = 0;
2280: while (*p >= '0' && *p <= '9')
2281: option = option * 10 + *p++ - '0';
2282: if (*p == ';')
2283: p++;
2284:
2285: switch (option) {
2286: case 0:
2287: case 2:
1.176 nicm 2288: if (screen_set_title(sctx->s, p) && wp != NULL) {
1.182 nicm 2289: notify_pane("pane-title-changed", wp);
1.176 nicm 2290: server_redraw_window_borders(wp->window);
2291: server_status_window(wp->window);
2292: }
1.38 nicm 2293: break;
1.107 nicm 2294: case 4:
1.138 nicm 2295: input_osc_4(ictx, p);
1.165 nicm 2296: break;
2297: case 7:
2298: if (utf8_isvalid(p)) {
2299: screen_set_path(sctx->s, p);
1.176 nicm 2300: if (wp != NULL) {
2301: server_redraw_window_borders(wp->window);
1.171 nicm 2302: server_status_window(wp->window);
1.176 nicm 2303: }
1.165 nicm 2304: }
1.107 nicm 2305: break;
1.122 nicm 2306: case 10:
1.138 nicm 2307: input_osc_10(ictx, p);
1.122 nicm 2308: break;
2309: case 11:
1.138 nicm 2310: input_osc_11(ictx, p);
1.108 nicm 2311: break;
1.38 nicm 2312: case 12:
1.124 nicm 2313: if (utf8_isvalid(p) && *p != '?') /* ? is colour request */
1.144 nicm 2314: screen_set_cursor_colour(sctx->s, p);
1.38 nicm 2315: break;
1.122 nicm 2316: case 52:
1.138 nicm 2317: input_osc_52(ictx, p);
1.122 nicm 2318: break;
1.107 nicm 2319: case 104:
1.138 nicm 2320: input_osc_104(ictx, p);
1.107 nicm 2321: break;
1.186 nicm 2322: case 110:
2323: input_osc_110(ictx, p);
2324: break;
2325: case 111:
2326: input_osc_111(ictx, p);
2327: break;
1.38 nicm 2328: case 112:
1.57 nicm 2329: if (*p == '\0') /* no arguments allowed */
1.144 nicm 2330: screen_set_cursor_colour(sctx->s, "");
1.38 nicm 2331: break;
2332: default:
2333: log_debug("%s: unknown '%u'", __func__, option);
2334: break;
2335: }
1.28 nicm 2336: }
2337:
2338: /* APC string started. */
1.104 nicm 2339: static void
1.28 nicm 2340: input_enter_apc(struct input_ctx *ictx)
2341: {
2342: log_debug("%s", __func__);
2343:
1.35 nicm 2344: input_clear(ictx);
1.125 nicm 2345: input_start_timer(ictx);
1.127 nicm 2346: ictx->last = -1;
1.28 nicm 2347: }
2348:
2349: /* APC terminator (ST) received. */
1.104 nicm 2350: static void
1.28 nicm 2351: input_exit_apc(struct input_ctx *ictx)
2352: {
1.144 nicm 2353: struct screen_write_ctx *sctx = &ictx->ctx;
1.171 nicm 2354: struct window_pane *wp = ictx->wp;
1.144 nicm 2355:
1.28 nicm 2356: if (ictx->flags & INPUT_DISCARD)
2357: return;
2358: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
2359:
1.176 nicm 2360: if (screen_set_title(sctx->s, ictx->input_buf) && wp != NULL) {
1.182 nicm 2361: notify_pane("pane-title-changed", wp);
1.176 nicm 2362: server_redraw_window_borders(wp->window);
1.171 nicm 2363: server_status_window(wp->window);
1.176 nicm 2364: }
1.28 nicm 2365: }
2366:
2367: /* Rename string started. */
1.104 nicm 2368: static void
1.28 nicm 2369: input_enter_rename(struct input_ctx *ictx)
2370: {
2371: log_debug("%s", __func__);
2372:
1.35 nicm 2373: input_clear(ictx);
1.125 nicm 2374: input_start_timer(ictx);
1.127 nicm 2375: ictx->last = -1;
1.28 nicm 2376: }
2377:
2378: /* Rename terminator (ST) received. */
1.104 nicm 2379: static void
1.28 nicm 2380: input_exit_rename(struct input_ctx *ictx)
2381: {
1.162 nicm 2382: struct window_pane *wp = ictx->wp;
1.181 nicm 2383: struct options_entry *o;
1.162 nicm 2384:
1.171 nicm 2385: if (wp == NULL)
2386: return;
1.28 nicm 2387: if (ictx->flags & INPUT_DISCARD)
1.44 nicm 2388: return;
1.157 nicm 2389: if (!options_get_number(ictx->wp->options, "allow-rename"))
1.28 nicm 2390: return;
2391: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
2392:
1.124 nicm 2393: if (!utf8_isvalid(ictx->input_buf))
2394: return;
1.162 nicm 2395:
2396: if (ictx->input_len == 0) {
1.181 nicm 2397: o = options_get_only(wp->window->options, "automatic-rename");
2398: if (o != NULL)
2399: options_remove_or_default(o, -1, NULL);
1.162 nicm 2400: return;
2401: }
1.171 nicm 2402: window_set_name(wp->window, ictx->input_buf);
2403: options_set_number(wp->window->options, "automatic-rename", 0);
1.176 nicm 2404: server_redraw_window_borders(wp->window);
1.171 nicm 2405: server_status_window(wp->window);
1.28 nicm 2406: }
2407:
2408: /* Open UTF-8 character. */
1.104 nicm 2409: static int
1.130 nicm 2410: input_top_bit_set(struct input_ctx *ictx)
1.28 nicm 2411: {
1.144 nicm 2412: struct screen_write_ctx *sctx = &ictx->ctx;
1.90 nicm 2413: struct utf8_data *ud = &ictx->utf8data;
2414:
1.127 nicm 2415: ictx->last = -1;
1.28 nicm 2416:
1.130 nicm 2417: if (!ictx->utf8started) {
2418: if (utf8_open(ud, ictx->ch) != UTF8_MORE)
2419: return (0);
2420: ictx->utf8started = 1;
2421: return (0);
2422: }
1.28 nicm 2423:
1.130 nicm 2424: switch (utf8_append(ud, ictx->ch)) {
2425: case UTF8_MORE:
2426: return (0);
2427: case UTF8_ERROR:
2428: ictx->utf8started = 0;
1.101 nicm 2429: return (0);
1.130 nicm 2430: case UTF8_DONE:
2431: break;
1.101 nicm 2432: }
1.130 nicm 2433: ictx->utf8started = 0;
1.28 nicm 2434:
1.90 nicm 2435: log_debug("%s %hhu '%*s' (width %hhu)", __func__, ud->size,
2436: (int)ud->size, ud->data, ud->width);
1.28 nicm 2437:
1.90 nicm 2438: utf8_copy(&ictx->cell.cell.data, ud);
1.144 nicm 2439: screen_write_collect_add(sctx, &ictx->cell.cell);
1.28 nicm 2440:
2441: return (0);
1.107 nicm 2442: }
2443:
1.163 nicm 2444: /* Parse colour from OSC. */
2445: static int
1.186 nicm 2446: input_osc_parse_colour(const char *p)
1.163 nicm 2447: {
1.186 nicm 2448: double c, m, y, k = 0;
2449: u_int r, g, b;
2450: size_t len = strlen(p);
2451: int colour = -1;
2452: char *copy;
2453:
2454: if ((len == 12 && sscanf(p, "rgb:%02x/%02x/%02x", &r, &g, &b) == 3) ||
2455: (len == 7 && sscanf(p, "#%02x%02x%02x", &r, &g, &b) == 3) ||
2456: sscanf(p, "%d,%d,%d", &r, &g, &b) == 3)
2457: colour = colour_join_rgb(r, g, b);
2458: else if ((len == 18 &&
2459: sscanf(p, "rgb:%04x/%04x/%04x", &r, &g, &b) == 3) ||
2460: (len == 13 && sscanf(p, "#%04x%04x%04x", &r, &g, &b) == 3))
2461: colour = colour_join_rgb(r >> 8, g >> 8, b >> 8);
2462: else if ((sscanf(p, "cmyk:%lf/%lf/%lf/%lf", &c, &m, &y, &k) == 4 ||
2463: sscanf(p, "cmy:%lf/%lf/%lf", &c, &m, &y) == 3) &&
2464: c >= 0 && c <= 1 && m >= 0 && m <= 1 &&
2465: y >= 0 && y <= 1 && k >= 0 && k <= 1) {
2466: colour = colour_join_rgb(
2467: (1 - c) * (1 - k) * 255,
2468: (1 - m) * (1 - k) * 255,
2469: (1 - y) * (1 - k) * 255);
2470: } else {
1.188 nicm 2471: while (len != 0 && *p == ' ') {
1.186 nicm 2472: p++;
1.188 nicm 2473: len--;
2474: }
1.186 nicm 2475: while (len != 0 && p[len - 1] == ' ')
2476: len--;
2477: copy = xstrndup(p, len);
2478: colour = colour_byname(copy);
2479: free(copy);
2480: }
2481: log_debug("%s: %s = %s", __func__, p, colour_tostring(colour));
2482: return (colour);
1.163 nicm 2483: }
2484:
1.183 nicm 2485: /* Reply to a colour request. */
2486: static void
2487: input_osc_colour_reply(struct input_ctx *ictx, u_int n, int c)
2488: {
2489: u_char r, g, b;
2490: const char *end;
2491:
2492: if (c == 8 || (~c & COLOUR_FLAG_RGB))
2493: return;
2494: colour_split_rgb(c, &r, &g, &b);
2495:
2496: if (ictx->input_end == INPUT_END_BEL)
2497: end = "\007";
2498: else
2499: end = "\033\\";
2500: input_reply(ictx, "\033]%u;rgb:%02hhx/%02hhx/%02hhx%s", n, r, g, b, end);
2501: }
2502:
1.107 nicm 2503: /* Handle the OSC 4 sequence for setting (multiple) palette entries. */
2504: static void
1.138 nicm 2505: input_osc_4(struct input_ctx *ictx, const char *p)
1.107 nicm 2506: {
1.190 nicm 2507: char *copy, *s, *next = NULL;
2508: long idx;
2509: int c, bad = 0, redraw = 0;
1.171 nicm 2510:
1.107 nicm 2511: copy = s = xstrdup(p);
2512: while (s != NULL && *s != '\0') {
2513: idx = strtol(s, &next, 10);
1.190 nicm 2514: if (*next++ != ';') {
2515: bad = 1;
2516: break;
2517: }
2518: if (idx < 0 || idx >= 256) {
2519: bad = 1;
2520: break;
2521: }
1.107 nicm 2522:
2523: s = strsep(&next, ";");
1.186 nicm 2524: if ((c = input_osc_parse_colour(s)) == -1) {
1.107 nicm 2525: s = next;
2526: continue;
2527: }
1.190 nicm 2528: if (colour_palette_set(ictx->palette, idx, c))
2529: redraw = 1;
1.107 nicm 2530: s = next;
2531: }
1.190 nicm 2532: if (bad)
2533: log_debug("bad OSC 4: %s", p);
2534: if (redraw)
2535: screen_write_fullredraw(&ictx->ctx);
1.107 nicm 2536: free(copy);
1.122 nicm 2537: }
2538:
1.183 nicm 2539: /* Handle the OSC 10 sequence for setting and querying foreground colour. */
1.122 nicm 2540: static void
1.138 nicm 2541: input_osc_10(struct input_ctx *ictx, const char *p)
1.122 nicm 2542: {
1.138 nicm 2543: struct window_pane *wp = ictx->wp;
1.183 nicm 2544: struct grid_cell defaults;
1.186 nicm 2545: int c;
1.122 nicm 2546:
1.190 nicm 2547: if (strcmp(p, "?") == 0) {
2548: if (wp != NULL) {
2549: tty_default_colours(&defaults, wp);
2550: input_osc_colour_reply(ictx, 10, defaults.fg);
2551: }
1.171 nicm 2552: return;
1.190 nicm 2553: }
1.183 nicm 2554:
1.190 nicm 2555: if ((c = input_osc_parse_colour(p)) == -1) {
2556: log_debug("bad OSC 10: %s", p);
1.163 nicm 2557: return;
1.183 nicm 2558: }
1.192 ! nicm 2559: if (ictx->palette != NULL) {
! 2560: ictx->palette->fg = c;
! 2561: if (wp != NULL)
! 2562: wp->flags |= PANE_STYLECHANGED;
! 2563: screen_write_fullredraw(&ictx->ctx);
! 2564: }
1.122 nicm 2565: }
2566:
1.186 nicm 2567: /* Handle the OSC 110 sequence for resetting background colour. */
2568: static void
2569: input_osc_110(struct input_ctx *ictx, const char *p)
2570: {
2571: struct window_pane *wp = ictx->wp;
2572:
2573: if (*p != '\0')
2574: return;
1.192 ! nicm 2575: if (ictx->palette != NULL) {
! 2576: ictx->palette->fg = 8;
! 2577: if (wp != NULL)
! 2578: wp->flags |= PANE_STYLECHANGED;
! 2579: screen_write_fullredraw(&ictx->ctx);
! 2580: }
1.186 nicm 2581: }
2582:
1.183 nicm 2583: /* Handle the OSC 11 sequence for setting and querying background colour. */
1.122 nicm 2584: static void
1.138 nicm 2585: input_osc_11(struct input_ctx *ictx, const char *p)
1.122 nicm 2586: {
1.138 nicm 2587: struct window_pane *wp = ictx->wp;
1.183 nicm 2588: struct grid_cell defaults;
1.186 nicm 2589: int c;
1.122 nicm 2590:
1.190 nicm 2591: if (strcmp(p, "?") == 0) {
2592: if (wp != NULL) {
2593: tty_default_colours(&defaults, wp);
2594: input_osc_colour_reply(ictx, 11, defaults.bg);
2595: }
1.171 nicm 2596: return;
1.190 nicm 2597: }
1.183 nicm 2598:
1.190 nicm 2599: if ((c = input_osc_parse_colour(p)) == -1) {
2600: log_debug("bad OSC 11: %s", p);
1.163 nicm 2601: return;
1.183 nicm 2602: }
1.192 ! nicm 2603: if (ictx->palette != NULL) {
! 2604: ictx->palette->bg = c;
! 2605: if (wp != NULL)
! 2606: wp->flags |= PANE_STYLECHANGED;
! 2607: screen_write_fullredraw(&ictx->ctx);
! 2608: }
1.186 nicm 2609: }
2610:
2611: /* Handle the OSC 111 sequence for resetting background colour. */
2612: static void
2613: input_osc_111(struct input_ctx *ictx, const char *p)
2614: {
2615: struct window_pane *wp = ictx->wp;
2616:
2617: if (*p != '\0')
2618: return;
1.192 ! nicm 2619: if (ictx->palette != NULL) {
! 2620: ictx->palette->bg = 8;
! 2621: if (wp != NULL)
! 2622: wp->flags |= PANE_STYLECHANGED;
! 2623: screen_write_fullredraw(&ictx->ctx);
! 2624: }
1.108 nicm 2625: }
2626:
2627: /* Handle the OSC 52 sequence for setting the clipboard. */
2628: static void
1.138 nicm 2629: input_osc_52(struct input_ctx *ictx, const char *p)
1.108 nicm 2630: {
1.138 nicm 2631: struct window_pane *wp = ictx->wp;
1.108 nicm 2632: char *end;
1.138 nicm 2633: const char *buf;
1.108 nicm 2634: size_t len;
2635: u_char *out;
1.123 nicm 2636: int outlen, state;
1.108 nicm 2637: struct screen_write_ctx ctx;
1.138 nicm 2638: struct paste_buffer *pb;
1.108 nicm 2639:
1.171 nicm 2640: if (wp == NULL)
2641: return;
1.123 nicm 2642: state = options_get_number(global_options, "set-clipboard");
2643: if (state != 2)
2644: return;
2645:
1.108 nicm 2646: if ((end = strchr(p, ';')) == NULL)
2647: return;
2648: end++;
2649: if (*end == '\0')
2650: return;
1.138 nicm 2651: log_debug("%s: %s", __func__, end);
2652:
2653: if (strcmp(end, "?") == 0) {
2654: if ((pb = paste_get_top(NULL)) != NULL) {
2655: buf = paste_buffer_data(pb, &len);
2656: outlen = 4 * ((len + 2) / 3) + 1;
2657: out = xmalloc(outlen);
2658: if ((outlen = b64_ntop(buf, len, out, outlen)) == -1) {
2659: free(out);
2660: return;
2661: }
2662: } else {
2663: outlen = 0;
2664: out = NULL;
2665: }
1.172 nicm 2666: bufferevent_write(ictx->event, "\033]52;;", 6);
1.138 nicm 2667: if (outlen != 0)
1.172 nicm 2668: bufferevent_write(ictx->event, out, outlen);
1.138 nicm 2669: if (ictx->input_end == INPUT_END_BEL)
1.172 nicm 2670: bufferevent_write(ictx->event, "\007", 1);
1.138 nicm 2671: else
1.172 nicm 2672: bufferevent_write(ictx->event, "\033\\", 2);
1.138 nicm 2673: free(out);
2674: return;
2675: }
1.108 nicm 2676:
2677: len = (strlen(end) / 4) * 3;
2678: if (len == 0)
2679: return;
2680:
2681: out = xmalloc(len);
2682: if ((outlen = b64_pton(end, out, len)) == -1) {
2683: free(out);
2684: return;
2685: }
2686:
1.177 nicm 2687: screen_write_start_pane(&ctx, wp, NULL);
1.123 nicm 2688: screen_write_setselection(&ctx, out, outlen);
2689: screen_write_stop(&ctx);
1.126 nicm 2690: notify_pane("pane-set-clipboard", wp);
1.123 nicm 2691:
1.150 nicm 2692: paste_add(NULL, out, outlen);
1.107 nicm 2693: }
2694:
2695: /* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */
2696: static void
1.138 nicm 2697: input_osc_104(struct input_ctx *ictx, const char *p)
1.107 nicm 2698: {
1.190 nicm 2699: char *copy, *s;
2700: long idx;
2701: int bad = 0, redraw = 0;
1.107 nicm 2702:
2703: if (*p == '\0') {
1.190 nicm 2704: colour_palette_clear(ictx->palette);
2705: screen_write_fullredraw(&ictx->ctx);
1.107 nicm 2706: return;
2707: }
2708:
2709: copy = s = xstrdup(p);
2710: while (*s != '\0') {
2711: idx = strtol(s, &s, 10);
1.190 nicm 2712: if (*s != '\0' && *s != ';') {
2713: bad = 1;
2714: break;
2715: }
2716: if (idx < 0 || idx >= 256) {
2717: bad = 1;
2718: break;
2719: }
2720: if (colour_palette_set(ictx->palette, idx, -1))
2721: redraw = 1;
1.107 nicm 2722: if (*s == ';')
2723: s++;
2724: }
1.190 nicm 2725: if (bad)
2726: log_debug("bad OSC 104: %s", p);
2727: if (redraw)
2728: screen_write_fullredraw(&ictx->ctx);
1.107 nicm 2729: free(copy);
1.1 nicm 2730: }