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