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>
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
{
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
;
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
);
140 input_add_argument(struct input_ctx
*ictx
, u_char ch
)
142 struct input_arg
*arg
;
144 if (ARRAY_LENGTH(&ictx
->args
) == 0)
147 arg
= &ARRAY_LAST(&ictx
->args
);
148 if (arg
->used
> (sizeof arg
->data
) - 1)
150 arg
->data
[arg
->used
++] = ch
;
156 input_get_argument(struct input_ctx
*ictx
, u_int i
, uint16_t *n
, uint16_t d
)
158 struct input_arg
*arg
;
162 if (i
>= ARRAY_LENGTH(&ictx
->args
))
165 arg
= &ARRAY_ITEM(&ictx
->args
, i
);
166 if (*arg
->data
== '\0')
169 *n
= strtonum(arg
->data
, 0, UINT16_MAX
, &errstr
);
176 input_start_string(struct input_ctx
*ictx
, int type
)
178 ictx
->string_type
= type
;
179 ictx
->string_len
= 0;
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
);
205 input_get_string(struct input_ctx
*ictx
)
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
;
218 input_state(struct input_ctx
*ictx
, void *state
)
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
);
239 input_state(ictx
, input_state_first
);
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
);
254 input_parse(struct window_pane
*wp
)
256 struct input_ctx
*ictx
= &wp
->ictx
;
259 if (EVBUFFER_LENGTH(wp
->event
->input
) == ictx
->was
)
261 wp
->window
->flags
|= WINDOW_ACTIVITY
;
263 ictx
->buf
= EVBUFFER_DATA(wp
->event
->input
);
264 ictx
->len
= EVBUFFER_LENGTH(wp
->event
->input
);
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
);
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
);
287 input_state_first(u_char ch
, struct input_ctx
*ictx
)
289 ictx
->intermediate
= '\0';
291 if (INPUT_C0CONTROL(ch
)) {
293 input_state(ictx
, input_state_escape
);
295 input_handle_c0_control(ch
, ictx
);
300 if (INPUT_C1CONTROL(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
);
311 input_handle_c1_control(ch
, ictx
);
316 if (INPUT_DELETE(ch
))
319 input_handle_character(ch
, ictx
);
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
))
329 if (INPUT_C0CONTROL(ch
)) {
330 input_handle_c0_control(ch
, ictx
);
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
);
341 if (INPUT_PARAMETER(ch
)) {
342 input_state(ictx
, input_state_first
);
343 input_handle_private_two(ch
, ictx
);
347 if (INPUT_UPPERCASE(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
);
357 input_state(ictx
, input_state_first
);
358 input_handle_c1_control(ch
, ictx
);
363 if (INPUT_LOWERCASE(ch
)) {
364 input_state(ictx
, input_state_first
);
365 input_handle_standard_two(ch
, ictx
);
369 input_state(ictx
, input_state_first
);
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
);
381 if (INPUT_PARAMETER(ch
)) {
382 input_state(ictx
, input_state_first
);
383 input_handle_private_two(ch
, ictx
);
387 if (INPUT_UPPERCASE(ch
) || INPUT_LOWERCASE(ch
)) {
388 input_state(ictx
, input_state_first
);
389 input_handle_standard_two(ch
, ictx
);
393 input_state(ictx
, input_state_first
);
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
);
408 } else if (ch
== 0x18 || ch
== 0x1a) { /* CAN and SUB */
409 /* Abort sequence. */
410 input_state(ictx
, input_state_first
);
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.
424 input_state(ictx
, input_state_sequence_next
);
426 /* Private sequence: always the first character. */
427 if (ch
>= 0x3c && ch
<= 0x3f) {
432 /* Pass character on directly. */
433 input_state_sequence_next(ch
, ictx
);
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
);
443 log_debug2(":: si1 %zu: %hhu (%c)", ictx
->off
, ch
, ch
);
444 input_state(ictx
, input_state_sequence_intermediate
);
449 if (INPUT_PARAMETER(ch
)) {
450 if (ARRAY_EMPTY(&ictx
->args
))
451 input_new_argument(ictx
);
454 if (input_add_argument(ictx
, '\0') != 0)
455 input_state(ictx
, input_state_first
);
457 input_new_argument(ictx
);
458 } else if (input_add_argument(ictx
, ch
) != 0)
459 input_state(ictx
, input_state_first
);
463 if (INPUT_UPPERCASE(ch
) || INPUT_LOWERCASE(ch
)) {
464 if (input_add_argument(ictx
, '\0') != 0)
465 input_state(ictx
, input_state_first
);
467 input_state(ictx
, input_state_first
);
468 input_handle_sequence(ch
, ictx
);
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
);
479 } else if (ch
== 0x18 || ch
== 0x1a) { /* CAN and SUB */
480 /* Abort sequence. */
481 input_state(ictx
, input_state_first
);
485 /* Handle C0 immediately. */
486 input_handle_c0_control(ch
, ictx
);
491 input_state(ictx
, input_state_first
);
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
);
502 if (INPUT_UPPERCASE(ch
) || INPUT_LOWERCASE(ch
)) {
503 input_state(ictx
, input_state_first
);
504 input_handle_sequence(ch
, ictx
);
508 input_state(ictx
, input_state_first
);
512 input_state_string_next(u_char ch
, struct input_ctx
*ictx
)
515 input_state(ictx
, input_state_string_escape
);
519 input_state_string_escape(ch
, ictx
);
524 if (input_add_string(ictx
, ch
) != 0)
525 input_state(ictx
, input_state_first
);
531 input_state_string_escape(u_char ch
, struct input_ctx
*ictx
)
535 if (ch
== '\007' || ch
== '\\') {
536 input_state(ictx
, input_state_first
);
537 switch (ictx
->string_type
) {
541 s
= input_get_string(ictx
);
542 if ((s
[0] != '0' && s
[0] != '2') || s
[1] != ';') {
546 screen_set_title(ictx
->ctx
.s
, s
+ 2);
547 server_status_window(ictx
->wp
->window
);
550 case STRING_APPLICATION
:
553 s
= input_get_string(ictx
);
554 screen_set_title(ictx
->ctx
.s
, s
);
555 server_status_window(ictx
->wp
->window
);
561 xfree(ictx
->wp
->window
->name
);
562 ictx
->wp
->window
->name
= input_get_string(ictx
);
563 server_status_window(ictx
->wp
->window
);
569 input_state(ictx
, input_state_string_next
);
570 input_state_string_next(ch
, ictx
);
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
;
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
);
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
);
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
);
617 screen_write_linefeed(&ictx
->ctx
, 0);
620 screen_write_carriagereturn(&ictx
->ctx
);
622 case '\007': /* BELL */
623 ictx
->wp
->window
->flags
|= WINDOW_BELL
;
625 case '\010': /* BS */
626 screen_write_backspace(&ictx
->ctx
);
628 case '\011': /* TAB */
629 /* Don't tab beyond the end of the line. */
630 if (s
->cx
>= screen_size_x(s
) - 1)
633 /* Find the next tab point, or use the last column if none. */
636 if (bit_test(s
->tabs
, s
->cx
))
638 } while (s
->cx
< screen_size_x(s
) - 1);
640 case '\013': /* VT */
641 screen_write_linefeed(&ictx
->ctx
, 0);
643 case '\016': /* SO */
644 ictx
->cell
.attr
|= GRID_ATTR_CHARSET
;
646 case '\017': /* SI */
647 ictx
->cell
.attr
&= ~GRID_ATTR_CHARSET
;
650 log_debug("unknown c0: %hhu", ch
);
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
);
664 screen_write_linefeed(&ictx
->ctx
, 0);
667 screen_write_carriagereturn(&ictx
->ctx
);
668 screen_write_linefeed(&ictx
->ctx
, 0);
671 if (s
->cx
< screen_size_x(s
))
672 bit_set(s
->tabs
, s
->cx
);
675 screen_write_reverseindex(&ictx
->ctx
);
678 log_debug("unknown c1: %hhu", ch
);
684 input_handle_private_two(u_char ch
, struct input_ctx
*ictx
)
686 struct screen
*s
= ictx
->ctx
.s
;
689 "-- p2 %zu: %hhu (%c) %hhu", ictx
->off
, ch
, ch
, ictx
->intermediate
);
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
) {
700 ictx
->cell
.attr
|= GRID_ATTR_CHARSET
;
704 case '=': /* DECKPAM */
705 if (ictx
->intermediate
!= '\0')
707 screen_write_kkeypadmode(&ictx
->ctx
, 1);
708 log_debug("kkeypad on (application mode)");
710 case '>': /* DECKPNM */
711 if (ictx
->intermediate
!= '\0')
713 screen_write_kkeypadmode(&ictx
->ctx
, 0);
714 log_debug("kkeypad off (number mode)");
716 case '7': /* DECSC */
717 if (ictx
->intermediate
!= '\0')
719 memcpy(&ictx
->saved_cell
, &ictx
->cell
, sizeof ictx
->saved_cell
);
720 ictx
->saved_cx
= s
->cx
;
721 ictx
->saved_cy
= s
->cy
;
724 switch (ictx
->intermediate
) {
725 case '\0': /* DECRC */
727 &ictx
->cell
, &ictx
->saved_cell
, sizeof ictx
->cell
);
728 screen_write_cursormove(
729 &ictx
->ctx
, ictx
->saved_cx
, ictx
->saved_cy
);
731 case '#': /* DECALN */
732 screen_write_alignmenttest(&ictx
->ctx
);
737 log_debug("unknown p2: %hhu", ch
);
743 input_handle_standard_two(u_char ch
, struct input_ctx
*ictx
)
746 "-- s2 %zu: %hhu (%c) %hhu", ictx
->off
, ch
, ch
, ictx
->intermediate
);
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
) {
757 ictx
->cell
.attr
&= ~GRID_ATTR_CHARSET
;
762 memcpy(&ictx
->cell
, &grid_default_cell
, sizeof ictx
->cell
);
764 memcpy(&ictx
->saved_cell
, &ictx
->cell
, sizeof ictx
->saved_cell
);
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);
782 input_start_string(ictx
, STRING_NAME
);
783 input_state(ictx
, input_state_string_next
);
786 log_debug("unknown s2: %hhu", ch
);
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
;
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
,
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
);
810 entry
= bsearch(&find
,
811 input_sequence_table
, nitems(input_sequence_table
),
812 sizeof input_sequence_table
[0], input_sequence_cmp
);
816 log_debug("unknown sq: %c (%hhu %hhu)", ch
, ch
, ictx
->private);
820 input_handle_sequence_cuu(struct input_ctx
*ictx
)
824 if (ictx
->private != '\0')
827 if (ARRAY_LENGTH(&ictx
->args
) > 1)
829 if (input_get_argument(ictx
, 0, &n
, 1) != 0)
834 screen_write_cursorup(&ictx
->ctx
, n
);
838 input_handle_sequence_cud(struct input_ctx
*ictx
)
842 if (ictx
->private != '\0')
845 if (ARRAY_LENGTH(&ictx
->args
) > 1)
847 if (input_get_argument(ictx
, 0, &n
, 1) != 0)
852 screen_write_cursordown(&ictx
->ctx
, n
);
856 input_handle_sequence_cuf(struct input_ctx
*ictx
)
860 if (ictx
->private != '\0')
863 if (ARRAY_LENGTH(&ictx
->args
) > 1)
865 if (input_get_argument(ictx
, 0, &n
, 1) != 0)
870 screen_write_cursorright(&ictx
->ctx
, n
);
874 input_handle_sequence_cub(struct input_ctx
*ictx
)
878 if (ictx
->private != '\0')
881 if (ARRAY_LENGTH(&ictx
->args
) > 1)
883 if (input_get_argument(ictx
, 0, &n
, 1) != 0)
888 screen_write_cursorleft(&ictx
->ctx
, n
);
892 input_handle_sequence_dch(struct input_ctx
*ictx
)
896 if (ictx
->private != '\0')
899 if (ARRAY_LENGTH(&ictx
->args
) > 1)
901 if (input_get_argument(ictx
, 0, &n
, 1) != 0)
906 screen_write_deletecharacter(&ictx
->ctx
, n
);
910 input_handle_sequence_cbt(struct input_ctx
*ictx
)
912 struct screen
*s
= ictx
->ctx
.s
;
915 if (ictx
->private != '\0')
918 if (ARRAY_LENGTH(&ictx
->args
) > 1)
920 if (input_get_argument(ictx
, 0, &n
, 1) != 0)
925 /* Find the previous tab point, n times. */
926 while (s
->cx
> 0 && n
-- > 0) {
929 while (s
->cx
> 0 && !bit_test(s
->tabs
, s
->cx
));
934 input_handle_sequence_da(struct input_ctx
*ictx
)
936 struct window_pane
*wp
= ictx
->wp
;
939 if (ictx
->private != '\0')
942 if (ARRAY_LENGTH(&ictx
->args
) > 1)
944 if (input_get_argument(ictx
, 0, &n
, 0) != 0)
949 bufferevent_write(wp
->event
, "\033[?1;2c", (sizeof "\033[?1;2c") - 1);
953 input_handle_sequence_dl(struct input_ctx
*ictx
)
957 if (ictx
->private != '\0')
960 if (ARRAY_LENGTH(&ictx
->args
) > 1)
962 if (input_get_argument(ictx
, 0, &n
, 1) != 0)
967 screen_write_deleteline(&ictx
->ctx
, n
);
971 input_handle_sequence_ich(struct input_ctx
*ictx
)
975 if (ictx
->private != '\0')
978 if (ARRAY_LENGTH(&ictx
->args
) > 1)
980 if (input_get_argument(ictx
, 0, &n
, 1) != 0)
985 screen_write_insertcharacter(&ictx
->ctx
, n
);
989 input_handle_sequence_il(struct input_ctx
*ictx
)
993 if (ictx
->private != '\0')
996 if (ARRAY_LENGTH(&ictx
->args
) > 1)
998 if (input_get_argument(ictx
, 0, &n
, 1) != 0)
1003 screen_write_insertline(&ictx
->ctx
, n
);
1007 input_handle_sequence_vpa(struct input_ctx
*ictx
)
1009 struct screen
*s
= ictx
->ctx
.s
;
1012 if (ictx
->private != '\0')
1015 if (ARRAY_LENGTH(&ictx
->args
) > 1)
1017 if (input_get_argument(ictx
, 0, &n
, 1) != 0)
1022 screen_write_cursormove(&ictx
->ctx
, s
->cx
, n
- 1);
1026 input_handle_sequence_hpa(struct input_ctx
*ictx
)
1028 struct screen
*s
= ictx
->ctx
.s
;
1031 if (ictx
->private != '\0')
1034 if (ARRAY_LENGTH(&ictx
->args
) > 1)
1036 if (input_get_argument(ictx
, 0, &n
, 1) != 0)
1041 screen_write_cursormove(&ictx
->ctx
, n
- 1, s
->cy
);
1045 input_handle_sequence_cup(struct input_ctx
*ictx
)
1049 if (ictx
->private != '\0')
1052 if (ARRAY_LENGTH(&ictx
->args
) > 2)
1054 if (input_get_argument(ictx
, 0, &n
, 1) != 0)
1056 if (input_get_argument(ictx
, 1, &m
, 1) != 0)
1063 screen_write_cursormove(&ictx
->ctx
, m
- 1, n
- 1);
1067 input_handle_sequence_tbc(struct input_ctx
*ictx
)
1069 struct screen
*s
= ictx
->ctx
.s
;
1072 if (ictx
->private != '\0')
1075 if (ARRAY_LENGTH(&ictx
->args
) > 1)
1077 if (input_get_argument(ictx
, 0, &n
, 1) != 0)
1082 if (s
->cx
< screen_size_x(s
))
1083 bit_clear(s
->tabs
, s
->cx
);
1086 bit_nclear(s
->tabs
, 0, screen_size_x(s
) - 1);
1092 input_handle_sequence_ed(struct input_ctx
*ictx
)
1096 if (ictx
->private != '\0')
1099 if (ARRAY_LENGTH(&ictx
->args
) > 1)
1101 if (input_get_argument(ictx
, 0, &n
, 0) != 0)
1108 screen_write_clearendofscreen(&ictx
->ctx
);
1111 screen_write_clearstartofscreen(&ictx
->ctx
);
1114 screen_write_clearscreen(&ictx
->ctx
);
1120 input_handle_sequence_el(struct input_ctx
*ictx
)
1124 if (ictx
->private != '\0')
1127 if (ARRAY_LENGTH(&ictx
->args
) > 1)
1129 if (input_get_argument(ictx
, 0, &n
, 0) != 0)
1136 screen_write_clearendofline(&ictx
->ctx
);
1139 screen_write_clearstartofline(&ictx
->ctx
);
1142 screen_write_clearline(&ictx
->ctx
);
1148 input_handle_sequence_sm(struct input_ctx
*ictx
)
1150 struct window_pane
*wp
= ictx
->wp
;
1151 struct screen
*s
= &wp
->base
;
1155 if (ARRAY_LENGTH(&ictx
->args
) > 1)
1157 if (input_get_argument(ictx
, 0, &n
, 0) != 0)
1160 if (ictx
->private == '?') {
1163 screen_write_kcursormode(&ictx
->ctx
, 1);
1164 log_debug("kcursor on");
1166 case 3: /* DECCOLM */
1167 screen_write_cursormove(&ictx
->ctx
, 0, 0);
1168 screen_write_clearscreen(&ictx
->ctx
);
1171 screen_write_cursormode(&ictx
->ctx
, 1);
1172 log_debug("cursor on");
1175 screen_write_mousemode(&ictx
->ctx
, 1);
1176 log_debug("mouse on");
1179 if (wp
->saved_grid
!= NULL
)
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
;
1204 log_debug("unknown SM [%hhu]: %u", ictx
->private, n
);
1210 screen_write_insertmode(&ictx
->ctx
, 1);
1211 log_debug("insert on");
1214 /* Cursor high visibility not supported. */
1217 log_debug("unknown SM [%hhu]: %u", ictx
->private, n
);
1224 input_handle_sequence_rm(struct input_ctx
*ictx
)
1226 struct window_pane
*wp
= ictx
->wp
;
1227 struct screen
*s
= &wp
->base
;
1231 if (ARRAY_LENGTH(&ictx
->args
) > 1)
1233 if (input_get_argument(ictx
, 0, &n
, 0) != 0)
1236 if (ictx
->private == '?') {
1239 screen_write_kcursormode(&ictx
->ctx
, 0);
1240 log_debug("kcursor off");
1242 case 3: /* DECCOLM */
1243 screen_write_cursormove(&ictx
->ctx
, 0, 0);
1244 screen_write_clearscreen(&ictx
->ctx
);
1247 screen_write_cursormode(&ictx
->ctx
, 0);
1248 log_debug("cursor off");
1251 screen_write_mousemode(&ictx
->ctx
, 0);
1252 log_debug("mouse off");
1255 if (wp
->saved_grid
== NULL
)
1257 sx
= screen_size_x(s
);
1258 sy
= screen_size_y(s
);
1261 * Exit alternative screen mode and restore the copied
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
;
1297 log_debug("unknown RM [%hhu]: %u", ictx
->private, n
);
1300 } else if (ictx
->private == '\0') {
1303 screen_write_insertmode(&ictx
->ctx
, 0);
1304 log_debug("insert off");
1307 /* Cursor high visibility not supported. */
1310 log_debug("unknown RM [%hhu]: %u", ictx
->private, n
);
1317 input_handle_sequence_dsr(struct input_ctx
*ictx
)
1319 struct window_pane
*wp
= ictx
->wp
;
1320 struct screen
*s
= ictx
->ctx
.s
;
1324 if (ARRAY_LENGTH(&ictx
->args
) > 1)
1326 if (input_get_argument(ictx
, 0, &n
, 0) != 0)
1329 if (ictx
->private == '\0') {
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
));
1342 input_handle_sequence_decstbm(struct input_ctx
*ictx
)
1344 struct screen
*s
= ictx
->ctx
.s
;
1347 if (ictx
->private != '\0')
1350 if (ARRAY_LENGTH(&ictx
->args
) > 2)
1352 if (input_get_argument(ictx
, 0, &n
, 0) != 0)
1354 if (input_get_argument(ictx
, 1, &m
, 0) != 0)
1359 m
= screen_size_y(s
);
1361 screen_write_scrollregion(&ictx
->ctx
, n
- 1, m
- 1);
1365 input_handle_sequence_sgr(struct input_ctx
*ictx
)
1367 struct grid_cell
*gc
= &ictx
->cell
;
1372 if (ARRAY_LENGTH(&ictx
->args
) == 0) {
1374 memcpy(gc
, &grid_default_cell
, sizeof *gc
);
1375 gc
->attr
|= (attr
& GRID_ATTR_CHARSET
);
1379 for (i
= 0; i
< ARRAY_LENGTH(&ictx
->args
); i
++) {
1380 if (input_get_argument(ictx
, i
, &m
, 0) != 0)
1383 if (m
== 38 || m
== 48) {
1385 if (input_get_argument(ictx
, i
, &o
, 0) != 0)
1391 if (input_get_argument(ictx
, i
, &o
, 0) != 0)
1394 gc
->flags
|= GRID_FLAG_FG256
;
1396 } else if (m
== 48) {
1397 gc
->flags
|= GRID_FLAG_BG256
;
1407 memcpy(gc
, &grid_default_cell
, sizeof *gc
);
1408 gc
->attr
|= (attr
& GRID_ATTR_CHARSET
);
1411 gc
->attr
|= GRID_ATTR_BRIGHT
;
1414 gc
->attr
|= GRID_ATTR_DIM
;
1417 gc
->attr
|= GRID_ATTR_ITALICS
;
1420 gc
->attr
|= GRID_ATTR_UNDERSCORE
;
1423 gc
->attr
|= GRID_ATTR_BLINK
;
1426 gc
->attr
|= GRID_ATTR_REVERSE
;
1429 gc
->attr
|= GRID_ATTR_HIDDEN
;
1432 gc
->attr
&= ~(GRID_ATTR_BRIGHT
|GRID_ATTR_DIM
);
1435 gc
->attr
&= ~GRID_ATTR_ITALICS
;
1438 gc
->attr
&= ~GRID_ATTR_UNDERSCORE
;
1441 gc
->attr
&= ~GRID_ATTR_BLINK
;
1444 gc
->attr
&= ~GRID_ATTR_REVERSE
;
1454 gc
->flags
&= ~GRID_FLAG_FG256
;
1458 gc
->flags
&= ~GRID_FLAG_FG256
;
1469 gc
->flags
&= ~GRID_FLAG_BG256
;
1473 gc
->flags
&= ~GRID_FLAG_BG256
;
1484 gc
->flags
&= ~GRID_FLAG_FG256
;
1495 gc
->flags
&= ~GRID_FLAG_BG256
;