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->gl = &screen->g0;
74 screen->gr = &screen->g1;
75 screen->g0 = &term_unicode_lower;
76 screen->g1 = &term_unicode_upper;
77 screen->g2 = &term_unicode_lower;
78 screen->g3 = &term_unicode_upper;
80 screen->saved.cursor_x = 0;
81 screen->saved.cursor_y = 0;
82 screen->saved.attr = screen->attr;
83 screen->saved.gl = screen->gl;
84 screen->saved.gr = screen->gr;
86 r = term_page_new(&screen->page_main);
90 r = term_page_new(&screen->page_alt);
94 r = term_parser_new(&screen->parser, false);
98 r = term_history_new(&screen->history_main);
102 screen->page = screen->page_main;
103 screen->history = screen->history_main;
110 term_screen *term_screen_ref(term_screen *screen) {
114 assert_return(screen->ref > 0, NULL);
120 term_screen *term_screen_unref(term_screen *screen) {
124 assert_return(screen->ref > 0, NULL);
129 free(screen->answerback);
131 term_history_free(screen->history_main);
132 term_page_free(screen->page_alt);
133 term_page_free(screen->page_main);
134 term_parser_free(screen->parser);
142 * Unfortunately, 7bit/8bit compat mode requires us to send C1 controls encoded
143 * as 7bit if asked by the application. This is really used in the wild, so we
144 * cannot fall back to "always 7bit".
145 * screen_write() is the underlying backend which forwards any writes to the
146 * users's callback. It's the users responsibility to buffer these and write
147 * them out once their call to term_screen_feed_*() returns.
148 * The SEQ_WRITE() and SEQ_WRITE_KEY() macros allow constructing C0/C1 sequences
149 * directly in the code-base without requiring any intermediate buffer during
154 #define C1_CSI "\x9b"
156 #define SEQ(_screen, _prefix_esc, _c0, _c1, _seq) \
157 (((_screen)->flags & TERM_FLAG_7BIT_MODE) ? \
158 ((_prefix_esc) ? ("\e" _c0 _seq) : (_c0 _seq)) : \
159 ((_prefix_esc) ? ("\e" _c1 _seq) : (_c1 _seq)))
161 #define SEQ_SIZE(_screen, _prefix_esc, _c0, _c1, _seq) \
162 (((_screen)->flags & TERM_FLAG_7BIT_MODE) ? \
163 ((_prefix_esc) ? sizeof("\e" _c0 _seq) : sizeof(_c0 _seq)) : \
164 ((_prefix_esc) ? sizeof("\e" _c1 _seq) : sizeof(_c1 _seq)))
166 #define SEQ_WRITE_KEY(_screen, _prefix_esc, _c0, _c1, _seq) \
167 screen_write((_screen), \
168 SEQ((_screen), (_prefix_esc), \
170 SEQ_SIZE((_screen), (_prefix_esc), \
173 #define SEQ_WRITE(_screen, _c0, _c1, _seq) \
174 SEQ_WRITE_KEY((_screen), false, _c0, _c1, _seq)
176 static int screen_write(term_screen *screen, const void *buf, size_t len) {
177 if (len < 1 || !screen->write_fn)
180 return screen->write_fn(screen, screen->write_fn_data, buf, len);
185 * Some commands cannot be handled by the screen-layer directly. Those are
186 * forwarded to the command-handler of the caller. This is rarely used and can
187 * safely be set to NULL.
190 static int screen_forward(term_screen *screen, unsigned int cmd, const term_seq *seq) {
194 return screen->cmd_fn(screen, screen->cmd_fn_data, cmd, seq);
199 * These helpers implement common-operations like cursor-handler and more, which
200 * are used by several command dispatchers.
203 static unsigned int screen_clamp_x(term_screen *screen, unsigned int x) {
204 if (x >= screen->page->width)
205 return (screen->page->width > 0) ? screen->page->width - 1 : 0;
210 static unsigned int screen_clamp_y(term_screen *screen, unsigned int y) {
211 if (y >= screen->page->height)
212 return (screen->page->height > 0) ? screen->page->height - 1 : 0;
217 static bool screen_tab_is_set(term_screen *screen, unsigned int pos) {
218 if (pos >= screen->page->width)
221 return screen->tabs[pos / 8] & (1 << (pos % 8));
224 static inline void screen_age_cursor(term_screen *screen) {
227 cell = term_page_get_cell(screen->page, screen->cursor_x, screen->cursor_y);
229 cell->age = screen->age;
232 static void screen_cursor_clear_wrap(term_screen *screen) {
233 screen->flags &= ~TERM_FLAG_PENDING_WRAP;
236 static void screen_cursor_set(term_screen *screen, unsigned int x, unsigned int y) {
237 x = screen_clamp_x(screen, x);
238 y = screen_clamp_y(screen, y);
240 if (x == screen->cursor_x && y == screen->cursor_y)
243 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
244 screen_age_cursor(screen);
246 screen->cursor_x = x;
247 screen->cursor_y = y;
249 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
250 screen_age_cursor(screen);
253 static void screen_cursor_set_rel(term_screen *screen, unsigned int x, unsigned int y) {
254 if (screen->flags & TERM_FLAG_ORIGIN_MODE) {
255 x = screen_clamp_x(screen, x);
256 y = screen_clamp_x(screen, y) + screen->page->scroll_idx;
258 if (y >= screen->page->scroll_idx + screen->page->scroll_num) {
259 y = screen->page->scroll_idx + screen->page->scroll_num;
260 if (screen->page->scroll_num > 0)
265 screen_cursor_set(screen, x, y);
268 static void screen_cursor_left(term_screen *screen, unsigned int num) {
269 if (num > screen->cursor_x)
270 num = screen->cursor_x;
272 screen_cursor_set(screen, screen->cursor_x - num, screen->cursor_y);
275 static void screen_cursor_left_tab(term_screen *screen, unsigned int num) {
278 i = screen->cursor_x;
279 while (i > 0 && num > 0) {
280 if (screen_tab_is_set(screen, --i))
284 screen_cursor_set(screen, i, screen->cursor_y);
287 static void screen_cursor_right(term_screen *screen, unsigned int num) {
288 if (num > screen->page->width)
289 num = screen->page->width;
291 screen_cursor_set(screen, screen->cursor_x + num, screen->cursor_y);
294 static void screen_cursor_right_tab(term_screen *screen, unsigned int num) {
297 i = screen->cursor_x;
298 while (i + 1 < screen->page->width && num > 0) {
299 if (screen_tab_is_set(screen, ++i))
303 screen_cursor_set(screen, i, screen->cursor_y);
306 static void screen_cursor_up(term_screen *screen, unsigned int num, bool scroll) {
309 if (screen->cursor_y < screen->page->scroll_idx) {
310 if (num > screen->cursor_y)
311 num = screen->cursor_y;
313 screen_cursor_set(screen, screen->cursor_x, screen->cursor_y - num);
315 max = screen->cursor_y - screen->page->scroll_idx;
320 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
321 screen_age_cursor(screen);
324 term_page_scroll_down(screen->page, num - max, &screen->attr, screen->age, NULL);
326 screen->cursor_y = screen->page->scroll_idx;
328 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
329 screen_age_cursor(screen);
331 screen_cursor_set(screen, screen->cursor_x, screen->cursor_y - num);
336 static void screen_cursor_down(term_screen *screen, unsigned int num, bool scroll) {
339 if (screen->cursor_y >= screen->page->scroll_idx + screen->page->scroll_num) {
340 if (num > screen->page->height)
341 num = screen->page->height;
343 screen_cursor_set(screen, screen->cursor_x, screen->cursor_y - num);
345 max = screen->page->scroll_idx + screen->page->scroll_num - 1 - screen->cursor_y;
350 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
351 screen_age_cursor(screen);
354 term_page_scroll_up(screen->page, num - max, &screen->attr, screen->age, screen->history);
356 screen->cursor_y = screen->page->scroll_idx + screen->page->scroll_num - 1;
358 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
359 screen_age_cursor(screen);
361 screen_cursor_set(screen, screen->cursor_x, screen->cursor_y + num);
366 static inline void set_reset(term_screen *screen, unsigned int flag, bool set) {
368 screen->flags |= flag;
370 screen->flags &= ~flag;
373 static void screen_mode_change(term_screen *screen, unsigned int mode, bool dec, bool set) {
378 * DECCKM: cursor-keys
381 set_reset(screen, TERM_FLAG_CURSOR_KEYS, set);
391 set_reset(screen, TERM_FLAG_ORIGIN_MODE, set);
398 * DECAWN: auto-wrap mode
401 set_reset(screen, TERM_FLAG_AUTO_WRAP, set);
408 * LNM: line-feed/new-line mode
411 set_reset(screen, TERM_FLAG_NEWLINE_MODE, set);
418 * DECTCEM: text-cursor-enable
421 set_reset(screen, TERM_FLAG_HIDE_CURSOR, !set);
428 /* map a character according to current GL and GR maps */
429 static uint32_t screen_map(term_screen *screen, uint32_t val) {
432 /* 32 and 127 always map to identity. 160 and 255 map to identity iff a
433 * 96 character set is loaded into GR. Values above 255 always map to
438 nval = (**screen->glt)[val - 32];
441 nval = (**screen->gl)[val - 32];
446 nval = (**screen->grt)[val - 160];
449 nval = (**screen->gr)[val - 160];
454 return (nval == -1U) ? val : nval;
459 * This is the unofficial documentation of all the TERM_CMD_* definitions. Each
460 * handled command has a separate function with an extensive comment on the
461 * semantics of the command.
462 * Note that many semantics are unknown and need to be verified. This is mostly
463 * about error-handling, though. Applications rarely rely on those features.
466 static int screen_DA1(term_screen *screen, const term_seq *seq);
467 static int screen_LF(term_screen *screen, const term_seq *seq);
469 static int screen_GRAPHIC(term_screen *screen, const term_seq *seq) {
470 term_char_t ch = TERM_CHAR_NULL;
473 if (screen->cursor_x + 1 == screen->page->width
474 && screen->flags & TERM_FLAG_PENDING_WRAP
475 && screen->flags & TERM_FLAG_AUTO_WRAP) {
476 screen_cursor_down(screen, 1, true);
477 screen_cursor_set(screen, 0, screen->cursor_y);
480 screen_cursor_clear_wrap(screen);
482 c = screen_map(screen, seq->terminator);
483 ch = term_char_merge(ch, screen_map(screen, c));
484 term_page_write(screen->page, screen->cursor_x, screen->cursor_y, ch, 1, &screen->attr, screen->age, false);
486 if (screen->cursor_x + 1 == screen->page->width)
487 screen->flags |= TERM_FLAG_PENDING_WRAP;
489 screen_cursor_right(screen, 1);
494 static int screen_BEL(term_screen *screen, const term_seq *seq) {
496 * BEL - sound bell tone
497 * This command should trigger an acoustic bell. Usually, this is
498 * forwarded directly to the pcspkr. However, bells have become quite
499 * uncommon and annoying, so we're not implementing them here. Instead,
500 * it's one of the commands we forward to the caller.
503 return screen_forward(screen, TERM_CMD_BEL, seq);
506 static int screen_BS(term_screen *screen, const term_seq *seq) {
509 * Move cursor one cell to the left. If already at the left margin,
513 screen_cursor_clear_wrap(screen);
514 screen_cursor_left(screen, 1);
518 static int screen_CBT(term_screen *screen, const term_seq *seq) {
520 * CBT - cursor-backward-tabulation
521 * Move the cursor @args[0] tabs backwards (to the left). The
522 * current cursor cell, in case it's a tab, is not counted.
523 * Furthermore, the cursor cannot be moved beyond position 0 and
524 * it will stop there.
530 unsigned int num = 1;
532 if (seq->args[0] > 0)
535 screen_cursor_clear_wrap(screen);
536 screen_cursor_left_tab(screen, num);
541 static int screen_CHA(term_screen *screen, const term_seq *seq) {
543 * CHA - cursor-horizontal-absolute
544 * Move the cursor to position @args[0] in the current line. The
545 * cursor cannot be moved beyond the rightmost cell and will stop
552 unsigned int pos = 1;
554 if (seq->args[0] > 0)
557 screen_cursor_clear_wrap(screen);
558 screen_cursor_set(screen, pos - 1, screen->cursor_y);
563 static int screen_CHT(term_screen *screen, const term_seq *seq) {
565 * CHT - cursor-horizontal-forward-tabulation
566 * Move the cursor @args[0] tabs forward (to the right). The
567 * current cursor cell, in case it's a tab, is not counted.
568 * Furthermore, the cursor cannot be moved beyond the rightmost cell
569 * and will stop there.
575 unsigned int num = 1;
577 if (seq->args[0] > 0)
580 screen_cursor_clear_wrap(screen);
581 screen_cursor_right_tab(screen, num);
586 static int screen_CNL(term_screen *screen, const term_seq *seq) {
588 * CNL - cursor-next-line
589 * Move the cursor @args[0] lines down.
591 * TODO: Does this stop at the bottom or cause a scroll-up?
597 unsigned int num = 1;
599 if (seq->args[0] > 0)
602 screen_cursor_clear_wrap(screen);
603 screen_cursor_down(screen, num, false);
608 static int screen_CPL(term_screen *screen, const term_seq *seq) {
610 * CPL - cursor-preceding-line
611 * Move the cursor @args[0] lines up.
613 * TODO: Does this stop at the top or cause a scroll-up?
619 unsigned int num = 1;
621 if (seq->args[0] > 0)
624 screen_cursor_clear_wrap(screen);
625 screen_cursor_up(screen, num, false);
630 static int screen_CR(term_screen *screen, const term_seq *seq) {
632 * CR - carriage-return
633 * Move the cursor to the left margin on the current line.
636 screen_cursor_clear_wrap(screen);
637 screen_cursor_set(screen, 0, screen->cursor_y);
642 static int screen_CUB(term_screen *screen, const term_seq *seq) {
644 * CUB - cursor-backward
645 * Move the cursor @args[0] positions to the left. The cursor stops
646 * at the left-most position.
652 unsigned int num = 1;
654 if (seq->args[0] > 0)
657 screen_cursor_clear_wrap(screen);
658 screen_cursor_left(screen, num);
663 static int screen_CUD(term_screen *screen, const term_seq *seq) {
666 * Move the cursor @args[0] positions down. The cursor stops at the
667 * bottom margin. If it was already moved further, it stops at the
674 unsigned int num = 1;
676 if (seq->args[0] > 0)
679 screen_cursor_clear_wrap(screen);
680 screen_cursor_down(screen, num, false);
685 static int screen_CUF(term_screen *screen, const term_seq *seq) {
687 * CUF -cursor-forward
688 * Move the cursor @args[0] positions to the right. The cursor stops
689 * at the right-most position.
695 unsigned int num = 1;
697 if (seq->args[0] > 0)
700 screen_cursor_clear_wrap(screen);
701 screen_cursor_right(screen, num);
706 static int screen_CUP(term_screen *screen, const term_seq *seq) {
708 * CUP - cursor-position
709 * Moves the cursor to position @args[1] x @args[0]. If either is 0, it
710 * is treated as 1. The positions are subject to the origin-mode and
711 * clamped to the addressable with/height.
718 unsigned int x = 1, y = 1;
720 if (seq->args[0] > 0)
722 if (seq->args[1] > 0)
725 screen_cursor_clear_wrap(screen);
726 screen_cursor_set_rel(screen, x - 1, y - 1);
731 static int screen_CUU(term_screen *screen, const term_seq *seq) {
734 * Move the cursor @args[0] positions up. The cursor stops at the
735 * top margin. If it was already moved further, it stops at the
743 unsigned int num = 1;
745 if (seq->args[0] > 0)
748 screen_cursor_clear_wrap(screen);
749 screen_cursor_up(screen, num, false);
754 static int screen_DA1(term_screen *screen, const term_seq *seq) {
756 * DA1 - primary-device-attributes
757 * The primary DA asks for basic terminal features. We simply return
758 * a hard-coded list of features we implement.
759 * Note that the primary DA asks for supported features, not currently
762 * The terminal's answer is:
764 * The first argument, 64, is fixed and denotes a VT420, the last
765 * DEC-term that extended this number.
766 * All following arguments denote supported features. Note
767 * that at most 15 features can be sent (max CSI args). It is safe to
768 * send more, but clients might not be able to parse them. This is a
769 * client's problem and we shouldn't care. There is no other way to
770 * send those feature lists, so we have to extend them beyond 15 in
775 * The 132 column mode is supported by the terminal.
777 * A priner-port is supported and can be addressed via
780 * Support for ReGIS graphics is available. The ReGIS routines
781 * provide the "remote graphics instruction set" and allow basic
784 * Support of Sixel graphics is available. This provides access
785 * to the sixel bitmap routines.
787 * The terminal supports DECSCA and related selective-erase
788 * functions. This allows to protect specific cells from being
789 * erased, if specified.
790 * 7: soft character set (DRCS)
792 * 8: user-defined keys (UDKs)
794 * 9: national-replacement character sets (NRCS)
795 * National-replacement character-sets are available.
796 * 12: Yugoslavian (SCS)
798 * 15: technical character set
799 * The DEC technical-character-set is available.
800 * 18: windowing capability
802 * 21: horizontal scrolling
810 * 29: ANSI text locator
812 * 42: ISO Latin-2 character set
818 * 46: ASCII emulation
822 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "?64;1;6;9;15c");
825 static int screen_DA2(term_screen *screen, const term_seq *seq) {
827 * DA2 - secondary-device-attributes
828 * The secondary DA asks for the terminal-ID, firmware versions and
829 * other non-primary attributes. All these values are
830 * informational-only and should not be used by the host to detect
833 * The terminal's response is:
834 * ^[ > 61 ; FIRMWARE ; KEYBOARD c
835 * whereas 65 is fixed for VT525 terminals, the last terminal-line that
836 * increased this number. FIRMWARE is the firmware
837 * version encoded as major/minor (20 == 2.0) and KEYBOARD is 0 for STD
838 * keyboard and 1 for PC keyboards.
840 * We replace the firmware-version with the systemd-version so clients
841 * can decode it again.
844 return SEQ_WRITE(screen, C0_CSI, C1_CSI, ">65;" PACKAGE_VERSION ";1c");
847 static int screen_DA3(term_screen *screen, const term_seq *seq) {
849 * DA3 - tertiary-device-attributes
850 * The tertiary DA is used to query the terminal-ID.
852 * The terminal's response is:
853 * ^P ! | XX AA BB CC ^\
854 * whereas all four parameters are hexadecimal-encoded pairs. XX
855 * denotes the manufacturing site, AA BB CC is the terminal's ID.
858 /* we do not support tertiary DAs */
862 static int screen_DC1(term_screen *screen, const term_seq *seq) {
864 * DC1 - device-control-1 or XON
865 * This clears any previous XOFF and resumes terminal-transmission.
868 /* we do not support XON */
872 static int screen_DC3(term_screen *screen, const term_seq *seq) {
874 * DC3 - device-control-3 or XOFF
875 * Stops terminal transmission. No further characters are sent until
876 * an XON is received.
879 /* we do not support XOFF */
883 static int screen_DCH(term_screen *screen, const term_seq *seq) {
885 * DCH - delete-character
886 * This deletes @argv[0] characters at the current cursor position. As
887 * characters are deleted, the remaining characters between the cursor
888 * and right margin move to the left. Character attributes move with the
889 * characters. The terminal adds blank spaces with no visual character
890 * attributes at the right margin. DCH has no effect outside the
897 unsigned int num = 1;
899 if (seq->args[0] > 0)
902 screen_cursor_clear_wrap(screen);
903 term_page_delete_cells(screen->page, screen->cursor_x, screen->cursor_y, num, &screen->attr, screen->age);
908 static int screen_DECALN(term_screen *screen, const term_seq *seq) {
910 * DECALN - screen-alignment-pattern
912 * Probably not worth implementing.
918 static int screen_DECANM(term_screen *screen, const term_seq *seq) {
921 * Set the terminal into VT52 compatibility mode. Control sequences
922 * overlap with regular sequences so we have to detect them early before
925 * Probably not worth implementing.
931 static int screen_DECBI(term_screen *screen, const term_seq *seq) {
934 * This control function moves the cursor backward one column. If the
935 * cursor is at the left margin, then all screen data within the margin
936 * moves one column to the right. The column that shifted past the right
938 * DECBI adds a new column at the left margin with no visual attributes.
939 * DECBI does not affect the margins. If the cursor is beyond the
940 * left-margin at the left border, then the terminal ignores DECBI.
942 * Probably not worth implementing.
948 static int screen_DECCARA(term_screen *screen, const term_seq *seq) {
950 * DECCARA - change-attributes-in-rectangular-area
952 * Probably not worth implementing.
958 static int screen_DECCRA(term_screen *screen, const term_seq *seq) {
960 * DECCRA - copy-rectangular-area
962 * Probably not worth implementing.
968 static int screen_DECDC(term_screen *screen, const term_seq *seq) {
970 * DECDC - delete-column
972 * Probably not worth implementing.
978 static int screen_DECDHL_BH(term_screen *screen, const term_seq *seq) {
980 * DECDHL_BH - double-width-double-height-line: bottom half
982 * Probably not worth implementing.
988 static int screen_DECDHL_TH(term_screen *screen, const term_seq *seq) {
990 * DECDHL_TH - double-width-double-height-line: top half
992 * Probably not worth implementing.
998 static int screen_DECDWL(term_screen *screen, const term_seq *seq) {
1000 * DECDWL - double-width-single-height-line
1002 * Probably not worth implementing.
1008 static int screen_DECEFR(term_screen *screen, const term_seq *seq) {
1010 * DECEFR - enable-filter-rectangle
1011 * Defines the coordinates of a filter rectangle (top, left, bottom,
1012 * right as @args[0] to @args[3]) and activates it.
1013 * Anytime the locator is detected outside of the filter rectangle, an
1014 * outside rectangle event is generated and the rectangle is disabled.
1015 * Filter rectangles are always treated as "one-shot" events. Any
1016 * parameters that are omitted default to the current locator position.
1017 * If all parameters are omitted, any locator motion will be reported.
1018 * DECELR always cancels any prevous rectangle definition.
1020 * The locator is usually associated with the mouse-cursor, but based
1021 * on cells instead of pixels. See DECELR how to initialize and enable
1022 * it. DECELR can also enable pixel-mode instead of cell-mode.
1030 static int screen_DECELF(term_screen *screen, const term_seq *seq) {
1032 * DECELF - enable-local-functions
1034 * Probably not worth implementing.
1040 static int screen_DECELR(term_screen *screen, const term_seq *seq) {
1042 * DECELR - enable-locator-reporting
1043 * This changes the locator-reporting mode. @args[0] specifies the mode
1044 * to set, 0 disables locator-reporting, 1 enables it continuously, 2
1045 * enables it for a single report. @args[1] specifies the
1046 * precision-mode. 0 and 2 set the reporting to cell-precision, 1 sets
1059 static int screen_DECERA(term_screen *screen, const term_seq *seq) {
1061 * DECERA - erase-rectangular-area
1063 * Probably not worth implementing.
1069 static int screen_DECFI(term_screen *screen, const term_seq *seq) {
1071 * DECFI - forward-index
1072 * This control function moves the cursor forward one column. If the
1073 * cursor is at the right margin, then all screen data within the
1074 * margins moves one column to the left. The column shifted past the
1075 * left margin is lost.
1076 * DECFI adds a new column at the right margin, with no visual
1077 * attributes. DECFI does not affect margins. If the cursor is beyond
1078 * the right margin at the border of the page when the terminal
1079 * receives DECFI, then the terminal ignores DECFI.
1081 * Probably not worth implementing.
1087 static int screen_DECFRA(term_screen *screen, const term_seq *seq) {
1089 * DECFRA - fill-rectangular-area
1091 * Probably not worth implementing.
1097 static int screen_DECIC(term_screen *screen, const term_seq *seq) {
1099 * DECIC - insert-column
1101 * Probably not worth implementing.
1107 static int screen_DECID(term_screen *screen, const term_seq *seq) {
1109 * DECID - return-terminal-id
1110 * This is an obsolete form of TERM_CMD_DA1.
1113 return screen_DA1(screen, seq);
1116 static int screen_DECINVM(term_screen *screen, const term_seq *seq) {
1118 * DECINVM - invoke-macro
1120 * Probably not worth implementing.
1126 static int screen_DECKBD(term_screen *screen, const term_seq *seq) {
1128 * DECKBD - keyboard-language-selection
1130 * Probably not worth implementing.
1136 static int screen_DECKPAM(term_screen *screen, const term_seq *seq) {
1138 * DECKPAM - keypad-application-mode
1139 * Enables the keypad-application mode. If enabled, the keypad sends
1140 * special characters instead of the printed characters. This way,
1141 * applications can detect whether a numeric key was pressed on the
1142 * top-row or on the keypad.
1143 * Default is keypad-numeric-mode.
1146 screen->flags |= TERM_FLAG_KEYPAD_MODE;
1151 static int screen_DECKPNM(term_screen *screen, const term_seq *seq) {
1153 * DECKPNM - keypad-numeric-mode
1154 * This disables the keypad-application-mode (DECKPAM) and returns to
1155 * the keypad-numeric-mode. Keypresses on the keypad generate the same
1156 * sequences as corresponding keypresses on the main keyboard.
1157 * Default is keypad-numeric-mode.
1160 screen->flags &= ~TERM_FLAG_KEYPAD_MODE;
1165 static int screen_DECLFKC(term_screen *screen, const term_seq *seq) {
1167 * DECLFKC - local-function-key-control
1169 * Probably not worth implementing.
1175 static int screen_DECLL(term_screen *screen, const term_seq *seq) {
1179 * Probably not worth implementing.
1185 static int screen_DECLTOD(term_screen *screen, const term_seq *seq) {
1187 * DECLTOD - load-time-of-day
1189 * Probably not worth implementing.
1195 static int screen_DECPCTERM(term_screen *screen, const term_seq *seq) {
1197 * DECPCTERM - pcterm-mode
1198 * This enters/exits the PCTerm mode. Default mode is VT-mode. It can
1199 * also select parameters for scancode/keycode mappings in SCO mode.
1201 * Definitely not worth implementing. Lets kill PCTerm/SCO modes!
1207 static int screen_DECPKA(term_screen *screen, const term_seq *seq) {
1209 * DECPKA - program-key-action
1211 * Probably not worth implementing.
1217 static int screen_DECPKFMR(term_screen *screen, const term_seq *seq) {
1219 * DECPKFMR - program-key-free-memory-report
1221 * Probably not worth implementing.
1227 static int screen_DECRARA(term_screen *screen, const term_seq *seq) {
1229 * DECRARA - reverse-attributes-in-rectangular-area
1231 * Probably not worth implementing.
1237 static int screen_DECRC(term_screen *screen, const term_seq *seq) {
1239 * DECRC - restore-cursor
1240 * Restores the terminal to the state saved by the save cursor (DECSC)
1241 * function. This includes more than just the cursor-position.
1243 * If nothing was saved by DECSC, then DECRC performs the following
1245 * * Moves the cursor to the home position (upper left of screen).
1246 * * Resets origin mode (DECOM).
1247 * * Turns all character attributes off (normal setting).
1248 * * Maps the ASCII character set into GL, and the DEC Supplemental
1249 * Graphic set into GR.
1251 * The terminal maintains a separate DECSC buffer for the main display
1252 * and the status line. This feature lets you save a separate operating
1253 * state for the main display and the status line.
1256 screen->attr = screen->saved.attr;
1257 screen->gl = screen->saved.gl;
1258 screen->gr = screen->saved.gr;
1259 screen->glt = screen->saved.glt;
1260 screen->grt = screen->saved.grt;
1261 set_reset(screen, TERM_FLAG_AUTO_WRAP, screen->flags & TERM_FLAG_AUTO_WRAP);
1262 set_reset(screen, TERM_FLAG_ORIGIN_MODE, screen->flags & TERM_FLAG_ORIGIN_MODE);
1263 screen_cursor_set(screen, screen->saved.cursor_x, screen->saved.cursor_y);
1268 static int screen_DECREQTPARM(term_screen *screen, const term_seq *seq) {
1270 * DECREQTPARM - request-terminal-parameters
1271 * The sequence DECREPTPARM is sent by the terminal controller to notify
1272 * the host of the status of selected terminal parameters. The status
1273 * sequence may be sent when requested by the host or at the terminal's
1274 * discretion. DECREPTPARM is sent upon receipt of a DECREQTPARM.
1276 * If @args[0] is 0, this marks a request and the terminal is allowed
1277 * to send DECREPTPARM messages without request. If it is 1, the same
1278 * applies but the terminal should no longer send DECREPTPARM
1280 * 2 and 3 mark a report, but 3 is only used if the terminal answers as
1281 * an explicit request with @args[0] == 1.
1283 * The other arguments are ignored in requests, but have the following
1284 * meaning in responses:
1285 * args[1]: 1=no-parity-set 4=parity-set-and-odd 5=parity-set-and-even
1286 * args[2]: 1=8bits-per-char 2=7bits-per-char
1287 * args[3]: transmission-speed
1288 * args[4]: receive-speed
1289 * args[5]: 1=bit-rate-multiplier-is-16
1290 * args[6]: This value communicates the four switch values in block 5
1291 * of SETUP B, which are only visible to the user when an STP
1292 * option is installed. These bits may be assigned for an STP
1293 * device. The four bits are a decimal-encoded binary number.
1294 * Value between 0-15.
1296 * The transmission/receive speeds have mappings for number => bits/s
1297 * which are quite weird. Examples are: 96->3600, 112->9600, 120->19200
1303 if (seq->n_args < 1 || seq->args[0] == 0) {
1304 screen->flags &= ~TERM_FLAG_INHIBIT_TPARM;
1305 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "2;1;1;120;120;1;0x");
1306 } else if (seq->args[0] == 1) {
1307 screen->flags |= TERM_FLAG_INHIBIT_TPARM;
1308 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "3;1;1;120;120;1;0x");
1314 static int screen_DECRPKT(term_screen *screen, const term_seq *seq) {
1316 * DECRPKT - report-key-type
1317 * Response to DECRQKT, we can safely ignore it as we're the one sending
1324 static int screen_DECRQCRA(term_screen *screen, const term_seq *seq) {
1326 * DECRQCRA - request-checksum-of-rectangular-area
1328 * Probably not worth implementing.
1334 static int screen_DECRQDE(term_screen *screen, const term_seq *seq) {
1336 * DECRQDE - request-display-extent
1338 * Probably not worth implementing.
1344 static int screen_DECRQKT(term_screen *screen, const term_seq *seq) {
1346 * DECRQKT - request-key-type
1348 * Probably not worth implementing.
1354 static int screen_DECRQLP(term_screen *screen, const term_seq *seq) {
1356 * DECRQLP - request-locator-position
1357 * See DECELR for locator-information.
1359 * TODO: document and implement
1365 static int screen_DECRQM_ANSI(term_screen *screen, const term_seq *seq) {
1367 * DECRQM_ANSI - request-mode-ansi
1368 * The host sends this control function to find out if a particular mode
1369 * is set or reset. The terminal responds with a report mode function.
1370 * @args[0] contains the mode to query.
1372 * Response is DECRPM with the first argument set to the mode that was
1373 * queried, second argument is 0 if mode is invalid, 1 if mode is set,
1374 * 2 if mode is not set (reset), 3 if mode is permanently set and 4 if
1375 * mode is permanently not set (reset):
1376 * ANSI: ^[ MODE ; VALUE $ y
1377 * DEC: ^[ ? MODE ; VALUE $ y
1385 static int screen_DECRQM_DEC(term_screen *screen, const term_seq *seq) {
1387 * DECRQM_DEC - request-mode-dec
1388 * Same as DECRQM_ANSI but for DEC modes.
1396 static int screen_DECRQPKFM(term_screen *screen, const term_seq *seq) {
1398 * DECRQPKFM - request-program-key-free-memory
1400 * Probably not worth implementing.
1406 static int screen_DECRQPSR(term_screen *screen, const term_seq *seq) {
1408 * DECRQPSR - request-presentation-state-report
1410 * Probably not worth implementing.
1416 static int screen_DECRQTSR(term_screen *screen, const term_seq *seq) {
1418 * DECRQTSR - request-terminal-state-report
1420 * Probably not worth implementing.
1426 static int screen_DECRQUPSS(term_screen *screen, const term_seq *seq) {
1428 * DECRQUPSS - request-user-preferred-supplemental-set
1430 * Probably not worth implementing.
1436 static int screen_DECSACE(term_screen *screen, const term_seq *seq) {
1438 * DECSACE - select-attribute-change-extent
1440 * Probably not worth implementing.
1446 static int screen_DECSASD(term_screen *screen, const term_seq *seq) {
1448 * DECSASD - select-active-status-display
1450 * Probably not worth implementing.
1456 static int screen_DECSC(term_screen *screen, const term_seq *seq) {
1458 * DECSC - save-cursor
1459 * Save cursor and terminal state so it can be restored later on.
1460 * Saves the following items in the terminal's memory:
1462 * * Character attributes set by the SGR command
1463 * * Character sets (G0, G1, G2, or G3) currently in GL and GR
1464 * * Wrap flag (autowrap or no autowrap)
1465 * * State of origin mode (DECOM)
1466 * * Selective erase attribute
1467 * * Any single shift 2 (SS2) or single shift 3 (SS3) functions sent
1470 screen->saved.cursor_x = screen->cursor_x;
1471 screen->saved.cursor_y = screen->cursor_y;
1472 screen->saved.attr = screen->attr;
1473 screen->saved.gl = screen->gl;
1474 screen->saved.gr = screen->gr;
1475 screen->saved.glt = screen->glt;
1476 screen->saved.grt = screen->grt;
1477 screen->saved.flags = screen->flags & (TERM_FLAG_AUTO_WRAP
1478 | TERM_FLAG_ORIGIN_MODE);
1483 static int screen_DECSCA(term_screen *screen, const term_seq *seq) {
1485 * DECSCA - select-character-protection-attribute
1486 * Defines the characters that come after it as erasable or not erasable
1487 * from the screen. The selective erase control functions (DECSED and
1488 * DECSEL) can only erase characters defined as erasable.
1490 * @args[0] specifies the new mode. 0 and 2 mark any following character
1491 * as erasable, 1 marks it as not erasable.
1497 unsigned int mode = 0;
1499 if (seq->args[0] > 0)
1500 mode = seq->args[0];
1505 screen->attr.protect = 0;
1508 screen->attr.protect = 1;
1515 static int screen_DECSCL(term_screen *screen, const term_seq *seq) {
1517 * DECSCL - select-conformance-level
1518 * Select the terminal's operating level. The factory default is
1519 * level 4 (VT Level 4 mode, 7-bit controls).
1520 * When you change the conformance level, the terminal performs a hard
1523 * @args[0] defines the conformance-level, valid values are:
1524 * 61: Level 1 (VT100)
1525 * 62: Level 2 (VT200)
1526 * 63: Level 3 (VT300)
1527 * 64: Level 4 (VT400)
1528 * @args[1] defines the 8bit-mode, valid values are:
1531 * 2: 8-bit controls (same as 0)
1533 * If @args[0] is 61, then @args[1] is ignored and 7bit controls are
1541 unsigned int level = 64, bit = 0;
1543 if (seq->n_args > 0) {
1544 level = seq->args[0];
1545 if (seq->n_args > 1)
1549 term_screen_hard_reset(screen);
1553 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT100;
1554 screen->flags |= TERM_FLAG_7BIT_MODE;
1557 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
1559 screen->flags |= TERM_FLAG_7BIT_MODE;
1561 screen->flags &= ~TERM_FLAG_7BIT_MODE;
1568 static int screen_DECSCP(term_screen *screen, const term_seq *seq) {
1570 * DECSCP - select-communication-port
1572 * Probably not worth implementing.
1578 static int screen_DECSCPP(term_screen *screen, const term_seq *seq) {
1580 * DECSCPP - select-columns-per-page
1581 * Select columns per page. The number of rows is unaffected by this.
1582 * @args[0] selectes the number of columns (width), DEC only defines 80
1583 * and 132, but we allow any integer here. 0 is equivalent to 80.
1584 * Page content is *not* cleared and the cursor is left untouched.
1585 * However, if the page is reduced in width and the cursor would be
1586 * outside the visible region, it's set to the right border. Newly added
1587 * cells are cleared. No data is retained outside the visible region.
1598 static int screen_DECSCS(term_screen *screen, const term_seq *seq) {
1600 * DECSCS - select-communication-speed
1602 * Probably not worth implementing.
1608 static int screen_DECSCUSR(term_screen *screen, const term_seq *seq) {
1610 * DECSCUSR - set-cursor-style
1611 * This changes the style of the cursor. @args[0] can be one of:
1612 * 0, 1: blinking block
1614 * 3: blinking underline
1615 * 4: steady underline
1616 * Changing this setting does _not_ affect the cursor visibility itself.
1617 * Use DECTCEM for that.
1628 static int screen_DECSDDT(term_screen *screen, const term_seq *seq) {
1630 * DECSDDT - select-disconnect-delay-time
1632 * Probably not worth implementing.
1638 static int screen_DECSDPT(term_screen *screen, const term_seq *seq) {
1640 * DECSDPT - select-digital-printed-data-type
1642 * Probably not worth implementing.
1648 static int screen_DECSED(term_screen *screen, const term_seq *seq) {
1650 * DECSED - selective-erase-in-display
1651 * This control function erases some or all of the erasable characters
1652 * in the display. DECSED can only erase characters defined as erasable
1653 * by the DECSCA control function. DECSED works inside or outside the
1654 * scrolling margins.
1656 * @args[0] defines which regions are erased. If it is 0, all cells from
1657 * the cursor (inclusive) till the end of the display are erase. If it
1658 * is 1, all cells from the start of the display till the cursor
1659 * (inclusive) are erased. If it is 2, all cells are erased.
1665 unsigned int mode = 0;
1667 if (seq->args[0] > 0)
1668 mode = seq->args[0];
1672 term_page_erase(screen->page,
1673 screen->cursor_x, screen->cursor_y,
1674 screen->page->width, screen->page->height,
1675 &screen->attr, screen->age, true);
1678 term_page_erase(screen->page,
1680 screen->cursor_x, screen->cursor_y,
1681 &screen->attr, screen->age, true);
1684 term_page_erase(screen->page,
1686 screen->page->width, screen->page->height,
1687 &screen->attr, screen->age, true);
1694 static int screen_DECSEL(term_screen *screen, const term_seq *seq) {
1696 * DECSEL - selective-erase-in-line
1697 * This control function erases some or all of the erasable characters
1698 * in a single line of text. DECSEL erases only those characters defined
1699 * as erasable by the DECSCA control function. DECSEL works inside or
1700 * outside the scrolling margins.
1702 * @args[0] defines the region to be erased. If it is 0, all cells from
1703 * the cursor (inclusive) till the end of the line are erase. If it is
1704 * 1, all cells from the start of the line till the cursor (inclusive)
1705 * are erased. If it is 2, the whole line of the cursor is erased.
1711 unsigned int mode = 0;
1713 if (seq->args[0] > 0)
1714 mode = seq->args[0];
1718 term_page_erase(screen->page,
1719 screen->cursor_x, screen->cursor_y,
1720 screen->page->width, screen->cursor_y,
1721 &screen->attr, screen->age, true);
1724 term_page_erase(screen->page,
1725 0, screen->cursor_y,
1726 screen->cursor_x, screen->cursor_y,
1727 &screen->attr, screen->age, true);
1730 term_page_erase(screen->page,
1731 0, screen->cursor_y,
1732 screen->page->width, screen->cursor_y,
1733 &screen->attr, screen->age, true);
1740 static int screen_DECSERA(term_screen *screen, const term_seq *seq) {
1742 * DECSERA - selective-erase-rectangular-area
1744 * Probably not worth implementing.
1750 static int screen_DECSFC(term_screen *screen, const term_seq *seq) {
1752 * DECSFC - select-flow-control
1754 * Probably not worth implementing.
1760 static int screen_DECSKCV(term_screen *screen, const term_seq *seq) {
1762 * DECSKCV - set-key-click-volume
1764 * Probably not worth implementing.
1770 static int screen_DECSLCK(term_screen *screen, const term_seq *seq) {
1772 * DECSLCK - set-lock-key-style
1774 * Probably not worth implementing.
1780 static int screen_DECSLE(term_screen *screen, const term_seq *seq) {
1782 * DECSLE - select-locator-events
1790 static int screen_DECSLPP(term_screen *screen, const term_seq *seq) {
1792 * DECSLPP - set-lines-per-page
1793 * Set the number of lines used for the page. @args[0] specifies the
1794 * number of lines to be used. DEC only allows a limited number of
1795 * choices, however, we allow all integers. 0 is equivalent to 24.
1806 static int screen_DECSLRM_OR_SC(term_screen *screen, const term_seq *seq) {
1808 * DECSLRM_OR_SC - set-left-and-right-margins or save-cursor
1810 * TODO: Detect save-cursor and run it. DECSLRM is not worth
1817 static int screen_DECSMBV(term_screen *screen, const term_seq *seq) {
1819 * DECSMBV - set-margin-bell-volume
1821 * Probably not worth implementing.
1827 static int screen_DECSMKR(term_screen *screen, const term_seq *seq) {
1829 * DECSMKR - select-modifier-key-reporting
1831 * Probably not worth implementing.
1837 static int screen_DECSNLS(term_screen *screen, const term_seq *seq) {
1839 * DECSNLS - set-lines-per-screen
1841 * Probably not worth implementing.
1847 static int screen_DECSPP(term_screen *screen, const term_seq *seq) {
1849 * DECSPP - set-port-parameter
1851 * Probably not worth implementing.
1857 static int screen_DECSPPCS(term_screen *screen, const term_seq *seq) {
1859 * DECSPPCS - select-pro-printer-character-set
1861 * Probably not worth implementing.
1867 static int screen_DECSPRTT(term_screen *screen, const term_seq *seq) {
1869 * DECSPRTT - select-printer-type
1871 * Probably not worth implementing.
1877 static int screen_DECSR(term_screen *screen, const term_seq *seq) {
1879 * DECSR - secure-reset
1881 * Probably not worth implementing.
1887 static int screen_DECSRFR(term_screen *screen, const term_seq *seq) {
1889 * DECSRFR - select-refresh-rate
1891 * Probably not worth implementing.
1897 static int screen_DECSSCLS(term_screen *screen, const term_seq *seq) {
1899 * DECSSCLS - set-scroll-speed
1901 * Probably not worth implementing.
1907 static int screen_DECSSDT(term_screen *screen, const term_seq *seq) {
1909 * DECSSDT - select-status-display-line-type
1911 * Probably not worth implementing.
1917 static int screen_DECSSL(term_screen *screen, const term_seq *seq) {
1919 * DECSSL - select-setup-language
1921 * Probably not worth implementing.
1927 static int screen_DECST8C(term_screen *screen, const term_seq *seq) {
1929 * DECST8C - set-tab-at-every-8-columns
1930 * Clear the tab-ruler and reset it to a tab at every 8th column,
1931 * starting at 9 (though, setting a tab at 1 is fine as it has no
1937 for (i = 0; i < screen->page->width; i += 8)
1938 screen->tabs[i / 8] = 0x1;
1943 static int screen_DECSTBM(term_screen *screen, const term_seq *seq) {
1945 * DECSTBM - set-top-and-bottom-margins
1946 * This control function sets the top and bottom margins for the current
1947 * page. You cannot perform scrolling outside the margins.
1949 * @args[0] defines the top margin, @args[1] defines the bottom margin.
1950 * The bottom margin must be lower than the top-margin.
1952 * This call resets the cursor position to 0/0 of the page.
1956 * args[1]: last page-line
1959 unsigned int top, bottom;
1962 bottom = screen->page->height;
1964 if (seq->args[0] > 0)
1966 if (seq->args[1] > 0)
1967 bottom = seq->args[1];
1969 if (top > screen->page->height)
1970 top = screen->page->height;
1971 if (bottom > screen->page->height)
1972 bottom = screen->page->height;
1974 if (top >= bottom || top > screen->page->height || bottom > screen->page->height) {
1976 bottom = screen->page->height;
1979 term_page_set_scroll_region(screen->page_main, top - 1, bottom - top + 1);
1980 term_page_set_scroll_region(screen->page_alt, top - 1, bottom - top + 1);
1981 screen_cursor_clear_wrap(screen);
1982 screen_cursor_set(screen, 0, 0);
1987 static int screen_DECSTR(term_screen *screen, const term_seq *seq) {
1989 * DECSTR - soft-terminal-reset
1990 * Perform a soft reset to the default values.
1993 term_screen_soft_reset(screen);
1998 static int screen_DECSTRL(term_screen *screen, const term_seq *seq) {
2000 * DECSTRL - set-transmit-rate-limit
2002 * Probably not worth implementing.
2008 static int screen_DECSWBV(term_screen *screen, const term_seq *seq) {
2010 * DECSWBV - set-warning-bell-volume
2012 * Probably not worth implementing.
2018 static int screen_DECSWL(term_screen *screen, const term_seq *seq) {
2020 * DECSWL - single-width-single-height-line
2022 * Probably not worth implementing.
2028 static int screen_DECTID(term_screen *screen, const term_seq *seq) {
2030 * DECTID - select-terminal-id
2032 * Probably not worth implementing.
2038 static int screen_DECTME(term_screen *screen, const term_seq *seq) {
2040 * DECTME - terminal-mode-emulation
2042 * Probably not worth implementing.
2048 static int screen_DECTST(term_screen *screen, const term_seq *seq) {
2050 * DECTST - invoke-confidence-test
2052 * Probably not worth implementing.
2058 static int screen_DL(term_screen *screen, const term_seq *seq) {
2061 * This control function deletes one or more lines in the scrolling
2062 * region, starting with the line that has the cursor. @args[0] defines
2063 * the number of lines to delete. 0 is treated the same as 1.
2064 * As lines are deleted, lines below the cursor and in the scrolling
2065 * region move up. The terminal adds blank lines with no visual
2066 * character attributes at the bottom of the scrolling region. If it is
2067 * greater than the number of lines remaining on the page, DL deletes
2068 * only the remaining lines. DL has no effect outside the scrolling
2075 unsigned int num = 1;
2077 if (seq->args[0] > 0)
2080 term_page_delete_lines(screen->page, screen->cursor_y, num, &screen->attr, screen->age);
2085 static int screen_DSR_ANSI(term_screen *screen, const term_seq *seq) {
2087 * DSR_ANSI - device-status-report-ansi
2095 static int screen_DSR_DEC(term_screen *screen, const term_seq *seq) {
2097 * DSR_DEC - device-status-report-dec
2105 static int screen_ECH(term_screen *screen, const term_seq *seq) {
2107 * ECH - erase-character
2108 * This control function erases one or more characters, from the cursor
2109 * position to the right. ECH clears character attributes from erased
2110 * character positions. ECH works inside or outside the scrolling
2112 * @args[0] defines the number of characters to erase. 0 is treated the
2119 unsigned int num = 1;
2121 if (seq->args[0] > 0)
2124 term_page_erase(screen->page,
2125 screen->cursor_x, screen->cursor_y,
2126 screen->cursor_x + num, screen->cursor_y,
2127 &screen->attr, screen->age, false);
2132 static int screen_ED(term_screen *screen, const term_seq *seq) {
2134 * ED - erase-in-display
2135 * This control function erases characters from part or all of the
2136 * display. When you erase complete lines, they become single-height,
2137 * single-width lines, with all visual character attributes cleared. ED
2138 * works inside or outside the scrolling margins.
2140 * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2141 * till the end of the screen. 1 means from the start of the screen till
2142 * the cursor (inclusive) and 2 means the whole screen.
2148 unsigned int mode = 0;
2150 if (seq->args[0] > 0)
2151 mode = seq->args[0];
2155 term_page_erase(screen->page,
2156 screen->cursor_x, screen->cursor_y,
2157 screen->page->width, screen->page->height,
2158 &screen->attr, screen->age, false);
2161 term_page_erase(screen->page,
2163 screen->cursor_x, screen->cursor_y,
2164 &screen->attr, screen->age, false);
2167 term_page_erase(screen->page,
2169 screen->page->width, screen->page->height,
2170 &screen->attr, screen->age, false);
2177 static int screen_EL(term_screen *screen, const term_seq *seq) {
2179 * EL - erase-in-line
2180 * This control function erases characters on the line that has the
2181 * cursor. EL clears all character attributes from erased character
2182 * positions. EL works inside or outside the scrolling margins.
2184 * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2185 * till the end of the line. 1 means from the start of the line till the
2186 * cursor (inclusive) and 2 means the whole line.
2192 unsigned int mode = 0;
2194 if (seq->args[0] > 0)
2195 mode = seq->args[0];
2199 term_page_erase(screen->page,
2200 screen->cursor_x, screen->cursor_y,
2201 screen->page->width, screen->cursor_y,
2202 &screen->attr, screen->age, false);
2205 term_page_erase(screen->page,
2206 0, screen->cursor_y,
2207 screen->cursor_x, screen->cursor_y,
2208 &screen->attr, screen->age, false);
2211 term_page_erase(screen->page,
2212 0, screen->cursor_y,
2213 screen->page->width, screen->cursor_y,
2214 &screen->attr, screen->age, false);
2221 static int screen_ENQ(term_screen *screen, const term_seq *seq) {
2224 * Transmit the answerback-string. If none is set, do nothing.
2227 if (screen->answerback)
2228 return screen_write(screen, screen->answerback, strlen(screen->answerback));
2233 static int screen_EPA(term_screen *screen, const term_seq *seq) {
2235 * EPA - end-of-guarded-area
2237 * TODO: What is this?
2243 static int screen_FF(term_screen *screen, const term_seq *seq) {
2246 * This causes the cursor to jump to the next line. It is treated the
2250 return screen_LF(screen, seq);
2253 static int screen_HPA(term_screen *screen, const term_seq *seq) {
2255 * HPA - horizontal-position-absolute
2256 * HPA causes the active position to be moved to the n-th horizontal
2257 * position of the active line. If an attempt is made to move the active
2258 * position past the last position on the line, then the active position
2259 * stops at the last position on the line.
2261 * @args[0] defines the horizontal position. 0 is treated as 1.
2267 unsigned int num = 1;
2269 if (seq->args[0] > 0)
2272 screen_cursor_clear_wrap(screen);
2273 screen_cursor_set(screen, num - 1, screen->cursor_y);
2278 static int screen_HPR(term_screen *screen, const term_seq *seq) {
2280 * HPR - horizontal-position-relative
2281 * HPR causes the active position to be moved to the n-th following
2282 * horizontal position of the active line. If an attempt is made to move
2283 * the active position past the last position on the line, then the
2284 * active position stops at the last position on the line.
2286 * @args[0] defines the horizontal position. 0 is treated as 1.
2292 unsigned int num = 1;
2294 if (seq->args[0] > 0)
2297 screen_cursor_clear_wrap(screen);
2298 screen_cursor_right(screen, num);
2303 static int screen_HT(term_screen *screen, const term_seq *seq) {
2305 * HT - horizontal-tab
2306 * Moves the cursor to the next tab stop. If there are no more tab
2307 * stops, the cursor moves to the right margin. HT does not cause text
2311 screen_cursor_clear_wrap(screen);
2312 screen_cursor_right_tab(screen, 1);
2317 static int screen_HTS(term_screen *screen, const term_seq *seq) {
2319 * HTS - horizontal-tab-set
2320 * HTS sets a horizontal tab stop at the column position indicated by
2321 * the value of the active column when the terminal receives an HTS.
2323 * Executing an HTS does not effect the other horizontal tab stop
2329 pos = screen->cursor_x;
2330 if (screen->page->width > 0)
2331 screen->tabs[pos / 8] |= 1U << (pos % 8);
2336 static int screen_HVP(term_screen *screen, const term_seq *seq) {
2338 * HVP - horizontal-and-vertical-position
2339 * This control function works the same as the cursor position (CUP)
2340 * function. Origin mode (DECOM) selects line numbering and the ability
2341 * to move the cursor into margins.
2348 return screen_CUP(screen, seq);
2351 static int screen_ICH(term_screen *screen, const term_seq *seq) {
2353 * ICH - insert-character
2354 * This control function inserts one or more space (SP) characters
2355 * starting at the cursor position. @args[0] is the number of characters
2356 * to insert. 0 is treated as 1.
2358 * The ICH sequence inserts blank characters with the normal
2359 * character attribute. The cursor remains at the beginning of the blank
2360 * characters. Text between the cursor and right margin moves to the
2361 * right. Characters scrolled past the right margin are lost. ICH has no
2362 * effect outside the scrolling margins.
2368 unsigned int num = 1;
2370 if (seq->args[0] > 0)
2373 screen_cursor_clear_wrap(screen);
2374 term_page_insert_cells(screen->page, screen->cursor_x, screen->cursor_y, num, &screen->attr, screen->age);
2379 static int screen_IL(term_screen *screen, const term_seq *seq) {
2382 * This control function inserts one or more blank lines, starting at
2383 * the cursor. @args[0] is the number of lines to insert. 0 is treated
2386 * As lines are inserted, lines below the cursor and in the scrolling
2387 * region move down. Lines scrolled off the page are lost. IL has no
2388 * effect outside the page margins.
2394 unsigned int num = 1;
2396 if (seq->args[0] > 0)
2399 screen_cursor_clear_wrap(screen);
2400 term_page_insert_lines(screen->page, screen->cursor_y, num, &screen->attr, screen->age);
2405 static int screen_IND(term_screen *screen, const term_seq *seq) {
2408 * IND moves the cursor down one line in the same column. If the cursor
2409 * is at the bottom margin, then the screen performs a scroll-up.
2412 screen_cursor_down(screen, 1, true);
2417 static int screen_LF(term_screen *screen, const term_seq *seq) {
2420 * Causes a line feed or a new line operation, depending on the setting
2421 * of line feed/new line mode.
2424 screen_cursor_down(screen, 1, true);
2425 if (screen->flags & TERM_FLAG_NEWLINE_MODE)
2426 screen_cursor_left(screen, screen->cursor_x);
2431 static int screen_LS1R(term_screen *screen, const term_seq *seq) {
2433 * LS1R - locking-shift-1-right
2437 screen->gr = &screen->g1;
2442 static int screen_LS2(term_screen *screen, const term_seq *seq) {
2444 * LS2 - locking-shift-2
2448 screen->gl = &screen->g2;
2453 static int screen_LS2R(term_screen *screen, const term_seq *seq) {
2455 * LS2R - locking-shift-2-right
2459 screen->gr = &screen->g2;
2464 static int screen_LS3(term_screen *screen, const term_seq *seq) {
2466 * LS3 - locking-shift-3
2470 screen->gl = &screen->g3;
2475 static int screen_LS3R(term_screen *screen, const term_seq *seq) {
2477 * LS3R - locking-shift-3-right
2481 screen->gr = &screen->g3;
2486 static int screen_MC_ANSI(term_screen *screen, const term_seq *seq) {
2488 * MC_ANSI - media-copy-ansi
2490 * Probably not worth implementing.
2496 static int screen_MC_DEC(term_screen *screen, const term_seq *seq) {
2498 * MC_DEC - media-copy-dec
2500 * Probably not worth implementing.
2506 static int screen_NEL(term_screen *screen, const term_seq *seq) {
2509 * Moves cursor to first position on next line. If cursor is at bottom
2510 * margin, then screen performs a scroll-up.
2513 screen_cursor_clear_wrap(screen);
2514 screen_cursor_down(screen, 1, true);
2515 screen_cursor_set(screen, 0, screen->cursor_y);
2520 static int screen_NP(term_screen *screen, const term_seq *seq) {
2523 * This control function moves the cursor forward to the home position
2524 * on one of the following pages in page memory. If there is only one
2525 * page, then the terminal ignores NP.
2526 * If NP tries to move the cursor past the last page in memory, then the
2527 * cursor stops at the last page.
2529 * @args[0] defines the number of pages to forward. 0 is treated as 1.
2534 * Probably not worth implementing. We only support a single page.
2540 static int screen_NULL(term_screen *screen, const term_seq *seq) {
2543 * The NULL operation does nothing. ASCII NULL is always ignored.
2549 static int screen_PP(term_screen *screen, const term_seq *seq) {
2551 * PP - preceding-page
2552 * This control function moves the cursor backward to the home position
2553 * on one of the preceding pages in page memory. If there is only one
2554 * page, then the terminal ignores PP.
2555 * If PP tries to move the cursor back farther than the first page in
2556 * memory, then the cursor stops at the first page.
2558 * @args[0] defines the number of pages to go backwards. 0 is treated
2564 * Probably not worth implementing. We only support a single page.
2570 static int screen_PPA(term_screen *screen, const term_seq *seq) {
2572 * PPA - page-position-absolute
2573 * This control function can move the cursor to the corresponding row
2574 * and column on any page in page memory. You select the page by its
2575 * number. If there is only one page, then the terminal ignores PPA.
2577 * @args[0] is the number of the page to move the cursor to. If it is
2578 * greater than the number of the last page in memory, then the cursor
2579 * stops at the last page. If it is less than the number of the first
2580 * page, then the cursor stops at the first page.
2585 * Probably not worth implementing. We only support a single page.
2591 static int screen_PPB(term_screen *screen, const term_seq *seq) {
2593 * PPB - page-position-backward
2594 * This control function moves the cursor backward to the corresponding
2595 * row and column on one of the preceding pages in page memory. If there
2596 * is only one page, then the terminal ignores PPB.
2598 * @args[0] indicates the number of pages to move the cursor backward.
2599 * If it tries to move the cursor back farther than the first page in
2600 * memory, then the cursor stops at the first page. 0 is treated as 1.
2605 * Probably not worth implementing. We only support a single page.
2611 static int screen_PPR(term_screen *screen, const term_seq *seq) {
2613 * PPR - page-position-relative
2614 * This control function moves the cursor forward to the corresponding
2615 * row and column on one of the following pages in page memory. If there
2616 * is only one page, then the terminal ignores PPR.
2618 * @args[0] indicates how many pages to move the cursor forward. If it
2619 * tries to move the cursor beyond the last page in memory, then the
2620 * cursor stops at the last page. 0 is treated as 1.
2625 * Probably not worth implementing. We only support a single page.
2631 static int screen_RC(term_screen *screen, const term_seq *seq) {
2633 * RC - restore-cursor
2636 return screen_DECRC(screen, seq);
2639 static int screen_REP(term_screen *screen, const term_seq *seq) {
2642 * Repeat the preceding graphics-character the given number of times.
2643 * @args[0] specifies how often it shall be repeated. 0 is treated as 1.
2648 * Probably not worth implementing.
2654 static int screen_RI(term_screen *screen, const term_seq *seq) {
2656 * RI - reverse-index
2657 * Moves the cursor up one line in the same column. If the cursor is at
2658 * the top margin, the page scrolls down.
2661 screen_cursor_up(screen, 1, true);
2666 static int screen_RIS(term_screen *screen, const term_seq *seq) {
2668 * RIS - reset-to-initial-state
2669 * This control function causes a nonvolatile memory (NVR) recall to
2670 * occur. RIS replaces all set-up features with their saved settings.
2672 * The terminal stores these saved settings in NVR memory. The saved
2673 * setting for a feature is the same as the factory-default setting,
2674 * unless you saved a new setting.
2677 term_screen_hard_reset(screen);
2682 static int screen_RM_ANSI(term_screen *screen, const term_seq *seq) {
2684 * RM_ANSI - reset-mode-ansi
2686 * TODO: implement (see VT510rm manual)
2691 for (i = 0; i < seq->n_args; ++i)
2692 screen_mode_change(screen, seq->args[i], false, false);
2697 static int screen_RM_DEC(term_screen *screen, const term_seq *seq) {
2699 * RM_DEC - reset-mode-dec
2700 * This is the same as RM_ANSI but for DEC modes.
2705 for (i = 0; i < seq->n_args; ++i)
2706 screen_mode_change(screen, seq->args[i], true, false);
2711 static int screen_S7C1T(term_screen *screen, const term_seq *seq) {
2713 * S7C1T - set-7bit-c1-terminal
2714 * This causes the terminal to start sending C1 controls as 7bit
2715 * sequences instead of 8bit C1 controls.
2716 * This is ignored if the terminal is below level-2 emulation mode
2717 * (VT100 and below), the terminal already sends 7bit controls then.
2720 if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2721 screen->flags |= TERM_FLAG_7BIT_MODE;
2726 static int screen_S8C1T(term_screen *screen, const term_seq *seq) {
2728 * S8C1T - set-8bit-c1-terminal
2729 * This causes the terminal to start sending C1 controls as 8bit C1
2730 * control instead of 7bit sequences.
2731 * This is ignored if the terminal is below level-2 emulation mode
2732 * (VT100 and below). The terminal always sends 7bit controls in those
2736 if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2737 screen->flags &= ~TERM_FLAG_7BIT_MODE;
2742 static int screen_SCS(term_screen *screen, const term_seq *seq) {
2744 * SCS - select-character-set
2745 * Designate character sets to G-sets. The mapping from intermediates
2746 * and terminal characters in the escape sequence to G-sets and
2747 * character-sets is non-trivial and implemented separately. See there
2748 * for more information.
2749 * This call simply sets the selected G-set to the desired
2753 term_charset *cs = NULL;
2755 /* TODO: support more of them? */
2756 switch (seq->charset) {
2757 case TERM_CHARSET_ISO_LATIN1_SUPPLEMENTAL:
2758 case TERM_CHARSET_ISO_LATIN2_SUPPLEMENTAL:
2759 case TERM_CHARSET_ISO_LATIN5_SUPPLEMENTAL:
2760 case TERM_CHARSET_ISO_GREEK_SUPPLEMENTAL:
2761 case TERM_CHARSET_ISO_HEBREW_SUPPLEMENTAL:
2762 case TERM_CHARSET_ISO_LATIN_CYRILLIC:
2765 case TERM_CHARSET_DEC_SPECIAL_GRAPHIC:
2766 cs = &term_dec_special_graphics;
2768 case TERM_CHARSET_DEC_SUPPLEMENTAL:
2769 cs = &term_dec_supplemental_graphics;
2771 case TERM_CHARSET_DEC_TECHNICAL:
2772 case TERM_CHARSET_CYRILLIC_DEC:
2773 case TERM_CHARSET_DUTCH_NRCS:
2774 case TERM_CHARSET_FINNISH_NRCS:
2775 case TERM_CHARSET_FRENCH_NRCS:
2776 case TERM_CHARSET_FRENCH_CANADIAN_NRCS:
2777 case TERM_CHARSET_GERMAN_NRCS:
2778 case TERM_CHARSET_GREEK_DEC:
2779 case TERM_CHARSET_GREEK_NRCS:
2780 case TERM_CHARSET_HEBREW_DEC:
2781 case TERM_CHARSET_HEBREW_NRCS:
2782 case TERM_CHARSET_ITALIAN_NRCS:
2783 case TERM_CHARSET_NORWEGIAN_DANISH_NRCS:
2784 case TERM_CHARSET_PORTUGUESE_NRCS:
2785 case TERM_CHARSET_RUSSIAN_NRCS:
2786 case TERM_CHARSET_SCS_NRCS:
2787 case TERM_CHARSET_SPANISH_NRCS:
2788 case TERM_CHARSET_SWEDISH_NRCS:
2789 case TERM_CHARSET_SWISS_NRCS:
2790 case TERM_CHARSET_TURKISH_DEC:
2791 case TERM_CHARSET_TURKISH_NRCS:
2794 case TERM_CHARSET_USERPREF_SUPPLEMENTAL:
2798 if (seq->intermediates & TERM_SEQ_FLAG_POPEN)
2799 screen->g0 = cs ? : &term_unicode_lower;
2800 else if (seq->intermediates & TERM_SEQ_FLAG_PCLOSE)
2801 screen->g1 = cs ? : &term_unicode_upper;
2802 else if (seq->intermediates & TERM_SEQ_FLAG_MULT)
2803 screen->g2 = cs ? : &term_unicode_lower;
2804 else if (seq->intermediates & TERM_SEQ_FLAG_PLUS)
2805 screen->g3 = cs ? : &term_unicode_upper;
2806 else if (seq->intermediates & TERM_SEQ_FLAG_MINUS)
2807 screen->g1 = cs ? : &term_unicode_upper;
2808 else if (seq->intermediates & TERM_SEQ_FLAG_DOT)
2809 screen->g2 = cs ? : &term_unicode_lower;
2810 else if (seq->intermediates & TERM_SEQ_FLAG_SLASH)
2811 screen->g3 = cs ? : &term_unicode_upper;
2816 static int screen_SD(term_screen *screen, const term_seq *seq) {
2819 * This control function moves the user window down a specified number
2820 * of lines in page memory.
2821 * @args[0] is the number of lines to move the
2822 * user window up in page memory. New lines appear at the top of the
2823 * display. Old lines disappear at the bottom of the display. You
2824 * cannot pan past the top margin of the current page. 0 is treated
2831 unsigned int num = 1;
2833 if (seq->args[0] > 0)
2836 term_page_scroll_down(screen->page, num, &screen->attr, screen->age, NULL);
2841 static int screen_SGR(term_screen *screen, const term_seq *seq) {
2843 * SGR - select-graphics-rendition
2847 unsigned int i, code;
2850 if (seq->n_args < 1) {
2855 for (i = 0; i < seq->n_args; ++i) {
2859 screen->attr.bold = 1;
2862 screen->attr.italic = 1;
2865 screen->attr.underline = 1;
2868 screen->attr.blink = 1;
2871 screen->attr.inverse = 1;
2874 screen->attr.hidden = 1;
2877 screen->attr.bold = 0;
2880 screen->attr.italic = 0;
2883 screen->attr.underline = 0;
2886 screen->attr.blink = 0;
2889 screen->attr.inverse = 0;
2892 screen->attr.hidden = 0;
2895 screen->attr.fg.ccode = v - 30 + TERM_CCODE_BLACK;
2898 screen->attr.fg.ccode = 0;
2901 screen->attr.bg.ccode = v - 40 + TERM_CCODE_BLACK;
2904 screen->attr.bg.ccode = 0;
2907 screen->attr.fg.ccode = v - 90 + TERM_CCODE_LIGHT_BLACK;
2910 screen->attr.bg.ccode = v - 100 + TERM_CCODE_LIGHT_BLACK;
2917 dst = &screen->attr.fg;
2919 dst = &screen->attr.bg;
2922 if (i >= seq->n_args)
2925 switch (seq->args[i]) {
2927 /* 24bit-color support */
2930 if (i >= seq->n_args)
2933 dst->ccode = TERM_CCODE_RGB;
2934 dst->red = (seq->args[i - 2] >= 0) ? seq->args[i - 2] : 0;
2935 dst->green = (seq->args[i - 1] >= 0) ? seq->args[i - 1] : 0;
2936 dst->blue = (seq->args[i] >= 0) ? seq->args[i] : 0;
2940 /* 256-color support */
2943 if (i >= seq->n_args || seq->args[i] < 0)
2946 code = seq->args[i];
2949 } else if (code < 232) {
2950 static const uint8_t bval[] = {
2955 dst->ccode = TERM_CCODE_256;
2958 dst->blue = bval[code % 6];
2960 dst->green = bval[code % 6];
2962 dst->red = bval[code % 6];
2963 } else if (code < 256) {
2964 dst->ccode = TERM_CCODE_256;
2966 code = (code - 232) * 10 + 8;
2987 static int screen_SI(term_screen *screen, const term_seq *seq) {
2993 screen->gl = &screen->g0;
2998 static int screen_SM_ANSI(term_screen *screen, const term_seq *seq) {
3000 * SM_ANSI - set-mode-ansi
3007 for (i = 0; i < seq->n_args; ++i)
3008 screen_mode_change(screen, seq->args[i], false, true);
3013 static int screen_SM_DEC(term_screen *screen, const term_seq *seq) {
3015 * SM_DEC - set-mode-dec
3016 * This is the same as SM_ANSI but for DEC modes.
3021 for (i = 0; i < seq->n_args; ++i)
3022 screen_mode_change(screen, seq->args[i], true, true);
3027 static int screen_SO(term_screen *screen, const term_seq *seq) {
3033 screen->gl = &screen->g1;
3038 static int screen_SPA(term_screen *screen, const term_seq *seq) {
3040 * SPA - start-of-protected-area
3042 * TODO: What is this?
3048 static int screen_SS2(term_screen *screen, const term_seq *seq) {
3050 * SS2 - single-shift-2
3051 * Temporarily map G2 into GL for the next graphics character.
3054 screen->glt = &screen->g2;
3059 static int screen_SS3(term_screen *screen, const term_seq *seq) {
3061 * SS3 - single-shift-3
3062 * Temporarily map G3 into GL for the next graphics character
3065 screen->glt = &screen->g3;
3070 static int screen_ST(term_screen *screen, const term_seq *seq) {
3072 * ST - string-terminator
3073 * The string-terminator is usually part of control-sequences and
3074 * handled by the parser. In all other situations it is silently
3081 static int screen_SU(term_screen *screen, const term_seq *seq) {
3084 * This control function moves the user window up a specified number of
3085 * lines in page memory.
3086 * @args[0] is the number of lines to move the
3087 * user window down in page memory. New lines appear at the bottom of
3088 * the display. Old lines disappear at the top of the display. You
3089 * cannot pan past the bottom margin of the current page. 0 is treated
3096 unsigned int num = 1;
3098 if (seq->args[0] > 0)
3101 term_page_scroll_up(screen->page, num, &screen->attr, screen->age, screen->history);
3106 static int screen_SUB(term_screen *screen, const term_seq *seq) {
3109 * Cancel the current control-sequence and print a replacement
3110 * character. Our parser already handles this so all we have to do is
3111 * print the replacement character.
3114 static const term_seq rep = {
3115 .type = TERM_SEQ_GRAPHIC,
3116 .command = TERM_CMD_GRAPHIC,
3117 .terminator = 0xfffd,
3120 return screen_GRAPHIC(screen, &rep);
3123 static int screen_TBC(term_screen *screen, const term_seq *seq) {
3126 * This clears tab-stops. If @args[0] is 0, the tab-stop at the current
3127 * cursor position is cleared. If it is 3, all tab stops are cleared.
3133 unsigned int mode = 0, pos;
3135 if (seq->args[0] > 0)
3136 mode = seq->args[0];
3140 pos = screen->cursor_x;
3141 if (screen->page->width > 0)
3142 screen->tabs[pos / 8] &= ~(1U << (pos % 8));
3145 if (screen->page->width > 0)
3146 memset(screen->tabs, 0, (screen->page->width + 7) / 8);
3153 static int screen_VPA(term_screen *screen, const term_seq *seq) {
3155 * VPA - vertical-line-position-absolute
3156 * VPA causes the active position to be moved to the corresponding
3157 * horizontal position. @args[0] specifies the line to jump to. If an
3158 * attempt is made to move the active position below the last line, then
3159 * the active position stops on the last line. 0 is treated as 1.
3165 unsigned int pos = 1;
3167 if (seq->args[0] > 0)
3170 screen_cursor_clear_wrap(screen);
3171 screen_cursor_set_rel(screen, screen->cursor_x, pos - 1);
3176 static int screen_VPR(term_screen *screen, const term_seq *seq) {
3178 * VPR - vertical-line-position-relative
3179 * VPR causes the active position to be moved to the corresponding
3180 * horizontal position. @args[0] specifies the number of lines to jump
3181 * down relative to the current cursor position. If an attempt is made
3182 * to move the active position below the last line, the active position
3183 * stops at the last line. 0 is treated as 1.
3189 unsigned int num = 1;
3191 if (seq->args[0] > 0)
3194 screen_cursor_clear_wrap(screen);
3195 screen_cursor_down(screen, num, false);
3200 static int screen_VT(term_screen *screen, const term_seq *seq) {
3203 * This causes a vertical jump by one line. Terminals treat it exactly
3207 return screen_LF(screen, seq);
3210 static int screen_XTERM_CLLHP(term_screen *screen, const term_seq *seq) {
3212 * XTERM_CLLHP - xterm-cursor-lower-left-hp-bugfix
3213 * Move the cursor to the lower-left corner of the page. This is an HP
3216 * Probably not worth implementing.
3222 static int screen_XTERM_IHMT(term_screen *screen, const term_seq *seq) {
3224 * XTERM_IHMT - xterm-initiate-highlight-mouse-tracking
3226 * Probably not worth implementing.
3232 static int screen_XTERM_MLHP(term_screen *screen, const term_seq *seq) {
3234 * XTERM_MLHP - xterm-memory-lock-hp-bugfix
3236 * Probably not worth implementing.
3242 static int screen_XTERM_MUHP(term_screen *screen, const term_seq *seq) {
3244 * XTERM_MUHP - xterm-memory-unlock-hp-bugfix
3246 * Probably not worth implementing.
3252 static int screen_XTERM_RPM(term_screen *screen, const term_seq *seq) {
3254 * XTERM_RPM - xterm-restore-private-mode
3256 * Probably not worth implementing.
3262 static int screen_XTERM_RRV(term_screen *screen, const term_seq *seq) {
3264 * XTERM_RRV - xterm-reset-resource-value
3266 * Probably not worth implementing.
3272 static int screen_XTERM_RTM(term_screen *screen, const term_seq *seq) {
3274 * XTERM_RTM - xterm-reset-title-mode
3276 * Probably not worth implementing.
3282 static int screen_XTERM_SACL1(term_screen *screen, const term_seq *seq) {
3284 * XTERM_SACL1 - xterm-set-ansi-conformance-level-1
3286 * Probably not worth implementing.
3292 static int screen_XTERM_SACL2(term_screen *screen, const term_seq *seq) {
3294 * XTERM_SACL2 - xterm-set-ansi-conformance-level-2
3296 * Probably not worth implementing.
3302 static int screen_XTERM_SACL3(term_screen *screen, const term_seq *seq) {
3304 * XTERM_SACL3 - xterm-set-ansi-conformance-level-3
3306 * Probably not worth implementing.
3312 static int screen_XTERM_SDCS(term_screen *screen, const term_seq *seq) {
3314 * XTERM_SDCS - xterm-set-default-character-set
3315 * Select the default character set. We treat this the same as UTF-8 as
3316 * this is our default character set. As we always use UTF-8, this
3323 static int screen_XTERM_SGFX(term_screen *screen, const term_seq *seq) {
3325 * XTERM_SGFX - xterm-sixel-graphics
3327 * Probably not worth implementing.
3333 static int screen_XTERM_SPM(term_screen *screen, const term_seq *seq) {
3335 * XTERM_SPM - xterm-set-private-mode
3337 * Probably not worth implementing.
3343 static int screen_XTERM_SRV(term_screen *screen, const term_seq *seq) {
3345 * XTERM_SRV - xterm-set-resource-value
3347 * Probably not worth implementing.
3353 static int screen_XTERM_STM(term_screen *screen, const term_seq *seq) {
3355 * XTERM_STM - xterm-set-title-mode
3357 * Probably not worth implementing.
3363 static int screen_XTERM_SUCS(term_screen *screen, const term_seq *seq) {
3365 * XTERM_SUCS - xterm-select-utf8-character-set
3366 * Select UTF-8 as character set. This is our default on only character
3367 * set. Hence, this is a no-op.
3373 static int screen_XTERM_WM(term_screen *screen, const term_seq *seq) {
3375 * XTERM_WM - xterm-window-management
3377 * Probably not worth implementing.
3385 * The screen_feed_*() handlers take data from the user and feed it into the
3386 * screen. Once the parser has detected a sequence, we parse the command-type
3387 * and forward it to the command-dispatchers.
3390 static int screen_feed_cmd(term_screen *screen, const term_seq *seq) {
3391 switch (seq->command) {
3392 case TERM_CMD_GRAPHIC:
3393 return screen_GRAPHIC(screen, seq);
3395 return screen_BEL(screen, seq);
3397 return screen_BS(screen, seq);
3399 return screen_CBT(screen, seq);
3401 return screen_CHA(screen, seq);
3403 return screen_CHT(screen, seq);
3405 return screen_CNL(screen, seq);
3407 return screen_CPL(screen, seq);
3409 return screen_CR(screen, seq);
3411 return screen_CUB(screen, seq);
3413 return screen_CUD(screen, seq);
3415 return screen_CUF(screen, seq);
3417 return screen_CUP(screen, seq);
3419 return screen_CUU(screen, seq);
3421 return screen_DA1(screen, seq);
3423 return screen_DA2(screen, seq);
3425 return screen_DA3(screen, seq);
3427 return screen_DC1(screen, seq);
3429 return screen_DC3(screen, seq);
3431 return screen_DCH(screen, seq);
3432 case TERM_CMD_DECALN:
3433 return screen_DECALN(screen, seq);
3434 case TERM_CMD_DECANM:
3435 return screen_DECANM(screen, seq);
3436 case TERM_CMD_DECBI:
3437 return screen_DECBI(screen, seq);
3438 case TERM_CMD_DECCARA:
3439 return screen_DECCARA(screen, seq);
3440 case TERM_CMD_DECCRA:
3441 return screen_DECCRA(screen, seq);
3442 case TERM_CMD_DECDC:
3443 return screen_DECDC(screen, seq);
3444 case TERM_CMD_DECDHL_BH:
3445 return screen_DECDHL_BH(screen, seq);
3446 case TERM_CMD_DECDHL_TH:
3447 return screen_DECDHL_TH(screen, seq);
3448 case TERM_CMD_DECDWL:
3449 return screen_DECDWL(screen, seq);
3450 case TERM_CMD_DECEFR:
3451 return screen_DECEFR(screen, seq);
3452 case TERM_CMD_DECELF:
3453 return screen_DECELF(screen, seq);
3454 case TERM_CMD_DECELR:
3455 return screen_DECELR(screen, seq);
3456 case TERM_CMD_DECERA:
3457 return screen_DECERA(screen, seq);
3458 case TERM_CMD_DECFI:
3459 return screen_DECFI(screen, seq);
3460 case TERM_CMD_DECFRA:
3461 return screen_DECFRA(screen, seq);
3462 case TERM_CMD_DECIC:
3463 return screen_DECIC(screen, seq);
3464 case TERM_CMD_DECID:
3465 return screen_DECID(screen, seq);
3466 case TERM_CMD_DECINVM:
3467 return screen_DECINVM(screen, seq);
3468 case TERM_CMD_DECKBD:
3469 return screen_DECKBD(screen, seq);
3470 case TERM_CMD_DECKPAM:
3471 return screen_DECKPAM(screen, seq);
3472 case TERM_CMD_DECKPNM:
3473 return screen_DECKPNM(screen, seq);
3474 case TERM_CMD_DECLFKC:
3475 return screen_DECLFKC(screen, seq);
3476 case TERM_CMD_DECLL:
3477 return screen_DECLL(screen, seq);
3478 case TERM_CMD_DECLTOD:
3479 return screen_DECLTOD(screen, seq);
3480 case TERM_CMD_DECPCTERM:
3481 return screen_DECPCTERM(screen, seq);
3482 case TERM_CMD_DECPKA:
3483 return screen_DECPKA(screen, seq);
3484 case TERM_CMD_DECPKFMR:
3485 return screen_DECPKFMR(screen, seq);
3486 case TERM_CMD_DECRARA:
3487 return screen_DECRARA(screen, seq);
3488 case TERM_CMD_DECRC:
3489 return screen_DECRC(screen, seq);
3490 case TERM_CMD_DECREQTPARM:
3491 return screen_DECREQTPARM(screen, seq);
3492 case TERM_CMD_DECRPKT:
3493 return screen_DECRPKT(screen, seq);
3494 case TERM_CMD_DECRQCRA:
3495 return screen_DECRQCRA(screen, seq);
3496 case TERM_CMD_DECRQDE:
3497 return screen_DECRQDE(screen, seq);
3498 case TERM_CMD_DECRQKT:
3499 return screen_DECRQKT(screen, seq);
3500 case TERM_CMD_DECRQLP:
3501 return screen_DECRQLP(screen, seq);
3502 case TERM_CMD_DECRQM_ANSI:
3503 return screen_DECRQM_ANSI(screen, seq);
3504 case TERM_CMD_DECRQM_DEC:
3505 return screen_DECRQM_DEC(screen, seq);
3506 case TERM_CMD_DECRQPKFM:
3507 return screen_DECRQPKFM(screen, seq);
3508 case TERM_CMD_DECRQPSR:
3509 return screen_DECRQPSR(screen, seq);
3510 case TERM_CMD_DECRQTSR:
3511 return screen_DECRQTSR(screen, seq);
3512 case TERM_CMD_DECRQUPSS:
3513 return screen_DECRQUPSS(screen, seq);
3514 case TERM_CMD_DECSACE:
3515 return screen_DECSACE(screen, seq);
3516 case TERM_CMD_DECSASD:
3517 return screen_DECSASD(screen, seq);
3518 case TERM_CMD_DECSC:
3519 return screen_DECSC(screen, seq);
3520 case TERM_CMD_DECSCA:
3521 return screen_DECSCA(screen, seq);
3522 case TERM_CMD_DECSCL:
3523 return screen_DECSCL(screen, seq);
3524 case TERM_CMD_DECSCP:
3525 return screen_DECSCP(screen, seq);
3526 case TERM_CMD_DECSCPP:
3527 return screen_DECSCPP(screen, seq);
3528 case TERM_CMD_DECSCS:
3529 return screen_DECSCS(screen, seq);
3530 case TERM_CMD_DECSCUSR:
3531 return screen_DECSCUSR(screen, seq);
3532 case TERM_CMD_DECSDDT:
3533 return screen_DECSDDT(screen, seq);
3534 case TERM_CMD_DECSDPT:
3535 return screen_DECSDPT(screen, seq);
3536 case TERM_CMD_DECSED:
3537 return screen_DECSED(screen, seq);
3538 case TERM_CMD_DECSEL:
3539 return screen_DECSEL(screen, seq);
3540 case TERM_CMD_DECSERA:
3541 return screen_DECSERA(screen, seq);
3542 case TERM_CMD_DECSFC:
3543 return screen_DECSFC(screen, seq);
3544 case TERM_CMD_DECSKCV:
3545 return screen_DECSKCV(screen, seq);
3546 case TERM_CMD_DECSLCK:
3547 return screen_DECSLCK(screen, seq);
3548 case TERM_CMD_DECSLE:
3549 return screen_DECSLE(screen, seq);
3550 case TERM_CMD_DECSLPP:
3551 return screen_DECSLPP(screen, seq);
3552 case TERM_CMD_DECSLRM_OR_SC:
3553 return screen_DECSLRM_OR_SC(screen, seq);
3554 case TERM_CMD_DECSMBV:
3555 return screen_DECSMBV(screen, seq);
3556 case TERM_CMD_DECSMKR:
3557 return screen_DECSMKR(screen, seq);
3558 case TERM_CMD_DECSNLS:
3559 return screen_DECSNLS(screen, seq);
3560 case TERM_CMD_DECSPP:
3561 return screen_DECSPP(screen, seq);
3562 case TERM_CMD_DECSPPCS:
3563 return screen_DECSPPCS(screen, seq);
3564 case TERM_CMD_DECSPRTT:
3565 return screen_DECSPRTT(screen, seq);
3566 case TERM_CMD_DECSR:
3567 return screen_DECSR(screen, seq);
3568 case TERM_CMD_DECSRFR:
3569 return screen_DECSRFR(screen, seq);
3570 case TERM_CMD_DECSSCLS:
3571 return screen_DECSSCLS(screen, seq);
3572 case TERM_CMD_DECSSDT:
3573 return screen_DECSSDT(screen, seq);
3574 case TERM_CMD_DECSSL:
3575 return screen_DECSSL(screen, seq);
3576 case TERM_CMD_DECST8C:
3577 return screen_DECST8C(screen, seq);
3578 case TERM_CMD_DECSTBM:
3579 return screen_DECSTBM(screen, seq);
3580 case TERM_CMD_DECSTR:
3581 return screen_DECSTR(screen, seq);
3582 case TERM_CMD_DECSTRL:
3583 return screen_DECSTRL(screen, seq);
3584 case TERM_CMD_DECSWBV:
3585 return screen_DECSWBV(screen, seq);
3586 case TERM_CMD_DECSWL:
3587 return screen_DECSWL(screen, seq);
3588 case TERM_CMD_DECTID:
3589 return screen_DECTID(screen, seq);
3590 case TERM_CMD_DECTME:
3591 return screen_DECTME(screen, seq);
3592 case TERM_CMD_DECTST:
3593 return screen_DECTST(screen, seq);
3595 return screen_DL(screen, seq);
3596 case TERM_CMD_DSR_ANSI:
3597 return screen_DSR_ANSI(screen, seq);
3598 case TERM_CMD_DSR_DEC:
3599 return screen_DSR_DEC(screen, seq);
3601 return screen_ECH(screen, seq);
3603 return screen_ED(screen, seq);
3605 return screen_EL(screen, seq);
3607 return screen_ENQ(screen, seq);
3609 return screen_EPA(screen, seq);
3611 return screen_FF(screen, seq);
3613 return screen_HPA(screen, seq);
3615 return screen_HPR(screen, seq);
3617 return screen_HT(screen, seq);
3619 return screen_HTS(screen, seq);
3621 return screen_HVP(screen, seq);
3623 return screen_ICH(screen, seq);
3625 return screen_IL(screen, seq);
3627 return screen_IND(screen, seq);
3629 return screen_LF(screen, seq);
3631 return screen_LS1R(screen, seq);
3633 return screen_LS2(screen, seq);
3635 return screen_LS2R(screen, seq);
3637 return screen_LS3(screen, seq);
3639 return screen_LS3R(screen, seq);
3640 case TERM_CMD_MC_ANSI:
3641 return screen_MC_ANSI(screen, seq);
3642 case TERM_CMD_MC_DEC:
3643 return screen_MC_DEC(screen, seq);
3645 return screen_NEL(screen, seq);
3647 return screen_NP(screen, seq);
3649 return screen_NULL(screen, seq);
3651 return screen_PP(screen, seq);
3653 return screen_PPA(screen, seq);
3655 return screen_PPB(screen, seq);
3657 return screen_PPR(screen, seq);
3659 return screen_RC(screen, seq);
3661 return screen_REP(screen, seq);
3663 return screen_RI(screen, seq);
3665 return screen_RIS(screen, seq);
3666 case TERM_CMD_RM_ANSI:
3667 return screen_RM_ANSI(screen, seq);
3668 case TERM_CMD_RM_DEC:
3669 return screen_RM_DEC(screen, seq);
3670 case TERM_CMD_S7C1T:
3671 return screen_S7C1T(screen, seq);
3672 case TERM_CMD_S8C1T:
3673 return screen_S8C1T(screen, seq);
3675 return screen_SCS(screen, seq);
3677 return screen_SD(screen, seq);
3679 return screen_SGR(screen, seq);
3681 return screen_SI(screen, seq);
3682 case TERM_CMD_SM_ANSI:
3683 return screen_SM_ANSI(screen, seq);
3684 case TERM_CMD_SM_DEC:
3685 return screen_SM_DEC(screen, seq);
3687 return screen_SO(screen, seq);
3689 return screen_SPA(screen, seq);
3691 return screen_SS2(screen, seq);
3693 return screen_SS3(screen, seq);
3695 return screen_ST(screen, seq);
3697 return screen_SU(screen, seq);
3699 return screen_SUB(screen, seq);
3701 return screen_TBC(screen, seq);
3703 return screen_VPA(screen, seq);
3705 return screen_VPR(screen, seq);
3707 return screen_VT(screen, seq);
3708 case TERM_CMD_XTERM_CLLHP:
3709 return screen_XTERM_CLLHP(screen, seq);
3710 case TERM_CMD_XTERM_IHMT:
3711 return screen_XTERM_IHMT(screen, seq);
3712 case TERM_CMD_XTERM_MLHP:
3713 return screen_XTERM_MLHP(screen, seq);
3714 case TERM_CMD_XTERM_MUHP:
3715 return screen_XTERM_MUHP(screen, seq);
3716 case TERM_CMD_XTERM_RPM:
3717 return screen_XTERM_RPM(screen, seq);
3718 case TERM_CMD_XTERM_RRV:
3719 return screen_XTERM_RRV(screen, seq);
3720 case TERM_CMD_XTERM_RTM:
3721 return screen_XTERM_RTM(screen, seq);
3722 case TERM_CMD_XTERM_SACL1:
3723 return screen_XTERM_SACL1(screen, seq);
3724 case TERM_CMD_XTERM_SACL2:
3725 return screen_XTERM_SACL2(screen, seq);
3726 case TERM_CMD_XTERM_SACL3:
3727 return screen_XTERM_SACL3(screen, seq);
3728 case TERM_CMD_XTERM_SDCS:
3729 return screen_XTERM_SDCS(screen, seq);
3730 case TERM_CMD_XTERM_SGFX:
3731 return screen_XTERM_SGFX(screen, seq);
3732 case TERM_CMD_XTERM_SPM:
3733 return screen_XTERM_SPM(screen, seq);
3734 case TERM_CMD_XTERM_SRV:
3735 return screen_XTERM_SRV(screen, seq);
3736 case TERM_CMD_XTERM_STM:
3737 return screen_XTERM_STM(screen, seq);
3738 case TERM_CMD_XTERM_SUCS:
3739 return screen_XTERM_SUCS(screen, seq);
3740 case TERM_CMD_XTERM_WM:
3741 return screen_XTERM_WM(screen, seq);
3747 unsigned int term_screen_get_width(term_screen *screen) {
3748 assert_return(screen, -EINVAL);
3750 return screen->page->width;
3753 unsigned int term_screen_get_height(term_screen *screen) {
3754 assert_return(screen, -EINVAL);
3756 return screen->page->height;
3759 int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size) {
3761 size_t i, j, ucs4_len;
3762 const term_seq *seq;
3765 assert_return(screen, -EINVAL);
3767 /* Feed bytes into utf8 decoder and handle parsed ucs4 chars. We always
3768 * treat data as UTF-8, but the parser makes sure to fall back to raw
3769 * 8bit mode if the stream is not valid UTF-8. This should be more than
3770 * enough to support old 7bit/8bit modes. */
3771 for (i = 0; i < size; ++i) {
3772 ucs4_len = term_utf8_decode(&screen->utf8, &ucs4_str, in[i]);
3773 for (j = 0; j < ucs4_len; ++j) {
3774 r = term_parser_feed(screen->parser, &seq, ucs4_str[j]);
3777 } else if (r != TERM_SEQ_NONE) {
3778 r = screen_feed_cmd(screen, seq);
3788 static char *screen_map_key(term_screen *screen,
3790 const uint32_t *keysyms,
3793 const uint32_t *ucs4,
3794 unsigned int mods) {
3795 char ch, ch2, ch_mods;
3799 /* TODO: All these key-mappings need to be verified. Public information
3800 * on those mappings is pretty scarce and every emulator seems to do it
3801 * slightly differently.
3802 * A lot of mappings are also missing. */
3810 v = XKB_KEY_NoSymbol;
3812 /* In some mappings, the modifiers are encoded as CSI parameters. The
3813 * encoding is rather arbitrary, but seems to work. */
3815 switch (mods & (TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT | TERM_KBDMOD_CTRL)) {
3816 case TERM_KBDMOD_SHIFT:
3819 case TERM_KBDMOD_ALT:
3822 case TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT:
3825 case TERM_KBDMOD_CTRL:
3828 case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT:
3831 case TERM_KBDMOD_CTRL | TERM_KBDMOD_ALT:
3834 case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT:
3839 /* A user might actually use multiple layouts for keyboard
3840 * input. @keysyms[0] contains the actual keysym that the user
3841 * used. But if this keysym is not in the ascii range, the
3842 * input handler does check all other layouts that the user
3843 * specified whether one of them maps the key to some ASCII
3844 * keysym and provides this via @ascii. We always use the real
3845 * keysym except when handling CTRL+<XY> shortcuts we use the
3846 * ascii keysym. This is for compatibility to xterm et. al. so
3847 * ctrl+c always works regardless of the currently active
3848 * keyboard layout. But if no ascii-sym is found, we still use
3849 * the real keysym. */
3850 if (ascii == XKB_KEY_NoSymbol)
3853 /* map CTRL+<ascii> */
3854 if (mods & TERM_KBDMOD_CTRL) {
3857 /* Right hand side is mapped to the left and then
3858 * treated equally. Fall through to left-hand side.. */
3861 /* Printable ASCII is mapped 1-1 in XKB and in
3862 * combination with CTRL bit 7 is flipped. This
3863 * is equivalent to the caret-notation. */
3864 *p++ = ascii ^ 0x40;
3869 /* map cursor keys */
3893 if (screen->flags & TERM_FLAG_CURSOR_KEYS)
3906 /* map action keys */
3912 case XKB_KEY_Insert:
3915 case XKB_KEY_Delete:
3918 case XKB_KEY_Select:
3921 case XKB_KEY_Page_Up:
3924 case XKB_KEY_Page_Down:
3940 /* map lower function keys */
3973 /* map upper function keys */
4024 /* map special keys */
4026 case 0xff08: /* XKB_KEY_BackSpace */
4027 case 0xff09: /* XKB_KEY_Tab */
4028 case 0xff0a: /* XKB_KEY_Linefeed */
4029 case 0xff0b: /* XKB_KEY_Clear */
4030 case 0xff15: /* XKB_KEY_Sys_Req */
4031 case 0xff1b: /* XKB_KEY_Escape */
4032 case 0xffff: /* XKB_KEY_Delete */
4035 case 0xff13: /* XKB_KEY_Pause */
4036 /* TODO: What should we do with this key?
4037 * Sending XOFF is awful as there is no simple
4038 * way on modern keyboards to send XON again.
4039 * If someone wants this, we can re-eanble
4042 case 0xff14: /* XKB_KEY_Scroll_Lock */
4043 /* TODO: What should we do on scroll-lock?
4044 * Sending 0x14 is what the specs say but it is
4045 * not used today the way most users would
4046 * expect so we disable it. If someone wants
4047 * this, we can re-enable it (optionally). */
4049 case XKB_KEY_Return:
4051 if (screen->flags & TERM_FLAG_NEWLINE_MODE)
4054 case XKB_KEY_ISO_Left_Tab:
4059 /* map unicode keys */
4060 for (i = 0; i < n_syms; ++i)
4061 p += term_utf8_encode(p, ucs4[i]);
4066 int term_screen_feed_keyboard(term_screen *screen,
4067 const uint32_t *keysyms,
4070 const uint32_t *ucs4,
4071 unsigned int mods) {
4072 _cleanup_free_ char *dyn = NULL;
4073 static const size_t padding = 1;
4074 char buf[128], *start, *p = buf;
4076 assert_return(screen, -EINVAL);
4078 /* allocate buffer if too small */
4080 if (4 * n_syms + padding > sizeof(buf)) {
4081 dyn = malloc(4 * n_syms + padding);
4088 /* reserve prefix space */
4092 p = screen_map_key(screen, p, keysyms, n_syms, ascii, ucs4, mods);
4093 if (!p || p - start < 1)
4096 /* The ALT modifier causes ESC to be prepended to any key-stroke. We
4097 * already accounted for that buffer space above, so simply prepend it
4099 * TODO: is altSendsEscape a suitable default? What are the semantics
4100 * exactly? Is it used in C0/C1 conversion? Is it prepended if there
4101 * already is an escape character? */
4102 if (mods & TERM_KBDMOD_ALT && *start != 0x1b)
4105 /* turn C0 into C1 */
4106 if (!(screen->flags & TERM_FLAG_7BIT_MODE) && p - start >= 2)
4107 if (start[0] == 0x1b && start[1] >= 0x40 && start[1] <= 0x5f)
4110 return screen_write(screen, start, p - start);
4113 int term_screen_resize(term_screen *screen, unsigned int x, unsigned int y) {
4118 assert_return(screen, -EINVAL);
4120 r = term_page_reserve(screen->page_main, x, y, &screen->attr, screen->age);
4124 r = term_page_reserve(screen->page_alt, x, y, &screen->attr, screen->age);
4128 if (x > screen->n_tabs) {
4129 t = realloc(screen->tabs, (x + 7) / 8);
4137 for (i = (screen->page->width + 7) / 8 * 8; i < x; i += 8)
4138 screen->tabs[i / 8] = 0x1;
4140 term_page_resize(screen->page_main, x, y, &screen->attr, screen->age, screen->history);
4141 term_page_resize(screen->page_alt, x, y, &screen->attr, screen->age, NULL);
4143 screen->cursor_x = screen_clamp_x(screen, screen->cursor_x);
4144 screen->cursor_y = screen_clamp_x(screen, screen->cursor_y);
4145 screen_cursor_clear_wrap(screen);
4150 void term_screen_soft_reset(term_screen *screen) {
4155 screen->gl = &screen->g0;
4156 screen->gr = &screen->g1;
4159 screen->g0 = &term_unicode_lower;
4160 screen->g1 = &term_unicode_upper;
4161 screen->g2 = &term_unicode_lower;
4162 screen->g3 = &term_unicode_upper;
4164 screen->page = screen->page_main;
4165 screen->history = screen->history_main;
4166 screen->flags = TERM_FLAG_7BIT_MODE;
4167 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
4168 screen->attr = screen->default_attr;
4170 screen->saved.cursor_x = 0;
4171 screen->saved.cursor_y = 0;
4172 screen->saved.attr = screen->attr;
4173 screen->saved.gl = screen->gl;
4174 screen->saved.gr = screen->gr;
4175 screen->saved.glt = NULL;
4176 screen->saved.grt = NULL;
4179 for (i = 0; i < screen->page->width; i += 8)
4180 screen->tabs[i / 8] = 0x1;
4182 term_page_set_scroll_region(screen->page_main, 0, screen->page->height);
4183 term_page_set_scroll_region(screen->page_alt, 0, screen->page->height);
4186 void term_screen_hard_reset(term_screen *screen) {
4189 term_screen_soft_reset(screen);
4191 screen->cursor_x = 0;
4192 screen->cursor_y = 0;
4193 term_page_erase(screen->page_main, 0, 0, screen->page->width, screen->page->height, &screen->attr, screen->age, false);
4194 term_page_erase(screen->page_alt, 0, 0, screen->page->width, screen->page->height, &screen->attr, screen->age, false);
4197 int term_screen_set_answerback(term_screen *screen, const char *answerback) {
4200 assert_return(screen, -EINVAL);
4203 t = strdup(answerback);
4208 free(screen->answerback);
4209 screen->answerback = t;
4214 int term_screen_draw(term_screen *screen,
4215 int (*draw_fn) (term_screen *screen,
4219 const term_attr *attr,
4222 unsigned int ch_width),
4225 uint64_t cell_age, line_age, age = 0;
4226 term_charbuf_t ch_buf;
4227 const uint32_t *ch_str;
4228 unsigned int i, j, cw;
4241 page = screen->page;
4243 for (j = 0; j < page->height; ++j) {
4244 line = page->lines[j];
4245 line_age = MAX(line->age, page->age);
4247 for (i = 0; i < page->width; ++i) {
4248 cell = &line->cells[i];
4249 cell_age = MAX(cell->age, line_age);
4251 if (age != 0 && cell_age <= age)
4254 ch_str = term_char_resolve(cell->ch, &ch_n, &ch_buf);
4256 /* Character-width of 0 is used for cleared cells.
4257 * Always treat this as single-cell character, so
4258 * renderers can assume ch_width is set properpy. */
4259 cw = MAX(cell->cwidth, 1U);
4275 *fb_age = screen->age++;