Annotation of src/usr.bin/tmux/input.c, Revision 1.4
1.4 ! nicm 1: /* $OpenBSD: input.c,v 1.3 2009/06/03 23:30:40 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 <stdint.h>
22: #include <stdlib.h>
23: #include <string.h>
24:
25: #include "tmux.h"
26:
27: #define INPUT_C0CONTROL(ch) (ch <= 0x1f)
28: #define INPUT_INTERMEDIATE(ch) (ch == 0xa0 || (ch >= 0x20 && ch <= 0x2f))
29: #define INPUT_PARAMETER(ch) (ch >= 0x30 && ch <= 0x3f)
30: #define INPUT_UPPERCASE(ch) (ch >= 0x40 && ch <= 0x5f)
31: #define INPUT_LOWERCASE(ch) (ch >= 0x60 && ch <= 0x7e)
32: #define INPUT_DELETE(ch) (ch == 0x7f)
33: #define INPUT_C1CONTROL(ch) (ch >= 0x80 && ch <= 0x9f)
34: #define INPUT_G1DISPLAYABLE(ch) (ch >= 0xa1 && ch <= 0xfe)
35: #define INPUT_SPECIAL(ch) (ch == 0xff)
36:
37: int input_get_argument(struct input_ctx *, u_int, uint16_t *, uint16_t);
38: int input_new_argument(struct input_ctx *);
39: int input_add_argument(struct input_ctx *, u_char);
40:
41: void input_start_string(struct input_ctx *, int);
42: void input_abort_string(struct input_ctx *);
43: int input_add_string(struct input_ctx *, u_char);
44: char *input_get_string(struct input_ctx *);
45:
46: void input_state(struct input_ctx *, void *);
47:
48: void input_state_first(u_char, struct input_ctx *);
49: void input_state_escape(u_char, struct input_ctx *);
50: void input_state_intermediate(u_char, struct input_ctx *);
51: void input_state_sequence_first(u_char, struct input_ctx *);
52: void input_state_sequence_next(u_char, struct input_ctx *);
53: void input_state_sequence_intermediate(u_char, struct input_ctx *);
54: void input_state_string_next(u_char, struct input_ctx *);
55: void input_state_string_escape(u_char, struct input_ctx *);
56: void input_state_utf8(u_char, struct input_ctx *);
57:
58: void input_handle_character(u_char, struct input_ctx *);
59: void input_handle_c0_control(u_char, struct input_ctx *);
60: void input_handle_c1_control(u_char, struct input_ctx *);
61: void input_handle_private_two(u_char, struct input_ctx *);
62: void input_handle_standard_two(u_char, struct input_ctx *);
63: void input_handle_sequence(u_char, struct input_ctx *);
64:
65: void input_handle_sequence_cuu(struct input_ctx *);
66: void input_handle_sequence_cud(struct input_ctx *);
67: void input_handle_sequence_cuf(struct input_ctx *);
68: void input_handle_sequence_cub(struct input_ctx *);
69: void input_handle_sequence_dch(struct input_ctx *);
70: void input_handle_sequence_dl(struct input_ctx *);
71: void input_handle_sequence_ich(struct input_ctx *);
72: void input_handle_sequence_il(struct input_ctx *);
73: void input_handle_sequence_vpa(struct input_ctx *);
74: void input_handle_sequence_hpa(struct input_ctx *);
75: void input_handle_sequence_cup(struct input_ctx *);
76: void input_handle_sequence_cup(struct input_ctx *);
77: void input_handle_sequence_ed(struct input_ctx *);
78: void input_handle_sequence_el(struct input_ctx *);
79: void input_handle_sequence_sm(struct input_ctx *);
80: void input_handle_sequence_rm(struct input_ctx *);
81: void input_handle_sequence_decstbm(struct input_ctx *);
82: void input_handle_sequence_sgr(struct input_ctx *);
83: void input_handle_sequence_dsr(struct input_ctx *);
84:
85: int input_sequence_cmp(const void *, const void *);
86:
87: struct input_sequence_entry {
88: u_char ch;
89: void (*fn)(struct input_ctx *);
90: };
91: const struct input_sequence_entry input_sequence_table[] = {
92: { '@', input_handle_sequence_ich },
93: { 'A', input_handle_sequence_cuu },
94: { 'B', input_handle_sequence_cud },
95: { 'C', input_handle_sequence_cuf },
96: { 'D', input_handle_sequence_cub },
97: { 'G', input_handle_sequence_hpa },
98: { 'H', input_handle_sequence_cup },
99: { 'J', input_handle_sequence_ed },
100: { 'K', input_handle_sequence_el },
101: { 'L', input_handle_sequence_il },
102: { 'M', input_handle_sequence_dl },
103: { 'P', input_handle_sequence_dch },
104: { 'd', input_handle_sequence_vpa },
105: { 'f', input_handle_sequence_cup },
106: { 'h', input_handle_sequence_sm },
107: { 'l', input_handle_sequence_rm },
108: { 'm', input_handle_sequence_sgr },
109: { 'n', input_handle_sequence_dsr },
110: { 'r', input_handle_sequence_decstbm },
111: };
112:
113: int
114: input_sequence_cmp(const void *a, const void *b)
115: {
116: int ai = ((const struct input_sequence_entry *) a)->ch;
117: int bi = ((const struct input_sequence_entry *) b)->ch;
118:
119: return (ai - bi);
120: }
121:
122: int
123: input_new_argument(struct input_ctx *ictx)
124: {
125: struct input_arg *arg;
126:
127: ARRAY_EXPAND(&ictx->args, 1);
128:
129: arg = &ARRAY_LAST(&ictx->args);
130: arg->used = 0;
131:
132: return (0);
133: }
134:
135: int
136: input_add_argument(struct input_ctx *ictx, u_char ch)
137: {
138: struct input_arg *arg;
139:
140: if (ARRAY_LENGTH(&ictx->args) == 0)
141: return (0);
142:
143: arg = &ARRAY_LAST(&ictx->args);
144: if (arg->used > (sizeof arg->data) - 1)
145: return (-1);
146: arg->data[arg->used++] = ch;
147:
148: return (0);
149: }
150:
151: int
152: input_get_argument(struct input_ctx *ictx, u_int i, uint16_t *n, uint16_t d)
153: {
154: struct input_arg *arg;
155: const char *errstr;
156:
157: *n = d;
158: if (i >= ARRAY_LENGTH(&ictx->args))
159: return (0);
160:
161: arg = &ARRAY_ITEM(&ictx->args, i);
162: if (*arg->data == '\0')
163: return (0);
164:
165: *n = strtonum(arg->data, 0, UINT16_MAX, &errstr);
166: if (errstr != NULL)
167: return (-1);
168: return (0);
169: }
170:
171: void
172: input_start_string(struct input_ctx *ictx, int type)
173: {
174: ictx->string_type = type;
175: ictx->string_len = 0;
176: }
177:
178: void
179: input_abort_string(struct input_ctx *ictx)
180: {
181: if (ictx->string_buf != NULL)
182: xfree(ictx->string_buf);
183: ictx->string_buf = NULL;
184: }
185:
186: int
187: input_add_string(struct input_ctx *ictx, u_char ch)
188: {
189: ictx->string_buf = xrealloc(ictx->string_buf, 1, ictx->string_len + 1);
190: ictx->string_buf[ictx->string_len++] = ch;
191:
192: if (ictx->string_len >= MAXSTRINGLEN) {
193: input_abort_string(ictx);
194: return (1);
195: }
196:
197: return (0);
198: }
199:
200: char *
201: input_get_string(struct input_ctx *ictx)
202: {
203: char *s;
204:
205: if (ictx->string_buf == NULL || input_add_string(ictx, '\0') != 0)
206: return (xstrdup(""));
207:
208: s = ictx->string_buf;
209: ictx->string_buf = NULL;
210: return (s);
211: }
212:
213: void
214: input_state(struct input_ctx *ictx, void *state)
215: {
216: ictx->state = state;
217: }
218:
219: void
220: input_init(struct window_pane *wp)
221: {
222: struct input_ctx *ictx = &wp->ictx;
223:
224: ARRAY_INIT(&ictx->args);
225:
226: ictx->string_len = 0;
227: ictx->string_buf = NULL;
228:
229: memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
230:
231: memcpy(&ictx->saved_cell, &grid_default_cell, sizeof ictx->saved_cell);
232: ictx->saved_cx = 0;
233: ictx->saved_cy = 0;
234:
235: input_state(ictx, input_state_first);
236: }
237:
238: void
239: input_free(struct window_pane *wp)
240: {
241: if (wp->ictx.string_buf != NULL)
242: xfree(wp->ictx.string_buf);
243:
244: ARRAY_FREE(&wp->ictx.args);
245: }
246:
247: void
248: input_parse(struct window_pane *wp)
249: {
250: struct input_ctx *ictx = &wp->ictx;
251: u_char ch;
252:
253: if (BUFFER_USED(wp->in) == 0)
254: return;
255:
256: ictx->buf = BUFFER_OUT(wp->in);
257: ictx->len = BUFFER_USED(wp->in);
258: ictx->off = 0;
259:
260: ictx->wp = wp;
261:
262: log_debug2("entry; buffer=%zu", ictx->len);
263:
264: if (wp->mode == NULL)
265: screen_write_start(&ictx->ctx, wp, &wp->base);
266: else
267: screen_write_start(&ictx->ctx, NULL, &wp->base);
268:
269: if (ictx->off != ictx->len)
270: wp->window->flags |= WINDOW_ACTIVITY;
271: while (ictx->off < ictx->len) {
272: ch = ictx->buf[ictx->off++];
273: ictx->state(ch, ictx);
274: }
275:
276: screen_write_stop(&ictx->ctx);
277:
278: buffer_remove(wp->in, ictx->len);
279: }
280:
281: void
282: input_state_first(u_char ch, struct input_ctx *ictx)
283: {
284: ictx->intermediate = '\0';
285:
286: if (INPUT_C0CONTROL(ch)) {
287: if (ch == 0x1b)
288: input_state(ictx, input_state_escape);
289: else
290: input_handle_c0_control(ch, ictx);
291: return;
292: }
293:
294: #if 0
295: if (INPUT_C1CONTROL(ch)) {
296: ch -= 0x40;
297: if (ch == '[')
298: input_state(ictx, input_state_sequence_first);
299: else if (ch == ']') {
300: input_start_string(ictx, STRING_SYSTEM);
301: input_state(ictx, input_state_string_next);
302: } else if (ch == '_') {
303: input_start_string(ictx, STRING_APPLICATION);
304: input_state(ictx, input_state_string_next);
305: } else
306: input_handle_c1_control(ch, ictx);
307: return;
308: }
309: #endif
310:
311: if (INPUT_DELETE(ch))
312: return;
313:
314: input_handle_character(ch, ictx);
315: }
316:
317: void
318: input_state_escape(u_char ch, struct input_ctx *ictx)
319: {
320: /* Treat C1 control and G1 displayable as 7-bit equivalent. */
321: if (INPUT_C1CONTROL(ch) || INPUT_G1DISPLAYABLE(ch))
322: ch &= 0x7f;
323:
324: if (INPUT_C0CONTROL(ch)) {
325: input_handle_c0_control(ch, ictx);
326: return;
327: }
328:
329: if (INPUT_INTERMEDIATE(ch)) {
330: log_debug2(":: in1 %zu: %hhu (%c)", ictx->off, ch, ch);
331: ictx->intermediate = ch;
332: input_state(ictx, input_state_intermediate);
333: return;
334: }
335:
336: if (INPUT_PARAMETER(ch)) {
337: input_state(ictx, input_state_first);
338: input_handle_private_two(ch, ictx);
339: return;
340: }
341:
342: if (INPUT_UPPERCASE(ch)) {
343: if (ch == '[')
344: input_state(ictx, input_state_sequence_first);
345: else if (ch == ']') {
346: input_start_string(ictx, STRING_SYSTEM);
347: input_state(ictx, input_state_string_next);
348: } else if (ch == '_') {
349: input_start_string(ictx, STRING_APPLICATION);
350: input_state(ictx, input_state_string_next);
351: } else {
352: input_state(ictx, input_state_first);
353: input_handle_c1_control(ch, ictx);
354: }
355: return;
356: }
357:
358: if (INPUT_LOWERCASE(ch)) {
359: input_state(ictx, input_state_first);
360: input_handle_standard_two(ch, ictx);
361: return;
362: }
363:
364: input_state(ictx, input_state_first);
365: }
366:
367: void
368: input_state_intermediate(u_char ch, struct input_ctx *ictx)
369: {
370: if (INPUT_INTERMEDIATE(ch)) {
371: /* Multiple intermediates currently ignored. */
372: log_debug2(":: in2 %zu: %hhu (%c)", ictx->off, ch, ch);
373: return;
374: }
375:
376: if (INPUT_PARAMETER(ch)) {
377: input_state(ictx, input_state_first);
378: input_handle_private_two(ch, ictx);
379: return;
380: }
381:
382: if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) {
383: input_state(ictx, input_state_first);
384: input_handle_standard_two(ch, ictx);
385: return;
386: }
387:
388: input_state(ictx, input_state_first);
389: }
390:
391: void
392: input_state_sequence_first(u_char ch, struct input_ctx *ictx)
393: {
394: ictx->private = '\0';
395: ARRAY_CLEAR(&ictx->args);
396:
1.4 ! nicm 397: /* Most C0 control are accepted within CSI. */
! 398: if (INPUT_C0CONTROL(ch)) {
! 399: if (ch == 0x1b) { /* ESC */
! 400: /* Abort sequence and begin with new. */
! 401: input_state(ictx, input_state_escape);
! 402: } else if (ch != 0x18 && ch != 0x1a) { /* CAN and SUB */
! 403: /* Handle C0 immediately. */
! 404: input_handle_c0_control(ch, ictx);
! 405: }
! 406: /*
! 407: * Just come back to this state, in case the next character
! 408: * is the start of a private sequence.
! 409: */
! 410: return;
! 411: }
! 412:
1.1 nicm 413: input_state(ictx, input_state_sequence_next);
414:
1.4 ! nicm 415: /* Private sequence: always the first character. */
! 416: if (ch >= 0x3c && ch <= 0x3f) {
! 417: ictx->private = ch;
! 418: return;
1.1 nicm 419: }
420:
421: /* Pass character on directly. */
422: input_state_sequence_next(ch, ictx);
423: }
424:
425: void
426: input_state_sequence_next(u_char ch, struct input_ctx *ictx)
427: {
428: if (INPUT_INTERMEDIATE(ch)) {
429: if (input_add_argument(ictx, '\0') != 0)
430: input_state(ictx, input_state_first);
431: else {
432: log_debug2(":: si1 %zu: %hhu (%c)", ictx->off, ch, ch);
433: input_state(ictx, input_state_sequence_intermediate);
434: }
435: return;
436: }
437:
438: if (INPUT_PARAMETER(ch)) {
1.4 ! nicm 439: if (ARRAY_EMPTY(&ictx->args))
! 440: input_new_argument(ictx);
! 441:
1.1 nicm 442: if (ch == ';') {
443: if (input_add_argument(ictx, '\0') != 0)
444: input_state(ictx, input_state_first);
445: else
446: input_new_argument(ictx);
447: } else if (input_add_argument(ictx, ch) != 0)
448: input_state(ictx, input_state_first);
449: return;
450: }
451:
452: if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) {
453: if (input_add_argument(ictx, '\0') != 0)
454: input_state(ictx, input_state_first);
455: else {
456: input_state(ictx, input_state_first);
457: input_handle_sequence(ch, ictx);
458: }
459: return;
460: }
461:
1.4 ! nicm 462: /* Most C0 control are accepted within CSI. */
! 463: if (INPUT_C0CONTROL(ch)) {
! 464: if (ch == 0x1b) { /* ESC */
! 465: /* Abort sequence and begin with new. */
! 466: input_state(ictx, input_state_escape);
! 467: } else if (ch != 0x18 && ch != 0x1a) { /* CAN and SUB */
! 468: /* Handle C0 immediately. */
! 469: input_handle_c0_control(ch, ictx);
! 470: }
! 471: return;
! 472: }
! 473:
1.1 nicm 474: input_state(ictx, input_state_first);
475: }
476:
477: void
478: input_state_sequence_intermediate(u_char ch, struct input_ctx *ictx)
479: {
480: if (INPUT_INTERMEDIATE(ch)) {
481: log_debug2(":: si2 %zu: %hhu (%c)", ictx->off, ch, ch);
482: return;
483: }
484:
485: if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) {
486: input_state(ictx, input_state_first);
487: input_handle_sequence(ch, ictx);
488: return;
489: }
490:
491: input_state(ictx, input_state_first);
492: }
493:
494: void
495: input_state_string_next(u_char ch, struct input_ctx *ictx)
496: {
497: if (ch == 0x1b) {
498: input_state(ictx, input_state_string_escape);
499: return;
500: }
501: if (ch == 0x07) {
502: input_state_string_escape(ch, ictx);
503: return;
504: }
505:
1.2 nicm 506: if (ch >= 0x20) {
1.1 nicm 507: if (input_add_string(ictx, ch) != 0)
508: input_state(ictx, input_state_first);
509: return;
510: }
511: }
512:
513: void
514: input_state_string_escape(u_char ch, struct input_ctx *ictx)
515: {
516: char *s;
517:
518: if (ch == '\007' || ch == '\\') {
519: input_state(ictx, input_state_first);
520: switch (ictx->string_type) {
521: case STRING_SYSTEM:
522: if (ch != '\007')
523: return;
524: s = input_get_string(ictx);
525: if ((s[0] != '0' && s[0] != '2') || s[1] != ';') {
526: xfree(s);
527: return;
528: }
529: screen_set_title(ictx->ctx.s, s + 2);
530: server_status_window(ictx->wp->window);
531: xfree(s);
532: break;
533: case STRING_APPLICATION:
534: if (ch != '\\')
535: return;
536: s = input_get_string(ictx);
537: screen_set_title(ictx->ctx.s, s);
538: server_status_window(ictx->wp->window);
539: xfree(s);
540: break;
541: case STRING_NAME:
542: if (ch != '\\')
543: return;
544: xfree(ictx->wp->window->name);
545: ictx->wp->window->name = input_get_string(ictx);
546: server_status_window(ictx->wp->window);
547: break;
548: }
549: return;
550: }
551:
552: input_state(ictx, input_state_string_next);
553: input_state_string_next(ch, ictx);
554: }
555:
556: void
557: input_state_utf8(u_char ch, struct input_ctx *ictx)
558: {
559: log_debug2("-- un %zu: %hhu (%c)", ictx->off, ch, ch);
560:
561: ictx->utf8_buf[ictx->utf8_off++] = ch;
562: if (--ictx->utf8_len != 0)
563: return;
564: input_state(ictx, input_state_first);
565:
566: ictx->cell.flags |= GRID_FLAG_UTF8;
567: screen_write_cell(&ictx->ctx, &ictx->cell, ictx->utf8_buf);
568: ictx->cell.flags &= ~GRID_FLAG_UTF8;
569: }
570:
571: void
572: input_handle_character(u_char ch, struct input_ctx *ictx)
573: {
574: struct window_pane *wp = ictx->wp;
575:
576: if (ch > 0x7f && options_get_number(&wp->window->options, "utf8")) {
577: /*
578: * UTF-8 sequence.
579: *
580: * 11000010-11011111 C2-DF start of 2-byte sequence
581: * 11100000-11101111 E0-EF start of 3-byte sequence
582: * 11110000-11110100 F0-F4 start of 4-byte sequence
583: */
584: memset(ictx->utf8_buf, 0xff, sizeof ictx->utf8_buf);
585: ictx->utf8_buf[0] = ch;
586: ictx->utf8_off = 1;
587:
588: if (ch >= 0xc2 && ch <= 0xdf) {
589: log_debug2("-- u2 %zu: %hhu (%c)", ictx->off, ch, ch);
590: input_state(ictx, input_state_utf8);
591: ictx->utf8_len = 1;
592: return;
593: }
594: if (ch >= 0xe0 && ch <= 0xef) {
595: log_debug2("-- u3 %zu: %hhu (%c)", ictx->off, ch, ch);
596: input_state(ictx, input_state_utf8);
597: ictx->utf8_len = 2;
598: return;
599: }
600: if (ch >= 0xf0 && ch <= 0xf4) {
601: log_debug2("-- u4 %zu: %hhu (%c)", ictx->off, ch, ch);
602: input_state(ictx, input_state_utf8);
603: ictx->utf8_len = 3;
604: return;
605: }
606: }
607: log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch);
608:
609: ictx->cell.data = ch;
610: screen_write_cell(&ictx->ctx, &ictx->cell, ictx->utf8_buf);
611: }
612:
613: void
614: input_handle_c0_control(u_char ch, struct input_ctx *ictx)
615: {
616: struct screen *s = ictx->ctx.s;
617:
618: log_debug2("-- c0 %zu: %hhu", ictx->off, ch);
619:
620: switch (ch) {
621: case '\0': /* NUL */
622: break;
623: case '\n': /* LF */
624: screen_write_linefeed(&ictx->ctx);
625: break;
626: case '\r': /* CR */
627: screen_write_carriagereturn(&ictx->ctx);
628: break;
629: case '\007': /* BELL */
630: ictx->wp->window->flags |= WINDOW_BELL;
631: break;
632: case '\010': /* BS */
633: screen_write_cursorleft(&ictx->ctx, 1);
634: break;
635: case '\011': /* TAB */
636: s->cx = ((s->cx / 8) * 8) + 8;
637: if (s->cx > screen_size_x(s) - 1) {
638: s->cx = 0;
639: screen_write_cursordown(&ictx->ctx, 1);
640: }
641: screen_write_cursormove(&ictx->ctx, s->cx, s->cy);
1.4 ! nicm 642: break;
! 643: case '\013': /* VT */
! 644: screen_write_linefeed(&ictx->ctx);
1.1 nicm 645: break;
646: case '\016': /* SO */
647: ictx->cell.attr |= GRID_ATTR_CHARSET;
648: break;
649: case '\017': /* SI */
650: ictx->cell.attr &= ~GRID_ATTR_CHARSET;
651: break;
652: default:
653: log_debug("unknown c0: %hhu", ch);
654: break;
655: }
656: }
657:
658: void
659: input_handle_c1_control(u_char ch, struct input_ctx *ictx)
660: {
661: log_debug2("-- c1 %zu: %hhu (%c)", ictx->off, ch, ch);
662:
663: switch (ch) {
1.3 nicm 664: case 'D': /* IND */
665: screen_write_linefeed(&ictx->ctx);
666: break;
1.1 nicm 667: case 'E': /* NEL */
668: screen_write_carriagereturn(&ictx->ctx);
669: screen_write_linefeed(&ictx->ctx);
670: break;
671: case 'M': /* RI */
672: screen_write_reverseindex(&ictx->ctx);
673: break;
674: default:
675: log_debug("unknown c1: %hhu", ch);
676: break;
677: }
678: }
679:
680: void
681: input_handle_private_two(u_char ch, struct input_ctx *ictx)
682: {
683: struct screen *s = ictx->ctx.s;
684:
685: log_debug2(
686: "-- p2 %zu: %hhu (%c) %hhu", ictx->off, ch, ch, ictx->intermediate);
687:
688: switch (ch) {
1.3 nicm 689: case '0': /* SCS */
1.1 nicm 690: /*
691: * Not really supported, but fake it up enough for those that
692: * use it to switch character sets (by redefining G0 to
693: * graphics set, rather than switching to G1).
694: */
695: switch (ictx->intermediate) {
696: case '(': /* G0 */
697: ictx->cell.attr |= GRID_ATTR_CHARSET;
698: break;
699: }
700: break;
701: case '=': /* DECKPAM */
1.3 nicm 702: if (ictx->intermediate != '\0')
703: break;
1.1 nicm 704: screen_write_kkeypadmode(&ictx->ctx, 1);
705: log_debug("kkeypad on (application mode)");
706: break;
707: case '>': /* DECKPNM */
1.3 nicm 708: if (ictx->intermediate != '\0')
709: break;
1.1 nicm 710: screen_write_kkeypadmode(&ictx->ctx, 0);
711: log_debug("kkeypad off (number mode)");
712: break;
713: case '7': /* DECSC */
1.3 nicm 714: if (ictx->intermediate != '\0')
715: break;
1.1 nicm 716: memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell);
717: ictx->saved_cx = s->cx;
718: ictx->saved_cy = s->cy;
719: break;
1.3 nicm 720: case '8':
721: switch (ictx->intermediate) {
722: case '\0': /* DECRC */
723: memcpy(
724: &ictx->cell, &ictx->saved_cell, sizeof ictx->cell);
725: screen_write_cursormove(
726: &ictx->ctx, ictx->saved_cx, ictx->saved_cy);
727: break;
728: case '#': /* DECALN */
729: screen_write_alignmenttest(&ictx->ctx);
730: break;
731: }
1.1 nicm 732: break;
733: default:
734: log_debug("unknown p2: %hhu", ch);
735: break;
736: }
737: }
738:
739: void
740: input_handle_standard_two(u_char ch, struct input_ctx *ictx)
741: {
742: log_debug2(
743: "-- s2 %zu: %hhu (%c) %hhu", ictx->off, ch, ch, ictx->intermediate);
744:
745: switch (ch) {
746: case 'B': /* Dscs (ASCII) */
747: /*
748: * Not really supported, but fake it up enough for those that
749: * use it to switch character sets (by redefining G0 to
750: * graphics set, rather than switching to G1).
751: */
752: switch (ictx->intermediate) {
753: case '(': /* G0 */
754: ictx->cell.attr &= ~GRID_ATTR_CHARSET;
755: break;
756: }
757: break;
758: case 'c': /* RIS */
759: memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
760:
761: memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell);
762: ictx->saved_cx = 0;
763: ictx->saved_cy = 0;
764:
765: screen_write_scrollregion(
766: &ictx->ctx, 0, screen_size_y(ictx->ctx.s) - 1);
767:
768: screen_write_insertmode(&ictx->ctx, 0);
769: screen_write_kcursormode(&ictx->ctx, 0);
770: screen_write_kkeypadmode(&ictx->ctx, 0);
771: screen_write_mousemode(&ictx->ctx, 0);
772:
773: screen_write_clearscreen(&ictx->ctx);
774: screen_write_cursormove(&ictx->ctx, 0, 0);
775: break;
776: case 'k':
777: input_start_string(ictx, STRING_NAME);
778: input_state(ictx, input_state_string_next);
779: break;
780: default:
781: log_debug("unknown s2: %hhu", ch);
782: break;
783: }
784: }
785:
786: void
787: input_handle_sequence(u_char ch, struct input_ctx *ictx)
788: {
789: struct input_sequence_entry *entry, find;
790: struct screen *s = ictx->ctx.s;
791: u_int i;
792: struct input_arg *iarg;
793:
794: log_debug2("-- sq %zu: %hhu (%c): %u [sx=%u, sy=%u, cx=%u, cy=%u, "
795: "ru=%u, rl=%u]", ictx->off, ch, ch, ARRAY_LENGTH(&ictx->args),
796: screen_size_x(s), screen_size_y(s), s->cx, s->cy, s->rupper,
797: s->rlower);
798: for (i = 0; i < ARRAY_LENGTH(&ictx->args); i++) {
799: iarg = &ARRAY_ITEM(&ictx->args, i);
800: if (*iarg->data != '\0')
801: log_debug2(" ++ %u: %s", i, iarg->data);
802: }
803:
804: find.ch = ch;
805: entry = bsearch(&find,
806: input_sequence_table, nitems(input_sequence_table),
807: sizeof input_sequence_table[0], input_sequence_cmp);
808: if (entry != NULL)
809: entry->fn(ictx);
810: else
811: log_debug("unknown sq: %c (%hhu %hhu)", ch, ch, ictx->private);
812: }
813:
814: void
815: input_handle_sequence_cuu(struct input_ctx *ictx)
816: {
817: uint16_t n;
818:
819: if (ictx->private != '\0')
820: return;
821:
822: if (ARRAY_LENGTH(&ictx->args) > 1)
823: return;
824: if (input_get_argument(ictx, 0, &n, 1) != 0)
825: return;
826: if (n == 0)
827: n = 1;
828:
829: screen_write_cursorup(&ictx->ctx, n);
830: }
831:
832: void
833: input_handle_sequence_cud(struct input_ctx *ictx)
834: {
835: uint16_t n;
836:
837: if (ictx->private != '\0')
838: return;
839:
840: if (ARRAY_LENGTH(&ictx->args) > 1)
841: return;
842: if (input_get_argument(ictx, 0, &n, 1) != 0)
843: return;
844: if (n == 0)
845: n = 1;
846:
847: screen_write_cursordown(&ictx->ctx, n);
848: }
849:
850: void
851: input_handle_sequence_cuf(struct input_ctx *ictx)
852: {
853: uint16_t n;
854:
855: if (ictx->private != '\0')
856: return;
857:
858: if (ARRAY_LENGTH(&ictx->args) > 1)
859: return;
860: if (input_get_argument(ictx, 0, &n, 1) != 0)
861: return;
862: if (n == 0)
863: n = 1;
864:
865: screen_write_cursorright(&ictx->ctx, n);
866: }
867:
868: void
869: input_handle_sequence_cub(struct input_ctx *ictx)
870: {
871: uint16_t n;
872:
873: if (ictx->private != '\0')
874: return;
875:
876: if (ARRAY_LENGTH(&ictx->args) > 1)
877: return;
878: if (input_get_argument(ictx, 0, &n, 1) != 0)
879: return;
880: if (n == 0)
881: n = 1;
882:
883: screen_write_cursorleft(&ictx->ctx, n);
884: }
885:
886: void
887: input_handle_sequence_dch(struct input_ctx *ictx)
888: {
889: uint16_t n;
890:
891: if (ictx->private != '\0')
892: return;
893:
894: if (ARRAY_LENGTH(&ictx->args) > 1)
895: return;
896: if (input_get_argument(ictx, 0, &n, 1) != 0)
897: return;
898: if (n == 0)
899: n = 1;
900:
901: screen_write_deletecharacter(&ictx->ctx, n);
902: }
903:
904: void
905: input_handle_sequence_dl(struct input_ctx *ictx)
906: {
907: uint16_t n;
908:
909: if (ictx->private != '\0')
910: return;
911:
912: if (ARRAY_LENGTH(&ictx->args) > 1)
913: return;
914: if (input_get_argument(ictx, 0, &n, 1) != 0)
915: return;
916: if (n == 0)
917: n = 1;
918:
919: screen_write_deleteline(&ictx->ctx, n);
920: }
921:
922: void
923: input_handle_sequence_ich(struct input_ctx *ictx)
924: {
925: uint16_t n;
926:
927: if (ictx->private != '\0')
928: return;
929:
930: if (ARRAY_LENGTH(&ictx->args) > 1)
931: return;
932: if (input_get_argument(ictx, 0, &n, 1) != 0)
933: return;
934: if (n == 0)
935: n = 1;
936:
937: screen_write_insertcharacter(&ictx->ctx, n);
938: }
939:
940: void
941: input_handle_sequence_il(struct input_ctx *ictx)
942: {
943: uint16_t n;
944:
945: if (ictx->private != '\0')
946: return;
947:
948: if (ARRAY_LENGTH(&ictx->args) > 1)
949: return;
950: if (input_get_argument(ictx, 0, &n, 1) != 0)
951: return;
952: if (n == 0)
953: n = 1;
954:
955: screen_write_insertline(&ictx->ctx, n);
956: }
957:
958: void
959: input_handle_sequence_vpa(struct input_ctx *ictx)
960: {
961: struct screen *s = ictx->ctx.s;
962: uint16_t n;
963:
964: if (ictx->private != '\0')
965: return;
966:
967: if (ARRAY_LENGTH(&ictx->args) > 1)
968: return;
969: if (input_get_argument(ictx, 0, &n, 1) != 0)
970: return;
971: if (n == 0)
972: n = 1;
973:
974: screen_write_cursormove(&ictx->ctx, s->cx, n - 1);
975: }
976:
977: void
978: input_handle_sequence_hpa(struct input_ctx *ictx)
979: {
980: struct screen *s = ictx->ctx.s;
981: uint16_t n;
982:
983: if (ictx->private != '\0')
984: return;
985:
986: if (ARRAY_LENGTH(&ictx->args) > 1)
987: return;
988: if (input_get_argument(ictx, 0, &n, 1) != 0)
989: return;
990: if (n == 0)
991: n = 1;
992:
993: screen_write_cursormove(&ictx->ctx, n - 1, s->cy);
994: }
995:
996: void
997: input_handle_sequence_cup(struct input_ctx *ictx)
998: {
999: uint16_t n, m;
1000:
1001: if (ictx->private != '\0')
1002: return;
1003:
1004: if (ARRAY_LENGTH(&ictx->args) > 2)
1005: return;
1006: if (input_get_argument(ictx, 0, &n, 1) != 0)
1007: return;
1008: if (input_get_argument(ictx, 1, &m, 1) != 0)
1009: return;
1010: if (n == 0)
1011: n = 1;
1012: if (m == 0)
1013: m = 1;
1014:
1015: screen_write_cursormove(&ictx->ctx, m - 1, n - 1);
1016: }
1017:
1018: void
1019: input_handle_sequence_ed(struct input_ctx *ictx)
1020: {
1021: uint16_t n;
1022:
1023: if (ictx->private != '\0')
1024: return;
1025:
1026: if (ARRAY_LENGTH(&ictx->args) > 1)
1027: return;
1028: if (input_get_argument(ictx, 0, &n, 0) != 0)
1029: return;
1030: if (n > 2)
1031: return;
1032:
1033: switch (n) {
1034: case 0:
1035: screen_write_clearendofscreen(&ictx->ctx);
1036: break;
1037: case 1:
1038: screen_write_clearstartofscreen(&ictx->ctx);
1039: break;
1040: case 2:
1041: screen_write_clearscreen(&ictx->ctx);
1042: break;
1043: }
1044: }
1045:
1046: void
1047: input_handle_sequence_el(struct input_ctx *ictx)
1048: {
1049: uint16_t n;
1050:
1051: if (ictx->private != '\0')
1052: return;
1053:
1054: if (ARRAY_LENGTH(&ictx->args) > 1)
1055: return;
1056: if (input_get_argument(ictx, 0, &n, 0) != 0)
1057: return;
1058: if (n > 2)
1059: return;
1060:
1061: switch (n) {
1062: case 0:
1063: screen_write_clearendofline(&ictx->ctx);
1064: break;
1065: case 1:
1066: screen_write_clearstartofline(&ictx->ctx);
1067: break;
1068: case 2:
1069: screen_write_clearline(&ictx->ctx);
1070: break;
1071: }
1072: }
1073:
1074: void
1075: input_handle_sequence_sm(struct input_ctx *ictx)
1076: {
1077: uint16_t n;
1078:
1079: if (ARRAY_LENGTH(&ictx->args) > 1)
1080: return;
1081: if (input_get_argument(ictx, 0, &n, 0) != 0)
1082: return;
1083:
1084: if (ictx->private == '?') {
1085: switch (n) {
1086: case 1: /* GATM */
1087: screen_write_kcursormode(&ictx->ctx, 1);
1088: log_debug("kcursor on");
1089: break;
1090: case 25: /* TCEM */
1091: screen_write_cursormode(&ictx->ctx, 1);
1092: log_debug("cursor on");
1093: break;
1094: case 1000:
1095: screen_write_mousemode(&ictx->ctx, 1);
1096: log_debug("mouse on");
1097: break;
1098: default:
1099: log_debug("unknown SM [%hhu]: %u", ictx->private, n);
1100: break;
1101: }
1102: } else {
1103: switch (n) {
1104: case 4: /* IRM */
1105: screen_write_insertmode(&ictx->ctx, 1);
1106: log_debug("insert on");
1107: break;
1108: case 34:
1109: /* Cursor high visibility not supported. */
1110: break;
1111: default:
1112: log_debug("unknown SM [%hhu]: %u", ictx->private, n);
1113: break;
1114: }
1115: }
1116: }
1117:
1118: void
1119: input_handle_sequence_rm(struct input_ctx *ictx)
1120: {
1121: uint16_t n;
1122:
1123: if (ARRAY_LENGTH(&ictx->args) > 1)
1124: return;
1125: if (input_get_argument(ictx, 0, &n, 0) != 0)
1126: return;
1127:
1128: if (ictx->private == '?') {
1129: switch (n) {
1130: case 1: /* GATM */
1131: screen_write_kcursormode(&ictx->ctx, 0);
1132: log_debug("kcursor off");
1133: break;
1134: case 25: /* TCEM */
1135: screen_write_cursormode(&ictx->ctx, 0);
1136: log_debug("cursor off");
1137: break;
1138: case 1000:
1139: screen_write_mousemode(&ictx->ctx, 0);
1140: log_debug("mouse off");
1141: break;
1142: default:
1143: log_debug("unknown RM [%hhu]: %u", ictx->private, n);
1144: break;
1145: }
1146: } else if (ictx->private == '\0') {
1147: switch (n) {
1148: case 4: /* IRM */
1149: screen_write_insertmode(&ictx->ctx, 0);
1150: log_debug("insert off");
1151: break;
1152: case 34:
1153: /* Cursor high visibility not supported. */
1154: break;
1155: default:
1156: log_debug("unknown RM [%hhu]: %u", ictx->private, n);
1157: break;
1158: }
1159: }
1160: }
1161:
1162: void
1163: input_handle_sequence_dsr(struct input_ctx *ictx)
1164: {
1165: struct screen *s = ictx->ctx.s;
1166: uint16_t n;
1167: char reply[32];
1168:
1169: if (ARRAY_LENGTH(&ictx->args) > 1)
1170: return;
1171: if (input_get_argument(ictx, 0, &n, 0) != 0)
1172: return;
1173:
1174: if (ictx->private == '\0') {
1175: switch (n) {
1176: case 6: /* cursor position */
1177: xsnprintf(reply, sizeof reply,
1178: "\033[%u;%uR", s->cy + 1, s->cx + 1);
1179: log_debug("cursor request, reply: %s", reply);
1180: buffer_write(ictx->wp->out, reply, strlen(reply));
1181: break;
1182: }
1183: }
1184:
1185: }
1186:
1187: void
1188: input_handle_sequence_decstbm(struct input_ctx *ictx)
1189: {
1190: struct screen *s = ictx->ctx.s;
1191: uint16_t n, m;
1192:
1193: if (ictx->private != '\0')
1194: return;
1195:
1196: if (ARRAY_LENGTH(&ictx->args) > 2)
1197: return;
1198: if (input_get_argument(ictx, 0, &n, 0) != 0)
1199: return;
1200: if (input_get_argument(ictx, 1, &m, 0) != 0)
1201: return;
1202: if (n == 0)
1203: n = 1;
1204: if (m == 0)
1205: m = screen_size_y(s);
1206:
1207: screen_write_scrollregion(&ictx->ctx, n - 1, m - 1);
1208: }
1209:
1210: void
1211: input_handle_sequence_sgr(struct input_ctx *ictx)
1212: {
1213: struct grid_cell *gc = &ictx->cell;
1214: u_int i;
1215: uint16_t m, o;
1216: u_char attr;
1217:
1218: if (ARRAY_LENGTH(&ictx->args) == 0) {
1219: attr = gc->attr;
1220: memcpy(gc, &grid_default_cell, sizeof *gc);
1221: gc->attr |= (attr & GRID_ATTR_CHARSET);
1222: return;
1223: }
1224:
1225: for (i = 0; i < ARRAY_LENGTH(&ictx->args); i++) {
1226: if (input_get_argument(ictx, i, &m, 0) != 0)
1227: return;
1228:
1229: if (m == 38 || m == 48) {
1230: i++;
1231: if (input_get_argument(ictx, i, &o, 0) != 0)
1232: return;
1233: if (o != 5)
1234: continue;
1235:
1236: i++;
1237: if (input_get_argument(ictx, i, &o, 0) != 0)
1238: return;
1239: if (m == 38) {
1240: gc->flags |= GRID_FLAG_FG256;
1241: gc->fg = o;
1242: } else if (m == 48) {
1243: gc->flags |= GRID_FLAG_BG256;
1244: gc->bg = o;
1245: }
1246: continue;
1247: }
1248:
1249: switch (m) {
1250: case 0:
1251: case 10:
1252: attr = gc->attr;
1253: memcpy(gc, &grid_default_cell, sizeof *gc);
1254: gc->attr |= (attr & GRID_ATTR_CHARSET);
1255: break;
1256: case 1:
1257: gc->attr |= GRID_ATTR_BRIGHT;
1258: break;
1259: case 2:
1260: gc->attr |= GRID_ATTR_DIM;
1261: break;
1262: case 3:
1263: gc->attr |= GRID_ATTR_ITALICS;
1264: break;
1265: case 4:
1266: gc->attr |= GRID_ATTR_UNDERSCORE;
1267: break;
1268: case 5:
1269: gc->attr |= GRID_ATTR_BLINK;
1270: break;
1271: case 7:
1272: gc->attr |= GRID_ATTR_REVERSE;
1273: break;
1274: case 8:
1275: gc->attr |= GRID_ATTR_HIDDEN;
1276: break;
1277: case 22:
1278: gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
1279: break;
1280: case 23:
1281: gc->attr &= ~GRID_ATTR_ITALICS;
1282: break;
1283: case 24:
1284: gc->attr &= ~GRID_ATTR_UNDERSCORE;
1285: break;
1286: case 25:
1287: gc->attr &= ~GRID_ATTR_BLINK;
1288: break;
1289: case 27:
1290: gc->attr &= ~GRID_ATTR_REVERSE;
1291: break;
1292: case 30:
1293: case 31:
1294: case 32:
1295: case 33:
1296: case 34:
1297: case 35:
1298: case 36:
1299: case 37:
1300: gc->flags &= ~GRID_FLAG_FG256;
1301: gc->fg = m - 30;
1302: break;
1303: case 39:
1304: gc->flags &= ~GRID_FLAG_FG256;
1305: gc->fg = 8;
1306: break;
1307: case 40:
1308: case 41:
1309: case 42:
1310: case 43:
1311: case 44:
1312: case 45:
1313: case 46:
1314: case 47:
1315: gc->flags &= ~GRID_FLAG_BG256;
1316: gc->bg = m - 40;
1317: break;
1318: case 49:
1319: gc->flags &= ~GRID_FLAG_BG256;
1320: gc->bg = 8;
1321: break;
1322: }
1323: }
1324: }