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