1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 * The term_screen layer implements the terminal-side. It handles all commands
25 * returned by the seq-parser and applies them to its own pages.
27 * While there are a lot of legacy control-sequences, we only support a small
28 * subset. There is no reason to implement unused codes like horizontal
30 * If you implement new commands, make sure to document them properly.
37 * http://www.vt100.net/emu/ctrlseq_dec.html
38 * http://www.vt100.net/docs/vt100-ug/chapter3.html
39 * http://www.vt100.net/docs/vt510-rm/chapter4
40 * http://www.vt100.net/docs/vt510-rm/contents
41 * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
43 * http://en.wikipedia.org/wiki/C0_and_C1_control_codes
44 * https://en.wikipedia.org/wiki/ANSI_color
50 #include <xkbcommon/xkbcommon-keysyms.h>
52 #include "term-internal.h"
55 int term_screen_new(term_screen **out, term_screen_write_fn write_fn, void *write_fn_data, term_screen_cmd_fn cmd_fn, void *cmd_fn_data) {
56 _cleanup_(term_screen_unrefp) term_screen *screen = NULL;
59 assert_return(out, -EINVAL);
61 screen = new0(term_screen, 1);
67 screen->write_fn = write_fn;
68 screen->write_fn_data = write_fn_data;
69 screen->cmd_fn = cmd_fn;
70 screen->cmd_fn_data = cmd_fn_data;
71 screen->flags = TERM_FLAG_7BIT_MODE;
72 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
73 screen->g0 = &term_unicode_lower;
74 screen->g1 = &term_unicode_upper;
75 screen->g2 = &term_unicode_lower;
76 screen->g3 = &term_unicode_upper;
77 screen->state.gl = &screen->g0;
78 screen->state.gr = &screen->g1;
79 screen->saved = screen->state;
80 screen->saved_alt = screen->saved;
82 r = term_page_new(&screen->page_main);
86 r = term_page_new(&screen->page_alt);
90 r = term_parser_new(&screen->parser, false);
94 r = term_history_new(&screen->history_main);
98 screen->page = screen->page_main;
99 screen->history = screen->history_main;
106 term_screen *term_screen_ref(term_screen *screen) {
110 assert_return(screen->ref > 0, NULL);
116 term_screen *term_screen_unref(term_screen *screen) {
120 assert_return(screen->ref > 0, NULL);
125 free(screen->answerback);
127 term_history_free(screen->history_main);
128 term_page_free(screen->page_alt);
129 term_page_free(screen->page_main);
130 term_parser_free(screen->parser);
138 * Unfortunately, 7bit/8bit compat mode requires us to send C1 controls encoded
139 * as 7bit if asked by the application. This is really used in the wild, so we
140 * cannot fall back to "always 7bit".
141 * screen_write() is the underlying backend which forwards any writes to the
142 * users's callback. It's the users responsibility to buffer these and write
143 * them out once their call to term_screen_feed_*() returns.
144 * The SEQ_WRITE() and SEQ_WRITE_KEY() macros allow constructing C0/C1 sequences
145 * directly in the code-base without requiring any intermediate buffer during
150 #define C1_CSI "\x9b"
152 #define SEQ(_screen, _prefix_esc, _c0, _c1, _seq) \
153 (((_screen)->flags & TERM_FLAG_7BIT_MODE) ? \
154 ((_prefix_esc) ? ("\e" _c0 _seq) : (_c0 _seq)) : \
155 ((_prefix_esc) ? ("\e" _c1 _seq) : (_c1 _seq)))
157 #define SEQ_SIZE(_screen, _prefix_esc, _c0, _c1, _seq) \
158 (((_screen)->flags & TERM_FLAG_7BIT_MODE) ? \
159 ((_prefix_esc) ? sizeof("\e" _c0 _seq) : sizeof(_c0 _seq)) : \
160 ((_prefix_esc) ? sizeof("\e" _c1 _seq) : sizeof(_c1 _seq)))
162 #define SEQ_WRITE_KEY(_screen, _prefix_esc, _c0, _c1, _seq) \
163 screen_write((_screen), \
164 SEQ((_screen), (_prefix_esc), \
166 SEQ_SIZE((_screen), (_prefix_esc), \
169 #define SEQ_WRITE(_screen, _c0, _c1, _seq) \
170 SEQ_WRITE_KEY((_screen), false, _c0, _c1, _seq)
172 static int screen_write(term_screen *screen, const void *buf, size_t len) {
173 if (len < 1 || !screen->write_fn)
176 return screen->write_fn(screen, screen->write_fn_data, buf, len);
181 * Some commands cannot be handled by the screen-layer directly. Those are
182 * forwarded to the command-handler of the caller. This is rarely used and can
183 * safely be set to NULL.
186 static int screen_forward(term_screen *screen, unsigned int cmd, const term_seq *seq) {
190 return screen->cmd_fn(screen, screen->cmd_fn_data, cmd, seq);
195 * These helpers implement common-operations like cursor-handler and more, which
196 * are used by several command dispatchers.
199 static unsigned int screen_clamp_x(term_screen *screen, unsigned int x) {
200 if (x >= screen->page->width)
201 return (screen->page->width > 0) ? screen->page->width - 1 : 0;
206 static unsigned int screen_clamp_y(term_screen *screen, unsigned int y) {
207 if (y >= screen->page->height)
208 return (screen->page->height > 0) ? screen->page->height - 1 : 0;
213 static bool screen_tab_is_set(term_screen *screen, unsigned int pos) {
214 if (pos >= screen->page->width)
217 return screen->tabs[pos / 8] & (1 << (pos % 8));
220 static inline void screen_age_cursor(term_screen *screen) {
223 cell = term_page_get_cell(screen->page, screen->state.cursor_x, screen->state.cursor_y);
225 cell->age = screen->age;
228 static void screen_cursor_clear_wrap(term_screen *screen) {
229 screen->flags &= ~TERM_FLAG_PENDING_WRAP;
232 static void screen_cursor_set(term_screen *screen, unsigned int x, unsigned int y) {
233 x = screen_clamp_x(screen, x);
234 y = screen_clamp_y(screen, y);
236 if (x == screen->state.cursor_x && y == screen->state.cursor_y)
239 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
240 screen_age_cursor(screen);
242 screen->state.cursor_x = x;
243 screen->state.cursor_y = y;
245 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
246 screen_age_cursor(screen);
249 static void screen_cursor_set_rel(term_screen *screen, unsigned int x, unsigned int y) {
250 if (screen->state.origin_mode) {
251 x = screen_clamp_x(screen, x);
252 y = screen_clamp_x(screen, y) + screen->page->scroll_idx;
254 if (y >= screen->page->scroll_idx + screen->page->scroll_num) {
255 y = screen->page->scroll_idx + screen->page->scroll_num;
256 if (screen->page->scroll_num > 0)
261 screen_cursor_set(screen, x, y);
264 static void screen_cursor_left(term_screen *screen, unsigned int num) {
265 if (num > screen->state.cursor_x)
266 num = screen->state.cursor_x;
268 screen_cursor_set(screen, screen->state.cursor_x - num, screen->state.cursor_y);
271 static void screen_cursor_left_tab(term_screen *screen, unsigned int num) {
274 i = screen->state.cursor_x;
275 while (i > 0 && num > 0) {
276 if (screen_tab_is_set(screen, --i))
280 screen_cursor_set(screen, i, screen->state.cursor_y);
283 static void screen_cursor_right(term_screen *screen, unsigned int num) {
284 if (num > screen->page->width)
285 num = screen->page->width;
287 screen_cursor_set(screen, screen->state.cursor_x + num, screen->state.cursor_y);
290 static void screen_cursor_right_tab(term_screen *screen, unsigned int num) {
293 i = screen->state.cursor_x;
294 while (i + 1 < screen->page->width && num > 0) {
295 if (screen_tab_is_set(screen, ++i))
299 screen_cursor_set(screen, i, screen->state.cursor_y);
302 static void screen_cursor_up(term_screen *screen, unsigned int num, bool scroll) {
305 if (screen->state.cursor_y < screen->page->scroll_idx) {
306 if (num > screen->state.cursor_y)
307 num = screen->state.cursor_y;
309 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num);
311 max = screen->state.cursor_y - screen->page->scroll_idx;
316 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
317 screen_age_cursor(screen);
320 term_page_scroll_down(screen->page, num - max, &screen->state.attr, screen->age, NULL);
322 screen->state.cursor_y = screen->page->scroll_idx;
324 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
325 screen_age_cursor(screen);
327 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num);
332 static void screen_cursor_down(term_screen *screen, unsigned int num, bool scroll) {
335 if (screen->state.cursor_y >= screen->page->scroll_idx + screen->page->scroll_num) {
336 if (num > screen->page->height)
337 num = screen->page->height;
339 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num);
341 max = screen->page->scroll_idx + screen->page->scroll_num - 1 - screen->state.cursor_y;
346 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
347 screen_age_cursor(screen);
350 term_page_scroll_up(screen->page, num - max, &screen->state.attr, screen->age, screen->history);
352 screen->state.cursor_y = screen->page->scroll_idx + screen->page->scroll_num - 1;
354 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
355 screen_age_cursor(screen);
357 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y + num);
362 static void screen_save_state(term_screen *screen, term_state *where) {
363 *where = screen->state;
366 static void screen_restore_state(term_screen *screen, term_state *from) {
367 screen_cursor_set(screen, from->cursor_x, from->cursor_y);
368 screen->state = *from;
371 static void screen_reset_page(term_screen *screen, term_page *page) {
372 term_page_set_scroll_region(page, 0, page->height);
373 term_page_erase(page, 0, 0, page->width, page->height, &screen->state.attr, screen->age, false);
376 static void screen_change_alt(term_screen *screen, bool set) {
378 screen->page = screen->page_alt;
379 screen->history = NULL;
381 screen->page = screen->page_main;
382 screen->history = screen->history_main;
385 screen->page->age = screen->age;
388 static inline void set_reset(term_screen *screen, unsigned int flag, bool set) {
390 screen->flags |= flag;
392 screen->flags &= ~flag;
395 static void screen_mode_change_ansi(term_screen *screen, unsigned mode, bool set) {
399 * LNM: line-feed/new-line mode
402 set_reset(screen, TERM_FLAG_NEWLINE_MODE, set);
406 log_debug("terminal: failed to %s unknown ANSI mode %u", set ? "set" : "unset", mode);
410 static void screen_mode_change_dec(term_screen *screen, unsigned int mode, bool set) {
414 * DECCKM: cursor-keys
417 set_reset(screen, TERM_FLAG_CURSOR_KEYS, set);
425 screen->state.origin_mode = set;
430 * DECAWN: auto-wrap mode
433 screen->state.auto_wrap = set;
438 * DECTCEM: text-cursor-enable
441 set_reset(screen, TERM_FLAG_HIDE_CURSOR, !set);
442 screen_age_cursor(screen);
447 * XTERM-ASB: alternate-screen-buffer
448 * This enables/disables the alternate screen-buffer.
449 * It effectively saves the current page content and
450 * allows you to restore it when changing to the
451 * original screen-buffer again.
453 screen_change_alt(screen, set);
458 * XTERM-ASBPE: alternate-screen-buffer-post-erase
459 * This is the same as XTERM-ASB but erases the
460 * alternate screen-buffer before switching back to the
461 * original buffer. Use it to discard any data on the
462 * alternate screen buffer when done.
465 screen_reset_page(screen, screen->page_alt);
467 screen_change_alt(screen, set);
472 * XTERM-ASBCS: alternate-screen-buffer-cursor-state
473 * This has the same effect as DECSC/DECRC, but uses a
474 * separate state buffer. It is usually used in
475 * combination with alternate screen buffers to provide
476 * stacked state storage.
479 screen_save_state(screen, &screen->saved_alt);
481 screen_restore_state(screen, &screen->saved_alt);
486 * XTERM-ASBX: alternate-screen-buffer-extended
487 * This combines XTERM-ASBPE and XTERM-ASBCS somewhat.
488 * When enabling, state is saved, alternate screen
489 * buffer is activated and cleared.
490 * When disabled, alternate screen buffer is cleared,
491 * then normal screen buffer is enabled and state is
495 screen_save_state(screen, &screen->saved_alt);
497 screen_reset_page(screen, screen->page_alt);
498 screen_change_alt(screen, set);
501 screen_restore_state(screen, &screen->saved_alt);
505 log_debug("terminal: failed to %s unknown DEC mode %u", set ? "set" : "unset", mode);
509 /* map a character according to current GL and GR maps */
510 static uint32_t screen_map(term_screen *screen, uint32_t val) {
513 /* 32 and 127 always map to identity. 160 and 255 map to identity iff a
514 * 96 character set is loaded into GR. Values above 255 always map to
518 if (screen->state.glt) {
519 nval = (**screen->state.glt)[val - 32];
520 screen->state.glt = NULL;
522 nval = (**screen->state.gl)[val - 32];
526 if (screen->state.grt) {
527 nval = (**screen->state.grt)[val - 160];
528 screen->state.grt = NULL;
530 nval = (**screen->state.gr)[val - 160];
535 return (nval == -1U) ? val : nval;
540 * This is the unofficial documentation of all the TERM_CMD_* definitions. Each
541 * handled command has a separate function with an extensive comment on the
542 * semantics of the command.
543 * Note that many semantics are unknown and need to be verified. This is mostly
544 * about error-handling, though. Applications rarely rely on those features.
547 static int screen_DA1(term_screen *screen, const term_seq *seq);
548 static int screen_LF(term_screen *screen, const term_seq *seq);
550 static int screen_GRAPHIC(term_screen *screen, const term_seq *seq) {
551 term_char_t ch = TERM_CHAR_NULL;
554 if (screen->state.cursor_x + 1 == screen->page->width
555 && screen->flags & TERM_FLAG_PENDING_WRAP
556 && screen->state.auto_wrap) {
557 screen_cursor_down(screen, 1, true);
558 screen_cursor_set(screen, 0, screen->state.cursor_y);
561 screen_cursor_clear_wrap(screen);
563 c = screen_map(screen, seq->terminator);
564 ch = term_char_merge(ch, screen_map(screen, c));
565 term_page_write(screen->page, screen->state.cursor_x, screen->state.cursor_y, ch, 1, &screen->state.attr, screen->age, false);
567 if (screen->state.cursor_x + 1 == screen->page->width)
568 screen->flags |= TERM_FLAG_PENDING_WRAP;
570 screen_cursor_right(screen, 1);
575 static int screen_BEL(term_screen *screen, const term_seq *seq) {
577 * BEL - sound bell tone
578 * This command should trigger an acoustic bell. Usually, this is
579 * forwarded directly to the pcspkr. However, bells have become quite
580 * uncommon and annoying, so we're not implementing them here. Instead,
581 * it's one of the commands we forward to the caller.
584 return screen_forward(screen, TERM_CMD_BEL, seq);
587 static int screen_BS(term_screen *screen, const term_seq *seq) {
590 * Move cursor one cell to the left. If already at the left margin,
594 screen_cursor_clear_wrap(screen);
595 screen_cursor_left(screen, 1);
599 static int screen_CBT(term_screen *screen, const term_seq *seq) {
601 * CBT - cursor-backward-tabulation
602 * Move the cursor @args[0] tabs backwards (to the left). The
603 * current cursor cell, in case it's a tab, is not counted.
604 * Furthermore, the cursor cannot be moved beyond position 0 and
605 * it will stop there.
611 unsigned int num = 1;
613 if (seq->args[0] > 0)
616 screen_cursor_clear_wrap(screen);
617 screen_cursor_left_tab(screen, num);
622 static int screen_CHA(term_screen *screen, const term_seq *seq) {
624 * CHA - cursor-horizontal-absolute
625 * Move the cursor to position @args[0] in the current line. The
626 * cursor cannot be moved beyond the rightmost cell and will stop
633 unsigned int pos = 1;
635 if (seq->args[0] > 0)
638 screen_cursor_clear_wrap(screen);
639 screen_cursor_set(screen, pos - 1, screen->state.cursor_y);
644 static int screen_CHT(term_screen *screen, const term_seq *seq) {
646 * CHT - cursor-horizontal-forward-tabulation
647 * Move the cursor @args[0] tabs forward (to the right). The
648 * current cursor cell, in case it's a tab, is not counted.
649 * Furthermore, the cursor cannot be moved beyond the rightmost cell
650 * and will stop there.
656 unsigned int num = 1;
658 if (seq->args[0] > 0)
661 screen_cursor_clear_wrap(screen);
662 screen_cursor_right_tab(screen, num);
667 static int screen_CNL(term_screen *screen, const term_seq *seq) {
669 * CNL - cursor-next-line
670 * Move the cursor @args[0] lines down.
672 * TODO: Does this stop at the bottom or cause a scroll-up?
678 unsigned int num = 1;
680 if (seq->args[0] > 0)
683 screen_cursor_clear_wrap(screen);
684 screen_cursor_down(screen, num, false);
689 static int screen_CPL(term_screen *screen, const term_seq *seq) {
691 * CPL - cursor-preceding-line
692 * Move the cursor @args[0] lines up.
694 * TODO: Does this stop at the top or cause a scroll-up?
700 unsigned int num = 1;
702 if (seq->args[0] > 0)
705 screen_cursor_clear_wrap(screen);
706 screen_cursor_up(screen, num, false);
711 static int screen_CR(term_screen *screen, const term_seq *seq) {
713 * CR - carriage-return
714 * Move the cursor to the left margin on the current line.
717 screen_cursor_clear_wrap(screen);
718 screen_cursor_set(screen, 0, screen->state.cursor_y);
723 static int screen_CUB(term_screen *screen, const term_seq *seq) {
725 * CUB - cursor-backward
726 * Move the cursor @args[0] positions to the left. The cursor stops
727 * at the left-most position.
733 unsigned int num = 1;
735 if (seq->args[0] > 0)
738 screen_cursor_clear_wrap(screen);
739 screen_cursor_left(screen, num);
744 static int screen_CUD(term_screen *screen, const term_seq *seq) {
747 * Move the cursor @args[0] positions down. The cursor stops at the
748 * bottom margin. If it was already moved further, it stops at the
755 unsigned int num = 1;
757 if (seq->args[0] > 0)
760 screen_cursor_clear_wrap(screen);
761 screen_cursor_down(screen, num, false);
766 static int screen_CUF(term_screen *screen, const term_seq *seq) {
768 * CUF -cursor-forward
769 * Move the cursor @args[0] positions to the right. The cursor stops
770 * at the right-most position.
776 unsigned int num = 1;
778 if (seq->args[0] > 0)
781 screen_cursor_clear_wrap(screen);
782 screen_cursor_right(screen, num);
787 static int screen_CUP(term_screen *screen, const term_seq *seq) {
789 * CUP - cursor-position
790 * Moves the cursor to position @args[1] x @args[0]. If either is 0, it
791 * is treated as 1. The positions are subject to the origin-mode and
792 * clamped to the addressable with/height.
799 unsigned int x = 1, y = 1;
801 if (seq->args[0] > 0)
803 if (seq->args[1] > 0)
806 screen_cursor_clear_wrap(screen);
807 screen_cursor_set_rel(screen, x - 1, y - 1);
812 static int screen_CUU(term_screen *screen, const term_seq *seq) {
815 * Move the cursor @args[0] positions up. The cursor stops at the
816 * top margin. If it was already moved further, it stops at the
824 unsigned int num = 1;
826 if (seq->args[0] > 0)
829 screen_cursor_clear_wrap(screen);
830 screen_cursor_up(screen, num, false);
835 static int screen_DA1(term_screen *screen, const term_seq *seq) {
837 * DA1 - primary-device-attributes
838 * The primary DA asks for basic terminal features. We simply return
839 * a hard-coded list of features we implement.
840 * Note that the primary DA asks for supported features, not currently
843 * The terminal's answer is:
845 * The first argument, 64, is fixed and denotes a VT420, the last
846 * DEC-term that extended this number.
847 * All following arguments denote supported features. Note
848 * that at most 15 features can be sent (max CSI args). It is safe to
849 * send more, but clients might not be able to parse them. This is a
850 * client's problem and we shouldn't care. There is no other way to
851 * send those feature lists, so we have to extend them beyond 15 in
856 * The 132 column mode is supported by the terminal.
858 * A priner-port is supported and can be addressed via
861 * Support for ReGIS graphics is available. The ReGIS routines
862 * provide the "remote graphics instruction set" and allow basic
865 * Support of Sixel graphics is available. This provides access
866 * to the sixel bitmap routines.
868 * The terminal supports DECSCA and related selective-erase
869 * functions. This allows to protect specific cells from being
870 * erased, if specified.
871 * 7: soft character set (DRCS)
873 * 8: user-defined keys (UDKs)
875 * 9: national-replacement character sets (NRCS)
876 * National-replacement character-sets are available.
877 * 12: Yugoslavian (SCS)
879 * 15: technical character set
880 * The DEC technical-character-set is available.
881 * 18: windowing capability
883 * 21: horizontal scrolling
891 * 29: ANSI text locator
893 * 42: ISO Latin-2 character set
899 * 46: ASCII emulation
903 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "?64;1;6;9;15c");
906 static int screen_DA2(term_screen *screen, const term_seq *seq) {
908 * DA2 - secondary-device-attributes
909 * The secondary DA asks for the terminal-ID, firmware versions and
910 * other non-primary attributes. All these values are
911 * informational-only and should not be used by the host to detect
914 * The terminal's response is:
915 * ^[ > 61 ; FIRMWARE ; KEYBOARD c
916 * whereas 65 is fixed for VT525 terminals, the last terminal-line that
917 * increased this number. FIRMWARE is the firmware
918 * version encoded as major/minor (20 == 2.0) and KEYBOARD is 0 for STD
919 * keyboard and 1 for PC keyboards.
921 * We replace the firmware-version with the systemd-version so clients
922 * can decode it again.
925 return SEQ_WRITE(screen, C0_CSI, C1_CSI, ">65;" PACKAGE_VERSION ";1c");
928 static int screen_DA3(term_screen *screen, const term_seq *seq) {
930 * DA3 - tertiary-device-attributes
931 * The tertiary DA is used to query the terminal-ID.
933 * The terminal's response is:
934 * ^P ! | XX AA BB CC ^\
935 * whereas all four parameters are hexadecimal-encoded pairs. XX
936 * denotes the manufacturing site, AA BB CC is the terminal's ID.
939 /* we do not support tertiary DAs */
943 static int screen_DC1(term_screen *screen, const term_seq *seq) {
945 * DC1 - device-control-1 or XON
946 * This clears any previous XOFF and resumes terminal-transmission.
949 /* we do not support XON */
953 static int screen_DC3(term_screen *screen, const term_seq *seq) {
955 * DC3 - device-control-3 or XOFF
956 * Stops terminal transmission. No further characters are sent until
957 * an XON is received.
960 /* we do not support XOFF */
964 static int screen_DCH(term_screen *screen, const term_seq *seq) {
966 * DCH - delete-character
967 * This deletes @argv[0] characters at the current cursor position. As
968 * characters are deleted, the remaining characters between the cursor
969 * and right margin move to the left. Character attributes move with the
970 * characters. The terminal adds blank spaces with no visual character
971 * attributes at the right margin. DCH has no effect outside the
978 unsigned int num = 1;
980 if (seq->args[0] > 0)
983 screen_cursor_clear_wrap(screen);
984 term_page_delete_cells(screen->page, screen->state.cursor_x, screen->state.cursor_y, num, &screen->state.attr, screen->age);
989 static int screen_DECALN(term_screen *screen, const term_seq *seq) {
991 * DECALN - screen-alignment-pattern
993 * Probably not worth implementing.
999 static int screen_DECANM(term_screen *screen, const term_seq *seq) {
1001 * DECANM - ansi-mode
1002 * Set the terminal into VT52 compatibility mode. Control sequences
1003 * overlap with regular sequences so we have to detect them early before
1006 * Probably not worth implementing.
1012 static int screen_DECBI(term_screen *screen, const term_seq *seq) {
1014 * DECBI - back-index
1015 * This control function moves the cursor backward one column. If the
1016 * cursor is at the left margin, then all screen data within the margin
1017 * moves one column to the right. The column that shifted past the right
1019 * DECBI adds a new column at the left margin with no visual attributes.
1020 * DECBI does not affect the margins. If the cursor is beyond the
1021 * left-margin at the left border, then the terminal ignores DECBI.
1023 * Probably not worth implementing.
1029 static int screen_DECCARA(term_screen *screen, const term_seq *seq) {
1031 * DECCARA - change-attributes-in-rectangular-area
1033 * Probably not worth implementing.
1039 static int screen_DECCRA(term_screen *screen, const term_seq *seq) {
1041 * DECCRA - copy-rectangular-area
1043 * Probably not worth implementing.
1049 static int screen_DECDC(term_screen *screen, const term_seq *seq) {
1051 * DECDC - delete-column
1053 * Probably not worth implementing.
1059 static int screen_DECDHL_BH(term_screen *screen, const term_seq *seq) {
1061 * DECDHL_BH - double-width-double-height-line: bottom half
1063 * Probably not worth implementing.
1069 static int screen_DECDHL_TH(term_screen *screen, const term_seq *seq) {
1071 * DECDHL_TH - double-width-double-height-line: top half
1073 * Probably not worth implementing.
1079 static int screen_DECDWL(term_screen *screen, const term_seq *seq) {
1081 * DECDWL - double-width-single-height-line
1083 * Probably not worth implementing.
1089 static int screen_DECEFR(term_screen *screen, const term_seq *seq) {
1091 * DECEFR - enable-filter-rectangle
1092 * Defines the coordinates of a filter rectangle (top, left, bottom,
1093 * right as @args[0] to @args[3]) and activates it.
1094 * Anytime the locator is detected outside of the filter rectangle, an
1095 * outside rectangle event is generated and the rectangle is disabled.
1096 * Filter rectangles are always treated as "one-shot" events. Any
1097 * parameters that are omitted default to the current locator position.
1098 * If all parameters are omitted, any locator motion will be reported.
1099 * DECELR always cancels any prevous rectangle definition.
1101 * The locator is usually associated with the mouse-cursor, but based
1102 * on cells instead of pixels. See DECELR how to initialize and enable
1103 * it. DECELR can also enable pixel-mode instead of cell-mode.
1111 static int screen_DECELF(term_screen *screen, const term_seq *seq) {
1113 * DECELF - enable-local-functions
1115 * Probably not worth implementing.
1121 static int screen_DECELR(term_screen *screen, const term_seq *seq) {
1123 * DECELR - enable-locator-reporting
1124 * This changes the locator-reporting mode. @args[0] specifies the mode
1125 * to set, 0 disables locator-reporting, 1 enables it continuously, 2
1126 * enables it for a single report. @args[1] specifies the
1127 * precision-mode. 0 and 2 set the reporting to cell-precision, 1 sets
1140 static int screen_DECERA(term_screen *screen, const term_seq *seq) {
1142 * DECERA - erase-rectangular-area
1144 * Probably not worth implementing.
1150 static int screen_DECFI(term_screen *screen, const term_seq *seq) {
1152 * DECFI - forward-index
1153 * This control function moves the cursor forward one column. If the
1154 * cursor is at the right margin, then all screen data within the
1155 * margins moves one column to the left. The column shifted past the
1156 * left margin is lost.
1157 * DECFI adds a new column at the right margin, with no visual
1158 * attributes. DECFI does not affect margins. If the cursor is beyond
1159 * the right margin at the border of the page when the terminal
1160 * receives DECFI, then the terminal ignores DECFI.
1162 * Probably not worth implementing.
1168 static int screen_DECFRA(term_screen *screen, const term_seq *seq) {
1170 * DECFRA - fill-rectangular-area
1172 * Probably not worth implementing.
1178 static int screen_DECIC(term_screen *screen, const term_seq *seq) {
1180 * DECIC - insert-column
1182 * Probably not worth implementing.
1188 static int screen_DECID(term_screen *screen, const term_seq *seq) {
1190 * DECID - return-terminal-id
1191 * This is an obsolete form of TERM_CMD_DA1.
1194 return screen_DA1(screen, seq);
1197 static int screen_DECINVM(term_screen *screen, const term_seq *seq) {
1199 * DECINVM - invoke-macro
1201 * Probably not worth implementing.
1207 static int screen_DECKBD(term_screen *screen, const term_seq *seq) {
1209 * DECKBD - keyboard-language-selection
1211 * Probably not worth implementing.
1217 static int screen_DECKPAM(term_screen *screen, const term_seq *seq) {
1219 * DECKPAM - keypad-application-mode
1220 * Enables the keypad-application mode. If enabled, the keypad sends
1221 * special characters instead of the printed characters. This way,
1222 * applications can detect whether a numeric key was pressed on the
1223 * top-row or on the keypad.
1224 * Default is keypad-numeric-mode.
1227 screen->flags |= TERM_FLAG_KEYPAD_MODE;
1232 static int screen_DECKPNM(term_screen *screen, const term_seq *seq) {
1234 * DECKPNM - keypad-numeric-mode
1235 * This disables the keypad-application-mode (DECKPAM) and returns to
1236 * the keypad-numeric-mode. Keypresses on the keypad generate the same
1237 * sequences as corresponding keypresses on the main keyboard.
1238 * Default is keypad-numeric-mode.
1241 screen->flags &= ~TERM_FLAG_KEYPAD_MODE;
1246 static int screen_DECLFKC(term_screen *screen, const term_seq *seq) {
1248 * DECLFKC - local-function-key-control
1250 * Probably not worth implementing.
1256 static int screen_DECLL(term_screen *screen, const term_seq *seq) {
1260 * Probably not worth implementing.
1266 static int screen_DECLTOD(term_screen *screen, const term_seq *seq) {
1268 * DECLTOD - load-time-of-day
1270 * Probably not worth implementing.
1276 static int screen_DECPCTERM(term_screen *screen, const term_seq *seq) {
1278 * DECPCTERM - pcterm-mode
1279 * This enters/exits the PCTerm mode. Default mode is VT-mode. It can
1280 * also select parameters for scancode/keycode mappings in SCO mode.
1282 * Definitely not worth implementing. Lets kill PCTerm/SCO modes!
1288 static int screen_DECPKA(term_screen *screen, const term_seq *seq) {
1290 * DECPKA - program-key-action
1292 * Probably not worth implementing.
1298 static int screen_DECPKFMR(term_screen *screen, const term_seq *seq) {
1300 * DECPKFMR - program-key-free-memory-report
1302 * Probably not worth implementing.
1308 static int screen_DECRARA(term_screen *screen, const term_seq *seq) {
1310 * DECRARA - reverse-attributes-in-rectangular-area
1312 * Probably not worth implementing.
1318 static int screen_DECRC(term_screen *screen, const term_seq *seq) {
1320 * DECRC - restore-cursor
1321 * Restores the terminal to the state saved by the save cursor (DECSC)
1322 * function. This includes more than just the cursor-position.
1324 * If nothing was saved by DECSC, then DECRC performs the following
1326 * * Moves the cursor to the home position (upper left of screen).
1327 * * Resets origin mode (DECOM).
1328 * * Turns all character attributes off (normal setting).
1329 * * Maps the ASCII character set into GL, and the DEC Supplemental
1330 * Graphic set into GR.
1332 * The terminal maintains a separate DECSC buffer for the main display
1333 * and the status line. This feature lets you save a separate operating
1334 * state for the main display and the status line.
1337 screen_restore_state(screen, &screen->saved);
1342 static int screen_DECREQTPARM(term_screen *screen, const term_seq *seq) {
1344 * DECREQTPARM - request-terminal-parameters
1345 * The sequence DECREPTPARM is sent by the terminal controller to notify
1346 * the host of the status of selected terminal parameters. The status
1347 * sequence may be sent when requested by the host or at the terminal's
1348 * discretion. DECREPTPARM is sent upon receipt of a DECREQTPARM.
1350 * If @args[0] is 0, this marks a request and the terminal is allowed
1351 * to send DECREPTPARM messages without request. If it is 1, the same
1352 * applies but the terminal should no longer send DECREPTPARM
1354 * 2 and 3 mark a report, but 3 is only used if the terminal answers as
1355 * an explicit request with @args[0] == 1.
1357 * The other arguments are ignored in requests, but have the following
1358 * meaning in responses:
1359 * args[1]: 1=no-parity-set 4=parity-set-and-odd 5=parity-set-and-even
1360 * args[2]: 1=8bits-per-char 2=7bits-per-char
1361 * args[3]: transmission-speed
1362 * args[4]: receive-speed
1363 * args[5]: 1=bit-rate-multiplier-is-16
1364 * args[6]: This value communicates the four switch values in block 5
1365 * of SETUP B, which are only visible to the user when an STP
1366 * option is installed. These bits may be assigned for an STP
1367 * device. The four bits are a decimal-encoded binary number.
1368 * Value between 0-15.
1370 * The transmission/receive speeds have mappings for number => bits/s
1371 * which are quite weird. Examples are: 96->3600, 112->9600, 120->19200
1377 if (seq->n_args < 1 || seq->args[0] == 0) {
1378 screen->flags &= ~TERM_FLAG_INHIBIT_TPARM;
1379 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "2;1;1;120;120;1;0x");
1380 } else if (seq->args[0] == 1) {
1381 screen->flags |= TERM_FLAG_INHIBIT_TPARM;
1382 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "3;1;1;120;120;1;0x");
1388 static int screen_DECRPKT(term_screen *screen, const term_seq *seq) {
1390 * DECRPKT - report-key-type
1391 * Response to DECRQKT, we can safely ignore it as we're the one sending
1398 static int screen_DECRQCRA(term_screen *screen, const term_seq *seq) {
1400 * DECRQCRA - request-checksum-of-rectangular-area
1402 * Probably not worth implementing.
1408 static int screen_DECRQDE(term_screen *screen, const term_seq *seq) {
1410 * DECRQDE - request-display-extent
1412 * Probably not worth implementing.
1418 static int screen_DECRQKT(term_screen *screen, const term_seq *seq) {
1420 * DECRQKT - request-key-type
1422 * Probably not worth implementing.
1428 static int screen_DECRQLP(term_screen *screen, const term_seq *seq) {
1430 * DECRQLP - request-locator-position
1431 * See DECELR for locator-information.
1433 * TODO: document and implement
1439 static int screen_DECRQM_ANSI(term_screen *screen, const term_seq *seq) {
1441 * DECRQM_ANSI - request-mode-ansi
1442 * The host sends this control function to find out if a particular mode
1443 * is set or reset. The terminal responds with a report mode function.
1444 * @args[0] contains the mode to query.
1446 * Response is DECRPM with the first argument set to the mode that was
1447 * queried, second argument is 0 if mode is invalid, 1 if mode is set,
1448 * 2 if mode is not set (reset), 3 if mode is permanently set and 4 if
1449 * mode is permanently not set (reset):
1450 * ANSI: ^[ MODE ; VALUE $ y
1451 * DEC: ^[ ? MODE ; VALUE $ y
1459 static int screen_DECRQM_DEC(term_screen *screen, const term_seq *seq) {
1461 * DECRQM_DEC - request-mode-dec
1462 * Same as DECRQM_ANSI but for DEC modes.
1470 static int screen_DECRQPKFM(term_screen *screen, const term_seq *seq) {
1472 * DECRQPKFM - request-program-key-free-memory
1474 * Probably not worth implementing.
1480 static int screen_DECRQPSR(term_screen *screen, const term_seq *seq) {
1482 * DECRQPSR - request-presentation-state-report
1484 * Probably not worth implementing.
1490 static int screen_DECRQTSR(term_screen *screen, const term_seq *seq) {
1492 * DECRQTSR - request-terminal-state-report
1494 * Probably not worth implementing.
1500 static int screen_DECRQUPSS(term_screen *screen, const term_seq *seq) {
1502 * DECRQUPSS - request-user-preferred-supplemental-set
1504 * Probably not worth implementing.
1510 static int screen_DECSACE(term_screen *screen, const term_seq *seq) {
1512 * DECSACE - select-attribute-change-extent
1514 * Probably not worth implementing.
1520 static int screen_DECSASD(term_screen *screen, const term_seq *seq) {
1522 * DECSASD - select-active-status-display
1524 * Probably not worth implementing.
1530 static int screen_DECSC(term_screen *screen, const term_seq *seq) {
1532 * DECSC - save-cursor
1533 * Save cursor and terminal state so it can be restored later on.
1534 * Saves the following items in the terminal's memory:
1536 * * Character attributes set by the SGR command
1537 * * Character sets (G0, G1, G2, or G3) currently in GL and GR
1538 * * Wrap flag (autowrap or no autowrap)
1539 * * State of origin mode (DECOM)
1540 * * Selective erase attribute
1541 * * Any single shift 2 (SS2) or single shift 3 (SS3) functions sent
1544 screen_save_state(screen, &screen->saved);
1549 static int screen_DECSCA(term_screen *screen, const term_seq *seq) {
1551 * DECSCA - select-character-protection-attribute
1552 * Defines the characters that come after it as erasable or not erasable
1553 * from the screen. The selective erase control functions (DECSED and
1554 * DECSEL) can only erase characters defined as erasable.
1556 * @args[0] specifies the new mode. 0 and 2 mark any following character
1557 * as erasable, 1 marks it as not erasable.
1563 unsigned int mode = 0;
1565 if (seq->args[0] > 0)
1566 mode = seq->args[0];
1571 screen->state.attr.protect = 0;
1574 screen->state.attr.protect = 1;
1581 static int screen_DECSCL(term_screen *screen, const term_seq *seq) {
1583 * DECSCL - select-conformance-level
1584 * Select the terminal's operating level. The factory default is
1585 * level 4 (VT Level 4 mode, 7-bit controls).
1586 * When you change the conformance level, the terminal performs a hard
1589 * @args[0] defines the conformance-level, valid values are:
1590 * 61: Level 1 (VT100)
1591 * 62: Level 2 (VT200)
1592 * 63: Level 3 (VT300)
1593 * 64: Level 4 (VT400)
1594 * @args[1] defines the 8bit-mode, valid values are:
1597 * 2: 8-bit controls (same as 0)
1599 * If @args[0] is 61, then @args[1] is ignored and 7bit controls are
1607 unsigned int level = 64, bit = 0;
1609 if (seq->n_args > 0) {
1610 level = seq->args[0];
1611 if (seq->n_args > 1)
1615 term_screen_hard_reset(screen);
1619 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT100;
1620 screen->flags |= TERM_FLAG_7BIT_MODE;
1623 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
1625 screen->flags |= TERM_FLAG_7BIT_MODE;
1627 screen->flags &= ~TERM_FLAG_7BIT_MODE;
1634 static int screen_DECSCP(term_screen *screen, const term_seq *seq) {
1636 * DECSCP - select-communication-port
1638 * Probably not worth implementing.
1644 static int screen_DECSCPP(term_screen *screen, const term_seq *seq) {
1646 * DECSCPP - select-columns-per-page
1647 * Select columns per page. The number of rows is unaffected by this.
1648 * @args[0] selectes the number of columns (width), DEC only defines 80
1649 * and 132, but we allow any integer here. 0 is equivalent to 80.
1650 * Page content is *not* cleared and the cursor is left untouched.
1651 * However, if the page is reduced in width and the cursor would be
1652 * outside the visible region, it's set to the right border. Newly added
1653 * cells are cleared. No data is retained outside the visible region.
1664 static int screen_DECSCS(term_screen *screen, const term_seq *seq) {
1666 * DECSCS - select-communication-speed
1668 * Probably not worth implementing.
1674 static int screen_DECSCUSR(term_screen *screen, const term_seq *seq) {
1676 * DECSCUSR - set-cursor-style
1677 * This changes the style of the cursor. @args[0] can be one of:
1678 * 0, 1: blinking block
1680 * 3: blinking underline
1681 * 4: steady underline
1682 * Changing this setting does _not_ affect the cursor visibility itself.
1683 * Use DECTCEM for that.
1694 static int screen_DECSDDT(term_screen *screen, const term_seq *seq) {
1696 * DECSDDT - select-disconnect-delay-time
1698 * Probably not worth implementing.
1704 static int screen_DECSDPT(term_screen *screen, const term_seq *seq) {
1706 * DECSDPT - select-digital-printed-data-type
1708 * Probably not worth implementing.
1714 static int screen_DECSED(term_screen *screen, const term_seq *seq) {
1716 * DECSED - selective-erase-in-display
1717 * This control function erases some or all of the erasable characters
1718 * in the display. DECSED can only erase characters defined as erasable
1719 * by the DECSCA control function. DECSED works inside or outside the
1720 * scrolling margins.
1722 * @args[0] defines which regions are erased. If it is 0, all cells from
1723 * the cursor (inclusive) till the end of the display are erase. If it
1724 * is 1, all cells from the start of the display till the cursor
1725 * (inclusive) are erased. If it is 2, all cells are erased.
1731 unsigned int mode = 0;
1733 if (seq->args[0] > 0)
1734 mode = seq->args[0];
1738 term_page_erase(screen->page,
1739 screen->state.cursor_x, screen->state.cursor_y,
1740 screen->page->width, screen->page->height,
1741 &screen->state.attr, screen->age, true);
1744 term_page_erase(screen->page,
1746 screen->state.cursor_x, screen->state.cursor_y,
1747 &screen->state.attr, screen->age, true);
1750 term_page_erase(screen->page,
1752 screen->page->width, screen->page->height,
1753 &screen->state.attr, screen->age, true);
1760 static int screen_DECSEL(term_screen *screen, const term_seq *seq) {
1762 * DECSEL - selective-erase-in-line
1763 * This control function erases some or all of the erasable characters
1764 * in a single line of text. DECSEL erases only those characters defined
1765 * as erasable by the DECSCA control function. DECSEL works inside or
1766 * outside the scrolling margins.
1768 * @args[0] defines the region to be erased. If it is 0, all cells from
1769 * the cursor (inclusive) till the end of the line are erase. If it is
1770 * 1, all cells from the start of the line till the cursor (inclusive)
1771 * are erased. If it is 2, the whole line of the cursor is erased.
1777 unsigned int mode = 0;
1779 if (seq->args[0] > 0)
1780 mode = seq->args[0];
1784 term_page_erase(screen->page,
1785 screen->state.cursor_x, screen->state.cursor_y,
1786 screen->page->width, screen->state.cursor_y,
1787 &screen->state.attr, screen->age, true);
1790 term_page_erase(screen->page,
1791 0, screen->state.cursor_y,
1792 screen->state.cursor_x, screen->state.cursor_y,
1793 &screen->state.attr, screen->age, true);
1796 term_page_erase(screen->page,
1797 0, screen->state.cursor_y,
1798 screen->page->width, screen->state.cursor_y,
1799 &screen->state.attr, screen->age, true);
1806 static int screen_DECSERA(term_screen *screen, const term_seq *seq) {
1808 * DECSERA - selective-erase-rectangular-area
1810 * Probably not worth implementing.
1816 static int screen_DECSFC(term_screen *screen, const term_seq *seq) {
1818 * DECSFC - select-flow-control
1820 * Probably not worth implementing.
1826 static int screen_DECSKCV(term_screen *screen, const term_seq *seq) {
1828 * DECSKCV - set-key-click-volume
1830 * Probably not worth implementing.
1836 static int screen_DECSLCK(term_screen *screen, const term_seq *seq) {
1838 * DECSLCK - set-lock-key-style
1840 * Probably not worth implementing.
1846 static int screen_DECSLE(term_screen *screen, const term_seq *seq) {
1848 * DECSLE - select-locator-events
1856 static int screen_DECSLPP(term_screen *screen, const term_seq *seq) {
1858 * DECSLPP - set-lines-per-page
1859 * Set the number of lines used for the page. @args[0] specifies the
1860 * number of lines to be used. DEC only allows a limited number of
1861 * choices, however, we allow all integers. 0 is equivalent to 24.
1872 static int screen_DECSLRM_OR_SC(term_screen *screen, const term_seq *seq) {
1874 * DECSLRM_OR_SC - set-left-and-right-margins or save-cursor
1876 * TODO: Detect save-cursor and run it. DECSLRM is not worth
1883 static int screen_DECSMBV(term_screen *screen, const term_seq *seq) {
1885 * DECSMBV - set-margin-bell-volume
1887 * Probably not worth implementing.
1893 static int screen_DECSMKR(term_screen *screen, const term_seq *seq) {
1895 * DECSMKR - select-modifier-key-reporting
1897 * Probably not worth implementing.
1903 static int screen_DECSNLS(term_screen *screen, const term_seq *seq) {
1905 * DECSNLS - set-lines-per-screen
1907 * Probably not worth implementing.
1913 static int screen_DECSPP(term_screen *screen, const term_seq *seq) {
1915 * DECSPP - set-port-parameter
1917 * Probably not worth implementing.
1923 static int screen_DECSPPCS(term_screen *screen, const term_seq *seq) {
1925 * DECSPPCS - select-pro-printer-character-set
1927 * Probably not worth implementing.
1933 static int screen_DECSPRTT(term_screen *screen, const term_seq *seq) {
1935 * DECSPRTT - select-printer-type
1937 * Probably not worth implementing.
1943 static int screen_DECSR(term_screen *screen, const term_seq *seq) {
1945 * DECSR - secure-reset
1947 * Probably not worth implementing.
1953 static int screen_DECSRFR(term_screen *screen, const term_seq *seq) {
1955 * DECSRFR - select-refresh-rate
1957 * Probably not worth implementing.
1963 static int screen_DECSSCLS(term_screen *screen, const term_seq *seq) {
1965 * DECSSCLS - set-scroll-speed
1967 * Probably not worth implementing.
1973 static int screen_DECSSDT(term_screen *screen, const term_seq *seq) {
1975 * DECSSDT - select-status-display-line-type
1977 * Probably not worth implementing.
1983 static int screen_DECSSL(term_screen *screen, const term_seq *seq) {
1985 * DECSSL - select-setup-language
1987 * Probably not worth implementing.
1993 static int screen_DECST8C(term_screen *screen, const term_seq *seq) {
1995 * DECST8C - set-tab-at-every-8-columns
1996 * Clear the tab-ruler and reset it to a tab at every 8th column,
1997 * starting at 9 (though, setting a tab at 1 is fine as it has no
2003 for (i = 0; i < screen->page->width; i += 8)
2004 screen->tabs[i / 8] = 0x1;
2009 static int screen_DECSTBM(term_screen *screen, const term_seq *seq) {
2011 * DECSTBM - set-top-and-bottom-margins
2012 * This control function sets the top and bottom margins for the current
2013 * page. You cannot perform scrolling outside the margins.
2015 * @args[0] defines the top margin, @args[1] defines the bottom margin.
2016 * The bottom margin must be lower than the top-margin.
2018 * This call resets the cursor position to 0/0 of the page.
2022 * args[1]: last page-line
2025 unsigned int top, bottom;
2028 bottom = screen->page->height;
2030 if (seq->args[0] > 0)
2032 if (seq->args[1] > 0)
2033 bottom = seq->args[1];
2035 if (top > screen->page->height)
2036 top = screen->page->height;
2037 if (bottom > screen->page->height)
2038 bottom = screen->page->height;
2040 if (top >= bottom || top > screen->page->height || bottom > screen->page->height) {
2042 bottom = screen->page->height;
2045 term_page_set_scroll_region(screen->page, top - 1, bottom - top + 1);
2046 screen_cursor_clear_wrap(screen);
2047 screen_cursor_set(screen, 0, 0);
2052 static int screen_DECSTR(term_screen *screen, const term_seq *seq) {
2054 * DECSTR - soft-terminal-reset
2055 * Perform a soft reset to the default values.
2058 term_screen_soft_reset(screen);
2063 static int screen_DECSTRL(term_screen *screen, const term_seq *seq) {
2065 * DECSTRL - set-transmit-rate-limit
2067 * Probably not worth implementing.
2073 static int screen_DECSWBV(term_screen *screen, const term_seq *seq) {
2075 * DECSWBV - set-warning-bell-volume
2077 * Probably not worth implementing.
2083 static int screen_DECSWL(term_screen *screen, const term_seq *seq) {
2085 * DECSWL - single-width-single-height-line
2087 * Probably not worth implementing.
2093 static int screen_DECTID(term_screen *screen, const term_seq *seq) {
2095 * DECTID - select-terminal-id
2097 * Probably not worth implementing.
2103 static int screen_DECTME(term_screen *screen, const term_seq *seq) {
2105 * DECTME - terminal-mode-emulation
2107 * Probably not worth implementing.
2113 static int screen_DECTST(term_screen *screen, const term_seq *seq) {
2115 * DECTST - invoke-confidence-test
2117 * Probably not worth implementing.
2123 static int screen_DL(term_screen *screen, const term_seq *seq) {
2126 * This control function deletes one or more lines in the scrolling
2127 * region, starting with the line that has the cursor. @args[0] defines
2128 * the number of lines to delete. 0 is treated the same as 1.
2129 * As lines are deleted, lines below the cursor and in the scrolling
2130 * region move up. The terminal adds blank lines with no visual
2131 * character attributes at the bottom of the scrolling region. If it is
2132 * greater than the number of lines remaining on the page, DL deletes
2133 * only the remaining lines. DL has no effect outside the scrolling
2140 unsigned int num = 1;
2142 if (seq->args[0] > 0)
2145 term_page_delete_lines(screen->page, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2150 static int screen_DSR_ANSI(term_screen *screen, const term_seq *seq) {
2152 * DSR_ANSI - device-status-report-ansi
2160 static int screen_DSR_DEC(term_screen *screen, const term_seq *seq) {
2162 * DSR_DEC - device-status-report-dec
2170 static int screen_ECH(term_screen *screen, const term_seq *seq) {
2172 * ECH - erase-character
2173 * This control function erases one or more characters, from the cursor
2174 * position to the right. ECH clears character attributes from erased
2175 * character positions. ECH works inside or outside the scrolling
2177 * @args[0] defines the number of characters to erase. 0 is treated the
2184 unsigned int num = 1;
2186 if (seq->args[0] > 0)
2189 term_page_erase(screen->page,
2190 screen->state.cursor_x, screen->state.cursor_y,
2191 screen->state.cursor_x + num, screen->state.cursor_y,
2192 &screen->state.attr, screen->age, false);
2197 static int screen_ED(term_screen *screen, const term_seq *seq) {
2199 * ED - erase-in-display
2200 * This control function erases characters from part or all of the
2201 * display. When you erase complete lines, they become single-height,
2202 * single-width lines, with all visual character attributes cleared. ED
2203 * works inside or outside the scrolling margins.
2205 * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2206 * till the end of the screen. 1 means from the start of the screen till
2207 * the cursor (inclusive) and 2 means the whole screen.
2213 unsigned int mode = 0;
2215 if (seq->args[0] > 0)
2216 mode = seq->args[0];
2220 term_page_erase(screen->page,
2221 screen->state.cursor_x, screen->state.cursor_y,
2222 screen->page->width, screen->page->height,
2223 &screen->state.attr, screen->age, false);
2226 term_page_erase(screen->page,
2228 screen->state.cursor_x, screen->state.cursor_y,
2229 &screen->state.attr, screen->age, false);
2232 term_page_erase(screen->page,
2234 screen->page->width, screen->page->height,
2235 &screen->state.attr, screen->age, false);
2242 static int screen_EL(term_screen *screen, const term_seq *seq) {
2244 * EL - erase-in-line
2245 * This control function erases characters on the line that has the
2246 * cursor. EL clears all character attributes from erased character
2247 * positions. EL works inside or outside the scrolling margins.
2249 * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2250 * till the end of the line. 1 means from the start of the line till the
2251 * cursor (inclusive) and 2 means the whole line.
2257 unsigned int mode = 0;
2259 if (seq->args[0] > 0)
2260 mode = seq->args[0];
2264 term_page_erase(screen->page,
2265 screen->state.cursor_x, screen->state.cursor_y,
2266 screen->page->width, screen->state.cursor_y,
2267 &screen->state.attr, screen->age, false);
2270 term_page_erase(screen->page,
2271 0, screen->state.cursor_y,
2272 screen->state.cursor_x, screen->state.cursor_y,
2273 &screen->state.attr, screen->age, false);
2276 term_page_erase(screen->page,
2277 0, screen->state.cursor_y,
2278 screen->page->width, screen->state.cursor_y,
2279 &screen->state.attr, screen->age, false);
2286 static int screen_ENQ(term_screen *screen, const term_seq *seq) {
2289 * Transmit the answerback-string. If none is set, do nothing.
2292 if (screen->answerback)
2293 return screen_write(screen, screen->answerback, strlen(screen->answerback));
2298 static int screen_EPA(term_screen *screen, const term_seq *seq) {
2300 * EPA - end-of-guarded-area
2302 * TODO: What is this?
2308 static int screen_FF(term_screen *screen, const term_seq *seq) {
2311 * This causes the cursor to jump to the next line. It is treated the
2315 return screen_LF(screen, seq);
2318 static int screen_HPA(term_screen *screen, const term_seq *seq) {
2320 * HPA - horizontal-position-absolute
2321 * HPA causes the active position to be moved to the n-th horizontal
2322 * position of the active line. If an attempt is made to move the active
2323 * position past the last position on the line, then the active position
2324 * stops at the last position on the line.
2326 * @args[0] defines the horizontal position. 0 is treated as 1.
2332 unsigned int num = 1;
2334 if (seq->args[0] > 0)
2337 screen_cursor_clear_wrap(screen);
2338 screen_cursor_set(screen, num - 1, screen->state.cursor_y);
2343 static int screen_HPR(term_screen *screen, const term_seq *seq) {
2345 * HPR - horizontal-position-relative
2346 * HPR causes the active position to be moved to the n-th following
2347 * horizontal position of the active line. If an attempt is made to move
2348 * the active position past the last position on the line, then the
2349 * active position stops at the last position on the line.
2351 * @args[0] defines the horizontal position. 0 is treated as 1.
2357 unsigned int num = 1;
2359 if (seq->args[0] > 0)
2362 screen_cursor_clear_wrap(screen);
2363 screen_cursor_right(screen, num);
2368 static int screen_HT(term_screen *screen, const term_seq *seq) {
2370 * HT - horizontal-tab
2371 * Moves the cursor to the next tab stop. If there are no more tab
2372 * stops, the cursor moves to the right margin. HT does not cause text
2376 screen_cursor_clear_wrap(screen);
2377 screen_cursor_right_tab(screen, 1);
2382 static int screen_HTS(term_screen *screen, const term_seq *seq) {
2384 * HTS - horizontal-tab-set
2385 * HTS sets a horizontal tab stop at the column position indicated by
2386 * the value of the active column when the terminal receives an HTS.
2388 * Executing an HTS does not effect the other horizontal tab stop
2394 pos = screen->state.cursor_x;
2395 if (screen->page->width > 0)
2396 screen->tabs[pos / 8] |= 1U << (pos % 8);
2401 static int screen_HVP(term_screen *screen, const term_seq *seq) {
2403 * HVP - horizontal-and-vertical-position
2404 * This control function works the same as the cursor position (CUP)
2405 * function. Origin mode (DECOM) selects line numbering and the ability
2406 * to move the cursor into margins.
2413 return screen_CUP(screen, seq);
2416 static int screen_ICH(term_screen *screen, const term_seq *seq) {
2418 * ICH - insert-character
2419 * This control function inserts one or more space (SP) characters
2420 * starting at the cursor position. @args[0] is the number of characters
2421 * to insert. 0 is treated as 1.
2423 * The ICH sequence inserts blank characters with the normal
2424 * character attribute. The cursor remains at the beginning of the blank
2425 * characters. Text between the cursor and right margin moves to the
2426 * right. Characters scrolled past the right margin are lost. ICH has no
2427 * effect outside the scrolling margins.
2433 unsigned int num = 1;
2435 if (seq->args[0] > 0)
2438 screen_cursor_clear_wrap(screen);
2439 term_page_insert_cells(screen->page, screen->state.cursor_x, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2444 static int screen_IL(term_screen *screen, const term_seq *seq) {
2447 * This control function inserts one or more blank lines, starting at
2448 * the cursor. @args[0] is the number of lines to insert. 0 is treated
2451 * As lines are inserted, lines below the cursor and in the scrolling
2452 * region move down. Lines scrolled off the page are lost. IL has no
2453 * effect outside the page margins.
2459 unsigned int num = 1;
2461 if (seq->args[0] > 0)
2464 screen_cursor_clear_wrap(screen);
2465 term_page_insert_lines(screen->page, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2470 static int screen_IND(term_screen *screen, const term_seq *seq) {
2473 * IND moves the cursor down one line in the same column. If the cursor
2474 * is at the bottom margin, then the screen performs a scroll-up.
2477 screen_cursor_down(screen, 1, true);
2482 static int screen_LF(term_screen *screen, const term_seq *seq) {
2485 * Causes a line feed or a new line operation, depending on the setting
2486 * of line feed/new line mode.
2489 screen_cursor_down(screen, 1, true);
2490 if (screen->flags & TERM_FLAG_NEWLINE_MODE)
2491 screen_cursor_left(screen, screen->state.cursor_x);
2496 static int screen_LS1R(term_screen *screen, const term_seq *seq) {
2498 * LS1R - locking-shift-1-right
2502 screen->state.gr = &screen->g1;
2507 static int screen_LS2(term_screen *screen, const term_seq *seq) {
2509 * LS2 - locking-shift-2
2513 screen->state.gl = &screen->g2;
2518 static int screen_LS2R(term_screen *screen, const term_seq *seq) {
2520 * LS2R - locking-shift-2-right
2524 screen->state.gr = &screen->g2;
2529 static int screen_LS3(term_screen *screen, const term_seq *seq) {
2531 * LS3 - locking-shift-3
2535 screen->state.gl = &screen->g3;
2540 static int screen_LS3R(term_screen *screen, const term_seq *seq) {
2542 * LS3R - locking-shift-3-right
2546 screen->state.gr = &screen->g3;
2551 static int screen_MC_ANSI(term_screen *screen, const term_seq *seq) {
2553 * MC_ANSI - media-copy-ansi
2555 * Probably not worth implementing.
2561 static int screen_MC_DEC(term_screen *screen, const term_seq *seq) {
2563 * MC_DEC - media-copy-dec
2565 * Probably not worth implementing.
2571 static int screen_NEL(term_screen *screen, const term_seq *seq) {
2574 * Moves cursor to first position on next line. If cursor is at bottom
2575 * margin, then screen performs a scroll-up.
2578 screen_cursor_clear_wrap(screen);
2579 screen_cursor_down(screen, 1, true);
2580 screen_cursor_set(screen, 0, screen->state.cursor_y);
2585 static int screen_NP(term_screen *screen, const term_seq *seq) {
2588 * This control function moves the cursor forward to the home position
2589 * on one of the following pages in page memory. If there is only one
2590 * page, then the terminal ignores NP.
2591 * If NP tries to move the cursor past the last page in memory, then the
2592 * cursor stops at the last page.
2594 * @args[0] defines the number of pages to forward. 0 is treated as 1.
2599 * Probably not worth implementing. We only support a single page.
2605 static int screen_NULL(term_screen *screen, const term_seq *seq) {
2608 * The NULL operation does nothing. ASCII NULL is always ignored.
2614 static int screen_PP(term_screen *screen, const term_seq *seq) {
2616 * PP - preceding-page
2617 * This control function moves the cursor backward to the home position
2618 * on one of the preceding pages in page memory. If there is only one
2619 * page, then the terminal ignores PP.
2620 * If PP tries to move the cursor back farther than the first page in
2621 * memory, then the cursor stops at the first page.
2623 * @args[0] defines the number of pages to go backwards. 0 is treated
2629 * Probably not worth implementing. We only support a single page.
2635 static int screen_PPA(term_screen *screen, const term_seq *seq) {
2637 * PPA - page-position-absolute
2638 * This control function can move the cursor to the corresponding row
2639 * and column on any page in page memory. You select the page by its
2640 * number. If there is only one page, then the terminal ignores PPA.
2642 * @args[0] is the number of the page to move the cursor to. If it is
2643 * greater than the number of the last page in memory, then the cursor
2644 * stops at the last page. If it is less than the number of the first
2645 * page, then the cursor stops at the first page.
2650 * Probably not worth implementing. We only support a single page.
2656 static int screen_PPB(term_screen *screen, const term_seq *seq) {
2658 * PPB - page-position-backward
2659 * This control function moves the cursor backward to the corresponding
2660 * row and column on one of the preceding pages in page memory. If there
2661 * is only one page, then the terminal ignores PPB.
2663 * @args[0] indicates the number of pages to move the cursor backward.
2664 * If it tries to move the cursor back farther than the first page in
2665 * memory, then the cursor stops at the first page. 0 is treated as 1.
2670 * Probably not worth implementing. We only support a single page.
2676 static int screen_PPR(term_screen *screen, const term_seq *seq) {
2678 * PPR - page-position-relative
2679 * This control function moves the cursor forward to the corresponding
2680 * row and column on one of the following pages in page memory. If there
2681 * is only one page, then the terminal ignores PPR.
2683 * @args[0] indicates how many pages to move the cursor forward. If it
2684 * tries to move the cursor beyond the last page in memory, then the
2685 * cursor stops at the last page. 0 is treated as 1.
2690 * Probably not worth implementing. We only support a single page.
2696 static int screen_RC(term_screen *screen, const term_seq *seq) {
2698 * RC - restore-cursor
2701 return screen_DECRC(screen, seq);
2704 static int screen_REP(term_screen *screen, const term_seq *seq) {
2707 * Repeat the preceding graphics-character the given number of times.
2708 * @args[0] specifies how often it shall be repeated. 0 is treated as 1.
2713 * Probably not worth implementing.
2719 static int screen_RI(term_screen *screen, const term_seq *seq) {
2721 * RI - reverse-index
2722 * Moves the cursor up one line in the same column. If the cursor is at
2723 * the top margin, the page scrolls down.
2726 screen_cursor_up(screen, 1, true);
2731 static int screen_RIS(term_screen *screen, const term_seq *seq) {
2733 * RIS - reset-to-initial-state
2734 * This control function causes a nonvolatile memory (NVR) recall to
2735 * occur. RIS replaces all set-up features with their saved settings.
2737 * The terminal stores these saved settings in NVR memory. The saved
2738 * setting for a feature is the same as the factory-default setting,
2739 * unless you saved a new setting.
2742 term_screen_hard_reset(screen);
2747 static int screen_RM_ANSI(term_screen *screen, const term_seq *seq) {
2749 * RM_ANSI - reset-mode-ansi
2751 * TODO: implement (see VT510rm manual)
2756 for (i = 0; i < seq->n_args; ++i)
2757 screen_mode_change_ansi(screen, seq->args[i], false);
2762 static int screen_RM_DEC(term_screen *screen, const term_seq *seq) {
2764 * RM_DEC - reset-mode-dec
2765 * This is the same as RM_ANSI but for DEC modes.
2770 for (i = 0; i < seq->n_args; ++i)
2771 screen_mode_change_dec(screen, seq->args[i], false);
2776 static int screen_S7C1T(term_screen *screen, const term_seq *seq) {
2778 * S7C1T - set-7bit-c1-terminal
2779 * This causes the terminal to start sending C1 controls as 7bit
2780 * sequences instead of 8bit C1 controls.
2781 * This is ignored if the terminal is below level-2 emulation mode
2782 * (VT100 and below), the terminal already sends 7bit controls then.
2785 if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2786 screen->flags |= TERM_FLAG_7BIT_MODE;
2791 static int screen_S8C1T(term_screen *screen, const term_seq *seq) {
2793 * S8C1T - set-8bit-c1-terminal
2794 * This causes the terminal to start sending C1 controls as 8bit C1
2795 * control instead of 7bit sequences.
2796 * This is ignored if the terminal is below level-2 emulation mode
2797 * (VT100 and below). The terminal always sends 7bit controls in those
2801 if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2802 screen->flags &= ~TERM_FLAG_7BIT_MODE;
2807 static int screen_SCS(term_screen *screen, const term_seq *seq) {
2809 * SCS - select-character-set
2810 * Designate character sets to G-sets. The mapping from intermediates
2811 * and terminal characters in the escape sequence to G-sets and
2812 * character-sets is non-trivial and implemented separately. See there
2813 * for more information.
2814 * This call simply sets the selected G-set to the desired
2818 term_charset *cs = NULL;
2820 /* TODO: support more of them? */
2821 switch (seq->charset) {
2822 case TERM_CHARSET_ISO_LATIN1_SUPPLEMENTAL:
2823 case TERM_CHARSET_ISO_LATIN2_SUPPLEMENTAL:
2824 case TERM_CHARSET_ISO_LATIN5_SUPPLEMENTAL:
2825 case TERM_CHARSET_ISO_GREEK_SUPPLEMENTAL:
2826 case TERM_CHARSET_ISO_HEBREW_SUPPLEMENTAL:
2827 case TERM_CHARSET_ISO_LATIN_CYRILLIC:
2830 case TERM_CHARSET_DEC_SPECIAL_GRAPHIC:
2831 cs = &term_dec_special_graphics;
2833 case TERM_CHARSET_DEC_SUPPLEMENTAL:
2834 cs = &term_dec_supplemental_graphics;
2836 case TERM_CHARSET_DEC_TECHNICAL:
2837 case TERM_CHARSET_CYRILLIC_DEC:
2838 case TERM_CHARSET_DUTCH_NRCS:
2839 case TERM_CHARSET_FINNISH_NRCS:
2840 case TERM_CHARSET_FRENCH_NRCS:
2841 case TERM_CHARSET_FRENCH_CANADIAN_NRCS:
2842 case TERM_CHARSET_GERMAN_NRCS:
2843 case TERM_CHARSET_GREEK_DEC:
2844 case TERM_CHARSET_GREEK_NRCS:
2845 case TERM_CHARSET_HEBREW_DEC:
2846 case TERM_CHARSET_HEBREW_NRCS:
2847 case TERM_CHARSET_ITALIAN_NRCS:
2848 case TERM_CHARSET_NORWEGIAN_DANISH_NRCS:
2849 case TERM_CHARSET_PORTUGUESE_NRCS:
2850 case TERM_CHARSET_RUSSIAN_NRCS:
2851 case TERM_CHARSET_SCS_NRCS:
2852 case TERM_CHARSET_SPANISH_NRCS:
2853 case TERM_CHARSET_SWEDISH_NRCS:
2854 case TERM_CHARSET_SWISS_NRCS:
2855 case TERM_CHARSET_TURKISH_DEC:
2856 case TERM_CHARSET_TURKISH_NRCS:
2859 case TERM_CHARSET_USERPREF_SUPPLEMENTAL:
2863 if (seq->intermediates & TERM_SEQ_FLAG_POPEN)
2864 screen->g0 = cs ? : &term_unicode_lower;
2865 else if (seq->intermediates & TERM_SEQ_FLAG_PCLOSE)
2866 screen->g1 = cs ? : &term_unicode_upper;
2867 else if (seq->intermediates & TERM_SEQ_FLAG_MULT)
2868 screen->g2 = cs ? : &term_unicode_lower;
2869 else if (seq->intermediates & TERM_SEQ_FLAG_PLUS)
2870 screen->g3 = cs ? : &term_unicode_upper;
2871 else if (seq->intermediates & TERM_SEQ_FLAG_MINUS)
2872 screen->g1 = cs ? : &term_unicode_upper;
2873 else if (seq->intermediates & TERM_SEQ_FLAG_DOT)
2874 screen->g2 = cs ? : &term_unicode_lower;
2875 else if (seq->intermediates & TERM_SEQ_FLAG_SLASH)
2876 screen->g3 = cs ? : &term_unicode_upper;
2881 static int screen_SD(term_screen *screen, const term_seq *seq) {
2884 * This control function moves the user window down a specified number
2885 * of lines in page memory.
2886 * @args[0] is the number of lines to move the
2887 * user window up in page memory. New lines appear at the top of the
2888 * display. Old lines disappear at the bottom of the display. You
2889 * cannot pan past the top margin of the current page. 0 is treated
2896 unsigned int num = 1;
2898 if (seq->args[0] > 0)
2901 term_page_scroll_down(screen->page, num, &screen->state.attr, screen->age, NULL);
2906 static int screen_SGR(term_screen *screen, const term_seq *seq) {
2908 * SGR - select-graphics-rendition
2912 unsigned int i, code;
2915 if (seq->n_args < 1) {
2916 zero(screen->state.attr);
2920 for (i = 0; i < seq->n_args; ++i) {
2924 screen->state.attr.bold = 1;
2927 screen->state.attr.italic = 1;
2930 screen->state.attr.underline = 1;
2933 screen->state.attr.blink = 1;
2936 screen->state.attr.inverse = 1;
2939 screen->state.attr.hidden = 1;
2942 screen->state.attr.bold = 0;
2945 screen->state.attr.italic = 0;
2948 screen->state.attr.underline = 0;
2951 screen->state.attr.blink = 0;
2954 screen->state.attr.inverse = 0;
2957 screen->state.attr.hidden = 0;
2960 screen->state.attr.fg.ccode = v - 30 + TERM_CCODE_BLACK;
2963 screen->state.attr.fg.ccode = 0;
2966 screen->state.attr.bg.ccode = v - 40 + TERM_CCODE_BLACK;
2969 screen->state.attr.bg.ccode = 0;
2972 screen->state.attr.fg.ccode = v - 90 + TERM_CCODE_LIGHT_BLACK;
2975 screen->state.attr.bg.ccode = v - 100 + TERM_CCODE_LIGHT_BLACK;
2982 dst = &screen->state.attr.fg;
2984 dst = &screen->state.attr.bg;
2987 if (i >= seq->n_args)
2990 switch (seq->args[i]) {
2992 /* 24bit-color support */
2995 if (i >= seq->n_args)
2998 dst->ccode = TERM_CCODE_RGB;
2999 dst->red = (seq->args[i - 2] >= 0) ? seq->args[i - 2] : 0;
3000 dst->green = (seq->args[i - 1] >= 0) ? seq->args[i - 1] : 0;
3001 dst->blue = (seq->args[i] >= 0) ? seq->args[i] : 0;
3005 /* 256-color support */
3008 if (i >= seq->n_args || seq->args[i] < 0)
3011 dst->ccode = TERM_CCODE_256;
3012 code = seq->args[i];
3013 dst->c256 = code < 256 ? code : 0;
3022 zero(screen->state.attr);
3030 static int screen_SI(term_screen *screen, const term_seq *seq) {
3036 screen->state.gl = &screen->g0;
3041 static int screen_SM_ANSI(term_screen *screen, const term_seq *seq) {
3043 * SM_ANSI - set-mode-ansi
3050 for (i = 0; i < seq->n_args; ++i)
3051 screen_mode_change_ansi(screen, seq->args[i], true);
3056 static int screen_SM_DEC(term_screen *screen, const term_seq *seq) {
3058 * SM_DEC - set-mode-dec
3059 * This is the same as SM_ANSI but for DEC modes.
3064 for (i = 0; i < seq->n_args; ++i)
3065 screen_mode_change_dec(screen, seq->args[i], true);
3070 static int screen_SO(term_screen *screen, const term_seq *seq) {
3076 screen->state.gl = &screen->g1;
3081 static int screen_SPA(term_screen *screen, const term_seq *seq) {
3083 * SPA - start-of-protected-area
3085 * TODO: What is this?
3091 static int screen_SS2(term_screen *screen, const term_seq *seq) {
3093 * SS2 - single-shift-2
3094 * Temporarily map G2 into GL for the next graphics character.
3097 screen->state.glt = &screen->g2;
3102 static int screen_SS3(term_screen *screen, const term_seq *seq) {
3104 * SS3 - single-shift-3
3105 * Temporarily map G3 into GL for the next graphics character
3108 screen->state.glt = &screen->g3;
3113 static int screen_ST(term_screen *screen, const term_seq *seq) {
3115 * ST - string-terminator
3116 * The string-terminator is usually part of control-sequences and
3117 * handled by the parser. In all other situations it is silently
3124 static int screen_SU(term_screen *screen, const term_seq *seq) {
3127 * This control function moves the user window up a specified number of
3128 * lines in page memory.
3129 * @args[0] is the number of lines to move the
3130 * user window down in page memory. New lines appear at the bottom of
3131 * the display. Old lines disappear at the top of the display. You
3132 * cannot pan past the bottom margin of the current page. 0 is treated
3139 unsigned int num = 1;
3141 if (seq->args[0] > 0)
3144 term_page_scroll_up(screen->page, num, &screen->state.attr, screen->age, screen->history);
3149 static int screen_SUB(term_screen *screen, const term_seq *seq) {
3152 * Cancel the current control-sequence and print a replacement
3153 * character. Our parser already handles this so all we have to do is
3154 * print the replacement character.
3157 static const term_seq rep = {
3158 .type = TERM_SEQ_GRAPHIC,
3159 .command = TERM_CMD_GRAPHIC,
3160 .terminator = 0xfffd,
3163 return screen_GRAPHIC(screen, &rep);
3166 static int screen_TBC(term_screen *screen, const term_seq *seq) {
3169 * This clears tab-stops. If @args[0] is 0, the tab-stop at the current
3170 * cursor position is cleared. If it is 3, all tab stops are cleared.
3176 unsigned int mode = 0, pos;
3178 if (seq->args[0] > 0)
3179 mode = seq->args[0];
3183 pos = screen->state.cursor_x;
3184 if (screen->page->width > 0)
3185 screen->tabs[pos / 8] &= ~(1U << (pos % 8));
3188 if (screen->page->width > 0)
3189 memset(screen->tabs, 0, (screen->page->width + 7) / 8);
3196 static int screen_VPA(term_screen *screen, const term_seq *seq) {
3198 * VPA - vertical-line-position-absolute
3199 * VPA causes the active position to be moved to the corresponding
3200 * horizontal position. @args[0] specifies the line to jump to. If an
3201 * attempt is made to move the active position below the last line, then
3202 * the active position stops on the last line. 0 is treated as 1.
3208 unsigned int pos = 1;
3210 if (seq->args[0] > 0)
3213 screen_cursor_clear_wrap(screen);
3214 screen_cursor_set_rel(screen, screen->state.cursor_x, pos - 1);
3219 static int screen_VPR(term_screen *screen, const term_seq *seq) {
3221 * VPR - vertical-line-position-relative
3222 * VPR causes the active position to be moved to the corresponding
3223 * horizontal position. @args[0] specifies the number of lines to jump
3224 * down relative to the current cursor position. If an attempt is made
3225 * to move the active position below the last line, the active position
3226 * stops at the last line. 0 is treated as 1.
3232 unsigned int num = 1;
3234 if (seq->args[0] > 0)
3237 screen_cursor_clear_wrap(screen);
3238 screen_cursor_down(screen, num, false);
3243 static int screen_VT(term_screen *screen, const term_seq *seq) {
3246 * This causes a vertical jump by one line. Terminals treat it exactly
3250 return screen_LF(screen, seq);
3253 static int screen_XTERM_CLLHP(term_screen *screen, const term_seq *seq) {
3255 * XTERM_CLLHP - xterm-cursor-lower-left-hp-bugfix
3256 * Move the cursor to the lower-left corner of the page. This is an HP
3259 * Probably not worth implementing.
3265 static int screen_XTERM_IHMT(term_screen *screen, const term_seq *seq) {
3267 * XTERM_IHMT - xterm-initiate-highlight-mouse-tracking
3269 * Probably not worth implementing.
3275 static int screen_XTERM_MLHP(term_screen *screen, const term_seq *seq) {
3277 * XTERM_MLHP - xterm-memory-lock-hp-bugfix
3279 * Probably not worth implementing.
3285 static int screen_XTERM_MUHP(term_screen *screen, const term_seq *seq) {
3287 * XTERM_MUHP - xterm-memory-unlock-hp-bugfix
3289 * Probably not worth implementing.
3295 static int screen_XTERM_RPM(term_screen *screen, const term_seq *seq) {
3297 * XTERM_RPM - xterm-restore-private-mode
3299 * Probably not worth implementing.
3305 static int screen_XTERM_RRV(term_screen *screen, const term_seq *seq) {
3307 * XTERM_RRV - xterm-reset-resource-value
3309 * Probably not worth implementing.
3315 static int screen_XTERM_RTM(term_screen *screen, const term_seq *seq) {
3317 * XTERM_RTM - xterm-reset-title-mode
3319 * Probably not worth implementing.
3325 static int screen_XTERM_SACL1(term_screen *screen, const term_seq *seq) {
3327 * XTERM_SACL1 - xterm-set-ansi-conformance-level-1
3329 * Probably not worth implementing.
3335 static int screen_XTERM_SACL2(term_screen *screen, const term_seq *seq) {
3337 * XTERM_SACL2 - xterm-set-ansi-conformance-level-2
3339 * Probably not worth implementing.
3345 static int screen_XTERM_SACL3(term_screen *screen, const term_seq *seq) {
3347 * XTERM_SACL3 - xterm-set-ansi-conformance-level-3
3349 * Probably not worth implementing.
3355 static int screen_XTERM_SDCS(term_screen *screen, const term_seq *seq) {
3357 * XTERM_SDCS - xterm-set-default-character-set
3358 * Select the default character set. We treat this the same as UTF-8 as
3359 * this is our default character set. As we always use UTF-8, this
3366 static int screen_XTERM_SGFX(term_screen *screen, const term_seq *seq) {
3368 * XTERM_SGFX - xterm-sixel-graphics
3370 * Probably not worth implementing.
3376 static int screen_XTERM_SPM(term_screen *screen, const term_seq *seq) {
3378 * XTERM_SPM - xterm-set-private-mode
3380 * Probably not worth implementing.
3386 static int screen_XTERM_SRV(term_screen *screen, const term_seq *seq) {
3388 * XTERM_SRV - xterm-set-resource-value
3390 * Probably not worth implementing.
3396 static int screen_XTERM_STM(term_screen *screen, const term_seq *seq) {
3398 * XTERM_STM - xterm-set-title-mode
3400 * Probably not worth implementing.
3406 static int screen_XTERM_SUCS(term_screen *screen, const term_seq *seq) {
3408 * XTERM_SUCS - xterm-select-utf8-character-set
3409 * Select UTF-8 as character set. This is our default on only character
3410 * set. Hence, this is a no-op.
3416 static int screen_XTERM_WM(term_screen *screen, const term_seq *seq) {
3418 * XTERM_WM - xterm-window-management
3420 * Probably not worth implementing.
3428 * The screen_feed_*() handlers take data from the user and feed it into the
3429 * screen. Once the parser has detected a sequence, we parse the command-type
3430 * and forward it to the command-dispatchers.
3433 static int screen_feed_cmd(term_screen *screen, const term_seq *seq) {
3434 switch (seq->command) {
3435 case TERM_CMD_GRAPHIC:
3436 return screen_GRAPHIC(screen, seq);
3438 return screen_BEL(screen, seq);
3440 return screen_BS(screen, seq);
3442 return screen_CBT(screen, seq);
3444 return screen_CHA(screen, seq);
3446 return screen_CHT(screen, seq);
3448 return screen_CNL(screen, seq);
3450 return screen_CPL(screen, seq);
3452 return screen_CR(screen, seq);
3454 return screen_CUB(screen, seq);
3456 return screen_CUD(screen, seq);
3458 return screen_CUF(screen, seq);
3460 return screen_CUP(screen, seq);
3462 return screen_CUU(screen, seq);
3464 return screen_DA1(screen, seq);
3466 return screen_DA2(screen, seq);
3468 return screen_DA3(screen, seq);
3470 return screen_DC1(screen, seq);
3472 return screen_DC3(screen, seq);
3474 return screen_DCH(screen, seq);
3475 case TERM_CMD_DECALN:
3476 return screen_DECALN(screen, seq);
3477 case TERM_CMD_DECANM:
3478 return screen_DECANM(screen, seq);
3479 case TERM_CMD_DECBI:
3480 return screen_DECBI(screen, seq);
3481 case TERM_CMD_DECCARA:
3482 return screen_DECCARA(screen, seq);
3483 case TERM_CMD_DECCRA:
3484 return screen_DECCRA(screen, seq);
3485 case TERM_CMD_DECDC:
3486 return screen_DECDC(screen, seq);
3487 case TERM_CMD_DECDHL_BH:
3488 return screen_DECDHL_BH(screen, seq);
3489 case TERM_CMD_DECDHL_TH:
3490 return screen_DECDHL_TH(screen, seq);
3491 case TERM_CMD_DECDWL:
3492 return screen_DECDWL(screen, seq);
3493 case TERM_CMD_DECEFR:
3494 return screen_DECEFR(screen, seq);
3495 case TERM_CMD_DECELF:
3496 return screen_DECELF(screen, seq);
3497 case TERM_CMD_DECELR:
3498 return screen_DECELR(screen, seq);
3499 case TERM_CMD_DECERA:
3500 return screen_DECERA(screen, seq);
3501 case TERM_CMD_DECFI:
3502 return screen_DECFI(screen, seq);
3503 case TERM_CMD_DECFRA:
3504 return screen_DECFRA(screen, seq);
3505 case TERM_CMD_DECIC:
3506 return screen_DECIC(screen, seq);
3507 case TERM_CMD_DECID:
3508 return screen_DECID(screen, seq);
3509 case TERM_CMD_DECINVM:
3510 return screen_DECINVM(screen, seq);
3511 case TERM_CMD_DECKBD:
3512 return screen_DECKBD(screen, seq);
3513 case TERM_CMD_DECKPAM:
3514 return screen_DECKPAM(screen, seq);
3515 case TERM_CMD_DECKPNM:
3516 return screen_DECKPNM(screen, seq);
3517 case TERM_CMD_DECLFKC:
3518 return screen_DECLFKC(screen, seq);
3519 case TERM_CMD_DECLL:
3520 return screen_DECLL(screen, seq);
3521 case TERM_CMD_DECLTOD:
3522 return screen_DECLTOD(screen, seq);
3523 case TERM_CMD_DECPCTERM:
3524 return screen_DECPCTERM(screen, seq);
3525 case TERM_CMD_DECPKA:
3526 return screen_DECPKA(screen, seq);
3527 case TERM_CMD_DECPKFMR:
3528 return screen_DECPKFMR(screen, seq);
3529 case TERM_CMD_DECRARA:
3530 return screen_DECRARA(screen, seq);
3531 case TERM_CMD_DECRC:
3532 return screen_DECRC(screen, seq);
3533 case TERM_CMD_DECREQTPARM:
3534 return screen_DECREQTPARM(screen, seq);
3535 case TERM_CMD_DECRPKT:
3536 return screen_DECRPKT(screen, seq);
3537 case TERM_CMD_DECRQCRA:
3538 return screen_DECRQCRA(screen, seq);
3539 case TERM_CMD_DECRQDE:
3540 return screen_DECRQDE(screen, seq);
3541 case TERM_CMD_DECRQKT:
3542 return screen_DECRQKT(screen, seq);
3543 case TERM_CMD_DECRQLP:
3544 return screen_DECRQLP(screen, seq);
3545 case TERM_CMD_DECRQM_ANSI:
3546 return screen_DECRQM_ANSI(screen, seq);
3547 case TERM_CMD_DECRQM_DEC:
3548 return screen_DECRQM_DEC(screen, seq);
3549 case TERM_CMD_DECRQPKFM:
3550 return screen_DECRQPKFM(screen, seq);
3551 case TERM_CMD_DECRQPSR:
3552 return screen_DECRQPSR(screen, seq);
3553 case TERM_CMD_DECRQTSR:
3554 return screen_DECRQTSR(screen, seq);
3555 case TERM_CMD_DECRQUPSS:
3556 return screen_DECRQUPSS(screen, seq);
3557 case TERM_CMD_DECSACE:
3558 return screen_DECSACE(screen, seq);
3559 case TERM_CMD_DECSASD:
3560 return screen_DECSASD(screen, seq);
3561 case TERM_CMD_DECSC:
3562 return screen_DECSC(screen, seq);
3563 case TERM_CMD_DECSCA:
3564 return screen_DECSCA(screen, seq);
3565 case TERM_CMD_DECSCL:
3566 return screen_DECSCL(screen, seq);
3567 case TERM_CMD_DECSCP:
3568 return screen_DECSCP(screen, seq);
3569 case TERM_CMD_DECSCPP:
3570 return screen_DECSCPP(screen, seq);
3571 case TERM_CMD_DECSCS:
3572 return screen_DECSCS(screen, seq);
3573 case TERM_CMD_DECSCUSR:
3574 return screen_DECSCUSR(screen, seq);
3575 case TERM_CMD_DECSDDT:
3576 return screen_DECSDDT(screen, seq);
3577 case TERM_CMD_DECSDPT:
3578 return screen_DECSDPT(screen, seq);
3579 case TERM_CMD_DECSED:
3580 return screen_DECSED(screen, seq);
3581 case TERM_CMD_DECSEL:
3582 return screen_DECSEL(screen, seq);
3583 case TERM_CMD_DECSERA:
3584 return screen_DECSERA(screen, seq);
3585 case TERM_CMD_DECSFC:
3586 return screen_DECSFC(screen, seq);
3587 case TERM_CMD_DECSKCV:
3588 return screen_DECSKCV(screen, seq);
3589 case TERM_CMD_DECSLCK:
3590 return screen_DECSLCK(screen, seq);
3591 case TERM_CMD_DECSLE:
3592 return screen_DECSLE(screen, seq);
3593 case TERM_CMD_DECSLPP:
3594 return screen_DECSLPP(screen, seq);
3595 case TERM_CMD_DECSLRM_OR_SC:
3596 return screen_DECSLRM_OR_SC(screen, seq);
3597 case TERM_CMD_DECSMBV:
3598 return screen_DECSMBV(screen, seq);
3599 case TERM_CMD_DECSMKR:
3600 return screen_DECSMKR(screen, seq);
3601 case TERM_CMD_DECSNLS:
3602 return screen_DECSNLS(screen, seq);
3603 case TERM_CMD_DECSPP:
3604 return screen_DECSPP(screen, seq);
3605 case TERM_CMD_DECSPPCS:
3606 return screen_DECSPPCS(screen, seq);
3607 case TERM_CMD_DECSPRTT:
3608 return screen_DECSPRTT(screen, seq);
3609 case TERM_CMD_DECSR:
3610 return screen_DECSR(screen, seq);
3611 case TERM_CMD_DECSRFR:
3612 return screen_DECSRFR(screen, seq);
3613 case TERM_CMD_DECSSCLS:
3614 return screen_DECSSCLS(screen, seq);
3615 case TERM_CMD_DECSSDT:
3616 return screen_DECSSDT(screen, seq);
3617 case TERM_CMD_DECSSL:
3618 return screen_DECSSL(screen, seq);
3619 case TERM_CMD_DECST8C:
3620 return screen_DECST8C(screen, seq);
3621 case TERM_CMD_DECSTBM:
3622 return screen_DECSTBM(screen, seq);
3623 case TERM_CMD_DECSTR:
3624 return screen_DECSTR(screen, seq);
3625 case TERM_CMD_DECSTRL:
3626 return screen_DECSTRL(screen, seq);
3627 case TERM_CMD_DECSWBV:
3628 return screen_DECSWBV(screen, seq);
3629 case TERM_CMD_DECSWL:
3630 return screen_DECSWL(screen, seq);
3631 case TERM_CMD_DECTID:
3632 return screen_DECTID(screen, seq);
3633 case TERM_CMD_DECTME:
3634 return screen_DECTME(screen, seq);
3635 case TERM_CMD_DECTST:
3636 return screen_DECTST(screen, seq);
3638 return screen_DL(screen, seq);
3639 case TERM_CMD_DSR_ANSI:
3640 return screen_DSR_ANSI(screen, seq);
3641 case TERM_CMD_DSR_DEC:
3642 return screen_DSR_DEC(screen, seq);
3644 return screen_ECH(screen, seq);
3646 return screen_ED(screen, seq);
3648 return screen_EL(screen, seq);
3650 return screen_ENQ(screen, seq);
3652 return screen_EPA(screen, seq);
3654 return screen_FF(screen, seq);
3656 return screen_HPA(screen, seq);
3658 return screen_HPR(screen, seq);
3660 return screen_HT(screen, seq);
3662 return screen_HTS(screen, seq);
3664 return screen_HVP(screen, seq);
3666 return screen_ICH(screen, seq);
3668 return screen_IL(screen, seq);
3670 return screen_IND(screen, seq);
3672 return screen_LF(screen, seq);
3674 return screen_LS1R(screen, seq);
3676 return screen_LS2(screen, seq);
3678 return screen_LS2R(screen, seq);
3680 return screen_LS3(screen, seq);
3682 return screen_LS3R(screen, seq);
3683 case TERM_CMD_MC_ANSI:
3684 return screen_MC_ANSI(screen, seq);
3685 case TERM_CMD_MC_DEC:
3686 return screen_MC_DEC(screen, seq);
3688 return screen_NEL(screen, seq);
3690 return screen_NP(screen, seq);
3692 return screen_NULL(screen, seq);
3694 return screen_PP(screen, seq);
3696 return screen_PPA(screen, seq);
3698 return screen_PPB(screen, seq);
3700 return screen_PPR(screen, seq);
3702 return screen_RC(screen, seq);
3704 return screen_REP(screen, seq);
3706 return screen_RI(screen, seq);
3708 return screen_RIS(screen, seq);
3709 case TERM_CMD_RM_ANSI:
3710 return screen_RM_ANSI(screen, seq);
3711 case TERM_CMD_RM_DEC:
3712 return screen_RM_DEC(screen, seq);
3713 case TERM_CMD_S7C1T:
3714 return screen_S7C1T(screen, seq);
3715 case TERM_CMD_S8C1T:
3716 return screen_S8C1T(screen, seq);
3718 return screen_SCS(screen, seq);
3720 return screen_SD(screen, seq);
3722 return screen_SGR(screen, seq);
3724 return screen_SI(screen, seq);
3725 case TERM_CMD_SM_ANSI:
3726 return screen_SM_ANSI(screen, seq);
3727 case TERM_CMD_SM_DEC:
3728 return screen_SM_DEC(screen, seq);
3730 return screen_SO(screen, seq);
3732 return screen_SPA(screen, seq);
3734 return screen_SS2(screen, seq);
3736 return screen_SS3(screen, seq);
3738 return screen_ST(screen, seq);
3740 return screen_SU(screen, seq);
3742 return screen_SUB(screen, seq);
3744 return screen_TBC(screen, seq);
3746 return screen_VPA(screen, seq);
3748 return screen_VPR(screen, seq);
3750 return screen_VT(screen, seq);
3751 case TERM_CMD_XTERM_CLLHP:
3752 return screen_XTERM_CLLHP(screen, seq);
3753 case TERM_CMD_XTERM_IHMT:
3754 return screen_XTERM_IHMT(screen, seq);
3755 case TERM_CMD_XTERM_MLHP:
3756 return screen_XTERM_MLHP(screen, seq);
3757 case TERM_CMD_XTERM_MUHP:
3758 return screen_XTERM_MUHP(screen, seq);
3759 case TERM_CMD_XTERM_RPM:
3760 return screen_XTERM_RPM(screen, seq);
3761 case TERM_CMD_XTERM_RRV:
3762 return screen_XTERM_RRV(screen, seq);
3763 case TERM_CMD_XTERM_RTM:
3764 return screen_XTERM_RTM(screen, seq);
3765 case TERM_CMD_XTERM_SACL1:
3766 return screen_XTERM_SACL1(screen, seq);
3767 case TERM_CMD_XTERM_SACL2:
3768 return screen_XTERM_SACL2(screen, seq);
3769 case TERM_CMD_XTERM_SACL3:
3770 return screen_XTERM_SACL3(screen, seq);
3771 case TERM_CMD_XTERM_SDCS:
3772 return screen_XTERM_SDCS(screen, seq);
3773 case TERM_CMD_XTERM_SGFX:
3774 return screen_XTERM_SGFX(screen, seq);
3775 case TERM_CMD_XTERM_SPM:
3776 return screen_XTERM_SPM(screen, seq);
3777 case TERM_CMD_XTERM_SRV:
3778 return screen_XTERM_SRV(screen, seq);
3779 case TERM_CMD_XTERM_STM:
3780 return screen_XTERM_STM(screen, seq);
3781 case TERM_CMD_XTERM_SUCS:
3782 return screen_XTERM_SUCS(screen, seq);
3783 case TERM_CMD_XTERM_WM:
3784 return screen_XTERM_WM(screen, seq);
3790 unsigned int term_screen_get_width(term_screen *screen) {
3791 assert_return(screen, -EINVAL);
3793 return screen->page->width;
3796 unsigned int term_screen_get_height(term_screen *screen) {
3797 assert_return(screen, -EINVAL);
3799 return screen->page->height;
3802 uint64_t term_screen_get_age(term_screen *screen) {
3803 assert_return(screen, 0);
3808 int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size) {
3810 size_t i, j, ucs4_len;
3811 const term_seq *seq;
3814 assert_return(screen, -EINVAL);
3818 /* Feed bytes into utf8 decoder and handle parsed ucs4 chars. We always
3819 * treat data as UTF-8, but the parser makes sure to fall back to raw
3820 * 8bit mode if the stream is not valid UTF-8. This should be more than
3821 * enough to support old 7bit/8bit modes. */
3822 for (i = 0; i < size; ++i) {
3823 ucs4_len = term_utf8_decode(&screen->utf8, &ucs4_str, in[i]);
3824 for (j = 0; j < ucs4_len; ++j) {
3825 r = term_parser_feed(screen->parser, &seq, ucs4_str[j]);
3828 } else if (r != TERM_SEQ_NONE) {
3829 r = screen_feed_cmd(screen, seq);
3839 static char *screen_map_key(term_screen *screen,
3841 const uint32_t *keysyms,
3844 const uint32_t *ucs4,
3845 unsigned int mods) {
3846 char ch, ch2, ch_mods;
3850 /* TODO: All these key-mappings need to be verified. Public information
3851 * on those mappings is pretty scarce and every emulator seems to do it
3852 * slightly differently.
3853 * A lot of mappings are also missing. */
3861 v = XKB_KEY_NoSymbol;
3863 /* In some mappings, the modifiers are encoded as CSI parameters. The
3864 * encoding is rather arbitrary, but seems to work. */
3866 switch (mods & (TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT | TERM_KBDMOD_CTRL)) {
3867 case TERM_KBDMOD_SHIFT:
3870 case TERM_KBDMOD_ALT:
3873 case TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT:
3876 case TERM_KBDMOD_CTRL:
3879 case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT:
3882 case TERM_KBDMOD_CTRL | TERM_KBDMOD_ALT:
3885 case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT:
3890 /* A user might actually use multiple layouts for keyboard
3891 * input. @keysyms[0] contains the actual keysym that the user
3892 * used. But if this keysym is not in the ascii range, the
3893 * input handler does check all other layouts that the user
3894 * specified whether one of them maps the key to some ASCII
3895 * keysym and provides this via @ascii. We always use the real
3896 * keysym except when handling CTRL+<XY> shortcuts we use the
3897 * ascii keysym. This is for compatibility to xterm et. al. so
3898 * ctrl+c always works regardless of the currently active
3899 * keyboard layout. But if no ascii-sym is found, we still use
3900 * the real keysym. */
3901 if (ascii == XKB_KEY_NoSymbol)
3904 /* map CTRL+<ascii> */
3905 if (mods & TERM_KBDMOD_CTRL) {
3908 /* Right hand side is mapped to the left and then
3909 * treated equally. Fall through to left-hand side.. */
3912 /* Printable ASCII is mapped 1-1 in XKB and in
3913 * combination with CTRL bit 7 is flipped. This
3914 * is equivalent to the caret-notation. */
3915 *p++ = ascii ^ 0x40;
3920 /* map cursor keys */
3944 if (screen->flags & TERM_FLAG_CURSOR_KEYS)
3957 /* map action keys */
3963 case XKB_KEY_Insert:
3966 case XKB_KEY_Delete:
3969 case XKB_KEY_Select:
3972 case XKB_KEY_Page_Up:
3975 case XKB_KEY_Page_Down:
3991 /* map lower function keys */
4024 /* map upper function keys */
4075 /* map special keys */
4077 case 0xff08: /* XKB_KEY_BackSpace */
4078 case 0xff09: /* XKB_KEY_Tab */
4079 case 0xff0a: /* XKB_KEY_Linefeed */
4080 case 0xff0b: /* XKB_KEY_Clear */
4081 case 0xff15: /* XKB_KEY_Sys_Req */
4082 case 0xff1b: /* XKB_KEY_Escape */
4083 case 0xffff: /* XKB_KEY_Delete */
4086 case 0xff13: /* XKB_KEY_Pause */
4087 /* TODO: What should we do with this key?
4088 * Sending XOFF is awful as there is no simple
4089 * way on modern keyboards to send XON again.
4090 * If someone wants this, we can re-eanble
4093 case 0xff14: /* XKB_KEY_Scroll_Lock */
4094 /* TODO: What should we do on scroll-lock?
4095 * Sending 0x14 is what the specs say but it is
4096 * not used today the way most users would
4097 * expect so we disable it. If someone wants
4098 * this, we can re-enable it (optionally). */
4100 case XKB_KEY_Return:
4102 if (screen->flags & TERM_FLAG_NEWLINE_MODE)
4105 case XKB_KEY_ISO_Left_Tab:
4110 /* map unicode keys */
4111 for (i = 0; i < n_syms; ++i)
4112 p += term_utf8_encode(p, ucs4[i]);
4117 int term_screen_feed_keyboard(term_screen *screen,
4118 const uint32_t *keysyms,
4121 const uint32_t *ucs4,
4122 unsigned int mods) {
4123 _cleanup_free_ char *dyn = NULL;
4124 static const size_t padding = 1;
4125 char buf[128], *start, *p;
4127 assert_return(screen, -EINVAL);
4129 /* allocate buffer if too small */
4131 if (4 * n_syms + padding > sizeof(buf)) {
4132 dyn = malloc(4 * n_syms + padding);
4139 /* reserve prefix space */
4143 p = screen_map_key(screen, p, keysyms, n_syms, ascii, ucs4, mods);
4144 if (!p || p - start < 1)
4147 /* The ALT modifier causes ESC to be prepended to any key-stroke. We
4148 * already accounted for that buffer space above, so simply prepend it
4150 * TODO: is altSendsEscape a suitable default? What are the semantics
4151 * exactly? Is it used in C0/C1 conversion? Is it prepended if there
4152 * already is an escape character? */
4153 if (mods & TERM_KBDMOD_ALT && *start != 0x1b)
4156 /* turn C0 into C1 */
4157 if (!(screen->flags & TERM_FLAG_7BIT_MODE) && p - start >= 2)
4158 if (start[0] == 0x1b && start[1] >= 0x40 && start[1] <= 0x5f)
4161 return screen_write(screen, start, p - start);
4164 int term_screen_resize(term_screen *screen, unsigned int x, unsigned int y) {
4169 assert_return(screen, -EINVAL);
4171 r = term_page_reserve(screen->page_main, x, y, &screen->state.attr, screen->age);
4175 r = term_page_reserve(screen->page_alt, x, y, &screen->state.attr, screen->age);
4179 if (x > screen->n_tabs) {
4180 t = realloc(screen->tabs, (x + 7) / 8);
4188 for (i = (screen->page->width + 7) / 8 * 8; i < x; i += 8)
4189 screen->tabs[i / 8] = 0x1;
4191 term_page_resize(screen->page_main, x, y, &screen->state.attr, screen->age, screen->history);
4192 term_page_resize(screen->page_alt, x, y, &screen->state.attr, screen->age, NULL);
4194 screen->state.cursor_x = screen_clamp_x(screen, screen->state.cursor_x);
4195 screen->state.cursor_y = screen_clamp_x(screen, screen->state.cursor_y);
4196 screen_cursor_clear_wrap(screen);
4201 void term_screen_soft_reset(term_screen *screen) {
4206 screen->g0 = &term_unicode_lower;
4207 screen->g1 = &term_unicode_upper;
4208 screen->g2 = &term_unicode_lower;
4209 screen->g3 = &term_unicode_upper;
4210 screen->state.attr = screen->default_attr;
4211 screen->state.gl = &screen->g0;
4212 screen->state.gr = &screen->g1;
4213 screen->state.glt = NULL;
4214 screen->state.grt = NULL;
4215 screen->state.auto_wrap = 0;
4216 screen->state.origin_mode = 0;
4218 screen->saved = screen->state;
4219 screen->saved.cursor_x = 0;
4220 screen->saved.cursor_y = 0;
4221 screen->saved_alt = screen->saved;
4223 screen->page = screen->page_main;
4224 screen->history = screen->history_main;
4225 screen->flags = TERM_FLAG_7BIT_MODE;
4226 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
4228 for (i = 0; i < screen->page->width; i += 8)
4229 screen->tabs[i / 8] = 0x1;
4231 term_page_set_scroll_region(screen->page_main, 0, screen->page->height);
4232 term_page_set_scroll_region(screen->page_alt, 0, screen->page->height);
4235 void term_screen_hard_reset(term_screen *screen) {
4238 term_screen_soft_reset(screen);
4240 screen->state.cursor_x = 0;
4241 screen->state.cursor_y = 0;
4242 term_page_erase(screen->page_main, 0, 0, screen->page->width, screen->page->height, &screen->state.attr, screen->age, false);
4243 term_page_erase(screen->page_alt, 0, 0, screen->page->width, screen->page->height, &screen->state.attr, screen->age, false);
4246 int term_screen_set_answerback(term_screen *screen, const char *answerback) {
4249 assert_return(screen, -EINVAL);
4252 t = strdup(answerback);
4257 free(screen->answerback);
4258 screen->answerback = t;
4263 int term_screen_draw(term_screen *screen,
4264 int (*draw_fn) (term_screen *screen,
4268 const term_attr *attr,
4271 unsigned int ch_width),
4274 uint64_t cell_age, line_age, age = 0;
4275 term_charbuf_t ch_buf;
4276 const uint32_t *ch_str;
4277 unsigned int i, j, cw;
4290 page = screen->page;
4292 for (j = 0; j < page->height; ++j) {
4293 line = page->lines[j];
4294 line_age = MAX(line->age, page->age);
4296 for (i = 0; i < page->width; ++i) {
4299 cell = &line->cells[i];
4300 cell_age = MAX(cell->age, line_age);
4302 if (age != 0 && cell_age <= age)
4305 ch_str = term_char_resolve(cell->ch, &ch_n, &ch_buf);
4307 /* Character-width of 0 is used for cleared cells.
4308 * Always treat this as single-cell character, so
4309 * renderers can assume ch_width is set properpy. */
4310 cw = MAX(cell->cwidth, 1U);
4313 if (i == screen->state.cursor_x && j == screen->state.cursor_y &&
4314 !(screen->flags & TERM_FLAG_HIDE_CURSOR))
4331 *fb_age = screen->age;