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