1 /* $OpenBSD: input.c,v 1.22 2009/11/04 22:43:11 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 21 #include <stdint.h> 22 #include <stdlib.h> 23 #include <string.h> 24 25 #include "tmux.h" 26 27 #define INPUT_C0CONTROL(ch) (ch <= 0x1f) 28 #define INPUT_INTERMEDIATE(ch) (ch == 0xa0 || (ch >= 0x20 && ch <= 0x2f)) 29 #define INPUT_PARAMETER(ch) (ch >= 0x30 && ch <= 0x3f) 30 #define INPUT_UPPERCASE(ch) (ch >= 0x40 && ch <= 0x5f) 31 #define INPUT_LOWERCASE(ch) (ch >= 0x60 && ch <= 0x7e) 32 #define INPUT_DELETE(ch) (ch == 0x7f) 33 #define INPUT_C1CONTROL(ch) (ch >= 0x80 && ch <= 0x9f) 34 #define INPUT_G1DISPLAYABLE(ch) (ch >= 0xa1 && ch <= 0xfe) 35 #define INPUT_SPECIAL(ch) (ch == 0xff) 36 37 int input_get_argument(struct input_ctx *, u_int, uint16_t *, uint16_t); 38 void input_new_argument(struct input_ctx *); 39 int input_add_argument(struct input_ctx *, u_char); 40 41 void input_start_string(struct input_ctx *, int); 42 void input_abort_string(struct input_ctx *); 43 int input_add_string(struct input_ctx *, u_char); 44 char *input_get_string(struct input_ctx *); 45 46 void input_state(struct input_ctx *, void *); 47 48 void input_state_first(u_char, struct input_ctx *); 49 void input_state_escape(u_char, struct input_ctx *); 50 void input_state_intermediate(u_char, struct input_ctx *); 51 void input_state_sequence_first(u_char, struct input_ctx *); 52 void input_state_sequence_next(u_char, struct input_ctx *); 53 void input_state_sequence_intermediate(u_char, struct input_ctx *); 54 void input_state_string_next(u_char, struct input_ctx *); 55 void input_state_string_escape(u_char, struct input_ctx *); 56 void input_state_utf8(u_char, struct input_ctx *); 57 58 void input_handle_character(u_char, struct input_ctx *); 59 void input_handle_c0_control(u_char, struct input_ctx *); 60 void input_handle_c1_control(u_char, struct input_ctx *); 61 void input_handle_private_two(u_char, struct input_ctx *); 62 void input_handle_standard_two(u_char, struct input_ctx *); 63 void input_handle_sequence(u_char, struct input_ctx *); 64 65 void input_handle_sequence_cuu(struct input_ctx *); 66 void input_handle_sequence_cud(struct input_ctx *); 67 void input_handle_sequence_cuf(struct input_ctx *); 68 void input_handle_sequence_cub(struct input_ctx *); 69 void input_handle_sequence_dch(struct input_ctx *); 70 void input_handle_sequence_cbt(struct input_ctx *); 71 void input_handle_sequence_da(struct input_ctx *); 72 void input_handle_sequence_dl(struct input_ctx *); 73 void input_handle_sequence_ich(struct input_ctx *); 74 void input_handle_sequence_il(struct input_ctx *); 75 void input_handle_sequence_vpa(struct input_ctx *); 76 void input_handle_sequence_hpa(struct input_ctx *); 77 void input_handle_sequence_cup(struct input_ctx *); 78 void input_handle_sequence_cup(struct input_ctx *); 79 void input_handle_sequence_tbc(struct input_ctx *); 80 void input_handle_sequence_ed(struct input_ctx *); 81 void input_handle_sequence_el(struct input_ctx *); 82 void input_handle_sequence_sm(struct input_ctx *); 83 void input_handle_sequence_rm(struct input_ctx *); 84 void input_handle_sequence_decstbm(struct input_ctx *); 85 void input_handle_sequence_sgr(struct input_ctx *); 86 void input_handle_sequence_dsr(struct input_ctx *); 87 88 int input_sequence_cmp(const void *, const void *); 89 90 struct input_sequence_entry { 91 u_char ch; 92 void (*fn)(struct input_ctx *); 93 }; 94 const struct input_sequence_entry input_sequence_table[] = { 95 { '@', input_handle_sequence_ich }, 96 { 'A', input_handle_sequence_cuu }, 97 { 'B', input_handle_sequence_cud }, 98 { 'C', input_handle_sequence_cuf }, 99 { 'D', input_handle_sequence_cub }, 100 { 'G', input_handle_sequence_hpa }, 101 { 'H', input_handle_sequence_cup }, 102 { 'J', input_handle_sequence_ed }, 103 { 'K', input_handle_sequence_el }, 104 { 'L', input_handle_sequence_il }, 105 { 'M', input_handle_sequence_dl }, 106 { 'P', input_handle_sequence_dch }, 107 { 'Z', input_handle_sequence_cbt }, 108 { 'c', input_handle_sequence_da }, 109 { 'd', input_handle_sequence_vpa }, 110 { 'f', input_handle_sequence_cup }, 111 { 'g', input_handle_sequence_tbc }, 112 { 'h', input_handle_sequence_sm }, 113 { 'l', input_handle_sequence_rm }, 114 { 'm', input_handle_sequence_sgr }, 115 { 'n', input_handle_sequence_dsr }, 116 { 'r', input_handle_sequence_decstbm }, 117 }; 118 119 int 120 input_sequence_cmp(const void *a, const void *b) 121 { 122 int ai = ((const struct input_sequence_entry *) a)->ch; 123 int bi = ((const struct input_sequence_entry *) b)->ch; 124 125 return (ai - bi); 126 } 127 128 void 129 input_new_argument(struct input_ctx *ictx) 130 { 131 struct input_arg *arg; 132 133 ARRAY_EXPAND(&ictx->args, 1); 134 135 arg = &ARRAY_LAST(&ictx->args); 136 arg->used = 0; 137 } 138 139 int 140 input_add_argument(struct input_ctx *ictx, u_char ch) 141 { 142 struct input_arg *arg; 143 144 if (ARRAY_LENGTH(&ictx->args) == 0) 145 return (0); 146 147 arg = &ARRAY_LAST(&ictx->args); 148 if (arg->used > (sizeof arg->data) - 1) 149 return (-1); 150 arg->data[arg->used++] = ch; 151 152 return (0); 153 } 154 155 int 156 input_get_argument(struct input_ctx *ictx, u_int i, uint16_t *n, uint16_t d) 157 { 158 struct input_arg *arg; 159 const char *errstr; 160 161 *n = d; 162 if (i >= ARRAY_LENGTH(&ictx->args)) 163 return (0); 164 165 arg = &ARRAY_ITEM(&ictx->args, i); 166 if (*arg->data == '\0') 167 return (0); 168 169 *n = strtonum(arg->data, 0, UINT16_MAX, &errstr); 170 if (errstr != NULL) 171 return (-1); 172 return (0); 173 } 174 175 void 176 input_start_string(struct input_ctx *ictx, int type) 177 { 178 ictx->string_type = type; 179 ictx->string_len = 0; 180 } 181 182 void 183 input_abort_string(struct input_ctx *ictx) 184 { 185 if (ictx->string_buf != NULL) 186 xfree(ictx->string_buf); 187 ictx->string_buf = NULL; 188 } 189 190 int 191 input_add_string(struct input_ctx *ictx, u_char ch) 192 { 193 ictx->string_buf = xrealloc(ictx->string_buf, 1, ictx->string_len + 1); 194 ictx->string_buf[ictx->string_len++] = ch; 195 196 if (ictx->string_len >= MAXSTRINGLEN) { 197 input_abort_string(ictx); 198 return (1); 199 } 200 201 return (0); 202 } 203 204 char * 205 input_get_string(struct input_ctx *ictx) 206 { 207 char *s; 208 209 if (ictx->string_buf == NULL || input_add_string(ictx, '\0') != 0) 210 return (xstrdup("")); 211 212 s = ictx->string_buf; 213 ictx->string_buf = NULL; 214 return (s); 215 } 216 217 void 218 input_state(struct input_ctx *ictx, void *state) 219 { 220 ictx->state = state; 221 } 222 223 void 224 input_init(struct window_pane *wp) 225 { 226 struct input_ctx *ictx = &wp->ictx; 227 228 ARRAY_INIT(&ictx->args); 229 230 ictx->string_len = 0; 231 ictx->string_buf = NULL; 232 233 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell); 234 235 memcpy(&ictx->saved_cell, &grid_default_cell, sizeof ictx->saved_cell); 236 ictx->saved_cx = 0; 237 ictx->saved_cy = 0; 238 239 input_state(ictx, input_state_first); 240 241 ictx->was = 0; 242 } 243 244 void 245 input_free(struct window_pane *wp) 246 { 247 if (wp->ictx.string_buf != NULL) 248 xfree(wp->ictx.string_buf); 249 250 ARRAY_FREE(&wp->ictx.args); 251 } 252 253 void 254 input_parse(struct window_pane *wp) 255 { 256 struct input_ctx *ictx = &wp->ictx; 257 u_char ch; 258 259 if (EVBUFFER_LENGTH(wp->event->input) == ictx->was) 260 return; 261 wp->window->flags |= WINDOW_ACTIVITY; 262 263 ictx->buf = EVBUFFER_DATA(wp->event->input); 264 ictx->len = EVBUFFER_LENGTH(wp->event->input); 265 ictx->off = 0; 266 267 ictx->wp = wp; 268 269 if (wp->mode == NULL) 270 screen_write_start(&ictx->ctx, wp, &wp->base); 271 else 272 screen_write_start(&ictx->ctx, NULL, &wp->base); 273 274 while (ictx->off < ictx->len) { 275 ch = ictx->buf[ictx->off++]; 276 ictx->state(ch, ictx); 277 } 278 279 screen_write_stop(&ictx->ctx); 280 281 evbuffer_drain(wp->event->input, ictx->len); 282 ictx->was = EVBUFFER_LENGTH(wp->event->input); 283 } 284 285 void 286 input_state_first(u_char ch, struct input_ctx *ictx) 287 { 288 ictx->intermediate = '\0'; 289 290 if (INPUT_C0CONTROL(ch)) { 291 if (ch == 0x1b) 292 input_state(ictx, input_state_escape); 293 else 294 input_handle_c0_control(ch, ictx); 295 return; 296 } 297 298 #if 0 299 if (INPUT_C1CONTROL(ch)) { 300 ch -= 0x40; 301 if (ch == '[') 302 input_state(ictx, input_state_sequence_first); 303 else if (ch == ']') { 304 input_start_string(ictx, STRING_SYSTEM); 305 input_state(ictx, input_state_string_next); 306 } else if (ch == '_') { 307 input_start_string(ictx, STRING_APPLICATION); 308 input_state(ictx, input_state_string_next); 309 } else 310 input_handle_c1_control(ch, ictx); 311 return; 312 } 313 #endif 314 315 if (INPUT_DELETE(ch)) 316 return; 317 318 input_handle_character(ch, ictx); 319 } 320 321 void 322 input_state_escape(u_char ch, struct input_ctx *ictx) 323 { 324 /* Treat C1 control and G1 displayable as 7-bit equivalent. */ 325 if (INPUT_C1CONTROL(ch) || INPUT_G1DISPLAYABLE(ch)) 326 ch &= 0x7f; 327 328 if (INPUT_C0CONTROL(ch)) { 329 input_handle_c0_control(ch, ictx); 330 return; 331 } 332 333 if (INPUT_INTERMEDIATE(ch)) { 334 log_debug2(":: in1 %zu: %hhu (%c)", ictx->off, ch, ch); 335 ictx->intermediate = ch; 336 input_state(ictx, input_state_intermediate); 337 return; 338 } 339 340 if (INPUT_PARAMETER(ch)) { 341 input_state(ictx, input_state_first); 342 input_handle_private_two(ch, ictx); 343 return; 344 } 345 346 if (INPUT_UPPERCASE(ch)) { 347 if (ch == '[') 348 input_state(ictx, input_state_sequence_first); 349 else if (ch == ']') { 350 input_start_string(ictx, STRING_SYSTEM); 351 input_state(ictx, input_state_string_next); 352 } else if (ch == '_') { 353 input_start_string(ictx, STRING_APPLICATION); 354 input_state(ictx, input_state_string_next); 355 } else { 356 input_state(ictx, input_state_first); 357 input_handle_c1_control(ch, ictx); 358 } 359 return; 360 } 361 362 if (INPUT_LOWERCASE(ch)) { 363 input_state(ictx, input_state_first); 364 input_handle_standard_two(ch, ictx); 365 return; 366 } 367 368 input_state(ictx, input_state_first); 369 } 370 371 void 372 input_state_intermediate(u_char ch, struct input_ctx *ictx) 373 { 374 if (INPUT_INTERMEDIATE(ch)) { 375 /* Multiple intermediates currently ignored. */ 376 log_debug2(":: in2 %zu: %hhu (%c)", ictx->off, ch, ch); 377 return; 378 } 379 380 if (INPUT_PARAMETER(ch)) { 381 input_state(ictx, input_state_first); 382 input_handle_private_two(ch, ictx); 383 return; 384 } 385 386 if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) { 387 input_state(ictx, input_state_first); 388 input_handle_standard_two(ch, ictx); 389 return; 390 } 391 392 input_state(ictx, input_state_first); 393 } 394 395 void 396 input_state_sequence_first(u_char ch, struct input_ctx *ictx) 397 { 398 ictx->private = '\0'; 399 ARRAY_CLEAR(&ictx->args); 400 401 /* Most C0 control are accepted within CSI. */ 402 if (INPUT_C0CONTROL(ch)) { 403 if (ch == 0x1b) { /* ESC */ 404 /* Abort sequence and begin with new. */ 405 input_state(ictx, input_state_escape); 406 return; 407 } else if (ch == 0x18 || ch == 0x1a) { /* CAN and SUB */ 408 /* Abort sequence. */ 409 input_state(ictx, input_state_first); 410 return; 411 } 412 413 /* Handle C0 immediately. */ 414 input_handle_c0_control(ch, ictx); 415 416 /* 417 * Just come back to this state, in case the next character 418 * is the start of a private sequence. 419 */ 420 return; 421 } 422 423 input_state(ictx, input_state_sequence_next); 424 425 /* Private sequence: always the first character. */ 426 if (ch >= 0x3c && ch <= 0x3f) { 427 ictx->private = ch; 428 return; 429 } 430 431 /* Pass character on directly. */ 432 input_state_sequence_next(ch, ictx); 433 } 434 435 void 436 input_state_sequence_next(u_char ch, struct input_ctx *ictx) 437 { 438 if (INPUT_INTERMEDIATE(ch)) { 439 if (input_add_argument(ictx, '\0') != 0) 440 input_state(ictx, input_state_first); 441 else { 442 log_debug2(":: si1 %zu: %hhu (%c)", ictx->off, ch, ch); 443 input_state(ictx, input_state_sequence_intermediate); 444 } 445 return; 446 } 447 448 if (INPUT_PARAMETER(ch)) { 449 if (ARRAY_EMPTY(&ictx->args)) 450 input_new_argument(ictx); 451 452 if (ch == ';') { 453 if (input_add_argument(ictx, '\0') != 0) 454 input_state(ictx, input_state_first); 455 else 456 input_new_argument(ictx); 457 } else if (input_add_argument(ictx, ch) != 0) 458 input_state(ictx, input_state_first); 459 return; 460 } 461 462 if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) { 463 if (input_add_argument(ictx, '\0') != 0) 464 input_state(ictx, input_state_first); 465 else { 466 input_state(ictx, input_state_first); 467 input_handle_sequence(ch, ictx); 468 } 469 return; 470 } 471 472 /* Most C0 control are accepted within CSI. */ 473 if (INPUT_C0CONTROL(ch)) { 474 if (ch == 0x1b) { /* ESC */ 475 /* Abort sequence and begin with new. */ 476 input_state(ictx, input_state_escape); 477 return; 478 } else if (ch == 0x18 || ch == 0x1a) { /* CAN and SUB */ 479 /* Abort sequence. */ 480 input_state(ictx, input_state_first); 481 return; 482 } 483 484 /* Handle C0 immediately. */ 485 input_handle_c0_control(ch, ictx); 486 487 return; 488 } 489 490 input_state(ictx, input_state_first); 491 } 492 493 void 494 input_state_sequence_intermediate(u_char ch, struct input_ctx *ictx) 495 { 496 if (INPUT_INTERMEDIATE(ch)) { 497 log_debug2(":: si2 %zu: %hhu (%c)", ictx->off, ch, ch); 498 return; 499 } 500 501 if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) { 502 input_state(ictx, input_state_first); 503 input_handle_sequence(ch, ictx); 504 return; 505 } 506 507 input_state(ictx, input_state_first); 508 } 509 510 void 511 input_state_string_next(u_char ch, struct input_ctx *ictx) 512 { 513 if (ch == 0x1b) { 514 input_state(ictx, input_state_string_escape); 515 return; 516 } 517 if (ch == 0x07) { 518 input_state_string_escape(ch, ictx); 519 return; 520 } 521 522 if (ch >= 0x20) { 523 if (input_add_string(ictx, ch) != 0) 524 input_state(ictx, input_state_first); 525 return; 526 } 527 } 528 529 void 530 input_state_string_escape(u_char ch, struct input_ctx *ictx) 531 { 532 char *s; 533 534 if (ch == '\007' || ch == '\\') { 535 input_state(ictx, input_state_first); 536 switch (ictx->string_type) { 537 case STRING_SYSTEM: 538 if (ch != '\007') 539 return; 540 s = input_get_string(ictx); 541 if ((s[0] != '0' && s[0] != '2') || s[1] != ';') { 542 xfree(s); 543 return; 544 } 545 screen_set_title(ictx->ctx.s, s + 2); 546 server_status_window(ictx->wp->window); 547 xfree(s); 548 break; 549 case STRING_APPLICATION: 550 if (ch != '\\') 551 return; 552 s = input_get_string(ictx); 553 screen_set_title(ictx->ctx.s, s); 554 server_status_window(ictx->wp->window); 555 xfree(s); 556 break; 557 case STRING_NAME: 558 if (ch != '\\') 559 return; 560 xfree(ictx->wp->window->name); 561 ictx->wp->window->name = input_get_string(ictx); 562 server_status_window(ictx->wp->window); 563 break; 564 } 565 return; 566 } 567 568 input_state(ictx, input_state_string_next); 569 input_state_string_next(ch, ictx); 570 } 571 572 void 573 input_state_utf8(u_char ch, struct input_ctx *ictx) 574 { 575 log_debug2("-- utf8 next: %zu: %hhu (%c)", ictx->off, ch, ch); 576 577 if (utf8_append(&ictx->utf8data, ch)) 578 return; /* more to come */ 579 input_state(ictx, input_state_first); 580 581 ictx->cell.flags |= GRID_FLAG_UTF8; 582 screen_write_cell(&ictx->ctx, &ictx->cell, &ictx->utf8data); 583 ictx->cell.flags &= ~GRID_FLAG_UTF8; 584 } 585 586 void 587 input_handle_character(u_char ch, struct input_ctx *ictx) 588 { 589 struct window_pane *wp = ictx->wp; 590 591 if (ch > 0x7f && options_get_number(&wp->window->options, "utf8")) { 592 if (utf8_open(&ictx->utf8data, ch)) { 593 log_debug2("-- utf8 size %zu: %zu: %hhu (%c)", 594 ictx->utf8data.size, ictx->off, ch, ch); 595 input_state(ictx, input_state_utf8); 596 return; 597 } 598 } 599 log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch); 600 601 ictx->cell.data = ch; 602 screen_write_cell(&ictx->ctx, &ictx->cell, NULL); 603 } 604 605 void 606 input_handle_c0_control(u_char ch, struct input_ctx *ictx) 607 { 608 struct screen *s = ictx->ctx.s; 609 610 log_debug2("-- c0 %zu: %hhu", ictx->off, ch); 611 612 switch (ch) { 613 case '\0': /* NUL */ 614 break; 615 case '\n': /* LF */ 616 screen_write_linefeed(&ictx->ctx, 0); 617 break; 618 case '\r': /* CR */ 619 screen_write_carriagereturn(&ictx->ctx); 620 break; 621 case '\007': /* BELL */ 622 ictx->wp->window->flags |= WINDOW_BELL; 623 break; 624 case '\010': /* BS */ 625 screen_write_backspace(&ictx->ctx); 626 break; 627 case '\011': /* TAB */ 628 /* Don't tab beyond the end of the line. */ 629 if (s->cx >= screen_size_x(s) - 1) 630 break; 631 632 /* Find the next tab point, or use the last column if none. */ 633 do { 634 s->cx++; 635 if (bit_test(s->tabs, s->cx)) 636 break; 637 } while (s->cx < screen_size_x(s) - 1); 638 break; 639 case '\013': /* VT */ 640 screen_write_linefeed(&ictx->ctx, 0); 641 break; 642 case '\016': /* SO */ 643 ictx->cell.attr |= GRID_ATTR_CHARSET; 644 break; 645 case '\017': /* SI */ 646 ictx->cell.attr &= ~GRID_ATTR_CHARSET; 647 break; 648 default: 649 log_debug("unknown c0: %hhu", ch); 650 break; 651 } 652 } 653 654 void 655 input_handle_c1_control(u_char ch, struct input_ctx *ictx) 656 { 657 struct screen *s = ictx->ctx.s; 658 659 log_debug2("-- c1 %zu: %hhu (%c)", ictx->off, ch, ch); 660 661 switch (ch) { 662 case 'D': /* IND */ 663 screen_write_linefeed(&ictx->ctx, 0); 664 break; 665 case 'E': /* NEL */ 666 screen_write_carriagereturn(&ictx->ctx); 667 screen_write_linefeed(&ictx->ctx, 0); 668 break; 669 case 'H': /* HTS */ 670 if (s->cx < screen_size_x(s)) 671 bit_set(s->tabs, s->cx); 672 break; 673 case 'M': /* RI */ 674 screen_write_reverseindex(&ictx->ctx); 675 break; 676 default: 677 log_debug("unknown c1: %hhu", ch); 678 break; 679 } 680 } 681 682 void 683 input_handle_private_two(u_char ch, struct input_ctx *ictx) 684 { 685 struct screen *s = ictx->ctx.s; 686 687 log_debug2( 688 "-- p2 %zu: %hhu (%c) %hhu", ictx->off, ch, ch, ictx->intermediate); 689 690 switch (ch) { 691 case '0': /* SCS */ 692 /* 693 * Not really supported, but fake it up enough for those that 694 * use it to switch character sets (by redefining G0 to 695 * graphics set, rather than switching to G1). 696 */ 697 switch (ictx->intermediate) { 698 case '(': /* G0 */ 699 ictx->cell.attr |= GRID_ATTR_CHARSET; 700 break; 701 } 702 break; 703 case '=': /* DECKPAM */ 704 if (ictx->intermediate != '\0') 705 break; 706 screen_write_kkeypadmode(&ictx->ctx, 1); 707 log_debug("kkeypad on (application mode)"); 708 break; 709 case '>': /* DECKPNM */ 710 if (ictx->intermediate != '\0') 711 break; 712 screen_write_kkeypadmode(&ictx->ctx, 0); 713 log_debug("kkeypad off (number mode)"); 714 break; 715 case '7': /* DECSC */ 716 if (ictx->intermediate != '\0') 717 break; 718 memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell); 719 ictx->saved_cx = s->cx; 720 ictx->saved_cy = s->cy; 721 break; 722 case '8': 723 switch (ictx->intermediate) { 724 case '\0': /* DECRC */ 725 memcpy( 726 &ictx->cell, &ictx->saved_cell, sizeof ictx->cell); 727 screen_write_cursormove( 728 &ictx->ctx, ictx->saved_cx, ictx->saved_cy); 729 break; 730 case '#': /* DECALN */ 731 screen_write_alignmenttest(&ictx->ctx); 732 break; 733 } 734 break; 735 default: 736 log_debug("unknown p2: %hhu", ch); 737 break; 738 } 739 } 740 741 void 742 input_handle_standard_two(u_char ch, struct input_ctx *ictx) 743 { 744 log_debug2( 745 "-- s2 %zu: %hhu (%c) %hhu", ictx->off, ch, ch, ictx->intermediate); 746 747 switch (ch) { 748 case 'B': /* SCS */ 749 /* 750 * Not really supported, but fake it up enough for those that 751 * use it to switch character sets (by redefining G0 to 752 * graphics set, rather than switching to G1). 753 */ 754 switch (ictx->intermediate) { 755 case '(': /* G0 */ 756 ictx->cell.attr &= ~GRID_ATTR_CHARSET; 757 break; 758 } 759 break; 760 case 'c': /* RIS */ 761 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell); 762 763 memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell); 764 ictx->saved_cx = 0; 765 ictx->saved_cy = 0; 766 767 screen_reset_tabs(ictx->ctx.s); 768 769 screen_write_scrollregion( 770 &ictx->ctx, 0, screen_size_y(ictx->ctx.s) - 1); 771 772 screen_write_insertmode(&ictx->ctx, 0); 773 screen_write_kcursormode(&ictx->ctx, 0); 774 screen_write_kkeypadmode(&ictx->ctx, 0); 775 screen_write_mousemode(&ictx->ctx, 0); 776 777 screen_write_clearscreen(&ictx->ctx); 778 screen_write_cursormove(&ictx->ctx, 0, 0); 779 break; 780 case 'k': 781 input_start_string(ictx, STRING_NAME); 782 input_state(ictx, input_state_string_next); 783 break; 784 default: 785 log_debug("unknown s2: %hhu", ch); 786 break; 787 } 788 } 789 790 void 791 input_handle_sequence(u_char ch, struct input_ctx *ictx) 792 { 793 struct input_sequence_entry *entry, find; 794 struct screen *s = ictx->ctx.s; 795 u_int i; 796 struct input_arg *iarg; 797 798 log_debug2("-- sq %zu: %hhu (%c): %u [sx=%u, sy=%u, cx=%u, cy=%u, " 799 "ru=%u, rl=%u]", ictx->off, ch, ch, ARRAY_LENGTH(&ictx->args), 800 screen_size_x(s), screen_size_y(s), s->cx, s->cy, s->rupper, 801 s->rlower); 802 for (i = 0; i < ARRAY_LENGTH(&ictx->args); i++) { 803 iarg = &ARRAY_ITEM(&ictx->args, i); 804 if (*iarg->data != '\0') 805 log_debug2(" ++ %u: %s", i, iarg->data); 806 } 807 808 find.ch = ch; 809 entry = bsearch(&find, 810 input_sequence_table, nitems(input_sequence_table), 811 sizeof input_sequence_table[0], input_sequence_cmp); 812 if (entry != NULL) 813 entry->fn(ictx); 814 else 815 log_debug("unknown sq: %c (%hhu %hhu)", ch, ch, ictx->private); 816 } 817 818 void 819 input_handle_sequence_cuu(struct input_ctx *ictx) 820 { 821 uint16_t n; 822 823 if (ictx->private != '\0') 824 return; 825 826 if (ARRAY_LENGTH(&ictx->args) > 1) 827 return; 828 if (input_get_argument(ictx, 0, &n, 1) != 0) 829 return; 830 if (n == 0) 831 n = 1; 832 833 screen_write_cursorup(&ictx->ctx, n); 834 } 835 836 void 837 input_handle_sequence_cud(struct input_ctx *ictx) 838 { 839 uint16_t n; 840 841 if (ictx->private != '\0') 842 return; 843 844 if (ARRAY_LENGTH(&ictx->args) > 1) 845 return; 846 if (input_get_argument(ictx, 0, &n, 1) != 0) 847 return; 848 if (n == 0) 849 n = 1; 850 851 screen_write_cursordown(&ictx->ctx, n); 852 } 853 854 void 855 input_handle_sequence_cuf(struct input_ctx *ictx) 856 { 857 uint16_t n; 858 859 if (ictx->private != '\0') 860 return; 861 862 if (ARRAY_LENGTH(&ictx->args) > 1) 863 return; 864 if (input_get_argument(ictx, 0, &n, 1) != 0) 865 return; 866 if (n == 0) 867 n = 1; 868 869 screen_write_cursorright(&ictx->ctx, n); 870 } 871 872 void 873 input_handle_sequence_cub(struct input_ctx *ictx) 874 { 875 uint16_t n; 876 877 if (ictx->private != '\0') 878 return; 879 880 if (ARRAY_LENGTH(&ictx->args) > 1) 881 return; 882 if (input_get_argument(ictx, 0, &n, 1) != 0) 883 return; 884 if (n == 0) 885 n = 1; 886 887 screen_write_cursorleft(&ictx->ctx, n); 888 } 889 890 void 891 input_handle_sequence_dch(struct input_ctx *ictx) 892 { 893 uint16_t n; 894 895 if (ictx->private != '\0') 896 return; 897 898 if (ARRAY_LENGTH(&ictx->args) > 1) 899 return; 900 if (input_get_argument(ictx, 0, &n, 1) != 0) 901 return; 902 if (n == 0) 903 n = 1; 904 905 screen_write_deletecharacter(&ictx->ctx, n); 906 } 907 908 void 909 input_handle_sequence_cbt(struct input_ctx *ictx) 910 { 911 struct screen *s = ictx->ctx.s; 912 uint16_t n; 913 914 if (ictx->private != '\0') 915 return; 916 917 if (ARRAY_LENGTH(&ictx->args) > 1) 918 return; 919 if (input_get_argument(ictx, 0, &n, 1) != 0) 920 return; 921 if (n == 0) 922 n = 1; 923 924 /* Find the previous tab point, n times. */ 925 while (s->cx > 0 && n-- > 0) { 926 do 927 s->cx--; 928 while (s->cx > 0 && !bit_test(s->tabs, s->cx)); 929 } 930 } 931 932 void 933 input_handle_sequence_da(struct input_ctx *ictx) 934 { 935 struct window_pane *wp = ictx->wp; 936 uint16_t n; 937 938 if (ictx->private != '\0') 939 return; 940 941 if (ARRAY_LENGTH(&ictx->args) > 1) 942 return; 943 if (input_get_argument(ictx, 0, &n, 0) != 0) 944 return; 945 if (n != 0) 946 return; 947 948 bufferevent_write(wp->event, "\033[?1;2c", (sizeof "\033[?1;2c") - 1); 949 } 950 951 void 952 input_handle_sequence_dl(struct input_ctx *ictx) 953 { 954 uint16_t n; 955 956 if (ictx->private != '\0') 957 return; 958 959 if (ARRAY_LENGTH(&ictx->args) > 1) 960 return; 961 if (input_get_argument(ictx, 0, &n, 1) != 0) 962 return; 963 if (n == 0) 964 n = 1; 965 966 screen_write_deleteline(&ictx->ctx, n); 967 } 968 969 void 970 input_handle_sequence_ich(struct input_ctx *ictx) 971 { 972 uint16_t n; 973 974 if (ictx->private != '\0') 975 return; 976 977 if (ARRAY_LENGTH(&ictx->args) > 1) 978 return; 979 if (input_get_argument(ictx, 0, &n, 1) != 0) 980 return; 981 if (n == 0) 982 n = 1; 983 984 screen_write_insertcharacter(&ictx->ctx, n); 985 } 986 987 void 988 input_handle_sequence_il(struct input_ctx *ictx) 989 { 990 uint16_t n; 991 992 if (ictx->private != '\0') 993 return; 994 995 if (ARRAY_LENGTH(&ictx->args) > 1) 996 return; 997 if (input_get_argument(ictx, 0, &n, 1) != 0) 998 return; 999 if (n == 0) 1000 n = 1; 1001 1002 screen_write_insertline(&ictx->ctx, n); 1003 } 1004 1005 void 1006 input_handle_sequence_vpa(struct input_ctx *ictx) 1007 { 1008 struct screen *s = ictx->ctx.s; 1009 uint16_t n; 1010 1011 if (ictx->private != '\0') 1012 return; 1013 1014 if (ARRAY_LENGTH(&ictx->args) > 1) 1015 return; 1016 if (input_get_argument(ictx, 0, &n, 1) != 0) 1017 return; 1018 if (n == 0) 1019 n = 1; 1020 1021 screen_write_cursormove(&ictx->ctx, s->cx, n - 1); 1022 } 1023 1024 void 1025 input_handle_sequence_hpa(struct input_ctx *ictx) 1026 { 1027 struct screen *s = ictx->ctx.s; 1028 uint16_t n; 1029 1030 if (ictx->private != '\0') 1031 return; 1032 1033 if (ARRAY_LENGTH(&ictx->args) > 1) 1034 return; 1035 if (input_get_argument(ictx, 0, &n, 1) != 0) 1036 return; 1037 if (n == 0) 1038 n = 1; 1039 1040 screen_write_cursormove(&ictx->ctx, n - 1, s->cy); 1041 } 1042 1043 void 1044 input_handle_sequence_cup(struct input_ctx *ictx) 1045 { 1046 uint16_t n, m; 1047 1048 if (ictx->private != '\0') 1049 return; 1050 1051 if (ARRAY_LENGTH(&ictx->args) > 2) 1052 return; 1053 if (input_get_argument(ictx, 0, &n, 1) != 0) 1054 return; 1055 if (input_get_argument(ictx, 1, &m, 1) != 0) 1056 return; 1057 if (n == 0) 1058 n = 1; 1059 if (m == 0) 1060 m = 1; 1061 1062 screen_write_cursormove(&ictx->ctx, m - 1, n - 1); 1063 } 1064 1065 void 1066 input_handle_sequence_tbc(struct input_ctx *ictx) 1067 { 1068 struct screen *s = ictx->ctx.s; 1069 uint16_t n; 1070 1071 if (ictx->private != '\0') 1072 return; 1073 1074 if (ARRAY_LENGTH(&ictx->args) > 1) 1075 return; 1076 if (input_get_argument(ictx, 0, &n, 1) != 0) 1077 return; 1078 1079 switch (n) { 1080 case 0: 1081 if (s->cx < screen_size_x(s)) 1082 bit_clear(s->tabs, s->cx); 1083 break; 1084 case 3: 1085 bit_nclear(s->tabs, 0, screen_size_x(s) - 1); 1086 break; 1087 } 1088 } 1089 1090 void 1091 input_handle_sequence_ed(struct input_ctx *ictx) 1092 { 1093 uint16_t n; 1094 1095 if (ictx->private != '\0') 1096 return; 1097 1098 if (ARRAY_LENGTH(&ictx->args) > 1) 1099 return; 1100 if (input_get_argument(ictx, 0, &n, 0) != 0) 1101 return; 1102 if (n > 2) 1103 return; 1104 1105 switch (n) { 1106 case 0: 1107 screen_write_clearendofscreen(&ictx->ctx); 1108 break; 1109 case 1: 1110 screen_write_clearstartofscreen(&ictx->ctx); 1111 break; 1112 case 2: 1113 screen_write_clearscreen(&ictx->ctx); 1114 break; 1115 } 1116 } 1117 1118 void 1119 input_handle_sequence_el(struct input_ctx *ictx) 1120 { 1121 uint16_t n; 1122 1123 if (ictx->private != '\0') 1124 return; 1125 1126 if (ARRAY_LENGTH(&ictx->args) > 1) 1127 return; 1128 if (input_get_argument(ictx, 0, &n, 0) != 0) 1129 return; 1130 if (n > 2) 1131 return; 1132 1133 switch (n) { 1134 case 0: 1135 screen_write_clearendofline(&ictx->ctx); 1136 break; 1137 case 1: 1138 screen_write_clearstartofline(&ictx->ctx); 1139 break; 1140 case 2: 1141 screen_write_clearline(&ictx->ctx); 1142 break; 1143 } 1144 } 1145 1146 void 1147 input_handle_sequence_sm(struct input_ctx *ictx) 1148 { 1149 struct window_pane *wp = ictx->wp; 1150 struct screen *s = &wp->base; 1151 u_int sx, sy; 1152 uint16_t n; 1153 1154 if (ARRAY_LENGTH(&ictx->args) > 1) 1155 return; 1156 if (input_get_argument(ictx, 0, &n, 0) != 0) 1157 return; 1158 1159 if (ictx->private == '?') { 1160 switch (n) { 1161 case 1: /* GATM */ 1162 screen_write_kcursormode(&ictx->ctx, 1); 1163 log_debug("kcursor on"); 1164 break; 1165 case 3: /* DECCOLM */ 1166 screen_write_cursormove(&ictx->ctx, 0, 0); 1167 screen_write_clearscreen(&ictx->ctx); 1168 break; 1169 case 25: /* TCEM */ 1170 screen_write_cursormode(&ictx->ctx, 1); 1171 log_debug("cursor on"); 1172 break; 1173 case 1000: 1174 screen_write_mousemode(&ictx->ctx, 1); 1175 log_debug("mouse on"); 1176 break; 1177 case 1049: 1178 if (wp->saved_grid != NULL) 1179 break; 1180 sx = screen_size_x(s); 1181 sy = screen_size_y(s); 1182 1183 /* 1184 * Enter alternative screen mode. A copy of the visible 1185 * screen is saved and the history is not updated 1186 */ 1187 1188 wp->saved_grid = grid_create(sx, sy, 0); 1189 grid_duplicate_lines( 1190 wp->saved_grid, 0, s->grid, screen_hsize(s), sy); 1191 wp->saved_cx = s->cx; 1192 wp->saved_cy = s->cy; 1193 memcpy(&wp->saved_cell, 1194 &ictx->cell, sizeof wp->saved_cell); 1195 1196 grid_view_clear(s->grid, 0, 0, sx, sy); 1197 1198 wp->base.grid->flags &= ~GRID_HISTORY; 1199 1200 wp->flags |= PANE_REDRAW; 1201 break; 1202 default: 1203 log_debug("unknown SM [%hhu]: %u", ictx->private, n); 1204 break; 1205 } 1206 } else { 1207 switch (n) { 1208 case 4: /* IRM */ 1209 screen_write_insertmode(&ictx->ctx, 1); 1210 log_debug("insert on"); 1211 break; 1212 case 34: 1213 /* Cursor high visibility not supported. */ 1214 break; 1215 default: 1216 log_debug("unknown SM [%hhu]: %u", ictx->private, n); 1217 break; 1218 } 1219 } 1220 } 1221 1222 void 1223 input_handle_sequence_rm(struct input_ctx *ictx) 1224 { 1225 struct window_pane *wp = ictx->wp; 1226 struct screen *s = &wp->base; 1227 u_int sx, sy; 1228 uint16_t n; 1229 1230 if (ARRAY_LENGTH(&ictx->args) > 1) 1231 return; 1232 if (input_get_argument(ictx, 0, &n, 0) != 0) 1233 return; 1234 1235 if (ictx->private == '?') { 1236 switch (n) { 1237 case 1: /* GATM */ 1238 screen_write_kcursormode(&ictx->ctx, 0); 1239 log_debug("kcursor off"); 1240 break; 1241 case 3: /* DECCOLM */ 1242 screen_write_cursormove(&ictx->ctx, 0, 0); 1243 screen_write_clearscreen(&ictx->ctx); 1244 break; 1245 case 25: /* TCEM */ 1246 screen_write_cursormode(&ictx->ctx, 0); 1247 log_debug("cursor off"); 1248 break; 1249 case 1000: 1250 screen_write_mousemode(&ictx->ctx, 0); 1251 log_debug("mouse off"); 1252 break; 1253 case 1049: 1254 if (wp->saved_grid == NULL) 1255 break; 1256 sx = screen_size_x(s); 1257 sy = screen_size_y(s); 1258 1259 /* 1260 * Exit alternative screen mode and restore the copied 1261 * grid. 1262 */ 1263 1264 /* 1265 * If the current size is bigger, temporarily resize 1266 * to the old size before copying back. 1267 */ 1268 if (sy > wp->saved_grid->sy) 1269 screen_resize(s, sx, wp->saved_grid->sy); 1270 1271 /* Restore the grid, cursor position and cell. */ 1272 grid_duplicate_lines( 1273 s->grid, screen_hsize(s), wp->saved_grid, 0, sy); 1274 s->cx = wp->saved_cx; 1275 if (s->cx > screen_size_x(s) - 1) 1276 s->cx = screen_size_x(s) - 1; 1277 s->cy = wp->saved_cy; 1278 if (s->cy > screen_size_y(s) - 1) 1279 s->cy = screen_size_y(s) - 1; 1280 memcpy(&ictx->cell, &wp->saved_cell, sizeof ictx->cell); 1281 1282 /* 1283 * Turn history back on (so resize can use it) and then 1284 * resize back to the current size. 1285 */ 1286 wp->base.grid->flags |= GRID_HISTORY; 1287 if (sy > wp->saved_grid->sy) 1288 screen_resize(s, sx, sy); 1289 1290 grid_destroy(wp->saved_grid); 1291 wp->saved_grid = NULL; 1292 1293 wp->flags |= PANE_REDRAW; 1294 break; 1295 default: 1296 log_debug("unknown RM [%hhu]: %u", ictx->private, n); 1297 break; 1298 } 1299 } else if (ictx->private == '\0') { 1300 switch (n) { 1301 case 4: /* IRM */ 1302 screen_write_insertmode(&ictx->ctx, 0); 1303 log_debug("insert off"); 1304 break; 1305 case 34: 1306 /* Cursor high visibility not supported. */ 1307 break; 1308 default: 1309 log_debug("unknown RM [%hhu]: %u", ictx->private, n); 1310 break; 1311 } 1312 } 1313 } 1314 1315 void 1316 input_handle_sequence_dsr(struct input_ctx *ictx) 1317 { 1318 struct window_pane *wp = ictx->wp; 1319 struct screen *s = ictx->ctx.s; 1320 uint16_t n; 1321 char reply[32]; 1322 1323 if (ARRAY_LENGTH(&ictx->args) > 1) 1324 return; 1325 if (input_get_argument(ictx, 0, &n, 0) != 0) 1326 return; 1327 1328 if (ictx->private == '\0') { 1329 switch (n) { 1330 case 6: /* cursor position */ 1331 xsnprintf(reply, sizeof reply, 1332 "\033[%u;%uR", s->cy + 1, s->cx + 1); 1333 log_debug("cursor request, reply: %s", reply); 1334 bufferevent_write(wp->event, reply, strlen(reply)); 1335 break; 1336 } 1337 } 1338 } 1339 1340 void 1341 input_handle_sequence_decstbm(struct input_ctx *ictx) 1342 { 1343 struct screen *s = ictx->ctx.s; 1344 uint16_t n, m; 1345 1346 if (ictx->private != '\0') 1347 return; 1348 1349 if (ARRAY_LENGTH(&ictx->args) > 2) 1350 return; 1351 if (input_get_argument(ictx, 0, &n, 0) != 0) 1352 return; 1353 if (input_get_argument(ictx, 1, &m, 0) != 0) 1354 return; 1355 if (n == 0) 1356 n = 1; 1357 if (m == 0) 1358 m = screen_size_y(s); 1359 1360 screen_write_scrollregion(&ictx->ctx, n - 1, m - 1); 1361 } 1362 1363 void 1364 input_handle_sequence_sgr(struct input_ctx *ictx) 1365 { 1366 struct grid_cell *gc = &ictx->cell; 1367 u_int i; 1368 uint16_t m, o; 1369 u_char attr; 1370 1371 if (ARRAY_LENGTH(&ictx->args) == 0) { 1372 attr = gc->attr; 1373 memcpy(gc, &grid_default_cell, sizeof *gc); 1374 gc->attr |= (attr & GRID_ATTR_CHARSET); 1375 return; 1376 } 1377 1378 for (i = 0; i < ARRAY_LENGTH(&ictx->args); i++) { 1379 if (input_get_argument(ictx, i, &m, 0) != 0) 1380 return; 1381 1382 if (m == 38 || m == 48) { 1383 i++; 1384 if (input_get_argument(ictx, i, &o, 0) != 0) 1385 return; 1386 if (o != 5) 1387 continue; 1388 1389 i++; 1390 if (input_get_argument(ictx, i, &o, 0) != 0) 1391 return; 1392 if (m == 38) { 1393 gc->flags |= GRID_FLAG_FG256; 1394 gc->fg = o; 1395 } else if (m == 48) { 1396 gc->flags |= GRID_FLAG_BG256; 1397 gc->bg = o; 1398 } 1399 continue; 1400 } 1401 1402 switch (m) { 1403 case 0: 1404 case 10: 1405 attr = gc->attr; 1406 memcpy(gc, &grid_default_cell, sizeof *gc); 1407 gc->attr |= (attr & GRID_ATTR_CHARSET); 1408 break; 1409 case 1: 1410 gc->attr |= GRID_ATTR_BRIGHT; 1411 break; 1412 case 2: 1413 gc->attr |= GRID_ATTR_DIM; 1414 break; 1415 case 3: 1416 gc->attr |= GRID_ATTR_ITALICS; 1417 break; 1418 case 4: 1419 gc->attr |= GRID_ATTR_UNDERSCORE; 1420 break; 1421 case 5: 1422 gc->attr |= GRID_ATTR_BLINK; 1423 break; 1424 case 7: 1425 gc->attr |= GRID_ATTR_REVERSE; 1426 break; 1427 case 8: 1428 gc->attr |= GRID_ATTR_HIDDEN; 1429 break; 1430 case 22: 1431 gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM); 1432 break; 1433 case 23: 1434 gc->attr &= ~GRID_ATTR_ITALICS; 1435 break; 1436 case 24: 1437 gc->attr &= ~GRID_ATTR_UNDERSCORE; 1438 break; 1439 case 25: 1440 gc->attr &= ~GRID_ATTR_BLINK; 1441 break; 1442 case 27: 1443 gc->attr &= ~GRID_ATTR_REVERSE; 1444 break; 1445 case 30: 1446 case 31: 1447 case 32: 1448 case 33: 1449 case 34: 1450 case 35: 1451 case 36: 1452 case 37: 1453 gc->flags &= ~GRID_FLAG_FG256; 1454 gc->fg = m - 30; 1455 break; 1456 case 39: 1457 gc->flags &= ~GRID_FLAG_FG256; 1458 gc->fg = 8; 1459 break; 1460 case 40: 1461 case 41: 1462 case 42: 1463 case 43: 1464 case 44: 1465 case 45: 1466 case 46: 1467 case 47: 1468 gc->flags &= ~GRID_FLAG_BG256; 1469 gc->bg = m - 40; 1470 break; 1471 case 49: 1472 gc->flags &= ~GRID_FLAG_BG256; 1473 gc->bg = 8; 1474 break; 1475 case 90: 1476 case 91: 1477 case 92: 1478 case 93: 1479 case 94: 1480 case 95: 1481 case 96: 1482 case 97: 1483 gc->flags |= GRID_FLAG_FG256; 1484 gc->fg = m - 82; 1485 break; 1486 case 100: 1487 case 101: 1488 case 102: 1489 case 103: 1490 case 104: 1491 case 105: 1492 case 106: 1493 case 107: 1494 gc->flags |= GRID_FLAG_BG256; 1495 gc->bg = m - 92; 1496 break; 1497 } 1498 } 1499 } 1500