]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/teken/teken.c
- Switch releng/11.3 to -RELEASE.
[FreeBSD/FreeBSD.git] / 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$
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 >= '0' && 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 - '0';
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 - '0';
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"