FreeBSD/Linux Kernel Cross Reference
sys/teken/teken.c
1 /*-
2 * Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: releng/11.2/sys/teken/teken.c 330916 2018-03-14 07:47:26Z eadler $
27 */
28
29 #include <sys/cdefs.h>
30 #if defined(__FreeBSD__) && defined(_KERNEL)
31 #include <sys/param.h>
32 #include <sys/limits.h>
33 #include <sys/lock.h>
34 #include <sys/systm.h>
35 #define teken_assert(x) MPASS(x)
36 #else /* !(__FreeBSD__ && _KERNEL) */
37 #include <sys/types.h>
38 #include <assert.h>
39 #include <limits.h>
40 #include <stdint.h>
41 #include <stdio.h>
42 #include <string.h>
43 #define teken_assert(x) assert(x)
44 #endif /* __FreeBSD__ && _KERNEL */
45
46 /* debug messages */
47 #define teken_printf(x,...)
48
49 /* Private flags for t_stateflags. */
50 #define TS_FIRSTDIGIT 0x0001 /* First numeric digit in escape sequence. */
51 #define TS_INSERT 0x0002 /* Insert mode. */
52 #define TS_AUTOWRAP 0x0004 /* Autowrap. */
53 #define TS_ORIGIN 0x0008 /* Origin mode. */
54 #define TS_WRAPPED 0x0010 /* Next character should be printed on col 0. */
55 #define TS_8BIT 0x0020 /* UTF-8 disabled. */
56 #define TS_CONS25 0x0040 /* cons25 emulation. */
57 #define TS_INSTRING 0x0080 /* Inside string. */
58 #define TS_CURSORKEYS 0x0100 /* Cursor keys mode. */
59
60 /* Character that blanks a cell. */
61 #define BLANK ' '
62
63 #include "teken.h"
64 #include "teken_wcwidth.h"
65 #include "teken_scs.h"
66
67 static teken_state_t teken_state_init;
68
69 /*
70 * Wrappers for hooks.
71 */
72
73 static inline void
74 teken_funcs_bell(teken_t *t)
75 {
76
77 t->t_funcs->tf_bell(t->t_softc);
78 }
79
80 static inline void
81 teken_funcs_cursor(teken_t *t)
82 {
83
84 teken_assert(t->t_cursor.tp_row < t->t_winsize.tp_row);
85 teken_assert(t->t_cursor.tp_col < t->t_winsize.tp_col);
86
87 t->t_funcs->tf_cursor(t->t_softc, &t->t_cursor);
88 }
89
90 static inline void
91 teken_funcs_putchar(teken_t *t, const teken_pos_t *p, teken_char_t c,
92 const teken_attr_t *a)
93 {
94
95 teken_assert(p->tp_row < t->t_winsize.tp_row);
96 teken_assert(p->tp_col < t->t_winsize.tp_col);
97
98 t->t_funcs->tf_putchar(t->t_softc, p, c, a);
99 }
100
101 static inline void
102 teken_funcs_fill(teken_t *t, const teken_rect_t *r,
103 const teken_char_t c, const teken_attr_t *a)
104 {
105
106 teken_assert(r->tr_end.tp_row > r->tr_begin.tp_row);
107 teken_assert(r->tr_end.tp_row <= t->t_winsize.tp_row);
108 teken_assert(r->tr_end.tp_col > r->tr_begin.tp_col);
109 teken_assert(r->tr_end.tp_col <= t->t_winsize.tp_col);
110
111 t->t_funcs->tf_fill(t->t_softc, r, c, a);
112 }
113
114 static inline void
115 teken_funcs_copy(teken_t *t, const teken_rect_t *r, const teken_pos_t *p)
116 {
117
118 teken_assert(r->tr_end.tp_row > r->tr_begin.tp_row);
119 teken_assert(r->tr_end.tp_row <= t->t_winsize.tp_row);
120 teken_assert(r->tr_end.tp_col > r->tr_begin.tp_col);
121 teken_assert(r->tr_end.tp_col <= t->t_winsize.tp_col);
122 teken_assert(p->tp_row + (r->tr_end.tp_row - r->tr_begin.tp_row) <= t->t_winsize.tp_row);
123 teken_assert(p->tp_col + (r->tr_end.tp_col - r->tr_begin.tp_col) <= t->t_winsize.tp_col);
124
125 t->t_funcs->tf_copy(t->t_softc, r, p);
126 }
127
128 static inline void
129 teken_funcs_param(teken_t *t, int cmd, unsigned int value)
130 {
131
132 t->t_funcs->tf_param(t->t_softc, cmd, value);
133 }
134
135 static inline void
136 teken_funcs_respond(teken_t *t, const void *buf, size_t len)
137 {
138
139 t->t_funcs->tf_respond(t->t_softc, buf, len);
140 }
141
142 #include "teken_subr.h"
143 #include "teken_subr_compat.h"
144
145 /*
146 * Programming interface.
147 */
148
149 void
150 teken_init(teken_t *t, const teken_funcs_t *tf, void *softc)
151 {
152 teken_pos_t tp = { .tp_row = 24, .tp_col = 80 };
153
154 t->t_funcs = tf;
155 t->t_softc = softc;
156
157 t->t_nextstate = teken_state_init;
158 t->t_stateflags = 0;
159 t->t_utf8_left = 0;
160
161 t->t_defattr.ta_format = 0;
162 t->t_defattr.ta_fgcolor = TC_WHITE;
163 t->t_defattr.ta_bgcolor = TC_BLACK;
164 teken_subr_do_reset(t);
165
166 teken_set_winsize(t, &tp);
167 }
168
169 static void
170 teken_input_char(teken_t *t, teken_char_t c)
171 {
172
173 /*
174 * There is no support for DCS and OSC. Just discard strings
175 * until we receive characters that may indicate string
176 * termination.
177 */
178 if (t->t_stateflags & TS_INSTRING) {
179 switch (c) {
180 case '\x1B':
181 t->t_stateflags &= ~TS_INSTRING;
182 break;
183 case '\a':
184 t->t_stateflags &= ~TS_INSTRING;
185 return;
186 default:
187 return;
188 }
189 }
190
191 switch (c) {
192 case '\0':
193 break;
194 case '\a':
195 teken_subr_bell(t);
196 break;
197 case '\b':
198 teken_subr_backspace(t);
199 break;
200 case '\n':
201 case '\x0B':
202 teken_subr_newline(t);
203 break;
204 case '\x0C':
205 teken_subr_newpage(t);
206 break;
207 case '\x0E':
208 if (t->t_stateflags & TS_CONS25)
209 t->t_nextstate(t, c);
210 else
211 t->t_curscs = 1;
212 break;
213 case '\x0F':
214 if (t->t_stateflags & TS_CONS25)
215 t->t_nextstate(t, c);
216 else
217 t->t_curscs = 0;
218 break;
219 case '\r':
220 teken_subr_carriage_return(t);
221 break;
222 case '\t':
223 teken_subr_horizontal_tab(t);
224 break;
225 default:
226 t->t_nextstate(t, c);
227 break;
228 }
229
230 /* Post-processing assertions. */
231 teken_assert(t->t_cursor.tp_row >= t->t_originreg.ts_begin);
232 teken_assert(t->t_cursor.tp_row < t->t_originreg.ts_end);
233 teken_assert(t->t_cursor.tp_row < t->t_winsize.tp_row);
234 teken_assert(t->t_cursor.tp_col < t->t_winsize.tp_col);
235 teken_assert(t->t_saved_cursor.tp_row < t->t_winsize.tp_row);
236 teken_assert(t->t_saved_cursor.tp_col < t->t_winsize.tp_col);
237 teken_assert(t->t_scrollreg.ts_end <= t->t_winsize.tp_row);
238 teken_assert(t->t_scrollreg.ts_begin < t->t_scrollreg.ts_end);
239 /* Origin region has to be window size or the same as scrollreg. */
240 teken_assert((t->t_originreg.ts_begin == t->t_scrollreg.ts_begin &&
241 t->t_originreg.ts_end == t->t_scrollreg.ts_end) ||
242 (t->t_originreg.ts_begin == 0 &&
243 t->t_originreg.ts_end == t->t_winsize.tp_row));
244 }
245
246 static void
247 teken_input_byte(teken_t *t, unsigned char c)
248 {
249
250 /*
251 * UTF-8 handling.
252 */
253 if ((c & 0x80) == 0x00 || t->t_stateflags & TS_8BIT) {
254 /* One-byte sequence. */
255 t->t_utf8_left = 0;
256 teken_input_char(t, c);
257 } else if ((c & 0xe0) == 0xc0) {
258 /* Two-byte sequence. */
259 t->t_utf8_left = 1;
260 t->t_utf8_partial = c & 0x1f;
261 } else if ((c & 0xf0) == 0xe0) {
262 /* Three-byte sequence. */
263 t->t_utf8_left = 2;
264 t->t_utf8_partial = c & 0x0f;
265 } else if ((c & 0xf8) == 0xf0) {
266 /* Four-byte sequence. */
267 t->t_utf8_left = 3;
268 t->t_utf8_partial = c & 0x07;
269 } else if ((c & 0xc0) == 0x80) {
270 if (t->t_utf8_left == 0)
271 return;
272 t->t_utf8_left--;
273 t->t_utf8_partial = (t->t_utf8_partial << 6) | (c & 0x3f);
274 if (t->t_utf8_left == 0) {
275 teken_printf("Got UTF-8 char %x\n", t->t_utf8_partial);
276 teken_input_char(t, t->t_utf8_partial);
277 }
278 }
279 }
280
281 void
282 teken_input(teken_t *t, const void *buf, size_t len)
283 {
284 const char *c = buf;
285
286 while (len-- > 0)
287 teken_input_byte(t, *c++);
288 }
289
290 const teken_pos_t *
291 teken_get_cursor(teken_t *t)
292 {
293
294 return (&t->t_cursor);
295 }
296
297 void
298 teken_set_cursor(teken_t *t, const teken_pos_t *p)
299 {
300
301 /* XXX: bounds checking with originreg! */
302 teken_assert(p->tp_row < t->t_winsize.tp_row);
303 teken_assert(p->tp_col < t->t_winsize.tp_col);
304
305 t->t_cursor = *p;
306 }
307
308 const teken_attr_t *
309 teken_get_curattr(teken_t *t)
310 {
311
312 return (&t->t_curattr);
313 }
314
315 void
316 teken_set_curattr(teken_t *t, const teken_attr_t *a)
317 {
318
319 t->t_curattr = *a;
320 }
321
322 const teken_attr_t *
323 teken_get_defattr(teken_t *t)
324 {
325
326 return (&t->t_defattr);
327 }
328
329 void
330 teken_set_defattr(teken_t *t, const teken_attr_t *a)
331 {
332
333 t->t_curattr = t->t_saved_curattr = t->t_defattr = *a;
334 }
335
336 const teken_pos_t *
337 teken_get_winsize(teken_t *t)
338 {
339
340 return (&t->t_winsize);
341 }
342
343 static void
344 teken_trim_cursor_pos(teken_t *t, const teken_pos_t *new)
345 {
346 const teken_pos_t *cur;
347
348 cur = &t->t_winsize;
349
350 if (cur->tp_row < new->tp_row || cur->tp_col < new->tp_col)
351 return;
352 if (t->t_cursor.tp_row >= new->tp_row)
353 t->t_cursor.tp_row = new->tp_row - 1;
354 if (t->t_cursor.tp_col >= new->tp_col)
355 t->t_cursor.tp_col = new->tp_col - 1;
356 }
357
358 void
359 teken_set_winsize(teken_t *t, const teken_pos_t *p)
360 {
361
362 teken_trim_cursor_pos(t, p);
363 t->t_winsize = *p;
364 teken_subr_do_reset(t);
365 }
366
367 void
368 teken_set_winsize_noreset(teken_t *t, const teken_pos_t *p)
369 {
370
371 teken_trim_cursor_pos(t, p);
372 t->t_winsize = *p;
373 teken_subr_do_resize(t);
374 }
375
376 void
377 teken_set_8bit(teken_t *t)
378 {
379
380 t->t_stateflags |= TS_8BIT;
381 }
382
383 void
384 teken_set_cons25(teken_t *t)
385 {
386
387 t->t_stateflags |= TS_CONS25;
388 }
389
390 /*
391 * State machine.
392 */
393
394 static void
395 teken_state_switch(teken_t *t, teken_state_t *s)
396 {
397
398 t->t_nextstate = s;
399 t->t_curnum = 0;
400 t->t_stateflags |= TS_FIRSTDIGIT;
401 }
402
403 static int
404 teken_state_numbers(teken_t *t, teken_char_t c)
405 {
406
407 teken_assert(t->t_curnum < T_NUMSIZE);
408
409 if (c >= '' && c <= '9') {
410 if (t->t_stateflags & TS_FIRSTDIGIT) {
411 /* First digit. */
412 t->t_stateflags &= ~TS_FIRSTDIGIT;
413 t->t_nums[t->t_curnum] = c - '';
414 } else if (t->t_nums[t->t_curnum] < UINT_MAX / 100) {
415 /*
416 * There is no need to continue parsing input
417 * once the value exceeds the size of the
418 * terminal. It would only allow for integer
419 * overflows when performing arithmetic on the
420 * cursor position.
421 *
422 * Ignore any further digits if the value is
423 * already UINT_MAX / 100.
424 */
425 t->t_nums[t->t_curnum] =
426 t->t_nums[t->t_curnum] * 10 + c - '';
427 }
428 return (1);
429 } else if (c == ';') {
430 if (t->t_stateflags & TS_FIRSTDIGIT)
431 t->t_nums[t->t_curnum] = 0;
432
433 /* Only allow a limited set of arguments. */
434 if (++t->t_curnum == T_NUMSIZE) {
435 teken_state_switch(t, teken_state_init);
436 return (1);
437 }
438
439 t->t_stateflags |= TS_FIRSTDIGIT;
440 return (1);
441 } else {
442 if (t->t_stateflags & TS_FIRSTDIGIT && t->t_curnum > 0) {
443 /* Finish off the last empty argument. */
444 t->t_nums[t->t_curnum] = 0;
445 t->t_curnum++;
446 } else if ((t->t_stateflags & TS_FIRSTDIGIT) == 0) {
447 /* Also count the last argument. */
448 t->t_curnum++;
449 }
450 }
451
452 return (0);
453 }
454
455 #define k TC_BLACK
456 #define b TC_BLUE
457 #define y TC_BROWN
458 #define c TC_CYAN
459 #define g TC_GREEN
460 #define m TC_MAGENTA
461 #define r TC_RED
462 #define w TC_WHITE
463 #define K (TC_BLACK | TC_LIGHT)
464 #define B (TC_BLUE | TC_LIGHT)
465 #define Y (TC_BROWN | TC_LIGHT)
466 #define C (TC_CYAN | TC_LIGHT)
467 #define G (TC_GREEN | TC_LIGHT)
468 #define M (TC_MAGENTA | TC_LIGHT)
469 #define R (TC_RED | TC_LIGHT)
470 #define W (TC_WHITE | TC_LIGHT)
471
472 /**
473 * The xterm-256 color map has steps of 0x28 (in the range 0-0xff), except
474 * for the first step which is 0x5f. Scale to the range 0-6 by dividing
475 * by 0x28 and rounding down. The range of 0-5 cannot represent the
476 * larger first step.
477 *
478 * This table is generated by the follow rules:
479 * - if all components are equal, the result is black for (0, 0, 0) and
480 * (2, 2, 2), else white; otherwise:
481 * - subtract the smallest component from all components
482 * - if this gives only one nonzero component, then that is the color
483 * - else if one component is 2 or more larger than the other nonzero one,
484 * then that component gives the color
485 * - else there are 2 nonzero components. The color is that of a small
486 * equal mixture of these components (cyan, yellow or magenta). E.g.,
487 * (0, 5, 6) (Turquoise2) is a much purer cyan than (0, 2, 3)
488 * (DeepSkyBlue4), but we map both to cyan since we can't represent
489 * delicate shades of either blue or cyan and blue would be worse.
490 * Here it is important that components of 1 never occur. Blue would
491 * be twice as large as green in (0, 1, 2).
492 */
493 static const teken_color_t teken_256to8tab[] = {
494 /* xterm normal colors: */
495 k, r, g, y, b, m, c, w,
496
497 /* xterm bright colors: */
498 k, r, g, y, b, m, c, w,
499
500 /* Red0 submap. */
501 k, b, b, b, b, b,
502 g, c, c, b, b, b,
503 g, c, c, c, b, b,
504 g, g, c, c, c, b,
505 g, g, g, c, c, c,
506 g, g, g, g, c, c,
507
508 /* Red2 submap. */
509 r, m, m, b, b, b,
510 y, k, b, b, b, b,
511 y, g, c, c, b, b,
512 g, g, c, c, c, b,
513 g, g, g, c, c, c,
514 g, g, g, g, c, c,
515
516 /* Red3 submap. */
517 r, m, m, m, b, b,
518 y, r, m, m, b, b,
519 y, y, w, b, b, b,
520 y, y, g, c, c, b,
521 g, g, g, c, c, c,
522 g, g, g, g, c, c,
523
524 /* Red4 submap. */
525 r, r, m, m, m, b,
526 r, r, m, m, m, b,
527 y, y, r, m, m, b,
528 y, y, y, w, b, b,
529 y, y, y, g, c, c,
530 g, g, g, g, c, c,
531
532 /* Red5 submap. */
533 r, r, r, m, m, m,
534 r, r, r, m, m, m,
535 r, r, r, m, m, m,
536 y, y, y, r, m, m,
537 y, y, y, y, w, b,
538 y, y, y, y, g, c,
539
540 /* Red6 submap. */
541 r, r, r, r, m, m,
542 r, r, r, r, m, m,
543 r, r, r, r, m, m,
544 r, r, r, r, m, m,
545 y, y, y, y, r, m,
546 y, y, y, y, y, w,
547
548 /* Grey submap. */
549 k, k, k, k, k, k,
550 k, k, k, k, k, k,
551 w, w, w, w, w, w,
552 w, w, w, w, w, w,
553 };
554
555 /*
556 * This table is generated from the previous one by setting TC_LIGHT for
557 * entries whose luminosity in the xterm256 color map is 60% or larger.
558 * Thus the previous table is currently not really needed. It will be
559 * used for different fine tuning of the tables.
560 */
561 static const teken_color_t teken_256to16tab[] = {
562 /* xterm normal colors: */
563 k, r, g, y, b, m, c, w,
564
565 /* xterm bright colors: */
566 K, R, G, Y, B, M, C, W,
567
568 /* Red0 submap. */
569 k, b, b, b, b, b,
570 g, c, c, b, b, b,
571 g, c, c, c, b, b,
572 g, g, c, c, c, b,
573 g, g, g, c, c, c,
574 g, g, g, g, c, c,
575
576 /* Red2 submap. */
577 r, m, m, b, b, b,
578 y, K, b, b, B, B,
579 y, g, c, c, B, B,
580 g, g, c, c, C, B,
581 g, G, G, C, C, C,
582 g, G, G, G, C, C,
583
584 /* Red3 submap. */
585 r, m, m, m, b, b,
586 y, r, m, m, B, B,
587 y, y, w, B, B, B,
588 y, y, G, C, C, B,
589 g, G, G, C, C, C,
590 g, G, G, G, C, C,
591
592 /* Red4 submap. */
593 r, r, m, m, m, b,
594 r, r, m, m, M, B,
595 y, y, R, M, M, B,
596 y, y, Y, W, B, B,
597 y, Y, Y, G, C, C,
598 g, G, G, G, C, C,
599
600 /* Red5 submap. */
601 r, r, r, m, m, m,
602 r, R, R, M, M, M,
603 r, R, R, M, M, M,
604 y, Y, Y, R, M, M,
605 y, Y, Y, Y, W, B,
606 y, Y, Y, Y, G, C,
607
608 /* Red6 submap. */
609 r, r, r, r, m, m,
610 r, R, R, R, M, M,
611 r, R, R, R, M, M,
612 r, R, R, R, M, M,
613 y, Y, Y, Y, R, M,
614 y, Y, Y, Y, Y, W,
615
616 /* Grey submap. */
617 k, k, k, k, k, k,
618 K, K, K, K, K, K,
619 w, w, w, w, w, w,
620 W, W, W, W, W, W,
621 };
622
623 #undef k
624 #undef b
625 #undef y
626 #undef c
627 #undef g
628 #undef m
629 #undef r
630 #undef w
631 #undef K
632 #undef B
633 #undef Y
634 #undef C
635 #undef G
636 #undef M
637 #undef R
638 #undef W
639
640 teken_color_t
641 teken_256to8(teken_color_t c)
642 {
643
644 return (teken_256to8tab[c % 256]);
645 }
646
647 teken_color_t
648 teken_256to16(teken_color_t c)
649 {
650
651 return (teken_256to16tab[c % 256]);
652 }
653
654 static const char * const special_strings_cons25[] = {
655 [TKEY_UP] = "\x1B[A", [TKEY_DOWN] = "\x1B[B",
656 [TKEY_LEFT] = "\x1B[D", [TKEY_RIGHT] = "\x1B[C",
657
658 [TKEY_HOME] = "\x1B[H", [TKEY_END] = "\x1B[F",
659 [TKEY_INSERT] = "\x1B[L", [TKEY_DELETE] = "\x7F",
660 [TKEY_PAGE_UP] = "\x1B[I", [TKEY_PAGE_DOWN] = "\x1B[G",
661
662 [TKEY_F1] = "\x1B[M", [TKEY_F2] = "\x1B[N",
663 [TKEY_F3] = "\x1B[O", [TKEY_F4] = "\x1B[P",
664 [TKEY_F5] = "\x1B[Q", [TKEY_F6] = "\x1B[R",
665 [TKEY_F7] = "\x1B[S", [TKEY_F8] = "\x1B[T",
666 [TKEY_F9] = "\x1B[U", [TKEY_F10] = "\x1B[V",
667 [TKEY_F11] = "\x1B[W", [TKEY_F12] = "\x1B[X",
668 };
669
670 static const char * const special_strings_ckeys[] = {
671 [TKEY_UP] = "\x1BOA", [TKEY_DOWN] = "\x1BOB",
672 [TKEY_LEFT] = "\x1BOD", [TKEY_RIGHT] = "\x1BOC",
673
674 [TKEY_HOME] = "\x1BOH", [TKEY_END] = "\x1BOF",
675 };
676
677 static const char * const special_strings_normal[] = {
678 [TKEY_UP] = "\x1B[A", [TKEY_DOWN] = "\x1B[B",
679 [TKEY_LEFT] = "\x1B[D", [TKEY_RIGHT] = "\x1B[C",
680
681 [TKEY_HOME] = "\x1B[H", [TKEY_END] = "\x1B[F",
682 [TKEY_INSERT] = "\x1B[2~", [TKEY_DELETE] = "\x1B[3~",
683 [TKEY_PAGE_UP] = "\x1B[5~", [TKEY_PAGE_DOWN] = "\x1B[6~",
684
685 [TKEY_F1] = "\x1BOP", [TKEY_F2] = "\x1BOQ",
686 [TKEY_F3] = "\x1BOR", [TKEY_F4] = "\x1BOS",
687 [TKEY_F5] = "\x1B[15~", [TKEY_F6] = "\x1B[17~",
688 [TKEY_F7] = "\x1B[18~", [TKEY_F8] = "\x1B[19~",
689 [TKEY_F9] = "\x1B[20~", [TKEY_F10] = "\x1B[21~",
690 [TKEY_F11] = "\x1B[23~", [TKEY_F12] = "\x1B[24~",
691 };
692
693 const char *
694 teken_get_sequence(teken_t *t, unsigned int k)
695 {
696
697 /* Cons25 mode. */
698 if (t->t_stateflags & TS_CONS25 &&
699 k < sizeof special_strings_cons25 / sizeof(char *))
700 return (special_strings_cons25[k]);
701
702 /* Cursor keys mode. */
703 if (t->t_stateflags & TS_CURSORKEYS &&
704 k < sizeof special_strings_ckeys / sizeof(char *))
705 return (special_strings_ckeys[k]);
706
707 /* Default xterm sequences. */
708 if (k < sizeof special_strings_normal / sizeof(char *))
709 return (special_strings_normal[k]);
710
711 return (NULL);
712 }
713
714 #include "teken_state.h"
Cache object: b6d60827336d30daf17a288a45b10477
|