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