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