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);
422 screen_age_cursor(screen);
429 /* map a character according to current GL and GR maps */
430 static uint32_t screen_map(term_screen *screen, uint32_t val) {
433 /* 32 and 127 always map to identity. 160 and 255 map to identity iff a
434 * 96 character set is loaded into GR. Values above 255 always map to
439 nval = (**screen->glt)[val - 32];
442 nval = (**screen->gl)[val - 32];
447 nval = (**screen->grt)[val - 160];
450 nval = (**screen->gr)[val - 160];
455 return (nval == -1U) ? val : nval;
460 * This is the unofficial documentation of all the TERM_CMD_* definitions. Each
461 * handled command has a separate function with an extensive comment on the
462 * semantics of the command.
463 * Note that many semantics are unknown and need to be verified. This is mostly
464 * about error-handling, though. Applications rarely rely on those features.
467 static int screen_DA1(term_screen *screen, const term_seq *seq);
468 static int screen_LF(term_screen *screen, const term_seq *seq);
470 static int screen_GRAPHIC(term_screen *screen, const term_seq *seq) {
471 term_char_t ch = TERM_CHAR_NULL;
474 if (screen->cursor_x + 1 == screen->page->width
475 && screen->flags & TERM_FLAG_PENDING_WRAP
476 && screen->flags & TERM_FLAG_AUTO_WRAP) {
477 screen_cursor_down(screen, 1, true);
478 screen_cursor_set(screen, 0, screen->cursor_y);
481 screen_cursor_clear_wrap(screen);
483 c = screen_map(screen, seq->terminator);
484 ch = term_char_merge(ch, screen_map(screen, c));
485 term_page_write(screen->page, screen->cursor_x, screen->cursor_y, ch, 1, &screen->attr, screen->age, false);
487 if (screen->cursor_x + 1 == screen->page->width)
488 screen->flags |= TERM_FLAG_PENDING_WRAP;
490 screen_cursor_right(screen, 1);
495 static int screen_BEL(term_screen *screen, const term_seq *seq) {
497 * BEL - sound bell tone
498 * This command should trigger an acoustic bell. Usually, this is
499 * forwarded directly to the pcspkr. However, bells have become quite
500 * uncommon and annoying, so we're not implementing them here. Instead,
501 * it's one of the commands we forward to the caller.
504 return screen_forward(screen, TERM_CMD_BEL, seq);
507 static int screen_BS(term_screen *screen, const term_seq *seq) {
510 * Move cursor one cell to the left. If already at the left margin,
514 screen_cursor_clear_wrap(screen);
515 screen_cursor_left(screen, 1);
519 static int screen_CBT(term_screen *screen, const term_seq *seq) {
521 * CBT - cursor-backward-tabulation
522 * Move the cursor @args[0] tabs backwards (to the left). The
523 * current cursor cell, in case it's a tab, is not counted.
524 * Furthermore, the cursor cannot be moved beyond position 0 and
525 * it will stop there.
531 unsigned int num = 1;
533 if (seq->args[0] > 0)
536 screen_cursor_clear_wrap(screen);
537 screen_cursor_left_tab(screen, num);
542 static int screen_CHA(term_screen *screen, const term_seq *seq) {
544 * CHA - cursor-horizontal-absolute
545 * Move the cursor to position @args[0] in the current line. The
546 * cursor cannot be moved beyond the rightmost cell and will stop
553 unsigned int pos = 1;
555 if (seq->args[0] > 0)
558 screen_cursor_clear_wrap(screen);
559 screen_cursor_set(screen, pos - 1, screen->cursor_y);
564 static int screen_CHT(term_screen *screen, const term_seq *seq) {
566 * CHT - cursor-horizontal-forward-tabulation
567 * Move the cursor @args[0] tabs forward (to the right). The
568 * current cursor cell, in case it's a tab, is not counted.
569 * Furthermore, the cursor cannot be moved beyond the rightmost cell
570 * and will stop there.
576 unsigned int num = 1;
578 if (seq->args[0] > 0)
581 screen_cursor_clear_wrap(screen);
582 screen_cursor_right_tab(screen, num);
587 static int screen_CNL(term_screen *screen, const term_seq *seq) {
589 * CNL - cursor-next-line
590 * Move the cursor @args[0] lines down.
592 * TODO: Does this stop at the bottom or cause a scroll-up?
598 unsigned int num = 1;
600 if (seq->args[0] > 0)
603 screen_cursor_clear_wrap(screen);
604 screen_cursor_down(screen, num, false);
609 static int screen_CPL(term_screen *screen, const term_seq *seq) {
611 * CPL - cursor-preceding-line
612 * Move the cursor @args[0] lines up.
614 * TODO: Does this stop at the top or cause a scroll-up?
620 unsigned int num = 1;
622 if (seq->args[0] > 0)
625 screen_cursor_clear_wrap(screen);
626 screen_cursor_up(screen, num, false);
631 static int screen_CR(term_screen *screen, const term_seq *seq) {
633 * CR - carriage-return
634 * Move the cursor to the left margin on the current line.
637 screen_cursor_clear_wrap(screen);
638 screen_cursor_set(screen, 0, screen->cursor_y);
643 static int screen_CUB(term_screen *screen, const term_seq *seq) {
645 * CUB - cursor-backward
646 * Move the cursor @args[0] positions to the left. The cursor stops
647 * at the left-most position.
653 unsigned int num = 1;
655 if (seq->args[0] > 0)
658 screen_cursor_clear_wrap(screen);
659 screen_cursor_left(screen, num);
664 static int screen_CUD(term_screen *screen, const term_seq *seq) {
667 * Move the cursor @args[0] positions down. The cursor stops at the
668 * bottom margin. If it was already moved further, it stops at the
675 unsigned int num = 1;
677 if (seq->args[0] > 0)
680 screen_cursor_clear_wrap(screen);
681 screen_cursor_down(screen, num, false);
686 static int screen_CUF(term_screen *screen, const term_seq *seq) {
688 * CUF -cursor-forward
689 * Move the cursor @args[0] positions to the right. The cursor stops
690 * at the right-most position.
696 unsigned int num = 1;
698 if (seq->args[0] > 0)
701 screen_cursor_clear_wrap(screen);
702 screen_cursor_right(screen, num);
707 static int screen_CUP(term_screen *screen, const term_seq *seq) {
709 * CUP - cursor-position
710 * Moves the cursor to position @args[1] x @args[0]. If either is 0, it
711 * is treated as 1. The positions are subject to the origin-mode and
712 * clamped to the addressable with/height.
719 unsigned int x = 1, y = 1;
721 if (seq->args[0] > 0)
723 if (seq->args[1] > 0)
726 screen_cursor_clear_wrap(screen);
727 screen_cursor_set_rel(screen, x - 1, y - 1);
732 static int screen_CUU(term_screen *screen, const term_seq *seq) {
735 * Move the cursor @args[0] positions up. The cursor stops at the
736 * top margin. If it was already moved further, it stops at the
744 unsigned int num = 1;
746 if (seq->args[0] > 0)
749 screen_cursor_clear_wrap(screen);
750 screen_cursor_up(screen, num, false);
755 static int screen_DA1(term_screen *screen, const term_seq *seq) {
757 * DA1 - primary-device-attributes
758 * The primary DA asks for basic terminal features. We simply return
759 * a hard-coded list of features we implement.
760 * Note that the primary DA asks for supported features, not currently
763 * The terminal's answer is:
765 * The first argument, 64, is fixed and denotes a VT420, the last
766 * DEC-term that extended this number.
767 * All following arguments denote supported features. Note
768 * that at most 15 features can be sent (max CSI args). It is safe to
769 * send more, but clients might not be able to parse them. This is a
770 * client's problem and we shouldn't care. There is no other way to
771 * send those feature lists, so we have to extend them beyond 15 in
776 * The 132 column mode is supported by the terminal.
778 * A priner-port is supported and can be addressed via
781 * Support for ReGIS graphics is available. The ReGIS routines
782 * provide the "remote graphics instruction set" and allow basic
785 * Support of Sixel graphics is available. This provides access
786 * to the sixel bitmap routines.
788 * The terminal supports DECSCA and related selective-erase
789 * functions. This allows to protect specific cells from being
790 * erased, if specified.
791 * 7: soft character set (DRCS)
793 * 8: user-defined keys (UDKs)
795 * 9: national-replacement character sets (NRCS)
796 * National-replacement character-sets are available.
797 * 12: Yugoslavian (SCS)
799 * 15: technical character set
800 * The DEC technical-character-set is available.
801 * 18: windowing capability
803 * 21: horizontal scrolling
811 * 29: ANSI text locator
813 * 42: ISO Latin-2 character set
819 * 46: ASCII emulation
823 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "?64;1;6;9;15c");
826 static int screen_DA2(term_screen *screen, const term_seq *seq) {
828 * DA2 - secondary-device-attributes
829 * The secondary DA asks for the terminal-ID, firmware versions and
830 * other non-primary attributes. All these values are
831 * informational-only and should not be used by the host to detect
834 * The terminal's response is:
835 * ^[ > 61 ; FIRMWARE ; KEYBOARD c
836 * whereas 65 is fixed for VT525 terminals, the last terminal-line that
837 * increased this number. FIRMWARE is the firmware
838 * version encoded as major/minor (20 == 2.0) and KEYBOARD is 0 for STD
839 * keyboard and 1 for PC keyboards.
841 * We replace the firmware-version with the systemd-version so clients
842 * can decode it again.
845 return SEQ_WRITE(screen, C0_CSI, C1_CSI, ">65;" PACKAGE_VERSION ";1c");
848 static int screen_DA3(term_screen *screen, const term_seq *seq) {
850 * DA3 - tertiary-device-attributes
851 * The tertiary DA is used to query the terminal-ID.
853 * The terminal's response is:
854 * ^P ! | XX AA BB CC ^\
855 * whereas all four parameters are hexadecimal-encoded pairs. XX
856 * denotes the manufacturing site, AA BB CC is the terminal's ID.
859 /* we do not support tertiary DAs */
863 static int screen_DC1(term_screen *screen, const term_seq *seq) {
865 * DC1 - device-control-1 or XON
866 * This clears any previous XOFF and resumes terminal-transmission.
869 /* we do not support XON */
873 static int screen_DC3(term_screen *screen, const term_seq *seq) {
875 * DC3 - device-control-3 or XOFF
876 * Stops terminal transmission. No further characters are sent until
877 * an XON is received.
880 /* we do not support XOFF */
884 static int screen_DCH(term_screen *screen, const term_seq *seq) {
886 * DCH - delete-character
887 * This deletes @argv[0] characters at the current cursor position. As
888 * characters are deleted, the remaining characters between the cursor
889 * and right margin move to the left. Character attributes move with the
890 * characters. The terminal adds blank spaces with no visual character
891 * attributes at the right margin. DCH has no effect outside the
898 unsigned int num = 1;
900 if (seq->args[0] > 0)
903 screen_cursor_clear_wrap(screen);
904 term_page_delete_cells(screen->page, screen->cursor_x, screen->cursor_y, num, &screen->attr, screen->age);
909 static int screen_DECALN(term_screen *screen, const term_seq *seq) {
911 * DECALN - screen-alignment-pattern
913 * Probably not worth implementing.
919 static int screen_DECANM(term_screen *screen, const term_seq *seq) {
922 * Set the terminal into VT52 compatibility mode. Control sequences
923 * overlap with regular sequences so we have to detect them early before
926 * Probably not worth implementing.
932 static int screen_DECBI(term_screen *screen, const term_seq *seq) {
935 * This control function moves the cursor backward one column. If the
936 * cursor is at the left margin, then all screen data within the margin
937 * moves one column to the right. The column that shifted past the right
939 * DECBI adds a new column at the left margin with no visual attributes.
940 * DECBI does not affect the margins. If the cursor is beyond the
941 * left-margin at the left border, then the terminal ignores DECBI.
943 * Probably not worth implementing.
949 static int screen_DECCARA(term_screen *screen, const term_seq *seq) {
951 * DECCARA - change-attributes-in-rectangular-area
953 * Probably not worth implementing.
959 static int screen_DECCRA(term_screen *screen, const term_seq *seq) {
961 * DECCRA - copy-rectangular-area
963 * Probably not worth implementing.
969 static int screen_DECDC(term_screen *screen, const term_seq *seq) {
971 * DECDC - delete-column
973 * Probably not worth implementing.
979 static int screen_DECDHL_BH(term_screen *screen, const term_seq *seq) {
981 * DECDHL_BH - double-width-double-height-line: bottom half
983 * Probably not worth implementing.
989 static int screen_DECDHL_TH(term_screen *screen, const term_seq *seq) {
991 * DECDHL_TH - double-width-double-height-line: top half
993 * Probably not worth implementing.
999 static int screen_DECDWL(term_screen *screen, const term_seq *seq) {
1001 * DECDWL - double-width-single-height-line
1003 * Probably not worth implementing.
1009 static int screen_DECEFR(term_screen *screen, const term_seq *seq) {
1011 * DECEFR - enable-filter-rectangle
1012 * Defines the coordinates of a filter rectangle (top, left, bottom,
1013 * right as @args[0] to @args[3]) and activates it.
1014 * Anytime the locator is detected outside of the filter rectangle, an
1015 * outside rectangle event is generated and the rectangle is disabled.
1016 * Filter rectangles are always treated as "one-shot" events. Any
1017 * parameters that are omitted default to the current locator position.
1018 * If all parameters are omitted, any locator motion will be reported.
1019 * DECELR always cancels any prevous rectangle definition.
1021 * The locator is usually associated with the mouse-cursor, but based
1022 * on cells instead of pixels. See DECELR how to initialize and enable
1023 * it. DECELR can also enable pixel-mode instead of cell-mode.
1031 static int screen_DECELF(term_screen *screen, const term_seq *seq) {
1033 * DECELF - enable-local-functions
1035 * Probably not worth implementing.
1041 static int screen_DECELR(term_screen *screen, const term_seq *seq) {
1043 * DECELR - enable-locator-reporting
1044 * This changes the locator-reporting mode. @args[0] specifies the mode
1045 * to set, 0 disables locator-reporting, 1 enables it continuously, 2
1046 * enables it for a single report. @args[1] specifies the
1047 * precision-mode. 0 and 2 set the reporting to cell-precision, 1 sets
1060 static int screen_DECERA(term_screen *screen, const term_seq *seq) {
1062 * DECERA - erase-rectangular-area
1064 * Probably not worth implementing.
1070 static int screen_DECFI(term_screen *screen, const term_seq *seq) {
1072 * DECFI - forward-index
1073 * This control function moves the cursor forward one column. If the
1074 * cursor is at the right margin, then all screen data within the
1075 * margins moves one column to the left. The column shifted past the
1076 * left margin is lost.
1077 * DECFI adds a new column at the right margin, with no visual
1078 * attributes. DECFI does not affect margins. If the cursor is beyond
1079 * the right margin at the border of the page when the terminal
1080 * receives DECFI, then the terminal ignores DECFI.
1082 * Probably not worth implementing.
1088 static int screen_DECFRA(term_screen *screen, const term_seq *seq) {
1090 * DECFRA - fill-rectangular-area
1092 * Probably not worth implementing.
1098 static int screen_DECIC(term_screen *screen, const term_seq *seq) {
1100 * DECIC - insert-column
1102 * Probably not worth implementing.
1108 static int screen_DECID(term_screen *screen, const term_seq *seq) {
1110 * DECID - return-terminal-id
1111 * This is an obsolete form of TERM_CMD_DA1.
1114 return screen_DA1(screen, seq);
1117 static int screen_DECINVM(term_screen *screen, const term_seq *seq) {
1119 * DECINVM - invoke-macro
1121 * Probably not worth implementing.
1127 static int screen_DECKBD(term_screen *screen, const term_seq *seq) {
1129 * DECKBD - keyboard-language-selection
1131 * Probably not worth implementing.
1137 static int screen_DECKPAM(term_screen *screen, const term_seq *seq) {
1139 * DECKPAM - keypad-application-mode
1140 * Enables the keypad-application mode. If enabled, the keypad sends
1141 * special characters instead of the printed characters. This way,
1142 * applications can detect whether a numeric key was pressed on the
1143 * top-row or on the keypad.
1144 * Default is keypad-numeric-mode.
1147 screen->flags |= TERM_FLAG_KEYPAD_MODE;
1152 static int screen_DECKPNM(term_screen *screen, const term_seq *seq) {
1154 * DECKPNM - keypad-numeric-mode
1155 * This disables the keypad-application-mode (DECKPAM) and returns to
1156 * the keypad-numeric-mode. Keypresses on the keypad generate the same
1157 * sequences as corresponding keypresses on the main keyboard.
1158 * Default is keypad-numeric-mode.
1161 screen->flags &= ~TERM_FLAG_KEYPAD_MODE;
1166 static int screen_DECLFKC(term_screen *screen, const term_seq *seq) {
1168 * DECLFKC - local-function-key-control
1170 * Probably not worth implementing.
1176 static int screen_DECLL(term_screen *screen, const term_seq *seq) {
1180 * Probably not worth implementing.
1186 static int screen_DECLTOD(term_screen *screen, const term_seq *seq) {
1188 * DECLTOD - load-time-of-day
1190 * Probably not worth implementing.
1196 static int screen_DECPCTERM(term_screen *screen, const term_seq *seq) {
1198 * DECPCTERM - pcterm-mode
1199 * This enters/exits the PCTerm mode. Default mode is VT-mode. It can
1200 * also select parameters for scancode/keycode mappings in SCO mode.
1202 * Definitely not worth implementing. Lets kill PCTerm/SCO modes!
1208 static int screen_DECPKA(term_screen *screen, const term_seq *seq) {
1210 * DECPKA - program-key-action
1212 * Probably not worth implementing.
1218 static int screen_DECPKFMR(term_screen *screen, const term_seq *seq) {
1220 * DECPKFMR - program-key-free-memory-report
1222 * Probably not worth implementing.
1228 static int screen_DECRARA(term_screen *screen, const term_seq *seq) {
1230 * DECRARA - reverse-attributes-in-rectangular-area
1232 * Probably not worth implementing.
1238 static int screen_DECRC(term_screen *screen, const term_seq *seq) {
1240 * DECRC - restore-cursor
1241 * Restores the terminal to the state saved by the save cursor (DECSC)
1242 * function. This includes more than just the cursor-position.
1244 * If nothing was saved by DECSC, then DECRC performs the following
1246 * * Moves the cursor to the home position (upper left of screen).
1247 * * Resets origin mode (DECOM).
1248 * * Turns all character attributes off (normal setting).
1249 * * Maps the ASCII character set into GL, and the DEC Supplemental
1250 * Graphic set into GR.
1252 * The terminal maintains a separate DECSC buffer for the main display
1253 * and the status line. This feature lets you save a separate operating
1254 * state for the main display and the status line.
1257 screen->attr = screen->saved.attr;
1258 screen->gl = screen->saved.gl;
1259 screen->gr = screen->saved.gr;
1260 screen->glt = screen->saved.glt;
1261 screen->grt = screen->saved.grt;
1262 set_reset(screen, TERM_FLAG_AUTO_WRAP, screen->saved.flags & TERM_FLAG_AUTO_WRAP);
1263 set_reset(screen, TERM_FLAG_ORIGIN_MODE, screen->saved.flags & TERM_FLAG_ORIGIN_MODE);
1264 screen_cursor_set(screen, screen->saved.cursor_x, screen->saved.cursor_y);
1269 static int screen_DECREQTPARM(term_screen *screen, const term_seq *seq) {
1271 * DECREQTPARM - request-terminal-parameters
1272 * The sequence DECREPTPARM is sent by the terminal controller to notify
1273 * the host of the status of selected terminal parameters. The status
1274 * sequence may be sent when requested by the host or at the terminal's
1275 * discretion. DECREPTPARM is sent upon receipt of a DECREQTPARM.
1277 * If @args[0] is 0, this marks a request and the terminal is allowed
1278 * to send DECREPTPARM messages without request. If it is 1, the same
1279 * applies but the terminal should no longer send DECREPTPARM
1281 * 2 and 3 mark a report, but 3 is only used if the terminal answers as
1282 * an explicit request with @args[0] == 1.
1284 * The other arguments are ignored in requests, but have the following
1285 * meaning in responses:
1286 * args[1]: 1=no-parity-set 4=parity-set-and-odd 5=parity-set-and-even
1287 * args[2]: 1=8bits-per-char 2=7bits-per-char
1288 * args[3]: transmission-speed
1289 * args[4]: receive-speed
1290 * args[5]: 1=bit-rate-multiplier-is-16
1291 * args[6]: This value communicates the four switch values in block 5
1292 * of SETUP B, which are only visible to the user when an STP
1293 * option is installed. These bits may be assigned for an STP
1294 * device. The four bits are a decimal-encoded binary number.
1295 * Value between 0-15.
1297 * The transmission/receive speeds have mappings for number => bits/s
1298 * which are quite weird. Examples are: 96->3600, 112->9600, 120->19200
1304 if (seq->n_args < 1 || seq->args[0] == 0) {
1305 screen->flags &= ~TERM_FLAG_INHIBIT_TPARM;
1306 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "2;1;1;120;120;1;0x");
1307 } else if (seq->args[0] == 1) {
1308 screen->flags |= TERM_FLAG_INHIBIT_TPARM;
1309 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "3;1;1;120;120;1;0x");
1315 static int screen_DECRPKT(term_screen *screen, const term_seq *seq) {
1317 * DECRPKT - report-key-type
1318 * Response to DECRQKT, we can safely ignore it as we're the one sending
1325 static int screen_DECRQCRA(term_screen *screen, const term_seq *seq) {
1327 * DECRQCRA - request-checksum-of-rectangular-area
1329 * Probably not worth implementing.
1335 static int screen_DECRQDE(term_screen *screen, const term_seq *seq) {
1337 * DECRQDE - request-display-extent
1339 * Probably not worth implementing.
1345 static int screen_DECRQKT(term_screen *screen, const term_seq *seq) {
1347 * DECRQKT - request-key-type
1349 * Probably not worth implementing.
1355 static int screen_DECRQLP(term_screen *screen, const term_seq *seq) {
1357 * DECRQLP - request-locator-position
1358 * See DECELR for locator-information.
1360 * TODO: document and implement
1366 static int screen_DECRQM_ANSI(term_screen *screen, const term_seq *seq) {
1368 * DECRQM_ANSI - request-mode-ansi
1369 * The host sends this control function to find out if a particular mode
1370 * is set or reset. The terminal responds with a report mode function.
1371 * @args[0] contains the mode to query.
1373 * Response is DECRPM with the first argument set to the mode that was
1374 * queried, second argument is 0 if mode is invalid, 1 if mode is set,
1375 * 2 if mode is not set (reset), 3 if mode is permanently set and 4 if
1376 * mode is permanently not set (reset):
1377 * ANSI: ^[ MODE ; VALUE $ y
1378 * DEC: ^[ ? MODE ; VALUE $ y
1386 static int screen_DECRQM_DEC(term_screen *screen, const term_seq *seq) {
1388 * DECRQM_DEC - request-mode-dec
1389 * Same as DECRQM_ANSI but for DEC modes.
1397 static int screen_DECRQPKFM(term_screen *screen, const term_seq *seq) {
1399 * DECRQPKFM - request-program-key-free-memory
1401 * Probably not worth implementing.
1407 static int screen_DECRQPSR(term_screen *screen, const term_seq *seq) {
1409 * DECRQPSR - request-presentation-state-report
1411 * Probably not worth implementing.
1417 static int screen_DECRQTSR(term_screen *screen, const term_seq *seq) {
1419 * DECRQTSR - request-terminal-state-report
1421 * Probably not worth implementing.
1427 static int screen_DECRQUPSS(term_screen *screen, const term_seq *seq) {
1429 * DECRQUPSS - request-user-preferred-supplemental-set
1431 * Probably not worth implementing.
1437 static int screen_DECSACE(term_screen *screen, const term_seq *seq) {
1439 * DECSACE - select-attribute-change-extent
1441 * Probably not worth implementing.
1447 static int screen_DECSASD(term_screen *screen, const term_seq *seq) {
1449 * DECSASD - select-active-status-display
1451 * Probably not worth implementing.
1457 static int screen_DECSC(term_screen *screen, const term_seq *seq) {
1459 * DECSC - save-cursor
1460 * Save cursor and terminal state so it can be restored later on.
1461 * Saves the following items in the terminal's memory:
1463 * * Character attributes set by the SGR command
1464 * * Character sets (G0, G1, G2, or G3) currently in GL and GR
1465 * * Wrap flag (autowrap or no autowrap)
1466 * * State of origin mode (DECOM)
1467 * * Selective erase attribute
1468 * * Any single shift 2 (SS2) or single shift 3 (SS3) functions sent
1471 screen->saved.cursor_x = screen->cursor_x;
1472 screen->saved.cursor_y = screen->cursor_y;
1473 screen->saved.attr = screen->attr;
1474 screen->saved.gl = screen->gl;
1475 screen->saved.gr = screen->gr;
1476 screen->saved.glt = screen->glt;
1477 screen->saved.grt = screen->grt;
1478 screen->saved.flags = screen->flags & (TERM_FLAG_AUTO_WRAP
1479 | TERM_FLAG_ORIGIN_MODE);
1484 static int screen_DECSCA(term_screen *screen, const term_seq *seq) {
1486 * DECSCA - select-character-protection-attribute
1487 * Defines the characters that come after it as erasable or not erasable
1488 * from the screen. The selective erase control functions (DECSED and
1489 * DECSEL) can only erase characters defined as erasable.
1491 * @args[0] specifies the new mode. 0 and 2 mark any following character
1492 * as erasable, 1 marks it as not erasable.
1498 unsigned int mode = 0;
1500 if (seq->args[0] > 0)
1501 mode = seq->args[0];
1506 screen->attr.protect = 0;
1509 screen->attr.protect = 1;
1516 static int screen_DECSCL(term_screen *screen, const term_seq *seq) {
1518 * DECSCL - select-conformance-level
1519 * Select the terminal's operating level. The factory default is
1520 * level 4 (VT Level 4 mode, 7-bit controls).
1521 * When you change the conformance level, the terminal performs a hard
1524 * @args[0] defines the conformance-level, valid values are:
1525 * 61: Level 1 (VT100)
1526 * 62: Level 2 (VT200)
1527 * 63: Level 3 (VT300)
1528 * 64: Level 4 (VT400)
1529 * @args[1] defines the 8bit-mode, valid values are:
1532 * 2: 8-bit controls (same as 0)
1534 * If @args[0] is 61, then @args[1] is ignored and 7bit controls are
1542 unsigned int level = 64, bit = 0;
1544 if (seq->n_args > 0) {
1545 level = seq->args[0];
1546 if (seq->n_args > 1)
1550 term_screen_hard_reset(screen);
1554 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT100;
1555 screen->flags |= TERM_FLAG_7BIT_MODE;
1558 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
1560 screen->flags |= TERM_FLAG_7BIT_MODE;
1562 screen->flags &= ~TERM_FLAG_7BIT_MODE;
1569 static int screen_DECSCP(term_screen *screen, const term_seq *seq) {
1571 * DECSCP - select-communication-port
1573 * Probably not worth implementing.
1579 static int screen_DECSCPP(term_screen *screen, const term_seq *seq) {
1581 * DECSCPP - select-columns-per-page
1582 * Select columns per page. The number of rows is unaffected by this.
1583 * @args[0] selectes the number of columns (width), DEC only defines 80
1584 * and 132, but we allow any integer here. 0 is equivalent to 80.
1585 * Page content is *not* cleared and the cursor is left untouched.
1586 * However, if the page is reduced in width and the cursor would be
1587 * outside the visible region, it's set to the right border. Newly added
1588 * cells are cleared. No data is retained outside the visible region.
1599 static int screen_DECSCS(term_screen *screen, const term_seq *seq) {
1601 * DECSCS - select-communication-speed
1603 * Probably not worth implementing.
1609 static int screen_DECSCUSR(term_screen *screen, const term_seq *seq) {
1611 * DECSCUSR - set-cursor-style
1612 * This changes the style of the cursor. @args[0] can be one of:
1613 * 0, 1: blinking block
1615 * 3: blinking underline
1616 * 4: steady underline
1617 * Changing this setting does _not_ affect the cursor visibility itself.
1618 * Use DECTCEM for that.
1629 static int screen_DECSDDT(term_screen *screen, const term_seq *seq) {
1631 * DECSDDT - select-disconnect-delay-time
1633 * Probably not worth implementing.
1639 static int screen_DECSDPT(term_screen *screen, const term_seq *seq) {
1641 * DECSDPT - select-digital-printed-data-type
1643 * Probably not worth implementing.
1649 static int screen_DECSED(term_screen *screen, const term_seq *seq) {
1651 * DECSED - selective-erase-in-display
1652 * This control function erases some or all of the erasable characters
1653 * in the display. DECSED can only erase characters defined as erasable
1654 * by the DECSCA control function. DECSED works inside or outside the
1655 * scrolling margins.
1657 * @args[0] defines which regions are erased. If it is 0, all cells from
1658 * the cursor (inclusive) till the end of the display are erase. If it
1659 * is 1, all cells from the start of the display till the cursor
1660 * (inclusive) are erased. If it is 2, all cells are erased.
1666 unsigned int mode = 0;
1668 if (seq->args[0] > 0)
1669 mode = seq->args[0];
1673 term_page_erase(screen->page,
1674 screen->cursor_x, screen->cursor_y,
1675 screen->page->width, screen->page->height,
1676 &screen->attr, screen->age, true);
1679 term_page_erase(screen->page,
1681 screen->cursor_x, screen->cursor_y,
1682 &screen->attr, screen->age, true);
1685 term_page_erase(screen->page,
1687 screen->page->width, screen->page->height,
1688 &screen->attr, screen->age, true);
1695 static int screen_DECSEL(term_screen *screen, const term_seq *seq) {
1697 * DECSEL - selective-erase-in-line
1698 * This control function erases some or all of the erasable characters
1699 * in a single line of text. DECSEL erases only those characters defined
1700 * as erasable by the DECSCA control function. DECSEL works inside or
1701 * outside the scrolling margins.
1703 * @args[0] defines the region to be erased. If it is 0, all cells from
1704 * the cursor (inclusive) till the end of the line are erase. If it is
1705 * 1, all cells from the start of the line till the cursor (inclusive)
1706 * are erased. If it is 2, the whole line of the cursor is erased.
1712 unsigned int mode = 0;
1714 if (seq->args[0] > 0)
1715 mode = seq->args[0];
1719 term_page_erase(screen->page,
1720 screen->cursor_x, screen->cursor_y,
1721 screen->page->width, screen->cursor_y,
1722 &screen->attr, screen->age, true);
1725 term_page_erase(screen->page,
1726 0, screen->cursor_y,
1727 screen->cursor_x, screen->cursor_y,
1728 &screen->attr, screen->age, true);
1731 term_page_erase(screen->page,
1732 0, screen->cursor_y,
1733 screen->page->width, screen->cursor_y,
1734 &screen->attr, screen->age, true);
1741 static int screen_DECSERA(term_screen *screen, const term_seq *seq) {
1743 * DECSERA - selective-erase-rectangular-area
1745 * Probably not worth implementing.
1751 static int screen_DECSFC(term_screen *screen, const term_seq *seq) {
1753 * DECSFC - select-flow-control
1755 * Probably not worth implementing.
1761 static int screen_DECSKCV(term_screen *screen, const term_seq *seq) {
1763 * DECSKCV - set-key-click-volume
1765 * Probably not worth implementing.
1771 static int screen_DECSLCK(term_screen *screen, const term_seq *seq) {
1773 * DECSLCK - set-lock-key-style
1775 * Probably not worth implementing.
1781 static int screen_DECSLE(term_screen *screen, const term_seq *seq) {
1783 * DECSLE - select-locator-events
1791 static int screen_DECSLPP(term_screen *screen, const term_seq *seq) {
1793 * DECSLPP - set-lines-per-page
1794 * Set the number of lines used for the page. @args[0] specifies the
1795 * number of lines to be used. DEC only allows a limited number of
1796 * choices, however, we allow all integers. 0 is equivalent to 24.
1807 static int screen_DECSLRM_OR_SC(term_screen *screen, const term_seq *seq) {
1809 * DECSLRM_OR_SC - set-left-and-right-margins or save-cursor
1811 * TODO: Detect save-cursor and run it. DECSLRM is not worth
1818 static int screen_DECSMBV(term_screen *screen, const term_seq *seq) {
1820 * DECSMBV - set-margin-bell-volume
1822 * Probably not worth implementing.
1828 static int screen_DECSMKR(term_screen *screen, const term_seq *seq) {
1830 * DECSMKR - select-modifier-key-reporting
1832 * Probably not worth implementing.
1838 static int screen_DECSNLS(term_screen *screen, const term_seq *seq) {
1840 * DECSNLS - set-lines-per-screen
1842 * Probably not worth implementing.
1848 static int screen_DECSPP(term_screen *screen, const term_seq *seq) {
1850 * DECSPP - set-port-parameter
1852 * Probably not worth implementing.
1858 static int screen_DECSPPCS(term_screen *screen, const term_seq *seq) {
1860 * DECSPPCS - select-pro-printer-character-set
1862 * Probably not worth implementing.
1868 static int screen_DECSPRTT(term_screen *screen, const term_seq *seq) {
1870 * DECSPRTT - select-printer-type
1872 * Probably not worth implementing.
1878 static int screen_DECSR(term_screen *screen, const term_seq *seq) {
1880 * DECSR - secure-reset
1882 * Probably not worth implementing.
1888 static int screen_DECSRFR(term_screen *screen, const term_seq *seq) {
1890 * DECSRFR - select-refresh-rate
1892 * Probably not worth implementing.
1898 static int screen_DECSSCLS(term_screen *screen, const term_seq *seq) {
1900 * DECSSCLS - set-scroll-speed
1902 * Probably not worth implementing.
1908 static int screen_DECSSDT(term_screen *screen, const term_seq *seq) {
1910 * DECSSDT - select-status-display-line-type
1912 * Probably not worth implementing.
1918 static int screen_DECSSL(term_screen *screen, const term_seq *seq) {
1920 * DECSSL - select-setup-language
1922 * Probably not worth implementing.
1928 static int screen_DECST8C(term_screen *screen, const term_seq *seq) {
1930 * DECST8C - set-tab-at-every-8-columns
1931 * Clear the tab-ruler and reset it to a tab at every 8th column,
1932 * starting at 9 (though, setting a tab at 1 is fine as it has no
1938 for (i = 0; i < screen->page->width; i += 8)
1939 screen->tabs[i / 8] = 0x1;
1944 static int screen_DECSTBM(term_screen *screen, const term_seq *seq) {
1946 * DECSTBM - set-top-and-bottom-margins
1947 * This control function sets the top and bottom margins for the current
1948 * page. You cannot perform scrolling outside the margins.
1950 * @args[0] defines the top margin, @args[1] defines the bottom margin.
1951 * The bottom margin must be lower than the top-margin.
1953 * This call resets the cursor position to 0/0 of the page.
1957 * args[1]: last page-line
1960 unsigned int top, bottom;
1963 bottom = screen->page->height;
1965 if (seq->args[0] > 0)
1967 if (seq->args[1] > 0)
1968 bottom = seq->args[1];
1970 if (top > screen->page->height)
1971 top = screen->page->height;
1972 if (bottom > screen->page->height)
1973 bottom = screen->page->height;
1975 if (top >= bottom || top > screen->page->height || bottom > screen->page->height) {
1977 bottom = screen->page->height;
1980 term_page_set_scroll_region(screen->page_main, top - 1, bottom - top + 1);
1981 term_page_set_scroll_region(screen->page_alt, top - 1, bottom - top + 1);
1982 screen_cursor_clear_wrap(screen);
1983 screen_cursor_set(screen, 0, 0);
1988 static int screen_DECSTR(term_screen *screen, const term_seq *seq) {
1990 * DECSTR - soft-terminal-reset
1991 * Perform a soft reset to the default values.
1994 term_screen_soft_reset(screen);
1999 static int screen_DECSTRL(term_screen *screen, const term_seq *seq) {
2001 * DECSTRL - set-transmit-rate-limit
2003 * Probably not worth implementing.
2009 static int screen_DECSWBV(term_screen *screen, const term_seq *seq) {
2011 * DECSWBV - set-warning-bell-volume
2013 * Probably not worth implementing.
2019 static int screen_DECSWL(term_screen *screen, const term_seq *seq) {
2021 * DECSWL - single-width-single-height-line
2023 * Probably not worth implementing.
2029 static int screen_DECTID(term_screen *screen, const term_seq *seq) {
2031 * DECTID - select-terminal-id
2033 * Probably not worth implementing.
2039 static int screen_DECTME(term_screen *screen, const term_seq *seq) {
2041 * DECTME - terminal-mode-emulation
2043 * Probably not worth implementing.
2049 static int screen_DECTST(term_screen *screen, const term_seq *seq) {
2051 * DECTST - invoke-confidence-test
2053 * Probably not worth implementing.
2059 static int screen_DL(term_screen *screen, const term_seq *seq) {
2062 * This control function deletes one or more lines in the scrolling
2063 * region, starting with the line that has the cursor. @args[0] defines
2064 * the number of lines to delete. 0 is treated the same as 1.
2065 * As lines are deleted, lines below the cursor and in the scrolling
2066 * region move up. The terminal adds blank lines with no visual
2067 * character attributes at the bottom of the scrolling region. If it is
2068 * greater than the number of lines remaining on the page, DL deletes
2069 * only the remaining lines. DL has no effect outside the scrolling
2076 unsigned int num = 1;
2078 if (seq->args[0] > 0)
2081 term_page_delete_lines(screen->page, screen->cursor_y, num, &screen->attr, screen->age);
2086 static int screen_DSR_ANSI(term_screen *screen, const term_seq *seq) {
2088 * DSR_ANSI - device-status-report-ansi
2096 static int screen_DSR_DEC(term_screen *screen, const term_seq *seq) {
2098 * DSR_DEC - device-status-report-dec
2106 static int screen_ECH(term_screen *screen, const term_seq *seq) {
2108 * ECH - erase-character
2109 * This control function erases one or more characters, from the cursor
2110 * position to the right. ECH clears character attributes from erased
2111 * character positions. ECH works inside or outside the scrolling
2113 * @args[0] defines the number of characters to erase. 0 is treated the
2120 unsigned int num = 1;
2122 if (seq->args[0] > 0)
2125 term_page_erase(screen->page,
2126 screen->cursor_x, screen->cursor_y,
2127 screen->cursor_x + num, screen->cursor_y,
2128 &screen->attr, screen->age, false);
2133 static int screen_ED(term_screen *screen, const term_seq *seq) {
2135 * ED - erase-in-display
2136 * This control function erases characters from part or all of the
2137 * display. When you erase complete lines, they become single-height,
2138 * single-width lines, with all visual character attributes cleared. ED
2139 * works inside or outside the scrolling margins.
2141 * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2142 * till the end of the screen. 1 means from the start of the screen till
2143 * the cursor (inclusive) and 2 means the whole screen.
2149 unsigned int mode = 0;
2151 if (seq->args[0] > 0)
2152 mode = seq->args[0];
2156 term_page_erase(screen->page,
2157 screen->cursor_x, screen->cursor_y,
2158 screen->page->width, screen->page->height,
2159 &screen->attr, screen->age, false);
2162 term_page_erase(screen->page,
2164 screen->cursor_x, screen->cursor_y,
2165 &screen->attr, screen->age, false);
2168 term_page_erase(screen->page,
2170 screen->page->width, screen->page->height,
2171 &screen->attr, screen->age, false);
2178 static int screen_EL(term_screen *screen, const term_seq *seq) {
2180 * EL - erase-in-line
2181 * This control function erases characters on the line that has the
2182 * cursor. EL clears all character attributes from erased character
2183 * positions. EL works inside or outside the scrolling margins.
2185 * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2186 * till the end of the line. 1 means from the start of the line till the
2187 * cursor (inclusive) and 2 means the whole line.
2193 unsigned int mode = 0;
2195 if (seq->args[0] > 0)
2196 mode = seq->args[0];
2200 term_page_erase(screen->page,
2201 screen->cursor_x, screen->cursor_y,
2202 screen->page->width, screen->cursor_y,
2203 &screen->attr, screen->age, false);
2206 term_page_erase(screen->page,
2207 0, screen->cursor_y,
2208 screen->cursor_x, screen->cursor_y,
2209 &screen->attr, screen->age, false);
2212 term_page_erase(screen->page,
2213 0, screen->cursor_y,
2214 screen->page->width, screen->cursor_y,
2215 &screen->attr, screen->age, false);
2222 static int screen_ENQ(term_screen *screen, const term_seq *seq) {
2225 * Transmit the answerback-string. If none is set, do nothing.
2228 if (screen->answerback)
2229 return screen_write(screen, screen->answerback, strlen(screen->answerback));
2234 static int screen_EPA(term_screen *screen, const term_seq *seq) {
2236 * EPA - end-of-guarded-area
2238 * TODO: What is this?
2244 static int screen_FF(term_screen *screen, const term_seq *seq) {
2247 * This causes the cursor to jump to the next line. It is treated the
2251 return screen_LF(screen, seq);
2254 static int screen_HPA(term_screen *screen, const term_seq *seq) {
2256 * HPA - horizontal-position-absolute
2257 * HPA causes the active position to be moved to the n-th horizontal
2258 * position of the active line. If an attempt is made to move the active
2259 * position past the last position on the line, then the active position
2260 * stops at the last position on the line.
2262 * @args[0] defines the horizontal position. 0 is treated as 1.
2268 unsigned int num = 1;
2270 if (seq->args[0] > 0)
2273 screen_cursor_clear_wrap(screen);
2274 screen_cursor_set(screen, num - 1, screen->cursor_y);
2279 static int screen_HPR(term_screen *screen, const term_seq *seq) {
2281 * HPR - horizontal-position-relative
2282 * HPR causes the active position to be moved to the n-th following
2283 * horizontal position of the active line. If an attempt is made to move
2284 * the active position past the last position on the line, then the
2285 * active position stops at the last position on the line.
2287 * @args[0] defines the horizontal position. 0 is treated as 1.
2293 unsigned int num = 1;
2295 if (seq->args[0] > 0)
2298 screen_cursor_clear_wrap(screen);
2299 screen_cursor_right(screen, num);
2304 static int screen_HT(term_screen *screen, const term_seq *seq) {
2306 * HT - horizontal-tab
2307 * Moves the cursor to the next tab stop. If there are no more tab
2308 * stops, the cursor moves to the right margin. HT does not cause text
2312 screen_cursor_clear_wrap(screen);
2313 screen_cursor_right_tab(screen, 1);
2318 static int screen_HTS(term_screen *screen, const term_seq *seq) {
2320 * HTS - horizontal-tab-set
2321 * HTS sets a horizontal tab stop at the column position indicated by
2322 * the value of the active column when the terminal receives an HTS.
2324 * Executing an HTS does not effect the other horizontal tab stop
2330 pos = screen->cursor_x;
2331 if (screen->page->width > 0)
2332 screen->tabs[pos / 8] |= 1U << (pos % 8);
2337 static int screen_HVP(term_screen *screen, const term_seq *seq) {
2339 * HVP - horizontal-and-vertical-position
2340 * This control function works the same as the cursor position (CUP)
2341 * function. Origin mode (DECOM) selects line numbering and the ability
2342 * to move the cursor into margins.
2349 return screen_CUP(screen, seq);
2352 static int screen_ICH(term_screen *screen, const term_seq *seq) {
2354 * ICH - insert-character
2355 * This control function inserts one or more space (SP) characters
2356 * starting at the cursor position. @args[0] is the number of characters
2357 * to insert. 0 is treated as 1.
2359 * The ICH sequence inserts blank characters with the normal
2360 * character attribute. The cursor remains at the beginning of the blank
2361 * characters. Text between the cursor and right margin moves to the
2362 * right. Characters scrolled past the right margin are lost. ICH has no
2363 * effect outside the scrolling margins.
2369 unsigned int num = 1;
2371 if (seq->args[0] > 0)
2374 screen_cursor_clear_wrap(screen);
2375 term_page_insert_cells(screen->page, screen->cursor_x, screen->cursor_y, num, &screen->attr, screen->age);
2380 static int screen_IL(term_screen *screen, const term_seq *seq) {
2383 * This control function inserts one or more blank lines, starting at
2384 * the cursor. @args[0] is the number of lines to insert. 0 is treated
2387 * As lines are inserted, lines below the cursor and in the scrolling
2388 * region move down. Lines scrolled off the page are lost. IL has no
2389 * effect outside the page margins.
2395 unsigned int num = 1;
2397 if (seq->args[0] > 0)
2400 screen_cursor_clear_wrap(screen);
2401 term_page_insert_lines(screen->page, screen->cursor_y, num, &screen->attr, screen->age);
2406 static int screen_IND(term_screen *screen, const term_seq *seq) {
2409 * IND moves the cursor down one line in the same column. If the cursor
2410 * is at the bottom margin, then the screen performs a scroll-up.
2413 screen_cursor_down(screen, 1, true);
2418 static int screen_LF(term_screen *screen, const term_seq *seq) {
2421 * Causes a line feed or a new line operation, depending on the setting
2422 * of line feed/new line mode.
2425 screen_cursor_down(screen, 1, true);
2426 if (screen->flags & TERM_FLAG_NEWLINE_MODE)
2427 screen_cursor_left(screen, screen->cursor_x);
2432 static int screen_LS1R(term_screen *screen, const term_seq *seq) {
2434 * LS1R - locking-shift-1-right
2438 screen->gr = &screen->g1;
2443 static int screen_LS2(term_screen *screen, const term_seq *seq) {
2445 * LS2 - locking-shift-2
2449 screen->gl = &screen->g2;
2454 static int screen_LS2R(term_screen *screen, const term_seq *seq) {
2456 * LS2R - locking-shift-2-right
2460 screen->gr = &screen->g2;
2465 static int screen_LS3(term_screen *screen, const term_seq *seq) {
2467 * LS3 - locking-shift-3
2471 screen->gl = &screen->g3;
2476 static int screen_LS3R(term_screen *screen, const term_seq *seq) {
2478 * LS3R - locking-shift-3-right
2482 screen->gr = &screen->g3;
2487 static int screen_MC_ANSI(term_screen *screen, const term_seq *seq) {
2489 * MC_ANSI - media-copy-ansi
2491 * Probably not worth implementing.
2497 static int screen_MC_DEC(term_screen *screen, const term_seq *seq) {
2499 * MC_DEC - media-copy-dec
2501 * Probably not worth implementing.
2507 static int screen_NEL(term_screen *screen, const term_seq *seq) {
2510 * Moves cursor to first position on next line. If cursor is at bottom
2511 * margin, then screen performs a scroll-up.
2514 screen_cursor_clear_wrap(screen);
2515 screen_cursor_down(screen, 1, true);
2516 screen_cursor_set(screen, 0, screen->cursor_y);
2521 static int screen_NP(term_screen *screen, const term_seq *seq) {
2524 * This control function moves the cursor forward to the home position
2525 * on one of the following pages in page memory. If there is only one
2526 * page, then the terminal ignores NP.
2527 * If NP tries to move the cursor past the last page in memory, then the
2528 * cursor stops at the last page.
2530 * @args[0] defines the number of pages to forward. 0 is treated as 1.
2535 * Probably not worth implementing. We only support a single page.
2541 static int screen_NULL(term_screen *screen, const term_seq *seq) {
2544 * The NULL operation does nothing. ASCII NULL is always ignored.
2550 static int screen_PP(term_screen *screen, const term_seq *seq) {
2552 * PP - preceding-page
2553 * This control function moves the cursor backward to the home position
2554 * on one of the preceding pages in page memory. If there is only one
2555 * page, then the terminal ignores PP.
2556 * If PP tries to move the cursor back farther than the first page in
2557 * memory, then the cursor stops at the first page.
2559 * @args[0] defines the number of pages to go backwards. 0 is treated
2565 * Probably not worth implementing. We only support a single page.
2571 static int screen_PPA(term_screen *screen, const term_seq *seq) {
2573 * PPA - page-position-absolute
2574 * This control function can move the cursor to the corresponding row
2575 * and column on any page in page memory. You select the page by its
2576 * number. If there is only one page, then the terminal ignores PPA.
2578 * @args[0] is the number of the page to move the cursor to. If it is
2579 * greater than the number of the last page in memory, then the cursor
2580 * stops at the last page. If it is less than the number of the first
2581 * page, then the cursor stops at the first page.
2586 * Probably not worth implementing. We only support a single page.
2592 static int screen_PPB(term_screen *screen, const term_seq *seq) {
2594 * PPB - page-position-backward
2595 * This control function moves the cursor backward to the corresponding
2596 * row and column on one of the preceding pages in page memory. If there
2597 * is only one page, then the terminal ignores PPB.
2599 * @args[0] indicates the number of pages to move the cursor backward.
2600 * If it tries to move the cursor back farther than the first page in
2601 * memory, then the cursor stops at the first page. 0 is treated as 1.
2606 * Probably not worth implementing. We only support a single page.
2612 static int screen_PPR(term_screen *screen, const term_seq *seq) {
2614 * PPR - page-position-relative
2615 * This control function moves the cursor forward to the corresponding
2616 * row and column on one of the following pages in page memory. If there
2617 * is only one page, then the terminal ignores PPR.
2619 * @args[0] indicates how many pages to move the cursor forward. If it
2620 * tries to move the cursor beyond the last page in memory, then the
2621 * cursor stops at the last page. 0 is treated as 1.
2626 * Probably not worth implementing. We only support a single page.
2632 static int screen_RC(term_screen *screen, const term_seq *seq) {
2634 * RC - restore-cursor
2637 return screen_DECRC(screen, seq);
2640 static int screen_REP(term_screen *screen, const term_seq *seq) {
2643 * Repeat the preceding graphics-character the given number of times.
2644 * @args[0] specifies how often it shall be repeated. 0 is treated as 1.
2649 * Probably not worth implementing.
2655 static int screen_RI(term_screen *screen, const term_seq *seq) {
2657 * RI - reverse-index
2658 * Moves the cursor up one line in the same column. If the cursor is at
2659 * the top margin, the page scrolls down.
2662 screen_cursor_up(screen, 1, true);
2667 static int screen_RIS(term_screen *screen, const term_seq *seq) {
2669 * RIS - reset-to-initial-state
2670 * This control function causes a nonvolatile memory (NVR) recall to
2671 * occur. RIS replaces all set-up features with their saved settings.
2673 * The terminal stores these saved settings in NVR memory. The saved
2674 * setting for a feature is the same as the factory-default setting,
2675 * unless you saved a new setting.
2678 term_screen_hard_reset(screen);
2683 static int screen_RM_ANSI(term_screen *screen, const term_seq *seq) {
2685 * RM_ANSI - reset-mode-ansi
2687 * TODO: implement (see VT510rm manual)
2692 for (i = 0; i < seq->n_args; ++i)
2693 screen_mode_change(screen, seq->args[i], false, false);
2698 static int screen_RM_DEC(term_screen *screen, const term_seq *seq) {
2700 * RM_DEC - reset-mode-dec
2701 * This is the same as RM_ANSI but for DEC modes.
2706 for (i = 0; i < seq->n_args; ++i)
2707 screen_mode_change(screen, seq->args[i], true, false);
2712 static int screen_S7C1T(term_screen *screen, const term_seq *seq) {
2714 * S7C1T - set-7bit-c1-terminal
2715 * This causes the terminal to start sending C1 controls as 7bit
2716 * sequences instead of 8bit C1 controls.
2717 * This is ignored if the terminal is below level-2 emulation mode
2718 * (VT100 and below), the terminal already sends 7bit controls then.
2721 if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2722 screen->flags |= TERM_FLAG_7BIT_MODE;
2727 static int screen_S8C1T(term_screen *screen, const term_seq *seq) {
2729 * S8C1T - set-8bit-c1-terminal
2730 * This causes the terminal to start sending C1 controls as 8bit C1
2731 * control instead of 7bit sequences.
2732 * This is ignored if the terminal is below level-2 emulation mode
2733 * (VT100 and below). The terminal always sends 7bit controls in those
2737 if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2738 screen->flags &= ~TERM_FLAG_7BIT_MODE;
2743 static int screen_SCS(term_screen *screen, const term_seq *seq) {
2745 * SCS - select-character-set
2746 * Designate character sets to G-sets. The mapping from intermediates
2747 * and terminal characters in the escape sequence to G-sets and
2748 * character-sets is non-trivial and implemented separately. See there
2749 * for more information.
2750 * This call simply sets the selected G-set to the desired
2754 term_charset *cs = NULL;
2756 /* TODO: support more of them? */
2757 switch (seq->charset) {
2758 case TERM_CHARSET_ISO_LATIN1_SUPPLEMENTAL:
2759 case TERM_CHARSET_ISO_LATIN2_SUPPLEMENTAL:
2760 case TERM_CHARSET_ISO_LATIN5_SUPPLEMENTAL:
2761 case TERM_CHARSET_ISO_GREEK_SUPPLEMENTAL:
2762 case TERM_CHARSET_ISO_HEBREW_SUPPLEMENTAL:
2763 case TERM_CHARSET_ISO_LATIN_CYRILLIC:
2766 case TERM_CHARSET_DEC_SPECIAL_GRAPHIC:
2767 cs = &term_dec_special_graphics;
2769 case TERM_CHARSET_DEC_SUPPLEMENTAL:
2770 cs = &term_dec_supplemental_graphics;
2772 case TERM_CHARSET_DEC_TECHNICAL:
2773 case TERM_CHARSET_CYRILLIC_DEC:
2774 case TERM_CHARSET_DUTCH_NRCS:
2775 case TERM_CHARSET_FINNISH_NRCS:
2776 case TERM_CHARSET_FRENCH_NRCS:
2777 case TERM_CHARSET_FRENCH_CANADIAN_NRCS:
2778 case TERM_CHARSET_GERMAN_NRCS:
2779 case TERM_CHARSET_GREEK_DEC:
2780 case TERM_CHARSET_GREEK_NRCS:
2781 case TERM_CHARSET_HEBREW_DEC:
2782 case TERM_CHARSET_HEBREW_NRCS:
2783 case TERM_CHARSET_ITALIAN_NRCS:
2784 case TERM_CHARSET_NORWEGIAN_DANISH_NRCS:
2785 case TERM_CHARSET_PORTUGUESE_NRCS:
2786 case TERM_CHARSET_RUSSIAN_NRCS:
2787 case TERM_CHARSET_SCS_NRCS:
2788 case TERM_CHARSET_SPANISH_NRCS:
2789 case TERM_CHARSET_SWEDISH_NRCS:
2790 case TERM_CHARSET_SWISS_NRCS:
2791 case TERM_CHARSET_TURKISH_DEC:
2792 case TERM_CHARSET_TURKISH_NRCS:
2795 case TERM_CHARSET_USERPREF_SUPPLEMENTAL:
2799 if (seq->intermediates & TERM_SEQ_FLAG_POPEN)
2800 screen->g0 = cs ? : &term_unicode_lower;
2801 else if (seq->intermediates & TERM_SEQ_FLAG_PCLOSE)
2802 screen->g1 = cs ? : &term_unicode_upper;
2803 else if (seq->intermediates & TERM_SEQ_FLAG_MULT)
2804 screen->g2 = cs ? : &term_unicode_lower;
2805 else if (seq->intermediates & TERM_SEQ_FLAG_PLUS)
2806 screen->g3 = cs ? : &term_unicode_upper;
2807 else if (seq->intermediates & TERM_SEQ_FLAG_MINUS)
2808 screen->g1 = cs ? : &term_unicode_upper;
2809 else if (seq->intermediates & TERM_SEQ_FLAG_DOT)
2810 screen->g2 = cs ? : &term_unicode_lower;
2811 else if (seq->intermediates & TERM_SEQ_FLAG_SLASH)
2812 screen->g3 = cs ? : &term_unicode_upper;
2817 static int screen_SD(term_screen *screen, const term_seq *seq) {
2820 * This control function moves the user window down a specified number
2821 * of lines in page memory.
2822 * @args[0] is the number of lines to move the
2823 * user window up in page memory. New lines appear at the top of the
2824 * display. Old lines disappear at the bottom of the display. You
2825 * cannot pan past the top margin of the current page. 0 is treated
2832 unsigned int num = 1;
2834 if (seq->args[0] > 0)
2837 term_page_scroll_down(screen->page, num, &screen->attr, screen->age, NULL);
2842 static int screen_SGR(term_screen *screen, const term_seq *seq) {
2844 * SGR - select-graphics-rendition
2848 unsigned int i, code;
2851 if (seq->n_args < 1) {
2856 for (i = 0; i < seq->n_args; ++i) {
2860 screen->attr.bold = 1;
2863 screen->attr.italic = 1;
2866 screen->attr.underline = 1;
2869 screen->attr.blink = 1;
2872 screen->attr.inverse = 1;
2875 screen->attr.hidden = 1;
2878 screen->attr.bold = 0;
2881 screen->attr.italic = 0;
2884 screen->attr.underline = 0;
2887 screen->attr.blink = 0;
2890 screen->attr.inverse = 0;
2893 screen->attr.hidden = 0;
2896 screen->attr.fg.ccode = v - 30 + TERM_CCODE_BLACK;
2899 screen->attr.fg.ccode = 0;
2902 screen->attr.bg.ccode = v - 40 + TERM_CCODE_BLACK;
2905 screen->attr.bg.ccode = 0;
2908 screen->attr.fg.ccode = v - 90 + TERM_CCODE_LIGHT_BLACK;
2911 screen->attr.bg.ccode = v - 100 + TERM_CCODE_LIGHT_BLACK;
2918 dst = &screen->attr.fg;
2920 dst = &screen->attr.bg;
2923 if (i >= seq->n_args)
2926 switch (seq->args[i]) {
2928 /* 24bit-color support */
2931 if (i >= seq->n_args)
2934 dst->ccode = TERM_CCODE_RGB;
2935 dst->red = (seq->args[i - 2] >= 0) ? seq->args[i - 2] : 0;
2936 dst->green = (seq->args[i - 1] >= 0) ? seq->args[i - 1] : 0;
2937 dst->blue = (seq->args[i] >= 0) ? seq->args[i] : 0;
2941 /* 256-color support */
2944 if (i >= seq->n_args || seq->args[i] < 0)
2947 dst->ccode = TERM_CCODE_256;
2948 code = seq->args[i];
2949 dst->c256 = code < 256 ? code : 0;
2966 static int screen_SI(term_screen *screen, const term_seq *seq) {
2972 screen->gl = &screen->g0;
2977 static int screen_SM_ANSI(term_screen *screen, const term_seq *seq) {
2979 * SM_ANSI - set-mode-ansi
2986 for (i = 0; i < seq->n_args; ++i)
2987 screen_mode_change(screen, seq->args[i], false, true);
2992 static int screen_SM_DEC(term_screen *screen, const term_seq *seq) {
2994 * SM_DEC - set-mode-dec
2995 * This is the same as SM_ANSI but for DEC modes.
3000 for (i = 0; i < seq->n_args; ++i)
3001 screen_mode_change(screen, seq->args[i], true, true);
3006 static int screen_SO(term_screen *screen, const term_seq *seq) {
3012 screen->gl = &screen->g1;
3017 static int screen_SPA(term_screen *screen, const term_seq *seq) {
3019 * SPA - start-of-protected-area
3021 * TODO: What is this?
3027 static int screen_SS2(term_screen *screen, const term_seq *seq) {
3029 * SS2 - single-shift-2
3030 * Temporarily map G2 into GL for the next graphics character.
3033 screen->glt = &screen->g2;
3038 static int screen_SS3(term_screen *screen, const term_seq *seq) {
3040 * SS3 - single-shift-3
3041 * Temporarily map G3 into GL for the next graphics character
3044 screen->glt = &screen->g3;
3049 static int screen_ST(term_screen *screen, const term_seq *seq) {
3051 * ST - string-terminator
3052 * The string-terminator is usually part of control-sequences and
3053 * handled by the parser. In all other situations it is silently
3060 static int screen_SU(term_screen *screen, const term_seq *seq) {
3063 * This control function moves the user window up a specified number of
3064 * lines in page memory.
3065 * @args[0] is the number of lines to move the
3066 * user window down in page memory. New lines appear at the bottom of
3067 * the display. Old lines disappear at the top of the display. You
3068 * cannot pan past the bottom margin of the current page. 0 is treated
3075 unsigned int num = 1;
3077 if (seq->args[0] > 0)
3080 term_page_scroll_up(screen->page, num, &screen->attr, screen->age, screen->history);
3085 static int screen_SUB(term_screen *screen, const term_seq *seq) {
3088 * Cancel the current control-sequence and print a replacement
3089 * character. Our parser already handles this so all we have to do is
3090 * print the replacement character.
3093 static const term_seq rep = {
3094 .type = TERM_SEQ_GRAPHIC,
3095 .command = TERM_CMD_GRAPHIC,
3096 .terminator = 0xfffd,
3099 return screen_GRAPHIC(screen, &rep);
3102 static int screen_TBC(term_screen *screen, const term_seq *seq) {
3105 * This clears tab-stops. If @args[0] is 0, the tab-stop at the current
3106 * cursor position is cleared. If it is 3, all tab stops are cleared.
3112 unsigned int mode = 0, pos;
3114 if (seq->args[0] > 0)
3115 mode = seq->args[0];
3119 pos = screen->cursor_x;
3120 if (screen->page->width > 0)
3121 screen->tabs[pos / 8] &= ~(1U << (pos % 8));
3124 if (screen->page->width > 0)
3125 memset(screen->tabs, 0, (screen->page->width + 7) / 8);
3132 static int screen_VPA(term_screen *screen, const term_seq *seq) {
3134 * VPA - vertical-line-position-absolute
3135 * VPA causes the active position to be moved to the corresponding
3136 * horizontal position. @args[0] specifies the line to jump to. If an
3137 * attempt is made to move the active position below the last line, then
3138 * the active position stops on the last line. 0 is treated as 1.
3144 unsigned int pos = 1;
3146 if (seq->args[0] > 0)
3149 screen_cursor_clear_wrap(screen);
3150 screen_cursor_set_rel(screen, screen->cursor_x, pos - 1);
3155 static int screen_VPR(term_screen *screen, const term_seq *seq) {
3157 * VPR - vertical-line-position-relative
3158 * VPR causes the active position to be moved to the corresponding
3159 * horizontal position. @args[0] specifies the number of lines to jump
3160 * down relative to the current cursor position. If an attempt is made
3161 * to move the active position below the last line, the active position
3162 * stops at the last line. 0 is treated as 1.
3168 unsigned int num = 1;
3170 if (seq->args[0] > 0)
3173 screen_cursor_clear_wrap(screen);
3174 screen_cursor_down(screen, num, false);
3179 static int screen_VT(term_screen *screen, const term_seq *seq) {
3182 * This causes a vertical jump by one line. Terminals treat it exactly
3186 return screen_LF(screen, seq);
3189 static int screen_XTERM_CLLHP(term_screen *screen, const term_seq *seq) {
3191 * XTERM_CLLHP - xterm-cursor-lower-left-hp-bugfix
3192 * Move the cursor to the lower-left corner of the page. This is an HP
3195 * Probably not worth implementing.
3201 static int screen_XTERM_IHMT(term_screen *screen, const term_seq *seq) {
3203 * XTERM_IHMT - xterm-initiate-highlight-mouse-tracking
3205 * Probably not worth implementing.
3211 static int screen_XTERM_MLHP(term_screen *screen, const term_seq *seq) {
3213 * XTERM_MLHP - xterm-memory-lock-hp-bugfix
3215 * Probably not worth implementing.
3221 static int screen_XTERM_MUHP(term_screen *screen, const term_seq *seq) {
3223 * XTERM_MUHP - xterm-memory-unlock-hp-bugfix
3225 * Probably not worth implementing.
3231 static int screen_XTERM_RPM(term_screen *screen, const term_seq *seq) {
3233 * XTERM_RPM - xterm-restore-private-mode
3235 * Probably not worth implementing.
3241 static int screen_XTERM_RRV(term_screen *screen, const term_seq *seq) {
3243 * XTERM_RRV - xterm-reset-resource-value
3245 * Probably not worth implementing.
3251 static int screen_XTERM_RTM(term_screen *screen, const term_seq *seq) {
3253 * XTERM_RTM - xterm-reset-title-mode
3255 * Probably not worth implementing.
3261 static int screen_XTERM_SACL1(term_screen *screen, const term_seq *seq) {
3263 * XTERM_SACL1 - xterm-set-ansi-conformance-level-1
3265 * Probably not worth implementing.
3271 static int screen_XTERM_SACL2(term_screen *screen, const term_seq *seq) {
3273 * XTERM_SACL2 - xterm-set-ansi-conformance-level-2
3275 * Probably not worth implementing.
3281 static int screen_XTERM_SACL3(term_screen *screen, const term_seq *seq) {
3283 * XTERM_SACL3 - xterm-set-ansi-conformance-level-3
3285 * Probably not worth implementing.
3291 static int screen_XTERM_SDCS(term_screen *screen, const term_seq *seq) {
3293 * XTERM_SDCS - xterm-set-default-character-set
3294 * Select the default character set. We treat this the same as UTF-8 as
3295 * this is our default character set. As we always use UTF-8, this
3302 static int screen_XTERM_SGFX(term_screen *screen, const term_seq *seq) {
3304 * XTERM_SGFX - xterm-sixel-graphics
3306 * Probably not worth implementing.
3312 static int screen_XTERM_SPM(term_screen *screen, const term_seq *seq) {
3314 * XTERM_SPM - xterm-set-private-mode
3316 * Probably not worth implementing.
3322 static int screen_XTERM_SRV(term_screen *screen, const term_seq *seq) {
3324 * XTERM_SRV - xterm-set-resource-value
3326 * Probably not worth implementing.
3332 static int screen_XTERM_STM(term_screen *screen, const term_seq *seq) {
3334 * XTERM_STM - xterm-set-title-mode
3336 * Probably not worth implementing.
3342 static int screen_XTERM_SUCS(term_screen *screen, const term_seq *seq) {
3344 * XTERM_SUCS - xterm-select-utf8-character-set
3345 * Select UTF-8 as character set. This is our default on only character
3346 * set. Hence, this is a no-op.
3352 static int screen_XTERM_WM(term_screen *screen, const term_seq *seq) {
3354 * XTERM_WM - xterm-window-management
3356 * Probably not worth implementing.
3364 * The screen_feed_*() handlers take data from the user and feed it into the
3365 * screen. Once the parser has detected a sequence, we parse the command-type
3366 * and forward it to the command-dispatchers.
3369 static int screen_feed_cmd(term_screen *screen, const term_seq *seq) {
3370 switch (seq->command) {
3371 case TERM_CMD_GRAPHIC:
3372 return screen_GRAPHIC(screen, seq);
3374 return screen_BEL(screen, seq);
3376 return screen_BS(screen, seq);
3378 return screen_CBT(screen, seq);
3380 return screen_CHA(screen, seq);
3382 return screen_CHT(screen, seq);
3384 return screen_CNL(screen, seq);
3386 return screen_CPL(screen, seq);
3388 return screen_CR(screen, seq);
3390 return screen_CUB(screen, seq);
3392 return screen_CUD(screen, seq);
3394 return screen_CUF(screen, seq);
3396 return screen_CUP(screen, seq);
3398 return screen_CUU(screen, seq);
3400 return screen_DA1(screen, seq);
3402 return screen_DA2(screen, seq);
3404 return screen_DA3(screen, seq);
3406 return screen_DC1(screen, seq);
3408 return screen_DC3(screen, seq);
3410 return screen_DCH(screen, seq);
3411 case TERM_CMD_DECALN:
3412 return screen_DECALN(screen, seq);
3413 case TERM_CMD_DECANM:
3414 return screen_DECANM(screen, seq);
3415 case TERM_CMD_DECBI:
3416 return screen_DECBI(screen, seq);
3417 case TERM_CMD_DECCARA:
3418 return screen_DECCARA(screen, seq);
3419 case TERM_CMD_DECCRA:
3420 return screen_DECCRA(screen, seq);
3421 case TERM_CMD_DECDC:
3422 return screen_DECDC(screen, seq);
3423 case TERM_CMD_DECDHL_BH:
3424 return screen_DECDHL_BH(screen, seq);
3425 case TERM_CMD_DECDHL_TH:
3426 return screen_DECDHL_TH(screen, seq);
3427 case TERM_CMD_DECDWL:
3428 return screen_DECDWL(screen, seq);
3429 case TERM_CMD_DECEFR:
3430 return screen_DECEFR(screen, seq);
3431 case TERM_CMD_DECELF:
3432 return screen_DECELF(screen, seq);
3433 case TERM_CMD_DECELR:
3434 return screen_DECELR(screen, seq);
3435 case TERM_CMD_DECERA:
3436 return screen_DECERA(screen, seq);
3437 case TERM_CMD_DECFI:
3438 return screen_DECFI(screen, seq);
3439 case TERM_CMD_DECFRA:
3440 return screen_DECFRA(screen, seq);
3441 case TERM_CMD_DECIC:
3442 return screen_DECIC(screen, seq);
3443 case TERM_CMD_DECID:
3444 return screen_DECID(screen, seq);
3445 case TERM_CMD_DECINVM:
3446 return screen_DECINVM(screen, seq);
3447 case TERM_CMD_DECKBD:
3448 return screen_DECKBD(screen, seq);
3449 case TERM_CMD_DECKPAM:
3450 return screen_DECKPAM(screen, seq);
3451 case TERM_CMD_DECKPNM:
3452 return screen_DECKPNM(screen, seq);
3453 case TERM_CMD_DECLFKC:
3454 return screen_DECLFKC(screen, seq);
3455 case TERM_CMD_DECLL:
3456 return screen_DECLL(screen, seq);
3457 case TERM_CMD_DECLTOD:
3458 return screen_DECLTOD(screen, seq);
3459 case TERM_CMD_DECPCTERM:
3460 return screen_DECPCTERM(screen, seq);
3461 case TERM_CMD_DECPKA:
3462 return screen_DECPKA(screen, seq);
3463 case TERM_CMD_DECPKFMR:
3464 return screen_DECPKFMR(screen, seq);
3465 case TERM_CMD_DECRARA:
3466 return screen_DECRARA(screen, seq);
3467 case TERM_CMD_DECRC:
3468 return screen_DECRC(screen, seq);
3469 case TERM_CMD_DECREQTPARM:
3470 return screen_DECREQTPARM(screen, seq);
3471 case TERM_CMD_DECRPKT:
3472 return screen_DECRPKT(screen, seq);
3473 case TERM_CMD_DECRQCRA:
3474 return screen_DECRQCRA(screen, seq);
3475 case TERM_CMD_DECRQDE:
3476 return screen_DECRQDE(screen, seq);
3477 case TERM_CMD_DECRQKT:
3478 return screen_DECRQKT(screen, seq);
3479 case TERM_CMD_DECRQLP:
3480 return screen_DECRQLP(screen, seq);
3481 case TERM_CMD_DECRQM_ANSI:
3482 return screen_DECRQM_ANSI(screen, seq);
3483 case TERM_CMD_DECRQM_DEC:
3484 return screen_DECRQM_DEC(screen, seq);
3485 case TERM_CMD_DECRQPKFM:
3486 return screen_DECRQPKFM(screen, seq);
3487 case TERM_CMD_DECRQPSR:
3488 return screen_DECRQPSR(screen, seq);
3489 case TERM_CMD_DECRQTSR:
3490 return screen_DECRQTSR(screen, seq);
3491 case TERM_CMD_DECRQUPSS:
3492 return screen_DECRQUPSS(screen, seq);
3493 case TERM_CMD_DECSACE:
3494 return screen_DECSACE(screen, seq);
3495 case TERM_CMD_DECSASD:
3496 return screen_DECSASD(screen, seq);
3497 case TERM_CMD_DECSC:
3498 return screen_DECSC(screen, seq);
3499 case TERM_CMD_DECSCA:
3500 return screen_DECSCA(screen, seq);
3501 case TERM_CMD_DECSCL:
3502 return screen_DECSCL(screen, seq);
3503 case TERM_CMD_DECSCP:
3504 return screen_DECSCP(screen, seq);
3505 case TERM_CMD_DECSCPP:
3506 return screen_DECSCPP(screen, seq);
3507 case TERM_CMD_DECSCS:
3508 return screen_DECSCS(screen, seq);
3509 case TERM_CMD_DECSCUSR:
3510 return screen_DECSCUSR(screen, seq);
3511 case TERM_CMD_DECSDDT:
3512 return screen_DECSDDT(screen, seq);
3513 case TERM_CMD_DECSDPT:
3514 return screen_DECSDPT(screen, seq);
3515 case TERM_CMD_DECSED:
3516 return screen_DECSED(screen, seq);
3517 case TERM_CMD_DECSEL:
3518 return screen_DECSEL(screen, seq);
3519 case TERM_CMD_DECSERA:
3520 return screen_DECSERA(screen, seq);
3521 case TERM_CMD_DECSFC:
3522 return screen_DECSFC(screen, seq);
3523 case TERM_CMD_DECSKCV:
3524 return screen_DECSKCV(screen, seq);
3525 case TERM_CMD_DECSLCK:
3526 return screen_DECSLCK(screen, seq);
3527 case TERM_CMD_DECSLE:
3528 return screen_DECSLE(screen, seq);
3529 case TERM_CMD_DECSLPP:
3530 return screen_DECSLPP(screen, seq);
3531 case TERM_CMD_DECSLRM_OR_SC:
3532 return screen_DECSLRM_OR_SC(screen, seq);
3533 case TERM_CMD_DECSMBV:
3534 return screen_DECSMBV(screen, seq);
3535 case TERM_CMD_DECSMKR:
3536 return screen_DECSMKR(screen, seq);
3537 case TERM_CMD_DECSNLS:
3538 return screen_DECSNLS(screen, seq);
3539 case TERM_CMD_DECSPP:
3540 return screen_DECSPP(screen, seq);
3541 case TERM_CMD_DECSPPCS:
3542 return screen_DECSPPCS(screen, seq);
3543 case TERM_CMD_DECSPRTT:
3544 return screen_DECSPRTT(screen, seq);
3545 case TERM_CMD_DECSR:
3546 return screen_DECSR(screen, seq);
3547 case TERM_CMD_DECSRFR:
3548 return screen_DECSRFR(screen, seq);
3549 case TERM_CMD_DECSSCLS:
3550 return screen_DECSSCLS(screen, seq);
3551 case TERM_CMD_DECSSDT:
3552 return screen_DECSSDT(screen, seq);
3553 case TERM_CMD_DECSSL:
3554 return screen_DECSSL(screen, seq);
3555 case TERM_CMD_DECST8C:
3556 return screen_DECST8C(screen, seq);
3557 case TERM_CMD_DECSTBM:
3558 return screen_DECSTBM(screen, seq);
3559 case TERM_CMD_DECSTR:
3560 return screen_DECSTR(screen, seq);
3561 case TERM_CMD_DECSTRL:
3562 return screen_DECSTRL(screen, seq);
3563 case TERM_CMD_DECSWBV:
3564 return screen_DECSWBV(screen, seq);
3565 case TERM_CMD_DECSWL:
3566 return screen_DECSWL(screen, seq);
3567 case TERM_CMD_DECTID:
3568 return screen_DECTID(screen, seq);
3569 case TERM_CMD_DECTME:
3570 return screen_DECTME(screen, seq);
3571 case TERM_CMD_DECTST:
3572 return screen_DECTST(screen, seq);
3574 return screen_DL(screen, seq);
3575 case TERM_CMD_DSR_ANSI:
3576 return screen_DSR_ANSI(screen, seq);
3577 case TERM_CMD_DSR_DEC:
3578 return screen_DSR_DEC(screen, seq);
3580 return screen_ECH(screen, seq);
3582 return screen_ED(screen, seq);
3584 return screen_EL(screen, seq);
3586 return screen_ENQ(screen, seq);
3588 return screen_EPA(screen, seq);
3590 return screen_FF(screen, seq);
3592 return screen_HPA(screen, seq);
3594 return screen_HPR(screen, seq);
3596 return screen_HT(screen, seq);
3598 return screen_HTS(screen, seq);
3600 return screen_HVP(screen, seq);
3602 return screen_ICH(screen, seq);
3604 return screen_IL(screen, seq);
3606 return screen_IND(screen, seq);
3608 return screen_LF(screen, seq);
3610 return screen_LS1R(screen, seq);
3612 return screen_LS2(screen, seq);
3614 return screen_LS2R(screen, seq);
3616 return screen_LS3(screen, seq);
3618 return screen_LS3R(screen, seq);
3619 case TERM_CMD_MC_ANSI:
3620 return screen_MC_ANSI(screen, seq);
3621 case TERM_CMD_MC_DEC:
3622 return screen_MC_DEC(screen, seq);
3624 return screen_NEL(screen, seq);
3626 return screen_NP(screen, seq);
3628 return screen_NULL(screen, seq);
3630 return screen_PP(screen, seq);
3632 return screen_PPA(screen, seq);
3634 return screen_PPB(screen, seq);
3636 return screen_PPR(screen, seq);
3638 return screen_RC(screen, seq);
3640 return screen_REP(screen, seq);
3642 return screen_RI(screen, seq);
3644 return screen_RIS(screen, seq);
3645 case TERM_CMD_RM_ANSI:
3646 return screen_RM_ANSI(screen, seq);
3647 case TERM_CMD_RM_DEC:
3648 return screen_RM_DEC(screen, seq);
3649 case TERM_CMD_S7C1T:
3650 return screen_S7C1T(screen, seq);
3651 case TERM_CMD_S8C1T:
3652 return screen_S8C1T(screen, seq);
3654 return screen_SCS(screen, seq);
3656 return screen_SD(screen, seq);
3658 return screen_SGR(screen, seq);
3660 return screen_SI(screen, seq);
3661 case TERM_CMD_SM_ANSI:
3662 return screen_SM_ANSI(screen, seq);
3663 case TERM_CMD_SM_DEC:
3664 return screen_SM_DEC(screen, seq);
3666 return screen_SO(screen, seq);
3668 return screen_SPA(screen, seq);
3670 return screen_SS2(screen, seq);
3672 return screen_SS3(screen, seq);
3674 return screen_ST(screen, seq);
3676 return screen_SU(screen, seq);
3678 return screen_SUB(screen, seq);
3680 return screen_TBC(screen, seq);
3682 return screen_VPA(screen, seq);
3684 return screen_VPR(screen, seq);
3686 return screen_VT(screen, seq);
3687 case TERM_CMD_XTERM_CLLHP:
3688 return screen_XTERM_CLLHP(screen, seq);
3689 case TERM_CMD_XTERM_IHMT:
3690 return screen_XTERM_IHMT(screen, seq);
3691 case TERM_CMD_XTERM_MLHP:
3692 return screen_XTERM_MLHP(screen, seq);
3693 case TERM_CMD_XTERM_MUHP:
3694 return screen_XTERM_MUHP(screen, seq);
3695 case TERM_CMD_XTERM_RPM:
3696 return screen_XTERM_RPM(screen, seq);
3697 case TERM_CMD_XTERM_RRV:
3698 return screen_XTERM_RRV(screen, seq);
3699 case TERM_CMD_XTERM_RTM:
3700 return screen_XTERM_RTM(screen, seq);
3701 case TERM_CMD_XTERM_SACL1:
3702 return screen_XTERM_SACL1(screen, seq);
3703 case TERM_CMD_XTERM_SACL2:
3704 return screen_XTERM_SACL2(screen, seq);
3705 case TERM_CMD_XTERM_SACL3:
3706 return screen_XTERM_SACL3(screen, seq);
3707 case TERM_CMD_XTERM_SDCS:
3708 return screen_XTERM_SDCS(screen, seq);
3709 case TERM_CMD_XTERM_SGFX:
3710 return screen_XTERM_SGFX(screen, seq);
3711 case TERM_CMD_XTERM_SPM:
3712 return screen_XTERM_SPM(screen, seq);
3713 case TERM_CMD_XTERM_SRV:
3714 return screen_XTERM_SRV(screen, seq);
3715 case TERM_CMD_XTERM_STM:
3716 return screen_XTERM_STM(screen, seq);
3717 case TERM_CMD_XTERM_SUCS:
3718 return screen_XTERM_SUCS(screen, seq);
3719 case TERM_CMD_XTERM_WM:
3720 return screen_XTERM_WM(screen, seq);
3726 unsigned int term_screen_get_width(term_screen *screen) {
3727 assert_return(screen, -EINVAL);
3729 return screen->page->width;
3732 unsigned int term_screen_get_height(term_screen *screen) {
3733 assert_return(screen, -EINVAL);
3735 return screen->page->height;
3738 uint64_t term_screen_get_age(term_screen *screen) {
3739 assert_return(screen, 0);
3744 int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size) {
3746 size_t i, j, ucs4_len;
3747 const term_seq *seq;
3750 assert_return(screen, -EINVAL);
3754 /* Feed bytes into utf8 decoder and handle parsed ucs4 chars. We always
3755 * treat data as UTF-8, but the parser makes sure to fall back to raw
3756 * 8bit mode if the stream is not valid UTF-8. This should be more than
3757 * enough to support old 7bit/8bit modes. */
3758 for (i = 0; i < size; ++i) {
3759 ucs4_len = term_utf8_decode(&screen->utf8, &ucs4_str, in[i]);
3760 for (j = 0; j < ucs4_len; ++j) {
3761 r = term_parser_feed(screen->parser, &seq, ucs4_str[j]);
3764 } else if (r != TERM_SEQ_NONE) {
3765 r = screen_feed_cmd(screen, seq);
3775 static char *screen_map_key(term_screen *screen,
3777 const uint32_t *keysyms,
3780 const uint32_t *ucs4,
3781 unsigned int mods) {
3782 char ch, ch2, ch_mods;
3786 /* TODO: All these key-mappings need to be verified. Public information
3787 * on those mappings is pretty scarce and every emulator seems to do it
3788 * slightly differently.
3789 * A lot of mappings are also missing. */
3797 v = XKB_KEY_NoSymbol;
3799 /* In some mappings, the modifiers are encoded as CSI parameters. The
3800 * encoding is rather arbitrary, but seems to work. */
3802 switch (mods & (TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT | TERM_KBDMOD_CTRL)) {
3803 case TERM_KBDMOD_SHIFT:
3806 case TERM_KBDMOD_ALT:
3809 case TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT:
3812 case TERM_KBDMOD_CTRL:
3815 case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT:
3818 case TERM_KBDMOD_CTRL | TERM_KBDMOD_ALT:
3821 case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT:
3826 /* A user might actually use multiple layouts for keyboard
3827 * input. @keysyms[0] contains the actual keysym that the user
3828 * used. But if this keysym is not in the ascii range, the
3829 * input handler does check all other layouts that the user
3830 * specified whether one of them maps the key to some ASCII
3831 * keysym and provides this via @ascii. We always use the real
3832 * keysym except when handling CTRL+<XY> shortcuts we use the
3833 * ascii keysym. This is for compatibility to xterm et. al. so
3834 * ctrl+c always works regardless of the currently active
3835 * keyboard layout. But if no ascii-sym is found, we still use
3836 * the real keysym. */
3837 if (ascii == XKB_KEY_NoSymbol)
3840 /* map CTRL+<ascii> */
3841 if (mods & TERM_KBDMOD_CTRL) {
3844 /* Right hand side is mapped to the left and then
3845 * treated equally. Fall through to left-hand side.. */
3848 /* Printable ASCII is mapped 1-1 in XKB and in
3849 * combination with CTRL bit 7 is flipped. This
3850 * is equivalent to the caret-notation. */
3851 *p++ = ascii ^ 0x40;
3856 /* map cursor keys */
3880 if (screen->flags & TERM_FLAG_CURSOR_KEYS)
3893 /* map action keys */
3899 case XKB_KEY_Insert:
3902 case XKB_KEY_Delete:
3905 case XKB_KEY_Select:
3908 case XKB_KEY_Page_Up:
3911 case XKB_KEY_Page_Down:
3927 /* map lower function keys */
3960 /* map upper function keys */
4011 /* map special keys */
4013 case 0xff08: /* XKB_KEY_BackSpace */
4014 case 0xff09: /* XKB_KEY_Tab */
4015 case 0xff0a: /* XKB_KEY_Linefeed */
4016 case 0xff0b: /* XKB_KEY_Clear */
4017 case 0xff15: /* XKB_KEY_Sys_Req */
4018 case 0xff1b: /* XKB_KEY_Escape */
4019 case 0xffff: /* XKB_KEY_Delete */
4022 case 0xff13: /* XKB_KEY_Pause */
4023 /* TODO: What should we do with this key?
4024 * Sending XOFF is awful as there is no simple
4025 * way on modern keyboards to send XON again.
4026 * If someone wants this, we can re-eanble
4029 case 0xff14: /* XKB_KEY_Scroll_Lock */
4030 /* TODO: What should we do on scroll-lock?
4031 * Sending 0x14 is what the specs say but it is
4032 * not used today the way most users would
4033 * expect so we disable it. If someone wants
4034 * this, we can re-enable it (optionally). */
4036 case XKB_KEY_Return:
4038 if (screen->flags & TERM_FLAG_NEWLINE_MODE)
4041 case XKB_KEY_ISO_Left_Tab:
4046 /* map unicode keys */
4047 for (i = 0; i < n_syms; ++i)
4048 p += term_utf8_encode(p, ucs4[i]);
4053 int term_screen_feed_keyboard(term_screen *screen,
4054 const uint32_t *keysyms,
4057 const uint32_t *ucs4,
4058 unsigned int mods) {
4059 _cleanup_free_ char *dyn = NULL;
4060 static const size_t padding = 1;
4061 char buf[128], *start, *p = buf;
4063 assert_return(screen, -EINVAL);
4065 /* allocate buffer if too small */
4067 if (4 * n_syms + padding > sizeof(buf)) {
4068 dyn = malloc(4 * n_syms + padding);
4075 /* reserve prefix space */
4079 p = screen_map_key(screen, p, keysyms, n_syms, ascii, ucs4, mods);
4080 if (!p || p - start < 1)
4083 /* The ALT modifier causes ESC to be prepended to any key-stroke. We
4084 * already accounted for that buffer space above, so simply prepend it
4086 * TODO: is altSendsEscape a suitable default? What are the semantics
4087 * exactly? Is it used in C0/C1 conversion? Is it prepended if there
4088 * already is an escape character? */
4089 if (mods & TERM_KBDMOD_ALT && *start != 0x1b)
4092 /* turn C0 into C1 */
4093 if (!(screen->flags & TERM_FLAG_7BIT_MODE) && p - start >= 2)
4094 if (start[0] == 0x1b && start[1] >= 0x40 && start[1] <= 0x5f)
4097 return screen_write(screen, start, p - start);
4100 int term_screen_resize(term_screen *screen, unsigned int x, unsigned int y) {
4105 assert_return(screen, -EINVAL);
4107 r = term_page_reserve(screen->page_main, x, y, &screen->attr, screen->age);
4111 r = term_page_reserve(screen->page_alt, x, y, &screen->attr, screen->age);
4115 if (x > screen->n_tabs) {
4116 t = realloc(screen->tabs, (x + 7) / 8);
4124 for (i = (screen->page->width + 7) / 8 * 8; i < x; i += 8)
4125 screen->tabs[i / 8] = 0x1;
4127 term_page_resize(screen->page_main, x, y, &screen->attr, screen->age, screen->history);
4128 term_page_resize(screen->page_alt, x, y, &screen->attr, screen->age, NULL);
4130 screen->cursor_x = screen_clamp_x(screen, screen->cursor_x);
4131 screen->cursor_y = screen_clamp_x(screen, screen->cursor_y);
4132 screen_cursor_clear_wrap(screen);
4137 void term_screen_soft_reset(term_screen *screen) {
4142 screen->gl = &screen->g0;
4143 screen->gr = &screen->g1;
4146 screen->g0 = &term_unicode_lower;
4147 screen->g1 = &term_unicode_upper;
4148 screen->g2 = &term_unicode_lower;
4149 screen->g3 = &term_unicode_upper;
4151 screen->page = screen->page_main;
4152 screen->history = screen->history_main;
4153 screen->flags = TERM_FLAG_7BIT_MODE;
4154 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
4155 screen->attr = screen->default_attr;
4157 screen->saved.cursor_x = 0;
4158 screen->saved.cursor_y = 0;
4159 screen->saved.attr = screen->attr;
4160 screen->saved.gl = screen->gl;
4161 screen->saved.gr = screen->gr;
4162 screen->saved.glt = NULL;
4163 screen->saved.grt = NULL;
4166 for (i = 0; i < screen->page->width; i += 8)
4167 screen->tabs[i / 8] = 0x1;
4169 term_page_set_scroll_region(screen->page_main, 0, screen->page->height);
4170 term_page_set_scroll_region(screen->page_alt, 0, screen->page->height);
4173 void term_screen_hard_reset(term_screen *screen) {
4176 term_screen_soft_reset(screen);
4178 screen->cursor_x = 0;
4179 screen->cursor_y = 0;
4180 term_page_erase(screen->page_main, 0, 0, screen->page->width, screen->page->height, &screen->attr, screen->age, false);
4181 term_page_erase(screen->page_alt, 0, 0, screen->page->width, screen->page->height, &screen->attr, screen->age, false);
4184 int term_screen_set_answerback(term_screen *screen, const char *answerback) {
4187 assert_return(screen, -EINVAL);
4190 t = strdup(answerback);
4195 free(screen->answerback);
4196 screen->answerback = t;
4201 int term_screen_draw(term_screen *screen,
4202 int (*draw_fn) (term_screen *screen,
4206 const term_attr *attr,
4209 unsigned int ch_width),
4212 uint64_t cell_age, line_age, age = 0;
4213 term_charbuf_t ch_buf;
4214 const uint32_t *ch_str;
4215 unsigned int i, j, cw;
4228 page = screen->page;
4230 for (j = 0; j < page->height; ++j) {
4231 line = page->lines[j];
4232 line_age = MAX(line->age, page->age);
4234 for (i = 0; i < page->width; ++i) {
4237 cell = &line->cells[i];
4238 cell_age = MAX(cell->age, line_age);
4240 if (age != 0 && cell_age <= age)
4243 ch_str = term_char_resolve(cell->ch, &ch_n, &ch_buf);
4245 /* Character-width of 0 is used for cleared cells.
4246 * Always treat this as single-cell character, so
4247 * renderers can assume ch_width is set properpy. */
4248 cw = MAX(cell->cwidth, 1U);
4251 if (i == screen->cursor_x && j == screen->cursor_y &&
4252 !(screen->flags & TERM_FLAG_HIDE_CURSOR))
4269 *fb_age = screen->age;