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(term_screen *screen, unsigned int mode, bool dec, bool set) {
400 * DECCKM: cursor-keys
403 set_reset(screen, TERM_FLAG_CURSOR_KEYS, set);
413 screen->state.origin_mode = set;
420 * DECAWN: auto-wrap mode
423 screen->state.auto_wrap = set;
430 * LNM: line-feed/new-line mode
433 set_reset(screen, TERM_FLAG_NEWLINE_MODE, set);
440 * DECTCEM: text-cursor-enable
443 set_reset(screen, TERM_FLAG_HIDE_CURSOR, !set);
444 screen_age_cursor(screen);
451 * XTERM-ASB: alternate-screen-buffer
452 * This enables/disables the alternate screen-buffer.
453 * It effectively saves the current page content and
454 * allows you to restore it when changing to the
455 * original screen-buffer again.
457 screen_change_alt(screen, set);
464 * XTERM-ASBPE: alternate-screen-buffer-post-erase
465 * This is the same as XTERM-ASB but erases the
466 * alternate screen-buffer before switching back to the
467 * original buffer. Use it to discard any data on the
468 * alternate screen buffer when done.
471 screen_reset_page(screen, screen->page_alt);
473 screen_change_alt(screen, set);
480 * XTERM-ASBCS: alternate-screen-buffer-cursor-state
481 * This has the same effect as DECSC/DECRC, but uses a
482 * separate state buffer. It is usually used in
483 * combination with alternate screen buffers to provide
484 * stacked state storage.
487 screen_save_state(screen, &screen->saved_alt);
489 screen_restore_state(screen, &screen->saved_alt);
496 * XTERM-ASBX: alternate-screen-buffer-extended
497 * This combines XTERM-ASBPE and XTERM-ASBCS somewhat.
498 * When enabling, state is saved, alternate screen
499 * buffer is activated and cleared.
500 * When disabled, alternate screen buffer is cleared,
501 * then normal screen buffer is enabled and state is
505 screen_save_state(screen, &screen->saved_alt);
507 screen_reset_page(screen, screen->page_alt);
508 screen_change_alt(screen, set);
511 screen_restore_state(screen, &screen->saved_alt);
518 /* map a character according to current GL and GR maps */
519 static uint32_t screen_map(term_screen *screen, uint32_t val) {
522 /* 32 and 127 always map to identity. 160 and 255 map to identity iff a
523 * 96 character set is loaded into GR. Values above 255 always map to
527 if (screen->state.glt) {
528 nval = (**screen->state.glt)[val - 32];
529 screen->state.glt = NULL;
531 nval = (**screen->state.gl)[val - 32];
535 if (screen->state.grt) {
536 nval = (**screen->state.grt)[val - 160];
537 screen->state.grt = NULL;
539 nval = (**screen->state.gr)[val - 160];
544 return (nval == -1U) ? val : nval;
549 * This is the unofficial documentation of all the TERM_CMD_* definitions. Each
550 * handled command has a separate function with an extensive comment on the
551 * semantics of the command.
552 * Note that many semantics are unknown and need to be verified. This is mostly
553 * about error-handling, though. Applications rarely rely on those features.
556 static int screen_DA1(term_screen *screen, const term_seq *seq);
557 static int screen_LF(term_screen *screen, const term_seq *seq);
559 static int screen_GRAPHIC(term_screen *screen, const term_seq *seq) {
560 term_char_t ch = TERM_CHAR_NULL;
563 if (screen->state.cursor_x + 1 == screen->page->width
564 && screen->flags & TERM_FLAG_PENDING_WRAP
565 && screen->state.auto_wrap) {
566 screen_cursor_down(screen, 1, true);
567 screen_cursor_set(screen, 0, screen->state.cursor_y);
570 screen_cursor_clear_wrap(screen);
572 c = screen_map(screen, seq->terminator);
573 ch = term_char_merge(ch, screen_map(screen, c));
574 term_page_write(screen->page, screen->state.cursor_x, screen->state.cursor_y, ch, 1, &screen->state.attr, screen->age, false);
576 if (screen->state.cursor_x + 1 == screen->page->width)
577 screen->flags |= TERM_FLAG_PENDING_WRAP;
579 screen_cursor_right(screen, 1);
584 static int screen_BEL(term_screen *screen, const term_seq *seq) {
586 * BEL - sound bell tone
587 * This command should trigger an acoustic bell. Usually, this is
588 * forwarded directly to the pcspkr. However, bells have become quite
589 * uncommon and annoying, so we're not implementing them here. Instead,
590 * it's one of the commands we forward to the caller.
593 return screen_forward(screen, TERM_CMD_BEL, seq);
596 static int screen_BS(term_screen *screen, const term_seq *seq) {
599 * Move cursor one cell to the left. If already at the left margin,
603 screen_cursor_clear_wrap(screen);
604 screen_cursor_left(screen, 1);
608 static int screen_CBT(term_screen *screen, const term_seq *seq) {
610 * CBT - cursor-backward-tabulation
611 * Move the cursor @args[0] tabs backwards (to the left). The
612 * current cursor cell, in case it's a tab, is not counted.
613 * Furthermore, the cursor cannot be moved beyond position 0 and
614 * it will stop there.
620 unsigned int num = 1;
622 if (seq->args[0] > 0)
625 screen_cursor_clear_wrap(screen);
626 screen_cursor_left_tab(screen, num);
631 static int screen_CHA(term_screen *screen, const term_seq *seq) {
633 * CHA - cursor-horizontal-absolute
634 * Move the cursor to position @args[0] in the current line. The
635 * cursor cannot be moved beyond the rightmost cell and will stop
642 unsigned int pos = 1;
644 if (seq->args[0] > 0)
647 screen_cursor_clear_wrap(screen);
648 screen_cursor_set(screen, pos - 1, screen->state.cursor_y);
653 static int screen_CHT(term_screen *screen, const term_seq *seq) {
655 * CHT - cursor-horizontal-forward-tabulation
656 * Move the cursor @args[0] tabs forward (to the right). The
657 * current cursor cell, in case it's a tab, is not counted.
658 * Furthermore, the cursor cannot be moved beyond the rightmost cell
659 * and will stop there.
665 unsigned int num = 1;
667 if (seq->args[0] > 0)
670 screen_cursor_clear_wrap(screen);
671 screen_cursor_right_tab(screen, num);
676 static int screen_CNL(term_screen *screen, const term_seq *seq) {
678 * CNL - cursor-next-line
679 * Move the cursor @args[0] lines down.
681 * TODO: Does this stop at the bottom or cause a scroll-up?
687 unsigned int num = 1;
689 if (seq->args[0] > 0)
692 screen_cursor_clear_wrap(screen);
693 screen_cursor_down(screen, num, false);
698 static int screen_CPL(term_screen *screen, const term_seq *seq) {
700 * CPL - cursor-preceding-line
701 * Move the cursor @args[0] lines up.
703 * TODO: Does this stop at the top or cause a scroll-up?
709 unsigned int num = 1;
711 if (seq->args[0] > 0)
714 screen_cursor_clear_wrap(screen);
715 screen_cursor_up(screen, num, false);
720 static int screen_CR(term_screen *screen, const term_seq *seq) {
722 * CR - carriage-return
723 * Move the cursor to the left margin on the current line.
726 screen_cursor_clear_wrap(screen);
727 screen_cursor_set(screen, 0, screen->state.cursor_y);
732 static int screen_CUB(term_screen *screen, const term_seq *seq) {
734 * CUB - cursor-backward
735 * Move the cursor @args[0] positions to the left. The cursor stops
736 * at the left-most position.
742 unsigned int num = 1;
744 if (seq->args[0] > 0)
747 screen_cursor_clear_wrap(screen);
748 screen_cursor_left(screen, num);
753 static int screen_CUD(term_screen *screen, const term_seq *seq) {
756 * Move the cursor @args[0] positions down. The cursor stops at the
757 * bottom margin. If it was already moved further, it stops at the
764 unsigned int num = 1;
766 if (seq->args[0] > 0)
769 screen_cursor_clear_wrap(screen);
770 screen_cursor_down(screen, num, false);
775 static int screen_CUF(term_screen *screen, const term_seq *seq) {
777 * CUF -cursor-forward
778 * Move the cursor @args[0] positions to the right. The cursor stops
779 * at the right-most position.
785 unsigned int num = 1;
787 if (seq->args[0] > 0)
790 screen_cursor_clear_wrap(screen);
791 screen_cursor_right(screen, num);
796 static int screen_CUP(term_screen *screen, const term_seq *seq) {
798 * CUP - cursor-position
799 * Moves the cursor to position @args[1] x @args[0]. If either is 0, it
800 * is treated as 1. The positions are subject to the origin-mode and
801 * clamped to the addressable with/height.
808 unsigned int x = 1, y = 1;
810 if (seq->args[0] > 0)
812 if (seq->args[1] > 0)
815 screen_cursor_clear_wrap(screen);
816 screen_cursor_set_rel(screen, x - 1, y - 1);
821 static int screen_CUU(term_screen *screen, const term_seq *seq) {
824 * Move the cursor @args[0] positions up. The cursor stops at the
825 * top margin. If it was already moved further, it stops at the
833 unsigned int num = 1;
835 if (seq->args[0] > 0)
838 screen_cursor_clear_wrap(screen);
839 screen_cursor_up(screen, num, false);
844 static int screen_DA1(term_screen *screen, const term_seq *seq) {
846 * DA1 - primary-device-attributes
847 * The primary DA asks for basic terminal features. We simply return
848 * a hard-coded list of features we implement.
849 * Note that the primary DA asks for supported features, not currently
852 * The terminal's answer is:
854 * The first argument, 64, is fixed and denotes a VT420, the last
855 * DEC-term that extended this number.
856 * All following arguments denote supported features. Note
857 * that at most 15 features can be sent (max CSI args). It is safe to
858 * send more, but clients might not be able to parse them. This is a
859 * client's problem and we shouldn't care. There is no other way to
860 * send those feature lists, so we have to extend them beyond 15 in
865 * The 132 column mode is supported by the terminal.
867 * A priner-port is supported and can be addressed via
870 * Support for ReGIS graphics is available. The ReGIS routines
871 * provide the "remote graphics instruction set" and allow basic
874 * Support of Sixel graphics is available. This provides access
875 * to the sixel bitmap routines.
877 * The terminal supports DECSCA and related selective-erase
878 * functions. This allows to protect specific cells from being
879 * erased, if specified.
880 * 7: soft character set (DRCS)
882 * 8: user-defined keys (UDKs)
884 * 9: national-replacement character sets (NRCS)
885 * National-replacement character-sets are available.
886 * 12: Yugoslavian (SCS)
888 * 15: technical character set
889 * The DEC technical-character-set is available.
890 * 18: windowing capability
892 * 21: horizontal scrolling
900 * 29: ANSI text locator
902 * 42: ISO Latin-2 character set
908 * 46: ASCII emulation
912 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "?64;1;6;9;15c");
915 static int screen_DA2(term_screen *screen, const term_seq *seq) {
917 * DA2 - secondary-device-attributes
918 * The secondary DA asks for the terminal-ID, firmware versions and
919 * other non-primary attributes. All these values are
920 * informational-only and should not be used by the host to detect
923 * The terminal's response is:
924 * ^[ > 61 ; FIRMWARE ; KEYBOARD c
925 * whereas 65 is fixed for VT525 terminals, the last terminal-line that
926 * increased this number. FIRMWARE is the firmware
927 * version encoded as major/minor (20 == 2.0) and KEYBOARD is 0 for STD
928 * keyboard and 1 for PC keyboards.
930 * We replace the firmware-version with the systemd-version so clients
931 * can decode it again.
934 return SEQ_WRITE(screen, C0_CSI, C1_CSI, ">65;" PACKAGE_VERSION ";1c");
937 static int screen_DA3(term_screen *screen, const term_seq *seq) {
939 * DA3 - tertiary-device-attributes
940 * The tertiary DA is used to query the terminal-ID.
942 * The terminal's response is:
943 * ^P ! | XX AA BB CC ^\
944 * whereas all four parameters are hexadecimal-encoded pairs. XX
945 * denotes the manufacturing site, AA BB CC is the terminal's ID.
948 /* we do not support tertiary DAs */
952 static int screen_DC1(term_screen *screen, const term_seq *seq) {
954 * DC1 - device-control-1 or XON
955 * This clears any previous XOFF and resumes terminal-transmission.
958 /* we do not support XON */
962 static int screen_DC3(term_screen *screen, const term_seq *seq) {
964 * DC3 - device-control-3 or XOFF
965 * Stops terminal transmission. No further characters are sent until
966 * an XON is received.
969 /* we do not support XOFF */
973 static int screen_DCH(term_screen *screen, const term_seq *seq) {
975 * DCH - delete-character
976 * This deletes @argv[0] characters at the current cursor position. As
977 * characters are deleted, the remaining characters between the cursor
978 * and right margin move to the left. Character attributes move with the
979 * characters. The terminal adds blank spaces with no visual character
980 * attributes at the right margin. DCH has no effect outside the
987 unsigned int num = 1;
989 if (seq->args[0] > 0)
992 screen_cursor_clear_wrap(screen);
993 term_page_delete_cells(screen->page, screen->state.cursor_x, screen->state.cursor_y, num, &screen->state.attr, screen->age);
998 static int screen_DECALN(term_screen *screen, const term_seq *seq) {
1000 * DECALN - screen-alignment-pattern
1002 * Probably not worth implementing.
1008 static int screen_DECANM(term_screen *screen, const term_seq *seq) {
1010 * DECANM - ansi-mode
1011 * Set the terminal into VT52 compatibility mode. Control sequences
1012 * overlap with regular sequences so we have to detect them early before
1015 * Probably not worth implementing.
1021 static int screen_DECBI(term_screen *screen, const term_seq *seq) {
1023 * DECBI - back-index
1024 * This control function moves the cursor backward one column. If the
1025 * cursor is at the left margin, then all screen data within the margin
1026 * moves one column to the right. The column that shifted past the right
1028 * DECBI adds a new column at the left margin with no visual attributes.
1029 * DECBI does not affect the margins. If the cursor is beyond the
1030 * left-margin at the left border, then the terminal ignores DECBI.
1032 * Probably not worth implementing.
1038 static int screen_DECCARA(term_screen *screen, const term_seq *seq) {
1040 * DECCARA - change-attributes-in-rectangular-area
1042 * Probably not worth implementing.
1048 static int screen_DECCRA(term_screen *screen, const term_seq *seq) {
1050 * DECCRA - copy-rectangular-area
1052 * Probably not worth implementing.
1058 static int screen_DECDC(term_screen *screen, const term_seq *seq) {
1060 * DECDC - delete-column
1062 * Probably not worth implementing.
1068 static int screen_DECDHL_BH(term_screen *screen, const term_seq *seq) {
1070 * DECDHL_BH - double-width-double-height-line: bottom half
1072 * Probably not worth implementing.
1078 static int screen_DECDHL_TH(term_screen *screen, const term_seq *seq) {
1080 * DECDHL_TH - double-width-double-height-line: top half
1082 * Probably not worth implementing.
1088 static int screen_DECDWL(term_screen *screen, const term_seq *seq) {
1090 * DECDWL - double-width-single-height-line
1092 * Probably not worth implementing.
1098 static int screen_DECEFR(term_screen *screen, const term_seq *seq) {
1100 * DECEFR - enable-filter-rectangle
1101 * Defines the coordinates of a filter rectangle (top, left, bottom,
1102 * right as @args[0] to @args[3]) and activates it.
1103 * Anytime the locator is detected outside of the filter rectangle, an
1104 * outside rectangle event is generated and the rectangle is disabled.
1105 * Filter rectangles are always treated as "one-shot" events. Any
1106 * parameters that are omitted default to the current locator position.
1107 * If all parameters are omitted, any locator motion will be reported.
1108 * DECELR always cancels any prevous rectangle definition.
1110 * The locator is usually associated with the mouse-cursor, but based
1111 * on cells instead of pixels. See DECELR how to initialize and enable
1112 * it. DECELR can also enable pixel-mode instead of cell-mode.
1120 static int screen_DECELF(term_screen *screen, const term_seq *seq) {
1122 * DECELF - enable-local-functions
1124 * Probably not worth implementing.
1130 static int screen_DECELR(term_screen *screen, const term_seq *seq) {
1132 * DECELR - enable-locator-reporting
1133 * This changes the locator-reporting mode. @args[0] specifies the mode
1134 * to set, 0 disables locator-reporting, 1 enables it continuously, 2
1135 * enables it for a single report. @args[1] specifies the
1136 * precision-mode. 0 and 2 set the reporting to cell-precision, 1 sets
1149 static int screen_DECERA(term_screen *screen, const term_seq *seq) {
1151 * DECERA - erase-rectangular-area
1153 * Probably not worth implementing.
1159 static int screen_DECFI(term_screen *screen, const term_seq *seq) {
1161 * DECFI - forward-index
1162 * This control function moves the cursor forward one column. If the
1163 * cursor is at the right margin, then all screen data within the
1164 * margins moves one column to the left. The column shifted past the
1165 * left margin is lost.
1166 * DECFI adds a new column at the right margin, with no visual
1167 * attributes. DECFI does not affect margins. If the cursor is beyond
1168 * the right margin at the border of the page when the terminal
1169 * receives DECFI, then the terminal ignores DECFI.
1171 * Probably not worth implementing.
1177 static int screen_DECFRA(term_screen *screen, const term_seq *seq) {
1179 * DECFRA - fill-rectangular-area
1181 * Probably not worth implementing.
1187 static int screen_DECIC(term_screen *screen, const term_seq *seq) {
1189 * DECIC - insert-column
1191 * Probably not worth implementing.
1197 static int screen_DECID(term_screen *screen, const term_seq *seq) {
1199 * DECID - return-terminal-id
1200 * This is an obsolete form of TERM_CMD_DA1.
1203 return screen_DA1(screen, seq);
1206 static int screen_DECINVM(term_screen *screen, const term_seq *seq) {
1208 * DECINVM - invoke-macro
1210 * Probably not worth implementing.
1216 static int screen_DECKBD(term_screen *screen, const term_seq *seq) {
1218 * DECKBD - keyboard-language-selection
1220 * Probably not worth implementing.
1226 static int screen_DECKPAM(term_screen *screen, const term_seq *seq) {
1228 * DECKPAM - keypad-application-mode
1229 * Enables the keypad-application mode. If enabled, the keypad sends
1230 * special characters instead of the printed characters. This way,
1231 * applications can detect whether a numeric key was pressed on the
1232 * top-row or on the keypad.
1233 * Default is keypad-numeric-mode.
1236 screen->flags |= TERM_FLAG_KEYPAD_MODE;
1241 static int screen_DECKPNM(term_screen *screen, const term_seq *seq) {
1243 * DECKPNM - keypad-numeric-mode
1244 * This disables the keypad-application-mode (DECKPAM) and returns to
1245 * the keypad-numeric-mode. Keypresses on the keypad generate the same
1246 * sequences as corresponding keypresses on the main keyboard.
1247 * Default is keypad-numeric-mode.
1250 screen->flags &= ~TERM_FLAG_KEYPAD_MODE;
1255 static int screen_DECLFKC(term_screen *screen, const term_seq *seq) {
1257 * DECLFKC - local-function-key-control
1259 * Probably not worth implementing.
1265 static int screen_DECLL(term_screen *screen, const term_seq *seq) {
1269 * Probably not worth implementing.
1275 static int screen_DECLTOD(term_screen *screen, const term_seq *seq) {
1277 * DECLTOD - load-time-of-day
1279 * Probably not worth implementing.
1285 static int screen_DECPCTERM(term_screen *screen, const term_seq *seq) {
1287 * DECPCTERM - pcterm-mode
1288 * This enters/exits the PCTerm mode. Default mode is VT-mode. It can
1289 * also select parameters for scancode/keycode mappings in SCO mode.
1291 * Definitely not worth implementing. Lets kill PCTerm/SCO modes!
1297 static int screen_DECPKA(term_screen *screen, const term_seq *seq) {
1299 * DECPKA - program-key-action
1301 * Probably not worth implementing.
1307 static int screen_DECPKFMR(term_screen *screen, const term_seq *seq) {
1309 * DECPKFMR - program-key-free-memory-report
1311 * Probably not worth implementing.
1317 static int screen_DECRARA(term_screen *screen, const term_seq *seq) {
1319 * DECRARA - reverse-attributes-in-rectangular-area
1321 * Probably not worth implementing.
1327 static int screen_DECRC(term_screen *screen, const term_seq *seq) {
1329 * DECRC - restore-cursor
1330 * Restores the terminal to the state saved by the save cursor (DECSC)
1331 * function. This includes more than just the cursor-position.
1333 * If nothing was saved by DECSC, then DECRC performs the following
1335 * * Moves the cursor to the home position (upper left of screen).
1336 * * Resets origin mode (DECOM).
1337 * * Turns all character attributes off (normal setting).
1338 * * Maps the ASCII character set into GL, and the DEC Supplemental
1339 * Graphic set into GR.
1341 * The terminal maintains a separate DECSC buffer for the main display
1342 * and the status line. This feature lets you save a separate operating
1343 * state for the main display and the status line.
1346 screen_restore_state(screen, &screen->saved);
1351 static int screen_DECREQTPARM(term_screen *screen, const term_seq *seq) {
1353 * DECREQTPARM - request-terminal-parameters
1354 * The sequence DECREPTPARM is sent by the terminal controller to notify
1355 * the host of the status of selected terminal parameters. The status
1356 * sequence may be sent when requested by the host or at the terminal's
1357 * discretion. DECREPTPARM is sent upon receipt of a DECREQTPARM.
1359 * If @args[0] is 0, this marks a request and the terminal is allowed
1360 * to send DECREPTPARM messages without request. If it is 1, the same
1361 * applies but the terminal should no longer send DECREPTPARM
1363 * 2 and 3 mark a report, but 3 is only used if the terminal answers as
1364 * an explicit request with @args[0] == 1.
1366 * The other arguments are ignored in requests, but have the following
1367 * meaning in responses:
1368 * args[1]: 1=no-parity-set 4=parity-set-and-odd 5=parity-set-and-even
1369 * args[2]: 1=8bits-per-char 2=7bits-per-char
1370 * args[3]: transmission-speed
1371 * args[4]: receive-speed
1372 * args[5]: 1=bit-rate-multiplier-is-16
1373 * args[6]: This value communicates the four switch values in block 5
1374 * of SETUP B, which are only visible to the user when an STP
1375 * option is installed. These bits may be assigned for an STP
1376 * device. The four bits are a decimal-encoded binary number.
1377 * Value between 0-15.
1379 * The transmission/receive speeds have mappings for number => bits/s
1380 * which are quite weird. Examples are: 96->3600, 112->9600, 120->19200
1386 if (seq->n_args < 1 || seq->args[0] == 0) {
1387 screen->flags &= ~TERM_FLAG_INHIBIT_TPARM;
1388 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "2;1;1;120;120;1;0x");
1389 } else if (seq->args[0] == 1) {
1390 screen->flags |= TERM_FLAG_INHIBIT_TPARM;
1391 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "3;1;1;120;120;1;0x");
1397 static int screen_DECRPKT(term_screen *screen, const term_seq *seq) {
1399 * DECRPKT - report-key-type
1400 * Response to DECRQKT, we can safely ignore it as we're the one sending
1407 static int screen_DECRQCRA(term_screen *screen, const term_seq *seq) {
1409 * DECRQCRA - request-checksum-of-rectangular-area
1411 * Probably not worth implementing.
1417 static int screen_DECRQDE(term_screen *screen, const term_seq *seq) {
1419 * DECRQDE - request-display-extent
1421 * Probably not worth implementing.
1427 static int screen_DECRQKT(term_screen *screen, const term_seq *seq) {
1429 * DECRQKT - request-key-type
1431 * Probably not worth implementing.
1437 static int screen_DECRQLP(term_screen *screen, const term_seq *seq) {
1439 * DECRQLP - request-locator-position
1440 * See DECELR for locator-information.
1442 * TODO: document and implement
1448 static int screen_DECRQM_ANSI(term_screen *screen, const term_seq *seq) {
1450 * DECRQM_ANSI - request-mode-ansi
1451 * The host sends this control function to find out if a particular mode
1452 * is set or reset. The terminal responds with a report mode function.
1453 * @args[0] contains the mode to query.
1455 * Response is DECRPM with the first argument set to the mode that was
1456 * queried, second argument is 0 if mode is invalid, 1 if mode is set,
1457 * 2 if mode is not set (reset), 3 if mode is permanently set and 4 if
1458 * mode is permanently not set (reset):
1459 * ANSI: ^[ MODE ; VALUE $ y
1460 * DEC: ^[ ? MODE ; VALUE $ y
1468 static int screen_DECRQM_DEC(term_screen *screen, const term_seq *seq) {
1470 * DECRQM_DEC - request-mode-dec
1471 * Same as DECRQM_ANSI but for DEC modes.
1479 static int screen_DECRQPKFM(term_screen *screen, const term_seq *seq) {
1481 * DECRQPKFM - request-program-key-free-memory
1483 * Probably not worth implementing.
1489 static int screen_DECRQPSR(term_screen *screen, const term_seq *seq) {
1491 * DECRQPSR - request-presentation-state-report
1493 * Probably not worth implementing.
1499 static int screen_DECRQTSR(term_screen *screen, const term_seq *seq) {
1501 * DECRQTSR - request-terminal-state-report
1503 * Probably not worth implementing.
1509 static int screen_DECRQUPSS(term_screen *screen, const term_seq *seq) {
1511 * DECRQUPSS - request-user-preferred-supplemental-set
1513 * Probably not worth implementing.
1519 static int screen_DECSACE(term_screen *screen, const term_seq *seq) {
1521 * DECSACE - select-attribute-change-extent
1523 * Probably not worth implementing.
1529 static int screen_DECSASD(term_screen *screen, const term_seq *seq) {
1531 * DECSASD - select-active-status-display
1533 * Probably not worth implementing.
1539 static int screen_DECSC(term_screen *screen, const term_seq *seq) {
1541 * DECSC - save-cursor
1542 * Save cursor and terminal state so it can be restored later on.
1543 * Saves the following items in the terminal's memory:
1545 * * Character attributes set by the SGR command
1546 * * Character sets (G0, G1, G2, or G3) currently in GL and GR
1547 * * Wrap flag (autowrap or no autowrap)
1548 * * State of origin mode (DECOM)
1549 * * Selective erase attribute
1550 * * Any single shift 2 (SS2) or single shift 3 (SS3) functions sent
1553 screen_save_state(screen, &screen->saved);
1558 static int screen_DECSCA(term_screen *screen, const term_seq *seq) {
1560 * DECSCA - select-character-protection-attribute
1561 * Defines the characters that come after it as erasable or not erasable
1562 * from the screen. The selective erase control functions (DECSED and
1563 * DECSEL) can only erase characters defined as erasable.
1565 * @args[0] specifies the new mode. 0 and 2 mark any following character
1566 * as erasable, 1 marks it as not erasable.
1572 unsigned int mode = 0;
1574 if (seq->args[0] > 0)
1575 mode = seq->args[0];
1580 screen->state.attr.protect = 0;
1583 screen->state.attr.protect = 1;
1590 static int screen_DECSCL(term_screen *screen, const term_seq *seq) {
1592 * DECSCL - select-conformance-level
1593 * Select the terminal's operating level. The factory default is
1594 * level 4 (VT Level 4 mode, 7-bit controls).
1595 * When you change the conformance level, the terminal performs a hard
1598 * @args[0] defines the conformance-level, valid values are:
1599 * 61: Level 1 (VT100)
1600 * 62: Level 2 (VT200)
1601 * 63: Level 3 (VT300)
1602 * 64: Level 4 (VT400)
1603 * @args[1] defines the 8bit-mode, valid values are:
1606 * 2: 8-bit controls (same as 0)
1608 * If @args[0] is 61, then @args[1] is ignored and 7bit controls are
1616 unsigned int level = 64, bit = 0;
1618 if (seq->n_args > 0) {
1619 level = seq->args[0];
1620 if (seq->n_args > 1)
1624 term_screen_hard_reset(screen);
1628 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT100;
1629 screen->flags |= TERM_FLAG_7BIT_MODE;
1632 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
1634 screen->flags |= TERM_FLAG_7BIT_MODE;
1636 screen->flags &= ~TERM_FLAG_7BIT_MODE;
1643 static int screen_DECSCP(term_screen *screen, const term_seq *seq) {
1645 * DECSCP - select-communication-port
1647 * Probably not worth implementing.
1653 static int screen_DECSCPP(term_screen *screen, const term_seq *seq) {
1655 * DECSCPP - select-columns-per-page
1656 * Select columns per page. The number of rows is unaffected by this.
1657 * @args[0] selectes the number of columns (width), DEC only defines 80
1658 * and 132, but we allow any integer here. 0 is equivalent to 80.
1659 * Page content is *not* cleared and the cursor is left untouched.
1660 * However, if the page is reduced in width and the cursor would be
1661 * outside the visible region, it's set to the right border. Newly added
1662 * cells are cleared. No data is retained outside the visible region.
1673 static int screen_DECSCS(term_screen *screen, const term_seq *seq) {
1675 * DECSCS - select-communication-speed
1677 * Probably not worth implementing.
1683 static int screen_DECSCUSR(term_screen *screen, const term_seq *seq) {
1685 * DECSCUSR - set-cursor-style
1686 * This changes the style of the cursor. @args[0] can be one of:
1687 * 0, 1: blinking block
1689 * 3: blinking underline
1690 * 4: steady underline
1691 * Changing this setting does _not_ affect the cursor visibility itself.
1692 * Use DECTCEM for that.
1703 static int screen_DECSDDT(term_screen *screen, const term_seq *seq) {
1705 * DECSDDT - select-disconnect-delay-time
1707 * Probably not worth implementing.
1713 static int screen_DECSDPT(term_screen *screen, const term_seq *seq) {
1715 * DECSDPT - select-digital-printed-data-type
1717 * Probably not worth implementing.
1723 static int screen_DECSED(term_screen *screen, const term_seq *seq) {
1725 * DECSED - selective-erase-in-display
1726 * This control function erases some or all of the erasable characters
1727 * in the display. DECSED can only erase characters defined as erasable
1728 * by the DECSCA control function. DECSED works inside or outside the
1729 * scrolling margins.
1731 * @args[0] defines which regions are erased. If it is 0, all cells from
1732 * the cursor (inclusive) till the end of the display are erase. If it
1733 * is 1, all cells from the start of the display till the cursor
1734 * (inclusive) are erased. If it is 2, all cells are erased.
1740 unsigned int mode = 0;
1742 if (seq->args[0] > 0)
1743 mode = seq->args[0];
1747 term_page_erase(screen->page,
1748 screen->state.cursor_x, screen->state.cursor_y,
1749 screen->page->width, screen->page->height,
1750 &screen->state.attr, screen->age, true);
1753 term_page_erase(screen->page,
1755 screen->state.cursor_x, screen->state.cursor_y,
1756 &screen->state.attr, screen->age, true);
1759 term_page_erase(screen->page,
1761 screen->page->width, screen->page->height,
1762 &screen->state.attr, screen->age, true);
1769 static int screen_DECSEL(term_screen *screen, const term_seq *seq) {
1771 * DECSEL - selective-erase-in-line
1772 * This control function erases some or all of the erasable characters
1773 * in a single line of text. DECSEL erases only those characters defined
1774 * as erasable by the DECSCA control function. DECSEL works inside or
1775 * outside the scrolling margins.
1777 * @args[0] defines the region to be erased. If it is 0, all cells from
1778 * the cursor (inclusive) till the end of the line are erase. If it is
1779 * 1, all cells from the start of the line till the cursor (inclusive)
1780 * are erased. If it is 2, the whole line of the cursor is erased.
1786 unsigned int mode = 0;
1788 if (seq->args[0] > 0)
1789 mode = seq->args[0];
1793 term_page_erase(screen->page,
1794 screen->state.cursor_x, screen->state.cursor_y,
1795 screen->page->width, screen->state.cursor_y,
1796 &screen->state.attr, screen->age, true);
1799 term_page_erase(screen->page,
1800 0, screen->state.cursor_y,
1801 screen->state.cursor_x, screen->state.cursor_y,
1802 &screen->state.attr, screen->age, true);
1805 term_page_erase(screen->page,
1806 0, screen->state.cursor_y,
1807 screen->page->width, screen->state.cursor_y,
1808 &screen->state.attr, screen->age, true);
1815 static int screen_DECSERA(term_screen *screen, const term_seq *seq) {
1817 * DECSERA - selective-erase-rectangular-area
1819 * Probably not worth implementing.
1825 static int screen_DECSFC(term_screen *screen, const term_seq *seq) {
1827 * DECSFC - select-flow-control
1829 * Probably not worth implementing.
1835 static int screen_DECSKCV(term_screen *screen, const term_seq *seq) {
1837 * DECSKCV - set-key-click-volume
1839 * Probably not worth implementing.
1845 static int screen_DECSLCK(term_screen *screen, const term_seq *seq) {
1847 * DECSLCK - set-lock-key-style
1849 * Probably not worth implementing.
1855 static int screen_DECSLE(term_screen *screen, const term_seq *seq) {
1857 * DECSLE - select-locator-events
1865 static int screen_DECSLPP(term_screen *screen, const term_seq *seq) {
1867 * DECSLPP - set-lines-per-page
1868 * Set the number of lines used for the page. @args[0] specifies the
1869 * number of lines to be used. DEC only allows a limited number of
1870 * choices, however, we allow all integers. 0 is equivalent to 24.
1881 static int screen_DECSLRM_OR_SC(term_screen *screen, const term_seq *seq) {
1883 * DECSLRM_OR_SC - set-left-and-right-margins or save-cursor
1885 * TODO: Detect save-cursor and run it. DECSLRM is not worth
1892 static int screen_DECSMBV(term_screen *screen, const term_seq *seq) {
1894 * DECSMBV - set-margin-bell-volume
1896 * Probably not worth implementing.
1902 static int screen_DECSMKR(term_screen *screen, const term_seq *seq) {
1904 * DECSMKR - select-modifier-key-reporting
1906 * Probably not worth implementing.
1912 static int screen_DECSNLS(term_screen *screen, const term_seq *seq) {
1914 * DECSNLS - set-lines-per-screen
1916 * Probably not worth implementing.
1922 static int screen_DECSPP(term_screen *screen, const term_seq *seq) {
1924 * DECSPP - set-port-parameter
1926 * Probably not worth implementing.
1932 static int screen_DECSPPCS(term_screen *screen, const term_seq *seq) {
1934 * DECSPPCS - select-pro-printer-character-set
1936 * Probably not worth implementing.
1942 static int screen_DECSPRTT(term_screen *screen, const term_seq *seq) {
1944 * DECSPRTT - select-printer-type
1946 * Probably not worth implementing.
1952 static int screen_DECSR(term_screen *screen, const term_seq *seq) {
1954 * DECSR - secure-reset
1956 * Probably not worth implementing.
1962 static int screen_DECSRFR(term_screen *screen, const term_seq *seq) {
1964 * DECSRFR - select-refresh-rate
1966 * Probably not worth implementing.
1972 static int screen_DECSSCLS(term_screen *screen, const term_seq *seq) {
1974 * DECSSCLS - set-scroll-speed
1976 * Probably not worth implementing.
1982 static int screen_DECSSDT(term_screen *screen, const term_seq *seq) {
1984 * DECSSDT - select-status-display-line-type
1986 * Probably not worth implementing.
1992 static int screen_DECSSL(term_screen *screen, const term_seq *seq) {
1994 * DECSSL - select-setup-language
1996 * Probably not worth implementing.
2002 static int screen_DECST8C(term_screen *screen, const term_seq *seq) {
2004 * DECST8C - set-tab-at-every-8-columns
2005 * Clear the tab-ruler and reset it to a tab at every 8th column,
2006 * starting at 9 (though, setting a tab at 1 is fine as it has no
2012 for (i = 0; i < screen->page->width; i += 8)
2013 screen->tabs[i / 8] = 0x1;
2018 static int screen_DECSTBM(term_screen *screen, const term_seq *seq) {
2020 * DECSTBM - set-top-and-bottom-margins
2021 * This control function sets the top and bottom margins for the current
2022 * page. You cannot perform scrolling outside the margins.
2024 * @args[0] defines the top margin, @args[1] defines the bottom margin.
2025 * The bottom margin must be lower than the top-margin.
2027 * This call resets the cursor position to 0/0 of the page.
2031 * args[1]: last page-line
2034 unsigned int top, bottom;
2037 bottom = screen->page->height;
2039 if (seq->args[0] > 0)
2041 if (seq->args[1] > 0)
2042 bottom = seq->args[1];
2044 if (top > screen->page->height)
2045 top = screen->page->height;
2046 if (bottom > screen->page->height)
2047 bottom = screen->page->height;
2049 if (top >= bottom || top > screen->page->height || bottom > screen->page->height) {
2051 bottom = screen->page->height;
2054 term_page_set_scroll_region(screen->page, top - 1, bottom - top + 1);
2055 screen_cursor_clear_wrap(screen);
2056 screen_cursor_set(screen, 0, 0);
2061 static int screen_DECSTR(term_screen *screen, const term_seq *seq) {
2063 * DECSTR - soft-terminal-reset
2064 * Perform a soft reset to the default values.
2067 term_screen_soft_reset(screen);
2072 static int screen_DECSTRL(term_screen *screen, const term_seq *seq) {
2074 * DECSTRL - set-transmit-rate-limit
2076 * Probably not worth implementing.
2082 static int screen_DECSWBV(term_screen *screen, const term_seq *seq) {
2084 * DECSWBV - set-warning-bell-volume
2086 * Probably not worth implementing.
2092 static int screen_DECSWL(term_screen *screen, const term_seq *seq) {
2094 * DECSWL - single-width-single-height-line
2096 * Probably not worth implementing.
2102 static int screen_DECTID(term_screen *screen, const term_seq *seq) {
2104 * DECTID - select-terminal-id
2106 * Probably not worth implementing.
2112 static int screen_DECTME(term_screen *screen, const term_seq *seq) {
2114 * DECTME - terminal-mode-emulation
2116 * Probably not worth implementing.
2122 static int screen_DECTST(term_screen *screen, const term_seq *seq) {
2124 * DECTST - invoke-confidence-test
2126 * Probably not worth implementing.
2132 static int screen_DL(term_screen *screen, const term_seq *seq) {
2135 * This control function deletes one or more lines in the scrolling
2136 * region, starting with the line that has the cursor. @args[0] defines
2137 * the number of lines to delete. 0 is treated the same as 1.
2138 * As lines are deleted, lines below the cursor and in the scrolling
2139 * region move up. The terminal adds blank lines with no visual
2140 * character attributes at the bottom of the scrolling region. If it is
2141 * greater than the number of lines remaining on the page, DL deletes
2142 * only the remaining lines. DL has no effect outside the scrolling
2149 unsigned int num = 1;
2151 if (seq->args[0] > 0)
2154 term_page_delete_lines(screen->page, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2159 static int screen_DSR_ANSI(term_screen *screen, const term_seq *seq) {
2161 * DSR_ANSI - device-status-report-ansi
2169 static int screen_DSR_DEC(term_screen *screen, const term_seq *seq) {
2171 * DSR_DEC - device-status-report-dec
2179 static int screen_ECH(term_screen *screen, const term_seq *seq) {
2181 * ECH - erase-character
2182 * This control function erases one or more characters, from the cursor
2183 * position to the right. ECH clears character attributes from erased
2184 * character positions. ECH works inside or outside the scrolling
2186 * @args[0] defines the number of characters to erase. 0 is treated the
2193 unsigned int num = 1;
2195 if (seq->args[0] > 0)
2198 term_page_erase(screen->page,
2199 screen->state.cursor_x, screen->state.cursor_y,
2200 screen->state.cursor_x + num, screen->state.cursor_y,
2201 &screen->state.attr, screen->age, false);
2206 static int screen_ED(term_screen *screen, const term_seq *seq) {
2208 * ED - erase-in-display
2209 * This control function erases characters from part or all of the
2210 * display. When you erase complete lines, they become single-height,
2211 * single-width lines, with all visual character attributes cleared. ED
2212 * works inside or outside the scrolling margins.
2214 * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2215 * till the end of the screen. 1 means from the start of the screen till
2216 * the cursor (inclusive) and 2 means the whole screen.
2222 unsigned int mode = 0;
2224 if (seq->args[0] > 0)
2225 mode = seq->args[0];
2229 term_page_erase(screen->page,
2230 screen->state.cursor_x, screen->state.cursor_y,
2231 screen->page->width, screen->page->height,
2232 &screen->state.attr, screen->age, false);
2235 term_page_erase(screen->page,
2237 screen->state.cursor_x, screen->state.cursor_y,
2238 &screen->state.attr, screen->age, false);
2241 term_page_erase(screen->page,
2243 screen->page->width, screen->page->height,
2244 &screen->state.attr, screen->age, false);
2251 static int screen_EL(term_screen *screen, const term_seq *seq) {
2253 * EL - erase-in-line
2254 * This control function erases characters on the line that has the
2255 * cursor. EL clears all character attributes from erased character
2256 * positions. EL works inside or outside the scrolling margins.
2258 * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2259 * till the end of the line. 1 means from the start of the line till the
2260 * cursor (inclusive) and 2 means the whole line.
2266 unsigned int mode = 0;
2268 if (seq->args[0] > 0)
2269 mode = seq->args[0];
2273 term_page_erase(screen->page,
2274 screen->state.cursor_x, screen->state.cursor_y,
2275 screen->page->width, screen->state.cursor_y,
2276 &screen->state.attr, screen->age, false);
2279 term_page_erase(screen->page,
2280 0, screen->state.cursor_y,
2281 screen->state.cursor_x, screen->state.cursor_y,
2282 &screen->state.attr, screen->age, false);
2285 term_page_erase(screen->page,
2286 0, screen->state.cursor_y,
2287 screen->page->width, screen->state.cursor_y,
2288 &screen->state.attr, screen->age, false);
2295 static int screen_ENQ(term_screen *screen, const term_seq *seq) {
2298 * Transmit the answerback-string. If none is set, do nothing.
2301 if (screen->answerback)
2302 return screen_write(screen, screen->answerback, strlen(screen->answerback));
2307 static int screen_EPA(term_screen *screen, const term_seq *seq) {
2309 * EPA - end-of-guarded-area
2311 * TODO: What is this?
2317 static int screen_FF(term_screen *screen, const term_seq *seq) {
2320 * This causes the cursor to jump to the next line. It is treated the
2324 return screen_LF(screen, seq);
2327 static int screen_HPA(term_screen *screen, const term_seq *seq) {
2329 * HPA - horizontal-position-absolute
2330 * HPA causes the active position to be moved to the n-th horizontal
2331 * position of the active line. If an attempt is made to move the active
2332 * position past the last position on the line, then the active position
2333 * stops at the last position on the line.
2335 * @args[0] defines the horizontal position. 0 is treated as 1.
2341 unsigned int num = 1;
2343 if (seq->args[0] > 0)
2346 screen_cursor_clear_wrap(screen);
2347 screen_cursor_set(screen, num - 1, screen->state.cursor_y);
2352 static int screen_HPR(term_screen *screen, const term_seq *seq) {
2354 * HPR - horizontal-position-relative
2355 * HPR causes the active position to be moved to the n-th following
2356 * horizontal position of the active line. If an attempt is made to move
2357 * the active position past the last position on the line, then the
2358 * active position stops at the last position on the line.
2360 * @args[0] defines the horizontal position. 0 is treated as 1.
2366 unsigned int num = 1;
2368 if (seq->args[0] > 0)
2371 screen_cursor_clear_wrap(screen);
2372 screen_cursor_right(screen, num);
2377 static int screen_HT(term_screen *screen, const term_seq *seq) {
2379 * HT - horizontal-tab
2380 * Moves the cursor to the next tab stop. If there are no more tab
2381 * stops, the cursor moves to the right margin. HT does not cause text
2385 screen_cursor_clear_wrap(screen);
2386 screen_cursor_right_tab(screen, 1);
2391 static int screen_HTS(term_screen *screen, const term_seq *seq) {
2393 * HTS - horizontal-tab-set
2394 * HTS sets a horizontal tab stop at the column position indicated by
2395 * the value of the active column when the terminal receives an HTS.
2397 * Executing an HTS does not effect the other horizontal tab stop
2403 pos = screen->state.cursor_x;
2404 if (screen->page->width > 0)
2405 screen->tabs[pos / 8] |= 1U << (pos % 8);
2410 static int screen_HVP(term_screen *screen, const term_seq *seq) {
2412 * HVP - horizontal-and-vertical-position
2413 * This control function works the same as the cursor position (CUP)
2414 * function. Origin mode (DECOM) selects line numbering and the ability
2415 * to move the cursor into margins.
2422 return screen_CUP(screen, seq);
2425 static int screen_ICH(term_screen *screen, const term_seq *seq) {
2427 * ICH - insert-character
2428 * This control function inserts one or more space (SP) characters
2429 * starting at the cursor position. @args[0] is the number of characters
2430 * to insert. 0 is treated as 1.
2432 * The ICH sequence inserts blank characters with the normal
2433 * character attribute. The cursor remains at the beginning of the blank
2434 * characters. Text between the cursor and right margin moves to the
2435 * right. Characters scrolled past the right margin are lost. ICH has no
2436 * effect outside the scrolling margins.
2442 unsigned int num = 1;
2444 if (seq->args[0] > 0)
2447 screen_cursor_clear_wrap(screen);
2448 term_page_insert_cells(screen->page, screen->state.cursor_x, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2453 static int screen_IL(term_screen *screen, const term_seq *seq) {
2456 * This control function inserts one or more blank lines, starting at
2457 * the cursor. @args[0] is the number of lines to insert. 0 is treated
2460 * As lines are inserted, lines below the cursor and in the scrolling
2461 * region move down. Lines scrolled off the page are lost. IL has no
2462 * effect outside the page margins.
2468 unsigned int num = 1;
2470 if (seq->args[0] > 0)
2473 screen_cursor_clear_wrap(screen);
2474 term_page_insert_lines(screen->page, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2479 static int screen_IND(term_screen *screen, const term_seq *seq) {
2482 * IND moves the cursor down one line in the same column. If the cursor
2483 * is at the bottom margin, then the screen performs a scroll-up.
2486 screen_cursor_down(screen, 1, true);
2491 static int screen_LF(term_screen *screen, const term_seq *seq) {
2494 * Causes a line feed or a new line operation, depending on the setting
2495 * of line feed/new line mode.
2498 screen_cursor_down(screen, 1, true);
2499 if (screen->flags & TERM_FLAG_NEWLINE_MODE)
2500 screen_cursor_left(screen, screen->state.cursor_x);
2505 static int screen_LS1R(term_screen *screen, const term_seq *seq) {
2507 * LS1R - locking-shift-1-right
2511 screen->state.gr = &screen->g1;
2516 static int screen_LS2(term_screen *screen, const term_seq *seq) {
2518 * LS2 - locking-shift-2
2522 screen->state.gl = &screen->g2;
2527 static int screen_LS2R(term_screen *screen, const term_seq *seq) {
2529 * LS2R - locking-shift-2-right
2533 screen->state.gr = &screen->g2;
2538 static int screen_LS3(term_screen *screen, const term_seq *seq) {
2540 * LS3 - locking-shift-3
2544 screen->state.gl = &screen->g3;
2549 static int screen_LS3R(term_screen *screen, const term_seq *seq) {
2551 * LS3R - locking-shift-3-right
2555 screen->state.gr = &screen->g3;
2560 static int screen_MC_ANSI(term_screen *screen, const term_seq *seq) {
2562 * MC_ANSI - media-copy-ansi
2564 * Probably not worth implementing.
2570 static int screen_MC_DEC(term_screen *screen, const term_seq *seq) {
2572 * MC_DEC - media-copy-dec
2574 * Probably not worth implementing.
2580 static int screen_NEL(term_screen *screen, const term_seq *seq) {
2583 * Moves cursor to first position on next line. If cursor is at bottom
2584 * margin, then screen performs a scroll-up.
2587 screen_cursor_clear_wrap(screen);
2588 screen_cursor_down(screen, 1, true);
2589 screen_cursor_set(screen, 0, screen->state.cursor_y);
2594 static int screen_NP(term_screen *screen, const term_seq *seq) {
2597 * This control function moves the cursor forward to the home position
2598 * on one of the following pages in page memory. If there is only one
2599 * page, then the terminal ignores NP.
2600 * If NP tries to move the cursor past the last page in memory, then the
2601 * cursor stops at the last page.
2603 * @args[0] defines the number of pages to forward. 0 is treated as 1.
2608 * Probably not worth implementing. We only support a single page.
2614 static int screen_NULL(term_screen *screen, const term_seq *seq) {
2617 * The NULL operation does nothing. ASCII NULL is always ignored.
2623 static int screen_PP(term_screen *screen, const term_seq *seq) {
2625 * PP - preceding-page
2626 * This control function moves the cursor backward to the home position
2627 * on one of the preceding pages in page memory. If there is only one
2628 * page, then the terminal ignores PP.
2629 * If PP tries to move the cursor back farther than the first page in
2630 * memory, then the cursor stops at the first page.
2632 * @args[0] defines the number of pages to go backwards. 0 is treated
2638 * Probably not worth implementing. We only support a single page.
2644 static int screen_PPA(term_screen *screen, const term_seq *seq) {
2646 * PPA - page-position-absolute
2647 * This control function can move the cursor to the corresponding row
2648 * and column on any page in page memory. You select the page by its
2649 * number. If there is only one page, then the terminal ignores PPA.
2651 * @args[0] is the number of the page to move the cursor to. If it is
2652 * greater than the number of the last page in memory, then the cursor
2653 * stops at the last page. If it is less than the number of the first
2654 * page, then the cursor stops at the first page.
2659 * Probably not worth implementing. We only support a single page.
2665 static int screen_PPB(term_screen *screen, const term_seq *seq) {
2667 * PPB - page-position-backward
2668 * This control function moves the cursor backward to the corresponding
2669 * row and column on one of the preceding pages in page memory. If there
2670 * is only one page, then the terminal ignores PPB.
2672 * @args[0] indicates the number of pages to move the cursor backward.
2673 * If it tries to move the cursor back farther than the first page in
2674 * memory, then the cursor stops at the first page. 0 is treated as 1.
2679 * Probably not worth implementing. We only support a single page.
2685 static int screen_PPR(term_screen *screen, const term_seq *seq) {
2687 * PPR - page-position-relative
2688 * This control function moves the cursor forward to the corresponding
2689 * row and column on one of the following pages in page memory. If there
2690 * is only one page, then the terminal ignores PPR.
2692 * @args[0] indicates how many pages to move the cursor forward. If it
2693 * tries to move the cursor beyond the last page in memory, then the
2694 * cursor stops at the last page. 0 is treated as 1.
2699 * Probably not worth implementing. We only support a single page.
2705 static int screen_RC(term_screen *screen, const term_seq *seq) {
2707 * RC - restore-cursor
2710 return screen_DECRC(screen, seq);
2713 static int screen_REP(term_screen *screen, const term_seq *seq) {
2716 * Repeat the preceding graphics-character the given number of times.
2717 * @args[0] specifies how often it shall be repeated. 0 is treated as 1.
2722 * Probably not worth implementing.
2728 static int screen_RI(term_screen *screen, const term_seq *seq) {
2730 * RI - reverse-index
2731 * Moves the cursor up one line in the same column. If the cursor is at
2732 * the top margin, the page scrolls down.
2735 screen_cursor_up(screen, 1, true);
2740 static int screen_RIS(term_screen *screen, const term_seq *seq) {
2742 * RIS - reset-to-initial-state
2743 * This control function causes a nonvolatile memory (NVR) recall to
2744 * occur. RIS replaces all set-up features with their saved settings.
2746 * The terminal stores these saved settings in NVR memory. The saved
2747 * setting for a feature is the same as the factory-default setting,
2748 * unless you saved a new setting.
2751 term_screen_hard_reset(screen);
2756 static int screen_RM_ANSI(term_screen *screen, const term_seq *seq) {
2758 * RM_ANSI - reset-mode-ansi
2760 * TODO: implement (see VT510rm manual)
2765 for (i = 0; i < seq->n_args; ++i)
2766 screen_mode_change(screen, seq->args[i], false, false);
2771 static int screen_RM_DEC(term_screen *screen, const term_seq *seq) {
2773 * RM_DEC - reset-mode-dec
2774 * This is the same as RM_ANSI but for DEC modes.
2779 for (i = 0; i < seq->n_args; ++i)
2780 screen_mode_change(screen, seq->args[i], true, false);
2785 static int screen_S7C1T(term_screen *screen, const term_seq *seq) {
2787 * S7C1T - set-7bit-c1-terminal
2788 * This causes the terminal to start sending C1 controls as 7bit
2789 * sequences instead of 8bit C1 controls.
2790 * This is ignored if the terminal is below level-2 emulation mode
2791 * (VT100 and below), the terminal already sends 7bit controls then.
2794 if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2795 screen->flags |= TERM_FLAG_7BIT_MODE;
2800 static int screen_S8C1T(term_screen *screen, const term_seq *seq) {
2802 * S8C1T - set-8bit-c1-terminal
2803 * This causes the terminal to start sending C1 controls as 8bit C1
2804 * control instead of 7bit sequences.
2805 * This is ignored if the terminal is below level-2 emulation mode
2806 * (VT100 and below). The terminal always sends 7bit controls in those
2810 if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2811 screen->flags &= ~TERM_FLAG_7BIT_MODE;
2816 static int screen_SCS(term_screen *screen, const term_seq *seq) {
2818 * SCS - select-character-set
2819 * Designate character sets to G-sets. The mapping from intermediates
2820 * and terminal characters in the escape sequence to G-sets and
2821 * character-sets is non-trivial and implemented separately. See there
2822 * for more information.
2823 * This call simply sets the selected G-set to the desired
2827 term_charset *cs = NULL;
2829 /* TODO: support more of them? */
2830 switch (seq->charset) {
2831 case TERM_CHARSET_ISO_LATIN1_SUPPLEMENTAL:
2832 case TERM_CHARSET_ISO_LATIN2_SUPPLEMENTAL:
2833 case TERM_CHARSET_ISO_LATIN5_SUPPLEMENTAL:
2834 case TERM_CHARSET_ISO_GREEK_SUPPLEMENTAL:
2835 case TERM_CHARSET_ISO_HEBREW_SUPPLEMENTAL:
2836 case TERM_CHARSET_ISO_LATIN_CYRILLIC:
2839 case TERM_CHARSET_DEC_SPECIAL_GRAPHIC:
2840 cs = &term_dec_special_graphics;
2842 case TERM_CHARSET_DEC_SUPPLEMENTAL:
2843 cs = &term_dec_supplemental_graphics;
2845 case TERM_CHARSET_DEC_TECHNICAL:
2846 case TERM_CHARSET_CYRILLIC_DEC:
2847 case TERM_CHARSET_DUTCH_NRCS:
2848 case TERM_CHARSET_FINNISH_NRCS:
2849 case TERM_CHARSET_FRENCH_NRCS:
2850 case TERM_CHARSET_FRENCH_CANADIAN_NRCS:
2851 case TERM_CHARSET_GERMAN_NRCS:
2852 case TERM_CHARSET_GREEK_DEC:
2853 case TERM_CHARSET_GREEK_NRCS:
2854 case TERM_CHARSET_HEBREW_DEC:
2855 case TERM_CHARSET_HEBREW_NRCS:
2856 case TERM_CHARSET_ITALIAN_NRCS:
2857 case TERM_CHARSET_NORWEGIAN_DANISH_NRCS:
2858 case TERM_CHARSET_PORTUGUESE_NRCS:
2859 case TERM_CHARSET_RUSSIAN_NRCS:
2860 case TERM_CHARSET_SCS_NRCS:
2861 case TERM_CHARSET_SPANISH_NRCS:
2862 case TERM_CHARSET_SWEDISH_NRCS:
2863 case TERM_CHARSET_SWISS_NRCS:
2864 case TERM_CHARSET_TURKISH_DEC:
2865 case TERM_CHARSET_TURKISH_NRCS:
2868 case TERM_CHARSET_USERPREF_SUPPLEMENTAL:
2872 if (seq->intermediates & TERM_SEQ_FLAG_POPEN)
2873 screen->g0 = cs ? : &term_unicode_lower;
2874 else if (seq->intermediates & TERM_SEQ_FLAG_PCLOSE)
2875 screen->g1 = cs ? : &term_unicode_upper;
2876 else if (seq->intermediates & TERM_SEQ_FLAG_MULT)
2877 screen->g2 = cs ? : &term_unicode_lower;
2878 else if (seq->intermediates & TERM_SEQ_FLAG_PLUS)
2879 screen->g3 = cs ? : &term_unicode_upper;
2880 else if (seq->intermediates & TERM_SEQ_FLAG_MINUS)
2881 screen->g1 = cs ? : &term_unicode_upper;
2882 else if (seq->intermediates & TERM_SEQ_FLAG_DOT)
2883 screen->g2 = cs ? : &term_unicode_lower;
2884 else if (seq->intermediates & TERM_SEQ_FLAG_SLASH)
2885 screen->g3 = cs ? : &term_unicode_upper;
2890 static int screen_SD(term_screen *screen, const term_seq *seq) {
2893 * This control function moves the user window down a specified number
2894 * of lines in page memory.
2895 * @args[0] is the number of lines to move the
2896 * user window up in page memory. New lines appear at the top of the
2897 * display. Old lines disappear at the bottom of the display. You
2898 * cannot pan past the top margin of the current page. 0 is treated
2905 unsigned int num = 1;
2907 if (seq->args[0] > 0)
2910 term_page_scroll_down(screen->page, num, &screen->state.attr, screen->age, NULL);
2915 static int screen_SGR(term_screen *screen, const term_seq *seq) {
2917 * SGR - select-graphics-rendition
2921 unsigned int i, code;
2924 if (seq->n_args < 1) {
2925 zero(screen->state.attr);
2929 for (i = 0; i < seq->n_args; ++i) {
2933 screen->state.attr.bold = 1;
2936 screen->state.attr.italic = 1;
2939 screen->state.attr.underline = 1;
2942 screen->state.attr.blink = 1;
2945 screen->state.attr.inverse = 1;
2948 screen->state.attr.hidden = 1;
2951 screen->state.attr.bold = 0;
2954 screen->state.attr.italic = 0;
2957 screen->state.attr.underline = 0;
2960 screen->state.attr.blink = 0;
2963 screen->state.attr.inverse = 0;
2966 screen->state.attr.hidden = 0;
2969 screen->state.attr.fg.ccode = v - 30 + TERM_CCODE_BLACK;
2972 screen->state.attr.fg.ccode = 0;
2975 screen->state.attr.bg.ccode = v - 40 + TERM_CCODE_BLACK;
2978 screen->state.attr.bg.ccode = 0;
2981 screen->state.attr.fg.ccode = v - 90 + TERM_CCODE_LIGHT_BLACK;
2984 screen->state.attr.bg.ccode = v - 100 + TERM_CCODE_LIGHT_BLACK;
2991 dst = &screen->state.attr.fg;
2993 dst = &screen->state.attr.bg;
2996 if (i >= seq->n_args)
2999 switch (seq->args[i]) {
3001 /* 24bit-color support */
3004 if (i >= seq->n_args)
3007 dst->ccode = TERM_CCODE_RGB;
3008 dst->red = (seq->args[i - 2] >= 0) ? seq->args[i - 2] : 0;
3009 dst->green = (seq->args[i - 1] >= 0) ? seq->args[i - 1] : 0;
3010 dst->blue = (seq->args[i] >= 0) ? seq->args[i] : 0;
3014 /* 256-color support */
3017 if (i >= seq->n_args || seq->args[i] < 0)
3020 dst->ccode = TERM_CCODE_256;
3021 code = seq->args[i];
3022 dst->c256 = code < 256 ? code : 0;
3031 zero(screen->state.attr);
3039 static int screen_SI(term_screen *screen, const term_seq *seq) {
3045 screen->state.gl = &screen->g0;
3050 static int screen_SM_ANSI(term_screen *screen, const term_seq *seq) {
3052 * SM_ANSI - set-mode-ansi
3059 for (i = 0; i < seq->n_args; ++i)
3060 screen_mode_change(screen, seq->args[i], false, true);
3065 static int screen_SM_DEC(term_screen *screen, const term_seq *seq) {
3067 * SM_DEC - set-mode-dec
3068 * This is the same as SM_ANSI but for DEC modes.
3073 for (i = 0; i < seq->n_args; ++i)
3074 screen_mode_change(screen, seq->args[i], true, true);
3079 static int screen_SO(term_screen *screen, const term_seq *seq) {
3085 screen->state.gl = &screen->g1;
3090 static int screen_SPA(term_screen *screen, const term_seq *seq) {
3092 * SPA - start-of-protected-area
3094 * TODO: What is this?
3100 static int screen_SS2(term_screen *screen, const term_seq *seq) {
3102 * SS2 - single-shift-2
3103 * Temporarily map G2 into GL for the next graphics character.
3106 screen->state.glt = &screen->g2;
3111 static int screen_SS3(term_screen *screen, const term_seq *seq) {
3113 * SS3 - single-shift-3
3114 * Temporarily map G3 into GL for the next graphics character
3117 screen->state.glt = &screen->g3;
3122 static int screen_ST(term_screen *screen, const term_seq *seq) {
3124 * ST - string-terminator
3125 * The string-terminator is usually part of control-sequences and
3126 * handled by the parser. In all other situations it is silently
3133 static int screen_SU(term_screen *screen, const term_seq *seq) {
3136 * This control function moves the user window up a specified number of
3137 * lines in page memory.
3138 * @args[0] is the number of lines to move the
3139 * user window down in page memory. New lines appear at the bottom of
3140 * the display. Old lines disappear at the top of the display. You
3141 * cannot pan past the bottom margin of the current page. 0 is treated
3148 unsigned int num = 1;
3150 if (seq->args[0] > 0)
3153 term_page_scroll_up(screen->page, num, &screen->state.attr, screen->age, screen->history);
3158 static int screen_SUB(term_screen *screen, const term_seq *seq) {
3161 * Cancel the current control-sequence and print a replacement
3162 * character. Our parser already handles this so all we have to do is
3163 * print the replacement character.
3166 static const term_seq rep = {
3167 .type = TERM_SEQ_GRAPHIC,
3168 .command = TERM_CMD_GRAPHIC,
3169 .terminator = 0xfffd,
3172 return screen_GRAPHIC(screen, &rep);
3175 static int screen_TBC(term_screen *screen, const term_seq *seq) {
3178 * This clears tab-stops. If @args[0] is 0, the tab-stop at the current
3179 * cursor position is cleared. If it is 3, all tab stops are cleared.
3185 unsigned int mode = 0, pos;
3187 if (seq->args[0] > 0)
3188 mode = seq->args[0];
3192 pos = screen->state.cursor_x;
3193 if (screen->page->width > 0)
3194 screen->tabs[pos / 8] &= ~(1U << (pos % 8));
3197 if (screen->page->width > 0)
3198 memset(screen->tabs, 0, (screen->page->width + 7) / 8);
3205 static int screen_VPA(term_screen *screen, const term_seq *seq) {
3207 * VPA - vertical-line-position-absolute
3208 * VPA causes the active position to be moved to the corresponding
3209 * horizontal position. @args[0] specifies the line to jump to. If an
3210 * attempt is made to move the active position below the last line, then
3211 * the active position stops on the last line. 0 is treated as 1.
3217 unsigned int pos = 1;
3219 if (seq->args[0] > 0)
3222 screen_cursor_clear_wrap(screen);
3223 screen_cursor_set_rel(screen, screen->state.cursor_x, pos - 1);
3228 static int screen_VPR(term_screen *screen, const term_seq *seq) {
3230 * VPR - vertical-line-position-relative
3231 * VPR causes the active position to be moved to the corresponding
3232 * horizontal position. @args[0] specifies the number of lines to jump
3233 * down relative to the current cursor position. If an attempt is made
3234 * to move the active position below the last line, the active position
3235 * stops at the last line. 0 is treated as 1.
3241 unsigned int num = 1;
3243 if (seq->args[0] > 0)
3246 screen_cursor_clear_wrap(screen);
3247 screen_cursor_down(screen, num, false);
3252 static int screen_VT(term_screen *screen, const term_seq *seq) {
3255 * This causes a vertical jump by one line. Terminals treat it exactly
3259 return screen_LF(screen, seq);
3262 static int screen_XTERM_CLLHP(term_screen *screen, const term_seq *seq) {
3264 * XTERM_CLLHP - xterm-cursor-lower-left-hp-bugfix
3265 * Move the cursor to the lower-left corner of the page. This is an HP
3268 * Probably not worth implementing.
3274 static int screen_XTERM_IHMT(term_screen *screen, const term_seq *seq) {
3276 * XTERM_IHMT - xterm-initiate-highlight-mouse-tracking
3278 * Probably not worth implementing.
3284 static int screen_XTERM_MLHP(term_screen *screen, const term_seq *seq) {
3286 * XTERM_MLHP - xterm-memory-lock-hp-bugfix
3288 * Probably not worth implementing.
3294 static int screen_XTERM_MUHP(term_screen *screen, const term_seq *seq) {
3296 * XTERM_MUHP - xterm-memory-unlock-hp-bugfix
3298 * Probably not worth implementing.
3304 static int screen_XTERM_RPM(term_screen *screen, const term_seq *seq) {
3306 * XTERM_RPM - xterm-restore-private-mode
3308 * Probably not worth implementing.
3314 static int screen_XTERM_RRV(term_screen *screen, const term_seq *seq) {
3316 * XTERM_RRV - xterm-reset-resource-value
3318 * Probably not worth implementing.
3324 static int screen_XTERM_RTM(term_screen *screen, const term_seq *seq) {
3326 * XTERM_RTM - xterm-reset-title-mode
3328 * Probably not worth implementing.
3334 static int screen_XTERM_SACL1(term_screen *screen, const term_seq *seq) {
3336 * XTERM_SACL1 - xterm-set-ansi-conformance-level-1
3338 * Probably not worth implementing.
3344 static int screen_XTERM_SACL2(term_screen *screen, const term_seq *seq) {
3346 * XTERM_SACL2 - xterm-set-ansi-conformance-level-2
3348 * Probably not worth implementing.
3354 static int screen_XTERM_SACL3(term_screen *screen, const term_seq *seq) {
3356 * XTERM_SACL3 - xterm-set-ansi-conformance-level-3
3358 * Probably not worth implementing.
3364 static int screen_XTERM_SDCS(term_screen *screen, const term_seq *seq) {
3366 * XTERM_SDCS - xterm-set-default-character-set
3367 * Select the default character set. We treat this the same as UTF-8 as
3368 * this is our default character set. As we always use UTF-8, this
3375 static int screen_XTERM_SGFX(term_screen *screen, const term_seq *seq) {
3377 * XTERM_SGFX - xterm-sixel-graphics
3379 * Probably not worth implementing.
3385 static int screen_XTERM_SPM(term_screen *screen, const term_seq *seq) {
3387 * XTERM_SPM - xterm-set-private-mode
3389 * Probably not worth implementing.
3395 static int screen_XTERM_SRV(term_screen *screen, const term_seq *seq) {
3397 * XTERM_SRV - xterm-set-resource-value
3399 * Probably not worth implementing.
3405 static int screen_XTERM_STM(term_screen *screen, const term_seq *seq) {
3407 * XTERM_STM - xterm-set-title-mode
3409 * Probably not worth implementing.
3415 static int screen_XTERM_SUCS(term_screen *screen, const term_seq *seq) {
3417 * XTERM_SUCS - xterm-select-utf8-character-set
3418 * Select UTF-8 as character set. This is our default on only character
3419 * set. Hence, this is a no-op.
3425 static int screen_XTERM_WM(term_screen *screen, const term_seq *seq) {
3427 * XTERM_WM - xterm-window-management
3429 * Probably not worth implementing.
3437 * The screen_feed_*() handlers take data from the user and feed it into the
3438 * screen. Once the parser has detected a sequence, we parse the command-type
3439 * and forward it to the command-dispatchers.
3442 static int screen_feed_cmd(term_screen *screen, const term_seq *seq) {
3443 switch (seq->command) {
3444 case TERM_CMD_GRAPHIC:
3445 return screen_GRAPHIC(screen, seq);
3447 return screen_BEL(screen, seq);
3449 return screen_BS(screen, seq);
3451 return screen_CBT(screen, seq);
3453 return screen_CHA(screen, seq);
3455 return screen_CHT(screen, seq);
3457 return screen_CNL(screen, seq);
3459 return screen_CPL(screen, seq);
3461 return screen_CR(screen, seq);
3463 return screen_CUB(screen, seq);
3465 return screen_CUD(screen, seq);
3467 return screen_CUF(screen, seq);
3469 return screen_CUP(screen, seq);
3471 return screen_CUU(screen, seq);
3473 return screen_DA1(screen, seq);
3475 return screen_DA2(screen, seq);
3477 return screen_DA3(screen, seq);
3479 return screen_DC1(screen, seq);
3481 return screen_DC3(screen, seq);
3483 return screen_DCH(screen, seq);
3484 case TERM_CMD_DECALN:
3485 return screen_DECALN(screen, seq);
3486 case TERM_CMD_DECANM:
3487 return screen_DECANM(screen, seq);
3488 case TERM_CMD_DECBI:
3489 return screen_DECBI(screen, seq);
3490 case TERM_CMD_DECCARA:
3491 return screen_DECCARA(screen, seq);
3492 case TERM_CMD_DECCRA:
3493 return screen_DECCRA(screen, seq);
3494 case TERM_CMD_DECDC:
3495 return screen_DECDC(screen, seq);
3496 case TERM_CMD_DECDHL_BH:
3497 return screen_DECDHL_BH(screen, seq);
3498 case TERM_CMD_DECDHL_TH:
3499 return screen_DECDHL_TH(screen, seq);
3500 case TERM_CMD_DECDWL:
3501 return screen_DECDWL(screen, seq);
3502 case TERM_CMD_DECEFR:
3503 return screen_DECEFR(screen, seq);
3504 case TERM_CMD_DECELF:
3505 return screen_DECELF(screen, seq);
3506 case TERM_CMD_DECELR:
3507 return screen_DECELR(screen, seq);
3508 case TERM_CMD_DECERA:
3509 return screen_DECERA(screen, seq);
3510 case TERM_CMD_DECFI:
3511 return screen_DECFI(screen, seq);
3512 case TERM_CMD_DECFRA:
3513 return screen_DECFRA(screen, seq);
3514 case TERM_CMD_DECIC:
3515 return screen_DECIC(screen, seq);
3516 case TERM_CMD_DECID:
3517 return screen_DECID(screen, seq);
3518 case TERM_CMD_DECINVM:
3519 return screen_DECINVM(screen, seq);
3520 case TERM_CMD_DECKBD:
3521 return screen_DECKBD(screen, seq);
3522 case TERM_CMD_DECKPAM:
3523 return screen_DECKPAM(screen, seq);
3524 case TERM_CMD_DECKPNM:
3525 return screen_DECKPNM(screen, seq);
3526 case TERM_CMD_DECLFKC:
3527 return screen_DECLFKC(screen, seq);
3528 case TERM_CMD_DECLL:
3529 return screen_DECLL(screen, seq);
3530 case TERM_CMD_DECLTOD:
3531 return screen_DECLTOD(screen, seq);
3532 case TERM_CMD_DECPCTERM:
3533 return screen_DECPCTERM(screen, seq);
3534 case TERM_CMD_DECPKA:
3535 return screen_DECPKA(screen, seq);
3536 case TERM_CMD_DECPKFMR:
3537 return screen_DECPKFMR(screen, seq);
3538 case TERM_CMD_DECRARA:
3539 return screen_DECRARA(screen, seq);
3540 case TERM_CMD_DECRC:
3541 return screen_DECRC(screen, seq);
3542 case TERM_CMD_DECREQTPARM:
3543 return screen_DECREQTPARM(screen, seq);
3544 case TERM_CMD_DECRPKT:
3545 return screen_DECRPKT(screen, seq);
3546 case TERM_CMD_DECRQCRA:
3547 return screen_DECRQCRA(screen, seq);
3548 case TERM_CMD_DECRQDE:
3549 return screen_DECRQDE(screen, seq);
3550 case TERM_CMD_DECRQKT:
3551 return screen_DECRQKT(screen, seq);
3552 case TERM_CMD_DECRQLP:
3553 return screen_DECRQLP(screen, seq);
3554 case TERM_CMD_DECRQM_ANSI:
3555 return screen_DECRQM_ANSI(screen, seq);
3556 case TERM_CMD_DECRQM_DEC:
3557 return screen_DECRQM_DEC(screen, seq);
3558 case TERM_CMD_DECRQPKFM:
3559 return screen_DECRQPKFM(screen, seq);
3560 case TERM_CMD_DECRQPSR:
3561 return screen_DECRQPSR(screen, seq);
3562 case TERM_CMD_DECRQTSR:
3563 return screen_DECRQTSR(screen, seq);
3564 case TERM_CMD_DECRQUPSS:
3565 return screen_DECRQUPSS(screen, seq);
3566 case TERM_CMD_DECSACE:
3567 return screen_DECSACE(screen, seq);
3568 case TERM_CMD_DECSASD:
3569 return screen_DECSASD(screen, seq);
3570 case TERM_CMD_DECSC:
3571 return screen_DECSC(screen, seq);
3572 case TERM_CMD_DECSCA:
3573 return screen_DECSCA(screen, seq);
3574 case TERM_CMD_DECSCL:
3575 return screen_DECSCL(screen, seq);
3576 case TERM_CMD_DECSCP:
3577 return screen_DECSCP(screen, seq);
3578 case TERM_CMD_DECSCPP:
3579 return screen_DECSCPP(screen, seq);
3580 case TERM_CMD_DECSCS:
3581 return screen_DECSCS(screen, seq);
3582 case TERM_CMD_DECSCUSR:
3583 return screen_DECSCUSR(screen, seq);
3584 case TERM_CMD_DECSDDT:
3585 return screen_DECSDDT(screen, seq);
3586 case TERM_CMD_DECSDPT:
3587 return screen_DECSDPT(screen, seq);
3588 case TERM_CMD_DECSED:
3589 return screen_DECSED(screen, seq);
3590 case TERM_CMD_DECSEL:
3591 return screen_DECSEL(screen, seq);
3592 case TERM_CMD_DECSERA:
3593 return screen_DECSERA(screen, seq);
3594 case TERM_CMD_DECSFC:
3595 return screen_DECSFC(screen, seq);
3596 case TERM_CMD_DECSKCV:
3597 return screen_DECSKCV(screen, seq);
3598 case TERM_CMD_DECSLCK:
3599 return screen_DECSLCK(screen, seq);
3600 case TERM_CMD_DECSLE:
3601 return screen_DECSLE(screen, seq);
3602 case TERM_CMD_DECSLPP:
3603 return screen_DECSLPP(screen, seq);
3604 case TERM_CMD_DECSLRM_OR_SC:
3605 return screen_DECSLRM_OR_SC(screen, seq);
3606 case TERM_CMD_DECSMBV:
3607 return screen_DECSMBV(screen, seq);
3608 case TERM_CMD_DECSMKR:
3609 return screen_DECSMKR(screen, seq);
3610 case TERM_CMD_DECSNLS:
3611 return screen_DECSNLS(screen, seq);
3612 case TERM_CMD_DECSPP:
3613 return screen_DECSPP(screen, seq);
3614 case TERM_CMD_DECSPPCS:
3615 return screen_DECSPPCS(screen, seq);
3616 case TERM_CMD_DECSPRTT:
3617 return screen_DECSPRTT(screen, seq);
3618 case TERM_CMD_DECSR:
3619 return screen_DECSR(screen, seq);
3620 case TERM_CMD_DECSRFR:
3621 return screen_DECSRFR(screen, seq);
3622 case TERM_CMD_DECSSCLS:
3623 return screen_DECSSCLS(screen, seq);
3624 case TERM_CMD_DECSSDT:
3625 return screen_DECSSDT(screen, seq);
3626 case TERM_CMD_DECSSL:
3627 return screen_DECSSL(screen, seq);
3628 case TERM_CMD_DECST8C:
3629 return screen_DECST8C(screen, seq);
3630 case TERM_CMD_DECSTBM:
3631 return screen_DECSTBM(screen, seq);
3632 case TERM_CMD_DECSTR:
3633 return screen_DECSTR(screen, seq);
3634 case TERM_CMD_DECSTRL:
3635 return screen_DECSTRL(screen, seq);
3636 case TERM_CMD_DECSWBV:
3637 return screen_DECSWBV(screen, seq);
3638 case TERM_CMD_DECSWL:
3639 return screen_DECSWL(screen, seq);
3640 case TERM_CMD_DECTID:
3641 return screen_DECTID(screen, seq);
3642 case TERM_CMD_DECTME:
3643 return screen_DECTME(screen, seq);
3644 case TERM_CMD_DECTST:
3645 return screen_DECTST(screen, seq);
3647 return screen_DL(screen, seq);
3648 case TERM_CMD_DSR_ANSI:
3649 return screen_DSR_ANSI(screen, seq);
3650 case TERM_CMD_DSR_DEC:
3651 return screen_DSR_DEC(screen, seq);
3653 return screen_ECH(screen, seq);
3655 return screen_ED(screen, seq);
3657 return screen_EL(screen, seq);
3659 return screen_ENQ(screen, seq);
3661 return screen_EPA(screen, seq);
3663 return screen_FF(screen, seq);
3665 return screen_HPA(screen, seq);
3667 return screen_HPR(screen, seq);
3669 return screen_HT(screen, seq);
3671 return screen_HTS(screen, seq);
3673 return screen_HVP(screen, seq);
3675 return screen_ICH(screen, seq);
3677 return screen_IL(screen, seq);
3679 return screen_IND(screen, seq);
3681 return screen_LF(screen, seq);
3683 return screen_LS1R(screen, seq);
3685 return screen_LS2(screen, seq);
3687 return screen_LS2R(screen, seq);
3689 return screen_LS3(screen, seq);
3691 return screen_LS3R(screen, seq);
3692 case TERM_CMD_MC_ANSI:
3693 return screen_MC_ANSI(screen, seq);
3694 case TERM_CMD_MC_DEC:
3695 return screen_MC_DEC(screen, seq);
3697 return screen_NEL(screen, seq);
3699 return screen_NP(screen, seq);
3701 return screen_NULL(screen, seq);
3703 return screen_PP(screen, seq);
3705 return screen_PPA(screen, seq);
3707 return screen_PPB(screen, seq);
3709 return screen_PPR(screen, seq);
3711 return screen_RC(screen, seq);
3713 return screen_REP(screen, seq);
3715 return screen_RI(screen, seq);
3717 return screen_RIS(screen, seq);
3718 case TERM_CMD_RM_ANSI:
3719 return screen_RM_ANSI(screen, seq);
3720 case TERM_CMD_RM_DEC:
3721 return screen_RM_DEC(screen, seq);
3722 case TERM_CMD_S7C1T:
3723 return screen_S7C1T(screen, seq);
3724 case TERM_CMD_S8C1T:
3725 return screen_S8C1T(screen, seq);
3727 return screen_SCS(screen, seq);
3729 return screen_SD(screen, seq);
3731 return screen_SGR(screen, seq);
3733 return screen_SI(screen, seq);
3734 case TERM_CMD_SM_ANSI:
3735 return screen_SM_ANSI(screen, seq);
3736 case TERM_CMD_SM_DEC:
3737 return screen_SM_DEC(screen, seq);
3739 return screen_SO(screen, seq);
3741 return screen_SPA(screen, seq);
3743 return screen_SS2(screen, seq);
3745 return screen_SS3(screen, seq);
3747 return screen_ST(screen, seq);
3749 return screen_SU(screen, seq);
3751 return screen_SUB(screen, seq);
3753 return screen_TBC(screen, seq);
3755 return screen_VPA(screen, seq);
3757 return screen_VPR(screen, seq);
3759 return screen_VT(screen, seq);
3760 case TERM_CMD_XTERM_CLLHP:
3761 return screen_XTERM_CLLHP(screen, seq);
3762 case TERM_CMD_XTERM_IHMT:
3763 return screen_XTERM_IHMT(screen, seq);
3764 case TERM_CMD_XTERM_MLHP:
3765 return screen_XTERM_MLHP(screen, seq);
3766 case TERM_CMD_XTERM_MUHP:
3767 return screen_XTERM_MUHP(screen, seq);
3768 case TERM_CMD_XTERM_RPM:
3769 return screen_XTERM_RPM(screen, seq);
3770 case TERM_CMD_XTERM_RRV:
3771 return screen_XTERM_RRV(screen, seq);
3772 case TERM_CMD_XTERM_RTM:
3773 return screen_XTERM_RTM(screen, seq);
3774 case TERM_CMD_XTERM_SACL1:
3775 return screen_XTERM_SACL1(screen, seq);
3776 case TERM_CMD_XTERM_SACL2:
3777 return screen_XTERM_SACL2(screen, seq);
3778 case TERM_CMD_XTERM_SACL3:
3779 return screen_XTERM_SACL3(screen, seq);
3780 case TERM_CMD_XTERM_SDCS:
3781 return screen_XTERM_SDCS(screen, seq);
3782 case TERM_CMD_XTERM_SGFX:
3783 return screen_XTERM_SGFX(screen, seq);
3784 case TERM_CMD_XTERM_SPM:
3785 return screen_XTERM_SPM(screen, seq);
3786 case TERM_CMD_XTERM_SRV:
3787 return screen_XTERM_SRV(screen, seq);
3788 case TERM_CMD_XTERM_STM:
3789 return screen_XTERM_STM(screen, seq);
3790 case TERM_CMD_XTERM_SUCS:
3791 return screen_XTERM_SUCS(screen, seq);
3792 case TERM_CMD_XTERM_WM:
3793 return screen_XTERM_WM(screen, seq);
3799 unsigned int term_screen_get_width(term_screen *screen) {
3800 assert_return(screen, -EINVAL);
3802 return screen->page->width;
3805 unsigned int term_screen_get_height(term_screen *screen) {
3806 assert_return(screen, -EINVAL);
3808 return screen->page->height;
3811 uint64_t term_screen_get_age(term_screen *screen) {
3812 assert_return(screen, 0);
3817 int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size) {
3819 size_t i, j, ucs4_len;
3820 const term_seq *seq;
3823 assert_return(screen, -EINVAL);
3827 /* Feed bytes into utf8 decoder and handle parsed ucs4 chars. We always
3828 * treat data as UTF-8, but the parser makes sure to fall back to raw
3829 * 8bit mode if the stream is not valid UTF-8. This should be more than
3830 * enough to support old 7bit/8bit modes. */
3831 for (i = 0; i < size; ++i) {
3832 ucs4_len = term_utf8_decode(&screen->utf8, &ucs4_str, in[i]);
3833 for (j = 0; j < ucs4_len; ++j) {
3834 r = term_parser_feed(screen->parser, &seq, ucs4_str[j]);
3837 } else if (r != TERM_SEQ_NONE) {
3838 r = screen_feed_cmd(screen, seq);
3848 static char *screen_map_key(term_screen *screen,
3850 const uint32_t *keysyms,
3853 const uint32_t *ucs4,
3854 unsigned int mods) {
3855 char ch, ch2, ch_mods;
3859 /* TODO: All these key-mappings need to be verified. Public information
3860 * on those mappings is pretty scarce and every emulator seems to do it
3861 * slightly differently.
3862 * A lot of mappings are also missing. */
3870 v = XKB_KEY_NoSymbol;
3872 /* In some mappings, the modifiers are encoded as CSI parameters. The
3873 * encoding is rather arbitrary, but seems to work. */
3875 switch (mods & (TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT | TERM_KBDMOD_CTRL)) {
3876 case TERM_KBDMOD_SHIFT:
3879 case TERM_KBDMOD_ALT:
3882 case TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT:
3885 case TERM_KBDMOD_CTRL:
3888 case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT:
3891 case TERM_KBDMOD_CTRL | TERM_KBDMOD_ALT:
3894 case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT:
3899 /* A user might actually use multiple layouts for keyboard
3900 * input. @keysyms[0] contains the actual keysym that the user
3901 * used. But if this keysym is not in the ascii range, the
3902 * input handler does check all other layouts that the user
3903 * specified whether one of them maps the key to some ASCII
3904 * keysym and provides this via @ascii. We always use the real
3905 * keysym except when handling CTRL+<XY> shortcuts we use the
3906 * ascii keysym. This is for compatibility to xterm et. al. so
3907 * ctrl+c always works regardless of the currently active
3908 * keyboard layout. But if no ascii-sym is found, we still use
3909 * the real keysym. */
3910 if (ascii == XKB_KEY_NoSymbol)
3913 /* map CTRL+<ascii> */
3914 if (mods & TERM_KBDMOD_CTRL) {
3917 /* Right hand side is mapped to the left and then
3918 * treated equally. Fall through to left-hand side.. */
3921 /* Printable ASCII is mapped 1-1 in XKB and in
3922 * combination with CTRL bit 7 is flipped. This
3923 * is equivalent to the caret-notation. */
3924 *p++ = ascii ^ 0x40;
3929 /* map cursor keys */
3953 if (screen->flags & TERM_FLAG_CURSOR_KEYS)
3966 /* map action keys */
3972 case XKB_KEY_Insert:
3975 case XKB_KEY_Delete:
3978 case XKB_KEY_Select:
3981 case XKB_KEY_Page_Up:
3984 case XKB_KEY_Page_Down:
4000 /* map lower function keys */
4033 /* map upper function keys */
4084 /* map special keys */
4086 case 0xff08: /* XKB_KEY_BackSpace */
4087 case 0xff09: /* XKB_KEY_Tab */
4088 case 0xff0a: /* XKB_KEY_Linefeed */
4089 case 0xff0b: /* XKB_KEY_Clear */
4090 case 0xff15: /* XKB_KEY_Sys_Req */
4091 case 0xff1b: /* XKB_KEY_Escape */
4092 case 0xffff: /* XKB_KEY_Delete */
4095 case 0xff13: /* XKB_KEY_Pause */
4096 /* TODO: What should we do with this key?
4097 * Sending XOFF is awful as there is no simple
4098 * way on modern keyboards to send XON again.
4099 * If someone wants this, we can re-eanble
4102 case 0xff14: /* XKB_KEY_Scroll_Lock */
4103 /* TODO: What should we do on scroll-lock?
4104 * Sending 0x14 is what the specs say but it is
4105 * not used today the way most users would
4106 * expect so we disable it. If someone wants
4107 * this, we can re-enable it (optionally). */
4109 case XKB_KEY_Return:
4111 if (screen->flags & TERM_FLAG_NEWLINE_MODE)
4114 case XKB_KEY_ISO_Left_Tab:
4119 /* map unicode keys */
4120 for (i = 0; i < n_syms; ++i)
4121 p += term_utf8_encode(p, ucs4[i]);
4126 int term_screen_feed_keyboard(term_screen *screen,
4127 const uint32_t *keysyms,
4130 const uint32_t *ucs4,
4131 unsigned int mods) {
4132 _cleanup_free_ char *dyn = NULL;
4133 static const size_t padding = 1;
4134 char buf[128], *start, *p;
4136 assert_return(screen, -EINVAL);
4138 /* allocate buffer if too small */
4140 if (4 * n_syms + padding > sizeof(buf)) {
4141 dyn = malloc(4 * n_syms + padding);
4148 /* reserve prefix space */
4152 p = screen_map_key(screen, p, keysyms, n_syms, ascii, ucs4, mods);
4153 if (!p || p - start < 1)
4156 /* The ALT modifier causes ESC to be prepended to any key-stroke. We
4157 * already accounted for that buffer space above, so simply prepend it
4159 * TODO: is altSendsEscape a suitable default? What are the semantics
4160 * exactly? Is it used in C0/C1 conversion? Is it prepended if there
4161 * already is an escape character? */
4162 if (mods & TERM_KBDMOD_ALT && *start != 0x1b)
4165 /* turn C0 into C1 */
4166 if (!(screen->flags & TERM_FLAG_7BIT_MODE) && p - start >= 2)
4167 if (start[0] == 0x1b && start[1] >= 0x40 && start[1] <= 0x5f)
4170 return screen_write(screen, start, p - start);
4173 int term_screen_resize(term_screen *screen, unsigned int x, unsigned int y) {
4178 assert_return(screen, -EINVAL);
4180 r = term_page_reserve(screen->page_main, x, y, &screen->state.attr, screen->age);
4184 r = term_page_reserve(screen->page_alt, x, y, &screen->state.attr, screen->age);
4188 if (x > screen->n_tabs) {
4189 t = realloc(screen->tabs, (x + 7) / 8);
4197 for (i = (screen->page->width + 7) / 8 * 8; i < x; i += 8)
4198 screen->tabs[i / 8] = 0x1;
4200 term_page_resize(screen->page_main, x, y, &screen->state.attr, screen->age, screen->history);
4201 term_page_resize(screen->page_alt, x, y, &screen->state.attr, screen->age, NULL);
4203 screen->state.cursor_x = screen_clamp_x(screen, screen->state.cursor_x);
4204 screen->state.cursor_y = screen_clamp_x(screen, screen->state.cursor_y);
4205 screen_cursor_clear_wrap(screen);
4210 void term_screen_soft_reset(term_screen *screen) {
4215 screen->g0 = &term_unicode_lower;
4216 screen->g1 = &term_unicode_upper;
4217 screen->g2 = &term_unicode_lower;
4218 screen->g3 = &term_unicode_upper;
4219 screen->state.attr = screen->default_attr;
4220 screen->state.gl = &screen->g0;
4221 screen->state.gr = &screen->g1;
4222 screen->state.glt = NULL;
4223 screen->state.grt = NULL;
4224 screen->state.auto_wrap = 0;
4225 screen->state.origin_mode = 0;
4227 screen->saved = screen->state;
4228 screen->saved.cursor_x = 0;
4229 screen->saved.cursor_y = 0;
4230 screen->saved_alt = screen->saved;
4232 screen->page = screen->page_main;
4233 screen->history = screen->history_main;
4234 screen->flags = TERM_FLAG_7BIT_MODE;
4235 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
4237 for (i = 0; i < screen->page->width; i += 8)
4238 screen->tabs[i / 8] = 0x1;
4240 term_page_set_scroll_region(screen->page_main, 0, screen->page->height);
4241 term_page_set_scroll_region(screen->page_alt, 0, screen->page->height);
4244 void term_screen_hard_reset(term_screen *screen) {
4247 term_screen_soft_reset(screen);
4249 screen->state.cursor_x = 0;
4250 screen->state.cursor_y = 0;
4251 term_page_erase(screen->page_main, 0, 0, screen->page->width, screen->page->height, &screen->state.attr, screen->age, false);
4252 term_page_erase(screen->page_alt, 0, 0, screen->page->width, screen->page->height, &screen->state.attr, screen->age, false);
4255 int term_screen_set_answerback(term_screen *screen, const char *answerback) {
4258 assert_return(screen, -EINVAL);
4261 t = strdup(answerback);
4266 free(screen->answerback);
4267 screen->answerback = t;
4272 int term_screen_draw(term_screen *screen,
4273 int (*draw_fn) (term_screen *screen,
4277 const term_attr *attr,
4280 unsigned int ch_width),
4283 uint64_t cell_age, line_age, age = 0;
4284 term_charbuf_t ch_buf;
4285 const uint32_t *ch_str;
4286 unsigned int i, j, cw;
4299 page = screen->page;
4301 for (j = 0; j < page->height; ++j) {
4302 line = page->lines[j];
4303 line_age = MAX(line->age, page->age);
4305 for (i = 0; i < page->width; ++i) {
4308 cell = &line->cells[i];
4309 cell_age = MAX(cell->age, line_age);
4311 if (age != 0 && cell_age <= age)
4314 ch_str = term_char_resolve(cell->ch, &ch_n, &ch_buf);
4316 /* Character-width of 0 is used for cleared cells.
4317 * Always treat this as single-cell character, so
4318 * renderers can assume ch_width is set properpy. */
4319 cw = MAX(cell->cwidth, 1U);
4322 if (i == screen->state.cursor_x && j == screen->state.cursor_y &&
4323 !(screen->flags & TERM_FLAG_HIDE_CURSOR))
4340 *fb_age = screen->age;