Annotation of src/usr.bin/tmux/input.c, Revision 1.55
1.55 ! nicm 1: /* $OpenBSD: input.c,v 1.54 2012/09/25 07:41:22 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15: * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/types.h>
20:
21: #include <stdlib.h>
22: #include <string.h>
23:
24: #include "tmux.h"
25:
1.28 nicm 26: /*
27: * Based on the description by Paul Williams at:
28: *
29: * http://vt100.net/emu/dec_ansi_parser
30: *
31: * With the following changes:
32: *
33: * - 7-bit only.
34: *
35: * - Support for UTF-8.
36: *
37: * - OSC (but not APC) may be terminated by \007 as well as ST.
38: *
39: * - A state for APC similar to OSC. Some terminals appear to use this to set
40: * the title.
41: *
42: * - A state for the screen \033k...\033\\ sequence to rename a window. This is
43: * pretty stupid but not supporting it is more trouble than it is worth.
1.37 nicm 44: *
45: * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to
46: * be passed to the underlying teminal(s).
1.28 nicm 47: */
48:
49: /* Helper functions. */
1.52 nicm 50: struct input_transition;
1.28 nicm 51: int input_split(struct input_ctx *);
52: int input_get(struct input_ctx *, u_int, int, int);
53: void input_reply(struct input_ctx *, const char *, ...);
1.52 nicm 54: void input_set_state(struct window_pane *, const struct input_transition *);
1.28 nicm 55:
56: /* Transition entry/exit handlers. */
57: void input_clear(struct input_ctx *);
58: void input_enter_osc(struct input_ctx *);
59: void input_exit_osc(struct input_ctx *);
60: void input_enter_apc(struct input_ctx *);
61: void input_exit_apc(struct input_ctx *);
62: void input_enter_rename(struct input_ctx *);
63: void input_exit_rename(struct input_ctx *);
64:
65: /* Input state handlers. */
66: int input_print(struct input_ctx *);
67: int input_intermediate(struct input_ctx *);
68: int input_parameter(struct input_ctx *);
69: int input_input(struct input_ctx *);
70: int input_c0_dispatch(struct input_ctx *);
71: int input_esc_dispatch(struct input_ctx *);
72: int input_csi_dispatch(struct input_ctx *);
73: void input_csi_dispatch_sgr(struct input_ctx *);
1.37 nicm 74: int input_dcs_dispatch(struct input_ctx *);
1.28 nicm 75: int input_utf8_open(struct input_ctx *);
76: int input_utf8_add(struct input_ctx *);
77: int input_utf8_close(struct input_ctx *);
78:
79: /* Command table comparison function. */
80: int input_table_compare(const void *, const void *);
81:
82: /* Command table entry. */
83: struct input_table_entry {
84: int ch;
85: const char *interm;
86: int type;
1.1 nicm 87: };
88:
1.28 nicm 89: /* Escape commands. */
90: enum input_esc_type {
91: INPUT_ESC_DECALN,
92: INPUT_ESC_DECKPAM,
93: INPUT_ESC_DECKPNM,
94: INPUT_ESC_DECRC,
95: INPUT_ESC_DECSC,
96: INPUT_ESC_HTS,
97: INPUT_ESC_IND,
98: INPUT_ESC_NEL,
99: INPUT_ESC_RI,
100: INPUT_ESC_RIS,
101: INPUT_ESC_SCSOFF_G0,
102: INPUT_ESC_SCSON_G0,
103: };
1.1 nicm 104:
1.28 nicm 105: /* Escape command table. */
106: const struct input_table_entry input_esc_table[] = {
107: { '0', "(", INPUT_ESC_SCSOFF_G0 },
108: { '7', "", INPUT_ESC_DECSC },
109: { '8', "", INPUT_ESC_DECRC },
110: { '8', "#", INPUT_ESC_DECALN },
111: { '=', "", INPUT_ESC_DECKPAM },
112: { '>', "", INPUT_ESC_DECKPNM },
113: { 'B', "(", INPUT_ESC_SCSON_G0 },
114: { 'D', "", INPUT_ESC_IND },
115: { 'E', "", INPUT_ESC_NEL },
116: { 'H', "", INPUT_ESC_HTS },
117: { 'M', "", INPUT_ESC_RI },
118: { 'c', "", INPUT_ESC_RIS },
119: };
1.1 nicm 120:
1.28 nicm 121: /* Control (CSI) commands. */
122: enum input_csi_type {
123: INPUT_CSI_CBT,
1.43 nicm 124: INPUT_CSI_CNL,
125: INPUT_CSI_CPL,
1.28 nicm 126: INPUT_CSI_CUB,
127: INPUT_CSI_CUD,
128: INPUT_CSI_CUF,
129: INPUT_CSI_CUP,
130: INPUT_CSI_CUU,
131: INPUT_CSI_DA,
1.50 nicm 132: INPUT_CSI_DA_TWO,
1.28 nicm 133: INPUT_CSI_DCH,
1.39 nicm 134: INPUT_CSI_DECSCUSR,
1.28 nicm 135: INPUT_CSI_DECSTBM,
136: INPUT_CSI_DL,
137: INPUT_CSI_DSR,
138: INPUT_CSI_ED,
139: INPUT_CSI_EL,
140: INPUT_CSI_HPA,
141: INPUT_CSI_ICH,
142: INPUT_CSI_IL,
1.42 nicm 143: INPUT_CSI_RCP,
1.28 nicm 144: INPUT_CSI_RM,
145: INPUT_CSI_RM_PRIVATE,
1.42 nicm 146: INPUT_CSI_SCP,
1.28 nicm 147: INPUT_CSI_SGR,
148: INPUT_CSI_SM,
149: INPUT_CSI_SM_PRIVATE,
150: INPUT_CSI_TBC,
151: INPUT_CSI_VPA,
152: };
1.1 nicm 153:
1.28 nicm 154: /* Control (CSI) command table. */
155: const struct input_table_entry input_csi_table[] = {
156: { '@', "", INPUT_CSI_ICH },
157: { 'A', "", INPUT_CSI_CUU },
158: { 'B', "", INPUT_CSI_CUD },
159: { 'C', "", INPUT_CSI_CUF },
160: { 'D', "", INPUT_CSI_CUB },
1.43 nicm 161: { 'E', "", INPUT_CSI_CNL },
162: { 'F', "", INPUT_CSI_CPL },
1.28 nicm 163: { 'G', "", INPUT_CSI_HPA },
164: { 'H', "", INPUT_CSI_CUP },
165: { 'J', "", INPUT_CSI_ED },
166: { 'K', "", INPUT_CSI_EL },
167: { 'L', "", INPUT_CSI_IL },
168: { 'M', "", INPUT_CSI_DL },
169: { 'P', "", INPUT_CSI_DCH },
170: { 'Z', "", INPUT_CSI_CBT },
171: { 'c', "", INPUT_CSI_DA },
1.50 nicm 172: { 'c', ">", INPUT_CSI_DA_TWO },
1.28 nicm 173: { 'd', "", INPUT_CSI_VPA },
174: { 'f', "", INPUT_CSI_CUP },
175: { 'g', "", INPUT_CSI_TBC },
176: { 'h', "", INPUT_CSI_SM },
177: { 'h', "?", INPUT_CSI_SM_PRIVATE },
178: { 'l', "", INPUT_CSI_RM },
179: { 'l', "?", INPUT_CSI_RM_PRIVATE },
180: { 'm', "", INPUT_CSI_SGR },
181: { 'n', "", INPUT_CSI_DSR },
1.39 nicm 182: { 'q', " ", INPUT_CSI_DECSCUSR },
1.28 nicm 183: { 'r', "", INPUT_CSI_DECSTBM },
1.42 nicm 184: { 's', "", INPUT_CSI_SCP },
185: { 'u', "", INPUT_CSI_RCP },
1.28 nicm 186: };
1.1 nicm 187:
1.28 nicm 188: /* Input transition. */
189: struct input_transition {
190: int first;
191: int last;
1.1 nicm 192:
1.28 nicm 193: int (*handler)(struct input_ctx *);
194: const struct input_state *state;
195: };
1.1 nicm 196:
1.28 nicm 197: /* Input state. */
198: struct input_state {
199: const char *name;
200: void (*enter)(struct input_ctx *);
201: void (*exit)(struct input_ctx *);
202: const struct input_transition *transitions;
203: };
1.1 nicm 204:
1.28 nicm 205: /* State transitions available from all states. */
206: #define INPUT_STATE_ANYWHERE \
207: { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
208: { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
209: { 0x1b, 0x1b, NULL, &input_state_esc_enter }
210:
211: /* Forward declarations of state tables. */
212: const struct input_transition input_state_ground_table[];
213: const struct input_transition input_state_esc_enter_table[];
214: const struct input_transition input_state_esc_intermediate_table[];
215: const struct input_transition input_state_csi_enter_table[];
216: const struct input_transition input_state_csi_parameter_table[];
217: const struct input_transition input_state_csi_intermediate_table[];
218: const struct input_transition input_state_csi_ignore_table[];
219: const struct input_transition input_state_dcs_enter_table[];
220: const struct input_transition input_state_dcs_parameter_table[];
221: const struct input_transition input_state_dcs_intermediate_table[];
222: const struct input_transition input_state_dcs_handler_table[];
1.37 nicm 223: const struct input_transition input_state_dcs_escape_table[];
1.28 nicm 224: const struct input_transition input_state_dcs_ignore_table[];
225: const struct input_transition input_state_osc_string_table[];
226: const struct input_transition input_state_apc_string_table[];
227: const struct input_transition input_state_rename_string_table[];
228: const struct input_transition input_state_consume_st_table[];
229: const struct input_transition input_state_utf8_three_table[];
230: const struct input_transition input_state_utf8_two_table[];
231: const struct input_transition input_state_utf8_one_table[];
232:
233: /* ground state definition. */
234: const struct input_state input_state_ground = {
235: "ground",
236: NULL, NULL,
237: input_state_ground_table
238: };
1.1 nicm 239:
1.28 nicm 240: /* esc_enter state definition. */
241: const struct input_state input_state_esc_enter = {
242: "esc_enter",
243: input_clear, NULL,
244: input_state_esc_enter_table
245: };
1.1 nicm 246:
1.28 nicm 247: /* esc_intermediate state definition. */
248: const struct input_state input_state_esc_intermediate = {
249: "esc_intermediate",
250: NULL, NULL,
251: input_state_esc_intermediate_table
252: };
1.1 nicm 253:
1.28 nicm 254: /* csi_enter state definition. */
255: const struct input_state input_state_csi_enter = {
256: "csi_enter",
257: input_clear, NULL,
258: input_state_csi_enter_table
259: };
1.1 nicm 260:
1.28 nicm 261: /* csi_parameter state definition. */
262: const struct input_state input_state_csi_parameter = {
263: "csi_parameter",
264: NULL, NULL,
265: input_state_csi_parameter_table
266: };
1.1 nicm 267:
1.28 nicm 268: /* csi_intermediate state definition. */
269: const struct input_state input_state_csi_intermediate = {
270: "csi_intermediate",
271: NULL, NULL,
272: input_state_csi_intermediate_table
273: };
1.1 nicm 274:
1.28 nicm 275: /* csi_ignore state definition. */
276: const struct input_state input_state_csi_ignore = {
277: "csi_ignore",
278: NULL, NULL,
279: input_state_csi_ignore_table
280: };
1.1 nicm 281:
1.28 nicm 282: /* dcs_enter state definition. */
283: const struct input_state input_state_dcs_enter = {
284: "dcs_enter",
285: input_clear, NULL,
286: input_state_dcs_enter_table
287: };
1.1 nicm 288:
1.28 nicm 289: /* dcs_parameter state definition. */
290: const struct input_state input_state_dcs_parameter = {
291: "dcs_parameter",
292: NULL, NULL,
293: input_state_dcs_parameter_table
294: };
1.1 nicm 295:
1.28 nicm 296: /* dcs_intermediate state definition. */
297: const struct input_state input_state_dcs_intermediate = {
298: "dcs_intermediate",
299: NULL, NULL,
300: input_state_dcs_intermediate_table
301: };
1.1 nicm 302:
1.28 nicm 303: /* dcs_handler state definition. */
304: const struct input_state input_state_dcs_handler = {
305: "dcs_handler",
1.37 nicm 306: NULL, NULL,
1.28 nicm 307: input_state_dcs_handler_table
308: };
1.1 nicm 309:
1.37 nicm 310: /* dcs_escape state definition. */
311: const struct input_state input_state_dcs_escape = {
312: "dcs_escape",
313: NULL, NULL,
314: input_state_dcs_escape_table
315: };
316:
1.28 nicm 317: /* dcs_ignore state definition. */
318: const struct input_state input_state_dcs_ignore = {
319: "dcs_ignore",
320: NULL, NULL,
321: input_state_dcs_ignore_table
322: };
1.1 nicm 323:
1.28 nicm 324: /* osc_string state definition. */
325: const struct input_state input_state_osc_string = {
326: "osc_string",
327: input_enter_osc, input_exit_osc,
328: input_state_osc_string_table
329: };
1.1 nicm 330:
1.28 nicm 331: /* apc_string state definition. */
332: const struct input_state input_state_apc_string = {
333: "apc_string",
334: input_enter_apc, input_exit_apc,
335: input_state_apc_string_table
336: };
1.1 nicm 337:
1.28 nicm 338: /* rename_string state definition. */
339: const struct input_state input_state_rename_string = {
340: "rename_string",
341: input_enter_rename, input_exit_rename,
342: input_state_rename_string_table
343: };
1.1 nicm 344:
1.28 nicm 345: /* consume_st state definition. */
346: const struct input_state input_state_consume_st = {
347: "consume_st",
348: NULL, NULL,
349: input_state_consume_st_table
350: };
1.1 nicm 351:
1.28 nicm 352: /* utf8_three state definition. */
353: const struct input_state input_state_utf8_three = {
354: "utf8_three",
355: NULL, NULL,
356: input_state_utf8_three_table
357: };
1.1 nicm 358:
1.28 nicm 359: /* utf8_two state definition. */
360: const struct input_state input_state_utf8_two = {
361: "utf8_two",
362: NULL, NULL,
363: input_state_utf8_two_table
364: };
1.1 nicm 365:
1.28 nicm 366: /* utf8_one state definition. */
367: const struct input_state input_state_utf8_one = {
368: "utf8_one",
369: NULL, NULL,
370: input_state_utf8_one_table
371: };
1.1 nicm 372:
1.28 nicm 373: /* ground state table. */
374: const struct input_transition input_state_ground_table[] = {
375: INPUT_STATE_ANYWHERE,
376:
377: { 0x00, 0x17, input_c0_dispatch, NULL },
378: { 0x19, 0x19, input_c0_dispatch, NULL },
379: { 0x1c, 0x1f, input_c0_dispatch, NULL },
380: { 0x20, 0x7e, input_print, NULL },
381: { 0x7f, 0x7f, NULL, NULL },
382: { 0x80, 0xc1, input_print, NULL },
383: { 0xc2, 0xdf, input_utf8_open, &input_state_utf8_one },
384: { 0xe0, 0xef, input_utf8_open, &input_state_utf8_two },
385: { 0xf0, 0xf4, input_utf8_open, &input_state_utf8_three },
386: { 0xf5, 0xff, input_print, NULL },
1.1 nicm 387:
1.28 nicm 388: { -1, -1, NULL, NULL }
389: };
1.13 nicm 390:
1.28 nicm 391: /* esc_enter state table. */
392: const struct input_transition input_state_esc_enter_table[] = {
393: INPUT_STATE_ANYWHERE,
394:
395: { 0x00, 0x17, input_c0_dispatch, NULL },
396: { 0x19, 0x19, input_c0_dispatch, NULL },
397: { 0x1c, 0x1f, input_c0_dispatch, NULL },
398: { 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate },
399: { 0x30, 0x4f, input_esc_dispatch, &input_state_ground },
400: { 0x50, 0x50, NULL, &input_state_dcs_enter },
401: { 0x51, 0x57, input_esc_dispatch, &input_state_ground },
402: { 0x58, 0x58, NULL, &input_state_consume_st },
403: { 0x59, 0x59, input_esc_dispatch, &input_state_ground },
404: { 0x5a, 0x5a, input_esc_dispatch, &input_state_ground },
405: { 0x5b, 0x5b, NULL, &input_state_csi_enter },
406: { 0x5c, 0x5c, input_esc_dispatch, &input_state_ground },
407: { 0x5d, 0x5d, NULL, &input_state_osc_string },
408: { 0x5e, 0x5e, NULL, &input_state_consume_st },
409: { 0x5f, 0x5f, NULL, &input_state_apc_string },
410: { 0x60, 0x6a, input_esc_dispatch, &input_state_ground },
411: { 0x6b, 0x6b, NULL, &input_state_rename_string },
1.29 nicm 412: { 0x6c, 0x7e, input_esc_dispatch, &input_state_ground },
1.28 nicm 413: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 414:
1.28 nicm 415: { -1, -1, NULL, NULL }
416: };
1.1 nicm 417:
1.28 nicm 418: /* esc_interm state table. */
419: const struct input_transition input_state_esc_intermediate_table[] = {
420: INPUT_STATE_ANYWHERE,
421:
422: { 0x00, 0x17, input_c0_dispatch, NULL },
423: { 0x19, 0x19, input_c0_dispatch, NULL },
424: { 0x1c, 0x1f, input_c0_dispatch, NULL },
425: { 0x20, 0x2f, input_intermediate, NULL },
426: { 0x30, 0x7e, input_esc_dispatch, &input_state_ground },
427: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 428:
1.28 nicm 429: { -1, -1, NULL, NULL }
430: };
1.1 nicm 431:
1.28 nicm 432: /* csi_enter state table. */
433: const struct input_transition input_state_csi_enter_table[] = {
434: INPUT_STATE_ANYWHERE,
435:
436: { 0x00, 0x17, input_c0_dispatch, NULL },
437: { 0x19, 0x19, input_c0_dispatch, NULL },
438: { 0x1c, 0x1f, input_c0_dispatch, NULL },
439: { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
440: { 0x30, 0x39, input_parameter, &input_state_csi_parameter },
441: { 0x3a, 0x3a, NULL, &input_state_csi_ignore },
442: { 0x3b, 0x3b, input_parameter, &input_state_csi_parameter },
443: { 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter },
444: { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
445: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 446:
1.28 nicm 447: { -1, -1, NULL, NULL }
448: };
1.1 nicm 449:
1.28 nicm 450: /* csi_parameter state table. */
451: const struct input_transition input_state_csi_parameter_table[] = {
452: INPUT_STATE_ANYWHERE,
453:
454: { 0x00, 0x17, input_c0_dispatch, NULL },
455: { 0x19, 0x19, input_c0_dispatch, NULL },
456: { 0x1c, 0x1f, input_c0_dispatch, NULL },
457: { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
458: { 0x30, 0x39, input_parameter, NULL },
459: { 0x3a, 0x3a, NULL, &input_state_csi_ignore },
460: { 0x3b, 0x3b, input_parameter, NULL },
461: { 0x3c, 0x3f, NULL, &input_state_csi_ignore },
462: { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
463: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 464:
1.28 nicm 465: { -1, -1, NULL, NULL }
466: };
1.1 nicm 467:
1.28 nicm 468: /* csi_intermediate state table. */
469: const struct input_transition input_state_csi_intermediate_table[] = {
470: INPUT_STATE_ANYWHERE,
471:
472: { 0x00, 0x17, input_c0_dispatch, NULL },
473: { 0x19, 0x19, input_c0_dispatch, NULL },
474: { 0x1c, 0x1f, input_c0_dispatch, NULL },
475: { 0x20, 0x2f, input_intermediate, NULL },
476: { 0x30, 0x3f, NULL, &input_state_csi_ignore },
477: { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
478: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 479:
1.28 nicm 480: { -1, -1, NULL, NULL }
481: };
1.1 nicm 482:
1.28 nicm 483: /* csi_ignore state table. */
484: const struct input_transition input_state_csi_ignore_table[] = {
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, 0x3f, NULL, NULL },
491: { 0x40, 0x7e, NULL, &input_state_ground },
492: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 493:
1.28 nicm 494: { -1, -1, NULL, NULL }
495: };
1.1 nicm 496:
1.28 nicm 497: /* dcs_enter state table. */
498: const struct input_transition input_state_dcs_enter_table[] = {
499: INPUT_STATE_ANYWHERE,
500:
501: { 0x00, 0x17, NULL, NULL },
502: { 0x19, 0x19, NULL, NULL },
503: { 0x1c, 0x1f, NULL, NULL },
504: { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
505: { 0x30, 0x39, input_parameter, &input_state_dcs_parameter },
506: { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
507: { 0x3b, 0x3b, input_parameter, &input_state_dcs_parameter },
508: { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter },
1.37 nicm 509: { 0x40, 0x7e, input_input, &input_state_dcs_handler },
1.28 nicm 510: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 511:
1.28 nicm 512: { -1, -1, NULL, NULL }
513: };
1.1 nicm 514:
1.28 nicm 515: /* dcs_parameter state table. */
516: const struct input_transition input_state_dcs_parameter_table[] = {
517: INPUT_STATE_ANYWHERE,
518:
519: { 0x00, 0x17, NULL, NULL },
520: { 0x19, 0x19, NULL, NULL },
521: { 0x1c, 0x1f, NULL, NULL },
522: { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
523: { 0x30, 0x39, input_parameter, NULL },
524: { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
525: { 0x3b, 0x3b, input_parameter, NULL },
526: { 0x3c, 0x3f, NULL, &input_state_dcs_ignore },
1.37 nicm 527: { 0x40, 0x7e, input_input, &input_state_dcs_handler },
1.28 nicm 528: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 529:
1.28 nicm 530: { -1, -1, NULL, NULL }
531: };
1.1 nicm 532:
1.28 nicm 533: /* dcs_interm state table. */
534: const struct input_transition input_state_dcs_intermediate_table[] = {
535: INPUT_STATE_ANYWHERE,
536:
537: { 0x00, 0x17, NULL, NULL },
538: { 0x19, 0x19, NULL, NULL },
539: { 0x1c, 0x1f, NULL, NULL },
540: { 0x20, 0x2f, input_intermediate, NULL },
541: { 0x30, 0x3f, NULL, &input_state_dcs_ignore },
1.37 nicm 542: { 0x40, 0x7e, input_input, &input_state_dcs_handler },
1.28 nicm 543: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 544:
1.28 nicm 545: { -1, -1, NULL, NULL }
546: };
1.1 nicm 547:
1.28 nicm 548: /* dcs_handler state table. */
549: const struct input_transition input_state_dcs_handler_table[] = {
1.37 nicm 550: /* No INPUT_STATE_ANYWHERE */
551:
552: { 0x00, 0x1a, input_input, NULL },
553: { 0x1b, 0x1b, NULL, &input_state_dcs_escape },
554: { 0x1c, 0xff, input_input, NULL },
555:
556: { -1, -1, NULL, NULL }
557: };
558:
559: /* dcs_escape state table. */
560: const struct input_transition input_state_dcs_escape_table[] = {
561: /* No INPUT_STATE_ANYWHERE */
1.28 nicm 562:
1.37 nicm 563: { 0x00, 0x5b, input_input, &input_state_dcs_handler },
564: { 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground },
565: { 0x5d, 0xff, input_input, &input_state_dcs_handler },
1.1 nicm 566:
1.28 nicm 567: { -1, -1, NULL, NULL }
568: };
1.1 nicm 569:
1.40 nicm 570: /* dcs_ignore state table. */
1.28 nicm 571: const struct input_transition input_state_dcs_ignore_table[] = {
572: INPUT_STATE_ANYWHERE,
573:
574: { 0x00, 0x17, NULL, NULL },
575: { 0x19, 0x19, NULL, NULL },
576: { 0x1c, 0x1f, NULL, NULL },
577: { 0x20, 0xff, NULL, NULL },
1.1 nicm 578:
1.28 nicm 579: { -1, -1, NULL, NULL }
580: };
1.1 nicm 581:
1.28 nicm 582: /* osc_string state table. */
583: const struct input_transition input_state_osc_string_table[] = {
584: INPUT_STATE_ANYWHERE,
585:
586: { 0x00, 0x06, NULL, NULL },
587: { 0x07, 0x07, NULL, &input_state_ground },
588: { 0x08, 0x17, NULL, NULL },
589: { 0x19, 0x19, NULL, NULL },
590: { 0x1c, 0x1f, NULL, NULL },
591: { 0x20, 0xff, input_input, NULL },
1.1 nicm 592:
1.28 nicm 593: { -1, -1, NULL, NULL }
594: };
1.1 nicm 595:
1.28 nicm 596: /* apc_string state table. */
597: const struct input_transition input_state_apc_string_table[] = {
598: INPUT_STATE_ANYWHERE,
599:
600: { 0x00, 0x17, NULL, NULL },
601: { 0x19, 0x19, NULL, NULL },
602: { 0x1c, 0x1f, NULL, NULL },
603: { 0x20, 0xff, input_input, NULL },
1.1 nicm 604:
1.28 nicm 605: { -1, -1, NULL, NULL }
606: };
1.1 nicm 607:
1.28 nicm 608: /* rename_string state table. */
609: const struct input_transition input_state_rename_string_table[] = {
610: INPUT_STATE_ANYWHERE,
611:
612: { 0x00, 0x17, NULL, NULL },
613: { 0x19, 0x19, NULL, NULL },
614: { 0x1c, 0x1f, NULL, NULL },
615: { 0x20, 0xff, input_input, NULL },
1.1 nicm 616:
1.28 nicm 617: { -1, -1, NULL, NULL }
618: };
1.1 nicm 619:
1.28 nicm 620: /* consume_st state table. */
621: const struct input_transition input_state_consume_st_table[] = {
622: INPUT_STATE_ANYWHERE,
623:
624: { 0x00, 0x17, NULL, NULL },
625: { 0x19, 0x19, NULL, NULL },
626: { 0x1c, 0x1f, NULL, NULL },
627: { 0x20, 0xff, NULL, NULL },
1.6 nicm 628:
1.28 nicm 629: { -1, -1, NULL, NULL }
630: };
1.6 nicm 631:
1.28 nicm 632: /* utf8_three state table. */
633: const struct input_transition input_state_utf8_three_table[] = {
634: /* No INPUT_STATE_ANYWHERE */
635:
636: { 0x00, 0x7f, NULL, &input_state_ground },
637: { 0x80, 0xbf, input_utf8_add, &input_state_utf8_two },
638: { 0xc0, 0xff, NULL, &input_state_ground },
1.4 nicm 639:
1.28 nicm 640: { -1, -1, NULL, NULL }
641: };
1.1 nicm 642:
1.28 nicm 643: /* utf8_two state table. */
644: const struct input_transition input_state_utf8_two_table[] = {
645: /* No INPUT_STATE_ANYWHERE */
646:
647: { 0x00, 0x7f, NULL, &input_state_ground },
648: { 0x80, 0xbf, input_utf8_add, &input_state_utf8_one },
649: { 0xc0, 0xff, NULL, &input_state_ground },
1.1 nicm 650:
1.28 nicm 651: { -1, -1, NULL, NULL }
652: };
1.1 nicm 653:
1.28 nicm 654: /* utf8_one state table. */
655: const struct input_transition input_state_utf8_one_table[] = {
656: /* No INPUT_STATE_ANYWHERE */
657:
658: { 0x00, 0x7f, NULL, &input_state_ground },
659: { 0x80, 0xbf, input_utf8_close, &input_state_ground },
660: { 0xc0, 0xff, NULL, &input_state_ground },
1.1 nicm 661:
1.28 nicm 662: { -1, -1, NULL, NULL }
663: };
1.1 nicm 664:
1.28 nicm 665: /* Input table compare. */
666: int
667: input_table_compare(const void *key, const void *value)
1.1 nicm 668: {
1.28 nicm 669: const struct input_ctx *ictx = key;
670: const struct input_table_entry *entry = value;
1.1 nicm 671:
1.28 nicm 672: if (ictx->ch != entry->ch)
673: return (ictx->ch - entry->ch);
674: return (strcmp(ictx->interm_buf, entry->interm));
1.1 nicm 675: }
676:
1.28 nicm 677: /* Initialise input parser. */
1.1 nicm 678: void
1.28 nicm 679: input_init(struct window_pane *wp)
1.1 nicm 680: {
1.28 nicm 681: struct input_ctx *ictx = &wp->ictx;
1.1 nicm 682:
1.28 nicm 683: memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
1.1 nicm 684:
1.28 nicm 685: memcpy(&ictx->old_cell, &grid_default_cell, sizeof ictx->old_cell);
686: ictx->old_cx = 0;
687: ictx->old_cy = 0;
1.1 nicm 688:
1.28 nicm 689: *ictx->interm_buf = '\0';
690: ictx->interm_len = 0;
1.1 nicm 691:
1.28 nicm 692: *ictx->param_buf = '\0';
693: ictx->param_len = 0;
1.1 nicm 694:
1.28 nicm 695: ictx->state = &input_state_ground;
696: ictx->flags = 0;
1.52 nicm 697:
698: ictx->since_ground = evbuffer_new();
1.1 nicm 699: }
700:
1.28 nicm 701: /* Destroy input parser. */
1.1 nicm 702: void
1.52 nicm 703: input_free(struct window_pane *wp)
1.1 nicm 704: {
1.52 nicm 705: if (wp != NULL)
706: evbuffer_free(wp->ictx.since_ground);
707: }
708:
709: /* Change input state. */
710: void
711: input_set_state(struct window_pane *wp, const struct input_transition *itr)
712: {
713: struct input_ctx *ictx = &wp->ictx;
714: struct evbuffer *ground_evb = ictx->since_ground;
715:
716: if (ictx->state->exit != NULL)
717: ictx->state->exit(ictx);
718:
719: if (itr->state == &input_state_ground)
720: evbuffer_drain(ground_evb, EVBUFFER_LENGTH(ground_evb));
721:
722: ictx->state = itr->state;
723: if (ictx->state->enter != NULL)
724: ictx->state->enter(ictx);
1.1 nicm 725: }
726:
1.28 nicm 727: /* Parse input. */
1.1 nicm 728: void
1.28 nicm 729: input_parse(struct window_pane *wp)
1.1 nicm 730: {
1.28 nicm 731: struct input_ctx *ictx = &wp->ictx;
732: const struct input_transition *itr;
733: struct evbuffer *evb = wp->event->input;
734: u_char *buf;
735: size_t len, off;
1.1 nicm 736:
1.28 nicm 737: if (EVBUFFER_LENGTH(evb) == 0)
738: return;
1.30 nicm 739:
1.28 nicm 740: wp->window->flags |= WINDOW_ACTIVITY;
1.30 nicm 741: wp->window->flags &= ~WINDOW_SILENCE;
1.1 nicm 742:
1.28 nicm 743: /*
744: * Open the screen. Use NULL wp if there is a mode set as don't want to
745: * update the tty.
746: */
747: if (wp->mode == NULL)
748: screen_write_start(&ictx->ctx, wp, &wp->base);
749: else
750: screen_write_start(&ictx->ctx, NULL, &wp->base);
751: ictx->wp = wp;
1.7 nicm 752:
1.28 nicm 753: buf = EVBUFFER_DATA(evb);
754: len = EVBUFFER_LENGTH(evb);
1.54 nicm 755: notify_input(wp, evb);
1.28 nicm 756: off = 0;
757:
758: /* Parse the input. */
759: while (off < len) {
760: ictx->ch = buf[off++];
761: log_debug("%s: '%c' %s", __func__, ictx->ch, ictx->state->name);
762:
763: /* Find the transition. */
764: itr = ictx->state->transitions;
765: while (itr->first != -1 && itr->last != -1) {
766: if (ictx->ch >= itr->first && ictx->ch <= itr->last)
1.7 nicm 767: break;
1.28 nicm 768: itr++;
1.1 nicm 769: }
1.28 nicm 770: if (itr->first == -1 || itr->last == -1) {
771: /* No transition? Eh? */
772: fatalx("No transition from state!");
1.3 nicm 773: }
1.1 nicm 774:
775: /*
1.28 nicm 776: * Execute the handler, if any. Don't switch state if it
777: * returns non-zero.
1.1 nicm 778: */
1.31 nicm 779: if (itr->handler != NULL && itr->handler(ictx) != 0)
1.28 nicm 780: continue;
781:
782: /* And switch state, if necessary. */
1.52 nicm 783: if (itr->state != NULL)
784: input_set_state(wp, itr);
785:
786: /* If not in ground state, save input. */
787: if (ictx->state != &input_state_ground)
788: evbuffer_add(ictx->since_ground, &ictx->ch, 1);
1.1 nicm 789: }
790:
1.28 nicm 791: /* Close the screen. */
792: screen_write_stop(&ictx->ctx);
1.1 nicm 793:
1.28 nicm 794: evbuffer_drain(evb, len);
1.1 nicm 795: }
796:
1.28 nicm 797: /* Split the parameter list (if any). */
798: int
799: input_split(struct input_ctx *ictx)
1.1 nicm 800:
801: {
1.28 nicm 802: const char *errstr;
803: char *ptr, *out;
804: int n;
1.1 nicm 805:
1.28 nicm 806: ictx->param_list_len = 0;
807: if (ictx->param_len == 0)
808: return (0);
1.1 nicm 809:
1.28 nicm 810: ptr = ictx->param_buf;
811: while ((out = strsep(&ptr, ";")) != NULL) {
812: if (*out == '\0')
813: n = -1;
814: else {
815: n = strtonum(out, 0, INT_MAX, &errstr);
816: if (errstr != NULL)
817: return (-1);
818: }
1.1 nicm 819:
1.28 nicm 820: ictx->param_list[ictx->param_list_len++] = n;
821: if (ictx->param_list_len == nitems(ictx->param_list))
822: return (-1);
823: }
1.1 nicm 824:
1.28 nicm 825: return (0);
1.1 nicm 826: }
827:
1.40 nicm 828: /* Get an argument or return default value. */
1.28 nicm 829: int
830: input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
1.1 nicm 831: {
1.28 nicm 832: int retval;
1.1 nicm 833:
1.28 nicm 834: if (validx >= ictx->param_list_len)
835: return (defval);
1.1 nicm 836:
1.28 nicm 837: retval = ictx->param_list[validx];
838: if (retval == -1)
839: return (defval);
840: if (retval < minval)
841: return (minval);
842: return (retval);
1.1 nicm 843: }
844:
1.28 nicm 845: /* Reply to terminal query. */
1.1 nicm 846: void
1.28 nicm 847: input_reply(struct input_ctx *ictx, const char *fmt, ...)
1.1 nicm 848: {
1.28 nicm 849: va_list ap;
850: char *reply;
1.1 nicm 851:
1.28 nicm 852: va_start(ap, fmt);
853: vasprintf(&reply, fmt, ap);
854: va_end(ap);
1.1 nicm 855:
1.28 nicm 856: bufferevent_write(ictx->wp->event, reply, strlen(reply));
1.53 nicm 857: free(reply);
1.8 nicm 858: }
859:
1.28 nicm 860: /* Clear saved state. */
1.8 nicm 861: void
1.28 nicm 862: input_clear(struct input_ctx *ictx)
1.8 nicm 863: {
1.28 nicm 864: *ictx->interm_buf = '\0';
865: ictx->interm_len = 0;
1.8 nicm 866:
1.28 nicm 867: *ictx->param_buf = '\0';
868: ictx->param_len = 0;
1.8 nicm 869:
1.35 nicm 870: *ictx->input_buf = '\0';
871: ictx->input_len = 0;
872:
1.28 nicm 873: ictx->flags &= ~INPUT_DISCARD;
1.14 nicm 874: }
875:
1.28 nicm 876: /* Output this character to the screen. */
877: int
878: input_print(struct input_ctx *ictx)
1.14 nicm 879: {
1.28 nicm 880: ictx->cell.data = ictx->ch;
881: screen_write_cell(&ictx->ctx, &ictx->cell, NULL);
1.14 nicm 882:
1.28 nicm 883: return (0);
1.1 nicm 884: }
885:
1.28 nicm 886: /* Collect intermediate string. */
887: int
888: input_intermediate(struct input_ctx *ictx)
1.1 nicm 889: {
1.28 nicm 890: if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
891: ictx->flags |= INPUT_DISCARD;
892: else {
893: ictx->interm_buf[ictx->interm_len++] = ictx->ch;
894: ictx->interm_buf[ictx->interm_len] = '\0';
895: }
1.1 nicm 896:
1.28 nicm 897: return (0);
1.1 nicm 898: }
899:
1.28 nicm 900: /* Collect parameter string. */
901: int
902: input_parameter(struct input_ctx *ictx)
1.1 nicm 903: {
1.28 nicm 904: if (ictx->param_len == (sizeof ictx->param_buf) - 1)
905: ictx->flags |= INPUT_DISCARD;
906: else {
907: ictx->param_buf[ictx->param_len++] = ictx->ch;
908: ictx->param_buf[ictx->param_len] = '\0';
909: }
1.1 nicm 910:
1.28 nicm 911: return (0);
1.1 nicm 912: }
913:
1.28 nicm 914: /* Collect input string. */
915: int
916: input_input(struct input_ctx *ictx)
1.1 nicm 917: {
1.28 nicm 918: if (ictx->input_len == (sizeof ictx->input_buf) - 1)
919: ictx->flags |= INPUT_DISCARD;
920: else {
921: ictx->input_buf[ictx->input_len++] = ictx->ch;
922: ictx->input_buf[ictx->input_len] = '\0';
923: }
1.1 nicm 924:
1.28 nicm 925: return (0);
1.1 nicm 926: }
927:
1.28 nicm 928: /* Execute C0 control sequence. */
929: int
930: input_c0_dispatch(struct input_ctx *ictx)
1.1 nicm 931: {
1.28 nicm 932: struct screen_write_ctx *sctx = &ictx->ctx;
933: struct window_pane *wp = ictx->wp;
934: struct screen *s = sctx->s;
1.51 nicm 935: u_int trigger;
1.1 nicm 936:
1.28 nicm 937: log_debug("%s: '%c", __func__, ictx->ch);
1.1 nicm 938:
1.28 nicm 939: switch (ictx->ch) {
940: case '\000': /* NUL */
941: break;
942: case '\007': /* BEL */
943: wp->window->flags |= WINDOW_BELL;
944: break;
945: case '\010': /* BS */
946: screen_write_backspace(sctx);
1.51 nicm 947: goto count_c0;
1.28 nicm 948: case '\011': /* HT */
949: /* Don't tab beyond the end of the line. */
950: if (s->cx >= screen_size_x(s) - 1)
951: break;
1.1 nicm 952:
1.28 nicm 953: /* Find the next tab point, or use the last column if none. */
954: do {
955: s->cx++;
956: if (bit_test(s->tabs, s->cx))
957: break;
958: } while (s->cx < screen_size_x(s) - 1);
959: break;
960: case '\012': /* LF */
961: case '\013': /* VT */
962: case '\014': /* FF */
963: screen_write_linefeed(sctx, 0);
1.51 nicm 964: goto count_c0;
1.28 nicm 965: case '\015': /* CR */
966: screen_write_carriagereturn(sctx);
1.51 nicm 967: goto count_c0;
1.28 nicm 968: case '\016': /* SO */
969: ictx->cell.attr |= GRID_ATTR_CHARSET;
970: break;
971: case '\017': /* SI */
972: ictx->cell.attr &= ~GRID_ATTR_CHARSET;
973: break;
974: default:
975: log_debug("%s: unknown '%c'", __func__, ictx->ch);
976: break;
1.51 nicm 977: }
978:
979: return (0);
980:
981: count_c0:
982: trigger = options_get_number(&wp->window->options, "c0-change-trigger");
983: if (++wp->changes == trigger) {
984: wp->flags |= PANE_DROP;
985: window_pane_timer_start(wp);
1.28 nicm 986: }
1.1 nicm 987:
1.28 nicm 988: return (0);
1.7 nicm 989: }
990:
1.28 nicm 991: /* Execute escape sequence. */
992: int
993: input_esc_dispatch(struct input_ctx *ictx)
1.7 nicm 994: {
1.31 nicm 995: struct screen_write_ctx *sctx = &ictx->ctx;
996: struct screen *s = sctx->s;
997: struct input_table_entry *entry;
1.7 nicm 998:
1.28 nicm 999: if (ictx->flags & INPUT_DISCARD)
1000: return (0);
1001: log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
1.7 nicm 1002:
1.28 nicm 1003: entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
1004: sizeof input_esc_table[0], input_table_compare);
1005: if (entry == NULL) {
1006: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1007: return (0);
1008: }
1.7 nicm 1009:
1.28 nicm 1010: switch (entry->type) {
1011: case INPUT_ESC_RIS:
1012: memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
1013: memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1014: ictx->old_cx = 0;
1015: ictx->old_cy = 0;
1.1 nicm 1016:
1.46 nicm 1017: screen_write_reset(sctx);
1.28 nicm 1018: break;
1019: case INPUT_ESC_IND:
1020: screen_write_linefeed(sctx, 0);
1021: break;
1022: case INPUT_ESC_NEL:
1023: screen_write_carriagereturn(sctx);
1024: screen_write_linefeed(sctx, 0);
1025: break;
1026: case INPUT_ESC_HTS:
1027: if (s->cx < screen_size_x(s))
1028: bit_set(s->tabs, s->cx);
1029: break;
1030: case INPUT_ESC_RI:
1031: screen_write_reverseindex(sctx);
1032: break;
1033: case INPUT_ESC_DECKPAM:
1034: screen_write_kkeypadmode(sctx, 1);
1035: break;
1036: case INPUT_ESC_DECKPNM:
1037: screen_write_kkeypadmode(sctx, 0);
1.1 nicm 1038: break;
1.28 nicm 1039: case INPUT_ESC_DECSC:
1040: memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1041: ictx->old_cx = s->cx;
1042: ictx->old_cy = s->cy;
1043: break;
1044: case INPUT_ESC_DECRC:
1045: memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
1046: screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
1047: break;
1048: case INPUT_ESC_DECALN:
1049: screen_write_alignmenttest(sctx);
1050: break;
1051: case INPUT_ESC_SCSON_G0:
1052: /*
1053: * Not really supported, but fake it up enough for those that
1054: * use it to switch character sets (by redefining G0 to
1055: * graphics set, rather than switching to G1).
1056: */
1057: ictx->cell.attr &= ~GRID_ATTR_CHARSET;
1.1 nicm 1058: break;
1.28 nicm 1059: case INPUT_ESC_SCSOFF_G0:
1060: ictx->cell.attr |= GRID_ATTR_CHARSET;
1.1 nicm 1061: break;
1062: }
1.28 nicm 1063:
1064: return (0);
1.1 nicm 1065: }
1066:
1.28 nicm 1067: /* Execute control sequence. */
1068: int
1069: input_csi_dispatch(struct input_ctx *ictx)
1.1 nicm 1070: {
1.28 nicm 1071: struct screen_write_ctx *sctx = &ictx->ctx;
1072: struct window_pane *wp = ictx->wp;
1073: struct screen *s = sctx->s;
1074: struct input_table_entry *entry;
1075: int n, m;
1.1 nicm 1076:
1.28 nicm 1077: if (ictx->flags & INPUT_DISCARD)
1078: return (0);
1079: if (input_split(ictx) != 0)
1080: return (0);
1081: log_debug("%s: '%c' \"%s\" \"%s\"",
1082: __func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
1.1 nicm 1083:
1.28 nicm 1084: entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
1085: sizeof input_csi_table[0], input_table_compare);
1086: if (entry == NULL) {
1087: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1088: return (0);
1089: }
1.1 nicm 1090:
1.28 nicm 1091: switch (entry->type) {
1092: case INPUT_CSI_CBT:
1093: /* Find the previous tab point, n times. */
1094: n = input_get(ictx, 0, 1, 1);
1095: while (s->cx > 0 && n-- > 0) {
1096: do
1097: s->cx--;
1098: while (s->cx > 0 && !bit_test(s->tabs, s->cx));
1099: }
1100: break;
1101: case INPUT_CSI_CUB:
1102: screen_write_cursorleft(sctx, input_get(ictx, 0, 1, 1));
1103: break;
1104: case INPUT_CSI_CUD:
1105: screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
1106: break;
1107: case INPUT_CSI_CUF:
1108: screen_write_cursorright(sctx, input_get(ictx, 0, 1, 1));
1109: break;
1110: case INPUT_CSI_CUP:
1111: n = input_get(ictx, 0, 1, 1);
1112: m = input_get(ictx, 1, 1, 1);
1113: screen_write_cursormove(sctx, m - 1, n - 1);
1114: break;
1115: case INPUT_CSI_CUU:
1.43 nicm 1116: screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
1117: break;
1118: case INPUT_CSI_CNL:
1119: screen_write_carriagereturn(sctx);
1120: screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
1121: break;
1122: case INPUT_CSI_CPL:
1123: screen_write_carriagereturn(sctx);
1.28 nicm 1124: screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
1125: break;
1126: case INPUT_CSI_DA:
1127: switch (input_get(ictx, 0, 0, 0)) {
1128: case 0:
1129: input_reply(ictx, "\033[?1;2c");
1.50 nicm 1130: break;
1131: default:
1132: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1133: break;
1134: }
1135: break;
1136: case INPUT_CSI_DA_TWO:
1137: switch (input_get(ictx, 0, 0, 0)) {
1138: case 0:
1139: input_reply(ictx, "\033[>0;95;0c");
1.28 nicm 1140: break;
1141: default:
1142: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1143: break;
1144: }
1145: break;
1146: case INPUT_CSI_DCH:
1147: screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1));
1148: break;
1149: case INPUT_CSI_DECSTBM:
1150: n = input_get(ictx, 0, 1, 1);
1151: m = input_get(ictx, 1, 1, screen_size_y(s));
1152: screen_write_scrollregion(sctx, n - 1, m - 1);
1.1 nicm 1153: break;
1.28 nicm 1154: case INPUT_CSI_DL:
1155: screen_write_deleteline(sctx, input_get(ictx, 0, 1, 1));
1.1 nicm 1156: break;
1.28 nicm 1157: case INPUT_CSI_DSR:
1158: switch (input_get(ictx, 0, 0, 0)) {
1159: case 5:
1160: input_reply(ictx, "\033[0n");
1161: break;
1162: case 6:
1163: input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
1164: break;
1165: default:
1166: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1167: break;
1168: }
1169: break;
1170: case INPUT_CSI_ED:
1171: switch (input_get(ictx, 0, 0, 0)) {
1172: case 0:
1173: screen_write_clearendofscreen(sctx);
1174: break;
1175: case 1:
1176: screen_write_clearstartofscreen(sctx);
1177: break;
1178: case 2:
1179: screen_write_clearscreen(sctx);
1.41 nicm 1180: break;
1181: case 3:
1182: switch (input_get(ictx, 1, 0, 0)) {
1183: case 0:
1184: /*
1185: * Linux console extension to clear history
1186: * (for example before locking the screen).
1187: */
1188: screen_write_clearhistory(sctx);
1189: break;
1190: }
1.28 nicm 1191: break;
1192: default:
1193: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1194: break;
1195: }
1196: break;
1197: case INPUT_CSI_EL:
1198: switch (input_get(ictx, 0, 0, 0)) {
1199: case 0:
1200: screen_write_clearendofline(sctx);
1201: break;
1202: case 1:
1203: screen_write_clearstartofline(sctx);
1204: break;
1205: case 2:
1206: screen_write_clearline(sctx);
1207: break;
1208: default:
1209: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1210: break;
1211: }
1212: break;
1213: case INPUT_CSI_HPA:
1214: n = input_get(ictx, 0, 1, 1);
1215: screen_write_cursormove(sctx, n - 1, s->cy);
1216: break;
1217: case INPUT_CSI_ICH:
1218: screen_write_insertcharacter(sctx, input_get(ictx, 0, 1, 1));
1219: break;
1220: case INPUT_CSI_IL:
1221: screen_write_insertline(sctx, input_get(ictx, 0, 1, 1));
1222: break;
1.42 nicm 1223: case INPUT_CSI_RCP:
1224: memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
1225: screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
1226: break;
1.28 nicm 1227: case INPUT_CSI_RM:
1228: switch (input_get(ictx, 0, 0, -1)) {
1229: case 4: /* IRM */
1230: screen_write_insertmode(&ictx->ctx, 0);
1231: break;
1232: default:
1233: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1234: break;
1235: }
1.1 nicm 1236: break;
1.28 nicm 1237: case INPUT_CSI_RM_PRIVATE:
1238: switch (input_get(ictx, 0, 0, -1)) {
1.1 nicm 1239: case 1: /* GATM */
1.28 nicm 1240: screen_write_kcursormode(&ictx->ctx, 0);
1.1 nicm 1241: break;
1.17 nicm 1242: case 3: /* DECCOLM */
1.24 nicm 1243: screen_write_cursormove(&ictx->ctx, 0, 0);
1.17 nicm 1244: screen_write_clearscreen(&ictx->ctx);
1245: break;
1.1 nicm 1246: case 25: /* TCEM */
1.28 nicm 1247: screen_write_cursormode(&ictx->ctx, 0);
1.1 nicm 1248: break;
1249: case 1000:
1.32 nicm 1250: case 1001:
1251: case 1002:
1252: case 1003:
1253: screen_write_mousemode_off(&ictx->ctx);
1.1 nicm 1254: break;
1.33 nicm 1255: case 1005:
1256: screen_write_utf8mousemode(&ictx->ctx, 0);
1257: break;
1.55 ! nicm 1258: case 47:
! 1259: case 1047:
! 1260: window_pane_alternate_off(wp, &ictx->cell, 0);
! 1261: break;
1.9 nicm 1262: case 1049:
1.55 ! nicm 1263: window_pane_alternate_off(wp, &ictx->cell, 1);
1.9 nicm 1264: break;
1.49 nicm 1265: case 2004:
1266: screen_write_bracketpaste(&ictx->ctx, 0);
1267: break;
1.1 nicm 1268: default:
1.28 nicm 1269: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1270: break;
1271: }
1.42 nicm 1272: break;
1273: case INPUT_CSI_SCP:
1274: memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1275: ictx->old_cx = s->cx;
1276: ictx->old_cy = s->cy;
1.28 nicm 1277: break;
1278: case INPUT_CSI_SGR:
1279: input_csi_dispatch_sgr(ictx);
1280: break;
1281: case INPUT_CSI_SM:
1282: switch (input_get(ictx, 0, 0, -1)) {
1.1 nicm 1283: case 4: /* IRM */
1284: screen_write_insertmode(&ictx->ctx, 1);
1285: break;
1286: default:
1.28 nicm 1287: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1288: break;
1289: }
1.28 nicm 1290: break;
1291: case INPUT_CSI_SM_PRIVATE:
1292: switch (input_get(ictx, 0, 0, -1)) {
1.1 nicm 1293: case 1: /* GATM */
1.28 nicm 1294: screen_write_kcursormode(&ictx->ctx, 1);
1.17 nicm 1295: break;
1296: case 3: /* DECCOLM */
1.24 nicm 1297: screen_write_cursormove(&ictx->ctx, 0, 0);
1.17 nicm 1298: screen_write_clearscreen(&ictx->ctx);
1.1 nicm 1299: break;
1300: case 25: /* TCEM */
1.28 nicm 1301: screen_write_cursormode(&ictx->ctx, 1);
1.1 nicm 1302: break;
1303: case 1000:
1.32 nicm 1304: screen_write_mousemode_on(
1305: &ictx->ctx, MODE_MOUSE_STANDARD);
1306: break;
1307: case 1002:
1308: screen_write_mousemode_on(
1309: &ictx->ctx, MODE_MOUSE_BUTTON);
1310: break;
1311: case 1003:
1312: screen_write_mousemode_on(&ictx->ctx, MODE_MOUSE_ANY);
1.33 nicm 1313: break;
1314: case 1005:
1315: screen_write_utf8mousemode(&ictx->ctx, 1);
1.9 nicm 1316: break;
1.55 ! nicm 1317: case 47:
! 1318: case 1047:
! 1319: window_pane_alternate_on(wp, &ictx->cell, 0);
! 1320: break;
1.9 nicm 1321: case 1049:
1.55 ! nicm 1322: window_pane_alternate_on(wp, &ictx->cell, 1);
1.49 nicm 1323: break;
1324: case 2004:
1325: screen_write_bracketpaste(&ictx->ctx, 1);
1.1 nicm 1326: break;
1327: default:
1.28 nicm 1328: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1329: break;
1330: }
1.28 nicm 1331: break;
1332: case INPUT_CSI_TBC:
1333: switch (input_get(ictx, 0, 0, 0)) {
1334: case 0:
1335: if (s->cx < screen_size_x(s))
1336: bit_clear(s->tabs, s->cx);
1.1 nicm 1337: break;
1.28 nicm 1338: case 3:
1339: bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1.1 nicm 1340: break;
1341: default:
1.28 nicm 1342: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1343: break;
1344: }
1.28 nicm 1345: break;
1346: case INPUT_CSI_VPA:
1347: n = input_get(ictx, 0, 1, 1);
1348: screen_write_cursormove(sctx, s->cx, n - 1);
1.39 nicm 1349: break;
1350: case INPUT_CSI_DECSCUSR:
1351: n = input_get(ictx, 0, 0, 0);
1352: screen_set_cursor_style(s, n);
1.28 nicm 1353: break;
1.1 nicm 1354: }
1355:
1.28 nicm 1356: return (0);
1.1 nicm 1357: }
1358:
1.28 nicm 1359: /* Handle CSI SGR. */
1.1 nicm 1360: void
1.28 nicm 1361: input_csi_dispatch_sgr(struct input_ctx *ictx)
1.1 nicm 1362: {
1.28 nicm 1363: struct grid_cell *gc = &ictx->cell;
1364: u_int i;
1365: int n, m;
1366: u_char attr;
1.1 nicm 1367:
1.28 nicm 1368: if (ictx->param_list_len == 0) {
1.1 nicm 1369: attr = gc->attr;
1370: memcpy(gc, &grid_default_cell, sizeof *gc);
1.24 nicm 1371: gc->attr |= (attr & GRID_ATTR_CHARSET);
1.1 nicm 1372: return;
1373: }
1374:
1.28 nicm 1375: for (i = 0; i < ictx->param_list_len; i++) {
1376: n = input_get(ictx, i, 0, 0);
1.1 nicm 1377:
1.28 nicm 1378: if (n == 38 || n == 48) {
1.1 nicm 1379: i++;
1.28 nicm 1380: if (input_get(ictx, i, 0, -1) != 5)
1.1 nicm 1381: continue;
1382:
1383: i++;
1.28 nicm 1384: m = input_get(ictx, i, 0, -1);
1385: if (m == -1) {
1386: if (n == 38) {
1387: gc->flags &= ~GRID_FLAG_FG256;
1388: gc->fg = 8;
1389: } else if (n == 48) {
1390: gc->flags &= ~GRID_FLAG_BG256;
1.36 nicm 1391: gc->bg = 8;
1.28 nicm 1392: }
1393:
1394: } else {
1395: if (n == 38) {
1396: gc->flags |= GRID_FLAG_FG256;
1397: gc->fg = m;
1398: } else if (n == 48) {
1399: gc->flags |= GRID_FLAG_BG256;
1400: gc->bg = m;
1401: }
1.1 nicm 1402: }
1403: continue;
1404: }
1405:
1.28 nicm 1406: switch (n) {
1.1 nicm 1407: case 0:
1408: case 10:
1409: attr = gc->attr;
1410: memcpy(gc, &grid_default_cell, sizeof *gc);
1411: gc->attr |= (attr & GRID_ATTR_CHARSET);
1412: break;
1413: case 1:
1414: gc->attr |= GRID_ATTR_BRIGHT;
1415: break;
1416: case 2:
1417: gc->attr |= GRID_ATTR_DIM;
1418: break;
1419: case 3:
1420: gc->attr |= GRID_ATTR_ITALICS;
1421: break;
1422: case 4:
1423: gc->attr |= GRID_ATTR_UNDERSCORE;
1424: break;
1425: case 5:
1426: gc->attr |= GRID_ATTR_BLINK;
1427: break;
1428: case 7:
1429: gc->attr |= GRID_ATTR_REVERSE;
1430: break;
1431: case 8:
1432: gc->attr |= GRID_ATTR_HIDDEN;
1433: break;
1434: case 22:
1435: gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
1436: break;
1437: case 23:
1438: gc->attr &= ~GRID_ATTR_ITALICS;
1439: break;
1440: case 24:
1441: gc->attr &= ~GRID_ATTR_UNDERSCORE;
1442: break;
1443: case 25:
1444: gc->attr &= ~GRID_ATTR_BLINK;
1445: break;
1446: case 27:
1447: gc->attr &= ~GRID_ATTR_REVERSE;
1448: break;
1449: case 30:
1450: case 31:
1451: case 32:
1452: case 33:
1453: case 34:
1454: case 35:
1455: case 36:
1456: case 37:
1457: gc->flags &= ~GRID_FLAG_FG256;
1.28 nicm 1458: gc->fg = n - 30;
1.1 nicm 1459: break;
1460: case 39:
1461: gc->flags &= ~GRID_FLAG_FG256;
1462: gc->fg = 8;
1463: break;
1464: case 40:
1465: case 41:
1466: case 42:
1467: case 43:
1468: case 44:
1469: case 45:
1470: case 46:
1471: case 47:
1472: gc->flags &= ~GRID_FLAG_BG256;
1.28 nicm 1473: gc->bg = n - 40;
1.1 nicm 1474: break;
1475: case 49:
1476: gc->flags &= ~GRID_FLAG_BG256;
1477: gc->bg = 8;
1.20 nicm 1478: break;
1479: case 90:
1480: case 91:
1481: case 92:
1482: case 93:
1483: case 94:
1484: case 95:
1485: case 96:
1486: case 97:
1.26 nicm 1487: gc->flags &= ~GRID_FLAG_FG256;
1.28 nicm 1488: gc->fg = n;
1.20 nicm 1489: break;
1490: case 100:
1491: case 101:
1492: case 102:
1493: case 103:
1494: case 104:
1495: case 105:
1496: case 106:
1497: case 107:
1.26 nicm 1498: gc->flags &= ~GRID_FLAG_BG256;
1.47 nicm 1499: gc->bg = n - 10;
1.1 nicm 1500: break;
1501: }
1502: }
1.28 nicm 1503: }
1504:
1.37 nicm 1505: /* DCS terminator (ST) received. */
1506: int
1507: input_dcs_dispatch(struct input_ctx *ictx)
1.28 nicm 1508: {
1.37 nicm 1509: const char prefix[] = "tmux;";
1510: const u_int prefix_len = (sizeof prefix) - 1;
1511:
1512: if (ictx->flags & INPUT_DISCARD)
1513: return (0);
1514:
1515: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1.28 nicm 1516:
1.37 nicm 1517: /* Check for tmux prefix. */
1518: if (ictx->input_len >= prefix_len &&
1519: strncmp(ictx->input_buf, prefix, prefix_len) == 0) {
1520: screen_write_rawstring(&ictx->ctx,
1521: ictx->input_buf + prefix_len, ictx->input_len - prefix_len);
1522: }
1.28 nicm 1523:
1.37 nicm 1524: return (0);
1.28 nicm 1525: }
1526:
1527: /* OSC string started. */
1528: void
1529: input_enter_osc(struct input_ctx *ictx)
1530: {
1531: log_debug("%s", __func__);
1532:
1.35 nicm 1533: input_clear(ictx);
1.28 nicm 1534: }
1535:
1536: /* OSC terminator (ST) received. */
1537: void
1538: input_exit_osc(struct input_ctx *ictx)
1539: {
1.38 nicm 1540: u_char *p = ictx->input_buf;
1541: int option;
1542:
1.28 nicm 1543: if (ictx->flags & INPUT_DISCARD)
1544: return;
1.38 nicm 1545: if (ictx->input_len < 1 || *p < '0' || *p > '9')
1546: return;
1.28 nicm 1547:
1.38 nicm 1548: log_debug("%s: \"%s\"", __func__, p);
1.28 nicm 1549:
1.38 nicm 1550: option = 0;
1551: while (*p >= '0' && *p <= '9')
1552: option = option * 10 + *p++ - '0';
1553: if (*p == ';')
1554: p++;
1555:
1556: switch (option) {
1557: case 0:
1558: case 2:
1559: screen_set_title(ictx->ctx.s, p);
1560: server_status_window(ictx->wp->window);
1561: break;
1562: case 12:
1563: screen_set_cursor_colour(ictx->ctx.s, p);
1564: break;
1565: case 112:
1566: if (*p == '\0') /* No arguments allowed. */
1567: screen_set_cursor_colour(ictx->ctx.s, "");
1568: break;
1569: default:
1570: log_debug("%s: unknown '%u'", __func__, option);
1571: break;
1572: }
1.28 nicm 1573: }
1574:
1575: /* APC string started. */
1576: void
1577: input_enter_apc(struct input_ctx *ictx)
1578: {
1579: log_debug("%s", __func__);
1580:
1.35 nicm 1581: input_clear(ictx);
1.28 nicm 1582: }
1583:
1584: /* APC terminator (ST) received. */
1585: void
1586: input_exit_apc(struct input_ctx *ictx)
1587: {
1588: if (ictx->flags & INPUT_DISCARD)
1589: return;
1590: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1591:
1592: screen_set_title(ictx->ctx.s, ictx->input_buf);
1593: server_status_window(ictx->wp->window);
1594: }
1595:
1596: /* Rename string started. */
1597: void
1598: input_enter_rename(struct input_ctx *ictx)
1599: {
1600: log_debug("%s", __func__);
1601:
1.35 nicm 1602: input_clear(ictx);
1.28 nicm 1603: }
1604:
1605: /* Rename terminator (ST) received. */
1606: void
1607: input_exit_rename(struct input_ctx *ictx)
1608: {
1609: if (ictx->flags & INPUT_DISCARD)
1.44 nicm 1610: return;
1611: if (!options_get_number(&ictx->wp->window->options, "allow-rename"))
1.28 nicm 1612: return;
1613: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1614:
1.48 nicm 1615: window_set_name(ictx->wp->window, ictx->input_buf);
1.28 nicm 1616: options_set_number(&ictx->wp->window->options, "automatic-rename", 0);
1617:
1618: server_status_window(ictx->wp->window);
1619: }
1620:
1621: /* Open UTF-8 character. */
1622: int
1623: input_utf8_open(struct input_ctx *ictx)
1624: {
1625: if (!options_get_number(&ictx->wp->window->options, "utf8")) {
1626: /* Print, and do not switch state. */
1627: input_print(ictx);
1628: return (-1);
1629: }
1630: log_debug("%s", __func__);
1631:
1632: utf8_open(&ictx->utf8data, ictx->ch);
1633: return (0);
1634: }
1635:
1636: /* Append to UTF-8 character. */
1637: int
1638: input_utf8_add(struct input_ctx *ictx)
1639: {
1640: log_debug("%s", __func__);
1641:
1642: utf8_append(&ictx->utf8data, ictx->ch);
1643: return (0);
1644: }
1645:
1646: /* Close UTF-8 string. */
1647: int
1648: input_utf8_close(struct input_ctx *ictx)
1649: {
1650: log_debug("%s", __func__);
1651:
1652: utf8_append(&ictx->utf8data, ictx->ch);
1653:
1654: ictx->cell.flags |= GRID_FLAG_UTF8;
1655: screen_write_cell(&ictx->ctx, &ictx->cell, &ictx->utf8data);
1656: ictx->cell.flags &= ~GRID_FLAG_UTF8;
1657:
1658: return (0);
1.1 nicm 1659: }