1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 * The term_screen layer implements the terminal-side. It handles all commands
25 * returned by the seq-parser and applies them to its own pages.
27 * While there are a lot of legacy control-sequences, we only support a small
28 * subset. There is no reason to implement unused codes like horizontal
30 * If you implement new commands, make sure to document them properly.
37 * http://www.vt100.net/emu/ctrlseq_dec.html
38 * http://www.vt100.net/docs/vt100-ug/chapter3.html
39 * http://www.vt100.net/docs/vt510-rm/chapter4
40 * http://www.vt100.net/docs/vt510-rm/contents
41 * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
43 * http://en.wikipedia.org/wiki/C0_and_C1_control_codes
44 * https://en.wikipedia.org/wiki/ANSI_color
50 #include <xkbcommon/xkbcommon-keysyms.h>
52 #include "term-internal.h"
56 int term_screen_new(term_screen **out, term_screen_write_fn write_fn, void *write_fn_data, term_screen_cmd_fn cmd_fn, void *cmd_fn_data) {
57 _cleanup_(term_screen_unrefp) term_screen *screen = NULL;
60 assert_return(out, -EINVAL);
62 screen = new0(term_screen, 1);
68 screen->write_fn = write_fn;
69 screen->write_fn_data = write_fn_data;
70 screen->cmd_fn = cmd_fn;
71 screen->cmd_fn_data = cmd_fn_data;
72 screen->flags = TERM_FLAG_7BIT_MODE;
73 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
74 screen->g0 = &term_unicode_lower;
75 screen->g1 = &term_unicode_upper;
76 screen->g2 = &term_unicode_lower;
77 screen->g3 = &term_unicode_upper;
78 screen->state.gl = &screen->g0;
79 screen->state.gr = &screen->g1;
80 screen->saved = screen->state;
81 screen->saved_alt = screen->saved;
83 r = term_page_new(&screen->page_main);
87 r = term_page_new(&screen->page_alt);
91 r = term_parser_new(&screen->parser, false);
95 r = term_history_new(&screen->history_main);
99 screen->page = screen->page_main;
100 screen->history = screen->history_main;
107 term_screen *term_screen_ref(term_screen *screen) {
111 assert_return(screen->ref > 0, NULL);
117 term_screen *term_screen_unref(term_screen *screen) {
121 assert_return(screen->ref > 0, NULL);
126 free(screen->answerback);
128 term_history_free(screen->history_main);
129 term_page_free(screen->page_alt);
130 term_page_free(screen->page_main);
131 term_parser_free(screen->parser);
139 * Unfortunately, 7bit/8bit compat mode requires us to send C1 controls encoded
140 * as 7bit if asked by the application. This is really used in the wild, so we
141 * cannot fall back to "always 7bit".
142 * screen_write() is the underlying backend which forwards any writes to the
143 * users's callback. It's the users responsibility to buffer these and write
144 * them out once their call to term_screen_feed_*() returns.
145 * The SEQ_WRITE() and SEQ_WRITE_KEY() macros allow constructing C0/C1 sequences
146 * directly in the code-base without requiring any intermediate buffer during
151 #define C1_CSI "\x9b"
153 #define SEQ(_screen, _prefix_esc, _c0, _c1, _seq) \
154 (((_screen)->flags & TERM_FLAG_7BIT_MODE) ? \
155 ((_prefix_esc) ? ("\e" _c0 _seq) : (_c0 _seq)) : \
156 ((_prefix_esc) ? ("\e" _c1 _seq) : (_c1 _seq)))
158 #define SEQ_SIZE(_screen, _prefix_esc, _c0, _c1, _seq) \
159 (((_screen)->flags & TERM_FLAG_7BIT_MODE) ? \
160 ((_prefix_esc) ? sizeof("\e" _c0 _seq) : sizeof(_c0 _seq)) : \
161 ((_prefix_esc) ? sizeof("\e" _c1 _seq) : sizeof(_c1 _seq)))
163 #define SEQ_WRITE_KEY(_screen, _prefix_esc, _c0, _c1, _seq) \
164 screen_write((_screen), \
165 SEQ((_screen), (_prefix_esc), \
167 SEQ_SIZE((_screen), (_prefix_esc), \
170 #define SEQ_WRITE(_screen, _c0, _c1, _seq) \
171 SEQ_WRITE_KEY((_screen), false, _c0, _c1, _seq)
173 static int screen_write(term_screen *screen, const void *buf, size_t len) {
174 if (len < 1 || !screen->write_fn)
177 return screen->write_fn(screen, screen->write_fn_data, buf, len);
182 * Some commands cannot be handled by the screen-layer directly. Those are
183 * forwarded to the command-handler of the caller. This is rarely used and can
184 * safely be set to NULL.
187 static int screen_forward(term_screen *screen, unsigned int cmd, const term_seq *seq) {
191 return screen->cmd_fn(screen, screen->cmd_fn_data, cmd, seq);
196 * These helpers implement common-operations like cursor-handler and more, which
197 * are used by several command dispatchers.
200 static unsigned int screen_clamp_x(term_screen *screen, unsigned int x) {
201 if (x >= screen->page->width)
202 return (screen->page->width > 0) ? screen->page->width - 1 : 0;
207 static unsigned int screen_clamp_y(term_screen *screen, unsigned int y) {
208 if (y >= screen->page->height)
209 return (screen->page->height > 0) ? screen->page->height - 1 : 0;
214 static bool screen_tab_is_set(term_screen *screen, unsigned int pos) {
215 if (pos >= screen->page->width)
218 return screen->tabs[pos / 8] & (1 << (pos % 8));
221 static inline void screen_age_cursor(term_screen *screen) {
224 cell = term_page_get_cell(screen->page, screen->state.cursor_x, screen->state.cursor_y);
226 cell->age = screen->age;
229 static void screen_cursor_clear_wrap(term_screen *screen) {
230 screen->flags &= ~TERM_FLAG_PENDING_WRAP;
233 static void screen_cursor_set(term_screen *screen, unsigned int x, unsigned int y) {
234 x = screen_clamp_x(screen, x);
235 y = screen_clamp_y(screen, y);
237 if (x == screen->state.cursor_x && y == screen->state.cursor_y)
240 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
241 screen_age_cursor(screen);
243 screen->state.cursor_x = x;
244 screen->state.cursor_y = y;
246 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
247 screen_age_cursor(screen);
250 static void screen_cursor_set_rel(term_screen *screen, unsigned int x, unsigned int y) {
251 if (screen->state.origin_mode) {
252 x = screen_clamp_x(screen, x);
253 y = screen_clamp_x(screen, y) + screen->page->scroll_idx;
255 if (y >= screen->page->scroll_idx + screen->page->scroll_num) {
256 y = screen->page->scroll_idx + screen->page->scroll_num;
257 if (screen->page->scroll_num > 0)
262 screen_cursor_set(screen, x, y);
265 static void screen_cursor_left(term_screen *screen, unsigned int num) {
266 if (num > screen->state.cursor_x)
267 num = screen->state.cursor_x;
269 screen_cursor_set(screen, screen->state.cursor_x - num, screen->state.cursor_y);
272 static void screen_cursor_left_tab(term_screen *screen, unsigned int num) {
275 i = screen->state.cursor_x;
276 while (i > 0 && num > 0) {
277 if (screen_tab_is_set(screen, --i))
281 screen_cursor_set(screen, i, screen->state.cursor_y);
284 static void screen_cursor_right(term_screen *screen, unsigned int num) {
285 if (num > screen->page->width)
286 num = screen->page->width;
288 screen_cursor_set(screen, screen->state.cursor_x + num, screen->state.cursor_y);
291 static void screen_cursor_right_tab(term_screen *screen, unsigned int num) {
294 i = screen->state.cursor_x;
295 while (i + 1 < screen->page->width && num > 0) {
296 if (screen_tab_is_set(screen, ++i))
300 screen_cursor_set(screen, i, screen->state.cursor_y);
303 static void screen_cursor_up(term_screen *screen, unsigned int num, bool scroll) {
306 if (screen->state.cursor_y < screen->page->scroll_idx) {
307 if (num > screen->state.cursor_y)
308 num = screen->state.cursor_y;
310 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num);
312 max = screen->state.cursor_y - screen->page->scroll_idx;
317 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
318 screen_age_cursor(screen);
321 term_page_scroll_down(screen->page, num - max, &screen->state.attr, screen->age, NULL);
323 screen->state.cursor_y = screen->page->scroll_idx;
325 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
326 screen_age_cursor(screen);
328 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num);
333 static void screen_cursor_down(term_screen *screen, unsigned int num, bool scroll) {
336 if (screen->state.cursor_y >= screen->page->scroll_idx + screen->page->scroll_num) {
337 if (num > screen->page->height)
338 num = screen->page->height;
340 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num);
342 max = screen->page->scroll_idx + screen->page->scroll_num - 1 - screen->state.cursor_y;
347 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
348 screen_age_cursor(screen);
351 term_page_scroll_up(screen->page, num - max, &screen->state.attr, screen->age, screen->history);
353 screen->state.cursor_y = screen->page->scroll_idx + screen->page->scroll_num - 1;
355 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
356 screen_age_cursor(screen);
358 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y + num);
363 static void screen_save_state(term_screen *screen, term_state *where) {
364 *where = screen->state;
367 static void screen_restore_state(term_screen *screen, term_state *from) {
368 screen_cursor_set(screen, from->cursor_x, from->cursor_y);
369 screen->state = *from;
372 static void screen_reset_page(term_screen *screen, term_page *page) {
373 term_page_set_scroll_region(page, 0, page->height);
374 term_page_erase(page, 0, 0, page->width, page->height, &screen->state.attr, screen->age, false);
377 static void screen_change_alt(term_screen *screen, bool set) {
379 screen->page = screen->page_alt;
380 screen->history = NULL;
382 screen->page = screen->page_main;
383 screen->history = screen->history_main;
386 screen->page->age = screen->age;
389 static inline void set_reset(term_screen *screen, unsigned int flag, bool set) {
391 screen->flags |= flag;
393 screen->flags &= ~flag;
396 static void screen_mode_change_ansi(term_screen *screen, unsigned mode, bool set) {
400 * LNM: line-feed/new-line mode
403 set_reset(screen, TERM_FLAG_NEWLINE_MODE, set);
407 log_debug("terminal: failed to %s unknown ANSI mode %u", set ? "set" : "unset", mode);
411 static void screen_mode_change_dec(term_screen *screen, unsigned int mode, bool set) {
415 * DECCKM: cursor-keys
418 set_reset(screen, TERM_FLAG_CURSOR_KEYS, set);
426 screen->state.origin_mode = set;
431 * DECAWN: auto-wrap mode
434 screen->state.auto_wrap = set;
439 * DECTCEM: text-cursor-enable
442 set_reset(screen, TERM_FLAG_HIDE_CURSOR, !set);
443 screen_age_cursor(screen);
448 * XTERM-ASB: alternate-screen-buffer
449 * This enables/disables the alternate screen-buffer.
450 * It effectively saves the current page content and
451 * allows you to restore it when changing to the
452 * original screen-buffer again.
454 screen_change_alt(screen, set);
459 * XTERM-ASBPE: alternate-screen-buffer-post-erase
460 * This is the same as XTERM-ASB but erases the
461 * alternate screen-buffer before switching back to the
462 * original buffer. Use it to discard any data on the
463 * alternate screen buffer when done.
466 screen_reset_page(screen, screen->page_alt);
468 screen_change_alt(screen, set);
473 * XTERM-ASBCS: alternate-screen-buffer-cursor-state
474 * This has the same effect as DECSC/DECRC, but uses a
475 * separate state buffer. It is usually used in
476 * combination with alternate screen buffers to provide
477 * stacked state storage.
480 screen_save_state(screen, &screen->saved_alt);
482 screen_restore_state(screen, &screen->saved_alt);
487 * XTERM-ASBX: alternate-screen-buffer-extended
488 * This combines XTERM-ASBPE and XTERM-ASBCS somewhat.
489 * When enabling, state is saved, alternate screen
490 * buffer is activated and cleared.
491 * When disabled, alternate screen buffer is cleared,
492 * then normal screen buffer is enabled and state is
496 screen_save_state(screen, &screen->saved_alt);
498 screen_reset_page(screen, screen->page_alt);
499 screen_change_alt(screen, set);
502 screen_restore_state(screen, &screen->saved_alt);
506 log_debug("terminal: failed to %s unknown DEC mode %u", set ? "set" : "unset", mode);
510 /* map a character according to current GL and GR maps */
511 static uint32_t screen_map(term_screen *screen, uint32_t val) {
514 /* 32 and 127 always map to identity. 160 and 255 map to identity iff a
515 * 96 character set is loaded into GR. Values above 255 always map to
519 if (screen->state.glt) {
520 nval = (**screen->state.glt)[val - 32];
521 screen->state.glt = NULL;
523 nval = (**screen->state.gl)[val - 32];
527 if (screen->state.grt) {
528 nval = (**screen->state.grt)[val - 160];
529 screen->state.grt = NULL;
531 nval = (**screen->state.gr)[val - 160];
536 return (nval == -1U) ? val : nval;
541 * This is the unofficial documentation of all the TERM_CMD_* definitions. Each
542 * handled command has a separate function with an extensive comment on the
543 * semantics of the command.
544 * Note that many semantics are unknown and need to be verified. This is mostly
545 * about error-handling, though. Applications rarely rely on those features.
548 static int screen_DA1(term_screen *screen, const term_seq *seq);
549 static int screen_LF(term_screen *screen, const term_seq *seq);
551 static int screen_GRAPHIC(term_screen *screen, const term_seq *seq) {
552 term_char_t ch = TERM_CHAR_NULL;
554 if (screen->state.cursor_x + 1 == screen->page->width
555 && screen->flags & TERM_FLAG_PENDING_WRAP
556 && screen->state.auto_wrap) {
557 screen_cursor_down(screen, 1, true);
558 screen_cursor_set(screen, 0, screen->state.cursor_y);
561 screen_cursor_clear_wrap(screen);
563 ch = term_char_merge(ch, screen_map(screen, seq->terminator));
564 term_page_write(screen->page, screen->state.cursor_x, screen->state.cursor_y, ch, 1, &screen->state.attr, screen->age, false);
566 if (screen->state.cursor_x + 1 == screen->page->width)
567 screen->flags |= TERM_FLAG_PENDING_WRAP;
569 screen_cursor_right(screen, 1);
574 static int screen_BEL(term_screen *screen, const term_seq *seq) {
576 * BEL - sound bell tone
577 * This command should trigger an acoustic bell. Usually, this is
578 * forwarded directly to the pcspkr. However, bells have become quite
579 * uncommon and annoying, so we're not implementing them here. Instead,
580 * it's one of the commands we forward to the caller.
583 return screen_forward(screen, TERM_CMD_BEL, seq);
586 static int screen_BS(term_screen *screen, const term_seq *seq) {
589 * Move cursor one cell to the left. If already at the left margin,
593 screen_cursor_clear_wrap(screen);
594 screen_cursor_left(screen, 1);
598 static int screen_CBT(term_screen *screen, const term_seq *seq) {
600 * CBT - cursor-backward-tabulation
601 * Move the cursor @args[0] tabs backwards (to the left). The
602 * current cursor cell, in case it's a tab, is not counted.
603 * Furthermore, the cursor cannot be moved beyond position 0 and
604 * it will stop there.
610 unsigned int num = 1;
612 if (seq->args[0] > 0)
615 screen_cursor_clear_wrap(screen);
616 screen_cursor_left_tab(screen, num);
621 static int screen_CHA(term_screen *screen, const term_seq *seq) {
623 * CHA - cursor-horizontal-absolute
624 * Move the cursor to position @args[0] in the current line. The
625 * cursor cannot be moved beyond the rightmost cell and will stop
632 unsigned int pos = 1;
634 if (seq->args[0] > 0)
637 screen_cursor_clear_wrap(screen);
638 screen_cursor_set(screen, pos - 1, screen->state.cursor_y);
643 static int screen_CHT(term_screen *screen, const term_seq *seq) {
645 * CHT - cursor-horizontal-forward-tabulation
646 * Move the cursor @args[0] tabs forward (to the right). The
647 * current cursor cell, in case it's a tab, is not counted.
648 * Furthermore, the cursor cannot be moved beyond the rightmost cell
649 * and will stop there.
655 unsigned int num = 1;
657 if (seq->args[0] > 0)
660 screen_cursor_clear_wrap(screen);
661 screen_cursor_right_tab(screen, num);
666 static int screen_CNL(term_screen *screen, const term_seq *seq) {
668 * CNL - cursor-next-line
669 * Move the cursor @args[0] lines down.
671 * TODO: Does this stop at the bottom or cause a scroll-up?
677 unsigned int num = 1;
679 if (seq->args[0] > 0)
682 screen_cursor_clear_wrap(screen);
683 screen_cursor_down(screen, num, false);
688 static int screen_CPL(term_screen *screen, const term_seq *seq) {
690 * CPL - cursor-preceding-line
691 * Move the cursor @args[0] lines up.
693 * TODO: Does this stop at the top or cause a scroll-up?
699 unsigned int num = 1;
701 if (seq->args[0] > 0)
704 screen_cursor_clear_wrap(screen);
705 screen_cursor_up(screen, num, false);
710 static int screen_CR(term_screen *screen, const term_seq *seq) {
712 * CR - carriage-return
713 * Move the cursor to the left margin on the current line.
716 screen_cursor_clear_wrap(screen);
717 screen_cursor_set(screen, 0, screen->state.cursor_y);
722 static int screen_CUB(term_screen *screen, const term_seq *seq) {
724 * CUB - cursor-backward
725 * Move the cursor @args[0] positions to the left. The cursor stops
726 * at the left-most position.
732 unsigned int num = 1;
734 if (seq->args[0] > 0)
737 screen_cursor_clear_wrap(screen);
738 screen_cursor_left(screen, num);
743 static int screen_CUD(term_screen *screen, const term_seq *seq) {
746 * Move the cursor @args[0] positions down. The cursor stops at the
747 * bottom margin. If it was already moved further, it stops at the
754 unsigned int num = 1;
756 if (seq->args[0] > 0)
759 screen_cursor_clear_wrap(screen);
760 screen_cursor_down(screen, num, false);
765 static int screen_CUF(term_screen *screen, const term_seq *seq) {
767 * CUF -cursor-forward
768 * Move the cursor @args[0] positions to the right. The cursor stops
769 * at the right-most position.
775 unsigned int num = 1;
777 if (seq->args[0] > 0)
780 screen_cursor_clear_wrap(screen);
781 screen_cursor_right(screen, num);
786 static int screen_CUP(term_screen *screen, const term_seq *seq) {
788 * CUP - cursor-position
789 * Moves the cursor to position @args[1] x @args[0]. If either is 0, it
790 * is treated as 1. The positions are subject to the origin-mode and
791 * clamped to the addressable with/height.
798 unsigned int x = 1, y = 1;
800 if (seq->args[0] > 0)
802 if (seq->args[1] > 0)
805 screen_cursor_clear_wrap(screen);
806 screen_cursor_set_rel(screen, x - 1, y - 1);
811 static int screen_CUU(term_screen *screen, const term_seq *seq) {
814 * Move the cursor @args[0] positions up. The cursor stops at the
815 * top margin. If it was already moved further, it stops at the
823 unsigned int num = 1;
825 if (seq->args[0] > 0)
828 screen_cursor_clear_wrap(screen);
829 screen_cursor_up(screen, num, false);
834 static int screen_DA1(term_screen *screen, const term_seq *seq) {
836 * DA1 - primary-device-attributes
837 * The primary DA asks for basic terminal features. We simply return
838 * a hard-coded list of features we implement.
839 * Note that the primary DA asks for supported features, not currently
842 * The terminal's answer is:
844 * The first argument, 64, is fixed and denotes a VT420, the last
845 * DEC-term that extended this number.
846 * All following arguments denote supported features. Note
847 * that at most 15 features can be sent (max CSI args). It is safe to
848 * send more, but clients might not be able to parse them. This is a
849 * client's problem and we shouldn't care. There is no other way to
850 * send those feature lists, so we have to extend them beyond 15 in
855 * The 132 column mode is supported by the terminal.
857 * A priner-port is supported and can be addressed via
860 * Support for ReGIS graphics is available. The ReGIS routines
861 * provide the "remote graphics instruction set" and allow basic
864 * Support of Sixel graphics is available. This provides access
865 * to the sixel bitmap routines.
867 * The terminal supports DECSCA and related selective-erase
868 * functions. This allows to protect specific cells from being
869 * erased, if specified.
870 * 7: soft character set (DRCS)
872 * 8: user-defined keys (UDKs)
874 * 9: national-replacement character sets (NRCS)
875 * National-replacement character-sets are available.
876 * 12: Yugoslavian (SCS)
878 * 15: technical character set
879 * The DEC technical-character-set is available.
880 * 18: windowing capability
882 * 21: horizontal scrolling
890 * 29: ANSI text locator
892 * 42: ISO Latin-2 character set
898 * 46: ASCII emulation
902 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "?64;1;6;9;15c");
905 static int screen_DA2(term_screen *screen, const term_seq *seq) {
907 * DA2 - secondary-device-attributes
908 * The secondary DA asks for the terminal-ID, firmware versions and
909 * other non-primary attributes. All these values are
910 * informational-only and should not be used by the host to detect
913 * The terminal's response is:
914 * ^[ > 61 ; FIRMWARE ; KEYBOARD c
915 * whereas 65 is fixed for VT525 terminals, the last terminal-line that
916 * increased this number. FIRMWARE is the firmware
917 * version encoded as major/minor (20 == 2.0) and KEYBOARD is 0 for STD
918 * keyboard and 1 for PC keyboards.
920 * We replace the firmware-version with the systemd-version so clients
921 * can decode it again.
924 return SEQ_WRITE(screen, C0_CSI, C1_CSI, ">65;" PACKAGE_VERSION ";1c");
927 static int screen_DA3(term_screen *screen, const term_seq *seq) {
929 * DA3 - tertiary-device-attributes
930 * The tertiary DA is used to query the terminal-ID.
932 * The terminal's response is:
933 * ^P ! | XX AA BB CC ^\
934 * whereas all four parameters are hexadecimal-encoded pairs. XX
935 * denotes the manufacturing site, AA BB CC is the terminal's ID.
938 /* we do not support tertiary DAs */
942 static int screen_DC1(term_screen *screen, const term_seq *seq) {
944 * DC1 - device-control-1 or XON
945 * This clears any previous XOFF and resumes terminal-transmission.
948 /* we do not support XON */
952 static int screen_DC3(term_screen *screen, const term_seq *seq) {
954 * DC3 - device-control-3 or XOFF
955 * Stops terminal transmission. No further characters are sent until
956 * an XON is received.
959 /* we do not support XOFF */
963 static int screen_DCH(term_screen *screen, const term_seq *seq) {
965 * DCH - delete-character
966 * This deletes @argv[0] characters at the current cursor position. As
967 * characters are deleted, the remaining characters between the cursor
968 * and right margin move to the left. Character attributes move with the
969 * characters. The terminal adds blank spaces with no visual character
970 * attributes at the right margin. DCH has no effect outside the
977 unsigned int num = 1;
979 if (seq->args[0] > 0)
982 screen_cursor_clear_wrap(screen);
983 term_page_delete_cells(screen->page, screen->state.cursor_x, screen->state.cursor_y, num, &screen->state.attr, screen->age);
988 static int screen_DECALN(term_screen *screen, const term_seq *seq) {
990 * DECALN - screen-alignment-pattern
992 * Probably not worth implementing.
998 static int screen_DECANM(term_screen *screen, const term_seq *seq) {
1000 * DECANM - ansi-mode
1001 * Set the terminal into VT52 compatibility mode. Control sequences
1002 * overlap with regular sequences so we have to detect them early before
1005 * Probably not worth implementing.
1011 static int screen_DECBI(term_screen *screen, const term_seq *seq) {
1013 * DECBI - back-index
1014 * This control function moves the cursor backward one column. If the
1015 * cursor is at the left margin, then all screen data within the margin
1016 * moves one column to the right. The column that shifted past the right
1018 * DECBI adds a new column at the left margin with no visual attributes.
1019 * DECBI does not affect the margins. If the cursor is beyond the
1020 * left-margin at the left border, then the terminal ignores DECBI.
1022 * Probably not worth implementing.
1028 static int screen_DECCARA(term_screen *screen, const term_seq *seq) {
1030 * DECCARA - change-attributes-in-rectangular-area
1032 * Probably not worth implementing.
1038 static int screen_DECCRA(term_screen *screen, const term_seq *seq) {
1040 * DECCRA - copy-rectangular-area
1042 * Probably not worth implementing.
1048 static int screen_DECDC(term_screen *screen, const term_seq *seq) {
1050 * DECDC - delete-column
1052 * Probably not worth implementing.
1058 static int screen_DECDHL_BH(term_screen *screen, const term_seq *seq) {
1060 * DECDHL_BH - double-width-double-height-line: bottom half
1062 * Probably not worth implementing.
1068 static int screen_DECDHL_TH(term_screen *screen, const term_seq *seq) {
1070 * DECDHL_TH - double-width-double-height-line: top half
1072 * Probably not worth implementing.
1078 static int screen_DECDWL(term_screen *screen, const term_seq *seq) {
1080 * DECDWL - double-width-single-height-line
1082 * Probably not worth implementing.
1088 static int screen_DECEFR(term_screen *screen, const term_seq *seq) {
1090 * DECEFR - enable-filter-rectangle
1091 * Defines the coordinates of a filter rectangle (top, left, bottom,
1092 * right as @args[0] to @args[3]) and activates it.
1093 * Anytime the locator is detected outside of the filter rectangle, an
1094 * outside rectangle event is generated and the rectangle is disabled.
1095 * Filter rectangles are always treated as "one-shot" events. Any
1096 * parameters that are omitted default to the current locator position.
1097 * If all parameters are omitted, any locator motion will be reported.
1098 * DECELR always cancels any prevous rectangle definition.
1100 * The locator is usually associated with the mouse-cursor, but based
1101 * on cells instead of pixels. See DECELR how to initialize and enable
1102 * it. DECELR can also enable pixel-mode instead of cell-mode.
1110 static int screen_DECELF(term_screen *screen, const term_seq *seq) {
1112 * DECELF - enable-local-functions
1114 * Probably not worth implementing.
1120 static int screen_DECELR(term_screen *screen, const term_seq *seq) {
1122 * DECELR - enable-locator-reporting
1123 * This changes the locator-reporting mode. @args[0] specifies the mode
1124 * to set, 0 disables locator-reporting, 1 enables it continuously, 2
1125 * enables it for a single report. @args[1] specifies the
1126 * precision-mode. 0 and 2 set the reporting to cell-precision, 1 sets
1139 static int screen_DECERA(term_screen *screen, const term_seq *seq) {
1141 * DECERA - erase-rectangular-area
1143 * Probably not worth implementing.
1149 static int screen_DECFI(term_screen *screen, const term_seq *seq) {
1151 * DECFI - forward-index
1152 * This control function moves the cursor forward one column. If the
1153 * cursor is at the right margin, then all screen data within the
1154 * margins moves one column to the left. The column shifted past the
1155 * left margin is lost.
1156 * DECFI adds a new column at the right margin, with no visual
1157 * attributes. DECFI does not affect margins. If the cursor is beyond
1158 * the right margin at the border of the page when the terminal
1159 * receives DECFI, then the terminal ignores DECFI.
1161 * Probably not worth implementing.
1167 static int screen_DECFRA(term_screen *screen, const term_seq *seq) {
1169 * DECFRA - fill-rectangular-area
1171 * Probably not worth implementing.
1177 static int screen_DECIC(term_screen *screen, const term_seq *seq) {
1179 * DECIC - insert-column
1181 * Probably not worth implementing.
1187 static int screen_DECID(term_screen *screen, const term_seq *seq) {
1189 * DECID - return-terminal-id
1190 * This is an obsolete form of TERM_CMD_DA1.
1193 return screen_DA1(screen, seq);
1196 static int screen_DECINVM(term_screen *screen, const term_seq *seq) {
1198 * DECINVM - invoke-macro
1200 * Probably not worth implementing.
1206 static int screen_DECKBD(term_screen *screen, const term_seq *seq) {
1208 * DECKBD - keyboard-language-selection
1210 * Probably not worth implementing.
1216 static int screen_DECKPAM(term_screen *screen, const term_seq *seq) {
1218 * DECKPAM - keypad-application-mode
1219 * Enables the keypad-application mode. If enabled, the keypad sends
1220 * special characters instead of the printed characters. This way,
1221 * applications can detect whether a numeric key was pressed on the
1222 * top-row or on the keypad.
1223 * Default is keypad-numeric-mode.
1226 screen->flags |= TERM_FLAG_KEYPAD_MODE;
1231 static int screen_DECKPNM(term_screen *screen, const term_seq *seq) {
1233 * DECKPNM - keypad-numeric-mode
1234 * This disables the keypad-application-mode (DECKPAM) and returns to
1235 * the keypad-numeric-mode. Keypresses on the keypad generate the same
1236 * sequences as corresponding keypresses on the main keyboard.
1237 * Default is keypad-numeric-mode.
1240 screen->flags &= ~TERM_FLAG_KEYPAD_MODE;
1245 static int screen_DECLFKC(term_screen *screen, const term_seq *seq) {
1247 * DECLFKC - local-function-key-control
1249 * Probably not worth implementing.
1255 static int screen_DECLL(term_screen *screen, const term_seq *seq) {
1259 * Probably not worth implementing.
1265 static int screen_DECLTOD(term_screen *screen, const term_seq *seq) {
1267 * DECLTOD - load-time-of-day
1269 * Probably not worth implementing.
1275 static int screen_DECPCTERM(term_screen *screen, const term_seq *seq) {
1277 * DECPCTERM - pcterm-mode
1278 * This enters/exits the PCTerm mode. Default mode is VT-mode. It can
1279 * also select parameters for scancode/keycode mappings in SCO mode.
1281 * Definitely not worth implementing. Lets kill PCTerm/SCO modes!
1287 static int screen_DECPKA(term_screen *screen, const term_seq *seq) {
1289 * DECPKA - program-key-action
1291 * Probably not worth implementing.
1297 static int screen_DECPKFMR(term_screen *screen, const term_seq *seq) {
1299 * DECPKFMR - program-key-free-memory-report
1301 * Probably not worth implementing.
1307 static int screen_DECRARA(term_screen *screen, const term_seq *seq) {
1309 * DECRARA - reverse-attributes-in-rectangular-area
1311 * Probably not worth implementing.
1317 static int screen_DECRC(term_screen *screen, const term_seq *seq) {
1319 * DECRC - restore-cursor
1320 * Restores the terminal to the state saved by the save cursor (DECSC)
1321 * function. This includes more than just the cursor-position.
1323 * If nothing was saved by DECSC, then DECRC performs the following
1325 * * Moves the cursor to the home position (upper left of screen).
1326 * * Resets origin mode (DECOM).
1327 * * Turns all character attributes off (normal setting).
1328 * * Maps the ASCII character set into GL, and the DEC Supplemental
1329 * Graphic set into GR.
1331 * The terminal maintains a separate DECSC buffer for the main display
1332 * and the status line. This feature lets you save a separate operating
1333 * state for the main display and the status line.
1336 screen_restore_state(screen, &screen->saved);
1341 static int screen_DECREQTPARM(term_screen *screen, const term_seq *seq) {
1343 * DECREQTPARM - request-terminal-parameters
1344 * The sequence DECREPTPARM is sent by the terminal controller to notify
1345 * the host of the status of selected terminal parameters. The status
1346 * sequence may be sent when requested by the host or at the terminal's
1347 * discretion. DECREPTPARM is sent upon receipt of a DECREQTPARM.
1349 * If @args[0] is 0, this marks a request and the terminal is allowed
1350 * to send DECREPTPARM messages without request. If it is 1, the same
1351 * applies but the terminal should no longer send DECREPTPARM
1353 * 2 and 3 mark a report, but 3 is only used if the terminal answers as
1354 * an explicit request with @args[0] == 1.
1356 * The other arguments are ignored in requests, but have the following
1357 * meaning in responses:
1358 * args[1]: 1=no-parity-set 4=parity-set-and-odd 5=parity-set-and-even
1359 * args[2]: 1=8bits-per-char 2=7bits-per-char
1360 * args[3]: transmission-speed
1361 * args[4]: receive-speed
1362 * args[5]: 1=bit-rate-multiplier-is-16
1363 * args[6]: This value communicates the four switch values in block 5
1364 * of SETUP B, which are only visible to the user when an STP
1365 * option is installed. These bits may be assigned for an STP
1366 * device. The four bits are a decimal-encoded binary number.
1367 * Value between 0-15.
1369 * The transmission/receive speeds have mappings for number => bits/s
1370 * which are quite weird. Examples are: 96->3600, 112->9600, 120->19200
1376 if (seq->n_args < 1 || seq->args[0] == 0) {
1377 screen->flags &= ~TERM_FLAG_INHIBIT_TPARM;
1378 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "2;1;1;120;120;1;0x");
1379 } else if (seq->args[0] == 1) {
1380 screen->flags |= TERM_FLAG_INHIBIT_TPARM;
1381 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "3;1;1;120;120;1;0x");
1387 static int screen_DECRPKT(term_screen *screen, const term_seq *seq) {
1389 * DECRPKT - report-key-type
1390 * Response to DECRQKT, we can safely ignore it as we're the one sending
1397 static int screen_DECRQCRA(term_screen *screen, const term_seq *seq) {
1399 * DECRQCRA - request-checksum-of-rectangular-area
1401 * Probably not worth implementing.
1407 static int screen_DECRQDE(term_screen *screen, const term_seq *seq) {
1409 * DECRQDE - request-display-extent
1411 * Probably not worth implementing.
1417 static int screen_DECRQKT(term_screen *screen, const term_seq *seq) {
1419 * DECRQKT - request-key-type
1421 * Probably not worth implementing.
1427 static int screen_DECRQLP(term_screen *screen, const term_seq *seq) {
1429 * DECRQLP - request-locator-position
1430 * See DECELR for locator-information.
1432 * TODO: document and implement
1438 static int screen_DECRQM_ANSI(term_screen *screen, const term_seq *seq) {
1440 * DECRQM_ANSI - request-mode-ansi
1441 * The host sends this control function to find out if a particular mode
1442 * is set or reset. The terminal responds with a report mode function.
1443 * @args[0] contains the mode to query.
1445 * Response is DECRPM with the first argument set to the mode that was
1446 * queried, second argument is 0 if mode is invalid, 1 if mode is set,
1447 * 2 if mode is not set (reset), 3 if mode is permanently set and 4 if
1448 * mode is permanently not set (reset):
1449 * ANSI: ^[ MODE ; VALUE $ y
1450 * DEC: ^[ ? MODE ; VALUE $ y
1458 static int screen_DECRQM_DEC(term_screen *screen, const term_seq *seq) {
1460 * DECRQM_DEC - request-mode-dec
1461 * Same as DECRQM_ANSI but for DEC modes.
1469 static int screen_DECRQPKFM(term_screen *screen, const term_seq *seq) {
1471 * DECRQPKFM - request-program-key-free-memory
1473 * Probably not worth implementing.
1479 static int screen_DECRQPSR(term_screen *screen, const term_seq *seq) {
1481 * DECRQPSR - request-presentation-state-report
1483 * Probably not worth implementing.
1489 static int screen_DECRQTSR(term_screen *screen, const term_seq *seq) {
1491 * DECRQTSR - request-terminal-state-report
1493 * Probably not worth implementing.
1499 static int screen_DECRQUPSS(term_screen *screen, const term_seq *seq) {
1501 * DECRQUPSS - request-user-preferred-supplemental-set
1503 * Probably not worth implementing.
1509 static int screen_DECSACE(term_screen *screen, const term_seq *seq) {
1511 * DECSACE - select-attribute-change-extent
1513 * Probably not worth implementing.
1519 static int screen_DECSASD(term_screen *screen, const term_seq *seq) {
1521 * DECSASD - select-active-status-display
1523 * Probably not worth implementing.
1529 static int screen_DECSC(term_screen *screen, const term_seq *seq) {
1531 * DECSC - save-cursor
1532 * Save cursor and terminal state so it can be restored later on.
1533 * Saves the following items in the terminal's memory:
1535 * * Character attributes set by the SGR command
1536 * * Character sets (G0, G1, G2, or G3) currently in GL and GR
1537 * * Wrap flag (autowrap or no autowrap)
1538 * * State of origin mode (DECOM)
1539 * * Selective erase attribute
1540 * * Any single shift 2 (SS2) or single shift 3 (SS3) functions sent
1543 screen_save_state(screen, &screen->saved);
1548 static int screen_DECSCA(term_screen *screen, const term_seq *seq) {
1550 * DECSCA - select-character-protection-attribute
1551 * Defines the characters that come after it as erasable or not erasable
1552 * from the screen. The selective erase control functions (DECSED and
1553 * DECSEL) can only erase characters defined as erasable.
1555 * @args[0] specifies the new mode. 0 and 2 mark any following character
1556 * as erasable, 1 marks it as not erasable.
1562 unsigned int mode = 0;
1564 if (seq->args[0] > 0)
1565 mode = seq->args[0];
1570 screen->state.attr.protect = 0;
1573 screen->state.attr.protect = 1;
1580 static int screen_DECSCL(term_screen *screen, const term_seq *seq) {
1582 * DECSCL - select-conformance-level
1583 * Select the terminal's operating level. The factory default is
1584 * level 4 (VT Level 4 mode, 7-bit controls).
1585 * When you change the conformance level, the terminal performs a hard
1588 * @args[0] defines the conformance-level, valid values are:
1589 * 61: Level 1 (VT100)
1590 * 62: Level 2 (VT200)
1591 * 63: Level 3 (VT300)
1592 * 64: Level 4 (VT400)
1593 * @args[1] defines the 8bit-mode, valid values are:
1596 * 2: 8-bit controls (same as 0)
1598 * If @args[0] is 61, then @args[1] is ignored and 7bit controls are
1606 unsigned int level = 64, bit = 0;
1608 if (seq->n_args > 0) {
1609 level = seq->args[0];
1610 if (seq->n_args > 1)
1614 term_screen_hard_reset(screen);
1618 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT100;
1619 screen->flags |= TERM_FLAG_7BIT_MODE;
1622 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
1624 screen->flags |= TERM_FLAG_7BIT_MODE;
1626 screen->flags &= ~TERM_FLAG_7BIT_MODE;
1633 static int screen_DECSCP(term_screen *screen, const term_seq *seq) {
1635 * DECSCP - select-communication-port
1637 * Probably not worth implementing.
1643 static int screen_DECSCPP(term_screen *screen, const term_seq *seq) {
1645 * DECSCPP - select-columns-per-page
1646 * Select columns per page. The number of rows is unaffected by this.
1647 * @args[0] selectes the number of columns (width), DEC only defines 80
1648 * and 132, but we allow any integer here. 0 is equivalent to 80.
1649 * Page content is *not* cleared and the cursor is left untouched.
1650 * However, if the page is reduced in width and the cursor would be
1651 * outside the visible region, it's set to the right border. Newly added
1652 * cells are cleared. No data is retained outside the visible region.
1663 static int screen_DECSCS(term_screen *screen, const term_seq *seq) {
1665 * DECSCS - select-communication-speed
1667 * Probably not worth implementing.
1673 static int screen_DECSCUSR(term_screen *screen, const term_seq *seq) {
1675 * DECSCUSR - set-cursor-style
1676 * This changes the style of the cursor. @args[0] can be one of:
1677 * 0, 1: blinking block
1679 * 3: blinking underline
1680 * 4: steady underline
1681 * Changing this setting does _not_ affect the cursor visibility itself.
1682 * Use DECTCEM for that.
1693 static int screen_DECSDDT(term_screen *screen, const term_seq *seq) {
1695 * DECSDDT - select-disconnect-delay-time
1697 * Probably not worth implementing.
1703 static int screen_DECSDPT(term_screen *screen, const term_seq *seq) {
1705 * DECSDPT - select-digital-printed-data-type
1707 * Probably not worth implementing.
1713 static int screen_DECSED(term_screen *screen, const term_seq *seq) {
1715 * DECSED - selective-erase-in-display
1716 * This control function erases some or all of the erasable characters
1717 * in the display. DECSED can only erase characters defined as erasable
1718 * by the DECSCA control function. DECSED works inside or outside the
1719 * scrolling margins.
1721 * @args[0] defines which regions are erased. If it is 0, all cells from
1722 * the cursor (inclusive) till the end of the display are erase. If it
1723 * is 1, all cells from the start of the display till the cursor
1724 * (inclusive) are erased. If it is 2, all cells are erased.
1730 unsigned int mode = 0;
1732 if (seq->args[0] > 0)
1733 mode = seq->args[0];
1737 term_page_erase(screen->page,
1738 screen->state.cursor_x, screen->state.cursor_y,
1739 screen->page->width, screen->page->height,
1740 &screen->state.attr, screen->age, true);
1743 term_page_erase(screen->page,
1745 screen->state.cursor_x, screen->state.cursor_y,
1746 &screen->state.attr, screen->age, true);
1749 term_page_erase(screen->page,
1751 screen->page->width, screen->page->height,
1752 &screen->state.attr, screen->age, true);
1759 static int screen_DECSEL(term_screen *screen, const term_seq *seq) {
1761 * DECSEL - selective-erase-in-line
1762 * This control function erases some or all of the erasable characters
1763 * in a single line of text. DECSEL erases only those characters defined
1764 * as erasable by the DECSCA control function. DECSEL works inside or
1765 * outside the scrolling margins.
1767 * @args[0] defines the region to be erased. If it is 0, all cells from
1768 * the cursor (inclusive) till the end of the line are erase. If it is
1769 * 1, all cells from the start of the line till the cursor (inclusive)
1770 * are erased. If it is 2, the whole line of the cursor is erased.
1776 unsigned int mode = 0;
1778 if (seq->args[0] > 0)
1779 mode = seq->args[0];
1783 term_page_erase(screen->page,
1784 screen->state.cursor_x, screen->state.cursor_y,
1785 screen->page->width, screen->state.cursor_y,
1786 &screen->state.attr, screen->age, true);
1789 term_page_erase(screen->page,
1790 0, screen->state.cursor_y,
1791 screen->state.cursor_x, screen->state.cursor_y,
1792 &screen->state.attr, screen->age, true);
1795 term_page_erase(screen->page,
1796 0, screen->state.cursor_y,
1797 screen->page->width, screen->state.cursor_y,
1798 &screen->state.attr, screen->age, true);
1805 static int screen_DECSERA(term_screen *screen, const term_seq *seq) {
1807 * DECSERA - selective-erase-rectangular-area
1809 * Probably not worth implementing.
1815 static int screen_DECSFC(term_screen *screen, const term_seq *seq) {
1817 * DECSFC - select-flow-control
1819 * Probably not worth implementing.
1825 static int screen_DECSKCV(term_screen *screen, const term_seq *seq) {
1827 * DECSKCV - set-key-click-volume
1829 * Probably not worth implementing.
1835 static int screen_DECSLCK(term_screen *screen, const term_seq *seq) {
1837 * DECSLCK - set-lock-key-style
1839 * Probably not worth implementing.
1845 static int screen_DECSLE(term_screen *screen, const term_seq *seq) {
1847 * DECSLE - select-locator-events
1855 static int screen_DECSLPP(term_screen *screen, const term_seq *seq) {
1857 * DECSLPP - set-lines-per-page
1858 * Set the number of lines used for the page. @args[0] specifies the
1859 * number of lines to be used. DEC only allows a limited number of
1860 * choices, however, we allow all integers. 0 is equivalent to 24.
1871 static int screen_DECSLRM_OR_SC(term_screen *screen, const term_seq *seq) {
1873 * DECSLRM_OR_SC - set-left-and-right-margins or save-cursor
1875 * TODO: Detect save-cursor and run it. DECSLRM is not worth
1882 static int screen_DECSMBV(term_screen *screen, const term_seq *seq) {
1884 * DECSMBV - set-margin-bell-volume
1886 * Probably not worth implementing.
1892 static int screen_DECSMKR(term_screen *screen, const term_seq *seq) {
1894 * DECSMKR - select-modifier-key-reporting
1896 * Probably not worth implementing.
1902 static int screen_DECSNLS(term_screen *screen, const term_seq *seq) {
1904 * DECSNLS - set-lines-per-screen
1906 * Probably not worth implementing.
1912 static int screen_DECSPP(term_screen *screen, const term_seq *seq) {
1914 * DECSPP - set-port-parameter
1916 * Probably not worth implementing.
1922 static int screen_DECSPPCS(term_screen *screen, const term_seq *seq) {
1924 * DECSPPCS - select-pro-printer-character-set
1926 * Probably not worth implementing.
1932 static int screen_DECSPRTT(term_screen *screen, const term_seq *seq) {
1934 * DECSPRTT - select-printer-type
1936 * Probably not worth implementing.
1942 static int screen_DECSR(term_screen *screen, const term_seq *seq) {
1944 * DECSR - secure-reset
1946 * Probably not worth implementing.
1952 static int screen_DECSRFR(term_screen *screen, const term_seq *seq) {
1954 * DECSRFR - select-refresh-rate
1956 * Probably not worth implementing.
1962 static int screen_DECSSCLS(term_screen *screen, const term_seq *seq) {
1964 * DECSSCLS - set-scroll-speed
1966 * Probably not worth implementing.
1972 static int screen_DECSSDT(term_screen *screen, const term_seq *seq) {
1974 * DECSSDT - select-status-display-line-type
1976 * Probably not worth implementing.
1982 static int screen_DECSSL(term_screen *screen, const term_seq *seq) {
1984 * DECSSL - select-setup-language
1986 * Probably not worth implementing.
1992 static int screen_DECST8C(term_screen *screen, const term_seq *seq) {
1994 * DECST8C - set-tab-at-every-8-columns
1995 * Clear the tab-ruler and reset it to a tab at every 8th column,
1996 * starting at 9 (though, setting a tab at 1 is fine as it has no
2002 for (i = 0; i < screen->page->width; i += 8)
2003 screen->tabs[i / 8] = 0x1;
2008 static int screen_DECSTBM(term_screen *screen, const term_seq *seq) {
2010 * DECSTBM - set-top-and-bottom-margins
2011 * This control function sets the top and bottom margins for the current
2012 * page. You cannot perform scrolling outside the margins.
2014 * @args[0] defines the top margin, @args[1] defines the bottom margin.
2015 * The bottom margin must be lower than the top-margin.
2017 * This call resets the cursor position to 0/0 of the page.
2021 * args[1]: last page-line
2024 unsigned int top, bottom;
2027 bottom = screen->page->height;
2029 if (seq->args[0] > 0)
2031 if (seq->args[1] > 0)
2032 bottom = seq->args[1];
2034 if (top > screen->page->height)
2035 top = screen->page->height;
2036 if (bottom > screen->page->height)
2037 bottom = screen->page->height;
2039 if (top >= bottom || top > screen->page->height || bottom > screen->page->height) {
2041 bottom = screen->page->height;
2044 term_page_set_scroll_region(screen->page, top - 1, bottom - top + 1);
2045 screen_cursor_clear_wrap(screen);
2046 screen_cursor_set(screen, 0, 0);
2051 static int screen_DECSTR(term_screen *screen, const term_seq *seq) {
2053 * DECSTR - soft-terminal-reset
2054 * Perform a soft reset to the default values.
2057 term_screen_soft_reset(screen);
2062 static int screen_DECSTRL(term_screen *screen, const term_seq *seq) {
2064 * DECSTRL - set-transmit-rate-limit
2066 * Probably not worth implementing.
2072 static int screen_DECSWBV(term_screen *screen, const term_seq *seq) {
2074 * DECSWBV - set-warning-bell-volume
2076 * Probably not worth implementing.
2082 static int screen_DECSWL(term_screen *screen, const term_seq *seq) {
2084 * DECSWL - single-width-single-height-line
2086 * Probably not worth implementing.
2092 static int screen_DECTID(term_screen *screen, const term_seq *seq) {
2094 * DECTID - select-terminal-id
2096 * Probably not worth implementing.
2102 static int screen_DECTME(term_screen *screen, const term_seq *seq) {
2104 * DECTME - terminal-mode-emulation
2106 * Probably not worth implementing.
2112 static int screen_DECTST(term_screen *screen, const term_seq *seq) {
2114 * DECTST - invoke-confidence-test
2116 * Probably not worth implementing.
2122 static int screen_DL(term_screen *screen, const term_seq *seq) {
2125 * This control function deletes one or more lines in the scrolling
2126 * region, starting with the line that has the cursor. @args[0] defines
2127 * the number of lines to delete. 0 is treated the same as 1.
2128 * As lines are deleted, lines below the cursor and in the scrolling
2129 * region move up. The terminal adds blank lines with no visual
2130 * character attributes at the bottom of the scrolling region. If it is
2131 * greater than the number of lines remaining on the page, DL deletes
2132 * only the remaining lines. DL has no effect outside the scrolling
2139 unsigned int num = 1;
2141 if (seq->args[0] > 0)
2144 term_page_delete_lines(screen->page, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2149 static int screen_DSR_ANSI(term_screen *screen, const term_seq *seq) {
2151 * DSR_ANSI - device-status-report-ansi
2159 static int screen_DSR_DEC(term_screen *screen, const term_seq *seq) {
2161 * DSR_DEC - device-status-report-dec
2169 static int screen_ECH(term_screen *screen, const term_seq *seq) {
2171 * ECH - erase-character
2172 * This control function erases one or more characters, from the cursor
2173 * position to the right. ECH clears character attributes from erased
2174 * character positions. ECH works inside or outside the scrolling
2176 * @args[0] defines the number of characters to erase. 0 is treated the
2183 unsigned int num = 1;
2185 if (seq->args[0] > 0)
2188 term_page_erase(screen->page,
2189 screen->state.cursor_x, screen->state.cursor_y,
2190 screen->state.cursor_x + num, screen->state.cursor_y,
2191 &screen->state.attr, screen->age, false);
2196 static int screen_ED(term_screen *screen, const term_seq *seq) {
2198 * ED - erase-in-display
2199 * This control function erases characters from part or all of the
2200 * display. When you erase complete lines, they become single-height,
2201 * single-width lines, with all visual character attributes cleared. ED
2202 * works inside or outside the scrolling margins.
2204 * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2205 * till the end of the screen. 1 means from the start of the screen till
2206 * the cursor (inclusive) and 2 means the whole screen.
2212 unsigned int mode = 0;
2214 if (seq->args[0] > 0)
2215 mode = seq->args[0];
2219 term_page_erase(screen->page,
2220 screen->state.cursor_x, screen->state.cursor_y,
2221 screen->page->width, screen->page->height,
2222 &screen->state.attr, screen->age, false);
2225 term_page_erase(screen->page,
2227 screen->state.cursor_x, screen->state.cursor_y,
2228 &screen->state.attr, screen->age, false);
2231 term_page_erase(screen->page,
2233 screen->page->width, screen->page->height,
2234 &screen->state.attr, screen->age, false);
2241 static int screen_EL(term_screen *screen, const term_seq *seq) {
2243 * EL - erase-in-line
2244 * This control function erases characters on the line that has the
2245 * cursor. EL clears all character attributes from erased character
2246 * positions. EL works inside or outside the scrolling margins.
2248 * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2249 * till the end of the line. 1 means from the start of the line till the
2250 * cursor (inclusive) and 2 means the whole line.
2256 unsigned int mode = 0;
2258 if (seq->args[0] > 0)
2259 mode = seq->args[0];
2263 term_page_erase(screen->page,
2264 screen->state.cursor_x, screen->state.cursor_y,
2265 screen->page->width, screen->state.cursor_y,
2266 &screen->state.attr, screen->age, false);
2269 term_page_erase(screen->page,
2270 0, screen->state.cursor_y,
2271 screen->state.cursor_x, screen->state.cursor_y,
2272 &screen->state.attr, screen->age, false);
2275 term_page_erase(screen->page,
2276 0, screen->state.cursor_y,
2277 screen->page->width, screen->state.cursor_y,
2278 &screen->state.attr, screen->age, false);
2285 static int screen_ENQ(term_screen *screen, const term_seq *seq) {
2288 * Transmit the answerback-string. If none is set, do nothing.
2291 if (screen->answerback)
2292 return screen_write(screen, screen->answerback, strlen(screen->answerback));
2297 static int screen_EPA(term_screen *screen, const term_seq *seq) {
2299 * EPA - end-of-guarded-area
2301 * TODO: What is this?
2307 static int screen_FF(term_screen *screen, const term_seq *seq) {
2310 * This causes the cursor to jump to the next line. It is treated the
2314 return screen_LF(screen, seq);
2317 static int screen_HPA(term_screen *screen, const term_seq *seq) {
2319 * HPA - horizontal-position-absolute
2320 * HPA causes the active position to be moved to the n-th horizontal
2321 * position of the active line. If an attempt is made to move the active
2322 * position past the last position on the line, then the active position
2323 * stops at the last position on the line.
2325 * @args[0] defines the horizontal position. 0 is treated as 1.
2331 unsigned int num = 1;
2333 if (seq->args[0] > 0)
2336 screen_cursor_clear_wrap(screen);
2337 screen_cursor_set(screen, num - 1, screen->state.cursor_y);
2342 static int screen_HPR(term_screen *screen, const term_seq *seq) {
2344 * HPR - horizontal-position-relative
2345 * HPR causes the active position to be moved to the n-th following
2346 * horizontal position of the active line. If an attempt is made to move
2347 * the active position past the last position on the line, then the
2348 * active position stops at the last position on the line.
2350 * @args[0] defines the horizontal position. 0 is treated as 1.
2356 unsigned int num = 1;
2358 if (seq->args[0] > 0)
2361 screen_cursor_clear_wrap(screen);
2362 screen_cursor_right(screen, num);
2367 static int screen_HT(term_screen *screen, const term_seq *seq) {
2369 * HT - horizontal-tab
2370 * Moves the cursor to the next tab stop. If there are no more tab
2371 * stops, the cursor moves to the right margin. HT does not cause text
2375 screen_cursor_clear_wrap(screen);
2376 screen_cursor_right_tab(screen, 1);
2381 static int screen_HTS(term_screen *screen, const term_seq *seq) {
2383 * HTS - horizontal-tab-set
2384 * HTS sets a horizontal tab stop at the column position indicated by
2385 * the value of the active column when the terminal receives an HTS.
2387 * Executing an HTS does not effect the other horizontal tab stop
2393 pos = screen->state.cursor_x;
2394 if (screen->page->width > 0)
2395 screen->tabs[pos / 8] |= 1U << (pos % 8);
2400 static int screen_HVP(term_screen *screen, const term_seq *seq) {
2402 * HVP - horizontal-and-vertical-position
2403 * This control function works the same as the cursor position (CUP)
2404 * function. Origin mode (DECOM) selects line numbering and the ability
2405 * to move the cursor into margins.
2412 return screen_CUP(screen, seq);
2415 static int screen_ICH(term_screen *screen, const term_seq *seq) {
2417 * ICH - insert-character
2418 * This control function inserts one or more space (SP) characters
2419 * starting at the cursor position. @args[0] is the number of characters
2420 * to insert. 0 is treated as 1.
2422 * The ICH sequence inserts blank characters with the normal
2423 * character attribute. The cursor remains at the beginning of the blank
2424 * characters. Text between the cursor and right margin moves to the
2425 * right. Characters scrolled past the right margin are lost. ICH has no
2426 * effect outside the scrolling margins.
2432 unsigned int num = 1;
2434 if (seq->args[0] > 0)
2437 screen_cursor_clear_wrap(screen);
2438 term_page_insert_cells(screen->page, screen->state.cursor_x, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2443 static int screen_IL(term_screen *screen, const term_seq *seq) {
2446 * This control function inserts one or more blank lines, starting at
2447 * the cursor. @args[0] is the number of lines to insert. 0 is treated
2450 * As lines are inserted, lines below the cursor and in the scrolling
2451 * region move down. Lines scrolled off the page are lost. IL has no
2452 * effect outside the page margins.
2458 unsigned int num = 1;
2460 if (seq->args[0] > 0)
2463 screen_cursor_clear_wrap(screen);
2464 term_page_insert_lines(screen->page, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2469 static int screen_IND(term_screen *screen, const term_seq *seq) {
2472 * IND moves the cursor down one line in the same column. If the cursor
2473 * is at the bottom margin, then the screen performs a scroll-up.
2476 screen_cursor_down(screen, 1, true);
2481 static int screen_LF(term_screen *screen, const term_seq *seq) {
2484 * Causes a line feed or a new line operation, depending on the setting
2485 * of line feed/new line mode.
2488 screen_cursor_down(screen, 1, true);
2489 if (screen->flags & TERM_FLAG_NEWLINE_MODE)
2490 screen_cursor_left(screen, screen->state.cursor_x);
2495 static int screen_LS1R(term_screen *screen, const term_seq *seq) {
2497 * LS1R - locking-shift-1-right
2501 screen->state.gr = &screen->g1;
2506 static int screen_LS2(term_screen *screen, const term_seq *seq) {
2508 * LS2 - locking-shift-2
2512 screen->state.gl = &screen->g2;
2517 static int screen_LS2R(term_screen *screen, const term_seq *seq) {
2519 * LS2R - locking-shift-2-right
2523 screen->state.gr = &screen->g2;
2528 static int screen_LS3(term_screen *screen, const term_seq *seq) {
2530 * LS3 - locking-shift-3
2534 screen->state.gl = &screen->g3;
2539 static int screen_LS3R(term_screen *screen, const term_seq *seq) {
2541 * LS3R - locking-shift-3-right
2545 screen->state.gr = &screen->g3;
2550 static int screen_MC_ANSI(term_screen *screen, const term_seq *seq) {
2552 * MC_ANSI - media-copy-ansi
2554 * Probably not worth implementing.
2560 static int screen_MC_DEC(term_screen *screen, const term_seq *seq) {
2562 * MC_DEC - media-copy-dec
2564 * Probably not worth implementing.
2570 static int screen_NEL(term_screen *screen, const term_seq *seq) {
2573 * Moves cursor to first position on next line. If cursor is at bottom
2574 * margin, then screen performs a scroll-up.
2577 screen_cursor_clear_wrap(screen);
2578 screen_cursor_down(screen, 1, true);
2579 screen_cursor_set(screen, 0, screen->state.cursor_y);
2584 static int screen_NP(term_screen *screen, const term_seq *seq) {
2587 * This control function moves the cursor forward to the home position
2588 * on one of the following pages in page memory. If there is only one
2589 * page, then the terminal ignores NP.
2590 * If NP tries to move the cursor past the last page in memory, then the
2591 * cursor stops at the last page.
2593 * @args[0] defines the number of pages to forward. 0 is treated as 1.
2598 * Probably not worth implementing. We only support a single page.
2604 static int screen_NULL(term_screen *screen, const term_seq *seq) {
2607 * The NULL operation does nothing. ASCII NULL is always ignored.
2613 static int screen_PP(term_screen *screen, const term_seq *seq) {
2615 * PP - preceding-page
2616 * This control function moves the cursor backward to the home position
2617 * on one of the preceding pages in page memory. If there is only one
2618 * page, then the terminal ignores PP.
2619 * If PP tries to move the cursor back farther than the first page in
2620 * memory, then the cursor stops at the first page.
2622 * @args[0] defines the number of pages to go backwards. 0 is treated
2628 * Probably not worth implementing. We only support a single page.
2634 static int screen_PPA(term_screen *screen, const term_seq *seq) {
2636 * PPA - page-position-absolute
2637 * This control function can move the cursor to the corresponding row
2638 * and column on any page in page memory. You select the page by its
2639 * number. If there is only one page, then the terminal ignores PPA.
2641 * @args[0] is the number of the page to move the cursor to. If it is
2642 * greater than the number of the last page in memory, then the cursor
2643 * stops at the last page. If it is less than the number of the first
2644 * page, then the cursor stops at the first page.
2649 * Probably not worth implementing. We only support a single page.
2655 static int screen_PPB(term_screen *screen, const term_seq *seq) {
2657 * PPB - page-position-backward
2658 * This control function moves the cursor backward to the corresponding
2659 * row and column on one of the preceding pages in page memory. If there
2660 * is only one page, then the terminal ignores PPB.
2662 * @args[0] indicates the number of pages to move the cursor backward.
2663 * If it tries to move the cursor back farther than the first page in
2664 * memory, then the cursor stops at the first page. 0 is treated as 1.
2669 * Probably not worth implementing. We only support a single page.
2675 static int screen_PPR(term_screen *screen, const term_seq *seq) {
2677 * PPR - page-position-relative
2678 * This control function moves the cursor forward to the corresponding
2679 * row and column on one of the following pages in page memory. If there
2680 * is only one page, then the terminal ignores PPR.
2682 * @args[0] indicates how many pages to move the cursor forward. If it
2683 * tries to move the cursor beyond the last page in memory, then the
2684 * cursor stops at the last page. 0 is treated as 1.
2689 * Probably not worth implementing. We only support a single page.
2695 static int screen_RC(term_screen *screen, const term_seq *seq) {
2697 * RC - restore-cursor
2700 return screen_DECRC(screen, seq);
2703 static int screen_REP(term_screen *screen, const term_seq *seq) {
2706 * Repeat the preceding graphics-character the given number of times.
2707 * @args[0] specifies how often it shall be repeated. 0 is treated as 1.
2712 * Probably not worth implementing.
2718 static int screen_RI(term_screen *screen, const term_seq *seq) {
2720 * RI - reverse-index
2721 * Moves the cursor up one line in the same column. If the cursor is at
2722 * the top margin, the page scrolls down.
2725 screen_cursor_up(screen, 1, true);
2730 static int screen_RIS(term_screen *screen, const term_seq *seq) {
2732 * RIS - reset-to-initial-state
2733 * This control function causes a nonvolatile memory (NVR) recall to
2734 * occur. RIS replaces all set-up features with their saved settings.
2736 * The terminal stores these saved settings in NVR memory. The saved
2737 * setting for a feature is the same as the factory-default setting,
2738 * unless you saved a new setting.
2741 term_screen_hard_reset(screen);
2746 static int screen_RM_ANSI(term_screen *screen, const term_seq *seq) {
2748 * RM_ANSI - reset-mode-ansi
2750 * TODO: implement (see VT510rm manual)
2755 for (i = 0; i < seq->n_args; ++i)
2756 screen_mode_change_ansi(screen, seq->args[i], false);
2761 static int screen_RM_DEC(term_screen *screen, const term_seq *seq) {
2763 * RM_DEC - reset-mode-dec
2764 * This is the same as RM_ANSI but for DEC modes.
2769 for (i = 0; i < seq->n_args; ++i)
2770 screen_mode_change_dec(screen, seq->args[i], false);
2775 static int screen_S7C1T(term_screen *screen, const term_seq *seq) {
2777 * S7C1T - set-7bit-c1-terminal
2778 * This causes the terminal to start sending C1 controls as 7bit
2779 * sequences instead of 8bit C1 controls.
2780 * This is ignored if the terminal is below level-2 emulation mode
2781 * (VT100 and below), the terminal already sends 7bit controls then.
2784 if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2785 screen->flags |= TERM_FLAG_7BIT_MODE;
2790 static int screen_S8C1T(term_screen *screen, const term_seq *seq) {
2792 * S8C1T - set-8bit-c1-terminal
2793 * This causes the terminal to start sending C1 controls as 8bit C1
2794 * control instead of 7bit sequences.
2795 * This is ignored if the terminal is below level-2 emulation mode
2796 * (VT100 and below). The terminal always sends 7bit controls in those
2800 if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2801 screen->flags &= ~TERM_FLAG_7BIT_MODE;
2806 static int screen_SCS(term_screen *screen, const term_seq *seq) {
2808 * SCS - select-character-set
2809 * Designate character sets to G-sets. The mapping from intermediates
2810 * and terminal characters in the escape sequence to G-sets and
2811 * character-sets is non-trivial and implemented separately. See there
2812 * for more information.
2813 * This call simply sets the selected G-set to the desired
2817 term_charset *cs = NULL;
2819 /* TODO: support more of them? */
2820 switch (seq->charset) {
2821 case TERM_CHARSET_ISO_LATIN1_SUPPLEMENTAL:
2822 case TERM_CHARSET_ISO_LATIN2_SUPPLEMENTAL:
2823 case TERM_CHARSET_ISO_LATIN5_SUPPLEMENTAL:
2824 case TERM_CHARSET_ISO_GREEK_SUPPLEMENTAL:
2825 case TERM_CHARSET_ISO_HEBREW_SUPPLEMENTAL:
2826 case TERM_CHARSET_ISO_LATIN_CYRILLIC:
2829 case TERM_CHARSET_DEC_SPECIAL_GRAPHIC:
2830 cs = &term_dec_special_graphics;
2832 case TERM_CHARSET_DEC_SUPPLEMENTAL:
2833 cs = &term_dec_supplemental_graphics;
2835 case TERM_CHARSET_DEC_TECHNICAL:
2836 case TERM_CHARSET_CYRILLIC_DEC:
2837 case TERM_CHARSET_DUTCH_NRCS:
2838 case TERM_CHARSET_FINNISH_NRCS:
2839 case TERM_CHARSET_FRENCH_NRCS:
2840 case TERM_CHARSET_FRENCH_CANADIAN_NRCS:
2841 case TERM_CHARSET_GERMAN_NRCS:
2842 case TERM_CHARSET_GREEK_DEC:
2843 case TERM_CHARSET_GREEK_NRCS:
2844 case TERM_CHARSET_HEBREW_DEC:
2845 case TERM_CHARSET_HEBREW_NRCS:
2846 case TERM_CHARSET_ITALIAN_NRCS:
2847 case TERM_CHARSET_NORWEGIAN_DANISH_NRCS:
2848 case TERM_CHARSET_PORTUGUESE_NRCS:
2849 case TERM_CHARSET_RUSSIAN_NRCS:
2850 case TERM_CHARSET_SCS_NRCS:
2851 case TERM_CHARSET_SPANISH_NRCS:
2852 case TERM_CHARSET_SWEDISH_NRCS:
2853 case TERM_CHARSET_SWISS_NRCS:
2854 case TERM_CHARSET_TURKISH_DEC:
2855 case TERM_CHARSET_TURKISH_NRCS:
2858 case TERM_CHARSET_USERPREF_SUPPLEMENTAL:
2862 if (seq->intermediates & TERM_SEQ_FLAG_POPEN)
2863 screen->g0 = cs ? : &term_unicode_lower;
2864 else if (seq->intermediates & TERM_SEQ_FLAG_PCLOSE)
2865 screen->g1 = cs ? : &term_unicode_upper;
2866 else if (seq->intermediates & TERM_SEQ_FLAG_MULT)
2867 screen->g2 = cs ? : &term_unicode_lower;
2868 else if (seq->intermediates & TERM_SEQ_FLAG_PLUS)
2869 screen->g3 = cs ? : &term_unicode_upper;
2870 else if (seq->intermediates & TERM_SEQ_FLAG_MINUS)
2871 screen->g1 = cs ? : &term_unicode_upper;
2872 else if (seq->intermediates & TERM_SEQ_FLAG_DOT)
2873 screen->g2 = cs ? : &term_unicode_lower;
2874 else if (seq->intermediates & TERM_SEQ_FLAG_SLASH)
2875 screen->g3 = cs ? : &term_unicode_upper;
2880 static int screen_SD(term_screen *screen, const term_seq *seq) {
2883 * This control function moves the user window down a specified number
2884 * of lines in page memory.
2885 * @args[0] is the number of lines to move the
2886 * user window up in page memory. New lines appear at the top of the
2887 * display. Old lines disappear at the bottom of the display. You
2888 * cannot pan past the top margin of the current page. 0 is treated
2895 unsigned int num = 1;
2897 if (seq->args[0] > 0)
2900 term_page_scroll_down(screen->page, num, &screen->state.attr, screen->age, NULL);
2905 static int screen_SGR(term_screen *screen, const term_seq *seq) {
2907 * SGR - select-graphics-rendition
2911 unsigned int i, code;
2914 if (seq->n_args < 1) {
2915 zero(screen->state.attr);
2919 for (i = 0; i < seq->n_args; ++i) {
2923 screen->state.attr.bold = 1;
2926 screen->state.attr.italic = 1;
2929 screen->state.attr.underline = 1;
2932 screen->state.attr.blink = 1;
2935 screen->state.attr.inverse = 1;
2938 screen->state.attr.hidden = 1;
2941 screen->state.attr.bold = 0;
2944 screen->state.attr.italic = 0;
2947 screen->state.attr.underline = 0;
2950 screen->state.attr.blink = 0;
2953 screen->state.attr.inverse = 0;
2956 screen->state.attr.hidden = 0;
2959 screen->state.attr.fg.ccode = v - 30 + TERM_CCODE_BLACK;
2962 screen->state.attr.fg.ccode = 0;
2965 screen->state.attr.bg.ccode = v - 40 + TERM_CCODE_BLACK;
2968 screen->state.attr.bg.ccode = 0;
2971 screen->state.attr.fg.ccode = v - 90 + TERM_CCODE_LIGHT_BLACK;
2974 screen->state.attr.bg.ccode = v - 100 + TERM_CCODE_LIGHT_BLACK;
2981 dst = &screen->state.attr.fg;
2983 dst = &screen->state.attr.bg;
2986 if (i >= seq->n_args)
2989 switch (seq->args[i]) {
2991 /* 24bit-color support */
2994 if (i >= seq->n_args)
2997 dst->ccode = TERM_CCODE_RGB;
2998 dst->red = (seq->args[i - 2] >= 0) ? seq->args[i - 2] : 0;
2999 dst->green = (seq->args[i - 1] >= 0) ? seq->args[i - 1] : 0;
3000 dst->blue = (seq->args[i] >= 0) ? seq->args[i] : 0;
3004 /* 256-color support */
3007 if (i >= seq->n_args || seq->args[i] < 0)
3010 dst->ccode = TERM_CCODE_256;
3011 code = seq->args[i];
3012 dst->c256 = code < 256 ? code : 0;
3021 zero(screen->state.attr);
3029 static int screen_SI(term_screen *screen, const term_seq *seq) {
3035 screen->state.gl = &screen->g0;
3040 static int screen_SM_ANSI(term_screen *screen, const term_seq *seq) {
3042 * SM_ANSI - set-mode-ansi
3049 for (i = 0; i < seq->n_args; ++i)
3050 screen_mode_change_ansi(screen, seq->args[i], true);
3055 static int screen_SM_DEC(term_screen *screen, const term_seq *seq) {
3057 * SM_DEC - set-mode-dec
3058 * This is the same as SM_ANSI but for DEC modes.
3063 for (i = 0; i < seq->n_args; ++i)
3064 screen_mode_change_dec(screen, seq->args[i], true);
3069 static int screen_SO(term_screen *screen, const term_seq *seq) {
3075 screen->state.gl = &screen->g1;
3080 static int screen_SPA(term_screen *screen, const term_seq *seq) {
3082 * SPA - start-of-protected-area
3084 * TODO: What is this?
3090 static int screen_SS2(term_screen *screen, const term_seq *seq) {
3092 * SS2 - single-shift-2
3093 * Temporarily map G2 into GL for the next graphics character.
3096 screen->state.glt = &screen->g2;
3101 static int screen_SS3(term_screen *screen, const term_seq *seq) {
3103 * SS3 - single-shift-3
3104 * Temporarily map G3 into GL for the next graphics character
3107 screen->state.glt = &screen->g3;
3112 static int screen_ST(term_screen *screen, const term_seq *seq) {
3114 * ST - string-terminator
3115 * The string-terminator is usually part of control-sequences and
3116 * handled by the parser. In all other situations it is silently
3123 static int screen_SU(term_screen *screen, const term_seq *seq) {
3126 * This control function moves the user window up a specified number of
3127 * lines in page memory.
3128 * @args[0] is the number of lines to move the
3129 * user window down in page memory. New lines appear at the bottom of
3130 * the display. Old lines disappear at the top of the display. You
3131 * cannot pan past the bottom margin of the current page. 0 is treated
3138 unsigned int num = 1;
3140 if (seq->args[0] > 0)
3143 term_page_scroll_up(screen->page, num, &screen->state.attr, screen->age, screen->history);
3148 static int screen_SUB(term_screen *screen, const term_seq *seq) {
3151 * Cancel the current control-sequence and print a replacement
3152 * character. Our parser already handles this so all we have to do is
3153 * print the replacement character.
3156 static const term_seq rep = {
3157 .type = TERM_SEQ_GRAPHIC,
3158 .command = TERM_CMD_GRAPHIC,
3159 .terminator = 0xfffd,
3162 return screen_GRAPHIC(screen, &rep);
3165 static int screen_TBC(term_screen *screen, const term_seq *seq) {
3168 * This clears tab-stops. If @args[0] is 0, the tab-stop at the current
3169 * cursor position is cleared. If it is 3, all tab stops are cleared.
3175 unsigned int mode = 0, pos;
3177 if (seq->args[0] > 0)
3178 mode = seq->args[0];
3182 pos = screen->state.cursor_x;
3183 if (screen->page->width > 0)
3184 screen->tabs[pos / 8] &= ~(1U << (pos % 8));
3187 if (screen->page->width > 0)
3188 memzero(screen->tabs, (screen->page->width + 7) / 8);
3195 static int screen_VPA(term_screen *screen, const term_seq *seq) {
3197 * VPA - vertical-line-position-absolute
3198 * VPA causes the active position to be moved to the corresponding
3199 * horizontal position. @args[0] specifies the line to jump to. If an
3200 * attempt is made to move the active position below the last line, then
3201 * the active position stops on the last line. 0 is treated as 1.
3207 unsigned int pos = 1;
3209 if (seq->args[0] > 0)
3212 screen_cursor_clear_wrap(screen);
3213 screen_cursor_set_rel(screen, screen->state.cursor_x, pos - 1);
3218 static int screen_VPR(term_screen *screen, const term_seq *seq) {
3220 * VPR - vertical-line-position-relative
3221 * VPR causes the active position to be moved to the corresponding
3222 * horizontal position. @args[0] specifies the number of lines to jump
3223 * down relative to the current cursor position. If an attempt is made
3224 * to move the active position below the last line, the active position
3225 * stops at the last line. 0 is treated as 1.
3231 unsigned int num = 1;
3233 if (seq->args[0] > 0)
3236 screen_cursor_clear_wrap(screen);
3237 screen_cursor_down(screen, num, false);
3242 static int screen_VT(term_screen *screen, const term_seq *seq) {
3245 * This causes a vertical jump by one line. Terminals treat it exactly
3249 return screen_LF(screen, seq);
3252 static int screen_XTERM_CLLHP(term_screen *screen, const term_seq *seq) {
3254 * XTERM_CLLHP - xterm-cursor-lower-left-hp-bugfix
3255 * Move the cursor to the lower-left corner of the page. This is an HP
3258 * Probably not worth implementing.
3264 static int screen_XTERM_IHMT(term_screen *screen, const term_seq *seq) {
3266 * XTERM_IHMT - xterm-initiate-highlight-mouse-tracking
3268 * Probably not worth implementing.
3274 static int screen_XTERM_MLHP(term_screen *screen, const term_seq *seq) {
3276 * XTERM_MLHP - xterm-memory-lock-hp-bugfix
3278 * Probably not worth implementing.
3284 static int screen_XTERM_MUHP(term_screen *screen, const term_seq *seq) {
3286 * XTERM_MUHP - xterm-memory-unlock-hp-bugfix
3288 * Probably not worth implementing.
3294 static int screen_XTERM_RPM(term_screen *screen, const term_seq *seq) {
3296 * XTERM_RPM - xterm-restore-private-mode
3298 * Probably not worth implementing.
3304 static int screen_XTERM_RRV(term_screen *screen, const term_seq *seq) {
3306 * XTERM_RRV - xterm-reset-resource-value
3308 * Probably not worth implementing.
3314 static int screen_XTERM_RTM(term_screen *screen, const term_seq *seq) {
3316 * XTERM_RTM - xterm-reset-title-mode
3318 * Probably not worth implementing.
3324 static int screen_XTERM_SACL1(term_screen *screen, const term_seq *seq) {
3326 * XTERM_SACL1 - xterm-set-ansi-conformance-level-1
3328 * Probably not worth implementing.
3334 static int screen_XTERM_SACL2(term_screen *screen, const term_seq *seq) {
3336 * XTERM_SACL2 - xterm-set-ansi-conformance-level-2
3338 * Probably not worth implementing.
3344 static int screen_XTERM_SACL3(term_screen *screen, const term_seq *seq) {
3346 * XTERM_SACL3 - xterm-set-ansi-conformance-level-3
3348 * Probably not worth implementing.
3354 static int screen_XTERM_SDCS(term_screen *screen, const term_seq *seq) {
3356 * XTERM_SDCS - xterm-set-default-character-set
3357 * Select the default character set. We treat this the same as UTF-8 as
3358 * this is our default character set. As we always use UTF-8, this
3365 static int screen_XTERM_SGFX(term_screen *screen, const term_seq *seq) {
3367 * XTERM_SGFX - xterm-sixel-graphics
3369 * Probably not worth implementing.
3375 static int screen_XTERM_SPM(term_screen *screen, const term_seq *seq) {
3377 * XTERM_SPM - xterm-set-private-mode
3379 * Probably not worth implementing.
3385 static int screen_XTERM_SRV(term_screen *screen, const term_seq *seq) {
3387 * XTERM_SRV - xterm-set-resource-value
3389 * Probably not worth implementing.
3395 static int screen_XTERM_STM(term_screen *screen, const term_seq *seq) {
3397 * XTERM_STM - xterm-set-title-mode
3399 * Probably not worth implementing.
3405 static int screen_XTERM_SUCS(term_screen *screen, const term_seq *seq) {
3407 * XTERM_SUCS - xterm-select-utf8-character-set
3408 * Select UTF-8 as character set. This is our default on only character
3409 * set. Hence, this is a no-op.
3415 static int screen_XTERM_WM(term_screen *screen, const term_seq *seq) {
3417 * XTERM_WM - xterm-window-management
3419 * Probably not worth implementing.
3427 * The screen_feed_*() handlers take data from the user and feed it into the
3428 * screen. Once the parser has detected a sequence, we parse the command-type
3429 * and forward it to the command-dispatchers.
3432 static int screen_feed_cmd(term_screen *screen, const term_seq *seq) {
3433 switch (seq->command) {
3434 case TERM_CMD_GRAPHIC:
3435 return screen_GRAPHIC(screen, seq);
3437 return screen_BEL(screen, seq);
3439 return screen_BS(screen, seq);
3441 return screen_CBT(screen, seq);
3443 return screen_CHA(screen, seq);
3445 return screen_CHT(screen, seq);
3447 return screen_CNL(screen, seq);
3449 return screen_CPL(screen, seq);
3451 return screen_CR(screen, seq);
3453 return screen_CUB(screen, seq);
3455 return screen_CUD(screen, seq);
3457 return screen_CUF(screen, seq);
3459 return screen_CUP(screen, seq);
3461 return screen_CUU(screen, seq);
3463 return screen_DA1(screen, seq);
3465 return screen_DA2(screen, seq);
3467 return screen_DA3(screen, seq);
3469 return screen_DC1(screen, seq);
3471 return screen_DC3(screen, seq);
3473 return screen_DCH(screen, seq);
3474 case TERM_CMD_DECALN:
3475 return screen_DECALN(screen, seq);
3476 case TERM_CMD_DECANM:
3477 return screen_DECANM(screen, seq);
3478 case TERM_CMD_DECBI:
3479 return screen_DECBI(screen, seq);
3480 case TERM_CMD_DECCARA:
3481 return screen_DECCARA(screen, seq);
3482 case TERM_CMD_DECCRA:
3483 return screen_DECCRA(screen, seq);
3484 case TERM_CMD_DECDC:
3485 return screen_DECDC(screen, seq);
3486 case TERM_CMD_DECDHL_BH:
3487 return screen_DECDHL_BH(screen, seq);
3488 case TERM_CMD_DECDHL_TH:
3489 return screen_DECDHL_TH(screen, seq);
3490 case TERM_CMD_DECDWL:
3491 return screen_DECDWL(screen, seq);
3492 case TERM_CMD_DECEFR:
3493 return screen_DECEFR(screen, seq);
3494 case TERM_CMD_DECELF:
3495 return screen_DECELF(screen, seq);
3496 case TERM_CMD_DECELR:
3497 return screen_DECELR(screen, seq);
3498 case TERM_CMD_DECERA:
3499 return screen_DECERA(screen, seq);
3500 case TERM_CMD_DECFI:
3501 return screen_DECFI(screen, seq);
3502 case TERM_CMD_DECFRA:
3503 return screen_DECFRA(screen, seq);
3504 case TERM_CMD_DECIC:
3505 return screen_DECIC(screen, seq);
3506 case TERM_CMD_DECID:
3507 return screen_DECID(screen, seq);
3508 case TERM_CMD_DECINVM:
3509 return screen_DECINVM(screen, seq);
3510 case TERM_CMD_DECKBD:
3511 return screen_DECKBD(screen, seq);
3512 case TERM_CMD_DECKPAM:
3513 return screen_DECKPAM(screen, seq);
3514 case TERM_CMD_DECKPNM:
3515 return screen_DECKPNM(screen, seq);
3516 case TERM_CMD_DECLFKC:
3517 return screen_DECLFKC(screen, seq);
3518 case TERM_CMD_DECLL:
3519 return screen_DECLL(screen, seq);
3520 case TERM_CMD_DECLTOD:
3521 return screen_DECLTOD(screen, seq);
3522 case TERM_CMD_DECPCTERM:
3523 return screen_DECPCTERM(screen, seq);
3524 case TERM_CMD_DECPKA:
3525 return screen_DECPKA(screen, seq);
3526 case TERM_CMD_DECPKFMR:
3527 return screen_DECPKFMR(screen, seq);
3528 case TERM_CMD_DECRARA:
3529 return screen_DECRARA(screen, seq);
3530 case TERM_CMD_DECRC:
3531 return screen_DECRC(screen, seq);
3532 case TERM_CMD_DECREQTPARM:
3533 return screen_DECREQTPARM(screen, seq);
3534 case TERM_CMD_DECRPKT:
3535 return screen_DECRPKT(screen, seq);
3536 case TERM_CMD_DECRQCRA:
3537 return screen_DECRQCRA(screen, seq);
3538 case TERM_CMD_DECRQDE:
3539 return screen_DECRQDE(screen, seq);
3540 case TERM_CMD_DECRQKT:
3541 return screen_DECRQKT(screen, seq);
3542 case TERM_CMD_DECRQLP:
3543 return screen_DECRQLP(screen, seq);
3544 case TERM_CMD_DECRQM_ANSI:
3545 return screen_DECRQM_ANSI(screen, seq);
3546 case TERM_CMD_DECRQM_DEC:
3547 return screen_DECRQM_DEC(screen, seq);
3548 case TERM_CMD_DECRQPKFM:
3549 return screen_DECRQPKFM(screen, seq);
3550 case TERM_CMD_DECRQPSR:
3551 return screen_DECRQPSR(screen, seq);
3552 case TERM_CMD_DECRQTSR:
3553 return screen_DECRQTSR(screen, seq);
3554 case TERM_CMD_DECRQUPSS:
3555 return screen_DECRQUPSS(screen, seq);
3556 case TERM_CMD_DECSACE:
3557 return screen_DECSACE(screen, seq);
3558 case TERM_CMD_DECSASD:
3559 return screen_DECSASD(screen, seq);
3560 case TERM_CMD_DECSC:
3561 return screen_DECSC(screen, seq);
3562 case TERM_CMD_DECSCA:
3563 return screen_DECSCA(screen, seq);
3564 case TERM_CMD_DECSCL:
3565 return screen_DECSCL(screen, seq);
3566 case TERM_CMD_DECSCP:
3567 return screen_DECSCP(screen, seq);
3568 case TERM_CMD_DECSCPP:
3569 return screen_DECSCPP(screen, seq);
3570 case TERM_CMD_DECSCS:
3571 return screen_DECSCS(screen, seq);
3572 case TERM_CMD_DECSCUSR:
3573 return screen_DECSCUSR(screen, seq);
3574 case TERM_CMD_DECSDDT:
3575 return screen_DECSDDT(screen, seq);
3576 case TERM_CMD_DECSDPT:
3577 return screen_DECSDPT(screen, seq);
3578 case TERM_CMD_DECSED:
3579 return screen_DECSED(screen, seq);
3580 case TERM_CMD_DECSEL:
3581 return screen_DECSEL(screen, seq);
3582 case TERM_CMD_DECSERA:
3583 return screen_DECSERA(screen, seq);
3584 case TERM_CMD_DECSFC:
3585 return screen_DECSFC(screen, seq);
3586 case TERM_CMD_DECSKCV:
3587 return screen_DECSKCV(screen, seq);
3588 case TERM_CMD_DECSLCK:
3589 return screen_DECSLCK(screen, seq);
3590 case TERM_CMD_DECSLE:
3591 return screen_DECSLE(screen, seq);
3592 case TERM_CMD_DECSLPP:
3593 return screen_DECSLPP(screen, seq);
3594 case TERM_CMD_DECSLRM_OR_SC:
3595 return screen_DECSLRM_OR_SC(screen, seq);
3596 case TERM_CMD_DECSMBV:
3597 return screen_DECSMBV(screen, seq);
3598 case TERM_CMD_DECSMKR:
3599 return screen_DECSMKR(screen, seq);
3600 case TERM_CMD_DECSNLS:
3601 return screen_DECSNLS(screen, seq);
3602 case TERM_CMD_DECSPP:
3603 return screen_DECSPP(screen, seq);
3604 case TERM_CMD_DECSPPCS:
3605 return screen_DECSPPCS(screen, seq);
3606 case TERM_CMD_DECSPRTT:
3607 return screen_DECSPRTT(screen, seq);
3608 case TERM_CMD_DECSR:
3609 return screen_DECSR(screen, seq);
3610 case TERM_CMD_DECSRFR:
3611 return screen_DECSRFR(screen, seq);
3612 case TERM_CMD_DECSSCLS:
3613 return screen_DECSSCLS(screen, seq);
3614 case TERM_CMD_DECSSDT:
3615 return screen_DECSSDT(screen, seq);
3616 case TERM_CMD_DECSSL:
3617 return screen_DECSSL(screen, seq);
3618 case TERM_CMD_DECST8C:
3619 return screen_DECST8C(screen, seq);
3620 case TERM_CMD_DECSTBM:
3621 return screen_DECSTBM(screen, seq);
3622 case TERM_CMD_DECSTR:
3623 return screen_DECSTR(screen, seq);
3624 case TERM_CMD_DECSTRL:
3625 return screen_DECSTRL(screen, seq);
3626 case TERM_CMD_DECSWBV:
3627 return screen_DECSWBV(screen, seq);
3628 case TERM_CMD_DECSWL:
3629 return screen_DECSWL(screen, seq);
3630 case TERM_CMD_DECTID:
3631 return screen_DECTID(screen, seq);
3632 case TERM_CMD_DECTME:
3633 return screen_DECTME(screen, seq);
3634 case TERM_CMD_DECTST:
3635 return screen_DECTST(screen, seq);
3637 return screen_DL(screen, seq);
3638 case TERM_CMD_DSR_ANSI:
3639 return screen_DSR_ANSI(screen, seq);
3640 case TERM_CMD_DSR_DEC:
3641 return screen_DSR_DEC(screen, seq);
3643 return screen_ECH(screen, seq);
3645 return screen_ED(screen, seq);
3647 return screen_EL(screen, seq);
3649 return screen_ENQ(screen, seq);
3651 return screen_EPA(screen, seq);
3653 return screen_FF(screen, seq);
3655 return screen_HPA(screen, seq);
3657 return screen_HPR(screen, seq);
3659 return screen_HT(screen, seq);
3661 return screen_HTS(screen, seq);
3663 return screen_HVP(screen, seq);
3665 return screen_ICH(screen, seq);
3667 return screen_IL(screen, seq);
3669 return screen_IND(screen, seq);
3671 return screen_LF(screen, seq);
3673 return screen_LS1R(screen, seq);
3675 return screen_LS2(screen, seq);
3677 return screen_LS2R(screen, seq);
3679 return screen_LS3(screen, seq);
3681 return screen_LS3R(screen, seq);
3682 case TERM_CMD_MC_ANSI:
3683 return screen_MC_ANSI(screen, seq);
3684 case TERM_CMD_MC_DEC:
3685 return screen_MC_DEC(screen, seq);
3687 return screen_NEL(screen, seq);
3689 return screen_NP(screen, seq);
3691 return screen_NULL(screen, seq);
3693 return screen_PP(screen, seq);
3695 return screen_PPA(screen, seq);
3697 return screen_PPB(screen, seq);
3699 return screen_PPR(screen, seq);
3701 return screen_RC(screen, seq);
3703 return screen_REP(screen, seq);
3705 return screen_RI(screen, seq);
3707 return screen_RIS(screen, seq);
3708 case TERM_CMD_RM_ANSI:
3709 return screen_RM_ANSI(screen, seq);
3710 case TERM_CMD_RM_DEC:
3711 return screen_RM_DEC(screen, seq);
3712 case TERM_CMD_S7C1T:
3713 return screen_S7C1T(screen, seq);
3714 case TERM_CMD_S8C1T:
3715 return screen_S8C1T(screen, seq);
3717 return screen_SCS(screen, seq);
3719 return screen_SD(screen, seq);
3721 return screen_SGR(screen, seq);
3723 return screen_SI(screen, seq);
3724 case TERM_CMD_SM_ANSI:
3725 return screen_SM_ANSI(screen, seq);
3726 case TERM_CMD_SM_DEC:
3727 return screen_SM_DEC(screen, seq);
3729 return screen_SO(screen, seq);
3731 return screen_SPA(screen, seq);
3733 return screen_SS2(screen, seq);
3735 return screen_SS3(screen, seq);
3737 return screen_ST(screen, seq);
3739 return screen_SU(screen, seq);
3741 return screen_SUB(screen, seq);
3743 return screen_TBC(screen, seq);
3745 return screen_VPA(screen, seq);
3747 return screen_VPR(screen, seq);
3749 return screen_VT(screen, seq);
3750 case TERM_CMD_XTERM_CLLHP:
3751 return screen_XTERM_CLLHP(screen, seq);
3752 case TERM_CMD_XTERM_IHMT:
3753 return screen_XTERM_IHMT(screen, seq);
3754 case TERM_CMD_XTERM_MLHP:
3755 return screen_XTERM_MLHP(screen, seq);
3756 case TERM_CMD_XTERM_MUHP:
3757 return screen_XTERM_MUHP(screen, seq);
3758 case TERM_CMD_XTERM_RPM:
3759 return screen_XTERM_RPM(screen, seq);
3760 case TERM_CMD_XTERM_RRV:
3761 return screen_XTERM_RRV(screen, seq);
3762 case TERM_CMD_XTERM_RTM:
3763 return screen_XTERM_RTM(screen, seq);
3764 case TERM_CMD_XTERM_SACL1:
3765 return screen_XTERM_SACL1(screen, seq);
3766 case TERM_CMD_XTERM_SACL2:
3767 return screen_XTERM_SACL2(screen, seq);
3768 case TERM_CMD_XTERM_SACL3:
3769 return screen_XTERM_SACL3(screen, seq);
3770 case TERM_CMD_XTERM_SDCS:
3771 return screen_XTERM_SDCS(screen, seq);
3772 case TERM_CMD_XTERM_SGFX:
3773 return screen_XTERM_SGFX(screen, seq);
3774 case TERM_CMD_XTERM_SPM:
3775 return screen_XTERM_SPM(screen, seq);
3776 case TERM_CMD_XTERM_SRV:
3777 return screen_XTERM_SRV(screen, seq);
3778 case TERM_CMD_XTERM_STM:
3779 return screen_XTERM_STM(screen, seq);
3780 case TERM_CMD_XTERM_SUCS:
3781 return screen_XTERM_SUCS(screen, seq);
3782 case TERM_CMD_XTERM_WM:
3783 return screen_XTERM_WM(screen, seq);
3789 unsigned int term_screen_get_width(term_screen *screen) {
3790 assert_return(screen, -EINVAL);
3792 return screen->page->width;
3795 unsigned int term_screen_get_height(term_screen *screen) {
3796 assert_return(screen, -EINVAL);
3798 return screen->page->height;
3801 uint64_t term_screen_get_age(term_screen *screen) {
3802 assert_return(screen, 0);
3807 int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size) {
3809 size_t i, j, ucs4_len;
3810 const term_seq *seq;
3813 assert_return(screen, -EINVAL);
3817 /* Feed bytes into utf8 decoder and handle parsed ucs4 chars. We always
3818 * treat data as UTF-8, but the parser makes sure to fall back to raw
3819 * 8bit mode if the stream is not valid UTF-8. This should be more than
3820 * enough to support old 7bit/8bit modes. */
3821 for (i = 0; i < size; ++i) {
3822 ucs4_len = term_utf8_decode(&screen->utf8, &ucs4_str, in[i]);
3823 for (j = 0; j < ucs4_len; ++j) {
3824 r = term_parser_feed(screen->parser, &seq, ucs4_str[j]);
3827 } else if (r != TERM_SEQ_NONE) {
3828 r = screen_feed_cmd(screen, seq);
3838 static char *screen_map_key(term_screen *screen,
3840 const uint32_t *keysyms,
3843 const uint32_t *ucs4,
3844 unsigned int mods) {
3845 char ch, ch2, ch_mods;
3849 /* TODO: All these key-mappings need to be verified. Public information
3850 * on those mappings is pretty scarce and every emulator seems to do it
3851 * slightly differently.
3852 * A lot of mappings are also missing. */
3860 v = XKB_KEY_NoSymbol;
3862 /* In some mappings, the modifiers are encoded as CSI parameters. The
3863 * encoding is rather arbitrary, but seems to work. */
3865 switch (mods & (TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT | TERM_KBDMOD_CTRL)) {
3866 case TERM_KBDMOD_SHIFT:
3869 case TERM_KBDMOD_ALT:
3872 case TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT:
3875 case TERM_KBDMOD_CTRL:
3878 case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT:
3881 case TERM_KBDMOD_CTRL | TERM_KBDMOD_ALT:
3884 case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT:
3889 /* A user might actually use multiple layouts for keyboard
3890 * input. @keysyms[0] contains the actual keysym that the user
3891 * used. But if this keysym is not in the ascii range, the
3892 * input handler does check all other layouts that the user
3893 * specified whether one of them maps the key to some ASCII
3894 * keysym and provides this via @ascii. We always use the real
3895 * keysym except when handling CTRL+<XY> shortcuts we use the
3896 * ascii keysym. This is for compatibility to xterm et. al. so
3897 * ctrl+c always works regardless of the currently active
3898 * keyboard layout. But if no ascii-sym is found, we still use
3899 * the real keysym. */
3900 if (ascii == XKB_KEY_NoSymbol)
3903 /* map CTRL+<ascii> */
3904 if (mods & TERM_KBDMOD_CTRL) {
3907 /* Right hand side is mapped to the left and then
3908 * treated equally. Fall through to left-hand side.. */
3911 /* Printable ASCII is mapped 1-1 in XKB and in
3912 * combination with CTRL bit 7 is flipped. This
3913 * is equivalent to the caret-notation. */
3914 *p++ = ascii ^ 0x40;
3919 /* map cursor keys */
3943 if (screen->flags & TERM_FLAG_CURSOR_KEYS)
3956 /* map action keys */
3962 case XKB_KEY_Insert:
3965 case XKB_KEY_Delete:
3968 case XKB_KEY_Select:
3971 case XKB_KEY_Page_Up:
3974 case XKB_KEY_Page_Down:
3990 /* map lower function keys */
4023 /* map upper function keys */
4074 /* map special keys */
4076 case 0xff08: /* XKB_KEY_BackSpace */
4077 case 0xff09: /* XKB_KEY_Tab */
4078 case 0xff0a: /* XKB_KEY_Linefeed */
4079 case 0xff0b: /* XKB_KEY_Clear */
4080 case 0xff15: /* XKB_KEY_Sys_Req */
4081 case 0xff1b: /* XKB_KEY_Escape */
4082 case 0xffff: /* XKB_KEY_Delete */
4085 case 0xff13: /* XKB_KEY_Pause */
4086 /* TODO: What should we do with this key?
4087 * Sending XOFF is awful as there is no simple
4088 * way on modern keyboards to send XON again.
4089 * If someone wants this, we can re-eanble
4092 case 0xff14: /* XKB_KEY_Scroll_Lock */
4093 /* TODO: What should we do on scroll-lock?
4094 * Sending 0x14 is what the specs say but it is
4095 * not used today the way most users would
4096 * expect so we disable it. If someone wants
4097 * this, we can re-enable it (optionally). */
4099 case XKB_KEY_Return:
4101 if (screen->flags & TERM_FLAG_NEWLINE_MODE)
4104 case XKB_KEY_ISO_Left_Tab:
4109 /* map unicode keys */
4110 for (i = 0; i < n_syms; ++i)
4111 p += utf8_encode_unichar(p, ucs4[i]);
4116 int term_screen_feed_keyboard(term_screen *screen,
4117 const uint32_t *keysyms,
4120 const uint32_t *ucs4,
4121 unsigned int mods) {
4122 _cleanup_free_ char *dyn = NULL;
4123 static const size_t padding = 1;
4124 char buf[128], *start, *p;
4126 assert_return(screen, -EINVAL);
4128 /* allocate buffer if too small */
4130 if (4 * n_syms + padding > sizeof(buf)) {
4131 dyn = malloc(4 * n_syms + padding);
4138 /* reserve prefix space */
4142 p = screen_map_key(screen, p, keysyms, n_syms, ascii, ucs4, mods);
4143 if (!p || p - start < 1)
4146 /* The ALT modifier causes ESC to be prepended to any key-stroke. We
4147 * already accounted for that buffer space above, so simply prepend it
4149 * TODO: is altSendsEscape a suitable default? What are the semantics
4150 * exactly? Is it used in C0/C1 conversion? Is it prepended if there
4151 * already is an escape character? */
4152 if (mods & TERM_KBDMOD_ALT && *start != 0x1b)
4155 /* turn C0 into C1 */
4156 if (!(screen->flags & TERM_FLAG_7BIT_MODE) && p - start >= 2)
4157 if (start[0] == 0x1b && start[1] >= 0x40 && start[1] <= 0x5f)
4160 return screen_write(screen, start, p - start);
4163 int term_screen_resize(term_screen *screen, unsigned int x, unsigned int y) {
4168 assert_return(screen, -EINVAL);
4170 r = term_page_reserve(screen->page_main, x, y, &screen->state.attr, screen->age);
4174 r = term_page_reserve(screen->page_alt, x, y, &screen->state.attr, screen->age);
4178 if (x > screen->n_tabs) {
4179 t = realloc(screen->tabs, (x + 7) / 8);
4187 for (i = (screen->page->width + 7) / 8 * 8; i < x; i += 8)
4188 screen->tabs[i / 8] = 0x1;
4190 term_page_resize(screen->page_main, x, y, &screen->state.attr, screen->age, screen->history);
4191 term_page_resize(screen->page_alt, x, y, &screen->state.attr, screen->age, NULL);
4193 screen->state.cursor_x = screen_clamp_x(screen, screen->state.cursor_x);
4194 screen->state.cursor_y = screen_clamp_x(screen, screen->state.cursor_y);
4195 screen_cursor_clear_wrap(screen);
4200 void term_screen_soft_reset(term_screen *screen) {
4205 screen->g0 = &term_unicode_lower;
4206 screen->g1 = &term_unicode_upper;
4207 screen->g2 = &term_unicode_lower;
4208 screen->g3 = &term_unicode_upper;
4209 screen->state.attr = screen->default_attr;
4210 screen->state.gl = &screen->g0;
4211 screen->state.gr = &screen->g1;
4212 screen->state.glt = NULL;
4213 screen->state.grt = NULL;
4214 screen->state.auto_wrap = 0;
4215 screen->state.origin_mode = 0;
4217 screen->saved = screen->state;
4218 screen->saved.cursor_x = 0;
4219 screen->saved.cursor_y = 0;
4220 screen->saved_alt = screen->saved;
4222 screen->page = screen->page_main;
4223 screen->history = screen->history_main;
4224 screen->flags = TERM_FLAG_7BIT_MODE;
4225 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
4227 for (i = 0; i < screen->page->width; i += 8)
4228 screen->tabs[i / 8] = 0x1;
4230 term_page_set_scroll_region(screen->page_main, 0, screen->page->height);
4231 term_page_set_scroll_region(screen->page_alt, 0, screen->page->height);
4234 void term_screen_hard_reset(term_screen *screen) {
4237 term_screen_soft_reset(screen);
4239 screen->state.cursor_x = 0;
4240 screen->state.cursor_y = 0;
4241 term_page_erase(screen->page_main, 0, 0, screen->page->width, screen->page->height, &screen->state.attr, screen->age, false);
4242 term_page_erase(screen->page_alt, 0, 0, screen->page->width, screen->page->height, &screen->state.attr, screen->age, false);
4245 int term_screen_set_answerback(term_screen *screen, const char *answerback) {
4248 assert_return(screen, -EINVAL);
4251 t = strdup(answerback);
4256 free(screen->answerback);
4257 screen->answerback = t;
4262 int term_screen_draw(term_screen *screen,
4263 int (*draw_fn) (term_screen *screen,
4267 const term_attr *attr,
4270 unsigned int ch_width),
4273 uint64_t cell_age, line_age, age = 0;
4274 term_charbuf_t ch_buf;
4275 const uint32_t *ch_str;
4276 unsigned int i, j, cw;
4289 page = screen->page;
4291 for (j = 0; j < page->height; ++j) {
4292 line = page->lines[j];
4293 line_age = MAX(line->age, page->age);
4295 for (i = 0; i < page->width; ++i) {
4298 cell = &line->cells[i];
4299 cell_age = MAX(cell->age, line_age);
4301 if (age != 0 && cell_age <= age)
4304 ch_str = term_char_resolve(cell->ch, &ch_n, &ch_buf);
4306 /* Character-width of 0 is used for cleared cells.
4307 * Always treat this as single-cell character, so
4308 * renderers can assume ch_width is set properpy. */
4309 cw = MAX(cell->cwidth, 1U);
4312 if (i == screen->state.cursor_x && j == screen->state.cursor_y &&
4313 !(screen->flags & TERM_FLAG_HIDE_CURSOR))
4330 *fb_age = screen->age;