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"
55 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) {
56 _cleanup_(term_screen_unrefp) term_screen *screen = NULL;
59 assert_return(out, -EINVAL);
61 screen = new0(term_screen, 1);
67 screen->write_fn = write_fn;
68 screen->write_fn_data = write_fn_data;
69 screen->cmd_fn = cmd_fn;
70 screen->cmd_fn_data = cmd_fn_data;
71 screen->flags = TERM_FLAG_7BIT_MODE;
72 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
73 screen->g0 = &term_unicode_lower;
74 screen->g1 = &term_unicode_upper;
75 screen->g2 = &term_unicode_lower;
76 screen->g3 = &term_unicode_upper;
77 screen->state.gl = &screen->g0;
78 screen->state.gr = &screen->g1;
79 screen->saved = screen->state;
80 screen->saved_alt = screen->saved;
82 r = term_page_new(&screen->page_main);
86 r = term_page_new(&screen->page_alt);
90 r = term_parser_new(&screen->parser, false);
94 r = term_history_new(&screen->history_main);
98 screen->page = screen->page_main;
99 screen->history = screen->history_main;
106 term_screen *term_screen_ref(term_screen *screen) {
110 assert_return(screen->ref > 0, NULL);
116 term_screen *term_screen_unref(term_screen *screen) {
120 assert_return(screen->ref > 0, NULL);
125 free(screen->answerback);
127 term_history_free(screen->history_main);
128 term_page_free(screen->page_alt);
129 term_page_free(screen->page_main);
130 term_parser_free(screen->parser);
138 * Unfortunately, 7bit/8bit compat mode requires us to send C1 controls encoded
139 * as 7bit if asked by the application. This is really used in the wild, so we
140 * cannot fall back to "always 7bit".
141 * screen_write() is the underlying backend which forwards any writes to the
142 * users's callback. It's the users responsibility to buffer these and write
143 * them out once their call to term_screen_feed_*() returns.
144 * The SEQ_WRITE() and SEQ_WRITE_KEY() macros allow constructing C0/C1 sequences
145 * directly in the code-base without requiring any intermediate buffer during
150 #define C1_CSI "\x9b"
152 #define SEQ(_screen, _prefix_esc, _c0, _c1, _seq) \
153 (((_screen)->flags & TERM_FLAG_7BIT_MODE) ? \
154 ((_prefix_esc) ? ("\e" _c0 _seq) : (_c0 _seq)) : \
155 ((_prefix_esc) ? ("\e" _c1 _seq) : (_c1 _seq)))
157 #define SEQ_SIZE(_screen, _prefix_esc, _c0, _c1, _seq) \
158 (((_screen)->flags & TERM_FLAG_7BIT_MODE) ? \
159 ((_prefix_esc) ? sizeof("\e" _c0 _seq) : sizeof(_c0 _seq)) : \
160 ((_prefix_esc) ? sizeof("\e" _c1 _seq) : sizeof(_c1 _seq)))
162 #define SEQ_WRITE_KEY(_screen, _prefix_esc, _c0, _c1, _seq) \
163 screen_write((_screen), \
164 SEQ((_screen), (_prefix_esc), \
166 SEQ_SIZE((_screen), (_prefix_esc), \
169 #define SEQ_WRITE(_screen, _c0, _c1, _seq) \
170 SEQ_WRITE_KEY((_screen), false, _c0, _c1, _seq)
172 static int screen_write(term_screen *screen, const void *buf, size_t len) {
173 if (len < 1 || !screen->write_fn)
176 return screen->write_fn(screen, screen->write_fn_data, buf, len);
181 * Some commands cannot be handled by the screen-layer directly. Those are
182 * forwarded to the command-handler of the caller. This is rarely used and can
183 * safely be set to NULL.
186 static int screen_forward(term_screen *screen, unsigned int cmd, const term_seq *seq) {
190 return screen->cmd_fn(screen, screen->cmd_fn_data, cmd, seq);
195 * These helpers implement common-operations like cursor-handler and more, which
196 * are used by several command dispatchers.
199 static unsigned int screen_clamp_x(term_screen *screen, unsigned int x) {
200 if (x >= screen->page->width)
201 return (screen->page->width > 0) ? screen->page->width - 1 : 0;
206 static unsigned int screen_clamp_y(term_screen *screen, unsigned int y) {
207 if (y >= screen->page->height)
208 return (screen->page->height > 0) ? screen->page->height - 1 : 0;
213 static bool screen_tab_is_set(term_screen *screen, unsigned int pos) {
214 if (pos >= screen->page->width)
217 return screen->tabs[pos / 8] & (1 << (pos % 8));
220 static inline void screen_age_cursor(term_screen *screen) {
223 cell = term_page_get_cell(screen->page, screen->state.cursor_x, screen->state.cursor_y);
225 cell->age = screen->age;
228 static void screen_cursor_clear_wrap(term_screen *screen) {
229 screen->flags &= ~TERM_FLAG_PENDING_WRAP;
232 static void screen_cursor_set(term_screen *screen, unsigned int x, unsigned int y) {
233 x = screen_clamp_x(screen, x);
234 y = screen_clamp_y(screen, y);
236 if (x == screen->state.cursor_x && y == screen->state.cursor_y)
239 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
240 screen_age_cursor(screen);
242 screen->state.cursor_x = x;
243 screen->state.cursor_y = y;
245 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
246 screen_age_cursor(screen);
249 static void screen_cursor_set_rel(term_screen *screen, unsigned int x, unsigned int y) {
250 if (screen->state.origin_mode) {
251 x = screen_clamp_x(screen, x);
252 y = screen_clamp_x(screen, y) + screen->page->scroll_idx;
254 if (y >= screen->page->scroll_idx + screen->page->scroll_num) {
255 y = screen->page->scroll_idx + screen->page->scroll_num;
256 if (screen->page->scroll_num > 0)
261 screen_cursor_set(screen, x, y);
264 static void screen_cursor_left(term_screen *screen, unsigned int num) {
265 if (num > screen->state.cursor_x)
266 num = screen->state.cursor_x;
268 screen_cursor_set(screen, screen->state.cursor_x - num, screen->state.cursor_y);
271 static void screen_cursor_left_tab(term_screen *screen, unsigned int num) {
274 i = screen->state.cursor_x;
275 while (i > 0 && num > 0) {
276 if (screen_tab_is_set(screen, --i))
280 screen_cursor_set(screen, i, screen->state.cursor_y);
283 static void screen_cursor_right(term_screen *screen, unsigned int num) {
284 if (num > screen->page->width)
285 num = screen->page->width;
287 screen_cursor_set(screen, screen->state.cursor_x + num, screen->state.cursor_y);
290 static void screen_cursor_right_tab(term_screen *screen, unsigned int num) {
293 i = screen->state.cursor_x;
294 while (i + 1 < screen->page->width && num > 0) {
295 if (screen_tab_is_set(screen, ++i))
299 screen_cursor_set(screen, i, screen->state.cursor_y);
302 static void screen_cursor_up(term_screen *screen, unsigned int num, bool scroll) {
305 if (screen->state.cursor_y < screen->page->scroll_idx) {
306 if (num > screen->state.cursor_y)
307 num = screen->state.cursor_y;
309 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num);
311 max = screen->state.cursor_y - screen->page->scroll_idx;
316 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
317 screen_age_cursor(screen);
320 term_page_scroll_down(screen->page, num - max, &screen->state.attr, screen->age, NULL);
322 screen->state.cursor_y = screen->page->scroll_idx;
324 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
325 screen_age_cursor(screen);
327 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num);
332 static void screen_cursor_down(term_screen *screen, unsigned int num, bool scroll) {
335 if (screen->state.cursor_y >= screen->page->scroll_idx + screen->page->scroll_num) {
336 if (num > screen->page->height)
337 num = screen->page->height;
339 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num);
341 max = screen->page->scroll_idx + screen->page->scroll_num - 1 - screen->state.cursor_y;
346 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
347 screen_age_cursor(screen);
350 term_page_scroll_up(screen->page, num - max, &screen->state.attr, screen->age, screen->history);
352 screen->state.cursor_y = screen->page->scroll_idx + screen->page->scroll_num - 1;
354 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
355 screen_age_cursor(screen);
357 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y + num);
362 static void screen_save_state(term_screen *screen, term_state *where) {
363 *where = screen->state;
366 static void screen_restore_state(term_screen *screen, term_state *from) {
367 screen_cursor_set(screen, from->cursor_x, from->cursor_y);
368 screen->state = *from;
371 static void screen_reset_page(term_screen *screen, term_page *page) {
372 term_page_set_scroll_region(page, 0, page->height);
373 term_page_erase(page, 0, 0, page->width, page->height, &screen->state.attr, screen->age, false);
376 static void screen_change_alt(term_screen *screen, bool set) {
378 screen->page = screen->page_alt;
379 screen->history = NULL;
381 screen->page = screen->page_main;
382 screen->history = screen->history_main;
385 screen->page->age = screen->age;
388 static inline void set_reset(term_screen *screen, unsigned int flag, bool set) {
390 screen->flags |= flag;
392 screen->flags &= ~flag;
395 static void screen_mode_change_ansi(term_screen *screen, unsigned mode, bool set) {
399 * LNM: line-feed/new-line mode
402 set_reset(screen, TERM_FLAG_NEWLINE_MODE, set);
406 log_debug("terminal: failed to %s unknown ANSI mode %u", set ? "set" : "unset", mode);
410 static void screen_mode_change_dec(term_screen *screen, unsigned int mode, bool set) {
414 * DECCKM: cursor-keys
417 set_reset(screen, TERM_FLAG_CURSOR_KEYS, set);
425 screen->state.origin_mode = set;
430 * DECAWN: auto-wrap mode
433 screen->state.auto_wrap = set;
438 * DECTCEM: text-cursor-enable
441 set_reset(screen, TERM_FLAG_HIDE_CURSOR, !set);
442 screen_age_cursor(screen);
447 * XTERM-ASB: alternate-screen-buffer
448 * This enables/disables the alternate screen-buffer.
449 * It effectively saves the current page content and
450 * allows you to restore it when changing to the
451 * original screen-buffer again.
453 screen_change_alt(screen, set);
458 * XTERM-ASBPE: alternate-screen-buffer-post-erase
459 * This is the same as XTERM-ASB but erases the
460 * alternate screen-buffer before switching back to the
461 * original buffer. Use it to discard any data on the
462 * alternate screen buffer when done.
465 screen_reset_page(screen, screen->page_alt);
467 screen_change_alt(screen, set);
472 * XTERM-ASBCS: alternate-screen-buffer-cursor-state
473 * This has the same effect as DECSC/DECRC, but uses a
474 * separate state buffer. It is usually used in
475 * combination with alternate screen buffers to provide
476 * stacked state storage.
479 screen_save_state(screen, &screen->saved_alt);
481 screen_restore_state(screen, &screen->saved_alt);
486 * XTERM-ASBX: alternate-screen-buffer-extended
487 * This combines XTERM-ASBPE and XTERM-ASBCS somewhat.
488 * When enabling, state is saved, alternate screen
489 * buffer is activated and cleared.
490 * When disabled, alternate screen buffer is cleared,
491 * then normal screen buffer is enabled and state is
495 screen_save_state(screen, &screen->saved_alt);
497 screen_reset_page(screen, screen->page_alt);
498 screen_change_alt(screen, set);
501 screen_restore_state(screen, &screen->saved_alt);
505 log_debug("terminal: failed to %s unknown DEC mode %u", set ? "set" : "unset", mode);
509 /* map a character according to current GL and GR maps */
510 static uint32_t screen_map(term_screen *screen, uint32_t val) {
513 /* 32 and 127 always map to identity. 160 and 255 map to identity iff a
514 * 96 character set is loaded into GR. Values above 255 always map to
518 if (screen->state.glt) {
519 nval = (**screen->state.glt)[val - 32];
520 screen->state.glt = NULL;
522 nval = (**screen->state.gl)[val - 32];
526 if (screen->state.grt) {
527 nval = (**screen->state.grt)[val - 160];
528 screen->state.grt = NULL;
530 nval = (**screen->state.gr)[val - 160];
535 return (nval == -1U) ? val : nval;
540 * This is the unofficial documentation of all the TERM_CMD_* definitions. Each
541 * handled command has a separate function with an extensive comment on the
542 * semantics of the command.
543 * Note that many semantics are unknown and need to be verified. This is mostly
544 * about error-handling, though. Applications rarely rely on those features.
547 static int screen_DA1(term_screen *screen, const term_seq *seq);
548 static int screen_LF(term_screen *screen, const term_seq *seq);
550 static int screen_GRAPHIC(term_screen *screen, const term_seq *seq) {
551 term_char_t ch = TERM_CHAR_NULL;
553 if (screen->state.cursor_x + 1 == screen->page->width
554 && screen->flags & TERM_FLAG_PENDING_WRAP
555 && screen->state.auto_wrap) {
556 screen_cursor_down(screen, 1, true);
557 screen_cursor_set(screen, 0, screen->state.cursor_y);
560 screen_cursor_clear_wrap(screen);
562 ch = term_char_merge(ch, screen_map(screen, seq->terminator));
563 term_page_write(screen->page, screen->state.cursor_x, screen->state.cursor_y, ch, 1, &screen->state.attr, screen->age, false);
565 if (screen->state.cursor_x + 1 == screen->page->width)
566 screen->flags |= TERM_FLAG_PENDING_WRAP;
568 screen_cursor_right(screen, 1);
573 static int screen_BEL(term_screen *screen, const term_seq *seq) {
575 * BEL - sound bell tone
576 * This command should trigger an acoustic bell. Usually, this is
577 * forwarded directly to the pcspkr. However, bells have become quite
578 * uncommon and annoying, so we're not implementing them here. Instead,
579 * it's one of the commands we forward to the caller.
582 return screen_forward(screen, TERM_CMD_BEL, seq);
585 static int screen_BS(term_screen *screen, const term_seq *seq) {
588 * Move cursor one cell to the left. If already at the left margin,
592 screen_cursor_clear_wrap(screen);
593 screen_cursor_left(screen, 1);
597 static int screen_CBT(term_screen *screen, const term_seq *seq) {
599 * CBT - cursor-backward-tabulation
600 * Move the cursor @args[0] tabs backwards (to the left). The
601 * current cursor cell, in case it's a tab, is not counted.
602 * Furthermore, the cursor cannot be moved beyond position 0 and
603 * it will stop there.
609 unsigned int num = 1;
611 if (seq->args[0] > 0)
614 screen_cursor_clear_wrap(screen);
615 screen_cursor_left_tab(screen, num);
620 static int screen_CHA(term_screen *screen, const term_seq *seq) {
622 * CHA - cursor-horizontal-absolute
623 * Move the cursor to position @args[0] in the current line. The
624 * cursor cannot be moved beyond the rightmost cell and will stop
631 unsigned int pos = 1;
633 if (seq->args[0] > 0)
636 screen_cursor_clear_wrap(screen);
637 screen_cursor_set(screen, pos - 1, screen->state.cursor_y);
642 static int screen_CHT(term_screen *screen, const term_seq *seq) {
644 * CHT - cursor-horizontal-forward-tabulation
645 * Move the cursor @args[0] tabs forward (to the right). The
646 * current cursor cell, in case it's a tab, is not counted.
647 * Furthermore, the cursor cannot be moved beyond the rightmost cell
648 * and will stop there.
654 unsigned int num = 1;
656 if (seq->args[0] > 0)
659 screen_cursor_clear_wrap(screen);
660 screen_cursor_right_tab(screen, num);
665 static int screen_CNL(term_screen *screen, const term_seq *seq) {
667 * CNL - cursor-next-line
668 * Move the cursor @args[0] lines down.
670 * TODO: Does this stop at the bottom or cause a scroll-up?
676 unsigned int num = 1;
678 if (seq->args[0] > 0)
681 screen_cursor_clear_wrap(screen);
682 screen_cursor_down(screen, num, false);
687 static int screen_CPL(term_screen *screen, const term_seq *seq) {
689 * CPL - cursor-preceding-line
690 * Move the cursor @args[0] lines up.
692 * TODO: Does this stop at the top or cause a scroll-up?
698 unsigned int num = 1;
700 if (seq->args[0] > 0)
703 screen_cursor_clear_wrap(screen);
704 screen_cursor_up(screen, num, false);
709 static int screen_CR(term_screen *screen, const term_seq *seq) {
711 * CR - carriage-return
712 * Move the cursor to the left margin on the current line.
715 screen_cursor_clear_wrap(screen);
716 screen_cursor_set(screen, 0, screen->state.cursor_y);
721 static int screen_CUB(term_screen *screen, const term_seq *seq) {
723 * CUB - cursor-backward
724 * Move the cursor @args[0] positions to the left. The cursor stops
725 * at the left-most position.
731 unsigned int num = 1;
733 if (seq->args[0] > 0)
736 screen_cursor_clear_wrap(screen);
737 screen_cursor_left(screen, num);
742 static int screen_CUD(term_screen *screen, const term_seq *seq) {
745 * Move the cursor @args[0] positions down. The cursor stops at the
746 * bottom margin. If it was already moved further, it stops at the
753 unsigned int num = 1;
755 if (seq->args[0] > 0)
758 screen_cursor_clear_wrap(screen);
759 screen_cursor_down(screen, num, false);
764 static int screen_CUF(term_screen *screen, const term_seq *seq) {
766 * CUF -cursor-forward
767 * Move the cursor @args[0] positions to the right. The cursor stops
768 * at the right-most position.
774 unsigned int num = 1;
776 if (seq->args[0] > 0)
779 screen_cursor_clear_wrap(screen);
780 screen_cursor_right(screen, num);
785 static int screen_CUP(term_screen *screen, const term_seq *seq) {
787 * CUP - cursor-position
788 * Moves the cursor to position @args[1] x @args[0]. If either is 0, it
789 * is treated as 1. The positions are subject to the origin-mode and
790 * clamped to the addressable with/height.
797 unsigned int x = 1, y = 1;
799 if (seq->args[0] > 0)
801 if (seq->args[1] > 0)
804 screen_cursor_clear_wrap(screen);
805 screen_cursor_set_rel(screen, x - 1, y - 1);
810 static int screen_CUU(term_screen *screen, const term_seq *seq) {
813 * Move the cursor @args[0] positions up. The cursor stops at the
814 * top margin. If it was already moved further, it stops at the
822 unsigned int num = 1;
824 if (seq->args[0] > 0)
827 screen_cursor_clear_wrap(screen);
828 screen_cursor_up(screen, num, false);
833 static int screen_DA1(term_screen *screen, const term_seq *seq) {
835 * DA1 - primary-device-attributes
836 * The primary DA asks for basic terminal features. We simply return
837 * a hard-coded list of features we implement.
838 * Note that the primary DA asks for supported features, not currently
841 * The terminal's answer is:
843 * The first argument, 64, is fixed and denotes a VT420, the last
844 * DEC-term that extended this number.
845 * All following arguments denote supported features. Note
846 * that at most 15 features can be sent (max CSI args). It is safe to
847 * send more, but clients might not be able to parse them. This is a
848 * client's problem and we shouldn't care. There is no other way to
849 * send those feature lists, so we have to extend them beyond 15 in
854 * The 132 column mode is supported by the terminal.
856 * A priner-port is supported and can be addressed via
859 * Support for ReGIS graphics is available. The ReGIS routines
860 * provide the "remote graphics instruction set" and allow basic
863 * Support of Sixel graphics is available. This provides access
864 * to the sixel bitmap routines.
866 * The terminal supports DECSCA and related selective-erase
867 * functions. This allows to protect specific cells from being
868 * erased, if specified.
869 * 7: soft character set (DRCS)
871 * 8: user-defined keys (UDKs)
873 * 9: national-replacement character sets (NRCS)
874 * National-replacement character-sets are available.
875 * 12: Yugoslavian (SCS)
877 * 15: technical character set
878 * The DEC technical-character-set is available.
879 * 18: windowing capability
881 * 21: horizontal scrolling
889 * 29: ANSI text locator
891 * 42: ISO Latin-2 character set
897 * 46: ASCII emulation
901 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "?64;1;6;9;15c");
904 static int screen_DA2(term_screen *screen, const term_seq *seq) {
906 * DA2 - secondary-device-attributes
907 * The secondary DA asks for the terminal-ID, firmware versions and
908 * other non-primary attributes. All these values are
909 * informational-only and should not be used by the host to detect
912 * The terminal's response is:
913 * ^[ > 61 ; FIRMWARE ; KEYBOARD c
914 * whereas 65 is fixed for VT525 terminals, the last terminal-line that
915 * increased this number. FIRMWARE is the firmware
916 * version encoded as major/minor (20 == 2.0) and KEYBOARD is 0 for STD
917 * keyboard and 1 for PC keyboards.
919 * We replace the firmware-version with the systemd-version so clients
920 * can decode it again.
923 return SEQ_WRITE(screen, C0_CSI, C1_CSI, ">65;" PACKAGE_VERSION ";1c");
926 static int screen_DA3(term_screen *screen, const term_seq *seq) {
928 * DA3 - tertiary-device-attributes
929 * The tertiary DA is used to query the terminal-ID.
931 * The terminal's response is:
932 * ^P ! | XX AA BB CC ^\
933 * whereas all four parameters are hexadecimal-encoded pairs. XX
934 * denotes the manufacturing site, AA BB CC is the terminal's ID.
937 /* we do not support tertiary DAs */
941 static int screen_DC1(term_screen *screen, const term_seq *seq) {
943 * DC1 - device-control-1 or XON
944 * This clears any previous XOFF and resumes terminal-transmission.
947 /* we do not support XON */
951 static int screen_DC3(term_screen *screen, const term_seq *seq) {
953 * DC3 - device-control-3 or XOFF
954 * Stops terminal transmission. No further characters are sent until
955 * an XON is received.
958 /* we do not support XOFF */
962 static int screen_DCH(term_screen *screen, const term_seq *seq) {
964 * DCH - delete-character
965 * This deletes @argv[0] characters at the current cursor position. As
966 * characters are deleted, the remaining characters between the cursor
967 * and right margin move to the left. Character attributes move with the
968 * characters. The terminal adds blank spaces with no visual character
969 * attributes at the right margin. DCH has no effect outside the
976 unsigned int num = 1;
978 if (seq->args[0] > 0)
981 screen_cursor_clear_wrap(screen);
982 term_page_delete_cells(screen->page, screen->state.cursor_x, screen->state.cursor_y, num, &screen->state.attr, screen->age);
987 static int screen_DECALN(term_screen *screen, const term_seq *seq) {
989 * DECALN - screen-alignment-pattern
991 * Probably not worth implementing.
997 static int screen_DECANM(term_screen *screen, const term_seq *seq) {
1000 * Set the terminal into VT52 compatibility mode. Control sequences
1001 * overlap with regular sequences so we have to detect them early before
1004 * Probably not worth implementing.
1010 static int screen_DECBI(term_screen *screen, const term_seq *seq) {
1012 * DECBI - back-index
1013 * This control function moves the cursor backward one column. If the
1014 * cursor is at the left margin, then all screen data within the margin
1015 * moves one column to the right. The column that shifted past the right
1017 * DECBI adds a new column at the left margin with no visual attributes.
1018 * DECBI does not affect the margins. If the cursor is beyond the
1019 * left-margin at the left border, then the terminal ignores DECBI.
1021 * Probably not worth implementing.
1027 static int screen_DECCARA(term_screen *screen, const term_seq *seq) {
1029 * DECCARA - change-attributes-in-rectangular-area
1031 * Probably not worth implementing.
1037 static int screen_DECCRA(term_screen *screen, const term_seq *seq) {
1039 * DECCRA - copy-rectangular-area
1041 * Probably not worth implementing.
1047 static int screen_DECDC(term_screen *screen, const term_seq *seq) {
1049 * DECDC - delete-column
1051 * Probably not worth implementing.
1057 static int screen_DECDHL_BH(term_screen *screen, const term_seq *seq) {
1059 * DECDHL_BH - double-width-double-height-line: bottom half
1061 * Probably not worth implementing.
1067 static int screen_DECDHL_TH(term_screen *screen, const term_seq *seq) {
1069 * DECDHL_TH - double-width-double-height-line: top half
1071 * Probably not worth implementing.
1077 static int screen_DECDWL(term_screen *screen, const term_seq *seq) {
1079 * DECDWL - double-width-single-height-line
1081 * Probably not worth implementing.
1087 static int screen_DECEFR(term_screen *screen, const term_seq *seq) {
1089 * DECEFR - enable-filter-rectangle
1090 * Defines the coordinates of a filter rectangle (top, left, bottom,
1091 * right as @args[0] to @args[3]) and activates it.
1092 * Anytime the locator is detected outside of the filter rectangle, an
1093 * outside rectangle event is generated and the rectangle is disabled.
1094 * Filter rectangles are always treated as "one-shot" events. Any
1095 * parameters that are omitted default to the current locator position.
1096 * If all parameters are omitted, any locator motion will be reported.
1097 * DECELR always cancels any prevous rectangle definition.
1099 * The locator is usually associated with the mouse-cursor, but based
1100 * on cells instead of pixels. See DECELR how to initialize and enable
1101 * it. DECELR can also enable pixel-mode instead of cell-mode.
1109 static int screen_DECELF(term_screen *screen, const term_seq *seq) {
1111 * DECELF - enable-local-functions
1113 * Probably not worth implementing.
1119 static int screen_DECELR(term_screen *screen, const term_seq *seq) {
1121 * DECELR - enable-locator-reporting
1122 * This changes the locator-reporting mode. @args[0] specifies the mode
1123 * to set, 0 disables locator-reporting, 1 enables it continuously, 2
1124 * enables it for a single report. @args[1] specifies the
1125 * precision-mode. 0 and 2 set the reporting to cell-precision, 1 sets
1138 static int screen_DECERA(term_screen *screen, const term_seq *seq) {
1140 * DECERA - erase-rectangular-area
1142 * Probably not worth implementing.
1148 static int screen_DECFI(term_screen *screen, const term_seq *seq) {
1150 * DECFI - forward-index
1151 * This control function moves the cursor forward one column. If the
1152 * cursor is at the right margin, then all screen data within the
1153 * margins moves one column to the left. The column shifted past the
1154 * left margin is lost.
1155 * DECFI adds a new column at the right margin, with no visual
1156 * attributes. DECFI does not affect margins. If the cursor is beyond
1157 * the right margin at the border of the page when the terminal
1158 * receives DECFI, then the terminal ignores DECFI.
1160 * Probably not worth implementing.
1166 static int screen_DECFRA(term_screen *screen, const term_seq *seq) {
1168 * DECFRA - fill-rectangular-area
1170 * Probably not worth implementing.
1176 static int screen_DECIC(term_screen *screen, const term_seq *seq) {
1178 * DECIC - insert-column
1180 * Probably not worth implementing.
1186 static int screen_DECID(term_screen *screen, const term_seq *seq) {
1188 * DECID - return-terminal-id
1189 * This is an obsolete form of TERM_CMD_DA1.
1192 return screen_DA1(screen, seq);
1195 static int screen_DECINVM(term_screen *screen, const term_seq *seq) {
1197 * DECINVM - invoke-macro
1199 * Probably not worth implementing.
1205 static int screen_DECKBD(term_screen *screen, const term_seq *seq) {
1207 * DECKBD - keyboard-language-selection
1209 * Probably not worth implementing.
1215 static int screen_DECKPAM(term_screen *screen, const term_seq *seq) {
1217 * DECKPAM - keypad-application-mode
1218 * Enables the keypad-application mode. If enabled, the keypad sends
1219 * special characters instead of the printed characters. This way,
1220 * applications can detect whether a numeric key was pressed on the
1221 * top-row or on the keypad.
1222 * Default is keypad-numeric-mode.
1225 screen->flags |= TERM_FLAG_KEYPAD_MODE;
1230 static int screen_DECKPNM(term_screen *screen, const term_seq *seq) {
1232 * DECKPNM - keypad-numeric-mode
1233 * This disables the keypad-application-mode (DECKPAM) and returns to
1234 * the keypad-numeric-mode. Keypresses on the keypad generate the same
1235 * sequences as corresponding keypresses on the main keyboard.
1236 * Default is keypad-numeric-mode.
1239 screen->flags &= ~TERM_FLAG_KEYPAD_MODE;
1244 static int screen_DECLFKC(term_screen *screen, const term_seq *seq) {
1246 * DECLFKC - local-function-key-control
1248 * Probably not worth implementing.
1254 static int screen_DECLL(term_screen *screen, const term_seq *seq) {
1258 * Probably not worth implementing.
1264 static int screen_DECLTOD(term_screen *screen, const term_seq *seq) {
1266 * DECLTOD - load-time-of-day
1268 * Probably not worth implementing.
1274 static int screen_DECPCTERM(term_screen *screen, const term_seq *seq) {
1276 * DECPCTERM - pcterm-mode
1277 * This enters/exits the PCTerm mode. Default mode is VT-mode. It can
1278 * also select parameters for scancode/keycode mappings in SCO mode.
1280 * Definitely not worth implementing. Lets kill PCTerm/SCO modes!
1286 static int screen_DECPKA(term_screen *screen, const term_seq *seq) {
1288 * DECPKA - program-key-action
1290 * Probably not worth implementing.
1296 static int screen_DECPKFMR(term_screen *screen, const term_seq *seq) {
1298 * DECPKFMR - program-key-free-memory-report
1300 * Probably not worth implementing.
1306 static int screen_DECRARA(term_screen *screen, const term_seq *seq) {
1308 * DECRARA - reverse-attributes-in-rectangular-area
1310 * Probably not worth implementing.
1316 static int screen_DECRC(term_screen *screen, const term_seq *seq) {
1318 * DECRC - restore-cursor
1319 * Restores the terminal to the state saved by the save cursor (DECSC)
1320 * function. This includes more than just the cursor-position.
1322 * If nothing was saved by DECSC, then DECRC performs the following
1324 * * Moves the cursor to the home position (upper left of screen).
1325 * * Resets origin mode (DECOM).
1326 * * Turns all character attributes off (normal setting).
1327 * * Maps the ASCII character set into GL, and the DEC Supplemental
1328 * Graphic set into GR.
1330 * The terminal maintains a separate DECSC buffer for the main display
1331 * and the status line. This feature lets you save a separate operating
1332 * state for the main display and the status line.
1335 screen_restore_state(screen, &screen->saved);
1340 static int screen_DECREQTPARM(term_screen *screen, const term_seq *seq) {
1342 * DECREQTPARM - request-terminal-parameters
1343 * The sequence DECREPTPARM is sent by the terminal controller to notify
1344 * the host of the status of selected terminal parameters. The status
1345 * sequence may be sent when requested by the host or at the terminal's
1346 * discretion. DECREPTPARM is sent upon receipt of a DECREQTPARM.
1348 * If @args[0] is 0, this marks a request and the terminal is allowed
1349 * to send DECREPTPARM messages without request. If it is 1, the same
1350 * applies but the terminal should no longer send DECREPTPARM
1352 * 2 and 3 mark a report, but 3 is only used if the terminal answers as
1353 * an explicit request with @args[0] == 1.
1355 * The other arguments are ignored in requests, but have the following
1356 * meaning in responses:
1357 * args[1]: 1=no-parity-set 4=parity-set-and-odd 5=parity-set-and-even
1358 * args[2]: 1=8bits-per-char 2=7bits-per-char
1359 * args[3]: transmission-speed
1360 * args[4]: receive-speed
1361 * args[5]: 1=bit-rate-multiplier-is-16
1362 * args[6]: This value communicates the four switch values in block 5
1363 * of SETUP B, which are only visible to the user when an STP
1364 * option is installed. These bits may be assigned for an STP
1365 * device. The four bits are a decimal-encoded binary number.
1366 * Value between 0-15.
1368 * The transmission/receive speeds have mappings for number => bits/s
1369 * which are quite weird. Examples are: 96->3600, 112->9600, 120->19200
1375 if (seq->n_args < 1 || seq->args[0] == 0) {
1376 screen->flags &= ~TERM_FLAG_INHIBIT_TPARM;
1377 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "2;1;1;120;120;1;0x");
1378 } else if (seq->args[0] == 1) {
1379 screen->flags |= TERM_FLAG_INHIBIT_TPARM;
1380 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "3;1;1;120;120;1;0x");
1386 static int screen_DECRPKT(term_screen *screen, const term_seq *seq) {
1388 * DECRPKT - report-key-type
1389 * Response to DECRQKT, we can safely ignore it as we're the one sending
1396 static int screen_DECRQCRA(term_screen *screen, const term_seq *seq) {
1398 * DECRQCRA - request-checksum-of-rectangular-area
1400 * Probably not worth implementing.
1406 static int screen_DECRQDE(term_screen *screen, const term_seq *seq) {
1408 * DECRQDE - request-display-extent
1410 * Probably not worth implementing.
1416 static int screen_DECRQKT(term_screen *screen, const term_seq *seq) {
1418 * DECRQKT - request-key-type
1420 * Probably not worth implementing.
1426 static int screen_DECRQLP(term_screen *screen, const term_seq *seq) {
1428 * DECRQLP - request-locator-position
1429 * See DECELR for locator-information.
1431 * TODO: document and implement
1437 static int screen_DECRQM_ANSI(term_screen *screen, const term_seq *seq) {
1439 * DECRQM_ANSI - request-mode-ansi
1440 * The host sends this control function to find out if a particular mode
1441 * is set or reset. The terminal responds with a report mode function.
1442 * @args[0] contains the mode to query.
1444 * Response is DECRPM with the first argument set to the mode that was
1445 * queried, second argument is 0 if mode is invalid, 1 if mode is set,
1446 * 2 if mode is not set (reset), 3 if mode is permanently set and 4 if
1447 * mode is permanently not set (reset):
1448 * ANSI: ^[ MODE ; VALUE $ y
1449 * DEC: ^[ ? MODE ; VALUE $ y
1457 static int screen_DECRQM_DEC(term_screen *screen, const term_seq *seq) {
1459 * DECRQM_DEC - request-mode-dec
1460 * Same as DECRQM_ANSI but for DEC modes.
1468 static int screen_DECRQPKFM(term_screen *screen, const term_seq *seq) {
1470 * DECRQPKFM - request-program-key-free-memory
1472 * Probably not worth implementing.
1478 static int screen_DECRQPSR(term_screen *screen, const term_seq *seq) {
1480 * DECRQPSR - request-presentation-state-report
1482 * Probably not worth implementing.
1488 static int screen_DECRQTSR(term_screen *screen, const term_seq *seq) {
1490 * DECRQTSR - request-terminal-state-report
1492 * Probably not worth implementing.
1498 static int screen_DECRQUPSS(term_screen *screen, const term_seq *seq) {
1500 * DECRQUPSS - request-user-preferred-supplemental-set
1502 * Probably not worth implementing.
1508 static int screen_DECSACE(term_screen *screen, const term_seq *seq) {
1510 * DECSACE - select-attribute-change-extent
1512 * Probably not worth implementing.
1518 static int screen_DECSASD(term_screen *screen, const term_seq *seq) {
1520 * DECSASD - select-active-status-display
1522 * Probably not worth implementing.
1528 static int screen_DECSC(term_screen *screen, const term_seq *seq) {
1530 * DECSC - save-cursor
1531 * Save cursor and terminal state so it can be restored later on.
1532 * Saves the following items in the terminal's memory:
1534 * * Character attributes set by the SGR command
1535 * * Character sets (G0, G1, G2, or G3) currently in GL and GR
1536 * * Wrap flag (autowrap or no autowrap)
1537 * * State of origin mode (DECOM)
1538 * * Selective erase attribute
1539 * * Any single shift 2 (SS2) or single shift 3 (SS3) functions sent
1542 screen_save_state(screen, &screen->saved);
1547 static int screen_DECSCA(term_screen *screen, const term_seq *seq) {
1549 * DECSCA - select-character-protection-attribute
1550 * Defines the characters that come after it as erasable or not erasable
1551 * from the screen. The selective erase control functions (DECSED and
1552 * DECSEL) can only erase characters defined as erasable.
1554 * @args[0] specifies the new mode. 0 and 2 mark any following character
1555 * as erasable, 1 marks it as not erasable.
1561 unsigned int mode = 0;
1563 if (seq->args[0] > 0)
1564 mode = seq->args[0];
1569 screen->state.attr.protect = 0;
1572 screen->state.attr.protect = 1;
1579 static int screen_DECSCL(term_screen *screen, const term_seq *seq) {
1581 * DECSCL - select-conformance-level
1582 * Select the terminal's operating level. The factory default is
1583 * level 4 (VT Level 4 mode, 7-bit controls).
1584 * When you change the conformance level, the terminal performs a hard
1587 * @args[0] defines the conformance-level, valid values are:
1588 * 61: Level 1 (VT100)
1589 * 62: Level 2 (VT200)
1590 * 63: Level 3 (VT300)
1591 * 64: Level 4 (VT400)
1592 * @args[1] defines the 8bit-mode, valid values are:
1595 * 2: 8-bit controls (same as 0)
1597 * If @args[0] is 61, then @args[1] is ignored and 7bit controls are
1605 unsigned int level = 64, bit = 0;
1607 if (seq->n_args > 0) {
1608 level = seq->args[0];
1609 if (seq->n_args > 1)
1613 term_screen_hard_reset(screen);
1617 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT100;
1618 screen->flags |= TERM_FLAG_7BIT_MODE;
1621 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
1623 screen->flags |= TERM_FLAG_7BIT_MODE;
1625 screen->flags &= ~TERM_FLAG_7BIT_MODE;
1632 static int screen_DECSCP(term_screen *screen, const term_seq *seq) {
1634 * DECSCP - select-communication-port
1636 * Probably not worth implementing.
1642 static int screen_DECSCPP(term_screen *screen, const term_seq *seq) {
1644 * DECSCPP - select-columns-per-page
1645 * Select columns per page. The number of rows is unaffected by this.
1646 * @args[0] selectes the number of columns (width), DEC only defines 80
1647 * and 132, but we allow any integer here. 0 is equivalent to 80.
1648 * Page content is *not* cleared and the cursor is left untouched.
1649 * However, if the page is reduced in width and the cursor would be
1650 * outside the visible region, it's set to the right border. Newly added
1651 * cells are cleared. No data is retained outside the visible region.
1662 static int screen_DECSCS(term_screen *screen, const term_seq *seq) {
1664 * DECSCS - select-communication-speed
1666 * Probably not worth implementing.
1672 static int screen_DECSCUSR(term_screen *screen, const term_seq *seq) {
1674 * DECSCUSR - set-cursor-style
1675 * This changes the style of the cursor. @args[0] can be one of:
1676 * 0, 1: blinking block
1678 * 3: blinking underline
1679 * 4: steady underline
1680 * Changing this setting does _not_ affect the cursor visibility itself.
1681 * Use DECTCEM for that.
1692 static int screen_DECSDDT(term_screen *screen, const term_seq *seq) {
1694 * DECSDDT - select-disconnect-delay-time
1696 * Probably not worth implementing.
1702 static int screen_DECSDPT(term_screen *screen, const term_seq *seq) {
1704 * DECSDPT - select-digital-printed-data-type
1706 * Probably not worth implementing.
1712 static int screen_DECSED(term_screen *screen, const term_seq *seq) {
1714 * DECSED - selective-erase-in-display
1715 * This control function erases some or all of the erasable characters
1716 * in the display. DECSED can only erase characters defined as erasable
1717 * by the DECSCA control function. DECSED works inside or outside the
1718 * scrolling margins.
1720 * @args[0] defines which regions are erased. If it is 0, all cells from
1721 * the cursor (inclusive) till the end of the display are erase. If it
1722 * is 1, all cells from the start of the display till the cursor
1723 * (inclusive) are erased. If it is 2, all cells are erased.
1729 unsigned int mode = 0;
1731 if (seq->args[0] > 0)
1732 mode = seq->args[0];
1736 term_page_erase(screen->page,
1737 screen->state.cursor_x, screen->state.cursor_y,
1738 screen->page->width, screen->page->height,
1739 &screen->state.attr, screen->age, true);
1742 term_page_erase(screen->page,
1744 screen->state.cursor_x, screen->state.cursor_y,
1745 &screen->state.attr, screen->age, true);
1748 term_page_erase(screen->page,
1750 screen->page->width, screen->page->height,
1751 &screen->state.attr, screen->age, true);
1758 static int screen_DECSEL(term_screen *screen, const term_seq *seq) {
1760 * DECSEL - selective-erase-in-line
1761 * This control function erases some or all of the erasable characters
1762 * in a single line of text. DECSEL erases only those characters defined
1763 * as erasable by the DECSCA control function. DECSEL works inside or
1764 * outside the scrolling margins.
1766 * @args[0] defines the region to be erased. If it is 0, all cells from
1767 * the cursor (inclusive) till the end of the line are erase. If it is
1768 * 1, all cells from the start of the line till the cursor (inclusive)
1769 * are erased. If it is 2, the whole line of the cursor is erased.
1775 unsigned int mode = 0;
1777 if (seq->args[0] > 0)
1778 mode = seq->args[0];
1782 term_page_erase(screen->page,
1783 screen->state.cursor_x, screen->state.cursor_y,
1784 screen->page->width, screen->state.cursor_y,
1785 &screen->state.attr, screen->age, true);
1788 term_page_erase(screen->page,
1789 0, screen->state.cursor_y,
1790 screen->state.cursor_x, screen->state.cursor_y,
1791 &screen->state.attr, screen->age, true);
1794 term_page_erase(screen->page,
1795 0, screen->state.cursor_y,
1796 screen->page->width, screen->state.cursor_y,
1797 &screen->state.attr, screen->age, true);
1804 static int screen_DECSERA(term_screen *screen, const term_seq *seq) {
1806 * DECSERA - selective-erase-rectangular-area
1808 * Probably not worth implementing.
1814 static int screen_DECSFC(term_screen *screen, const term_seq *seq) {
1816 * DECSFC - select-flow-control
1818 * Probably not worth implementing.
1824 static int screen_DECSKCV(term_screen *screen, const term_seq *seq) {
1826 * DECSKCV - set-key-click-volume
1828 * Probably not worth implementing.
1834 static int screen_DECSLCK(term_screen *screen, const term_seq *seq) {
1836 * DECSLCK - set-lock-key-style
1838 * Probably not worth implementing.
1844 static int screen_DECSLE(term_screen *screen, const term_seq *seq) {
1846 * DECSLE - select-locator-events
1854 static int screen_DECSLPP(term_screen *screen, const term_seq *seq) {
1856 * DECSLPP - set-lines-per-page
1857 * Set the number of lines used for the page. @args[0] specifies the
1858 * number of lines to be used. DEC only allows a limited number of
1859 * choices, however, we allow all integers. 0 is equivalent to 24.
1870 static int screen_DECSLRM_OR_SC(term_screen *screen, const term_seq *seq) {
1872 * DECSLRM_OR_SC - set-left-and-right-margins or save-cursor
1874 * TODO: Detect save-cursor and run it. DECSLRM is not worth
1881 static int screen_DECSMBV(term_screen *screen, const term_seq *seq) {
1883 * DECSMBV - set-margin-bell-volume
1885 * Probably not worth implementing.
1891 static int screen_DECSMKR(term_screen *screen, const term_seq *seq) {
1893 * DECSMKR - select-modifier-key-reporting
1895 * Probably not worth implementing.
1901 static int screen_DECSNLS(term_screen *screen, const term_seq *seq) {
1903 * DECSNLS - set-lines-per-screen
1905 * Probably not worth implementing.
1911 static int screen_DECSPP(term_screen *screen, const term_seq *seq) {
1913 * DECSPP - set-port-parameter
1915 * Probably not worth implementing.
1921 static int screen_DECSPPCS(term_screen *screen, const term_seq *seq) {
1923 * DECSPPCS - select-pro-printer-character-set
1925 * Probably not worth implementing.
1931 static int screen_DECSPRTT(term_screen *screen, const term_seq *seq) {
1933 * DECSPRTT - select-printer-type
1935 * Probably not worth implementing.
1941 static int screen_DECSR(term_screen *screen, const term_seq *seq) {
1943 * DECSR - secure-reset
1945 * Probably not worth implementing.
1951 static int screen_DECSRFR(term_screen *screen, const term_seq *seq) {
1953 * DECSRFR - select-refresh-rate
1955 * Probably not worth implementing.
1961 static int screen_DECSSCLS(term_screen *screen, const term_seq *seq) {
1963 * DECSSCLS - set-scroll-speed
1965 * Probably not worth implementing.
1971 static int screen_DECSSDT(term_screen *screen, const term_seq *seq) {
1973 * DECSSDT - select-status-display-line-type
1975 * Probably not worth implementing.
1981 static int screen_DECSSL(term_screen *screen, const term_seq *seq) {
1983 * DECSSL - select-setup-language
1985 * Probably not worth implementing.
1991 static int screen_DECST8C(term_screen *screen, const term_seq *seq) {
1993 * DECST8C - set-tab-at-every-8-columns
1994 * Clear the tab-ruler and reset it to a tab at every 8th column,
1995 * starting at 9 (though, setting a tab at 1 is fine as it has no
2001 for (i = 0; i < screen->page->width; i += 8)
2002 screen->tabs[i / 8] = 0x1;
2007 static int screen_DECSTBM(term_screen *screen, const term_seq *seq) {
2009 * DECSTBM - set-top-and-bottom-margins
2010 * This control function sets the top and bottom margins for the current
2011 * page. You cannot perform scrolling outside the margins.
2013 * @args[0] defines the top margin, @args[1] defines the bottom margin.
2014 * The bottom margin must be lower than the top-margin.
2016 * This call resets the cursor position to 0/0 of the page.
2020 * args[1]: last page-line
2023 unsigned int top, bottom;
2026 bottom = screen->page->height;
2028 if (seq->args[0] > 0)
2030 if (seq->args[1] > 0)
2031 bottom = seq->args[1];
2033 if (top > screen->page->height)
2034 top = screen->page->height;
2035 if (bottom > screen->page->height)
2036 bottom = screen->page->height;
2038 if (top >= bottom || top > screen->page->height || bottom > screen->page->height) {
2040 bottom = screen->page->height;
2043 term_page_set_scroll_region(screen->page, top - 1, bottom - top + 1);
2044 screen_cursor_clear_wrap(screen);
2045 screen_cursor_set(screen, 0, 0);
2050 static int screen_DECSTR(term_screen *screen, const term_seq *seq) {
2052 * DECSTR - soft-terminal-reset
2053 * Perform a soft reset to the default values.
2056 term_screen_soft_reset(screen);
2061 static int screen_DECSTRL(term_screen *screen, const term_seq *seq) {
2063 * DECSTRL - set-transmit-rate-limit
2065 * Probably not worth implementing.
2071 static int screen_DECSWBV(term_screen *screen, const term_seq *seq) {
2073 * DECSWBV - set-warning-bell-volume
2075 * Probably not worth implementing.
2081 static int screen_DECSWL(term_screen *screen, const term_seq *seq) {
2083 * DECSWL - single-width-single-height-line
2085 * Probably not worth implementing.
2091 static int screen_DECTID(term_screen *screen, const term_seq *seq) {
2093 * DECTID - select-terminal-id
2095 * Probably not worth implementing.
2101 static int screen_DECTME(term_screen *screen, const term_seq *seq) {
2103 * DECTME - terminal-mode-emulation
2105 * Probably not worth implementing.
2111 static int screen_DECTST(term_screen *screen, const term_seq *seq) {
2113 * DECTST - invoke-confidence-test
2115 * Probably not worth implementing.
2121 static int screen_DL(term_screen *screen, const term_seq *seq) {
2124 * This control function deletes one or more lines in the scrolling
2125 * region, starting with the line that has the cursor. @args[0] defines
2126 * the number of lines to delete. 0 is treated the same as 1.
2127 * As lines are deleted, lines below the cursor and in the scrolling
2128 * region move up. The terminal adds blank lines with no visual
2129 * character attributes at the bottom of the scrolling region. If it is
2130 * greater than the number of lines remaining on the page, DL deletes
2131 * only the remaining lines. DL has no effect outside the scrolling
2138 unsigned int num = 1;
2140 if (seq->args[0] > 0)
2143 term_page_delete_lines(screen->page, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2148 static int screen_DSR_ANSI(term_screen *screen, const term_seq *seq) {
2150 * DSR_ANSI - device-status-report-ansi
2158 static int screen_DSR_DEC(term_screen *screen, const term_seq *seq) {
2160 * DSR_DEC - device-status-report-dec
2168 static int screen_ECH(term_screen *screen, const term_seq *seq) {
2170 * ECH - erase-character
2171 * This control function erases one or more characters, from the cursor
2172 * position to the right. ECH clears character attributes from erased
2173 * character positions. ECH works inside or outside the scrolling
2175 * @args[0] defines the number of characters to erase. 0 is treated the
2182 unsigned int num = 1;
2184 if (seq->args[0] > 0)
2187 term_page_erase(screen->page,
2188 screen->state.cursor_x, screen->state.cursor_y,
2189 screen->state.cursor_x + num, screen->state.cursor_y,
2190 &screen->state.attr, screen->age, false);
2195 static int screen_ED(term_screen *screen, const term_seq *seq) {
2197 * ED - erase-in-display
2198 * This control function erases characters from part or all of the
2199 * display. When you erase complete lines, they become single-height,
2200 * single-width lines, with all visual character attributes cleared. ED
2201 * works inside or outside the scrolling margins.
2203 * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2204 * till the end of the screen. 1 means from the start of the screen till
2205 * the cursor (inclusive) and 2 means the whole screen.
2211 unsigned int mode = 0;
2213 if (seq->args[0] > 0)
2214 mode = seq->args[0];
2218 term_page_erase(screen->page,
2219 screen->state.cursor_x, screen->state.cursor_y,
2220 screen->page->width, screen->page->height,
2221 &screen->state.attr, screen->age, false);
2224 term_page_erase(screen->page,
2226 screen->state.cursor_x, screen->state.cursor_y,
2227 &screen->state.attr, screen->age, false);
2230 term_page_erase(screen->page,
2232 screen->page->width, screen->page->height,
2233 &screen->state.attr, screen->age, false);
2240 static int screen_EL(term_screen *screen, const term_seq *seq) {
2242 * EL - erase-in-line
2243 * This control function erases characters on the line that has the
2244 * cursor. EL clears all character attributes from erased character
2245 * positions. EL works inside or outside the scrolling margins.
2247 * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2248 * till the end of the line. 1 means from the start of the line till the
2249 * cursor (inclusive) and 2 means the whole line.
2255 unsigned int mode = 0;
2257 if (seq->args[0] > 0)
2258 mode = seq->args[0];
2262 term_page_erase(screen->page,
2263 screen->state.cursor_x, screen->state.cursor_y,
2264 screen->page->width, screen->state.cursor_y,
2265 &screen->state.attr, screen->age, false);
2268 term_page_erase(screen->page,
2269 0, screen->state.cursor_y,
2270 screen->state.cursor_x, screen->state.cursor_y,
2271 &screen->state.attr, screen->age, false);
2274 term_page_erase(screen->page,
2275 0, screen->state.cursor_y,
2276 screen->page->width, screen->state.cursor_y,
2277 &screen->state.attr, screen->age, false);
2284 static int screen_ENQ(term_screen *screen, const term_seq *seq) {
2287 * Transmit the answerback-string. If none is set, do nothing.
2290 if (screen->answerback)
2291 return screen_write(screen, screen->answerback, strlen(screen->answerback));
2296 static int screen_EPA(term_screen *screen, const term_seq *seq) {
2298 * EPA - end-of-guarded-area
2300 * TODO: What is this?
2306 static int screen_FF(term_screen *screen, const term_seq *seq) {
2309 * This causes the cursor to jump to the next line. It is treated the
2313 return screen_LF(screen, seq);
2316 static int screen_HPA(term_screen *screen, const term_seq *seq) {
2318 * HPA - horizontal-position-absolute
2319 * HPA causes the active position to be moved to the n-th horizontal
2320 * position of the active line. If an attempt is made to move the active
2321 * position past the last position on the line, then the active position
2322 * stops at the last position on the line.
2324 * @args[0] defines the horizontal position. 0 is treated as 1.
2330 unsigned int num = 1;
2332 if (seq->args[0] > 0)
2335 screen_cursor_clear_wrap(screen);
2336 screen_cursor_set(screen, num - 1, screen->state.cursor_y);
2341 static int screen_HPR(term_screen *screen, const term_seq *seq) {
2343 * HPR - horizontal-position-relative
2344 * HPR causes the active position to be moved to the n-th following
2345 * horizontal position of the active line. If an attempt is made to move
2346 * the active position past the last position on the line, then the
2347 * active position stops at the last position on the line.
2349 * @args[0] defines the horizontal position. 0 is treated as 1.
2355 unsigned int num = 1;
2357 if (seq->args[0] > 0)
2360 screen_cursor_clear_wrap(screen);
2361 screen_cursor_right(screen, num);
2366 static int screen_HT(term_screen *screen, const term_seq *seq) {
2368 * HT - horizontal-tab
2369 * Moves the cursor to the next tab stop. If there are no more tab
2370 * stops, the cursor moves to the right margin. HT does not cause text
2374 screen_cursor_clear_wrap(screen);
2375 screen_cursor_right_tab(screen, 1);
2380 static int screen_HTS(term_screen *screen, const term_seq *seq) {
2382 * HTS - horizontal-tab-set
2383 * HTS sets a horizontal tab stop at the column position indicated by
2384 * the value of the active column when the terminal receives an HTS.
2386 * Executing an HTS does not effect the other horizontal tab stop
2392 pos = screen->state.cursor_x;
2393 if (screen->page->width > 0)
2394 screen->tabs[pos / 8] |= 1U << (pos % 8);
2399 static int screen_HVP(term_screen *screen, const term_seq *seq) {
2401 * HVP - horizontal-and-vertical-position
2402 * This control function works the same as the cursor position (CUP)
2403 * function. Origin mode (DECOM) selects line numbering and the ability
2404 * to move the cursor into margins.
2411 return screen_CUP(screen, seq);
2414 static int screen_ICH(term_screen *screen, const term_seq *seq) {
2416 * ICH - insert-character
2417 * This control function inserts one or more space (SP) characters
2418 * starting at the cursor position. @args[0] is the number of characters
2419 * to insert. 0 is treated as 1.
2421 * The ICH sequence inserts blank characters with the normal
2422 * character attribute. The cursor remains at the beginning of the blank
2423 * characters. Text between the cursor and right margin moves to the
2424 * right. Characters scrolled past the right margin are lost. ICH has no
2425 * effect outside the scrolling margins.
2431 unsigned int num = 1;
2433 if (seq->args[0] > 0)
2436 screen_cursor_clear_wrap(screen);
2437 term_page_insert_cells(screen->page, screen->state.cursor_x, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2442 static int screen_IL(term_screen *screen, const term_seq *seq) {
2445 * This control function inserts one or more blank lines, starting at
2446 * the cursor. @args[0] is the number of lines to insert. 0 is treated
2449 * As lines are inserted, lines below the cursor and in the scrolling
2450 * region move down. Lines scrolled off the page are lost. IL has no
2451 * effect outside the page margins.
2457 unsigned int num = 1;
2459 if (seq->args[0] > 0)
2462 screen_cursor_clear_wrap(screen);
2463 term_page_insert_lines(screen->page, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2468 static int screen_IND(term_screen *screen, const term_seq *seq) {
2471 * IND moves the cursor down one line in the same column. If the cursor
2472 * is at the bottom margin, then the screen performs a scroll-up.
2475 screen_cursor_down(screen, 1, true);
2480 static int screen_LF(term_screen *screen, const term_seq *seq) {
2483 * Causes a line feed or a new line operation, depending on the setting
2484 * of line feed/new line mode.
2487 screen_cursor_down(screen, 1, true);
2488 if (screen->flags & TERM_FLAG_NEWLINE_MODE)
2489 screen_cursor_left(screen, screen->state.cursor_x);
2494 static int screen_LS1R(term_screen *screen, const term_seq *seq) {
2496 * LS1R - locking-shift-1-right
2500 screen->state.gr = &screen->g1;
2505 static int screen_LS2(term_screen *screen, const term_seq *seq) {
2507 * LS2 - locking-shift-2
2511 screen->state.gl = &screen->g2;
2516 static int screen_LS2R(term_screen *screen, const term_seq *seq) {
2518 * LS2R - locking-shift-2-right
2522 screen->state.gr = &screen->g2;
2527 static int screen_LS3(term_screen *screen, const term_seq *seq) {
2529 * LS3 - locking-shift-3
2533 screen->state.gl = &screen->g3;
2538 static int screen_LS3R(term_screen *screen, const term_seq *seq) {
2540 * LS3R - locking-shift-3-right
2544 screen->state.gr = &screen->g3;
2549 static int screen_MC_ANSI(term_screen *screen, const term_seq *seq) {
2551 * MC_ANSI - media-copy-ansi
2553 * Probably not worth implementing.
2559 static int screen_MC_DEC(term_screen *screen, const term_seq *seq) {
2561 * MC_DEC - media-copy-dec
2563 * Probably not worth implementing.
2569 static int screen_NEL(term_screen *screen, const term_seq *seq) {
2572 * Moves cursor to first position on next line. If cursor is at bottom
2573 * margin, then screen performs a scroll-up.
2576 screen_cursor_clear_wrap(screen);
2577 screen_cursor_down(screen, 1, true);
2578 screen_cursor_set(screen, 0, screen->state.cursor_y);
2583 static int screen_NP(term_screen *screen, const term_seq *seq) {
2586 * This control function moves the cursor forward to the home position
2587 * on one of the following pages in page memory. If there is only one
2588 * page, then the terminal ignores NP.
2589 * If NP tries to move the cursor past the last page in memory, then the
2590 * cursor stops at the last page.
2592 * @args[0] defines the number of pages to forward. 0 is treated as 1.
2597 * Probably not worth implementing. We only support a single page.
2603 static int screen_NULL(term_screen *screen, const term_seq *seq) {
2606 * The NULL operation does nothing. ASCII NULL is always ignored.
2612 static int screen_PP(term_screen *screen, const term_seq *seq) {
2614 * PP - preceding-page
2615 * This control function moves the cursor backward to the home position
2616 * on one of the preceding pages in page memory. If there is only one
2617 * page, then the terminal ignores PP.
2618 * If PP tries to move the cursor back farther than the first page in
2619 * memory, then the cursor stops at the first page.
2621 * @args[0] defines the number of pages to go backwards. 0 is treated
2627 * Probably not worth implementing. We only support a single page.
2633 static int screen_PPA(term_screen *screen, const term_seq *seq) {
2635 * PPA - page-position-absolute
2636 * This control function can move the cursor to the corresponding row
2637 * and column on any page in page memory. You select the page by its
2638 * number. If there is only one page, then the terminal ignores PPA.
2640 * @args[0] is the number of the page to move the cursor to. If it is
2641 * greater than the number of the last page in memory, then the cursor
2642 * stops at the last page. If it is less than the number of the first
2643 * page, then the cursor stops at the first page.
2648 * Probably not worth implementing. We only support a single page.
2654 static int screen_PPB(term_screen *screen, const term_seq *seq) {
2656 * PPB - page-position-backward
2657 * This control function moves the cursor backward to the corresponding
2658 * row and column on one of the preceding pages in page memory. If there
2659 * is only one page, then the terminal ignores PPB.
2661 * @args[0] indicates the number of pages to move the cursor backward.
2662 * If it tries to move the cursor back farther than the first page in
2663 * memory, then the cursor stops at the first page. 0 is treated as 1.
2668 * Probably not worth implementing. We only support a single page.
2674 static int screen_PPR(term_screen *screen, const term_seq *seq) {
2676 * PPR - page-position-relative
2677 * This control function moves the cursor forward to the corresponding
2678 * row and column on one of the following pages in page memory. If there
2679 * is only one page, then the terminal ignores PPR.
2681 * @args[0] indicates how many pages to move the cursor forward. If it
2682 * tries to move the cursor beyond the last page in memory, then the
2683 * cursor stops at the last page. 0 is treated as 1.
2688 * Probably not worth implementing. We only support a single page.
2694 static int screen_RC(term_screen *screen, const term_seq *seq) {
2696 * RC - restore-cursor
2699 return screen_DECRC(screen, seq);
2702 static int screen_REP(term_screen *screen, const term_seq *seq) {
2705 * Repeat the preceding graphics-character the given number of times.
2706 * @args[0] specifies how often it shall be repeated. 0 is treated as 1.
2711 * Probably not worth implementing.
2717 static int screen_RI(term_screen *screen, const term_seq *seq) {
2719 * RI - reverse-index
2720 * Moves the cursor up one line in the same column. If the cursor is at
2721 * the top margin, the page scrolls down.
2724 screen_cursor_up(screen, 1, true);
2729 static int screen_RIS(term_screen *screen, const term_seq *seq) {
2731 * RIS - reset-to-initial-state
2732 * This control function causes a nonvolatile memory (NVR) recall to
2733 * occur. RIS replaces all set-up features with their saved settings.
2735 * The terminal stores these saved settings in NVR memory. The saved
2736 * setting for a feature is the same as the factory-default setting,
2737 * unless you saved a new setting.
2740 term_screen_hard_reset(screen);
2745 static int screen_RM_ANSI(term_screen *screen, const term_seq *seq) {
2747 * RM_ANSI - reset-mode-ansi
2749 * TODO: implement (see VT510rm manual)
2754 for (i = 0; i < seq->n_args; ++i)
2755 screen_mode_change_ansi(screen, seq->args[i], false);
2760 static int screen_RM_DEC(term_screen *screen, const term_seq *seq) {
2762 * RM_DEC - reset-mode-dec
2763 * This is the same as RM_ANSI but for DEC modes.
2768 for (i = 0; i < seq->n_args; ++i)
2769 screen_mode_change_dec(screen, seq->args[i], false);
2774 static int screen_S7C1T(term_screen *screen, const term_seq *seq) {
2776 * S7C1T - set-7bit-c1-terminal
2777 * This causes the terminal to start sending C1 controls as 7bit
2778 * sequences instead of 8bit C1 controls.
2779 * This is ignored if the terminal is below level-2 emulation mode
2780 * (VT100 and below), the terminal already sends 7bit controls then.
2783 if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2784 screen->flags |= TERM_FLAG_7BIT_MODE;
2789 static int screen_S8C1T(term_screen *screen, const term_seq *seq) {
2791 * S8C1T - set-8bit-c1-terminal
2792 * This causes the terminal to start sending C1 controls as 8bit C1
2793 * control instead of 7bit sequences.
2794 * This is ignored if the terminal is below level-2 emulation mode
2795 * (VT100 and below). The terminal always sends 7bit controls in those
2799 if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2800 screen->flags &= ~TERM_FLAG_7BIT_MODE;
2805 static int screen_SCS(term_screen *screen, const term_seq *seq) {
2807 * SCS - select-character-set
2808 * Designate character sets to G-sets. The mapping from intermediates
2809 * and terminal characters in the escape sequence to G-sets and
2810 * character-sets is non-trivial and implemented separately. See there
2811 * for more information.
2812 * This call simply sets the selected G-set to the desired
2816 term_charset *cs = NULL;
2818 /* TODO: support more of them? */
2819 switch (seq->charset) {
2820 case TERM_CHARSET_ISO_LATIN1_SUPPLEMENTAL:
2821 case TERM_CHARSET_ISO_LATIN2_SUPPLEMENTAL:
2822 case TERM_CHARSET_ISO_LATIN5_SUPPLEMENTAL:
2823 case TERM_CHARSET_ISO_GREEK_SUPPLEMENTAL:
2824 case TERM_CHARSET_ISO_HEBREW_SUPPLEMENTAL:
2825 case TERM_CHARSET_ISO_LATIN_CYRILLIC:
2828 case TERM_CHARSET_DEC_SPECIAL_GRAPHIC:
2829 cs = &term_dec_special_graphics;
2831 case TERM_CHARSET_DEC_SUPPLEMENTAL:
2832 cs = &term_dec_supplemental_graphics;
2834 case TERM_CHARSET_DEC_TECHNICAL:
2835 case TERM_CHARSET_CYRILLIC_DEC:
2836 case TERM_CHARSET_DUTCH_NRCS:
2837 case TERM_CHARSET_FINNISH_NRCS:
2838 case TERM_CHARSET_FRENCH_NRCS:
2839 case TERM_CHARSET_FRENCH_CANADIAN_NRCS:
2840 case TERM_CHARSET_GERMAN_NRCS:
2841 case TERM_CHARSET_GREEK_DEC:
2842 case TERM_CHARSET_GREEK_NRCS:
2843 case TERM_CHARSET_HEBREW_DEC:
2844 case TERM_CHARSET_HEBREW_NRCS:
2845 case TERM_CHARSET_ITALIAN_NRCS:
2846 case TERM_CHARSET_NORWEGIAN_DANISH_NRCS:
2847 case TERM_CHARSET_PORTUGUESE_NRCS:
2848 case TERM_CHARSET_RUSSIAN_NRCS:
2849 case TERM_CHARSET_SCS_NRCS:
2850 case TERM_CHARSET_SPANISH_NRCS:
2851 case TERM_CHARSET_SWEDISH_NRCS:
2852 case TERM_CHARSET_SWISS_NRCS:
2853 case TERM_CHARSET_TURKISH_DEC:
2854 case TERM_CHARSET_TURKISH_NRCS:
2857 case TERM_CHARSET_USERPREF_SUPPLEMENTAL:
2861 if (seq->intermediates & TERM_SEQ_FLAG_POPEN)
2862 screen->g0 = cs ? : &term_unicode_lower;
2863 else if (seq->intermediates & TERM_SEQ_FLAG_PCLOSE)
2864 screen->g1 = cs ? : &term_unicode_upper;
2865 else if (seq->intermediates & TERM_SEQ_FLAG_MULT)
2866 screen->g2 = cs ? : &term_unicode_lower;
2867 else if (seq->intermediates & TERM_SEQ_FLAG_PLUS)
2868 screen->g3 = cs ? : &term_unicode_upper;
2869 else if (seq->intermediates & TERM_SEQ_FLAG_MINUS)
2870 screen->g1 = cs ? : &term_unicode_upper;
2871 else if (seq->intermediates & TERM_SEQ_FLAG_DOT)
2872 screen->g2 = cs ? : &term_unicode_lower;
2873 else if (seq->intermediates & TERM_SEQ_FLAG_SLASH)
2874 screen->g3 = cs ? : &term_unicode_upper;
2879 static int screen_SD(term_screen *screen, const term_seq *seq) {
2882 * This control function moves the user window down a specified number
2883 * of lines in page memory.
2884 * @args[0] is the number of lines to move the
2885 * user window up in page memory. New lines appear at the top of the
2886 * display. Old lines disappear at the bottom of the display. You
2887 * cannot pan past the top margin of the current page. 0 is treated
2894 unsigned int num = 1;
2896 if (seq->args[0] > 0)
2899 term_page_scroll_down(screen->page, num, &screen->state.attr, screen->age, NULL);
2904 static int screen_SGR(term_screen *screen, const term_seq *seq) {
2906 * SGR - select-graphics-rendition
2910 unsigned int i, code;
2913 if (seq->n_args < 1) {
2914 zero(screen->state.attr);
2918 for (i = 0; i < seq->n_args; ++i) {
2922 screen->state.attr.bold = 1;
2925 screen->state.attr.italic = 1;
2928 screen->state.attr.underline = 1;
2931 screen->state.attr.blink = 1;
2934 screen->state.attr.inverse = 1;
2937 screen->state.attr.hidden = 1;
2940 screen->state.attr.bold = 0;
2943 screen->state.attr.italic = 0;
2946 screen->state.attr.underline = 0;
2949 screen->state.attr.blink = 0;
2952 screen->state.attr.inverse = 0;
2955 screen->state.attr.hidden = 0;
2958 screen->state.attr.fg.ccode = v - 30 + TERM_CCODE_BLACK;
2961 screen->state.attr.fg.ccode = 0;
2964 screen->state.attr.bg.ccode = v - 40 + TERM_CCODE_BLACK;
2967 screen->state.attr.bg.ccode = 0;
2970 screen->state.attr.fg.ccode = v - 90 + TERM_CCODE_LIGHT_BLACK;
2973 screen->state.attr.bg.ccode = v - 100 + TERM_CCODE_LIGHT_BLACK;
2980 dst = &screen->state.attr.fg;
2982 dst = &screen->state.attr.bg;
2985 if (i >= seq->n_args)
2988 switch (seq->args[i]) {
2990 /* 24bit-color support */
2993 if (i >= seq->n_args)
2996 dst->ccode = TERM_CCODE_RGB;
2997 dst->red = (seq->args[i - 2] >= 0) ? seq->args[i - 2] : 0;
2998 dst->green = (seq->args[i - 1] >= 0) ? seq->args[i - 1] : 0;
2999 dst->blue = (seq->args[i] >= 0) ? seq->args[i] : 0;
3003 /* 256-color support */
3006 if (i >= seq->n_args || seq->args[i] < 0)
3009 dst->ccode = TERM_CCODE_256;
3010 code = seq->args[i];
3011 dst->c256 = code < 256 ? code : 0;
3020 zero(screen->state.attr);
3028 static int screen_SI(term_screen *screen, const term_seq *seq) {
3034 screen->state.gl = &screen->g0;
3039 static int screen_SM_ANSI(term_screen *screen, const term_seq *seq) {
3041 * SM_ANSI - set-mode-ansi
3048 for (i = 0; i < seq->n_args; ++i)
3049 screen_mode_change_ansi(screen, seq->args[i], true);
3054 static int screen_SM_DEC(term_screen *screen, const term_seq *seq) {
3056 * SM_DEC - set-mode-dec
3057 * This is the same as SM_ANSI but for DEC modes.
3062 for (i = 0; i < seq->n_args; ++i)
3063 screen_mode_change_dec(screen, seq->args[i], true);
3068 static int screen_SO(term_screen *screen, const term_seq *seq) {
3074 screen->state.gl = &screen->g1;
3079 static int screen_SPA(term_screen *screen, const term_seq *seq) {
3081 * SPA - start-of-protected-area
3083 * TODO: What is this?
3089 static int screen_SS2(term_screen *screen, const term_seq *seq) {
3091 * SS2 - single-shift-2
3092 * Temporarily map G2 into GL for the next graphics character.
3095 screen->state.glt = &screen->g2;
3100 static int screen_SS3(term_screen *screen, const term_seq *seq) {
3102 * SS3 - single-shift-3
3103 * Temporarily map G3 into GL for the next graphics character
3106 screen->state.glt = &screen->g3;
3111 static int screen_ST(term_screen *screen, const term_seq *seq) {
3113 * ST - string-terminator
3114 * The string-terminator is usually part of control-sequences and
3115 * handled by the parser. In all other situations it is silently
3122 static int screen_SU(term_screen *screen, const term_seq *seq) {
3125 * This control function moves the user window up a specified number of
3126 * lines in page memory.
3127 * @args[0] is the number of lines to move the
3128 * user window down in page memory. New lines appear at the bottom of
3129 * the display. Old lines disappear at the top of the display. You
3130 * cannot pan past the bottom margin of the current page. 0 is treated
3137 unsigned int num = 1;
3139 if (seq->args[0] > 0)
3142 term_page_scroll_up(screen->page, num, &screen->state.attr, screen->age, screen->history);
3147 static int screen_SUB(term_screen *screen, const term_seq *seq) {
3150 * Cancel the current control-sequence and print a replacement
3151 * character. Our parser already handles this so all we have to do is
3152 * print the replacement character.
3155 static const term_seq rep = {
3156 .type = TERM_SEQ_GRAPHIC,
3157 .command = TERM_CMD_GRAPHIC,
3158 .terminator = 0xfffd,
3161 return screen_GRAPHIC(screen, &rep);
3164 static int screen_TBC(term_screen *screen, const term_seq *seq) {
3167 * This clears tab-stops. If @args[0] is 0, the tab-stop at the current
3168 * cursor position is cleared. If it is 3, all tab stops are cleared.
3174 unsigned int mode = 0, pos;
3176 if (seq->args[0] > 0)
3177 mode = seq->args[0];
3181 pos = screen->state.cursor_x;
3182 if (screen->page->width > 0)
3183 screen->tabs[pos / 8] &= ~(1U << (pos % 8));
3186 if (screen->page->width > 0)
3187 memset(screen->tabs, 0, (screen->page->width + 7) / 8);
3194 static int screen_VPA(term_screen *screen, const term_seq *seq) {
3196 * VPA - vertical-line-position-absolute
3197 * VPA causes the active position to be moved to the corresponding
3198 * horizontal position. @args[0] specifies the line to jump to. If an
3199 * attempt is made to move the active position below the last line, then
3200 * the active position stops on the last line. 0 is treated as 1.
3206 unsigned int pos = 1;
3208 if (seq->args[0] > 0)
3211 screen_cursor_clear_wrap(screen);
3212 screen_cursor_set_rel(screen, screen->state.cursor_x, pos - 1);
3217 static int screen_VPR(term_screen *screen, const term_seq *seq) {
3219 * VPR - vertical-line-position-relative
3220 * VPR causes the active position to be moved to the corresponding
3221 * horizontal position. @args[0] specifies the number of lines to jump
3222 * down relative to the current cursor position. If an attempt is made
3223 * to move the active position below the last line, the active position
3224 * stops at the last line. 0 is treated as 1.
3230 unsigned int num = 1;
3232 if (seq->args[0] > 0)
3235 screen_cursor_clear_wrap(screen);
3236 screen_cursor_down(screen, num, false);
3241 static int screen_VT(term_screen *screen, const term_seq *seq) {
3244 * This causes a vertical jump by one line. Terminals treat it exactly
3248 return screen_LF(screen, seq);
3251 static int screen_XTERM_CLLHP(term_screen *screen, const term_seq *seq) {
3253 * XTERM_CLLHP - xterm-cursor-lower-left-hp-bugfix
3254 * Move the cursor to the lower-left corner of the page. This is an HP
3257 * Probably not worth implementing.
3263 static int screen_XTERM_IHMT(term_screen *screen, const term_seq *seq) {
3265 * XTERM_IHMT - xterm-initiate-highlight-mouse-tracking
3267 * Probably not worth implementing.
3273 static int screen_XTERM_MLHP(term_screen *screen, const term_seq *seq) {
3275 * XTERM_MLHP - xterm-memory-lock-hp-bugfix
3277 * Probably not worth implementing.
3283 static int screen_XTERM_MUHP(term_screen *screen, const term_seq *seq) {
3285 * XTERM_MUHP - xterm-memory-unlock-hp-bugfix
3287 * Probably not worth implementing.
3293 static int screen_XTERM_RPM(term_screen *screen, const term_seq *seq) {
3295 * XTERM_RPM - xterm-restore-private-mode
3297 * Probably not worth implementing.
3303 static int screen_XTERM_RRV(term_screen *screen, const term_seq *seq) {
3305 * XTERM_RRV - xterm-reset-resource-value
3307 * Probably not worth implementing.
3313 static int screen_XTERM_RTM(term_screen *screen, const term_seq *seq) {
3315 * XTERM_RTM - xterm-reset-title-mode
3317 * Probably not worth implementing.
3323 static int screen_XTERM_SACL1(term_screen *screen, const term_seq *seq) {
3325 * XTERM_SACL1 - xterm-set-ansi-conformance-level-1
3327 * Probably not worth implementing.
3333 static int screen_XTERM_SACL2(term_screen *screen, const term_seq *seq) {
3335 * XTERM_SACL2 - xterm-set-ansi-conformance-level-2
3337 * Probably not worth implementing.
3343 static int screen_XTERM_SACL3(term_screen *screen, const term_seq *seq) {
3345 * XTERM_SACL3 - xterm-set-ansi-conformance-level-3
3347 * Probably not worth implementing.
3353 static int screen_XTERM_SDCS(term_screen *screen, const term_seq *seq) {
3355 * XTERM_SDCS - xterm-set-default-character-set
3356 * Select the default character set. We treat this the same as UTF-8 as
3357 * this is our default character set. As we always use UTF-8, this
3364 static int screen_XTERM_SGFX(term_screen *screen, const term_seq *seq) {
3366 * XTERM_SGFX - xterm-sixel-graphics
3368 * Probably not worth implementing.
3374 static int screen_XTERM_SPM(term_screen *screen, const term_seq *seq) {
3376 * XTERM_SPM - xterm-set-private-mode
3378 * Probably not worth implementing.
3384 static int screen_XTERM_SRV(term_screen *screen, const term_seq *seq) {
3386 * XTERM_SRV - xterm-set-resource-value
3388 * Probably not worth implementing.
3394 static int screen_XTERM_STM(term_screen *screen, const term_seq *seq) {
3396 * XTERM_STM - xterm-set-title-mode
3398 * Probably not worth implementing.
3404 static int screen_XTERM_SUCS(term_screen *screen, const term_seq *seq) {
3406 * XTERM_SUCS - xterm-select-utf8-character-set
3407 * Select UTF-8 as character set. This is our default on only character
3408 * set. Hence, this is a no-op.
3414 static int screen_XTERM_WM(term_screen *screen, const term_seq *seq) {
3416 * XTERM_WM - xterm-window-management
3418 * Probably not worth implementing.
3426 * The screen_feed_*() handlers take data from the user and feed it into the
3427 * screen. Once the parser has detected a sequence, we parse the command-type
3428 * and forward it to the command-dispatchers.
3431 static int screen_feed_cmd(term_screen *screen, const term_seq *seq) {
3432 switch (seq->command) {
3433 case TERM_CMD_GRAPHIC:
3434 return screen_GRAPHIC(screen, seq);
3436 return screen_BEL(screen, seq);
3438 return screen_BS(screen, seq);
3440 return screen_CBT(screen, seq);
3442 return screen_CHA(screen, seq);
3444 return screen_CHT(screen, seq);
3446 return screen_CNL(screen, seq);
3448 return screen_CPL(screen, seq);
3450 return screen_CR(screen, seq);
3452 return screen_CUB(screen, seq);
3454 return screen_CUD(screen, seq);
3456 return screen_CUF(screen, seq);
3458 return screen_CUP(screen, seq);
3460 return screen_CUU(screen, seq);
3462 return screen_DA1(screen, seq);
3464 return screen_DA2(screen, seq);
3466 return screen_DA3(screen, seq);
3468 return screen_DC1(screen, seq);
3470 return screen_DC3(screen, seq);
3472 return screen_DCH(screen, seq);
3473 case TERM_CMD_DECALN:
3474 return screen_DECALN(screen, seq);
3475 case TERM_CMD_DECANM:
3476 return screen_DECANM(screen, seq);
3477 case TERM_CMD_DECBI:
3478 return screen_DECBI(screen, seq);
3479 case TERM_CMD_DECCARA:
3480 return screen_DECCARA(screen, seq);
3481 case TERM_CMD_DECCRA:
3482 return screen_DECCRA(screen, seq);
3483 case TERM_CMD_DECDC:
3484 return screen_DECDC(screen, seq);
3485 case TERM_CMD_DECDHL_BH:
3486 return screen_DECDHL_BH(screen, seq);
3487 case TERM_CMD_DECDHL_TH:
3488 return screen_DECDHL_TH(screen, seq);
3489 case TERM_CMD_DECDWL:
3490 return screen_DECDWL(screen, seq);
3491 case TERM_CMD_DECEFR:
3492 return screen_DECEFR(screen, seq);
3493 case TERM_CMD_DECELF:
3494 return screen_DECELF(screen, seq);
3495 case TERM_CMD_DECELR:
3496 return screen_DECELR(screen, seq);
3497 case TERM_CMD_DECERA:
3498 return screen_DECERA(screen, seq);
3499 case TERM_CMD_DECFI:
3500 return screen_DECFI(screen, seq);
3501 case TERM_CMD_DECFRA:
3502 return screen_DECFRA(screen, seq);
3503 case TERM_CMD_DECIC:
3504 return screen_DECIC(screen, seq);
3505 case TERM_CMD_DECID:
3506 return screen_DECID(screen, seq);
3507 case TERM_CMD_DECINVM:
3508 return screen_DECINVM(screen, seq);
3509 case TERM_CMD_DECKBD:
3510 return screen_DECKBD(screen, seq);
3511 case TERM_CMD_DECKPAM:
3512 return screen_DECKPAM(screen, seq);
3513 case TERM_CMD_DECKPNM:
3514 return screen_DECKPNM(screen, seq);
3515 case TERM_CMD_DECLFKC:
3516 return screen_DECLFKC(screen, seq);
3517 case TERM_CMD_DECLL:
3518 return screen_DECLL(screen, seq);
3519 case TERM_CMD_DECLTOD:
3520 return screen_DECLTOD(screen, seq);
3521 case TERM_CMD_DECPCTERM:
3522 return screen_DECPCTERM(screen, seq);
3523 case TERM_CMD_DECPKA:
3524 return screen_DECPKA(screen, seq);
3525 case TERM_CMD_DECPKFMR:
3526 return screen_DECPKFMR(screen, seq);
3527 case TERM_CMD_DECRARA:
3528 return screen_DECRARA(screen, seq);
3529 case TERM_CMD_DECRC:
3530 return screen_DECRC(screen, seq);
3531 case TERM_CMD_DECREQTPARM:
3532 return screen_DECREQTPARM(screen, seq);
3533 case TERM_CMD_DECRPKT:
3534 return screen_DECRPKT(screen, seq);
3535 case TERM_CMD_DECRQCRA:
3536 return screen_DECRQCRA(screen, seq);
3537 case TERM_CMD_DECRQDE:
3538 return screen_DECRQDE(screen, seq);
3539 case TERM_CMD_DECRQKT:
3540 return screen_DECRQKT(screen, seq);
3541 case TERM_CMD_DECRQLP:
3542 return screen_DECRQLP(screen, seq);
3543 case TERM_CMD_DECRQM_ANSI:
3544 return screen_DECRQM_ANSI(screen, seq);
3545 case TERM_CMD_DECRQM_DEC:
3546 return screen_DECRQM_DEC(screen, seq);
3547 case TERM_CMD_DECRQPKFM:
3548 return screen_DECRQPKFM(screen, seq);
3549 case TERM_CMD_DECRQPSR:
3550 return screen_DECRQPSR(screen, seq);
3551 case TERM_CMD_DECRQTSR:
3552 return screen_DECRQTSR(screen, seq);
3553 case TERM_CMD_DECRQUPSS:
3554 return screen_DECRQUPSS(screen, seq);
3555 case TERM_CMD_DECSACE:
3556 return screen_DECSACE(screen, seq);
3557 case TERM_CMD_DECSASD:
3558 return screen_DECSASD(screen, seq);
3559 case TERM_CMD_DECSC:
3560 return screen_DECSC(screen, seq);
3561 case TERM_CMD_DECSCA:
3562 return screen_DECSCA(screen, seq);
3563 case TERM_CMD_DECSCL:
3564 return screen_DECSCL(screen, seq);
3565 case TERM_CMD_DECSCP:
3566 return screen_DECSCP(screen, seq);
3567 case TERM_CMD_DECSCPP:
3568 return screen_DECSCPP(screen, seq);
3569 case TERM_CMD_DECSCS:
3570 return screen_DECSCS(screen, seq);
3571 case TERM_CMD_DECSCUSR:
3572 return screen_DECSCUSR(screen, seq);
3573 case TERM_CMD_DECSDDT:
3574 return screen_DECSDDT(screen, seq);
3575 case TERM_CMD_DECSDPT:
3576 return screen_DECSDPT(screen, seq);
3577 case TERM_CMD_DECSED:
3578 return screen_DECSED(screen, seq);
3579 case TERM_CMD_DECSEL:
3580 return screen_DECSEL(screen, seq);
3581 case TERM_CMD_DECSERA:
3582 return screen_DECSERA(screen, seq);
3583 case TERM_CMD_DECSFC:
3584 return screen_DECSFC(screen, seq);
3585 case TERM_CMD_DECSKCV:
3586 return screen_DECSKCV(screen, seq);
3587 case TERM_CMD_DECSLCK:
3588 return screen_DECSLCK(screen, seq);
3589 case TERM_CMD_DECSLE:
3590 return screen_DECSLE(screen, seq);
3591 case TERM_CMD_DECSLPP:
3592 return screen_DECSLPP(screen, seq);
3593 case TERM_CMD_DECSLRM_OR_SC:
3594 return screen_DECSLRM_OR_SC(screen, seq);
3595 case TERM_CMD_DECSMBV:
3596 return screen_DECSMBV(screen, seq);
3597 case TERM_CMD_DECSMKR:
3598 return screen_DECSMKR(screen, seq);
3599 case TERM_CMD_DECSNLS:
3600 return screen_DECSNLS(screen, seq);
3601 case TERM_CMD_DECSPP:
3602 return screen_DECSPP(screen, seq);
3603 case TERM_CMD_DECSPPCS:
3604 return screen_DECSPPCS(screen, seq);
3605 case TERM_CMD_DECSPRTT:
3606 return screen_DECSPRTT(screen, seq);
3607 case TERM_CMD_DECSR:
3608 return screen_DECSR(screen, seq);
3609 case TERM_CMD_DECSRFR:
3610 return screen_DECSRFR(screen, seq);
3611 case TERM_CMD_DECSSCLS:
3612 return screen_DECSSCLS(screen, seq);
3613 case TERM_CMD_DECSSDT:
3614 return screen_DECSSDT(screen, seq);
3615 case TERM_CMD_DECSSL:
3616 return screen_DECSSL(screen, seq);
3617 case TERM_CMD_DECST8C:
3618 return screen_DECST8C(screen, seq);
3619 case TERM_CMD_DECSTBM:
3620 return screen_DECSTBM(screen, seq);
3621 case TERM_CMD_DECSTR:
3622 return screen_DECSTR(screen, seq);
3623 case TERM_CMD_DECSTRL:
3624 return screen_DECSTRL(screen, seq);
3625 case TERM_CMD_DECSWBV:
3626 return screen_DECSWBV(screen, seq);
3627 case TERM_CMD_DECSWL:
3628 return screen_DECSWL(screen, seq);
3629 case TERM_CMD_DECTID:
3630 return screen_DECTID(screen, seq);
3631 case TERM_CMD_DECTME:
3632 return screen_DECTME(screen, seq);
3633 case TERM_CMD_DECTST:
3634 return screen_DECTST(screen, seq);
3636 return screen_DL(screen, seq);
3637 case TERM_CMD_DSR_ANSI:
3638 return screen_DSR_ANSI(screen, seq);
3639 case TERM_CMD_DSR_DEC:
3640 return screen_DSR_DEC(screen, seq);
3642 return screen_ECH(screen, seq);
3644 return screen_ED(screen, seq);
3646 return screen_EL(screen, seq);
3648 return screen_ENQ(screen, seq);
3650 return screen_EPA(screen, seq);
3652 return screen_FF(screen, seq);
3654 return screen_HPA(screen, seq);
3656 return screen_HPR(screen, seq);
3658 return screen_HT(screen, seq);
3660 return screen_HTS(screen, seq);
3662 return screen_HVP(screen, seq);
3664 return screen_ICH(screen, seq);
3666 return screen_IL(screen, seq);
3668 return screen_IND(screen, seq);
3670 return screen_LF(screen, seq);
3672 return screen_LS1R(screen, seq);
3674 return screen_LS2(screen, seq);
3676 return screen_LS2R(screen, seq);
3678 return screen_LS3(screen, seq);
3680 return screen_LS3R(screen, seq);
3681 case TERM_CMD_MC_ANSI:
3682 return screen_MC_ANSI(screen, seq);
3683 case TERM_CMD_MC_DEC:
3684 return screen_MC_DEC(screen, seq);
3686 return screen_NEL(screen, seq);
3688 return screen_NP(screen, seq);
3690 return screen_NULL(screen, seq);
3692 return screen_PP(screen, seq);
3694 return screen_PPA(screen, seq);
3696 return screen_PPB(screen, seq);
3698 return screen_PPR(screen, seq);
3700 return screen_RC(screen, seq);
3702 return screen_REP(screen, seq);
3704 return screen_RI(screen, seq);
3706 return screen_RIS(screen, seq);
3707 case TERM_CMD_RM_ANSI:
3708 return screen_RM_ANSI(screen, seq);
3709 case TERM_CMD_RM_DEC:
3710 return screen_RM_DEC(screen, seq);
3711 case TERM_CMD_S7C1T:
3712 return screen_S7C1T(screen, seq);
3713 case TERM_CMD_S8C1T:
3714 return screen_S8C1T(screen, seq);
3716 return screen_SCS(screen, seq);
3718 return screen_SD(screen, seq);
3720 return screen_SGR(screen, seq);
3722 return screen_SI(screen, seq);
3723 case TERM_CMD_SM_ANSI:
3724 return screen_SM_ANSI(screen, seq);
3725 case TERM_CMD_SM_DEC:
3726 return screen_SM_DEC(screen, seq);
3728 return screen_SO(screen, seq);
3730 return screen_SPA(screen, seq);
3732 return screen_SS2(screen, seq);
3734 return screen_SS3(screen, seq);
3736 return screen_ST(screen, seq);
3738 return screen_SU(screen, seq);
3740 return screen_SUB(screen, seq);
3742 return screen_TBC(screen, seq);
3744 return screen_VPA(screen, seq);
3746 return screen_VPR(screen, seq);
3748 return screen_VT(screen, seq);
3749 case TERM_CMD_XTERM_CLLHP:
3750 return screen_XTERM_CLLHP(screen, seq);
3751 case TERM_CMD_XTERM_IHMT:
3752 return screen_XTERM_IHMT(screen, seq);
3753 case TERM_CMD_XTERM_MLHP:
3754 return screen_XTERM_MLHP(screen, seq);
3755 case TERM_CMD_XTERM_MUHP:
3756 return screen_XTERM_MUHP(screen, seq);
3757 case TERM_CMD_XTERM_RPM:
3758 return screen_XTERM_RPM(screen, seq);
3759 case TERM_CMD_XTERM_RRV:
3760 return screen_XTERM_RRV(screen, seq);
3761 case TERM_CMD_XTERM_RTM:
3762 return screen_XTERM_RTM(screen, seq);
3763 case TERM_CMD_XTERM_SACL1:
3764 return screen_XTERM_SACL1(screen, seq);
3765 case TERM_CMD_XTERM_SACL2:
3766 return screen_XTERM_SACL2(screen, seq);
3767 case TERM_CMD_XTERM_SACL3:
3768 return screen_XTERM_SACL3(screen, seq);
3769 case TERM_CMD_XTERM_SDCS:
3770 return screen_XTERM_SDCS(screen, seq);
3771 case TERM_CMD_XTERM_SGFX:
3772 return screen_XTERM_SGFX(screen, seq);
3773 case TERM_CMD_XTERM_SPM:
3774 return screen_XTERM_SPM(screen, seq);
3775 case TERM_CMD_XTERM_SRV:
3776 return screen_XTERM_SRV(screen, seq);
3777 case TERM_CMD_XTERM_STM:
3778 return screen_XTERM_STM(screen, seq);
3779 case TERM_CMD_XTERM_SUCS:
3780 return screen_XTERM_SUCS(screen, seq);
3781 case TERM_CMD_XTERM_WM:
3782 return screen_XTERM_WM(screen, seq);
3788 unsigned int term_screen_get_width(term_screen *screen) {
3789 assert_return(screen, -EINVAL);
3791 return screen->page->width;
3794 unsigned int term_screen_get_height(term_screen *screen) {
3795 assert_return(screen, -EINVAL);
3797 return screen->page->height;
3800 uint64_t term_screen_get_age(term_screen *screen) {
3801 assert_return(screen, 0);
3806 int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size) {
3808 size_t i, j, ucs4_len;
3809 const term_seq *seq;
3812 assert_return(screen, -EINVAL);
3816 /* Feed bytes into utf8 decoder and handle parsed ucs4 chars. We always
3817 * treat data as UTF-8, but the parser makes sure to fall back to raw
3818 * 8bit mode if the stream is not valid UTF-8. This should be more than
3819 * enough to support old 7bit/8bit modes. */
3820 for (i = 0; i < size; ++i) {
3821 ucs4_len = term_utf8_decode(&screen->utf8, &ucs4_str, in[i]);
3822 for (j = 0; j < ucs4_len; ++j) {
3823 r = term_parser_feed(screen->parser, &seq, ucs4_str[j]);
3826 } else if (r != TERM_SEQ_NONE) {
3827 r = screen_feed_cmd(screen, seq);
3837 static char *screen_map_key(term_screen *screen,
3839 const uint32_t *keysyms,
3842 const uint32_t *ucs4,
3843 unsigned int mods) {
3844 char ch, ch2, ch_mods;
3848 /* TODO: All these key-mappings need to be verified. Public information
3849 * on those mappings is pretty scarce and every emulator seems to do it
3850 * slightly differently.
3851 * A lot of mappings are also missing. */
3859 v = XKB_KEY_NoSymbol;
3861 /* In some mappings, the modifiers are encoded as CSI parameters. The
3862 * encoding is rather arbitrary, but seems to work. */
3864 switch (mods & (TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT | TERM_KBDMOD_CTRL)) {
3865 case TERM_KBDMOD_SHIFT:
3868 case TERM_KBDMOD_ALT:
3871 case TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT:
3874 case TERM_KBDMOD_CTRL:
3877 case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT:
3880 case TERM_KBDMOD_CTRL | TERM_KBDMOD_ALT:
3883 case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT:
3888 /* A user might actually use multiple layouts for keyboard
3889 * input. @keysyms[0] contains the actual keysym that the user
3890 * used. But if this keysym is not in the ascii range, the
3891 * input handler does check all other layouts that the user
3892 * specified whether one of them maps the key to some ASCII
3893 * keysym and provides this via @ascii. We always use the real
3894 * keysym except when handling CTRL+<XY> shortcuts we use the
3895 * ascii keysym. This is for compatibility to xterm et. al. so
3896 * ctrl+c always works regardless of the currently active
3897 * keyboard layout. But if no ascii-sym is found, we still use
3898 * the real keysym. */
3899 if (ascii == XKB_KEY_NoSymbol)
3902 /* map CTRL+<ascii> */
3903 if (mods & TERM_KBDMOD_CTRL) {
3906 /* Right hand side is mapped to the left and then
3907 * treated equally. Fall through to left-hand side.. */
3910 /* Printable ASCII is mapped 1-1 in XKB and in
3911 * combination with CTRL bit 7 is flipped. This
3912 * is equivalent to the caret-notation. */
3913 *p++ = ascii ^ 0x40;
3918 /* map cursor keys */
3942 if (screen->flags & TERM_FLAG_CURSOR_KEYS)
3955 /* map action keys */
3961 case XKB_KEY_Insert:
3964 case XKB_KEY_Delete:
3967 case XKB_KEY_Select:
3970 case XKB_KEY_Page_Up:
3973 case XKB_KEY_Page_Down:
3989 /* map lower function keys */
4022 /* map upper function keys */
4073 /* map special keys */
4075 case 0xff08: /* XKB_KEY_BackSpace */
4076 case 0xff09: /* XKB_KEY_Tab */
4077 case 0xff0a: /* XKB_KEY_Linefeed */
4078 case 0xff0b: /* XKB_KEY_Clear */
4079 case 0xff15: /* XKB_KEY_Sys_Req */
4080 case 0xff1b: /* XKB_KEY_Escape */
4081 case 0xffff: /* XKB_KEY_Delete */
4084 case 0xff13: /* XKB_KEY_Pause */
4085 /* TODO: What should we do with this key?
4086 * Sending XOFF is awful as there is no simple
4087 * way on modern keyboards to send XON again.
4088 * If someone wants this, we can re-eanble
4091 case 0xff14: /* XKB_KEY_Scroll_Lock */
4092 /* TODO: What should we do on scroll-lock?
4093 * Sending 0x14 is what the specs say but it is
4094 * not used today the way most users would
4095 * expect so we disable it. If someone wants
4096 * this, we can re-enable it (optionally). */
4098 case XKB_KEY_Return:
4100 if (screen->flags & TERM_FLAG_NEWLINE_MODE)
4103 case XKB_KEY_ISO_Left_Tab:
4108 /* map unicode keys */
4109 for (i = 0; i < n_syms; ++i)
4110 p += term_utf8_encode(p, ucs4[i]);
4115 int term_screen_feed_keyboard(term_screen *screen,
4116 const uint32_t *keysyms,
4119 const uint32_t *ucs4,
4120 unsigned int mods) {
4121 _cleanup_free_ char *dyn = NULL;
4122 static const size_t padding = 1;
4123 char buf[128], *start, *p;
4125 assert_return(screen, -EINVAL);
4127 /* allocate buffer if too small */
4129 if (4 * n_syms + padding > sizeof(buf)) {
4130 dyn = malloc(4 * n_syms + padding);
4137 /* reserve prefix space */
4141 p = screen_map_key(screen, p, keysyms, n_syms, ascii, ucs4, mods);
4142 if (!p || p - start < 1)
4145 /* The ALT modifier causes ESC to be prepended to any key-stroke. We
4146 * already accounted for that buffer space above, so simply prepend it
4148 * TODO: is altSendsEscape a suitable default? What are the semantics
4149 * exactly? Is it used in C0/C1 conversion? Is it prepended if there
4150 * already is an escape character? */
4151 if (mods & TERM_KBDMOD_ALT && *start != 0x1b)
4154 /* turn C0 into C1 */
4155 if (!(screen->flags & TERM_FLAG_7BIT_MODE) && p - start >= 2)
4156 if (start[0] == 0x1b && start[1] >= 0x40 && start[1] <= 0x5f)
4159 return screen_write(screen, start, p - start);
4162 int term_screen_resize(term_screen *screen, unsigned int x, unsigned int y) {
4167 assert_return(screen, -EINVAL);
4169 r = term_page_reserve(screen->page_main, x, y, &screen->state.attr, screen->age);
4173 r = term_page_reserve(screen->page_alt, x, y, &screen->state.attr, screen->age);
4177 if (x > screen->n_tabs) {
4178 t = realloc(screen->tabs, (x + 7) / 8);
4186 for (i = (screen->page->width + 7) / 8 * 8; i < x; i += 8)
4187 screen->tabs[i / 8] = 0x1;
4189 term_page_resize(screen->page_main, x, y, &screen->state.attr, screen->age, screen->history);
4190 term_page_resize(screen->page_alt, x, y, &screen->state.attr, screen->age, NULL);
4192 screen->state.cursor_x = screen_clamp_x(screen, screen->state.cursor_x);
4193 screen->state.cursor_y = screen_clamp_x(screen, screen->state.cursor_y);
4194 screen_cursor_clear_wrap(screen);
4199 void term_screen_soft_reset(term_screen *screen) {
4204 screen->g0 = &term_unicode_lower;
4205 screen->g1 = &term_unicode_upper;
4206 screen->g2 = &term_unicode_lower;
4207 screen->g3 = &term_unicode_upper;
4208 screen->state.attr = screen->default_attr;
4209 screen->state.gl = &screen->g0;
4210 screen->state.gr = &screen->g1;
4211 screen->state.glt = NULL;
4212 screen->state.grt = NULL;
4213 screen->state.auto_wrap = 0;
4214 screen->state.origin_mode = 0;
4216 screen->saved = screen->state;
4217 screen->saved.cursor_x = 0;
4218 screen->saved.cursor_y = 0;
4219 screen->saved_alt = screen->saved;
4221 screen->page = screen->page_main;
4222 screen->history = screen->history_main;
4223 screen->flags = TERM_FLAG_7BIT_MODE;
4224 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
4226 for (i = 0; i < screen->page->width; i += 8)
4227 screen->tabs[i / 8] = 0x1;
4229 term_page_set_scroll_region(screen->page_main, 0, screen->page->height);
4230 term_page_set_scroll_region(screen->page_alt, 0, screen->page->height);
4233 void term_screen_hard_reset(term_screen *screen) {
4236 term_screen_soft_reset(screen);
4238 screen->state.cursor_x = 0;
4239 screen->state.cursor_y = 0;
4240 term_page_erase(screen->page_main, 0, 0, screen->page->width, screen->page->height, &screen->state.attr, screen->age, false);
4241 term_page_erase(screen->page_alt, 0, 0, screen->page->width, screen->page->height, &screen->state.attr, screen->age, false);
4244 int term_screen_set_answerback(term_screen *screen, const char *answerback) {
4247 assert_return(screen, -EINVAL);
4250 t = strdup(answerback);
4255 free(screen->answerback);
4256 screen->answerback = t;
4261 int term_screen_draw(term_screen *screen,
4262 int (*draw_fn) (term_screen *screen,
4266 const term_attr *attr,
4269 unsigned int ch_width),
4272 uint64_t cell_age, line_age, age = 0;
4273 term_charbuf_t ch_buf;
4274 const uint32_t *ch_str;
4275 unsigned int i, j, cw;
4288 page = screen->page;
4290 for (j = 0; j < page->height; ++j) {
4291 line = page->lines[j];
4292 line_age = MAX(line->age, page->age);
4294 for (i = 0; i < page->width; ++i) {
4297 cell = &line->cells[i];
4298 cell_age = MAX(cell->age, line_age);
4300 if (age != 0 && cell_age <= age)
4303 ch_str = term_char_resolve(cell->ch, &ch_n, &ch_buf);
4305 /* Character-width of 0 is used for cleared cells.
4306 * Always treat this as single-cell character, so
4307 * renderers can assume ch_width is set properpy. */
4308 cw = MAX(cell->cwidth, 1U);
4311 if (i == screen->state.cursor_x && j == screen->state.cursor_y &&
4312 !(screen->flags & TERM_FLAG_HIDE_CURSOR))
4329 *fb_age = screen->age;