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