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" 715