1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 * The term_screen layer implements the terminal-side. It handles all commands
25 * returned by the seq-parser and applies them to its own pages.
27 * While there are a lot of legacy control-sequences, we only support a small
28 * subset. There is no reason to implement unused codes like horizontal
30 * If you implement new commands, make sure to document them properly.
37 * http://www.vt100.net/emu/ctrlseq_dec.html
38 * http://www.vt100.net/docs/vt100-ug/chapter3.html
39 * http://www.vt100.net/docs/vt510-rm/chapter4
40 * http://www.vt100.net/docs/vt510-rm/contents
41 * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
43 * http://en.wikipedia.org/wiki/C0_and_C1_control_codes
44 * https://en.wikipedia.org/wiki/ANSI_color
50 #include <xkbcommon/xkbcommon-keysyms.h>
52 #include "term-internal.h"
55 int term_screen_new(term_screen **out, term_screen_write_fn write_fn, void *write_fn_data, term_screen_cmd_fn cmd_fn, void *cmd_fn_data) {
56 _cleanup_(term_screen_unrefp) term_screen *screen = NULL;
59 assert_return(out, -EINVAL);
61 screen = new0(term_screen, 1);
67 screen->write_fn = write_fn;
68 screen->write_fn_data = write_fn_data;
69 screen->cmd_fn = cmd_fn;
70 screen->cmd_fn_data = cmd_fn_data;
71 screen->flags = TERM_FLAG_7BIT_MODE;
72 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
73 screen->g0 = &term_unicode_lower;
74 screen->g1 = &term_unicode_upper;
75 screen->g2 = &term_unicode_lower;
76 screen->g3 = &term_unicode_upper;
77 screen->state.gl = &screen->g0;
78 screen->state.gr = &screen->g1;
79 screen->saved = screen->state;
80 screen->saved_alt = screen->saved;
82 r = term_page_new(&screen->page_main);
86 r = term_page_new(&screen->page_alt);
90 r = term_parser_new(&screen->parser, false);
94 r = term_history_new(&screen->history_main);
98 screen->page = screen->page_main;
99 screen->history = screen->history_main;
106 term_screen *term_screen_ref(term_screen *screen) {
110 assert_return(screen->ref > 0, NULL);
116 term_screen *term_screen_unref(term_screen *screen) {
120 assert_return(screen->ref > 0, NULL);
125 free(screen->answerback);
127 term_history_free(screen->history_main);
128 term_page_free(screen->page_alt);
129 term_page_free(screen->page_main);
130 term_parser_free(screen->parser);
138 * Unfortunately, 7bit/8bit compat mode requires us to send C1 controls encoded
139 * as 7bit if asked by the application. This is really used in the wild, so we
140 * cannot fall back to "always 7bit".
141 * screen_write() is the underlying backend which forwards any writes to the
142 * users's callback. It's the users responsibility to buffer these and write
143 * them out once their call to term_screen_feed_*() returns.
144 * The SEQ_WRITE() and SEQ_WRITE_KEY() macros allow constructing C0/C1 sequences
145 * directly in the code-base without requiring any intermediate buffer during
150 #define C1_CSI "\x9b"
152 #define SEQ(_screen, _prefix_esc, _c0, _c1, _seq) \
153 (((_screen)->flags & TERM_FLAG_7BIT_MODE) ? \
154 ((_prefix_esc) ? ("\e" _c0 _seq) : (_c0 _seq)) : \
155 ((_prefix_esc) ? ("\e" _c1 _seq) : (_c1 _seq)))
157 #define SEQ_SIZE(_screen, _prefix_esc, _c0, _c1, _seq) \
158 (((_screen)->flags & TERM_FLAG_7BIT_MODE) ? \
159 ((_prefix_esc) ? sizeof("\e" _c0 _seq) : sizeof(_c0 _seq)) : \
160 ((_prefix_esc) ? sizeof("\e" _c1 _seq) : sizeof(_c1 _seq)))
162 #define SEQ_WRITE_KEY(_screen, _prefix_esc, _c0, _c1, _seq) \
163 screen_write((_screen), \
164 SEQ((_screen), (_prefix_esc), \
166 SEQ_SIZE((_screen), (_prefix_esc), \
169 #define SEQ_WRITE(_screen, _c0, _c1, _seq) \
170 SEQ_WRITE_KEY((_screen), false, _c0, _c1, _seq)
172 static int screen_write(term_screen *screen, const void *buf, size_t len) {
173 if (len < 1 || !screen->write_fn)
176 return screen->write_fn(screen, screen->write_fn_data, buf, len);
181 * Some commands cannot be handled by the screen-layer directly. Those are
182 * forwarded to the command-handler of the caller. This is rarely used and can
183 * safely be set to NULL.
186 static int screen_forward(term_screen *screen, unsigned int cmd, const term_seq *seq) {
190 return screen->cmd_fn(screen, screen->cmd_fn_data, cmd, seq);
195 * These helpers implement common-operations like cursor-handler and more, which
196 * are used by several command dispatchers.
199 static unsigned int screen_clamp_x(term_screen *screen, unsigned int x) {
200 if (x >= screen->page->width)
201 return (screen->page->width > 0) ? screen->page->width - 1 : 0;
206 static unsigned int screen_clamp_y(term_screen *screen, unsigned int y) {
207 if (y >= screen->page->height)
208 return (screen->page->height > 0) ? screen->page->height - 1 : 0;
213 static bool screen_tab_is_set(term_screen *screen, unsigned int pos) {
214 if (pos >= screen->page->width)
217 return screen->tabs[pos / 8] & (1 << (pos % 8));
220 static inline void screen_age_cursor(term_screen *screen) {
223 cell = term_page_get_cell(screen->page, screen->state.cursor_x, screen->state.cursor_y);
225 cell->age = screen->age;
228 static void screen_cursor_clear_wrap(term_screen *screen) {
229 screen->flags &= ~TERM_FLAG_PENDING_WRAP;
232 static void screen_cursor_set(term_screen *screen, unsigned int x, unsigned int y) {
233 x = screen_clamp_x(screen, x);
234 y = screen_clamp_y(screen, y);
236 if (x == screen->state.cursor_x && y == screen->state.cursor_y)
239 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
240 screen_age_cursor(screen);
242 screen->state.cursor_x = x;
243 screen->state.cursor_y = y;
245 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
246 screen_age_cursor(screen);
249 static void screen_cursor_set_rel(term_screen *screen, unsigned int x, unsigned int y) {
250 if (screen->state.origin_mode) {
251 x = screen_clamp_x(screen, x);
252 y = screen_clamp_x(screen, y) + screen->page->scroll_idx;
254 if (y >= screen->page->scroll_idx + screen->page->scroll_num) {
255 y = screen->page->scroll_idx + screen->page->scroll_num;
256 if (screen->page->scroll_num > 0)
261 screen_cursor_set(screen, x, y);
264 static void screen_cursor_left(term_screen *screen, unsigned int num) {
265 if (num > screen->state.cursor_x)
266 num = screen->state.cursor_x;
268 screen_cursor_set(screen, screen->state.cursor_x - num, screen->state.cursor_y);
271 static void screen_cursor_left_tab(term_screen *screen, unsigned int num) {
274 i = screen->state.cursor_x;
275 while (i > 0 && num > 0) {
276 if (screen_tab_is_set(screen, --i))
280 screen_cursor_set(screen, i, screen->state.cursor_y);
283 static void screen_cursor_right(term_screen *screen, unsigned int num) {
284 if (num > screen->page->width)
285 num = screen->page->width;
287 screen_cursor_set(screen, screen->state.cursor_x + num, screen->state.cursor_y);
290 static void screen_cursor_right_tab(term_screen *screen, unsigned int num) {
293 i = screen->state.cursor_x;
294 while (i + 1 < screen->page->width && num > 0) {
295 if (screen_tab_is_set(screen, ++i))
299 screen_cursor_set(screen, i, screen->state.cursor_y);
302 static void screen_cursor_up(term_screen *screen, unsigned int num, bool scroll) {
305 if (screen->state.cursor_y < screen->page->scroll_idx) {
306 if (num > screen->state.cursor_y)
307 num = screen->state.cursor_y;
309 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num);
311 max = screen->state.cursor_y - screen->page->scroll_idx;
316 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
317 screen_age_cursor(screen);
320 term_page_scroll_down(screen->page, num - max, &screen->state.attr, screen->age, NULL);
322 screen->state.cursor_y = screen->page->scroll_idx;
324 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
325 screen_age_cursor(screen);
327 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num);
332 static void screen_cursor_down(term_screen *screen, unsigned int num, bool scroll) {
335 if (screen->state.cursor_y >= screen->page->scroll_idx + screen->page->scroll_num) {
336 if (num > screen->page->height)
337 num = screen->page->height;
339 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num);
341 max = screen->page->scroll_idx + screen->page->scroll_num - 1 - screen->state.cursor_y;
346 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
347 screen_age_cursor(screen);
350 term_page_scroll_up(screen->page, num - max, &screen->state.attr, screen->age, screen->history);
352 screen->state.cursor_y = screen->page->scroll_idx + screen->page->scroll_num - 1;
354 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
355 screen_age_cursor(screen);
357 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y + num);
362 static void screen_save_state(term_screen *screen, term_state *where) {
363 *where = screen->state;
366 static void screen_restore_state(term_screen *screen, term_state *from) {
367 screen_cursor_set(screen, from->cursor_x, from->cursor_y);
368 screen->state = *from;
371 static void screen_reset_page(term_screen *screen, term_page *page) {
372 term_page_set_scroll_region(page, 0, page->height);
373 term_page_erase(page, 0, 0, page->width, page->height, &screen->state.attr, screen->age, false);
376 static void screen_change_alt(term_screen *screen, bool set) {
378 screen->page = screen->page_alt;
379 screen->history = NULL;
381 screen->page = screen->page_main;
382 screen->history = screen->history_main;
385 screen->page->age = screen->age;
388 static inline void set_reset(term_screen *screen, unsigned int flag, bool set) {
390 screen->flags |= flag;
392 screen->flags &= ~flag;
395 static void screen_mode_change_ansi(term_screen *screen, unsigned mode, bool set) {
399 * LNM: line-feed/new-line mode
402 set_reset(screen, TERM_FLAG_NEWLINE_MODE, set);
408 static void screen_mode_change_dec(term_screen *screen, unsigned int mode, bool set) {
412 * DECCKM: cursor-keys
415 set_reset(screen, TERM_FLAG_CURSOR_KEYS, set);
423 screen->state.origin_mode = set;
428 * DECAWN: auto-wrap mode
431 screen->state.auto_wrap = set;
436 * DECTCEM: text-cursor-enable
439 set_reset(screen, TERM_FLAG_HIDE_CURSOR, !set);
440 screen_age_cursor(screen);
445 * XTERM-ASB: alternate-screen-buffer
446 * This enables/disables the alternate screen-buffer.
447 * It effectively saves the current page content and
448 * allows you to restore it when changing to the
449 * original screen-buffer again.
451 screen_change_alt(screen, set);
456 * XTERM-ASBPE: alternate-screen-buffer-post-erase
457 * This is the same as XTERM-ASB but erases the
458 * alternate screen-buffer before switching back to the
459 * original buffer. Use it to discard any data on the
460 * alternate screen buffer when done.
463 screen_reset_page(screen, screen->page_alt);
465 screen_change_alt(screen, set);
470 * XTERM-ASBCS: alternate-screen-buffer-cursor-state
471 * This has the same effect as DECSC/DECRC, but uses a
472 * separate state buffer. It is usually used in
473 * combination with alternate screen buffers to provide
474 * stacked state storage.
477 screen_save_state(screen, &screen->saved_alt);
479 screen_restore_state(screen, &screen->saved_alt);
484 * XTERM-ASBX: alternate-screen-buffer-extended
485 * This combines XTERM-ASBPE and XTERM-ASBCS somewhat.
486 * When enabling, state is saved, alternate screen
487 * buffer is activated and cleared.
488 * When disabled, alternate screen buffer is cleared,
489 * then normal screen buffer is enabled and state is
493 screen_save_state(screen, &screen->saved_alt);
495 screen_reset_page(screen, screen->page_alt);
496 screen_change_alt(screen, set);
499 screen_restore_state(screen, &screen->saved_alt);
505 /* map a character according to current GL and GR maps */
506 static uint32_t screen_map(term_screen *screen, uint32_t val) {
509 /* 32 and 127 always map to identity. 160 and 255 map to identity iff a
510 * 96 character set is loaded into GR. Values above 255 always map to
514 if (screen->state.glt) {
515 nval = (**screen->state.glt)[val - 32];
516 screen->state.glt = NULL;
518 nval = (**screen->state.gl)[val - 32];
522 if (screen->state.grt) {
523 nval = (**screen->state.grt)[val - 160];
524 screen->state.grt = NULL;
526 nval = (**screen->state.gr)[val - 160];
531 return (nval == -1U) ? val : nval;
536 * This is the unofficial documentation of all the TERM_CMD_* definitions. Each
537 * handled command has a separate function with an extensive comment on the
538 * semantics of the command.
539 * Note that many semantics are unknown and need to be verified. This is mostly
540 * about error-handling, though. Applications rarely rely on those features.
543 static int screen_DA1(term_screen *screen, const term_seq *seq);
544 static int screen_LF(term_screen *screen, const term_seq *seq);
546 static int screen_GRAPHIC(term_screen *screen, const term_seq *seq) {
547 term_char_t ch = TERM_CHAR_NULL;
550 if (screen->state.cursor_x + 1 == screen->page->width
551 && screen->flags & TERM_FLAG_PENDING_WRAP
552 && screen->state.auto_wrap) {
553 screen_cursor_down(screen, 1, true);
554 screen_cursor_set(screen, 0, screen->state.cursor_y);
557 screen_cursor_clear_wrap(screen);
559 c = screen_map(screen, seq->terminator);
560 ch = term_char_merge(ch, screen_map(screen, c));
561 term_page_write(screen->page, screen->state.cursor_x, screen->state.cursor_y, ch, 1, &screen->state.attr, screen->age, false);
563 if (screen->state.cursor_x + 1 == screen->page->width)
564 screen->flags |= TERM_FLAG_PENDING_WRAP;
566 screen_cursor_right(screen, 1);
571 static int screen_BEL(term_screen *screen, const term_seq *seq) {
573 * BEL - sound bell tone
574 * This command should trigger an acoustic bell. Usually, this is
575 * forwarded directly to the pcspkr. However, bells have become quite
576 * uncommon and annoying, so we're not implementing them here. Instead,
577 * it's one of the commands we forward to the caller.
580 return screen_forward(screen, TERM_CMD_BEL, seq);
583 static int screen_BS(term_screen *screen, const term_seq *seq) {
586 * Move cursor one cell to the left. If already at the left margin,
590 screen_cursor_clear_wrap(screen);
591 screen_cursor_left(screen, 1);
595 static int screen_CBT(term_screen *screen, const term_seq *seq) {
597 * CBT - cursor-backward-tabulation
598 * Move the cursor @args[0] tabs backwards (to the left). The
599 * current cursor cell, in case it's a tab, is not counted.
600 * Furthermore, the cursor cannot be moved beyond position 0 and
601 * it will stop there.
607 unsigned int num = 1;
609 if (seq->args[0] > 0)
612 screen_cursor_clear_wrap(screen);
613 screen_cursor_left_tab(screen, num);
618 static int screen_CHA(term_screen *screen, const term_seq *seq) {
620 * CHA - cursor-horizontal-absolute
621 * Move the cursor to position @args[0] in the current line. The
622 * cursor cannot be moved beyond the rightmost cell and will stop
629 unsigned int pos = 1;
631 if (seq->args[0] > 0)
634 screen_cursor_clear_wrap(screen);
635 screen_cursor_set(screen, pos - 1, screen->state.cursor_y);
640 static int screen_CHT(term_screen *screen, const term_seq *seq) {
642 * CHT - cursor-horizontal-forward-tabulation
643 * Move the cursor @args[0] tabs forward (to the right). The
644 * current cursor cell, in case it's a tab, is not counted.
645 * Furthermore, the cursor cannot be moved beyond the rightmost cell
646 * and will stop there.
652 unsigned int num = 1;
654 if (seq->args[0] > 0)
657 screen_cursor_clear_wrap(screen);
658 screen_cursor_right_tab(screen, num);
663 static int screen_CNL(term_screen *screen, const term_seq *seq) {
665 * CNL - cursor-next-line
666 * Move the cursor @args[0] lines down.
668 * TODO: Does this stop at the bottom or cause a scroll-up?
674 unsigned int num = 1;
676 if (seq->args[0] > 0)
679 screen_cursor_clear_wrap(screen);
680 screen_cursor_down(screen, num, false);
685 static int screen_CPL(term_screen *screen, const term_seq *seq) {
687 * CPL - cursor-preceding-line
688 * Move the cursor @args[0] lines up.
690 * TODO: Does this stop at the top or cause a scroll-up?
696 unsigned int num = 1;
698 if (seq->args[0] > 0)
701 screen_cursor_clear_wrap(screen);
702 screen_cursor_up(screen, num, false);
707 static int screen_CR(term_screen *screen, const term_seq *seq) {
709 * CR - carriage-return
710 * Move the cursor to the left margin on the current line.
713 screen_cursor_clear_wrap(screen);
714 screen_cursor_set(screen, 0, screen->state.cursor_y);
719 static int screen_CUB(term_screen *screen, const term_seq *seq) {
721 * CUB - cursor-backward
722 * Move the cursor @args[0] positions to the left. The cursor stops
723 * at the left-most position.
729 unsigned int num = 1;
731 if (seq->args[0] > 0)
734 screen_cursor_clear_wrap(screen);
735 screen_cursor_left(screen, num);
740 static int screen_CUD(term_screen *screen, const term_seq *seq) {
743 * Move the cursor @args[0] positions down. The cursor stops at the
744 * bottom margin. If it was already moved further, it stops at the
751 unsigned int num = 1;
753 if (seq->args[0] > 0)
756 screen_cursor_clear_wrap(screen);
757 screen_cursor_down(screen, num, false);
762 static int screen_CUF(term_screen *screen, const term_seq *seq) {
764 * CUF -cursor-forward
765 * Move the cursor @args[0] positions to the right. The cursor stops
766 * at the right-most position.
772 unsigned int num = 1;
774 if (seq->args[0] > 0)
777 screen_cursor_clear_wrap(screen);
778 screen_cursor_right(screen, num);
783 static int screen_CUP(term_screen *screen, const term_seq *seq) {
785 * CUP - cursor-position
786 * Moves the cursor to position @args[1] x @args[0]. If either is 0, it
787 * is treated as 1. The positions are subject to the origin-mode and
788 * clamped to the addressable with/height.
795 unsigned int x = 1, y = 1;
797 if (seq->args[0] > 0)
799 if (seq->args[1] > 0)
802 screen_cursor_clear_wrap(screen);
803 screen_cursor_set_rel(screen, x - 1, y - 1);
808 static int screen_CUU(term_screen *screen, const term_seq *seq) {
811 * Move the cursor @args[0] positions up. The cursor stops at the
812 * top margin. If it was already moved further, it stops at the
820 unsigned int num = 1;
822 if (seq->args[0] > 0)
825 screen_cursor_clear_wrap(screen);
826 screen_cursor_up(screen, num, false);
831 static int screen_DA1(term_screen *screen, const term_seq *seq) {
833 * DA1 - primary-device-attributes
834 * The primary DA asks for basic terminal features. We simply return
835 * a hard-coded list of features we implement.
836 * Note that the primary DA asks for supported features, not currently
839 * The terminal's answer is:
841 * The first argument, 64, is fixed and denotes a VT420, the last
842 * DEC-term that extended this number.
843 * All following arguments denote supported features. Note
844 * that at most 15 features can be sent (max CSI args). It is safe to
845 * send more, but clients might not be able to parse them. This is a
846 * client's problem and we shouldn't care. There is no other way to
847 * send those feature lists, so we have to extend them beyond 15 in
852 * The 132 column mode is supported by the terminal.
854 * A priner-port is supported and can be addressed via
857 * Support for ReGIS graphics is available. The ReGIS routines
858 * provide the "remote graphics instruction set" and allow basic
861 * Support of Sixel graphics is available. This provides access
862 * to the sixel bitmap routines.
864 * The terminal supports DECSCA and related selective-erase
865 * functions. This allows to protect specific cells from being
866 * erased, if specified.
867 * 7: soft character set (DRCS)
869 * 8: user-defined keys (UDKs)
871 * 9: national-replacement character sets (NRCS)
872 * National-replacement character-sets are available.
873 * 12: Yugoslavian (SCS)
875 * 15: technical character set
876 * The DEC technical-character-set is available.
877 * 18: windowing capability
879 * 21: horizontal scrolling
887 * 29: ANSI text locator
889 * 42: ISO Latin-2 character set
895 * 46: ASCII emulation
899 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "?64;1;6;9;15c");
902 static int screen_DA2(term_screen *screen, const term_seq *seq) {
904 * DA2 - secondary-device-attributes
905 * The secondary DA asks for the terminal-ID, firmware versions and
906 * other non-primary attributes. All these values are
907 * informational-only and should not be used by the host to detect
910 * The terminal's response is:
911 * ^[ > 61 ; FIRMWARE ; KEYBOARD c
912 * whereas 65 is fixed for VT525 terminals, the last terminal-line that
913 * increased this number. FIRMWARE is the firmware
914 * version encoded as major/minor (20 == 2.0) and KEYBOARD is 0 for STD
915 * keyboard and 1 for PC keyboards.
917 * We replace the firmware-version with the systemd-version so clients
918 * can decode it again.
921 return SEQ_WRITE(screen, C0_CSI, C1_CSI, ">65;" PACKAGE_VERSION ";1c");
924 static int screen_DA3(term_screen *screen, const term_seq *seq) {
926 * DA3 - tertiary-device-attributes
927 * The tertiary DA is used to query the terminal-ID.
929 * The terminal's response is:
930 * ^P ! | XX AA BB CC ^\
931 * whereas all four parameters are hexadecimal-encoded pairs. XX
932 * denotes the manufacturing site, AA BB CC is the terminal's ID.
935 /* we do not support tertiary DAs */
939 static int screen_DC1(term_screen *screen, const term_seq *seq) {
941 * DC1 - device-control-1 or XON
942 * This clears any previous XOFF and resumes terminal-transmission.
945 /* we do not support XON */
949 static int screen_DC3(term_screen *screen, const term_seq *seq) {
951 * DC3 - device-control-3 or XOFF
952 * Stops terminal transmission. No further characters are sent until
953 * an XON is received.
956 /* we do not support XOFF */
960 static int screen_DCH(term_screen *screen, const term_seq *seq) {
962 * DCH - delete-character
963 * This deletes @argv[0] characters at the current cursor position. As
964 * characters are deleted, the remaining characters between the cursor
965 * and right margin move to the left. Character attributes move with the
966 * characters. The terminal adds blank spaces with no visual character
967 * attributes at the right margin. DCH has no effect outside the
974 unsigned int num = 1;
976 if (seq->args[0] > 0)
979 screen_cursor_clear_wrap(screen);
980 term_page_delete_cells(screen->page, screen->state.cursor_x, screen->state.cursor_y, num, &screen->state.attr, screen->age);
985 static int screen_DECALN(term_screen *screen, const term_seq *seq) {
987 * DECALN - screen-alignment-pattern
989 * Probably not worth implementing.
995 static int screen_DECANM(term_screen *screen, const term_seq *seq) {
998 * Set the terminal into VT52 compatibility mode. Control sequences
999 * overlap with regular sequences so we have to detect them early before
1002 * Probably not worth implementing.
1008 static int screen_DECBI(term_screen *screen, const term_seq *seq) {
1010 * DECBI - back-index
1011 * This control function moves the cursor backward one column. If the
1012 * cursor is at the left margin, then all screen data within the margin
1013 * moves one column to the right. The column that shifted past the right
1015 * DECBI adds a new column at the left margin with no visual attributes.
1016 * DECBI does not affect the margins. If the cursor is beyond the
1017 * left-margin at the left border, then the terminal ignores DECBI.
1019 * Probably not worth implementing.
1025 static int screen_DECCARA(term_screen *screen, const term_seq *seq) {
1027 * DECCARA - change-attributes-in-rectangular-area
1029 * Probably not worth implementing.
1035 static int screen_DECCRA(term_screen *screen, const term_seq *seq) {
1037 * DECCRA - copy-rectangular-area
1039 * Probably not worth implementing.
1045 static int screen_DECDC(term_screen *screen, const term_seq *seq) {
1047 * DECDC - delete-column
1049 * Probably not worth implementing.
1055 static int screen_DECDHL_BH(term_screen *screen, const term_seq *seq) {
1057 * DECDHL_BH - double-width-double-height-line: bottom half
1059 * Probably not worth implementing.
1065 static int screen_DECDHL_TH(term_screen *screen, const term_seq *seq) {
1067 * DECDHL_TH - double-width-double-height-line: top half
1069 * Probably not worth implementing.
1075 static int screen_DECDWL(term_screen *screen, const term_seq *seq) {
1077 * DECDWL - double-width-single-height-line
1079 * Probably not worth implementing.
1085 static int screen_DECEFR(term_screen *screen, const term_seq *seq) {
1087 * DECEFR - enable-filter-rectangle
1088 * Defines the coordinates of a filter rectangle (top, left, bottom,
1089 * right as @args[0] to @args[3]) and activates it.
1090 * Anytime the locator is detected outside of the filter rectangle, an
1091 * outside rectangle event is generated and the rectangle is disabled.
1092 * Filter rectangles are always treated as "one-shot" events. Any
1093 * parameters that are omitted default to the current locator position.
1094 * If all parameters are omitted, any locator motion will be reported.
1095 * DECELR always cancels any prevous rectangle definition.
1097 * The locator is usually associated with the mouse-cursor, but based
1098 * on cells instead of pixels. See DECELR how to initialize and enable
1099 * it. DECELR can also enable pixel-mode instead of cell-mode.
1107 static int screen_DECELF(term_screen *screen, const term_seq *seq) {
1109 * DECELF - enable-local-functions
1111 * Probably not worth implementing.
1117 static int screen_DECELR(term_screen *screen, const term_seq *seq) {
1119 * DECELR - enable-locator-reporting
1120 * This changes the locator-reporting mode. @args[0] specifies the mode
1121 * to set, 0 disables locator-reporting, 1 enables it continuously, 2
1122 * enables it for a single report. @args[1] specifies the
1123 * precision-mode. 0 and 2 set the reporting to cell-precision, 1 sets
1136 static int screen_DECERA(term_screen *screen, const term_seq *seq) {
1138 * DECERA - erase-rectangular-area
1140 * Probably not worth implementing.
1146 static int screen_DECFI(term_screen *screen, const term_seq *seq) {
1148 * DECFI - forward-index
1149 * This control function moves the cursor forward one column. If the
1150 * cursor is at the right margin, then all screen data within the
1151 * margins moves one column to the left. The column shifted past the
1152 * left margin is lost.
1153 * DECFI adds a new column at the right margin, with no visual
1154 * attributes. DECFI does not affect margins. If the cursor is beyond
1155 * the right margin at the border of the page when the terminal
1156 * receives DECFI, then the terminal ignores DECFI.
1158 * Probably not worth implementing.
1164 static int screen_DECFRA(term_screen *screen, const term_seq *seq) {
1166 * DECFRA - fill-rectangular-area
1168 * Probably not worth implementing.
1174 static int screen_DECIC(term_screen *screen, const term_seq *seq) {
1176 * DECIC - insert-column
1178 * Probably not worth implementing.
1184 static int screen_DECID(term_screen *screen, const term_seq *seq) {
1186 * DECID - return-terminal-id
1187 * This is an obsolete form of TERM_CMD_DA1.
1190 return screen_DA1(screen, seq);
1193 static int screen_DECINVM(term_screen *screen, const term_seq *seq) {
1195 * DECINVM - invoke-macro
1197 * Probably not worth implementing.
1203 static int screen_DECKBD(term_screen *screen, const term_seq *seq) {
1205 * DECKBD - keyboard-language-selection
1207 * Probably not worth implementing.
1213 static int screen_DECKPAM(term_screen *screen, const term_seq *seq) {
1215 * DECKPAM - keypad-application-mode
1216 * Enables the keypad-application mode. If enabled, the keypad sends
1217 * special characters instead of the printed characters. This way,
1218 * applications can detect whether a numeric key was pressed on the
1219 * top-row or on the keypad.
1220 * Default is keypad-numeric-mode.
1223 screen->flags |= TERM_FLAG_KEYPAD_MODE;
1228 static int screen_DECKPNM(term_screen *screen, const term_seq *seq) {
1230 * DECKPNM - keypad-numeric-mode
1231 * This disables the keypad-application-mode (DECKPAM) and returns to
1232 * the keypad-numeric-mode. Keypresses on the keypad generate the same
1233 * sequences as corresponding keypresses on the main keyboard.
1234 * Default is keypad-numeric-mode.
1237 screen->flags &= ~TERM_FLAG_KEYPAD_MODE;
1242 static int screen_DECLFKC(term_screen *screen, const term_seq *seq) {
1244 * DECLFKC - local-function-key-control
1246 * Probably not worth implementing.
1252 static int screen_DECLL(term_screen *screen, const term_seq *seq) {
1256 * Probably not worth implementing.
1262 static int screen_DECLTOD(term_screen *screen, const term_seq *seq) {
1264 * DECLTOD - load-time-of-day
1266 * Probably not worth implementing.
1272 static int screen_DECPCTERM(term_screen *screen, const term_seq *seq) {
1274 * DECPCTERM - pcterm-mode
1275 * This enters/exits the PCTerm mode. Default mode is VT-mode. It can
1276 * also select parameters for scancode/keycode mappings in SCO mode.
1278 * Definitely not worth implementing. Lets kill PCTerm/SCO modes!
1284 static int screen_DECPKA(term_screen *screen, const term_seq *seq) {
1286 * DECPKA - program-key-action
1288 * Probably not worth implementing.
1294 static int screen_DECPKFMR(term_screen *screen, const term_seq *seq) {
1296 * DECPKFMR - program-key-free-memory-report
1298 * Probably not worth implementing.
1304 static int screen_DECRARA(term_screen *screen, const term_seq *seq) {
1306 * DECRARA - reverse-attributes-in-rectangular-area
1308 * Probably not worth implementing.
1314 static int screen_DECRC(term_screen *screen, const term_seq *seq) {
1316 * DECRC - restore-cursor
1317 * Restores the terminal to the state saved by the save cursor (DECSC)
1318 * function. This includes more than just the cursor-position.
1320 * If nothing was saved by DECSC, then DECRC performs the following
1322 * * Moves the cursor to the home position (upper left of screen).
1323 * * Resets origin mode (DECOM).
1324 * * Turns all character attributes off (normal setting).
1325 * * Maps the ASCII character set into GL, and the DEC Supplemental
1326 * Graphic set into GR.
1328 * The terminal maintains a separate DECSC buffer for the main display
1329 * and the status line. This feature lets you save a separate operating
1330 * state for the main display and the status line.
1333 screen_restore_state(screen, &screen->saved);
1338 static int screen_DECREQTPARM(term_screen *screen, const term_seq *seq) {
1340 * DECREQTPARM - request-terminal-parameters
1341 * The sequence DECREPTPARM is sent by the terminal controller to notify
1342 * the host of the status of selected terminal parameters. The status
1343 * sequence may be sent when requested by the host or at the terminal's
1344 * discretion. DECREPTPARM is sent upon receipt of a DECREQTPARM.
1346 * If @args[0] is 0, this marks a request and the terminal is allowed
1347 * to send DECREPTPARM messages without request. If it is 1, the same
1348 * applies but the terminal should no longer send DECREPTPARM
1350 * 2 and 3 mark a report, but 3 is only used if the terminal answers as
1351 * an explicit request with @args[0] == 1.
1353 * The other arguments are ignored in requests, but have the following
1354 * meaning in responses:
1355 * args[1]: 1=no-parity-set 4=parity-set-and-odd 5=parity-set-and-even
1356 * args[2]: 1=8bits-per-char 2=7bits-per-char
1357 * args[3]: transmission-speed
1358 * args[4]: receive-speed
1359 * args[5]: 1=bit-rate-multiplier-is-16
1360 * args[6]: This value communicates the four switch values in block 5
1361 * of SETUP B, which are only visible to the user when an STP
1362 * option is installed. These bits may be assigned for an STP
1363 * device. The four bits are a decimal-encoded binary number.
1364 * Value between 0-15.
1366 * The transmission/receive speeds have mappings for number => bits/s
1367 * which are quite weird. Examples are: 96->3600, 112->9600, 120->19200
1373 if (seq->n_args < 1 || seq->args[0] == 0) {
1374 screen->flags &= ~TERM_FLAG_INHIBIT_TPARM;
1375 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "2;1;1;120;120;1;0x");
1376 } else if (seq->args[0] == 1) {
1377 screen->flags |= TERM_FLAG_INHIBIT_TPARM;
1378 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "3;1;1;120;120;1;0x");
1384 static int screen_DECRPKT(term_screen *screen, const term_seq *seq) {
1386 * DECRPKT - report-key-type
1387 * Response to DECRQKT, we can safely ignore it as we're the one sending
1394 static int screen_DECRQCRA(term_screen *screen, const term_seq *seq) {
1396 * DECRQCRA - request-checksum-of-rectangular-area
1398 * Probably not worth implementing.
1404 static int screen_DECRQDE(term_screen *screen, const term_seq *seq) {
1406 * DECRQDE - request-display-extent
1408 * Probably not worth implementing.
1414 static int screen_DECRQKT(term_screen *screen, const term_seq *seq) {
1416 * DECRQKT - request-key-type
1418 * Probably not worth implementing.
1424 static int screen_DECRQLP(term_screen *screen, const term_seq *seq) {
1426 * DECRQLP - request-locator-position
1427 * See DECELR for locator-information.
1429 * TODO: document and implement
1435 static int screen_DECRQM_ANSI(term_screen *screen, const term_seq *seq) {
1437 * DECRQM_ANSI - request-mode-ansi
1438 * The host sends this control function to find out if a particular mode
1439 * is set or reset. The terminal responds with a report mode function.
1440 * @args[0] contains the mode to query.
1442 * Response is DECRPM with the first argument set to the mode that was
1443 * queried, second argument is 0 if mode is invalid, 1 if mode is set,
1444 * 2 if mode is not set (reset), 3 if mode is permanently set and 4 if
1445 * mode is permanently not set (reset):
1446 * ANSI: ^[ MODE ; VALUE $ y
1447 * DEC: ^[ ? MODE ; VALUE $ y
1455 static int screen_DECRQM_DEC(term_screen *screen, const term_seq *seq) {
1457 * DECRQM_DEC - request-mode-dec
1458 * Same as DECRQM_ANSI but for DEC modes.
1466 static int screen_DECRQPKFM(term_screen *screen, const term_seq *seq) {
1468 * DECRQPKFM - request-program-key-free-memory
1470 * Probably not worth implementing.
1476 static int screen_DECRQPSR(term_screen *screen, const term_seq *seq) {
1478 * DECRQPSR - request-presentation-state-report
1480 * Probably not worth implementing.
1486 static int screen_DECRQTSR(term_screen *screen, const term_seq *seq) {
1488 * DECRQTSR - request-terminal-state-report
1490 * Probably not worth implementing.
1496 static int screen_DECRQUPSS(term_screen *screen, const term_seq *seq) {
1498 * DECRQUPSS - request-user-preferred-supplemental-set
1500 * Probably not worth implementing.
1506 static int screen_DECSACE(term_screen *screen, const term_seq *seq) {
1508 * DECSACE - select-attribute-change-extent
1510 * Probably not worth implementing.
1516 static int screen_DECSASD(term_screen *screen, const term_seq *seq) {
1518 * DECSASD - select-active-status-display
1520 * Probably not worth implementing.
1526 static int screen_DECSC(term_screen *screen, const term_seq *seq) {
1528 * DECSC - save-cursor
1529 * Save cursor and terminal state so it can be restored later on.
1530 * Saves the following items in the terminal's memory:
1532 * * Character attributes set by the SGR command
1533 * * Character sets (G0, G1, G2, or G3) currently in GL and GR
1534 * * Wrap flag (autowrap or no autowrap)
1535 * * State of origin mode (DECOM)
1536 * * Selective erase attribute
1537 * * Any single shift 2 (SS2) or single shift 3 (SS3) functions sent
1540 screen_save_state(screen, &screen->saved);
1545 static int screen_DECSCA(term_screen *screen, const term_seq *seq) {
1547 * DECSCA - select-character-protection-attribute
1548 * Defines the characters that come after it as erasable or not erasable
1549 * from the screen. The selective erase control functions (DECSED and
1550 * DECSEL) can only erase characters defined as erasable.
1552 * @args[0] specifies the new mode. 0 and 2 mark any following character
1553 * as erasable, 1 marks it as not erasable.
1559 unsigned int mode = 0;
1561 if (seq->args[0] > 0)
1562 mode = seq->args[0];
1567 screen->state.attr.protect = 0;
1570 screen->state.attr.protect = 1;
1577 static int screen_DECSCL(term_screen *screen, const term_seq *seq) {
1579 * DECSCL - select-conformance-level
1580 * Select the terminal's operating level. The factory default is
1581 * level 4 (VT Level 4 mode, 7-bit controls).
1582 * When you change the conformance level, the terminal performs a hard
1585 * @args[0] defines the conformance-level, valid values are:
1586 * 61: Level 1 (VT100)
1587 * 62: Level 2 (VT200)
1588 * 63: Level 3 (VT300)
1589 * 64: Level 4 (VT400)
1590 * @args[1] defines the 8bit-mode, valid values are:
1593 * 2: 8-bit controls (same as 0)
1595 * If @args[0] is 61, then @args[1] is ignored and 7bit controls are
1603 unsigned int level = 64, bit = 0;
1605 if (seq->n_args > 0) {
1606 level = seq->args[0];
1607 if (seq->n_args > 1)
1611 term_screen_hard_reset(screen);
1615 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT100;
1616 screen->flags |= TERM_FLAG_7BIT_MODE;
1619 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
1621 screen->flags |= TERM_FLAG_7BIT_MODE;
1623 screen->flags &= ~TERM_FLAG_7BIT_MODE;
1630 static int screen_DECSCP(term_screen *screen, const term_seq *seq) {
1632 * DECSCP - select-communication-port
1634 * Probably not worth implementing.
1640 static int screen_DECSCPP(term_screen *screen, const term_seq *seq) {
1642 * DECSCPP - select-columns-per-page
1643 * Select columns per page. The number of rows is unaffected by this.
1644 * @args[0] selectes the number of columns (width), DEC only defines 80
1645 * and 132, but we allow any integer here. 0 is equivalent to 80.
1646 * Page content is *not* cleared and the cursor is left untouched.
1647 * However, if the page is reduced in width and the cursor would be
1648 * outside the visible region, it's set to the right border. Newly added
1649 * cells are cleared. No data is retained outside the visible region.
1660 static int screen_DECSCS(term_screen *screen, const term_seq *seq) {
1662 * DECSCS - select-communication-speed
1664 * Probably not worth implementing.
1670 static int screen_DECSCUSR(term_screen *screen, const term_seq *seq) {
1672 * DECSCUSR - set-cursor-style
1673 * This changes the style of the cursor. @args[0] can be one of:
1674 * 0, 1: blinking block
1676 * 3: blinking underline
1677 * 4: steady underline
1678 * Changing this setting does _not_ affect the cursor visibility itself.
1679 * Use DECTCEM for that.
1690 static int screen_DECSDDT(term_screen *screen, const term_seq *seq) {
1692 * DECSDDT - select-disconnect-delay-time
1694 * Probably not worth implementing.
1700 static int screen_DECSDPT(term_screen *screen, const term_seq *seq) {
1702 * DECSDPT - select-digital-printed-data-type
1704 * Probably not worth implementing.
1710 static int screen_DECSED(term_screen *screen, const term_seq *seq) {
1712 * DECSED - selective-erase-in-display
1713 * This control function erases some or all of the erasable characters
1714 * in the display. DECSED can only erase characters defined as erasable
1715 * by the DECSCA control function. DECSED works inside or outside the
1716 * scrolling margins.
1718 * @args[0] defines which regions are erased. If it is 0, all cells from
1719 * the cursor (inclusive) till the end of the display are erase. If it
1720 * is 1, all cells from the start of the display till the cursor
1721 * (inclusive) are erased. If it is 2, all cells are erased.
1727 unsigned int mode = 0;
1729 if (seq->args[0] > 0)
1730 mode = seq->args[0];
1734 term_page_erase(screen->page,
1735 screen->state.cursor_x, screen->state.cursor_y,
1736 screen->page->width, screen->page->height,
1737 &screen->state.attr, screen->age, true);
1740 term_page_erase(screen->page,
1742 screen->state.cursor_x, screen->state.cursor_y,
1743 &screen->state.attr, screen->age, true);
1746 term_page_erase(screen->page,
1748 screen->page->width, screen->page->height,
1749 &screen->state.attr, screen->age, true);
1756 static int screen_DECSEL(term_screen *screen, const term_seq *seq) {
1758 * DECSEL - selective-erase-in-line
1759 * This control function erases some or all of the erasable characters
1760 * in a single line of text. DECSEL erases only those characters defined
1761 * as erasable by the DECSCA control function. DECSEL works inside or
1762 * outside the scrolling margins.
1764 * @args[0] defines the region to be erased. If it is 0, all cells from
1765 * the cursor (inclusive) till the end of the line are erase. If it is
1766 * 1, all cells from the start of the line till the cursor (inclusive)
1767 * are erased. If it is 2, the whole line of the cursor is erased.
1773 unsigned int mode = 0;
1775 if (seq->args[0] > 0)
1776 mode = seq->args[0];
1780 term_page_erase(screen->page,
1781 screen->state.cursor_x, screen->state.cursor_y,
1782 screen->page->width, screen->state.cursor_y,
1783 &screen->state.attr, screen->age, true);
1786 term_page_erase(screen->page,
1787 0, screen->state.cursor_y,
1788 screen->state.cursor_x, screen->state.cursor_y,
1789 &screen->state.attr, screen->age, true);
1792 term_page_erase(screen->page,
1793 0, screen->state.cursor_y,
1794 screen->page->width, screen->state.cursor_y,
1795 &screen->state.attr, screen->age, true);
1802 static int screen_DECSERA(term_screen *screen, const term_seq *seq) {
1804 * DECSERA - selective-erase-rectangular-area
1806 * Probably not worth implementing.
1812 static int screen_DECSFC(term_screen *screen, const term_seq *seq) {
1814 * DECSFC - select-flow-control
1816 * Probably not worth implementing.
1822 static int screen_DECSKCV(term_screen *screen, const term_seq *seq) {
1824 * DECSKCV - set-key-click-volume
1826 * Probably not worth implementing.
1832 static int screen_DECSLCK(term_screen *screen, const term_seq *seq) {
1834 * DECSLCK - set-lock-key-style
1836 * Probably not worth implementing.
1842 static int screen_DECSLE(term_screen *screen, const term_seq *seq) {
1844 * DECSLE - select-locator-events
1852 static int screen_DECSLPP(term_screen *screen, const term_seq *seq) {
1854 * DECSLPP - set-lines-per-page
1855 * Set the number of lines used for the page. @args[0] specifies the
1856 * number of lines to be used. DEC only allows a limited number of
1857 * choices, however, we allow all integers. 0 is equivalent to 24.
1868 static int screen_DECSLRM_OR_SC(term_screen *screen, const term_seq *seq) {
1870 * DECSLRM_OR_SC - set-left-and-right-margins or save-cursor
1872 * TODO: Detect save-cursor and run it. DECSLRM is not worth
1879 static int screen_DECSMBV(term_screen *screen, const term_seq *seq) {
1881 * DECSMBV - set-margin-bell-volume
1883 * Probably not worth implementing.
1889 static int screen_DECSMKR(term_screen *screen, const term_seq *seq) {
1891 * DECSMKR - select-modifier-key-reporting
1893 * Probably not worth implementing.
1899 static int screen_DECSNLS(term_screen *screen, const term_seq *seq) {
1901 * DECSNLS - set-lines-per-screen
1903 * Probably not worth implementing.
1909 static int screen_DECSPP(term_screen *screen, const term_seq *seq) {
1911 * DECSPP - set-port-parameter
1913 * Probably not worth implementing.
1919 static int screen_DECSPPCS(term_screen *screen, const term_seq *seq) {
1921 * DECSPPCS - select-pro-printer-character-set
1923 * Probably not worth implementing.
1929 static int screen_DECSPRTT(term_screen *screen, const term_seq *seq) {
1931 * DECSPRTT - select-printer-type
1933 * Probably not worth implementing.
1939 static int screen_DECSR(term_screen *screen, const term_seq *seq) {
1941 * DECSR - secure-reset
1943 * Probably not worth implementing.
1949 static int screen_DECSRFR(term_screen *screen, const term_seq *seq) {
1951 * DECSRFR - select-refresh-rate
1953 * Probably not worth implementing.
1959 static int screen_DECSSCLS(term_screen *screen, const term_seq *seq) {
1961 * DECSSCLS - set-scroll-speed
1963 * Probably not worth implementing.
1969 static int screen_DECSSDT(term_screen *screen, const term_seq *seq) {
1971 * DECSSDT - select-status-display-line-type
1973 * Probably not worth implementing.
1979 static int screen_DECSSL(term_screen *screen, const term_seq *seq) {
1981 * DECSSL - select-setup-language
1983 * Probably not worth implementing.
1989 static int screen_DECST8C(term_screen *screen, const term_seq *seq) {
1991 * DECST8C - set-tab-at-every-8-columns
1992 * Clear the tab-ruler and reset it to a tab at every 8th column,
1993 * starting at 9 (though, setting a tab at 1 is fine as it has no
1999 for (i = 0; i < screen->page->width; i += 8)
2000 screen->tabs[i / 8] = 0x1;
2005 static int screen_DECSTBM(term_screen *screen, const term_seq *seq) {
2007 * DECSTBM - set-top-and-bottom-margins
2008 * This control function sets the top and bottom margins for the current
2009 * page. You cannot perform scrolling outside the margins.
2011 * @args[0] defines the top margin, @args[1] defines the bottom margin.
2012 * The bottom margin must be lower than the top-margin.
2014 * This call resets the cursor position to 0/0 of the page.
2018 * args[1]: last page-line
2021 unsigned int top, bottom;
2024 bottom = screen->page->height;
2026 if (seq->args[0] > 0)
2028 if (seq->args[1] > 0)
2029 bottom = seq->args[1];
2031 if (top > screen->page->height)
2032 top = screen->page->height;
2033 if (bottom > screen->page->height)
2034 bottom = screen->page->height;
2036 if (top >= bottom || top > screen->page->height || bottom > screen->page->height) {
2038 bottom = screen->page->height;
2041 term_page_set_scroll_region(screen->page, top - 1, bottom - top + 1);
2042 screen_cursor_clear_wrap(screen);
2043 screen_cursor_set(screen, 0, 0);
2048 static int screen_DECSTR(term_screen *screen, const term_seq *seq) {
2050 * DECSTR - soft-terminal-reset
2051 * Perform a soft reset to the default values.
2054 term_screen_soft_reset(screen);
2059 static int screen_DECSTRL(term_screen *screen, const term_seq *seq) {
2061 * DECSTRL - set-transmit-rate-limit
2063 * Probably not worth implementing.
2069 static int screen_DECSWBV(term_screen *screen, const term_seq *seq) {
2071 * DECSWBV - set-warning-bell-volume
2073 * Probably not worth implementing.
2079 static int screen_DECSWL(term_screen *screen, const term_seq *seq) {
2081 * DECSWL - single-width-single-height-line
2083 * Probably not worth implementing.
2089 static int screen_DECTID(term_screen *screen, const term_seq *seq) {
2091 * DECTID - select-terminal-id
2093 * Probably not worth implementing.
2099 static int screen_DECTME(term_screen *screen, const term_seq *seq) {
2101 * DECTME - terminal-mode-emulation
2103 * Probably not worth implementing.
2109 static int screen_DECTST(term_screen *screen, const term_seq *seq) {
2111 * DECTST - invoke-confidence-test
2113 * Probably not worth implementing.
2119 static int screen_DL(term_screen *screen, const term_seq *seq) {
2122 * This control function deletes one or more lines in the scrolling
2123 * region, starting with the line that has the cursor. @args[0] defines
2124 * the number of lines to delete. 0 is treated the same as 1.
2125 * As lines are deleted, lines below the cursor and in the scrolling
2126 * region move up. The terminal adds blank lines with no visual
2127 * character attributes at the bottom of the scrolling region. If it is
2128 * greater than the number of lines remaining on the page, DL deletes
2129 * only the remaining lines. DL has no effect outside the scrolling
2136 unsigned int num = 1;
2138 if (seq->args[0] > 0)
2141 term_page_delete_lines(screen->page, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2146 static int screen_DSR_ANSI(term_screen *screen, const term_seq *seq) {
2148 * DSR_ANSI - device-status-report-ansi
2156 static int screen_DSR_DEC(term_screen *screen, const term_seq *seq) {
2158 * DSR_DEC - device-status-report-dec
2166 static int screen_ECH(term_screen *screen, const term_seq *seq) {
2168 * ECH - erase-character
2169 * This control function erases one or more characters, from the cursor
2170 * position to the right. ECH clears character attributes from erased
2171 * character positions. ECH works inside or outside the scrolling
2173 * @args[0] defines the number of characters to erase. 0 is treated the
2180 unsigned int num = 1;
2182 if (seq->args[0] > 0)
2185 term_page_erase(screen->page,
2186 screen->state.cursor_x, screen->state.cursor_y,
2187 screen->state.cursor_x + num, screen->state.cursor_y,
2188 &screen->state.attr, screen->age, false);
2193 static int screen_ED(term_screen *screen, const term_seq *seq) {
2195 * ED - erase-in-display
2196 * This control function erases characters from part or all of the
2197 * display. When you erase complete lines, they become single-height,
2198 * single-width lines, with all visual character attributes cleared. ED
2199 * works inside or outside the scrolling margins.
2201 * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2202 * till the end of the screen. 1 means from the start of the screen till
2203 * the cursor (inclusive) and 2 means the whole screen.
2209 unsigned int mode = 0;
2211 if (seq->args[0] > 0)
2212 mode = seq->args[0];
2216 term_page_erase(screen->page,
2217 screen->state.cursor_x, screen->state.cursor_y,
2218 screen->page->width, screen->page->height,
2219 &screen->state.attr, screen->age, false);
2222 term_page_erase(screen->page,
2224 screen->state.cursor_x, screen->state.cursor_y,
2225 &screen->state.attr, screen->age, false);
2228 term_page_erase(screen->page,
2230 screen->page->width, screen->page->height,
2231 &screen->state.attr, screen->age, false);
2238 static int screen_EL(term_screen *screen, const term_seq *seq) {
2240 * EL - erase-in-line
2241 * This control function erases characters on the line that has the
2242 * cursor. EL clears all character attributes from erased character
2243 * positions. EL works inside or outside the scrolling margins.
2245 * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2246 * till the end of the line. 1 means from the start of the line till the
2247 * cursor (inclusive) and 2 means the whole line.
2253 unsigned int mode = 0;
2255 if (seq->args[0] > 0)
2256 mode = seq->args[0];
2260 term_page_erase(screen->page,
2261 screen->state.cursor_x, screen->state.cursor_y,
2262 screen->page->width, screen->state.cursor_y,
2263 &screen->state.attr, screen->age, false);
2266 term_page_erase(screen->page,
2267 0, screen->state.cursor_y,
2268 screen->state.cursor_x, screen->state.cursor_y,
2269 &screen->state.attr, screen->age, false);
2272 term_page_erase(screen->page,
2273 0, screen->state.cursor_y,
2274 screen->page->width, screen->state.cursor_y,
2275 &screen->state.attr, screen->age, false);
2282 static int screen_ENQ(term_screen *screen, const term_seq *seq) {
2285 * Transmit the answerback-string. If none is set, do nothing.
2288 if (screen->answerback)
2289 return screen_write(screen, screen->answerback, strlen(screen->answerback));
2294 static int screen_EPA(term_screen *screen, const term_seq *seq) {
2296 * EPA - end-of-guarded-area
2298 * TODO: What is this?
2304 static int screen_FF(term_screen *screen, const term_seq *seq) {
2307 * This causes the cursor to jump to the next line. It is treated the
2311 return screen_LF(screen, seq);
2314 static int screen_HPA(term_screen *screen, const term_seq *seq) {
2316 * HPA - horizontal-position-absolute
2317 * HPA causes the active position to be moved to the n-th horizontal
2318 * position of the active line. If an attempt is made to move the active
2319 * position past the last position on the line, then the active position
2320 * stops at the last position on the line.
2322 * @args[0] defines the horizontal position. 0 is treated as 1.
2328 unsigned int num = 1;
2330 if (seq->args[0] > 0)
2333 screen_cursor_clear_wrap(screen);
2334 screen_cursor_set(screen, num - 1, screen->state.cursor_y);
2339 static int screen_HPR(term_screen *screen, const term_seq *seq) {
2341 * HPR - horizontal-position-relative
2342 * HPR causes the active position to be moved to the n-th following
2343 * horizontal position of the active line. If an attempt is made to move
2344 * the active position past the last position on the line, then the
2345 * active position stops at the last position on the line.
2347 * @args[0] defines the horizontal position. 0 is treated as 1.
2353 unsigned int num = 1;
2355 if (seq->args[0] > 0)
2358 screen_cursor_clear_wrap(screen);
2359 screen_cursor_right(screen, num);
2364 static int screen_HT(term_screen *screen, const term_seq *seq) {
2366 * HT - horizontal-tab
2367 * Moves the cursor to the next tab stop. If there are no more tab
2368 * stops, the cursor moves to the right margin. HT does not cause text
2372 screen_cursor_clear_wrap(screen);
2373 screen_cursor_right_tab(screen, 1);
2378 static int screen_HTS(term_screen *screen, const term_seq *seq) {
2380 * HTS - horizontal-tab-set
2381 * HTS sets a horizontal tab stop at the column position indicated by
2382 * the value of the active column when the terminal receives an HTS.
2384 * Executing an HTS does not effect the other horizontal tab stop
2390 pos = screen->state.cursor_x;
2391 if (screen->page->width > 0)
2392 screen->tabs[pos / 8] |= 1U << (pos % 8);
2397 static int screen_HVP(term_screen *screen, const term_seq *seq) {
2399 * HVP - horizontal-and-vertical-position
2400 * This control function works the same as the cursor position (CUP)
2401 * function. Origin mode (DECOM) selects line numbering and the ability
2402 * to move the cursor into margins.
2409 return screen_CUP(screen, seq);
2412 static int screen_ICH(term_screen *screen, const term_seq *seq) {
2414 * ICH - insert-character
2415 * This control function inserts one or more space (SP) characters
2416 * starting at the cursor position. @args[0] is the number of characters
2417 * to insert. 0 is treated as 1.
2419 * The ICH sequence inserts blank characters with the normal
2420 * character attribute. The cursor remains at the beginning of the blank
2421 * characters. Text between the cursor and right margin moves to the
2422 * right. Characters scrolled past the right margin are lost. ICH has no
2423 * effect outside the scrolling margins.
2429 unsigned int num = 1;
2431 if (seq->args[0] > 0)
2434 screen_cursor_clear_wrap(screen);
2435 term_page_insert_cells(screen->page, screen->state.cursor_x, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2440 static int screen_IL(term_screen *screen, const term_seq *seq) {
2443 * This control function inserts one or more blank lines, starting at
2444 * the cursor. @args[0] is the number of lines to insert. 0 is treated
2447 * As lines are inserted, lines below the cursor and in the scrolling
2448 * region move down. Lines scrolled off the page are lost. IL has no
2449 * effect outside the page margins.
2455 unsigned int num = 1;
2457 if (seq->args[0] > 0)
2460 screen_cursor_clear_wrap(screen);
2461 term_page_insert_lines(screen->page, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2466 static int screen_IND(term_screen *screen, const term_seq *seq) {
2469 * IND moves the cursor down one line in the same column. If the cursor
2470 * is at the bottom margin, then the screen performs a scroll-up.
2473 screen_cursor_down(screen, 1, true);
2478 static int screen_LF(term_screen *screen, const term_seq *seq) {
2481 * Causes a line feed or a new line operation, depending on the setting
2482 * of line feed/new line mode.
2485 screen_cursor_down(screen, 1, true);
2486 if (screen->flags & TERM_FLAG_NEWLINE_MODE)
2487 screen_cursor_left(screen, screen->state.cursor_x);
2492 static int screen_LS1R(term_screen *screen, const term_seq *seq) {
2494 * LS1R - locking-shift-1-right
2498 screen->state.gr = &screen->g1;
2503 static int screen_LS2(term_screen *screen, const term_seq *seq) {
2505 * LS2 - locking-shift-2
2509 screen->state.gl = &screen->g2;
2514 static int screen_LS2R(term_screen *screen, const term_seq *seq) {
2516 * LS2R - locking-shift-2-right
2520 screen->state.gr = &screen->g2;
2525 static int screen_LS3(term_screen *screen, const term_seq *seq) {
2527 * LS3 - locking-shift-3
2531 screen->state.gl = &screen->g3;
2536 static int screen_LS3R(term_screen *screen, const term_seq *seq) {
2538 * LS3R - locking-shift-3-right
2542 screen->state.gr = &screen->g3;
2547 static int screen_MC_ANSI(term_screen *screen, const term_seq *seq) {
2549 * MC_ANSI - media-copy-ansi
2551 * Probably not worth implementing.
2557 static int screen_MC_DEC(term_screen *screen, const term_seq *seq) {
2559 * MC_DEC - media-copy-dec
2561 * Probably not worth implementing.
2567 static int screen_NEL(term_screen *screen, const term_seq *seq) {
2570 * Moves cursor to first position on next line. If cursor is at bottom
2571 * margin, then screen performs a scroll-up.
2574 screen_cursor_clear_wrap(screen);
2575 screen_cursor_down(screen, 1, true);
2576 screen_cursor_set(screen, 0, screen->state.cursor_y);
2581 static int screen_NP(term_screen *screen, const term_seq *seq) {
2584 * This control function moves the cursor forward to the home position
2585 * on one of the following pages in page memory. If there is only one
2586 * page, then the terminal ignores NP.
2587 * If NP tries to move the cursor past the last page in memory, then the
2588 * cursor stops at the last page.
2590 * @args[0] defines the number of pages to forward. 0 is treated as 1.
2595 * Probably not worth implementing. We only support a single page.
2601 static int screen_NULL(term_screen *screen, const term_seq *seq) {
2604 * The NULL operation does nothing. ASCII NULL is always ignored.
2610 static int screen_PP(term_screen *screen, const term_seq *seq) {
2612 * PP - preceding-page
2613 * This control function moves the cursor backward to the home position
2614 * on one of the preceding pages in page memory. If there is only one
2615 * page, then the terminal ignores PP.
2616 * If PP tries to move the cursor back farther than the first page in
2617 * memory, then the cursor stops at the first page.
2619 * @args[0] defines the number of pages to go backwards. 0 is treated
2625 * Probably not worth implementing. We only support a single page.
2631 static int screen_PPA(term_screen *screen, const term_seq *seq) {
2633 * PPA - page-position-absolute
2634 * This control function can move the cursor to the corresponding row
2635 * and column on any page in page memory. You select the page by its
2636 * number. If there is only one page, then the terminal ignores PPA.
2638 * @args[0] is the number of the page to move the cursor to. If it is
2639 * greater than the number of the last page in memory, then the cursor
2640 * stops at the last page. If it is less than the number of the first
2641 * page, then the cursor stops at the first page.
2646 * Probably not worth implementing. We only support a single page.
2652 static int screen_PPB(term_screen *screen, const term_seq *seq) {
2654 * PPB - page-position-backward
2655 * This control function moves the cursor backward to the corresponding
2656 * row and column on one of the preceding pages in page memory. If there
2657 * is only one page, then the terminal ignores PPB.
2659 * @args[0] indicates the number of pages to move the cursor backward.
2660 * If it tries to move the cursor back farther than the first page in
2661 * memory, then the cursor stops at the first page. 0 is treated as 1.
2666 * Probably not worth implementing. We only support a single page.
2672 static int screen_PPR(term_screen *screen, const term_seq *seq) {
2674 * PPR - page-position-relative
2675 * This control function moves the cursor forward to the corresponding
2676 * row and column on one of the following pages in page memory. If there
2677 * is only one page, then the terminal ignores PPR.
2679 * @args[0] indicates how many pages to move the cursor forward. If it
2680 * tries to move the cursor beyond the last page in memory, then the
2681 * cursor stops at the last page. 0 is treated as 1.
2686 * Probably not worth implementing. We only support a single page.
2692 static int screen_RC(term_screen *screen, const term_seq *seq) {
2694 * RC - restore-cursor
2697 return screen_DECRC(screen, seq);
2700 static int screen_REP(term_screen *screen, const term_seq *seq) {
2703 * Repeat the preceding graphics-character the given number of times.
2704 * @args[0] specifies how often it shall be repeated. 0 is treated as 1.
2709 * Probably not worth implementing.
2715 static int screen_RI(term_screen *screen, const term_seq *seq) {
2717 * RI - reverse-index
2718 * Moves the cursor up one line in the same column. If the cursor is at
2719 * the top margin, the page scrolls down.
2722 screen_cursor_up(screen, 1, true);
2727 static int screen_RIS(term_screen *screen, const term_seq *seq) {
2729 * RIS - reset-to-initial-state
2730 * This control function causes a nonvolatile memory (NVR) recall to
2731 * occur. RIS replaces all set-up features with their saved settings.
2733 * The terminal stores these saved settings in NVR memory. The saved
2734 * setting for a feature is the same as the factory-default setting,
2735 * unless you saved a new setting.
2738 term_screen_hard_reset(screen);
2743 static int screen_RM_ANSI(term_screen *screen, const term_seq *seq) {
2745 * RM_ANSI - reset-mode-ansi
2747 * TODO: implement (see VT510rm manual)
2752 for (i = 0; i < seq->n_args; ++i)
2753 screen_mode_change_ansi(screen, seq->args[i], false);
2758 static int screen_RM_DEC(term_screen *screen, const term_seq *seq) {
2760 * RM_DEC - reset-mode-dec
2761 * This is the same as RM_ANSI but for DEC modes.
2766 for (i = 0; i < seq->n_args; ++i)
2767 screen_mode_change_dec(screen, seq->args[i], false);
2772 static int screen_S7C1T(term_screen *screen, const term_seq *seq) {
2774 * S7C1T - set-7bit-c1-terminal
2775 * This causes the terminal to start sending C1 controls as 7bit
2776 * sequences instead of 8bit C1 controls.
2777 * This is ignored if the terminal is below level-2 emulation mode
2778 * (VT100 and below), the terminal already sends 7bit controls then.
2781 if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2782 screen->flags |= TERM_FLAG_7BIT_MODE;
2787 static int screen_S8C1T(term_screen *screen, const term_seq *seq) {
2789 * S8C1T - set-8bit-c1-terminal
2790 * This causes the terminal to start sending C1 controls as 8bit C1
2791 * control instead of 7bit sequences.
2792 * This is ignored if the terminal is below level-2 emulation mode
2793 * (VT100 and below). The terminal always sends 7bit controls in those
2797 if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2798 screen->flags &= ~TERM_FLAG_7BIT_MODE;
2803 static int screen_SCS(term_screen *screen, const term_seq *seq) {
2805 * SCS - select-character-set
2806 * Designate character sets to G-sets. The mapping from intermediates
2807 * and terminal characters in the escape sequence to G-sets and
2808 * character-sets is non-trivial and implemented separately. See there
2809 * for more information.
2810 * This call simply sets the selected G-set to the desired
2814 term_charset *cs = NULL;
2816 /* TODO: support more of them? */
2817 switch (seq->charset) {
2818 case TERM_CHARSET_ISO_LATIN1_SUPPLEMENTAL:
2819 case TERM_CHARSET_ISO_LATIN2_SUPPLEMENTAL:
2820 case TERM_CHARSET_ISO_LATIN5_SUPPLEMENTAL:
2821 case TERM_CHARSET_ISO_GREEK_SUPPLEMENTAL:
2822 case TERM_CHARSET_ISO_HEBREW_SUPPLEMENTAL:
2823 case TERM_CHARSET_ISO_LATIN_CYRILLIC:
2826 case TERM_CHARSET_DEC_SPECIAL_GRAPHIC:
2827 cs = &term_dec_special_graphics;
2829 case TERM_CHARSET_DEC_SUPPLEMENTAL:
2830 cs = &term_dec_supplemental_graphics;
2832 case TERM_CHARSET_DEC_TECHNICAL:
2833 case TERM_CHARSET_CYRILLIC_DEC:
2834 case TERM_CHARSET_DUTCH_NRCS:
2835 case TERM_CHARSET_FINNISH_NRCS:
2836 case TERM_CHARSET_FRENCH_NRCS:
2837 case TERM_CHARSET_FRENCH_CANADIAN_NRCS:
2838 case TERM_CHARSET_GERMAN_NRCS:
2839 case TERM_CHARSET_GREEK_DEC:
2840 case TERM_CHARSET_GREEK_NRCS:
2841 case TERM_CHARSET_HEBREW_DEC:
2842 case TERM_CHARSET_HEBREW_NRCS:
2843 case TERM_CHARSET_ITALIAN_NRCS:
2844 case TERM_CHARSET_NORWEGIAN_DANISH_NRCS:
2845 case TERM_CHARSET_PORTUGUESE_NRCS:
2846 case TERM_CHARSET_RUSSIAN_NRCS:
2847 case TERM_CHARSET_SCS_NRCS:
2848 case TERM_CHARSET_SPANISH_NRCS:
2849 case TERM_CHARSET_SWEDISH_NRCS:
2850 case TERM_CHARSET_SWISS_NRCS:
2851 case TERM_CHARSET_TURKISH_DEC:
2852 case TERM_CHARSET_TURKISH_NRCS:
2855 case TERM_CHARSET_USERPREF_SUPPLEMENTAL:
2859 if (seq->intermediates & TERM_SEQ_FLAG_POPEN)
2860 screen->g0 = cs ? : &term_unicode_lower;
2861 else if (seq->intermediates & TERM_SEQ_FLAG_PCLOSE)
2862 screen->g1 = cs ? : &term_unicode_upper;
2863 else if (seq->intermediates & TERM_SEQ_FLAG_MULT)
2864 screen->g2 = cs ? : &term_unicode_lower;
2865 else if (seq->intermediates & TERM_SEQ_FLAG_PLUS)
2866 screen->g3 = cs ? : &term_unicode_upper;
2867 else if (seq->intermediates & TERM_SEQ_FLAG_MINUS)
2868 screen->g1 = cs ? : &term_unicode_upper;
2869 else if (seq->intermediates & TERM_SEQ_FLAG_DOT)
2870 screen->g2 = cs ? : &term_unicode_lower;
2871 else if (seq->intermediates & TERM_SEQ_FLAG_SLASH)
2872 screen->g3 = cs ? : &term_unicode_upper;
2877 static int screen_SD(term_screen *screen, const term_seq *seq) {
2880 * This control function moves the user window down a specified number
2881 * of lines in page memory.
2882 * @args[0] is the number of lines to move the
2883 * user window up in page memory. New lines appear at the top of the
2884 * display. Old lines disappear at the bottom of the display. You
2885 * cannot pan past the top margin of the current page. 0 is treated
2892 unsigned int num = 1;
2894 if (seq->args[0] > 0)
2897 term_page_scroll_down(screen->page, num, &screen->state.attr, screen->age, NULL);
2902 static int screen_SGR(term_screen *screen, const term_seq *seq) {
2904 * SGR - select-graphics-rendition
2908 unsigned int i, code;
2911 if (seq->n_args < 1) {
2912 zero(screen->state.attr);
2916 for (i = 0; i < seq->n_args; ++i) {
2920 screen->state.attr.bold = 1;
2923 screen->state.attr.italic = 1;
2926 screen->state.attr.underline = 1;
2929 screen->state.attr.blink = 1;
2932 screen->state.attr.inverse = 1;
2935 screen->state.attr.hidden = 1;
2938 screen->state.attr.bold = 0;
2941 screen->state.attr.italic = 0;
2944 screen->state.attr.underline = 0;
2947 screen->state.attr.blink = 0;
2950 screen->state.attr.inverse = 0;
2953 screen->state.attr.hidden = 0;
2956 screen->state.attr.fg.ccode = v - 30 + TERM_CCODE_BLACK;
2959 screen->state.attr.fg.ccode = 0;
2962 screen->state.attr.bg.ccode = v - 40 + TERM_CCODE_BLACK;
2965 screen->state.attr.bg.ccode = 0;
2968 screen->state.attr.fg.ccode = v - 90 + TERM_CCODE_LIGHT_BLACK;
2971 screen->state.attr.bg.ccode = v - 100 + TERM_CCODE_LIGHT_BLACK;
2978 dst = &screen->state.attr.fg;
2980 dst = &screen->state.attr.bg;
2983 if (i >= seq->n_args)
2986 switch (seq->args[i]) {
2988 /* 24bit-color support */
2991 if (i >= seq->n_args)
2994 dst->ccode = TERM_CCODE_RGB;
2995 dst->red = (seq->args[i - 2] >= 0) ? seq->args[i - 2] : 0;
2996 dst->green = (seq->args[i - 1] >= 0) ? seq->args[i - 1] : 0;
2997 dst->blue = (seq->args[i] >= 0) ? seq->args[i] : 0;
3001 /* 256-color support */
3004 if (i >= seq->n_args || seq->args[i] < 0)
3007 dst->ccode = TERM_CCODE_256;
3008 code = seq->args[i];
3009 dst->c256 = code < 256 ? code : 0;
3018 zero(screen->state.attr);
3026 static int screen_SI(term_screen *screen, const term_seq *seq) {
3032 screen->state.gl = &screen->g0;
3037 static int screen_SM_ANSI(term_screen *screen, const term_seq *seq) {
3039 * SM_ANSI - set-mode-ansi
3046 for (i = 0; i < seq->n_args; ++i)
3047 screen_mode_change_ansi(screen, seq->args[i], true);
3052 static int screen_SM_DEC(term_screen *screen, const term_seq *seq) {
3054 * SM_DEC - set-mode-dec
3055 * This is the same as SM_ANSI but for DEC modes.
3060 for (i = 0; i < seq->n_args; ++i)
3061 screen_mode_change_dec(screen, seq->args[i], true);
3066 static int screen_SO(term_screen *screen, const term_seq *seq) {
3072 screen->state.gl = &screen->g1;
3077 static int screen_SPA(term_screen *screen, const term_seq *seq) {
3079 * SPA - start-of-protected-area
3081 * TODO: What is this?
3087 static int screen_SS2(term_screen *screen, const term_seq *seq) {
3089 * SS2 - single-shift-2
3090 * Temporarily map G2 into GL for the next graphics character.
3093 screen->state.glt = &screen->g2;
3098 static int screen_SS3(term_screen *screen, const term_seq *seq) {
3100 * SS3 - single-shift-3
3101 * Temporarily map G3 into GL for the next graphics character
3104 screen->state.glt = &screen->g3;
3109 static int screen_ST(term_screen *screen, const term_seq *seq) {
3111 * ST - string-terminator
3112 * The string-terminator is usually part of control-sequences and
3113 * handled by the parser. In all other situations it is silently
3120 static int screen_SU(term_screen *screen, const term_seq *seq) {
3123 * This control function moves the user window up a specified number of
3124 * lines in page memory.
3125 * @args[0] is the number of lines to move the
3126 * user window down in page memory. New lines appear at the bottom of
3127 * the display. Old lines disappear at the top of the display. You
3128 * cannot pan past the bottom margin of the current page. 0 is treated
3135 unsigned int num = 1;
3137 if (seq->args[0] > 0)
3140 term_page_scroll_up(screen->page, num, &screen->state.attr, screen->age, screen->history);
3145 static int screen_SUB(term_screen *screen, const term_seq *seq) {
3148 * Cancel the current control-sequence and print a replacement
3149 * character. Our parser already handles this so all we have to do is
3150 * print the replacement character.
3153 static const term_seq rep = {
3154 .type = TERM_SEQ_GRAPHIC,
3155 .command = TERM_CMD_GRAPHIC,
3156 .terminator = 0xfffd,
3159 return screen_GRAPHIC(screen, &rep);
3162 static int screen_TBC(term_screen *screen, const term_seq *seq) {
3165 * This clears tab-stops. If @args[0] is 0, the tab-stop at the current
3166 * cursor position is cleared. If it is 3, all tab stops are cleared.
3172 unsigned int mode = 0, pos;
3174 if (seq->args[0] > 0)
3175 mode = seq->args[0];
3179 pos = screen->state.cursor_x;
3180 if (screen->page->width > 0)
3181 screen->tabs[pos / 8] &= ~(1U << (pos % 8));
3184 if (screen->page->width > 0)
3185 memset(screen->tabs, 0, (screen->page->width + 7) / 8);
3192 static int screen_VPA(term_screen *screen, const term_seq *seq) {
3194 * VPA - vertical-line-position-absolute
3195 * VPA causes the active position to be moved to the corresponding
3196 * horizontal position. @args[0] specifies the line to jump to. If an
3197 * attempt is made to move the active position below the last line, then
3198 * the active position stops on the last line. 0 is treated as 1.
3204 unsigned int pos = 1;
3206 if (seq->args[0] > 0)
3209 screen_cursor_clear_wrap(screen);
3210 screen_cursor_set_rel(screen, screen->state.cursor_x, pos - 1);
3215 static int screen_VPR(term_screen *screen, const term_seq *seq) {
3217 * VPR - vertical-line-position-relative
3218 * VPR causes the active position to be moved to the corresponding
3219 * horizontal position. @args[0] specifies the number of lines to jump
3220 * down relative to the current cursor position. If an attempt is made
3221 * to move the active position below the last line, the active position
3222 * stops at the last line. 0 is treated as 1.
3228 unsigned int num = 1;
3230 if (seq->args[0] > 0)
3233 screen_cursor_clear_wrap(screen);
3234 screen_cursor_down(screen, num, false);
3239 static int screen_VT(term_screen *screen, const term_seq *seq) {
3242 * This causes a vertical jump by one line. Terminals treat it exactly
3246 return screen_LF(screen, seq);
3249 static int screen_XTERM_CLLHP(term_screen *screen, const term_seq *seq) {
3251 * XTERM_CLLHP - xterm-cursor-lower-left-hp-bugfix
3252 * Move the cursor to the lower-left corner of the page. This is an HP
3255 * Probably not worth implementing.
3261 static int screen_XTERM_IHMT(term_screen *screen, const term_seq *seq) {
3263 * XTERM_IHMT - xterm-initiate-highlight-mouse-tracking
3265 * Probably not worth implementing.
3271 static int screen_XTERM_MLHP(term_screen *screen, const term_seq *seq) {
3273 * XTERM_MLHP - xterm-memory-lock-hp-bugfix
3275 * Probably not worth implementing.
3281 static int screen_XTERM_MUHP(term_screen *screen, const term_seq *seq) {
3283 * XTERM_MUHP - xterm-memory-unlock-hp-bugfix
3285 * Probably not worth implementing.
3291 static int screen_XTERM_RPM(term_screen *screen, const term_seq *seq) {
3293 * XTERM_RPM - xterm-restore-private-mode
3295 * Probably not worth implementing.
3301 static int screen_XTERM_RRV(term_screen *screen, const term_seq *seq) {
3303 * XTERM_RRV - xterm-reset-resource-value
3305 * Probably not worth implementing.
3311 static int screen_XTERM_RTM(term_screen *screen, const term_seq *seq) {
3313 * XTERM_RTM - xterm-reset-title-mode
3315 * Probably not worth implementing.
3321 static int screen_XTERM_SACL1(term_screen *screen, const term_seq *seq) {
3323 * XTERM_SACL1 - xterm-set-ansi-conformance-level-1
3325 * Probably not worth implementing.
3331 static int screen_XTERM_SACL2(term_screen *screen, const term_seq *seq) {
3333 * XTERM_SACL2 - xterm-set-ansi-conformance-level-2
3335 * Probably not worth implementing.
3341 static int screen_XTERM_SACL3(term_screen *screen, const term_seq *seq) {
3343 * XTERM_SACL3 - xterm-set-ansi-conformance-level-3
3345 * Probably not worth implementing.
3351 static int screen_XTERM_SDCS(term_screen *screen, const term_seq *seq) {
3353 * XTERM_SDCS - xterm-set-default-character-set
3354 * Select the default character set. We treat this the same as UTF-8 as
3355 * this is our default character set. As we always use UTF-8, this
3362 static int screen_XTERM_SGFX(term_screen *screen, const term_seq *seq) {
3364 * XTERM_SGFX - xterm-sixel-graphics
3366 * Probably not worth implementing.
3372 static int screen_XTERM_SPM(term_screen *screen, const term_seq *seq) {
3374 * XTERM_SPM - xterm-set-private-mode
3376 * Probably not worth implementing.
3382 static int screen_XTERM_SRV(term_screen *screen, const term_seq *seq) {
3384 * XTERM_SRV - xterm-set-resource-value
3386 * Probably not worth implementing.
3392 static int screen_XTERM_STM(term_screen *screen, const term_seq *seq) {
3394 * XTERM_STM - xterm-set-title-mode
3396 * Probably not worth implementing.
3402 static int screen_XTERM_SUCS(term_screen *screen, const term_seq *seq) {
3404 * XTERM_SUCS - xterm-select-utf8-character-set
3405 * Select UTF-8 as character set. This is our default on only character
3406 * set. Hence, this is a no-op.
3412 static int screen_XTERM_WM(term_screen *screen, const term_seq *seq) {
3414 * XTERM_WM - xterm-window-management
3416 * Probably not worth implementing.
3424 * The screen_feed_*() handlers take data from the user and feed it into the
3425 * screen. Once the parser has detected a sequence, we parse the command-type
3426 * and forward it to the command-dispatchers.
3429 static int screen_feed_cmd(term_screen *screen, const term_seq *seq) {
3430 switch (seq->command) {
3431 case TERM_CMD_GRAPHIC:
3432 return screen_GRAPHIC(screen, seq);
3434 return screen_BEL(screen, seq);
3436 return screen_BS(screen, seq);
3438 return screen_CBT(screen, seq);
3440 return screen_CHA(screen, seq);
3442 return screen_CHT(screen, seq);
3444 return screen_CNL(screen, seq);
3446 return screen_CPL(screen, seq);
3448 return screen_CR(screen, seq);
3450 return screen_CUB(screen, seq);
3452 return screen_CUD(screen, seq);
3454 return screen_CUF(screen, seq);
3456 return screen_CUP(screen, seq);
3458 return screen_CUU(screen, seq);
3460 return screen_DA1(screen, seq);
3462 return screen_DA2(screen, seq);
3464 return screen_DA3(screen, seq);
3466 return screen_DC1(screen, seq);
3468 return screen_DC3(screen, seq);
3470 return screen_DCH(screen, seq);
3471 case TERM_CMD_DECALN:
3472 return screen_DECALN(screen, seq);
3473 case TERM_CMD_DECANM:
3474 return screen_DECANM(screen, seq);
3475 case TERM_CMD_DECBI:
3476 return screen_DECBI(screen, seq);
3477 case TERM_CMD_DECCARA:
3478 return screen_DECCARA(screen, seq);
3479 case TERM_CMD_DECCRA:
3480 return screen_DECCRA(screen, seq);
3481 case TERM_CMD_DECDC:
3482 return screen_DECDC(screen, seq);
3483 case TERM_CMD_DECDHL_BH:
3484 return screen_DECDHL_BH(screen, seq);
3485 case TERM_CMD_DECDHL_TH:
3486 return screen_DECDHL_TH(screen, seq);
3487 case TERM_CMD_DECDWL:
3488 return screen_DECDWL(screen, seq);
3489 case TERM_CMD_DECEFR:
3490 return screen_DECEFR(screen, seq);
3491 case TERM_CMD_DECELF:
3492 return screen_DECELF(screen, seq);
3493 case TERM_CMD_DECELR:
3494 return screen_DECELR(screen, seq);
3495 case TERM_CMD_DECERA:
3496 return screen_DECERA(screen, seq);
3497 case TERM_CMD_DECFI:
3498 return screen_DECFI(screen, seq);
3499 case TERM_CMD_DECFRA:
3500 return screen_DECFRA(screen, seq);
3501 case TERM_CMD_DECIC:
3502 return screen_DECIC(screen, seq);
3503 case TERM_CMD_DECID:
3504 return screen_DECID(screen, seq);
3505 case TERM_CMD_DECINVM:
3506 return screen_DECINVM(screen, seq);
3507 case TERM_CMD_DECKBD:
3508 return screen_DECKBD(screen, seq);
3509 case TERM_CMD_DECKPAM:
3510 return screen_DECKPAM(screen, seq);
3511 case TERM_CMD_DECKPNM:
3512 return screen_DECKPNM(screen, seq);
3513 case TERM_CMD_DECLFKC:
3514 return screen_DECLFKC(screen, seq);
3515 case TERM_CMD_DECLL:
3516 return screen_DECLL(screen, seq);
3517 case TERM_CMD_DECLTOD:
3518 return screen_DECLTOD(screen, seq);
3519 case TERM_CMD_DECPCTERM:
3520 return screen_DECPCTERM(screen, seq);
3521 case TERM_CMD_DECPKA:
3522 return screen_DECPKA(screen, seq);
3523 case TERM_CMD_DECPKFMR:
3524 return screen_DECPKFMR(screen, seq);
3525 case TERM_CMD_DECRARA:
3526 return screen_DECRARA(screen, seq);
3527 case TERM_CMD_DECRC:
3528 return screen_DECRC(screen, seq);
3529 case TERM_CMD_DECREQTPARM:
3530 return screen_DECREQTPARM(screen, seq);
3531 case TERM_CMD_DECRPKT:
3532 return screen_DECRPKT(screen, seq);
3533 case TERM_CMD_DECRQCRA:
3534 return screen_DECRQCRA(screen, seq);
3535 case TERM_CMD_DECRQDE:
3536 return screen_DECRQDE(screen, seq);
3537 case TERM_CMD_DECRQKT:
3538 return screen_DECRQKT(screen, seq);
3539 case TERM_CMD_DECRQLP:
3540 return screen_DECRQLP(screen, seq);
3541 case TERM_CMD_DECRQM_ANSI:
3542 return screen_DECRQM_ANSI(screen, seq);
3543 case TERM_CMD_DECRQM_DEC:
3544 return screen_DECRQM_DEC(screen, seq);
3545 case TERM_CMD_DECRQPKFM:
3546 return screen_DECRQPKFM(screen, seq);
3547 case TERM_CMD_DECRQPSR:
3548 return screen_DECRQPSR(screen, seq);
3549 case TERM_CMD_DECRQTSR:
3550 return screen_DECRQTSR(screen, seq);
3551 case TERM_CMD_DECRQUPSS:
3552 return screen_DECRQUPSS(screen, seq);
3553 case TERM_CMD_DECSACE:
3554 return screen_DECSACE(screen, seq);
3555 case TERM_CMD_DECSASD:
3556 return screen_DECSASD(screen, seq);
3557 case TERM_CMD_DECSC:
3558 return screen_DECSC(screen, seq);
3559 case TERM_CMD_DECSCA:
3560 return screen_DECSCA(screen, seq);
3561 case TERM_CMD_DECSCL:
3562 return screen_DECSCL(screen, seq);
3563 case TERM_CMD_DECSCP:
3564 return screen_DECSCP(screen, seq);
3565 case TERM_CMD_DECSCPP:
3566 return screen_DECSCPP(screen, seq);
3567 case TERM_CMD_DECSCS:
3568 return screen_DECSCS(screen, seq);
3569 case TERM_CMD_DECSCUSR:
3570 return screen_DECSCUSR(screen, seq);
3571 case TERM_CMD_DECSDDT:
3572 return screen_DECSDDT(screen, seq);
3573 case TERM_CMD_DECSDPT:
3574 return screen_DECSDPT(screen, seq);
3575 case TERM_CMD_DECSED:
3576 return screen_DECSED(screen, seq);
3577 case TERM_CMD_DECSEL:
3578 return screen_DECSEL(screen, seq);
3579 case TERM_CMD_DECSERA:
3580 return screen_DECSERA(screen, seq);
3581 case TERM_CMD_DECSFC:
3582 return screen_DECSFC(screen, seq);
3583 case TERM_CMD_DECSKCV:
3584 return screen_DECSKCV(screen, seq);
3585 case TERM_CMD_DECSLCK:
3586 return screen_DECSLCK(screen, seq);
3587 case TERM_CMD_DECSLE:
3588 return screen_DECSLE(screen, seq);
3589 case TERM_CMD_DECSLPP:
3590 return screen_DECSLPP(screen, seq);
3591 case TERM_CMD_DECSLRM_OR_SC:
3592 return screen_DECSLRM_OR_SC(screen, seq);
3593 case TERM_CMD_DECSMBV:
3594 return screen_DECSMBV(screen, seq);
3595 case TERM_CMD_DECSMKR:
3596 return screen_DECSMKR(screen, seq);
3597 case TERM_CMD_DECSNLS:
3598 return screen_DECSNLS(screen, seq);
3599 case TERM_CMD_DECSPP:
3600 return screen_DECSPP(screen, seq);
3601 case TERM_CMD_DECSPPCS:
3602 return screen_DECSPPCS(screen, seq);
3603 case TERM_CMD_DECSPRTT:
3604 return screen_DECSPRTT(screen, seq);
3605 case TERM_CMD_DECSR:
3606 return screen_DECSR(screen, seq);
3607 case TERM_CMD_DECSRFR:
3608 return screen_DECSRFR(screen, seq);
3609 case TERM_CMD_DECSSCLS:
3610 return screen_DECSSCLS(screen, seq);
3611 case TERM_CMD_DECSSDT:
3612 return screen_DECSSDT(screen, seq);
3613 case TERM_CMD_DECSSL:
3614 return screen_DECSSL(screen, seq);
3615 case TERM_CMD_DECST8C:
3616 return screen_DECST8C(screen, seq);
3617 case TERM_CMD_DECSTBM:
3618 return screen_DECSTBM(screen, seq);
3619 case TERM_CMD_DECSTR:
3620 return screen_DECSTR(screen, seq);
3621 case TERM_CMD_DECSTRL:
3622 return screen_DECSTRL(screen, seq);
3623 case TERM_CMD_DECSWBV:
3624 return screen_DECSWBV(screen, seq);
3625 case TERM_CMD_DECSWL:
3626 return screen_DECSWL(screen, seq);
3627 case TERM_CMD_DECTID:
3628 return screen_DECTID(screen, seq);
3629 case TERM_CMD_DECTME:
3630 return screen_DECTME(screen, seq);
3631 case TERM_CMD_DECTST:
3632 return screen_DECTST(screen, seq);
3634 return screen_DL(screen, seq);
3635 case TERM_CMD_DSR_ANSI:
3636 return screen_DSR_ANSI(screen, seq);
3637 case TERM_CMD_DSR_DEC:
3638 return screen_DSR_DEC(screen, seq);
3640 return screen_ECH(screen, seq);
3642 return screen_ED(screen, seq);
3644 return screen_EL(screen, seq);
3646 return screen_ENQ(screen, seq);
3648 return screen_EPA(screen, seq);
3650 return screen_FF(screen, seq);
3652 return screen_HPA(screen, seq);
3654 return screen_HPR(screen, seq);
3656 return screen_HT(screen, seq);
3658 return screen_HTS(screen, seq);
3660 return screen_HVP(screen, seq);
3662 return screen_ICH(screen, seq);
3664 return screen_IL(screen, seq);
3666 return screen_IND(screen, seq);
3668 return screen_LF(screen, seq);
3670 return screen_LS1R(screen, seq);
3672 return screen_LS2(screen, seq);
3674 return screen_LS2R(screen, seq);
3676 return screen_LS3(screen, seq);
3678 return screen_LS3R(screen, seq);
3679 case TERM_CMD_MC_ANSI:
3680 return screen_MC_ANSI(screen, seq);
3681 case TERM_CMD_MC_DEC:
3682 return screen_MC_DEC(screen, seq);
3684 return screen_NEL(screen, seq);
3686 return screen_NP(screen, seq);
3688 return screen_NULL(screen, seq);
3690 return screen_PP(screen, seq);
3692 return screen_PPA(screen, seq);
3694 return screen_PPB(screen, seq);
3696 return screen_PPR(screen, seq);
3698 return screen_RC(screen, seq);
3700 return screen_REP(screen, seq);
3702 return screen_RI(screen, seq);
3704 return screen_RIS(screen, seq);
3705 case TERM_CMD_RM_ANSI:
3706 return screen_RM_ANSI(screen, seq);
3707 case TERM_CMD_RM_DEC:
3708 return screen_RM_DEC(screen, seq);
3709 case TERM_CMD_S7C1T:
3710 return screen_S7C1T(screen, seq);
3711 case TERM_CMD_S8C1T:
3712 return screen_S8C1T(screen, seq);
3714 return screen_SCS(screen, seq);
3716 return screen_SD(screen, seq);
3718 return screen_SGR(screen, seq);
3720 return screen_SI(screen, seq);
3721 case TERM_CMD_SM_ANSI:
3722 return screen_SM_ANSI(screen, seq);
3723 case TERM_CMD_SM_DEC:
3724 return screen_SM_DEC(screen, seq);
3726 return screen_SO(screen, seq);
3728 return screen_SPA(screen, seq);
3730 return screen_SS2(screen, seq);
3732 return screen_SS3(screen, seq);
3734 return screen_ST(screen, seq);
3736 return screen_SU(screen, seq);
3738 return screen_SUB(screen, seq);
3740 return screen_TBC(screen, seq);
3742 return screen_VPA(screen, seq);
3744 return screen_VPR(screen, seq);
3746 return screen_VT(screen, seq);
3747 case TERM_CMD_XTERM_CLLHP:
3748 return screen_XTERM_CLLHP(screen, seq);
3749 case TERM_CMD_XTERM_IHMT:
3750 return screen_XTERM_IHMT(screen, seq);
3751 case TERM_CMD_XTERM_MLHP:
3752 return screen_XTERM_MLHP(screen, seq);
3753 case TERM_CMD_XTERM_MUHP:
3754 return screen_XTERM_MUHP(screen, seq);
3755 case TERM_CMD_XTERM_RPM:
3756 return screen_XTERM_RPM(screen, seq);
3757 case TERM_CMD_XTERM_RRV:
3758 return screen_XTERM_RRV(screen, seq);
3759 case TERM_CMD_XTERM_RTM:
3760 return screen_XTERM_RTM(screen, seq);
3761 case TERM_CMD_XTERM_SACL1:
3762 return screen_XTERM_SACL1(screen, seq);
3763 case TERM_CMD_XTERM_SACL2:
3764 return screen_XTERM_SACL2(screen, seq);
3765 case TERM_CMD_XTERM_SACL3:
3766 return screen_XTERM_SACL3(screen, seq);
3767 case TERM_CMD_XTERM_SDCS:
3768 return screen_XTERM_SDCS(screen, seq);
3769 case TERM_CMD_XTERM_SGFX:
3770 return screen_XTERM_SGFX(screen, seq);
3771 case TERM_CMD_XTERM_SPM:
3772 return screen_XTERM_SPM(screen, seq);
3773 case TERM_CMD_XTERM_SRV:
3774 return screen_XTERM_SRV(screen, seq);
3775 case TERM_CMD_XTERM_STM:
3776 return screen_XTERM_STM(screen, seq);
3777 case TERM_CMD_XTERM_SUCS:
3778 return screen_XTERM_SUCS(screen, seq);
3779 case TERM_CMD_XTERM_WM:
3780 return screen_XTERM_WM(screen, seq);
3786 unsigned int term_screen_get_width(term_screen *screen) {
3787 assert_return(screen, -EINVAL);
3789 return screen->page->width;
3792 unsigned int term_screen_get_height(term_screen *screen) {
3793 assert_return(screen, -EINVAL);
3795 return screen->page->height;
3798 uint64_t term_screen_get_age(term_screen *screen) {
3799 assert_return(screen, 0);
3804 int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size) {
3806 size_t i, j, ucs4_len;
3807 const term_seq *seq;
3810 assert_return(screen, -EINVAL);
3814 /* Feed bytes into utf8 decoder and handle parsed ucs4 chars. We always
3815 * treat data as UTF-8, but the parser makes sure to fall back to raw
3816 * 8bit mode if the stream is not valid UTF-8. This should be more than
3817 * enough to support old 7bit/8bit modes. */
3818 for (i = 0; i < size; ++i) {
3819 ucs4_len = term_utf8_decode(&screen->utf8, &ucs4_str, in[i]);
3820 for (j = 0; j < ucs4_len; ++j) {
3821 r = term_parser_feed(screen->parser, &seq, ucs4_str[j]);
3824 } else if (r != TERM_SEQ_NONE) {
3825 r = screen_feed_cmd(screen, seq);
3835 static char *screen_map_key(term_screen *screen,
3837 const uint32_t *keysyms,
3840 const uint32_t *ucs4,
3841 unsigned int mods) {
3842 char ch, ch2, ch_mods;
3846 /* TODO: All these key-mappings need to be verified. Public information
3847 * on those mappings is pretty scarce and every emulator seems to do it
3848 * slightly differently.
3849 * A lot of mappings are also missing. */
3857 v = XKB_KEY_NoSymbol;
3859 /* In some mappings, the modifiers are encoded as CSI parameters. The
3860 * encoding is rather arbitrary, but seems to work. */
3862 switch (mods & (TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT | TERM_KBDMOD_CTRL)) {
3863 case TERM_KBDMOD_SHIFT:
3866 case TERM_KBDMOD_ALT:
3869 case TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT:
3872 case TERM_KBDMOD_CTRL:
3875 case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT:
3878 case TERM_KBDMOD_CTRL | TERM_KBDMOD_ALT:
3881 case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT:
3886 /* A user might actually use multiple layouts for keyboard
3887 * input. @keysyms[0] contains the actual keysym that the user
3888 * used. But if this keysym is not in the ascii range, the
3889 * input handler does check all other layouts that the user
3890 * specified whether one of them maps the key to some ASCII
3891 * keysym and provides this via @ascii. We always use the real
3892 * keysym except when handling CTRL+<XY> shortcuts we use the
3893 * ascii keysym. This is for compatibility to xterm et. al. so
3894 * ctrl+c always works regardless of the currently active
3895 * keyboard layout. But if no ascii-sym is found, we still use
3896 * the real keysym. */
3897 if (ascii == XKB_KEY_NoSymbol)
3900 /* map CTRL+<ascii> */
3901 if (mods & TERM_KBDMOD_CTRL) {
3904 /* Right hand side is mapped to the left and then
3905 * treated equally. Fall through to left-hand side.. */
3908 /* Printable ASCII is mapped 1-1 in XKB and in
3909 * combination with CTRL bit 7 is flipped. This
3910 * is equivalent to the caret-notation. */
3911 *p++ = ascii ^ 0x40;
3916 /* map cursor keys */
3940 if (screen->flags & TERM_FLAG_CURSOR_KEYS)
3953 /* map action keys */
3959 case XKB_KEY_Insert:
3962 case XKB_KEY_Delete:
3965 case XKB_KEY_Select:
3968 case XKB_KEY_Page_Up:
3971 case XKB_KEY_Page_Down:
3987 /* map lower function keys */
4020 /* map upper function keys */
4071 /* map special keys */
4073 case 0xff08: /* XKB_KEY_BackSpace */
4074 case 0xff09: /* XKB_KEY_Tab */
4075 case 0xff0a: /* XKB_KEY_Linefeed */
4076 case 0xff0b: /* XKB_KEY_Clear */
4077 case 0xff15: /* XKB_KEY_Sys_Req */
4078 case 0xff1b: /* XKB_KEY_Escape */
4079 case 0xffff: /* XKB_KEY_Delete */
4082 case 0xff13: /* XKB_KEY_Pause */
4083 /* TODO: What should we do with this key?
4084 * Sending XOFF is awful as there is no simple
4085 * way on modern keyboards to send XON again.
4086 * If someone wants this, we can re-eanble
4089 case 0xff14: /* XKB_KEY_Scroll_Lock */
4090 /* TODO: What should we do on scroll-lock?
4091 * Sending 0x14 is what the specs say but it is
4092 * not used today the way most users would
4093 * expect so we disable it. If someone wants
4094 * this, we can re-enable it (optionally). */
4096 case XKB_KEY_Return:
4098 if (screen->flags & TERM_FLAG_NEWLINE_MODE)
4101 case XKB_KEY_ISO_Left_Tab:
4106 /* map unicode keys */
4107 for (i = 0; i < n_syms; ++i)
4108 p += term_utf8_encode(p, ucs4[i]);
4113 int term_screen_feed_keyboard(term_screen *screen,
4114 const uint32_t *keysyms,
4117 const uint32_t *ucs4,
4118 unsigned int mods) {
4119 _cleanup_free_ char *dyn = NULL;
4120 static const size_t padding = 1;
4121 char buf[128], *start, *p;
4123 assert_return(screen, -EINVAL);
4125 /* allocate buffer if too small */
4127 if (4 * n_syms + padding > sizeof(buf)) {
4128 dyn = malloc(4 * n_syms + padding);
4135 /* reserve prefix space */
4139 p = screen_map_key(screen, p, keysyms, n_syms, ascii, ucs4, mods);
4140 if (!p || p - start < 1)
4143 /* The ALT modifier causes ESC to be prepended to any key-stroke. We
4144 * already accounted for that buffer space above, so simply prepend it
4146 * TODO: is altSendsEscape a suitable default? What are the semantics
4147 * exactly? Is it used in C0/C1 conversion? Is it prepended if there
4148 * already is an escape character? */
4149 if (mods & TERM_KBDMOD_ALT && *start != 0x1b)
4152 /* turn C0 into C1 */
4153 if (!(screen->flags & TERM_FLAG_7BIT_MODE) && p - start >= 2)
4154 if (start[0] == 0x1b && start[1] >= 0x40 && start[1] <= 0x5f)
4157 return screen_write(screen, start, p - start);
4160 int term_screen_resize(term_screen *screen, unsigned int x, unsigned int y) {
4165 assert_return(screen, -EINVAL);
4167 r = term_page_reserve(screen->page_main, x, y, &screen->state.attr, screen->age);
4171 r = term_page_reserve(screen->page_alt, x, y, &screen->state.attr, screen->age);
4175 if (x > screen->n_tabs) {
4176 t = realloc(screen->tabs, (x + 7) / 8);
4184 for (i = (screen->page->width + 7) / 8 * 8; i < x; i += 8)
4185 screen->tabs[i / 8] = 0x1;
4187 term_page_resize(screen->page_main, x, y, &screen->state.attr, screen->age, screen->history);
4188 term_page_resize(screen->page_alt, x, y, &screen->state.attr, screen->age, NULL);
4190 screen->state.cursor_x = screen_clamp_x(screen, screen->state.cursor_x);
4191 screen->state.cursor_y = screen_clamp_x(screen, screen->state.cursor_y);
4192 screen_cursor_clear_wrap(screen);
4197 void term_screen_soft_reset(term_screen *screen) {
4202 screen->g0 = &term_unicode_lower;
4203 screen->g1 = &term_unicode_upper;
4204 screen->g2 = &term_unicode_lower;
4205 screen->g3 = &term_unicode_upper;
4206 screen->state.attr = screen->default_attr;
4207 screen->state.gl = &screen->g0;
4208 screen->state.gr = &screen->g1;
4209 screen->state.glt = NULL;
4210 screen->state.grt = NULL;
4211 screen->state.auto_wrap = 0;
4212 screen->state.origin_mode = 0;
4214 screen->saved = screen->state;
4215 screen->saved.cursor_x = 0;
4216 screen->saved.cursor_y = 0;
4217 screen->saved_alt = screen->saved;
4219 screen->page = screen->page_main;
4220 screen->history = screen->history_main;
4221 screen->flags = TERM_FLAG_7BIT_MODE;
4222 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
4224 for (i = 0; i < screen->page->width; i += 8)
4225 screen->tabs[i / 8] = 0x1;
4227 term_page_set_scroll_region(screen->page_main, 0, screen->page->height);
4228 term_page_set_scroll_region(screen->page_alt, 0, screen->page->height);
4231 void term_screen_hard_reset(term_screen *screen) {
4234 term_screen_soft_reset(screen);
4236 screen->state.cursor_x = 0;
4237 screen->state.cursor_y = 0;
4238 term_page_erase(screen->page_main, 0, 0, screen->page->width, screen->page->height, &screen->state.attr, screen->age, false);
4239 term_page_erase(screen->page_alt, 0, 0, screen->page->width, screen->page->height, &screen->state.attr, screen->age, false);
4242 int term_screen_set_answerback(term_screen *screen, const char *answerback) {
4245 assert_return(screen, -EINVAL);
4248 t = strdup(answerback);
4253 free(screen->answerback);
4254 screen->answerback = t;
4259 int term_screen_draw(term_screen *screen,
4260 int (*draw_fn) (term_screen *screen,
4264 const term_attr *attr,
4267 unsigned int ch_width),
4270 uint64_t cell_age, line_age, age = 0;
4271 term_charbuf_t ch_buf;
4272 const uint32_t *ch_str;
4273 unsigned int i, j, cw;
4286 page = screen->page;
4288 for (j = 0; j < page->height; ++j) {
4289 line = page->lines[j];
4290 line_age = MAX(line->age, page->age);
4292 for (i = 0; i < page->width; ++i) {
4295 cell = &line->cells[i];
4296 cell_age = MAX(cell->age, line_age);
4298 if (age != 0 && cell_age <= age)
4301 ch_str = term_char_resolve(cell->ch, &ch_n, &ch_buf);
4303 /* Character-width of 0 is used for cleared cells.
4304 * Always treat this as single-cell character, so
4305 * renderers can assume ch_width is set properpy. */
4306 cw = MAX(cell->cwidth, 1U);
4309 if (i == screen->state.cursor_x && j == screen->state.cursor_y &&
4310 !(screen->flags & TERM_FLAG_HIDE_CURSOR))
4327 *fb_age = screen->age;