mouse-select-pane has to redraw the borders now too.
[tmux-openbsd.git] / input.c
blobcfa42406f92f8298c514ad9127db6174f06c2449
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <string.h>
25 #include "tmux.h"
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)
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);
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 *);
46 void input_state(struct input_ctx *, void *);
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 *);
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 *);
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 *);
88 int input_sequence_cmp(const void *, const void *);
90 struct input_sequence_entry {
91 u_char ch;
92 void (*fn)(struct input_ctx *);
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 },
120 input_sequence_cmp(const void *a, const void *b)
122 int ai = ((const struct input_sequence_entry *) a)->ch;
123 int bi = ((const struct input_sequence_entry *) b)->ch;
125 return (ai - bi);
128 void
129 input_new_argument(struct input_ctx *ictx)
131 struct input_arg *arg;
133 ARRAY_EXPAND(&ictx->args, 1);
135 arg = &ARRAY_LAST(&ictx->args);
136 arg->used = 0;
140 input_add_argument(struct input_ctx *ictx, u_char ch)
142 struct input_arg *arg;
144 if (ARRAY_LENGTH(&ictx->args) == 0)
145 return (0);
147 arg = &ARRAY_LAST(&ictx->args);
148 if (arg->used > (sizeof arg->data) - 1)
149 return (-1);
150 arg->data[arg->used++] = ch;
152 return (0);
156 input_get_argument(struct input_ctx *ictx, u_int i, uint16_t *n, uint16_t d)
158 struct input_arg *arg;
159 const char *errstr;
161 *n = d;
162 if (i >= ARRAY_LENGTH(&ictx->args))
163 return (0);
165 arg = &ARRAY_ITEM(&ictx->args, i);
166 if (*arg->data == '\0')
167 return (0);
169 *n = strtonum(arg->data, 0, UINT16_MAX, &errstr);
170 if (errstr != NULL)
171 return (-1);
172 return (0);
175 void
176 input_start_string(struct input_ctx *ictx, int type)
178 ictx->string_type = type;
179 ictx->string_len = 0;
182 void
183 input_abort_string(struct input_ctx *ictx)
185 if (ictx->string_buf != NULL)
186 xfree(ictx->string_buf);
187 ictx->string_buf = NULL;
191 input_add_string(struct input_ctx *ictx, u_char ch)
193 ictx->string_buf = xrealloc(ictx->string_buf, 1, ictx->string_len + 1);
194 ictx->string_buf[ictx->string_len++] = ch;
196 if (ictx->string_len >= MAXSTRINGLEN) {
197 input_abort_string(ictx);
198 return (1);
201 return (0);
204 char *
205 input_get_string(struct input_ctx *ictx)
207 char *s;
209 if (ictx->string_buf == NULL || input_add_string(ictx, '\0') != 0)
210 return (xstrdup(""));
212 s = ictx->string_buf;
213 ictx->string_buf = NULL;
214 return (s);
217 void
218 input_state(struct input_ctx *ictx, void *state)
220 ictx->state = state;
223 void
224 input_init(struct window_pane *wp)
226 struct input_ctx *ictx = &wp->ictx;
228 ARRAY_INIT(&ictx->args);
230 ictx->string_len = 0;
231 ictx->string_buf = NULL;
233 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
235 memcpy(&ictx->saved_cell, &grid_default_cell, sizeof ictx->saved_cell);
236 ictx->saved_cx = 0;
237 ictx->saved_cy = 0;
239 input_state(ictx, input_state_first);
241 ictx->was = 0;
244 void
245 input_free(struct window_pane *wp)
247 if (wp->ictx.string_buf != NULL)
248 xfree(wp->ictx.string_buf);
250 ARRAY_FREE(&wp->ictx.args);
253 void
254 input_parse(struct window_pane *wp)
256 struct input_ctx *ictx = &wp->ictx;
257 u_char ch;
259 if (EVBUFFER_LENGTH(wp->event->input) == ictx->was)
260 return;
261 wp->window->flags |= WINDOW_ACTIVITY;
263 ictx->buf = EVBUFFER_DATA(wp->event->input);
264 ictx->len = EVBUFFER_LENGTH(wp->event->input);
265 ictx->off = 0;
267 ictx->wp = wp;
269 /* If there is a mode set, don't want to update the screen. */
270 if (wp->mode == NULL)
271 screen_write_start(&ictx->ctx, wp, &wp->base);
272 else
273 screen_write_start(&ictx->ctx, NULL, &wp->base);
275 while (ictx->off < ictx->len) {
276 ch = ictx->buf[ictx->off++];
277 ictx->state(ch, ictx);
280 screen_write_stop(&ictx->ctx);
282 evbuffer_drain(wp->event->input, ictx->len);
283 ictx->was = EVBUFFER_LENGTH(wp->event->input);
286 void
287 input_state_first(u_char ch, struct input_ctx *ictx)
289 ictx->intermediate = '\0';
291 if (INPUT_C0CONTROL(ch)) {
292 if (ch == 0x1b)
293 input_state(ictx, input_state_escape);
294 else
295 input_handle_c0_control(ch, ictx);
296 return;
299 #if 0
300 if (INPUT_C1CONTROL(ch)) {
301 ch -= 0x40;
302 if (ch == '[')
303 input_state(ictx, input_state_sequence_first);
304 else if (ch == ']') {
305 input_start_string(ictx, STRING_SYSTEM);
306 input_state(ictx, input_state_string_next);
307 } else if (ch == '_') {
308 input_start_string(ictx, STRING_APPLICATION);
309 input_state(ictx, input_state_string_next);
310 } else
311 input_handle_c1_control(ch, ictx);
312 return;
314 #endif
316 if (INPUT_DELETE(ch))
317 return;
319 input_handle_character(ch, ictx);
322 void
323 input_state_escape(u_char ch, struct input_ctx *ictx)
325 /* Treat C1 control and G1 displayable as 7-bit equivalent. */
326 if (INPUT_C1CONTROL(ch) || INPUT_G1DISPLAYABLE(ch))
327 ch &= 0x7f;
329 if (INPUT_C0CONTROL(ch)) {
330 input_handle_c0_control(ch, ictx);
331 return;
334 if (INPUT_INTERMEDIATE(ch)) {
335 log_debug2(":: in1 %zu: %hhu (%c)", ictx->off, ch, ch);
336 ictx->intermediate = ch;
337 input_state(ictx, input_state_intermediate);
338 return;
341 if (INPUT_PARAMETER(ch)) {
342 input_state(ictx, input_state_first);
343 input_handle_private_two(ch, ictx);
344 return;
347 if (INPUT_UPPERCASE(ch)) {
348 if (ch == '[')
349 input_state(ictx, input_state_sequence_first);
350 else if (ch == ']') {
351 input_start_string(ictx, STRING_SYSTEM);
352 input_state(ictx, input_state_string_next);
353 } else if (ch == '_') {
354 input_start_string(ictx, STRING_APPLICATION);
355 input_state(ictx, input_state_string_next);
356 } else {
357 input_state(ictx, input_state_first);
358 input_handle_c1_control(ch, ictx);
360 return;
363 if (INPUT_LOWERCASE(ch)) {
364 input_state(ictx, input_state_first);
365 input_handle_standard_two(ch, ictx);
366 return;
369 input_state(ictx, input_state_first);
372 void
373 input_state_intermediate(u_char ch, struct input_ctx *ictx)
375 if (INPUT_INTERMEDIATE(ch)) {
376 /* Multiple intermediates currently ignored. */
377 log_debug2(":: in2 %zu: %hhu (%c)", ictx->off, ch, ch);
378 return;
381 if (INPUT_PARAMETER(ch)) {
382 input_state(ictx, input_state_first);
383 input_handle_private_two(ch, ictx);
384 return;
387 if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) {
388 input_state(ictx, input_state_first);
389 input_handle_standard_two(ch, ictx);
390 return;
393 input_state(ictx, input_state_first);
396 void
397 input_state_sequence_first(u_char ch, struct input_ctx *ictx)
399 ictx->private = '\0';
400 ARRAY_CLEAR(&ictx->args);
402 /* Most C0 control are accepted within CSI. */
403 if (INPUT_C0CONTROL(ch)) {
404 if (ch == 0x1b) { /* ESC */
405 /* Abort sequence and begin with new. */
406 input_state(ictx, input_state_escape);
407 return;
408 } else if (ch == 0x18 || ch == 0x1a) { /* CAN and SUB */
409 /* Abort sequence. */
410 input_state(ictx, input_state_first);
411 return;
414 /* Handle C0 immediately. */
415 input_handle_c0_control(ch, ictx);
418 * Just come back to this state, in case the next character
419 * is the start of a private sequence.
421 return;
424 input_state(ictx, input_state_sequence_next);
426 /* Private sequence: always the first character. */
427 if (ch >= 0x3c && ch <= 0x3f) {
428 ictx->private = ch;
429 return;
432 /* Pass character on directly. */
433 input_state_sequence_next(ch, ictx);
436 void
437 input_state_sequence_next(u_char ch, struct input_ctx *ictx)
439 if (INPUT_INTERMEDIATE(ch)) {
440 if (input_add_argument(ictx, '\0') != 0)
441 input_state(ictx, input_state_first);
442 else {
443 log_debug2(":: si1 %zu: %hhu (%c)", ictx->off, ch, ch);
444 input_state(ictx, input_state_sequence_intermediate);
446 return;
449 if (INPUT_PARAMETER(ch)) {
450 if (ARRAY_EMPTY(&ictx->args))
451 input_new_argument(ictx);
453 if (ch == ';') {
454 if (input_add_argument(ictx, '\0') != 0)
455 input_state(ictx, input_state_first);
456 else
457 input_new_argument(ictx);
458 } else if (input_add_argument(ictx, ch) != 0)
459 input_state(ictx, input_state_first);
460 return;
463 if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) {
464 if (input_add_argument(ictx, '\0') != 0)
465 input_state(ictx, input_state_first);
466 else {
467 input_state(ictx, input_state_first);
468 input_handle_sequence(ch, ictx);
470 return;
473 /* Most C0 control are accepted within CSI. */
474 if (INPUT_C0CONTROL(ch)) {
475 if (ch == 0x1b) { /* ESC */
476 /* Abort sequence and begin with new. */
477 input_state(ictx, input_state_escape);
478 return;
479 } else if (ch == 0x18 || ch == 0x1a) { /* CAN and SUB */
480 /* Abort sequence. */
481 input_state(ictx, input_state_first);
482 return;
485 /* Handle C0 immediately. */
486 input_handle_c0_control(ch, ictx);
488 return;
491 input_state(ictx, input_state_first);
494 void
495 input_state_sequence_intermediate(u_char ch, struct input_ctx *ictx)
497 if (INPUT_INTERMEDIATE(ch)) {
498 log_debug2(":: si2 %zu: %hhu (%c)", ictx->off, ch, ch);
499 return;
502 if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) {
503 input_state(ictx, input_state_first);
504 input_handle_sequence(ch, ictx);
505 return;
508 input_state(ictx, input_state_first);
511 void
512 input_state_string_next(u_char ch, struct input_ctx *ictx)
514 if (ch == 0x1b) {
515 input_state(ictx, input_state_string_escape);
516 return;
518 if (ch == 0x07) {
519 input_state_string_escape(ch, ictx);
520 return;
523 if (ch >= 0x20) {
524 if (input_add_string(ictx, ch) != 0)
525 input_state(ictx, input_state_first);
526 return;
530 void
531 input_state_string_escape(u_char ch, struct input_ctx *ictx)
533 char *s;
535 if (ch == '\007' || ch == '\\') {
536 input_state(ictx, input_state_first);
537 switch (ictx->string_type) {
538 case STRING_SYSTEM:
539 if (ch != '\007')
540 return;
541 s = input_get_string(ictx);
542 if ((s[0] != '0' && s[0] != '2') || s[1] != ';') {
543 xfree(s);
544 return;
546 screen_set_title(ictx->ctx.s, s + 2);
547 server_status_window(ictx->wp->window);
548 xfree(s);
549 break;
550 case STRING_APPLICATION:
551 if (ch != '\\')
552 return;
553 s = input_get_string(ictx);
554 screen_set_title(ictx->ctx.s, s);
555 server_status_window(ictx->wp->window);
556 xfree(s);
557 break;
558 case STRING_NAME:
559 if (ch != '\\')
560 return;
561 xfree(ictx->wp->window->name);
562 ictx->wp->window->name = input_get_string(ictx);
563 server_status_window(ictx->wp->window);
564 break;
566 return;
569 input_state(ictx, input_state_string_next);
570 input_state_string_next(ch, ictx);
573 void
574 input_state_utf8(u_char ch, struct input_ctx *ictx)
576 log_debug2("-- utf8 next: %zu: %hhu (%c)", ictx->off, ch, ch);
578 if (utf8_append(&ictx->utf8data, ch))
579 return; /* more to come */
580 input_state(ictx, input_state_first);
582 ictx->cell.flags |= GRID_FLAG_UTF8;
583 screen_write_cell(&ictx->ctx, &ictx->cell, &ictx->utf8data);
584 ictx->cell.flags &= ~GRID_FLAG_UTF8;
587 void
588 input_handle_character(u_char ch, struct input_ctx *ictx)
590 struct window_pane *wp = ictx->wp;
592 if (ch > 0x7f && options_get_number(&wp->window->options, "utf8")) {
593 if (utf8_open(&ictx->utf8data, ch)) {
594 log_debug2("-- utf8 size %zu: %zu: %hhu (%c)",
595 ictx->utf8data.size, ictx->off, ch, ch);
596 input_state(ictx, input_state_utf8);
597 return;
600 log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch);
602 ictx->cell.data = ch;
603 screen_write_cell(&ictx->ctx, &ictx->cell, NULL);
606 void
607 input_handle_c0_control(u_char ch, struct input_ctx *ictx)
609 struct screen *s = ictx->ctx.s;
611 log_debug2("-- c0 %zu: %hhu", ictx->off, ch);
613 switch (ch) {
614 case '\0': /* NUL */
615 break;
616 case '\n': /* LF */
617 screen_write_linefeed(&ictx->ctx, 0);
618 break;
619 case '\r': /* CR */
620 screen_write_carriagereturn(&ictx->ctx);
621 break;
622 case '\007': /* BELL */
623 ictx->wp->window->flags |= WINDOW_BELL;
624 break;
625 case '\010': /* BS */
626 screen_write_backspace(&ictx->ctx);
627 break;
628 case '\011': /* TAB */
629 /* Don't tab beyond the end of the line. */
630 if (s->cx >= screen_size_x(s) - 1)
631 break;
633 /* Find the next tab point, or use the last column if none. */
634 do {
635 s->cx++;
636 if (bit_test(s->tabs, s->cx))
637 break;
638 } while (s->cx < screen_size_x(s) - 1);
639 break;
640 case '\013': /* VT */
641 screen_write_linefeed(&ictx->ctx, 0);
642 break;
643 case '\016': /* SO */
644 ictx->cell.attr |= GRID_ATTR_CHARSET;
645 break;
646 case '\017': /* SI */
647 ictx->cell.attr &= ~GRID_ATTR_CHARSET;
648 break;
649 default:
650 log_debug("unknown c0: %hhu", ch);
651 break;
655 void
656 input_handle_c1_control(u_char ch, struct input_ctx *ictx)
658 struct screen *s = ictx->ctx.s;
660 log_debug2("-- c1 %zu: %hhu (%c)", ictx->off, ch, ch);
662 switch (ch) {
663 case 'D': /* IND */
664 screen_write_linefeed(&ictx->ctx, 0);
665 break;
666 case 'E': /* NEL */
667 screen_write_carriagereturn(&ictx->ctx);
668 screen_write_linefeed(&ictx->ctx, 0);
669 break;
670 case 'H': /* HTS */
671 if (s->cx < screen_size_x(s))
672 bit_set(s->tabs, s->cx);
673 break;
674 case 'M': /* RI */
675 screen_write_reverseindex(&ictx->ctx);
676 break;
677 default:
678 log_debug("unknown c1: %hhu", ch);
679 break;
683 void
684 input_handle_private_two(u_char ch, struct input_ctx *ictx)
686 struct screen *s = ictx->ctx.s;
688 log_debug2(
689 "-- p2 %zu: %hhu (%c) %hhu", ictx->off, ch, ch, ictx->intermediate);
691 switch (ch) {
692 case '0': /* SCS */
694 * Not really supported, but fake it up enough for those that
695 * use it to switch character sets (by redefining G0 to
696 * graphics set, rather than switching to G1).
698 switch (ictx->intermediate) {
699 case '(': /* G0 */
700 ictx->cell.attr |= GRID_ATTR_CHARSET;
701 break;
703 break;
704 case '=': /* DECKPAM */
705 if (ictx->intermediate != '\0')
706 break;
707 screen_write_kkeypadmode(&ictx->ctx, 1);
708 log_debug("kkeypad on (application mode)");
709 break;
710 case '>': /* DECKPNM */
711 if (ictx->intermediate != '\0')
712 break;
713 screen_write_kkeypadmode(&ictx->ctx, 0);
714 log_debug("kkeypad off (number mode)");
715 break;
716 case '7': /* DECSC */
717 if (ictx->intermediate != '\0')
718 break;
719 memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell);
720 ictx->saved_cx = s->cx;
721 ictx->saved_cy = s->cy;
722 break;
723 case '8':
724 switch (ictx->intermediate) {
725 case '\0': /* DECRC */
726 memcpy(
727 &ictx->cell, &ictx->saved_cell, sizeof ictx->cell);
728 screen_write_cursormove(
729 &ictx->ctx, ictx->saved_cx, ictx->saved_cy);
730 break;
731 case '#': /* DECALN */
732 screen_write_alignmenttest(&ictx->ctx);
733 break;
735 break;
736 default:
737 log_debug("unknown p2: %hhu", ch);
738 break;
742 void
743 input_handle_standard_two(u_char ch, struct input_ctx *ictx)
745 log_debug2(
746 "-- s2 %zu: %hhu (%c) %hhu", ictx->off, ch, ch, ictx->intermediate);
748 switch (ch) {
749 case 'B': /* SCS */
751 * Not really supported, but fake it up enough for those that
752 * use it to switch character sets (by redefining G0 to
753 * graphics set, rather than switching to G1).
755 switch (ictx->intermediate) {
756 case '(': /* G0 */
757 ictx->cell.attr &= ~GRID_ATTR_CHARSET;
758 break;
760 break;
761 case 'c': /* RIS */
762 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
764 memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell);
765 ictx->saved_cx = 0;
766 ictx->saved_cy = 0;
768 screen_reset_tabs(ictx->ctx.s);
770 screen_write_scrollregion(
771 &ictx->ctx, 0, screen_size_y(ictx->ctx.s) - 1);
773 screen_write_insertmode(&ictx->ctx, 0);
774 screen_write_kcursormode(&ictx->ctx, 0);
775 screen_write_kkeypadmode(&ictx->ctx, 0);
776 screen_write_mousemode(&ictx->ctx, 0);
778 screen_write_clearscreen(&ictx->ctx);
779 screen_write_cursormove(&ictx->ctx, 0, 0);
780 break;
781 case 'k':
782 input_start_string(ictx, STRING_NAME);
783 input_state(ictx, input_state_string_next);
784 break;
785 default:
786 log_debug("unknown s2: %hhu", ch);
787 break;
791 void
792 input_handle_sequence(u_char ch, struct input_ctx *ictx)
794 struct input_sequence_entry *entry, find;
795 struct screen *s = ictx->ctx.s;
796 u_int i;
797 struct input_arg *iarg;
799 log_debug2("-- sq %zu: %hhu (%c): %u [sx=%u, sy=%u, cx=%u, cy=%u, "
800 "ru=%u, rl=%u]", ictx->off, ch, ch, ARRAY_LENGTH(&ictx->args),
801 screen_size_x(s), screen_size_y(s), s->cx, s->cy, s->rupper,
802 s->rlower);
803 for (i = 0; i < ARRAY_LENGTH(&ictx->args); i++) {
804 iarg = &ARRAY_ITEM(&ictx->args, i);
805 if (*iarg->data != '\0')
806 log_debug2(" ++ %u: %s", i, iarg->data);
809 find.ch = ch;
810 entry = bsearch(&find,
811 input_sequence_table, nitems(input_sequence_table),
812 sizeof input_sequence_table[0], input_sequence_cmp);
813 if (entry != NULL)
814 entry->fn(ictx);
815 else
816 log_debug("unknown sq: %c (%hhu %hhu)", ch, ch, ictx->private);
819 void
820 input_handle_sequence_cuu(struct input_ctx *ictx)
822 uint16_t n;
824 if (ictx->private != '\0')
825 return;
827 if (ARRAY_LENGTH(&ictx->args) > 1)
828 return;
829 if (input_get_argument(ictx, 0, &n, 1) != 0)
830 return;
831 if (n == 0)
832 n = 1;
834 screen_write_cursorup(&ictx->ctx, n);
837 void
838 input_handle_sequence_cud(struct input_ctx *ictx)
840 uint16_t n;
842 if (ictx->private != '\0')
843 return;
845 if (ARRAY_LENGTH(&ictx->args) > 1)
846 return;
847 if (input_get_argument(ictx, 0, &n, 1) != 0)
848 return;
849 if (n == 0)
850 n = 1;
852 screen_write_cursordown(&ictx->ctx, n);
855 void
856 input_handle_sequence_cuf(struct input_ctx *ictx)
858 uint16_t n;
860 if (ictx->private != '\0')
861 return;
863 if (ARRAY_LENGTH(&ictx->args) > 1)
864 return;
865 if (input_get_argument(ictx, 0, &n, 1) != 0)
866 return;
867 if (n == 0)
868 n = 1;
870 screen_write_cursorright(&ictx->ctx, n);
873 void
874 input_handle_sequence_cub(struct input_ctx *ictx)
876 uint16_t n;
878 if (ictx->private != '\0')
879 return;
881 if (ARRAY_LENGTH(&ictx->args) > 1)
882 return;
883 if (input_get_argument(ictx, 0, &n, 1) != 0)
884 return;
885 if (n == 0)
886 n = 1;
888 screen_write_cursorleft(&ictx->ctx, n);
891 void
892 input_handle_sequence_dch(struct input_ctx *ictx)
894 uint16_t n;
896 if (ictx->private != '\0')
897 return;
899 if (ARRAY_LENGTH(&ictx->args) > 1)
900 return;
901 if (input_get_argument(ictx, 0, &n, 1) != 0)
902 return;
903 if (n == 0)
904 n = 1;
906 screen_write_deletecharacter(&ictx->ctx, n);
909 void
910 input_handle_sequence_cbt(struct input_ctx *ictx)
912 struct screen *s = ictx->ctx.s;
913 uint16_t n;
915 if (ictx->private != '\0')
916 return;
918 if (ARRAY_LENGTH(&ictx->args) > 1)
919 return;
920 if (input_get_argument(ictx, 0, &n, 1) != 0)
921 return;
922 if (n == 0)
923 n = 1;
925 /* Find the previous tab point, n times. */
926 while (s->cx > 0 && n-- > 0) {
928 s->cx--;
929 while (s->cx > 0 && !bit_test(s->tabs, s->cx));
933 void
934 input_handle_sequence_da(struct input_ctx *ictx)
936 struct window_pane *wp = ictx->wp;
937 uint16_t n;
939 if (ictx->private != '\0')
940 return;
942 if (ARRAY_LENGTH(&ictx->args) > 1)
943 return;
944 if (input_get_argument(ictx, 0, &n, 0) != 0)
945 return;
946 if (n != 0)
947 return;
949 bufferevent_write(wp->event, "\033[?1;2c", (sizeof "\033[?1;2c") - 1);
952 void
953 input_handle_sequence_dl(struct input_ctx *ictx)
955 uint16_t n;
957 if (ictx->private != '\0')
958 return;
960 if (ARRAY_LENGTH(&ictx->args) > 1)
961 return;
962 if (input_get_argument(ictx, 0, &n, 1) != 0)
963 return;
964 if (n == 0)
965 n = 1;
967 screen_write_deleteline(&ictx->ctx, n);
970 void
971 input_handle_sequence_ich(struct input_ctx *ictx)
973 uint16_t n;
975 if (ictx->private != '\0')
976 return;
978 if (ARRAY_LENGTH(&ictx->args) > 1)
979 return;
980 if (input_get_argument(ictx, 0, &n, 1) != 0)
981 return;
982 if (n == 0)
983 n = 1;
985 screen_write_insertcharacter(&ictx->ctx, n);
988 void
989 input_handle_sequence_il(struct input_ctx *ictx)
991 uint16_t n;
993 if (ictx->private != '\0')
994 return;
996 if (ARRAY_LENGTH(&ictx->args) > 1)
997 return;
998 if (input_get_argument(ictx, 0, &n, 1) != 0)
999 return;
1000 if (n == 0)
1001 n = 1;
1003 screen_write_insertline(&ictx->ctx, n);
1006 void
1007 input_handle_sequence_vpa(struct input_ctx *ictx)
1009 struct screen *s = ictx->ctx.s;
1010 uint16_t n;
1012 if (ictx->private != '\0')
1013 return;
1015 if (ARRAY_LENGTH(&ictx->args) > 1)
1016 return;
1017 if (input_get_argument(ictx, 0, &n, 1) != 0)
1018 return;
1019 if (n == 0)
1020 n = 1;
1022 screen_write_cursormove(&ictx->ctx, s->cx, n - 1);
1025 void
1026 input_handle_sequence_hpa(struct input_ctx *ictx)
1028 struct screen *s = ictx->ctx.s;
1029 uint16_t n;
1031 if (ictx->private != '\0')
1032 return;
1034 if (ARRAY_LENGTH(&ictx->args) > 1)
1035 return;
1036 if (input_get_argument(ictx, 0, &n, 1) != 0)
1037 return;
1038 if (n == 0)
1039 n = 1;
1041 screen_write_cursormove(&ictx->ctx, n - 1, s->cy);
1044 void
1045 input_handle_sequence_cup(struct input_ctx *ictx)
1047 uint16_t n, m;
1049 if (ictx->private != '\0')
1050 return;
1052 if (ARRAY_LENGTH(&ictx->args) > 2)
1053 return;
1054 if (input_get_argument(ictx, 0, &n, 1) != 0)
1055 return;
1056 if (input_get_argument(ictx, 1, &m, 1) != 0)
1057 return;
1058 if (n == 0)
1059 n = 1;
1060 if (m == 0)
1061 m = 1;
1063 screen_write_cursormove(&ictx->ctx, m - 1, n - 1);
1066 void
1067 input_handle_sequence_tbc(struct input_ctx *ictx)
1069 struct screen *s = ictx->ctx.s;
1070 uint16_t n;
1072 if (ictx->private != '\0')
1073 return;
1075 if (ARRAY_LENGTH(&ictx->args) > 1)
1076 return;
1077 if (input_get_argument(ictx, 0, &n, 1) != 0)
1078 return;
1080 switch (n) {
1081 case 0:
1082 if (s->cx < screen_size_x(s))
1083 bit_clear(s->tabs, s->cx);
1084 break;
1085 case 3:
1086 bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1087 break;
1091 void
1092 input_handle_sequence_ed(struct input_ctx *ictx)
1094 uint16_t n;
1096 if (ictx->private != '\0')
1097 return;
1099 if (ARRAY_LENGTH(&ictx->args) > 1)
1100 return;
1101 if (input_get_argument(ictx, 0, &n, 0) != 0)
1102 return;
1103 if (n > 2)
1104 return;
1106 switch (n) {
1107 case 0:
1108 screen_write_clearendofscreen(&ictx->ctx);
1109 break;
1110 case 1:
1111 screen_write_clearstartofscreen(&ictx->ctx);
1112 break;
1113 case 2:
1114 screen_write_clearscreen(&ictx->ctx);
1115 break;
1119 void
1120 input_handle_sequence_el(struct input_ctx *ictx)
1122 uint16_t n;
1124 if (ictx->private != '\0')
1125 return;
1127 if (ARRAY_LENGTH(&ictx->args) > 1)
1128 return;
1129 if (input_get_argument(ictx, 0, &n, 0) != 0)
1130 return;
1131 if (n > 2)
1132 return;
1134 switch (n) {
1135 case 0:
1136 screen_write_clearendofline(&ictx->ctx);
1137 break;
1138 case 1:
1139 screen_write_clearstartofline(&ictx->ctx);
1140 break;
1141 case 2:
1142 screen_write_clearline(&ictx->ctx);
1143 break;
1147 void
1148 input_handle_sequence_sm(struct input_ctx *ictx)
1150 struct window_pane *wp = ictx->wp;
1151 struct screen *s = &wp->base;
1152 u_int sx, sy;
1153 uint16_t n;
1155 if (ARRAY_LENGTH(&ictx->args) > 1)
1156 return;
1157 if (input_get_argument(ictx, 0, &n, 0) != 0)
1158 return;
1160 if (ictx->private == '?') {
1161 switch (n) {
1162 case 1: /* GATM */
1163 screen_write_kcursormode(&ictx->ctx, 1);
1164 log_debug("kcursor on");
1165 break;
1166 case 3: /* DECCOLM */
1167 screen_write_cursormove(&ictx->ctx, 0, 0);
1168 screen_write_clearscreen(&ictx->ctx);
1169 break;
1170 case 25: /* TCEM */
1171 screen_write_cursormode(&ictx->ctx, 1);
1172 log_debug("cursor on");
1173 break;
1174 case 1000:
1175 screen_write_mousemode(&ictx->ctx, 1);
1176 log_debug("mouse on");
1177 break;
1178 case 1049:
1179 if (wp->saved_grid != NULL)
1180 break;
1181 sx = screen_size_x(s);
1182 sy = screen_size_y(s);
1185 * Enter alternative screen mode. A copy of the visible
1186 * screen is saved and the history is not updated
1189 wp->saved_grid = grid_create(sx, sy, 0);
1190 grid_duplicate_lines(
1191 wp->saved_grid, 0, s->grid, screen_hsize(s), sy);
1192 wp->saved_cx = s->cx;
1193 wp->saved_cy = s->cy;
1194 memcpy(&wp->saved_cell,
1195 &ictx->cell, sizeof wp->saved_cell);
1197 grid_view_clear(s->grid, 0, 0, sx, sy);
1199 wp->base.grid->flags &= ~GRID_HISTORY;
1201 wp->flags |= PANE_REDRAW;
1202 break;
1203 default:
1204 log_debug("unknown SM [%hhu]: %u", ictx->private, n);
1205 break;
1207 } else {
1208 switch (n) {
1209 case 4: /* IRM */
1210 screen_write_insertmode(&ictx->ctx, 1);
1211 log_debug("insert on");
1212 break;
1213 case 34:
1214 /* Cursor high visibility not supported. */
1215 break;
1216 default:
1217 log_debug("unknown SM [%hhu]: %u", ictx->private, n);
1218 break;
1223 void
1224 input_handle_sequence_rm(struct input_ctx *ictx)
1226 struct window_pane *wp = ictx->wp;
1227 struct screen *s = &wp->base;
1228 u_int sx, sy;
1229 uint16_t n;
1231 if (ARRAY_LENGTH(&ictx->args) > 1)
1232 return;
1233 if (input_get_argument(ictx, 0, &n, 0) != 0)
1234 return;
1236 if (ictx->private == '?') {
1237 switch (n) {
1238 case 1: /* GATM */
1239 screen_write_kcursormode(&ictx->ctx, 0);
1240 log_debug("kcursor off");
1241 break;
1242 case 3: /* DECCOLM */
1243 screen_write_cursormove(&ictx->ctx, 0, 0);
1244 screen_write_clearscreen(&ictx->ctx);
1245 break;
1246 case 25: /* TCEM */
1247 screen_write_cursormode(&ictx->ctx, 0);
1248 log_debug("cursor off");
1249 break;
1250 case 1000:
1251 screen_write_mousemode(&ictx->ctx, 0);
1252 log_debug("mouse off");
1253 break;
1254 case 1049:
1255 if (wp->saved_grid == NULL)
1256 break;
1257 sx = screen_size_x(s);
1258 sy = screen_size_y(s);
1261 * Exit alternative screen mode and restore the copied
1262 * grid.
1266 * If the current size is bigger, temporarily resize
1267 * to the old size before copying back.
1269 if (sy > wp->saved_grid->sy)
1270 screen_resize(s, sx, wp->saved_grid->sy);
1272 /* Restore the grid, cursor position and cell. */
1273 grid_duplicate_lines(
1274 s->grid, screen_hsize(s), wp->saved_grid, 0, sy);
1275 s->cx = wp->saved_cx;
1276 if (s->cx > screen_size_x(s) - 1)
1277 s->cx = screen_size_x(s) - 1;
1278 s->cy = wp->saved_cy;
1279 if (s->cy > screen_size_y(s) - 1)
1280 s->cy = screen_size_y(s) - 1;
1281 memcpy(&ictx->cell, &wp->saved_cell, sizeof ictx->cell);
1284 * Turn history back on (so resize can use it) and then
1285 * resize back to the current size.
1287 wp->base.grid->flags |= GRID_HISTORY;
1288 if (sy > wp->saved_grid->sy)
1289 screen_resize(s, sx, sy);
1291 grid_destroy(wp->saved_grid);
1292 wp->saved_grid = NULL;
1294 wp->flags |= PANE_REDRAW;
1295 break;
1296 default:
1297 log_debug("unknown RM [%hhu]: %u", ictx->private, n);
1298 break;
1300 } else if (ictx->private == '\0') {
1301 switch (n) {
1302 case 4: /* IRM */
1303 screen_write_insertmode(&ictx->ctx, 0);
1304 log_debug("insert off");
1305 break;
1306 case 34:
1307 /* Cursor high visibility not supported. */
1308 break;
1309 default:
1310 log_debug("unknown RM [%hhu]: %u", ictx->private, n);
1311 break;
1316 void
1317 input_handle_sequence_dsr(struct input_ctx *ictx)
1319 struct window_pane *wp = ictx->wp;
1320 struct screen *s = ictx->ctx.s;
1321 uint16_t n;
1322 char reply[32];
1324 if (ARRAY_LENGTH(&ictx->args) > 1)
1325 return;
1326 if (input_get_argument(ictx, 0, &n, 0) != 0)
1327 return;
1329 if (ictx->private == '\0') {
1330 switch (n) {
1331 case 6: /* cursor position */
1332 xsnprintf(reply, sizeof reply,
1333 "\033[%u;%uR", s->cy + 1, s->cx + 1);
1334 log_debug("cursor request, reply: %s", reply);
1335 bufferevent_write(wp->event, reply, strlen(reply));
1336 break;
1341 void
1342 input_handle_sequence_decstbm(struct input_ctx *ictx)
1344 struct screen *s = ictx->ctx.s;
1345 uint16_t n, m;
1347 if (ictx->private != '\0')
1348 return;
1350 if (ARRAY_LENGTH(&ictx->args) > 2)
1351 return;
1352 if (input_get_argument(ictx, 0, &n, 0) != 0)
1353 return;
1354 if (input_get_argument(ictx, 1, &m, 0) != 0)
1355 return;
1356 if (n == 0)
1357 n = 1;
1358 if (m == 0)
1359 m = screen_size_y(s);
1361 screen_write_scrollregion(&ictx->ctx, n - 1, m - 1);
1364 void
1365 input_handle_sequence_sgr(struct input_ctx *ictx)
1367 struct grid_cell *gc = &ictx->cell;
1368 u_int i;
1369 uint16_t m, o;
1370 u_char attr;
1372 if (ARRAY_LENGTH(&ictx->args) == 0) {
1373 attr = gc->attr;
1374 memcpy(gc, &grid_default_cell, sizeof *gc);
1375 gc->attr |= (attr & GRID_ATTR_CHARSET);
1376 return;
1379 for (i = 0; i < ARRAY_LENGTH(&ictx->args); i++) {
1380 if (input_get_argument(ictx, i, &m, 0) != 0)
1381 return;
1383 if (m == 38 || m == 48) {
1384 i++;
1385 if (input_get_argument(ictx, i, &o, 0) != 0)
1386 return;
1387 if (o != 5)
1388 continue;
1390 i++;
1391 if (input_get_argument(ictx, i, &o, 0) != 0)
1392 return;
1393 if (m == 38) {
1394 gc->flags |= GRID_FLAG_FG256;
1395 gc->fg = o;
1396 } else if (m == 48) {
1397 gc->flags |= GRID_FLAG_BG256;
1398 gc->bg = o;
1400 continue;
1403 switch (m) {
1404 case 0:
1405 case 10:
1406 attr = gc->attr;
1407 memcpy(gc, &grid_default_cell, sizeof *gc);
1408 gc->attr |= (attr & GRID_ATTR_CHARSET);
1409 break;
1410 case 1:
1411 gc->attr |= GRID_ATTR_BRIGHT;
1412 break;
1413 case 2:
1414 gc->attr |= GRID_ATTR_DIM;
1415 break;
1416 case 3:
1417 gc->attr |= GRID_ATTR_ITALICS;
1418 break;
1419 case 4:
1420 gc->attr |= GRID_ATTR_UNDERSCORE;
1421 break;
1422 case 5:
1423 gc->attr |= GRID_ATTR_BLINK;
1424 break;
1425 case 7:
1426 gc->attr |= GRID_ATTR_REVERSE;
1427 break;
1428 case 8:
1429 gc->attr |= GRID_ATTR_HIDDEN;
1430 break;
1431 case 22:
1432 gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
1433 break;
1434 case 23:
1435 gc->attr &= ~GRID_ATTR_ITALICS;
1436 break;
1437 case 24:
1438 gc->attr &= ~GRID_ATTR_UNDERSCORE;
1439 break;
1440 case 25:
1441 gc->attr &= ~GRID_ATTR_BLINK;
1442 break;
1443 case 27:
1444 gc->attr &= ~GRID_ATTR_REVERSE;
1445 break;
1446 case 30:
1447 case 31:
1448 case 32:
1449 case 33:
1450 case 34:
1451 case 35:
1452 case 36:
1453 case 37:
1454 gc->flags &= ~GRID_FLAG_FG256;
1455 gc->fg = m - 30;
1456 break;
1457 case 39:
1458 gc->flags &= ~GRID_FLAG_FG256;
1459 gc->fg = 8;
1460 break;
1461 case 40:
1462 case 41:
1463 case 42:
1464 case 43:
1465 case 44:
1466 case 45:
1467 case 46:
1468 case 47:
1469 gc->flags &= ~GRID_FLAG_BG256;
1470 gc->bg = m - 40;
1471 break;
1472 case 49:
1473 gc->flags &= ~GRID_FLAG_BG256;
1474 gc->bg = 8;
1475 break;
1476 case 90:
1477 case 91:
1478 case 92:
1479 case 93:
1480 case 94:
1481 case 95:
1482 case 96:
1483 case 97:
1484 gc->flags &= ~GRID_FLAG_FG256;
1485 gc->fg = m;
1486 break;
1487 case 100:
1488 case 101:
1489 case 102:
1490 case 103:
1491 case 104:
1492 case 105:
1493 case 106:
1494 case 107:
1495 gc->flags &= ~GRID_FLAG_BG256;
1496 gc->bg = m;
1497 break;