Annotation of src/usr.bin/tmux/input.c, Revision 1.6
1.6 ! nicm 1: /* $OpenBSD: input.c,v 1.5 2009/06/04 14:24:49 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);
1.6 ! nicm 402: return;
! 403: } else if (ch == 0x18 || ch == 0x1a) { /* CAN and SUB */
1.5 nicm 404: /* Abort sequence. */
405: input_state(ictx, input_state_first);
1.6 ! nicm 406: return;
1.4 nicm 407: }
1.6 ! nicm 408:
! 409: /* Handle C0 immediately. */
! 410: input_handle_c0_control(ch, ictx);
! 411:
1.4 nicm 412: /*
413: * Just come back to this state, in case the next character
414: * is the start of a private sequence.
415: */
416: return;
417: }
418:
1.1 nicm 419: input_state(ictx, input_state_sequence_next);
420:
1.4 nicm 421: /* Private sequence: always the first character. */
422: if (ch >= 0x3c && ch <= 0x3f) {
423: ictx->private = ch;
424: return;
1.1 nicm 425: }
426:
427: /* Pass character on directly. */
428: input_state_sequence_next(ch, ictx);
429: }
430:
431: void
432: input_state_sequence_next(u_char ch, struct input_ctx *ictx)
433: {
434: if (INPUT_INTERMEDIATE(ch)) {
435: if (input_add_argument(ictx, '\0') != 0)
436: input_state(ictx, input_state_first);
437: else {
438: log_debug2(":: si1 %zu: %hhu (%c)", ictx->off, ch, ch);
439: input_state(ictx, input_state_sequence_intermediate);
440: }
441: return;
442: }
443:
444: if (INPUT_PARAMETER(ch)) {
1.4 nicm 445: if (ARRAY_EMPTY(&ictx->args))
446: input_new_argument(ictx);
447:
1.1 nicm 448: if (ch == ';') {
449: if (input_add_argument(ictx, '\0') != 0)
450: input_state(ictx, input_state_first);
451: else
452: input_new_argument(ictx);
453: } else if (input_add_argument(ictx, ch) != 0)
454: input_state(ictx, input_state_first);
455: return;
456: }
457:
458: if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) {
459: if (input_add_argument(ictx, '\0') != 0)
460: input_state(ictx, input_state_first);
461: else {
462: input_state(ictx, input_state_first);
463: input_handle_sequence(ch, ictx);
464: }
465: return;
466: }
467:
1.4 nicm 468: /* Most C0 control are accepted within CSI. */
469: if (INPUT_C0CONTROL(ch)) {
470: if (ch == 0x1b) { /* ESC */
471: /* Abort sequence and begin with new. */
472: input_state(ictx, input_state_escape);
1.6 ! nicm 473: return;
! 474: } else if (ch == 0x18 || ch == 0x1a) { /* CAN and SUB */
1.5 nicm 475: /* Abort sequence. */
476: input_state(ictx, input_state_first);
1.6 ! nicm 477: return;
1.4 nicm 478: }
1.6 ! nicm 479:
! 480: /* Handle C0 immediately. */
! 481: input_handle_c0_control(ch, ictx);
! 482:
1.4 nicm 483: return;
484: }
485:
1.1 nicm 486: input_state(ictx, input_state_first);
487: }
488:
489: void
490: input_state_sequence_intermediate(u_char ch, struct input_ctx *ictx)
491: {
492: if (INPUT_INTERMEDIATE(ch)) {
493: log_debug2(":: si2 %zu: %hhu (%c)", ictx->off, ch, ch);
494: return;
495: }
496:
497: if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) {
498: input_state(ictx, input_state_first);
499: input_handle_sequence(ch, ictx);
500: return;
501: }
502:
503: input_state(ictx, input_state_first);
504: }
505:
506: void
507: input_state_string_next(u_char ch, struct input_ctx *ictx)
508: {
509: if (ch == 0x1b) {
510: input_state(ictx, input_state_string_escape);
511: return;
512: }
513: if (ch == 0x07) {
514: input_state_string_escape(ch, ictx);
515: return;
516: }
517:
1.2 nicm 518: if (ch >= 0x20) {
1.1 nicm 519: if (input_add_string(ictx, ch) != 0)
520: input_state(ictx, input_state_first);
521: return;
522: }
523: }
524:
525: void
526: input_state_string_escape(u_char ch, struct input_ctx *ictx)
527: {
528: char *s;
529:
530: if (ch == '\007' || ch == '\\') {
531: input_state(ictx, input_state_first);
532: switch (ictx->string_type) {
533: case STRING_SYSTEM:
534: if (ch != '\007')
535: return;
536: s = input_get_string(ictx);
537: if ((s[0] != '0' && s[0] != '2') || s[1] != ';') {
538: xfree(s);
539: return;
540: }
541: screen_set_title(ictx->ctx.s, s + 2);
542: server_status_window(ictx->wp->window);
543: xfree(s);
544: break;
545: case STRING_APPLICATION:
546: if (ch != '\\')
547: return;
548: s = input_get_string(ictx);
549: screen_set_title(ictx->ctx.s, s);
550: server_status_window(ictx->wp->window);
551: xfree(s);
552: break;
553: case STRING_NAME:
554: if (ch != '\\')
555: return;
556: xfree(ictx->wp->window->name);
557: ictx->wp->window->name = input_get_string(ictx);
558: server_status_window(ictx->wp->window);
559: break;
560: }
561: return;
562: }
563:
564: input_state(ictx, input_state_string_next);
565: input_state_string_next(ch, ictx);
566: }
567:
568: void
569: input_state_utf8(u_char ch, struct input_ctx *ictx)
570: {
571: log_debug2("-- un %zu: %hhu (%c)", ictx->off, ch, ch);
572:
573: ictx->utf8_buf[ictx->utf8_off++] = ch;
574: if (--ictx->utf8_len != 0)
575: return;
576: input_state(ictx, input_state_first);
577:
578: ictx->cell.flags |= GRID_FLAG_UTF8;
579: screen_write_cell(&ictx->ctx, &ictx->cell, ictx->utf8_buf);
580: ictx->cell.flags &= ~GRID_FLAG_UTF8;
581: }
582:
583: void
584: input_handle_character(u_char ch, struct input_ctx *ictx)
585: {
586: struct window_pane *wp = ictx->wp;
587:
588: if (ch > 0x7f && options_get_number(&wp->window->options, "utf8")) {
589: /*
590: * UTF-8 sequence.
591: *
592: * 11000010-11011111 C2-DF start of 2-byte sequence
593: * 11100000-11101111 E0-EF start of 3-byte sequence
594: * 11110000-11110100 F0-F4 start of 4-byte sequence
595: */
596: memset(ictx->utf8_buf, 0xff, sizeof ictx->utf8_buf);
597: ictx->utf8_buf[0] = ch;
598: ictx->utf8_off = 1;
599:
600: if (ch >= 0xc2 && ch <= 0xdf) {
601: log_debug2("-- u2 %zu: %hhu (%c)", ictx->off, ch, ch);
602: input_state(ictx, input_state_utf8);
603: ictx->utf8_len = 1;
604: return;
605: }
606: if (ch >= 0xe0 && ch <= 0xef) {
607: log_debug2("-- u3 %zu: %hhu (%c)", ictx->off, ch, ch);
608: input_state(ictx, input_state_utf8);
609: ictx->utf8_len = 2;
610: return;
611: }
612: if (ch >= 0xf0 && ch <= 0xf4) {
613: log_debug2("-- u4 %zu: %hhu (%c)", ictx->off, ch, ch);
614: input_state(ictx, input_state_utf8);
615: ictx->utf8_len = 3;
616: return;
617: }
618: }
619: log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch);
620:
621: ictx->cell.data = ch;
622: screen_write_cell(&ictx->ctx, &ictx->cell, ictx->utf8_buf);
623: }
624:
625: void
626: input_handle_c0_control(u_char ch, struct input_ctx *ictx)
627: {
628: struct screen *s = ictx->ctx.s;
629:
630: log_debug2("-- c0 %zu: %hhu", ictx->off, ch);
631:
632: switch (ch) {
633: case '\0': /* NUL */
634: break;
635: case '\n': /* LF */
636: screen_write_linefeed(&ictx->ctx);
637: break;
638: case '\r': /* CR */
639: screen_write_carriagereturn(&ictx->ctx);
640: break;
641: case '\007': /* BELL */
642: ictx->wp->window->flags |= WINDOW_BELL;
643: break;
644: case '\010': /* BS */
645: screen_write_cursorleft(&ictx->ctx, 1);
646: break;
647: case '\011': /* TAB */
648: s->cx = ((s->cx / 8) * 8) + 8;
649: if (s->cx > screen_size_x(s) - 1) {
650: s->cx = 0;
651: screen_write_cursordown(&ictx->ctx, 1);
652: }
653: screen_write_cursormove(&ictx->ctx, s->cx, s->cy);
1.4 nicm 654: break;
655: case '\013': /* VT */
656: screen_write_linefeed(&ictx->ctx);
1.1 nicm 657: break;
658: case '\016': /* SO */
659: ictx->cell.attr |= GRID_ATTR_CHARSET;
660: break;
661: case '\017': /* SI */
662: ictx->cell.attr &= ~GRID_ATTR_CHARSET;
663: break;
664: default:
665: log_debug("unknown c0: %hhu", ch);
666: break;
667: }
668: }
669:
670: void
671: input_handle_c1_control(u_char ch, struct input_ctx *ictx)
672: {
673: log_debug2("-- c1 %zu: %hhu (%c)", ictx->off, ch, ch);
674:
675: switch (ch) {
1.3 nicm 676: case 'D': /* IND */
677: screen_write_linefeed(&ictx->ctx);
678: break;
1.1 nicm 679: case 'E': /* NEL */
680: screen_write_carriagereturn(&ictx->ctx);
681: screen_write_linefeed(&ictx->ctx);
682: break;
683: case 'M': /* RI */
684: screen_write_reverseindex(&ictx->ctx);
685: break;
686: default:
687: log_debug("unknown c1: %hhu", ch);
688: break;
689: }
690: }
691:
692: void
693: input_handle_private_two(u_char ch, struct input_ctx *ictx)
694: {
695: struct screen *s = ictx->ctx.s;
696:
697: log_debug2(
698: "-- p2 %zu: %hhu (%c) %hhu", ictx->off, ch, ch, ictx->intermediate);
699:
700: switch (ch) {
1.3 nicm 701: case '0': /* SCS */
1.1 nicm 702: /*
703: * Not really supported, but fake it up enough for those that
704: * use it to switch character sets (by redefining G0 to
705: * graphics set, rather than switching to G1).
706: */
707: switch (ictx->intermediate) {
708: case '(': /* G0 */
709: ictx->cell.attr |= GRID_ATTR_CHARSET;
710: break;
711: }
712: break;
713: case '=': /* DECKPAM */
1.3 nicm 714: if (ictx->intermediate != '\0')
715: break;
1.1 nicm 716: screen_write_kkeypadmode(&ictx->ctx, 1);
717: log_debug("kkeypad on (application mode)");
718: break;
719: case '>': /* DECKPNM */
1.3 nicm 720: if (ictx->intermediate != '\0')
721: break;
1.1 nicm 722: screen_write_kkeypadmode(&ictx->ctx, 0);
723: log_debug("kkeypad off (number mode)");
724: break;
725: case '7': /* DECSC */
1.3 nicm 726: if (ictx->intermediate != '\0')
727: break;
1.1 nicm 728: memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell);
729: ictx->saved_cx = s->cx;
730: ictx->saved_cy = s->cy;
731: break;
1.3 nicm 732: case '8':
733: switch (ictx->intermediate) {
734: case '\0': /* DECRC */
735: memcpy(
736: &ictx->cell, &ictx->saved_cell, sizeof ictx->cell);
737: screen_write_cursormove(
738: &ictx->ctx, ictx->saved_cx, ictx->saved_cy);
739: break;
740: case '#': /* DECALN */
741: screen_write_alignmenttest(&ictx->ctx);
742: break;
743: }
1.1 nicm 744: break;
745: default:
746: log_debug("unknown p2: %hhu", ch);
747: break;
748: }
749: }
750:
751: void
752: input_handle_standard_two(u_char ch, struct input_ctx *ictx)
753: {
754: log_debug2(
755: "-- s2 %zu: %hhu (%c) %hhu", ictx->off, ch, ch, ictx->intermediate);
756:
757: switch (ch) {
758: case 'B': /* Dscs (ASCII) */
759: /*
760: * Not really supported, but fake it up enough for those that
761: * use it to switch character sets (by redefining G0 to
762: * graphics set, rather than switching to G1).
763: */
764: switch (ictx->intermediate) {
765: case '(': /* G0 */
766: ictx->cell.attr &= ~GRID_ATTR_CHARSET;
767: break;
768: }
769: break;
770: case 'c': /* RIS */
771: memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
772:
773: memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell);
774: ictx->saved_cx = 0;
775: ictx->saved_cy = 0;
776:
777: screen_write_scrollregion(
778: &ictx->ctx, 0, screen_size_y(ictx->ctx.s) - 1);
779:
780: screen_write_insertmode(&ictx->ctx, 0);
781: screen_write_kcursormode(&ictx->ctx, 0);
782: screen_write_kkeypadmode(&ictx->ctx, 0);
783: screen_write_mousemode(&ictx->ctx, 0);
784:
785: screen_write_clearscreen(&ictx->ctx);
786: screen_write_cursormove(&ictx->ctx, 0, 0);
787: break;
788: case 'k':
789: input_start_string(ictx, STRING_NAME);
790: input_state(ictx, input_state_string_next);
791: break;
792: default:
793: log_debug("unknown s2: %hhu", ch);
794: break;
795: }
796: }
797:
798: void
799: input_handle_sequence(u_char ch, struct input_ctx *ictx)
800: {
801: struct input_sequence_entry *entry, find;
802: struct screen *s = ictx->ctx.s;
803: u_int i;
804: struct input_arg *iarg;
805:
806: log_debug2("-- sq %zu: %hhu (%c): %u [sx=%u, sy=%u, cx=%u, cy=%u, "
807: "ru=%u, rl=%u]", ictx->off, ch, ch, ARRAY_LENGTH(&ictx->args),
808: screen_size_x(s), screen_size_y(s), s->cx, s->cy, s->rupper,
809: s->rlower);
810: for (i = 0; i < ARRAY_LENGTH(&ictx->args); i++) {
811: iarg = &ARRAY_ITEM(&ictx->args, i);
812: if (*iarg->data != '\0')
813: log_debug2(" ++ %u: %s", i, iarg->data);
814: }
815:
816: find.ch = ch;
817: entry = bsearch(&find,
818: input_sequence_table, nitems(input_sequence_table),
819: sizeof input_sequence_table[0], input_sequence_cmp);
820: if (entry != NULL)
821: entry->fn(ictx);
822: else
823: log_debug("unknown sq: %c (%hhu %hhu)", ch, ch, ictx->private);
824: }
825:
826: void
827: input_handle_sequence_cuu(struct input_ctx *ictx)
828: {
829: uint16_t n;
830:
831: if (ictx->private != '\0')
832: return;
833:
834: if (ARRAY_LENGTH(&ictx->args) > 1)
835: return;
836: if (input_get_argument(ictx, 0, &n, 1) != 0)
837: return;
838: if (n == 0)
839: n = 1;
840:
841: screen_write_cursorup(&ictx->ctx, n);
842: }
843:
844: void
845: input_handle_sequence_cud(struct input_ctx *ictx)
846: {
847: uint16_t n;
848:
849: if (ictx->private != '\0')
850: return;
851:
852: if (ARRAY_LENGTH(&ictx->args) > 1)
853: return;
854: if (input_get_argument(ictx, 0, &n, 1) != 0)
855: return;
856: if (n == 0)
857: n = 1;
858:
859: screen_write_cursordown(&ictx->ctx, n);
860: }
861:
862: void
863: input_handle_sequence_cuf(struct input_ctx *ictx)
864: {
865: uint16_t n;
866:
867: if (ictx->private != '\0')
868: return;
869:
870: if (ARRAY_LENGTH(&ictx->args) > 1)
871: return;
872: if (input_get_argument(ictx, 0, &n, 1) != 0)
873: return;
874: if (n == 0)
875: n = 1;
876:
877: screen_write_cursorright(&ictx->ctx, n);
878: }
879:
880: void
881: input_handle_sequence_cub(struct input_ctx *ictx)
882: {
883: uint16_t n;
884:
885: if (ictx->private != '\0')
886: return;
887:
888: if (ARRAY_LENGTH(&ictx->args) > 1)
889: return;
890: if (input_get_argument(ictx, 0, &n, 1) != 0)
891: return;
892: if (n == 0)
893: n = 1;
894:
895: screen_write_cursorleft(&ictx->ctx, n);
896: }
897:
898: void
899: input_handle_sequence_dch(struct input_ctx *ictx)
900: {
901: uint16_t n;
902:
903: if (ictx->private != '\0')
904: return;
905:
906: if (ARRAY_LENGTH(&ictx->args) > 1)
907: return;
908: if (input_get_argument(ictx, 0, &n, 1) != 0)
909: return;
910: if (n == 0)
911: n = 1;
912:
913: screen_write_deletecharacter(&ictx->ctx, n);
914: }
915:
916: void
917: input_handle_sequence_dl(struct input_ctx *ictx)
918: {
919: uint16_t n;
920:
921: if (ictx->private != '\0')
922: return;
923:
924: if (ARRAY_LENGTH(&ictx->args) > 1)
925: return;
926: if (input_get_argument(ictx, 0, &n, 1) != 0)
927: return;
928: if (n == 0)
929: n = 1;
930:
931: screen_write_deleteline(&ictx->ctx, n);
932: }
933:
934: void
935: input_handle_sequence_ich(struct input_ctx *ictx)
936: {
937: uint16_t n;
938:
939: if (ictx->private != '\0')
940: return;
941:
942: if (ARRAY_LENGTH(&ictx->args) > 1)
943: return;
944: if (input_get_argument(ictx, 0, &n, 1) != 0)
945: return;
946: if (n == 0)
947: n = 1;
948:
949: screen_write_insertcharacter(&ictx->ctx, n);
950: }
951:
952: void
953: input_handle_sequence_il(struct input_ctx *ictx)
954: {
955: uint16_t n;
956:
957: if (ictx->private != '\0')
958: return;
959:
960: if (ARRAY_LENGTH(&ictx->args) > 1)
961: return;
962: if (input_get_argument(ictx, 0, &n, 1) != 0)
963: return;
964: if (n == 0)
965: n = 1;
966:
967: screen_write_insertline(&ictx->ctx, n);
968: }
969:
970: void
971: input_handle_sequence_vpa(struct input_ctx *ictx)
972: {
973: struct screen *s = ictx->ctx.s;
974: uint16_t n;
975:
976: if (ictx->private != '\0')
977: return;
978:
979: if (ARRAY_LENGTH(&ictx->args) > 1)
980: return;
981: if (input_get_argument(ictx, 0, &n, 1) != 0)
982: return;
983: if (n == 0)
984: n = 1;
985:
986: screen_write_cursormove(&ictx->ctx, s->cx, n - 1);
987: }
988:
989: void
990: input_handle_sequence_hpa(struct input_ctx *ictx)
991: {
992: struct screen *s = ictx->ctx.s;
993: uint16_t n;
994:
995: if (ictx->private != '\0')
996: return;
997:
998: if (ARRAY_LENGTH(&ictx->args) > 1)
999: return;
1000: if (input_get_argument(ictx, 0, &n, 1) != 0)
1001: return;
1002: if (n == 0)
1003: n = 1;
1004:
1005: screen_write_cursormove(&ictx->ctx, n - 1, s->cy);
1006: }
1007:
1008: void
1009: input_handle_sequence_cup(struct input_ctx *ictx)
1010: {
1011: uint16_t n, m;
1012:
1013: if (ictx->private != '\0')
1014: return;
1015:
1016: if (ARRAY_LENGTH(&ictx->args) > 2)
1017: return;
1018: if (input_get_argument(ictx, 0, &n, 1) != 0)
1019: return;
1020: if (input_get_argument(ictx, 1, &m, 1) != 0)
1021: return;
1022: if (n == 0)
1023: n = 1;
1024: if (m == 0)
1025: m = 1;
1026:
1027: screen_write_cursormove(&ictx->ctx, m - 1, n - 1);
1028: }
1029:
1030: void
1031: input_handle_sequence_ed(struct input_ctx *ictx)
1032: {
1033: uint16_t n;
1034:
1035: if (ictx->private != '\0')
1036: return;
1037:
1038: if (ARRAY_LENGTH(&ictx->args) > 1)
1039: return;
1040: if (input_get_argument(ictx, 0, &n, 0) != 0)
1041: return;
1042: if (n > 2)
1043: return;
1044:
1045: switch (n) {
1046: case 0:
1047: screen_write_clearendofscreen(&ictx->ctx);
1048: break;
1049: case 1:
1050: screen_write_clearstartofscreen(&ictx->ctx);
1051: break;
1052: case 2:
1053: screen_write_clearscreen(&ictx->ctx);
1054: break;
1055: }
1056: }
1057:
1058: void
1059: input_handle_sequence_el(struct input_ctx *ictx)
1060: {
1061: uint16_t n;
1062:
1063: if (ictx->private != '\0')
1064: return;
1065:
1066: if (ARRAY_LENGTH(&ictx->args) > 1)
1067: return;
1068: if (input_get_argument(ictx, 0, &n, 0) != 0)
1069: return;
1070: if (n > 2)
1071: return;
1072:
1073: switch (n) {
1074: case 0:
1075: screen_write_clearendofline(&ictx->ctx);
1076: break;
1077: case 1:
1078: screen_write_clearstartofline(&ictx->ctx);
1079: break;
1080: case 2:
1081: screen_write_clearline(&ictx->ctx);
1082: break;
1083: }
1084: }
1085:
1086: void
1087: input_handle_sequence_sm(struct input_ctx *ictx)
1088: {
1089: uint16_t n;
1090:
1091: if (ARRAY_LENGTH(&ictx->args) > 1)
1092: return;
1093: if (input_get_argument(ictx, 0, &n, 0) != 0)
1094: return;
1095:
1096: if (ictx->private == '?') {
1097: switch (n) {
1098: case 1: /* GATM */
1099: screen_write_kcursormode(&ictx->ctx, 1);
1100: log_debug("kcursor on");
1101: break;
1102: case 25: /* TCEM */
1103: screen_write_cursormode(&ictx->ctx, 1);
1104: log_debug("cursor on");
1105: break;
1106: case 1000:
1107: screen_write_mousemode(&ictx->ctx, 1);
1108: log_debug("mouse on");
1109: break;
1110: default:
1111: log_debug("unknown SM [%hhu]: %u", ictx->private, n);
1112: break;
1113: }
1114: } else {
1115: switch (n) {
1116: case 4: /* IRM */
1117: screen_write_insertmode(&ictx->ctx, 1);
1118: log_debug("insert on");
1119: break;
1120: case 34:
1121: /* Cursor high visibility not supported. */
1122: break;
1123: default:
1124: log_debug("unknown SM [%hhu]: %u", ictx->private, n);
1125: break;
1126: }
1127: }
1128: }
1129:
1130: void
1131: input_handle_sequence_rm(struct input_ctx *ictx)
1132: {
1133: uint16_t n;
1134:
1135: if (ARRAY_LENGTH(&ictx->args) > 1)
1136: return;
1137: if (input_get_argument(ictx, 0, &n, 0) != 0)
1138: return;
1139:
1140: if (ictx->private == '?') {
1141: switch (n) {
1142: case 1: /* GATM */
1143: screen_write_kcursormode(&ictx->ctx, 0);
1144: log_debug("kcursor off");
1145: break;
1146: case 25: /* TCEM */
1147: screen_write_cursormode(&ictx->ctx, 0);
1148: log_debug("cursor off");
1149: break;
1150: case 1000:
1151: screen_write_mousemode(&ictx->ctx, 0);
1152: log_debug("mouse off");
1153: break;
1154: default:
1155: log_debug("unknown RM [%hhu]: %u", ictx->private, n);
1156: break;
1157: }
1158: } else if (ictx->private == '\0') {
1159: switch (n) {
1160: case 4: /* IRM */
1161: screen_write_insertmode(&ictx->ctx, 0);
1162: log_debug("insert off");
1163: break;
1164: case 34:
1165: /* Cursor high visibility not supported. */
1166: break;
1167: default:
1168: log_debug("unknown RM [%hhu]: %u", ictx->private, n);
1169: break;
1170: }
1171: }
1172: }
1173:
1174: void
1175: input_handle_sequence_dsr(struct input_ctx *ictx)
1176: {
1177: struct screen *s = ictx->ctx.s;
1178: uint16_t n;
1179: char reply[32];
1180:
1181: if (ARRAY_LENGTH(&ictx->args) > 1)
1182: return;
1183: if (input_get_argument(ictx, 0, &n, 0) != 0)
1184: return;
1185:
1186: if (ictx->private == '\0') {
1187: switch (n) {
1188: case 6: /* cursor position */
1189: xsnprintf(reply, sizeof reply,
1190: "\033[%u;%uR", s->cy + 1, s->cx + 1);
1191: log_debug("cursor request, reply: %s", reply);
1192: buffer_write(ictx->wp->out, reply, strlen(reply));
1193: break;
1194: }
1195: }
1196:
1197: }
1198:
1199: void
1200: input_handle_sequence_decstbm(struct input_ctx *ictx)
1201: {
1202: struct screen *s = ictx->ctx.s;
1203: uint16_t n, m;
1204:
1205: if (ictx->private != '\0')
1206: return;
1207:
1208: if (ARRAY_LENGTH(&ictx->args) > 2)
1209: return;
1210: if (input_get_argument(ictx, 0, &n, 0) != 0)
1211: return;
1212: if (input_get_argument(ictx, 1, &m, 0) != 0)
1213: return;
1214: if (n == 0)
1215: n = 1;
1216: if (m == 0)
1217: m = screen_size_y(s);
1218:
1219: screen_write_scrollregion(&ictx->ctx, n - 1, m - 1);
1220: }
1221:
1222: void
1223: input_handle_sequence_sgr(struct input_ctx *ictx)
1224: {
1225: struct grid_cell *gc = &ictx->cell;
1226: u_int i;
1227: uint16_t m, o;
1228: u_char attr;
1229:
1230: if (ARRAY_LENGTH(&ictx->args) == 0) {
1231: attr = gc->attr;
1232: memcpy(gc, &grid_default_cell, sizeof *gc);
1233: gc->attr |= (attr & GRID_ATTR_CHARSET);
1234: return;
1235: }
1236:
1237: for (i = 0; i < ARRAY_LENGTH(&ictx->args); i++) {
1238: if (input_get_argument(ictx, i, &m, 0) != 0)
1239: return;
1240:
1241: if (m == 38 || m == 48) {
1242: i++;
1243: if (input_get_argument(ictx, i, &o, 0) != 0)
1244: return;
1245: if (o != 5)
1246: continue;
1247:
1248: i++;
1249: if (input_get_argument(ictx, i, &o, 0) != 0)
1250: return;
1251: if (m == 38) {
1252: gc->flags |= GRID_FLAG_FG256;
1253: gc->fg = o;
1254: } else if (m == 48) {
1255: gc->flags |= GRID_FLAG_BG256;
1256: gc->bg = o;
1257: }
1258: continue;
1259: }
1260:
1261: switch (m) {
1262: case 0:
1263: case 10:
1264: attr = gc->attr;
1265: memcpy(gc, &grid_default_cell, sizeof *gc);
1266: gc->attr |= (attr & GRID_ATTR_CHARSET);
1267: break;
1268: case 1:
1269: gc->attr |= GRID_ATTR_BRIGHT;
1270: break;
1271: case 2:
1272: gc->attr |= GRID_ATTR_DIM;
1273: break;
1274: case 3:
1275: gc->attr |= GRID_ATTR_ITALICS;
1276: break;
1277: case 4:
1278: gc->attr |= GRID_ATTR_UNDERSCORE;
1279: break;
1280: case 5:
1281: gc->attr |= GRID_ATTR_BLINK;
1282: break;
1283: case 7:
1284: gc->attr |= GRID_ATTR_REVERSE;
1285: break;
1286: case 8:
1287: gc->attr |= GRID_ATTR_HIDDEN;
1288: break;
1289: case 22:
1290: gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
1291: break;
1292: case 23:
1293: gc->attr &= ~GRID_ATTR_ITALICS;
1294: break;
1295: case 24:
1296: gc->attr &= ~GRID_ATTR_UNDERSCORE;
1297: break;
1298: case 25:
1299: gc->attr &= ~GRID_ATTR_BLINK;
1300: break;
1301: case 27:
1302: gc->attr &= ~GRID_ATTR_REVERSE;
1303: break;
1304: case 30:
1305: case 31:
1306: case 32:
1307: case 33:
1308: case 34:
1309: case 35:
1310: case 36:
1311: case 37:
1312: gc->flags &= ~GRID_FLAG_FG256;
1313: gc->fg = m - 30;
1314: break;
1315: case 39:
1316: gc->flags &= ~GRID_FLAG_FG256;
1317: gc->fg = 8;
1318: break;
1319: case 40:
1320: case 41:
1321: case 42:
1322: case 43:
1323: case 44:
1324: case 45:
1325: case 46:
1326: case 47:
1327: gc->flags &= ~GRID_FLAG_BG256;
1328: gc->bg = m - 40;
1329: break;
1330: case 49:
1331: gc->flags &= ~GRID_FLAG_BG256;
1332: gc->bg = 8;
1333: break;
1334: }
1335: }
1336: }