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