diff --git a/html_orig/js/app.js b/html_orig/js/app.js
index ab6411b..6e819a2 100644
--- a/html_orig/js/app.js
+++ b/html_orig/js/app.js
@@ -1693,8 +1693,8 @@ var Screen = (function () {
cell = {
t: ' ',
- fg: cursor.fg,
- bg: cursor.bg,
+ fg: 7,
+ bg: 0, // the colors will be replaced immediately as we receive data (user won't see this)
attrs: 0,
e: e,
x: i % W,
@@ -1768,20 +1768,18 @@ var Screen = (function () {
// Attributes
num = parse2B(str, i); i += 2; // fg bg bold hidden
- cursor.fg = num & 0x0F;
- cursor.bg = (num & 0xF0) >> 4;
- cursor.hidden = !(num & 0x100);
- cursor.hanging = !!(num & 0x200);
+ cursor.hidden = !(num & 0x0001);
+ cursor.hanging = !!(num & 0x0002);
// console.log("Attributes word ",num.toString(16)+'h');
Input.setAlts(
- !!(num & 0x400), // cu
- !!(num & 0x800), // np
- !!(num & 0x1000) // fn
+ !!(num & 0x0004), // cu
+ !!(num & 0x0008), // np
+ !!(num & 0x0010) // fn
);
- fg = cursor.fg;
- bg = cursor.bg;
+ fg = 7;
+ bg = 0;
attrs = 0;
// Here come the content
diff --git a/html_orig/jssrc/term.js b/html_orig/jssrc/term.js
index 214a5c2..28627d6 100644
--- a/html_orig/jssrc/term.js
+++ b/html_orig/jssrc/term.js
@@ -136,8 +136,8 @@ var Screen = (function () {
cell = {
t: ' ',
- fg: cursor.fg,
- bg: cursor.bg,
+ fg: 7,
+ bg: 0, // the colors will be replaced immediately as we receive data (user won't see this)
attrs: 0,
e: e,
x: i % W,
@@ -211,20 +211,18 @@ var Screen = (function () {
// Attributes
num = parse2B(str, i); i += 2; // fg bg bold hidden
- cursor.fg = num & 0x0F;
- cursor.bg = (num & 0xF0) >> 4;
- cursor.hidden = !(num & 0x100);
- cursor.hanging = !!(num & 0x200);
+ cursor.hidden = !(num & 0x0001);
+ cursor.hanging = !!(num & 0x0002);
// console.log("Attributes word ",num.toString(16)+'h');
Input.setAlts(
- !!(num & 0x400), // cu
- !!(num & 0x800), // np
- !!(num & 0x1000) // fn
+ !!(num & 0x0004), // cu
+ !!(num & 0x0008), // np
+ !!(num & 0x0010) // fn
);
- fg = cursor.fg;
- bg = cursor.bg;
+ fg = 7;
+ bg = 0;
attrs = 0;
// Here come the content
diff --git a/user/ansi_parser.c b/user/ansi_parser.c
index b677b50..9786271 100644
--- a/user/ansi_parser.c
+++ b/user/ansi_parser.c
@@ -155,7 +155,7 @@ ansi_parser(char newchar)
return;
case TAB:
- screen_tab_forward();
+ screen_tab_forward(1);
return;
// Select G0 or G1
@@ -405,7 +405,7 @@ execFuncs:
/* #line 202 "user/ansi_parser.rl" */
{
// Reset the CSI builder
- leadchar = 0;
+ leadchar = NUL;
arg_ni = 0;
arg_cnt = 0;
diff --git a/user/ansi_parser.rl b/user/ansi_parser.rl
index 6d1654b..77b34a4 100644
--- a/user/ansi_parser.rl
+++ b/user/ansi_parser.rl
@@ -124,7 +124,7 @@ ansi_parser(char newchar)
return;
case TAB:
- screen_tab_forward();
+ screen_tab_forward(1);
return;
// Select G0 or G1
@@ -201,7 +201,7 @@ ansi_parser(char newchar)
action CSI_start {
// Reset the CSI builder
- leadchar = 0;
+ leadchar = NUL;
arg_ni = 0;
arg_cnt = 0;
diff --git a/user/ansi_parser_callbacks.c b/user/ansi_parser_callbacks.c
index ddb3f92..cbfc3ad 100644
--- a/user/ansi_parser_callbacks.c
+++ b/user/ansi_parser_callbacks.c
@@ -5,12 +5,16 @@
*/
#include
+#include
#include "ansi_parser_callbacks.h"
#include "screen.h"
#include "ansi_parser.h"
#include "uart_driver.h"
#include "sgr.h"
#include "cgi_sockets.h"
+#include "ascii.h"
+#include "user_main.h"
+#include "syscfg.h"
static char utf_collect[4];
static int utf_i = 0;
@@ -131,6 +135,37 @@ apars_handle_bel(void)
send_beep();
}
+// data tables for the DECREPTPARM command response
+
+struct DECREPTPARM_parity {int parity; const char * msg;};
+static const struct DECREPTPARM_parity DECREPTPARM_parity_arr[] = {
+ {PARITY_NONE, "1"},
+ {PARITY_ODD, "4"},
+ {PARITY_EVEN, "5"},
+ {-1, 0}
+};
+
+struct DECREPTPARM_baud {int baud; const char * msg;};
+static const struct DECREPTPARM_baud DECREPTPARM_baud_arr[] = {
+ {BIT_RATE_300, "48"},
+ {BIT_RATE_600, "56"},
+ {BIT_RATE_1200, "64"},
+ {BIT_RATE_2400, "88"},
+ {BIT_RATE_4800, "96"},
+ {BIT_RATE_9600 , "104"},
+ {BIT_RATE_19200 , "112"},
+ {BIT_RATE_38400 , "120"},
+ {BIT_RATE_57600 , "128"}, // this is the last in the spec, follow +8
+ {BIT_RATE_74880 , "136"},
+ {BIT_RATE_115200, "144"},
+ {BIT_RATE_230400, "152"},
+ {BIT_RATE_460800, "160"},
+ {BIT_RATE_921600, "168"},
+ {BIT_RATE_1843200, "176"},
+ {BIT_RATE_3686400, "184"},
+ {-1, 0}
+};
+
/**
* Handle fully received CSI ANSI sequence
* @param leadchar - private range leading character, 0 if none
@@ -143,10 +178,10 @@ apars_handle_CSI(char leadchar, const int *params, int count, char keychar)
int n1 = params[0];
int n2 = params[1];
int n3 = params[2];
- static char buf[20];
- bool yn = 0; // for ? l h
+ char buf[32];
+ bool yn = false; // for ? l h
- // defaults
+ // defaults - FIXME this may inadvertently affect some variants that should be left unchanged
switch (keychar) {
case 'A': // move
case 'B':
@@ -166,6 +201,7 @@ apars_handle_CSI(char leadchar, const int *params, int count, char keychar)
case 'P':
case 'I':
case 'Z':
+ case 'b':
if (n1 == 0) n1 = 1;
break;
@@ -215,6 +251,11 @@ apars_handle_CSI(char leadchar, const int *params, int count, char keychar)
screen_cursor_set_x(0);
break;
+ case 'b':
+ // TODO repeat preceding graphic character n1 times
+ ansi_warn("NOIMPL: Repeat char");
+ return;
+
// Set X
case 'G':
case '`': // alternate code
@@ -232,8 +273,66 @@ apars_handle_CSI(char leadchar, const int *params, int count, char keychar)
break; // 1-based
// SU, SD - scroll up/down
- case 'S': screen_scroll_up(n1); break;
- case 'T': screen_scroll_down(n1); break;
+ case 'S':
+ if (leadchar == NUL && count <= 1) {
+ screen_scroll_up(n1);
+ }
+ else {
+ // other:
+ // CSI ? Pi; Pa; Pv S (sixel)
+ ansi_warn("NOIMPL: CSI");
+ apars_handle_badseq();
+ }
+ break;
+ case 'T':
+ if (leadchar == NUL && count <= 1) {
+ // CSI Ps T
+ screen_scroll_down(n1);
+ }
+ else {
+ // other:
+ // CSI Ps ; Ps ; Ps ; Ps ; Ps T
+ // CSI > Ps; Ps T
+ ansi_warn("NOIMPL: CSI");
+ apars_handle_badseq();
+ }
+ break;
+
+ case 't': // xterm window commands
+ if (leadchar == NUL && count <= 2) {
+ // CSI Ps ; Ps ; Ps t
+ switch (n1) {
+ case 8: // set size
+ screen_resize(n2, n3);
+ break;
+ case 18: // report size
+ printf(buf, "\033[8;%d;%dt", termconf_scratch.height, termconf_scratch.width);
+ respond(buf);
+ break;
+ case 11: // Report iconified -> is not iconified
+ respond("\033[1t");
+ break;
+ case 21: // Report title
+ respond("\033]L");
+ respond(termconf_scratch.title);
+ respond("\033\\");
+ break;
+ case 24: // Set Height only
+ screen_resize(n2, termconf_scratch.width);
+ break;
+ default:
+ ansi_warn("NOIMPL CSI %d t", n1);
+ break;
+ }
+ }
+ else {
+ // other:
+ // CSI > Ps; Ps t
+ // CSI Ps SP t,
+ ansi_warn("NOIMPL: CSI");
+ apars_handle_badseq();
+ }
+ break;
// CUP,HVP - set position
case 'H':
@@ -242,6 +341,11 @@ apars_handle_CSI(char leadchar, const int *params, int count, char keychar)
break; // 1-based
case 'J': // Erase screen
+ if (leadchar == '?') {
+ // TODO selective erase
+ ansi_warn("NOIMPL: Selective erase");
+ }
+
if (n1 == 0) {
screen_clear(CLEAR_FROM_CURSOR);
} else if (n1 == 1) {
@@ -253,6 +357,11 @@ apars_handle_CSI(char leadchar, const int *params, int count, char keychar)
break;
case 'K': // Erase lines
+ if (leadchar == '?') {
+ // TODO selective erase
+ ansi_warn("NOIMPL: Selective erase");
+ }
+
if (n1 == 0) {
screen_clear_line(CLEAR_FROM_CURSOR);
} else if (n1 == 1) {
@@ -263,10 +372,37 @@ apars_handle_CSI(char leadchar, const int *params, int count, char keychar)
break;
// SCP, RCP - save/restore position
- case 's': screen_cursor_save(0); break;
- case 'u': screen_cursor_restore(0); break;
+ case 's':
+ if (leadchar == NUL && count == 0) {
+ screen_cursor_save(0);
+ }
+ else {
+ // other:
+ // CSI ? Pm s
+ // CSI Pl; Pr s
+ ansi_warn("NOIMPL: CSI");
+ apars_handle_badseq();
+ }
+ break;
+
+ case 'u':
+ if (leadchar == NUL && count == 0) {
+ screen_cursor_restore(0);
+ }
+ else {
+ ansi_warn("NOIMPL: CSI");
+ apars_handle_badseq();
+ }
+ break;
case 'n': // Queries
+ if (leadchar == '>') {
+ // some xterm garbage - discard
+ // CSI > Ps n
+ ansi_warn("NOIMPL: CSI > %d n", n1);
+ break;
+ }
+
if (n1 == 6) {
// Query cursor position
int x, y;
@@ -279,29 +415,47 @@ apars_handle_CSI(char leadchar, const int *params, int count, char keychar)
respond("\033[0n");
}
else {
- ansi_warn("NOIMPL: CSI %d n", n1);
+ ansi_warn("NOIMPL: CSI");
+ apars_handle_badseq();
}
break;
case 'h': // DEC feature enable
yn = 1;
case 'l': // DEC feature disable
+ // yn is 0 by default
for (int i = 0; i < count; i++) {
int n = params[i];
if (leadchar == '?') {
if (n == 1) {
screen_set_cursors_alt_mode(yn);
}
+ else if (n == 2) {
+ // should reset all Gx to USASCII and reset to VT100 (which we use always)
+ screen_set_charset(0, 'B');
+ screen_set_charset(1, 'B');
+ }
+ else if (n == 3) {
+ // TODO 132 column mode - not implemented due to RAM demands
+ ansi_warn("NOIMPL: 80->132");
+ }
+ else if (n == 4) {
+ // Smooth scroll - not implemented
+ }
+ else if (n == 5) {
+ screen_set_reverse_video(yn);
+ }
else if (n == 6) {
- // TODO origin mode (scrolling region)
+ screen_set_origin_mode(yn);
}
else if (n == 7) {
screen_wrap_enable(yn);
}
else if (n == 8) {
- // Key auto-repeat
+ // TODO Key auto-repeat
// We don't implement this currently, but it could be added
// - discard repeated keypress events between keydown and keyup.
+ ansi_warn("NOIMPL: Auto-repeat toggle");
}
else if (n == 9 || (n >= 1000 && n <= 1006)) {
// TODO mouse
@@ -312,20 +466,60 @@ apars_handle_CSI(char leadchar, const int *params, int count, char keychar)
// 1004 - Send FocusIn/FocusOut events
// 1005 - Enable UTF-8 Mouse Mode
// 1006 - SGR mouse mode
+ ansi_warn("NOIMPL: Mouse tracking");
}
else if (n == 12) {
// TODO Cursor blink on/off
+ ansi_warn("NOIMPL: Cursor blink toggle");
+ }
+ else if (n == 40) {
+ // TODO allow/disallow 80->132 mode
+ // not implemented because of RAM demands
+ ansi_warn("NOIMPL: 80->132 enable");
+ }
+ else if (n == 47 || n == 1047) {
+ // Switch to/from alternate screen
+ // - not implemented fully due to RAM demands
+ screen_swap_state(yn);
+ }
+ else if (n == 1048) {
+ // same as DECSC - save/restore cursor with attributes
+ if (yn) {
+ screen_cursor_save(true);
+ }
+ else {
+ screen_cursor_restore(true);
+ }
}
else if (n == 1049) {
- // XTERM: optionally switch to/from alternate screen
- // We can't implement this because of limited RAM size
+ // save/restore cursor and screen and clear it
+ if (yn) {
+ screen_cursor_save(true);
+ screen_swap_state(true); // this should save the screen - can't because of RAM size
+ screen_clear(CLEAR_ALL);
+ }
+ else {
+ screen_clear(CLEAR_ALL);
+ screen_swap_state(false); // this should restore the screen - can't because of RAM size
+ screen_cursor_restore(true);
+ }
+ }
+ else if (n >= 1050 && n <= 1053) {
+ // TODO Different kinds of function key emulation ?
+ // (In practice this seems hardly ever used)
+
+ // Ps = 1 0 5 0 -> Set terminfo/termcap function-key mode.
+ // Ps = 1 0 5 1 -> Set Sun function-key mode.
+ // Ps = 1 0 5 2 -> Set HP function-key mode.
+ // Ps = 1 0 5 3 -> Set SCO function-key mode.
+ ansi_warn("NOIMPL: FN key emul type");
}
else if (n == 2004) {
// Bracketed paste mode
// Discard, we don't implement this
}
else if (n == 25) {
- screen_cursor_visible(yn);
+ screen_set_cursor_visible(yn);
}
else {
ansi_warn("NOIMPL: CSI ? %d %c", n, keychar);
@@ -350,6 +544,12 @@ apars_handle_CSI(char leadchar, const int *params, int count, char keychar)
count = 1; // this makes it work as 0 (reset)
}
+ if (leadchar == '>') {
+ // some xterm garbage - discard
+ // CSI > Ps; Ps m
+ break;
+ }
+
// iterate arguments
for (int i = 0; i < count; i++) {
int n = params[i];
@@ -361,22 +561,22 @@ apars_handle_CSI(char leadchar, const int *params, int count, char keychar)
else if (n == SGR_FG_DEFAULT) screen_set_fg(termconf_scratch.default_fg); // default fg
else if (n == SGR_BG_DEFAULT) screen_set_bg(termconf_scratch.default_bg); // default bg
// -- set attr --
- else if (n == SGR_BOLD) screen_attr_enable(ATTR_BOLD);
- else if (n == SGR_FAINT) screen_attr_enable(ATTR_FAINT);
- else if (n == SGR_ITALIC) screen_attr_enable(ATTR_ITALIC);
- else if (n == SGR_UNDERLINE) screen_attr_enable(ATTR_UNDERLINE);
- else if (n == SGR_BLINK || n == SGR_BLINK_FAST) screen_attr_enable(ATTR_BLINK); // 6 - rapid blink, not supported
- else if (n == SGR_INVERSE) screen_inverse_enable(true);
- else if (n == SGR_STRIKE) screen_attr_enable(ATTR_STRIKE);
- else if (n == SGR_FRAKTUR) screen_attr_enable(ATTR_FRAKTUR);
+ else if (n == SGR_BOLD) screen_set_sgr(ATTR_BOLD, 1);
+ else if (n == SGR_FAINT) screen_set_sgr(ATTR_FAINT, 1);
+ else if (n == SGR_ITALIC) screen_set_sgr(ATTR_ITALIC, 1);
+ else if (n == SGR_UNDERLINE) screen_set_sgr(ATTR_UNDERLINE, 1);
+ else if (n == SGR_BLINK || n == SGR_BLINK_FAST) screen_set_sgr(ATTR_BLINK, 1); // 6 - rapid blink, not supported
+ else if (n == SGR_STRIKE) screen_set_sgr(ATTR_STRIKE, 1);
+ else if (n == SGR_FRAKTUR) screen_set_sgr(ATTR_FRAKTUR, 1);
+ else if (n == SGR_INVERSE) screen_set_sgr_inverse(1);
// -- clear attr --
- else if (n == SGR_OFF(SGR_BOLD)) screen_attr_disable(ATTR_BOLD);
- else if (n == SGR_OFF(SGR_FAINT)) screen_attr_disable(ATTR_FAINT);
- else if (n == SGR_OFF(SGR_ITALIC)) screen_attr_disable(ATTR_ITALIC|ATTR_FRAKTUR);
- else if (n == SGR_OFF(SGR_UNDERLINE)) screen_attr_disable(ATTR_UNDERLINE);
- else if (n == SGR_OFF(SGR_BLINK)) screen_attr_disable(ATTR_BLINK);
- else if (n == SGR_OFF(SGR_INVERSE)) screen_inverse_enable(false);
- else if (n == SGR_OFF(SGR_STRIKE)) screen_attr_disable(ATTR_STRIKE);
+ else if (n == SGR_OFF(SGR_BOLD)) screen_set_sgr(ATTR_BOLD, 0);
+ else if (n == SGR_OFF(SGR_FAINT)) screen_set_sgr(ATTR_FAINT, 0);
+ else if (n == SGR_OFF(SGR_ITALIC)) screen_set_sgr(ATTR_ITALIC | ATTR_FRAKTUR, 0); // there is no dedicated OFF code for Fraktur
+ else if (n == SGR_OFF(SGR_UNDERLINE)) screen_set_sgr(ATTR_UNDERLINE, 0);
+ else if (n == SGR_OFF(SGR_BLINK)) screen_set_sgr(ATTR_BLINK, 0);
+ else if (n == SGR_OFF(SGR_STRIKE)) screen_set_sgr(ATTR_STRIKE, 0);
+ else if (n == SGR_OFF(SGR_INVERSE)) screen_set_sgr_inverse(0);
// -- AIX bright colors --
else if (n >= SGR_FG_BRT_START && n <= SGR_FG_BRT_END) screen_set_fg((Color) ((n - SGR_FG_BRT_START) + 8)); // AIX bright fg
else if (n >= SGR_BG_BRT_START && n <= SGR_BG_BRT_END) screen_set_bg((Color) ((n - SGR_BG_BRT_START) + 8)); // AIX bright bg
@@ -386,32 +586,6 @@ apars_handle_CSI(char leadchar, const int *params, int count, char keychar)
}
break;
- case 't': // xterm window hacks
- switch(n1) {
- case 8: // set size
- screen_resize(n2, n3);
- break;
- case 18: // report size
- printf(buf, "\033[8;%d;%dt", termconf_scratch.height, termconf_scratch.width);
- respond(buf);
- break;
- case 11: // Report iconified -> is not iconified
- respond("\033[1t");
- break;
- case 21: // Report title
- respond("\033]L");
- respond(termconf_scratch.title);
- respond("\033\\");
- break;
- case 24: // Set Height only
- screen_resize(n2, termconf_scratch.width);
- break;
- default:
- ansi_warn("NOIMPL CSI %d t", n1);
- break;
- }
- break;
-
case 'L': // Insert lines (shove down)
screen_insert_lines(n1);
break;
@@ -429,7 +603,16 @@ apars_handle_CSI(char leadchar, const int *params, int count, char keychar)
break;
case 'r':
- // TODO scrolling region
+ if (leadchar == NUL && count == 2) {
+ screen_set_scrolling_region(n1, n2);
+ }
+ else {
+ // other:
+ // CSI ? Pm r
+ // CSI Pt; Pl; Pb; Pr; Ps$ r
+ ansi_warn("NOIMPL: CSI");
+ apars_handle_badseq();
+ }
break;
case 'g': // Clear tabs
@@ -441,19 +624,55 @@ apars_handle_CSI(char leadchar, const int *params, int count, char keychar)
break;
case 'Z': // Tab backward
- for(; n1 > 0; n1--) {
- screen_tab_reverse();
- }
+ screen_tab_reverse(n1);
break;
case 'I': // Tab forward
- for(; n1 > 0; n1--) {
- screen_tab_forward();
- }
+ screen_tab_forward(n1);
break;
case 'c': // CSI-c - report capabilities
- respond("\033[?64;22;c"); // pretend we're vt400
+ if (leadchar == NUL) {
+ respond("\033[?64;9c"); // pretend we're vt400 with national character sets
+ }
+ else if (leadchar == '>') {
+ // 41 - we're "VT400", 0 - ROM cartridge number
+ sprintf(buf, "\033[>41;%d;0c", FIRMWARE_VERSION_NUM);
+ respond(buf);
+ } else {
+ ansi_warn("NOIMPL: CSI");
+ apars_handle_badseq();
+ }
+ break;
+
+ case 'x': // DECREPTPARM
+ if (n1 <= 1) {
+ respond("\033[2;"); // this is a response
+
+ // Parity
+ for(const struct DECREPTPARM_parity *p = DECREPTPARM_parity_arr; p->parity != -1; p++) {
+ if (p->parity == sysconf->uart_parity) {
+ respond(p->msg);
+ break;
+ }
+ }
+
+ // bits per character (uart byte)
+ respond(";8;");
+
+ // Baud rate
+ for(const struct DECREPTPARM_baud *p = DECREPTPARM_baud_arr; p->baud != -1; p++) {
+ if (p->baud == sysconf->uart_baudrate) {
+ respond(p->msg);
+ respond(";");
+ respond(p->msg);
+ break;
+ }
+ }
+
+ // multiplier 1, flags 0
+ respond(";1;0x"); // ROM cartridge number ??
+ }
break;
default:
@@ -469,6 +688,13 @@ apars_handle_CSI(char leadchar, const int *params, int count, char keychar)
void ICACHE_FLASH_ATTR apars_handle_hashCode(char c)
{
switch(c) {
+ case '3': // Double size, top half
+ case '4': // Single size, bottom half
+ case '5': // Single width, single height
+ case '6': // Double width
+ ansi_warn("NOIMPL: Double Size Line");
+ break;
+
case '8':
screen_fill_with_E();
break;
diff --git a/user/ascii.h b/user/ascii.h
index a0deec3..55f5cdd 100644
--- a/user/ascii.h
+++ b/user/ascii.h
@@ -13,13 +13,13 @@ enum ASCII_CODES {
EOT = 4,
ENQ = 5,
ACK = 6,
- BEL = 7,
- BS = 8,
- TAB = 9,
- LF = 10,
- VT = 11,
- FF = 12,
- CR = 13,
+ BEL = 7, /* \a */
+ BS = 8, /* \b */
+ TAB = 9, /* \t */
+ LF = 10, /* \n */
+ VT = 11, /* \v */
+ FF = 12, /* \f */
+ CR = 13, /* \r */
SO = 14,
SI = 15,
DLE = 16,
@@ -33,7 +33,7 @@ enum ASCII_CODES {
CAN = 24,
EM = 25,
SUB = 26,
- ESC = 27,
+ ESC = 27, /* \033, \x1b, \e */
FS = 28,
GS = 29,
RS = 30,
diff --git a/user/screen.c b/user/screen.c
index 8cc75f6..83e6bc3 100644
--- a/user/screen.c
+++ b/user/screen.c
@@ -3,6 +3,7 @@
#include "screen.h"
#include "persist.h"
#include "sgr.h"
+#include "ascii.h"
TerminalConfigBundle * const termconf = &persist.current.termconf;
TerminalConfigBundle termconf_scratch;
@@ -48,6 +49,7 @@ static struct {
bool cursors_alt_mode; //!< Application mode for cursor keys
bool newline_mode;
+ bool reverse;
char charset0;
char charset1;
@@ -205,6 +207,7 @@ screen_reset(void)
scr.numpad_alt_mode = false;
scr.cursors_alt_mode = false;
scr.newline_mode = false;
+ scr.reverse = false;
scr.charset0 = 'B';
scr.charset1 = '0';
@@ -216,6 +219,18 @@ screen_reset(void)
NOTIFY_DONE();
}
+
+/**
+ * Swap screen buffer / state
+ * this is CSI ? 47/1047/1049 h/l
+ * @param alternate - true if we're swapping, false if unswapping
+ */
+void ICACHE_FLASH_ATTR
+screen_swap_state(bool alternate)
+{
+ // TODO impl - backup/restore title, size, global attributes (not SGR)
+}
+
//endregion
//region --- Tab stops ---
@@ -305,27 +320,32 @@ prev_tab_stop(void)
}
void ICACHE_FLASH_ATTR
-screen_tab_forward(void)
+screen_tab_forward(int count)
{
NOTIFY_LOCK();
- int tab = next_tab_stop();
- if (tab != -1) {
- cursor.x = tab;
- } else {
- cursor.x = W-1;
+ for (; count > 0; count--) {
+ int tab = next_tab_stop();
+ if (tab != -1) {
+ cursor.x = tab;
+ }
+ else {
+ cursor.x = W - 1;
+ }
}
NOTIFY_DONE();
}
void ICACHE_FLASH_ATTR
-screen_tab_reverse(void)
+screen_tab_reverse(int count)
{
NOTIFY_LOCK();
- int tab = prev_tab_stop();
- if (tab != -1) {
- cursor.x = tab;
- } else {
- cursor.x = 0;
+ for (; count > 0; count--) {
+ int tab = prev_tab_stop();
+ if (tab != -1) {
+ cursor.x = tab;
+ } else {
+ cursor.x = 0;
+ }
}
NOTIFY_DONE();
}
@@ -600,6 +620,14 @@ screen_scroll_down(unsigned int lines)
done:
NOTIFY_DONE();
}
+
+/** Set scrolling region */
+void ICACHE_FLASH_ATTR
+screen_set_scrolling_region(int from, int to)
+{
+ // TODO implement (also add to scr)
+}
+
//endregion
//region --- Cursor manipulation ---
@@ -726,7 +754,7 @@ screen_cursor_restore(bool withAttrs)
* Enable cursor display
*/
void ICACHE_FLASH_ATTR
-screen_cursor_visible(bool visible)
+screen_set_cursor_visible(bool visible)
{
NOTIFY_LOCK();
cursor.visible = visible;
@@ -763,19 +791,18 @@ screen_set_bg(Color color)
}
void ICACHE_FLASH_ATTR
-screen_attr_enable(u8 attrs)
+screen_set_sgr(u8 attrs, bool ena)
{
- cursor.attrs |= attrs;
-}
-
-void ICACHE_FLASH_ATTR
-screen_attr_disable(u8 attrs)
-{
- cursor.attrs &= ~attrs;
+ if (ena) {
+ cursor.attrs |= attrs;
+ }
+ else {
+ cursor.attrs &= ~attrs;
+ }
}
void ICACHE_FLASH_ATTR
-screen_inverse_enable(bool ena)
+screen_set_sgr_inverse(bool ena)
{
cursor.inverse = ena;
}
@@ -829,12 +856,26 @@ screen_set_cursors_alt_mode(bool alt_mode)
NOTIFY_DONE();
}
+void ICACHE_FLASH_ATTR
+screen_set_reverse_video(bool reverse)
+{
+ NOTIFY_LOCK();
+ scr.reverse = reverse;
+ NOTIFY_DONE();
+}
+
void ICACHE_FLASH_ATTR
screen_set_newline_mode(bool nlm)
{
scr.newline_mode = nlm;
}
+void ICACHE_FLASH_ATTR
+screen_set_origin_mode(bool region_origin)
+{
+ // TODO implement (also add to scr)
+}
+
void ICACHE_FLASH_ATTR
screen_report_sgr(char *buffer)
{
@@ -868,32 +909,31 @@ screen_putchar(const char *ch)
// Special treatment for CRLF
switch (ch[0]) {
- case '\r':
+ case CR:
screen_cursor_set_x(0);
- if (scr.newline_mode) {
- // like LF
- screen_cursor_move(1, 0, true);
- }
goto done;
- case '\n':
+ case LF:
screen_cursor_move(1, 0, true); // can scroll
+ if (scr.newline_mode) {
+ // like CR
+ screen_cursor_set_x(0);
+ }
goto done;
- case 8: // BS
+ case BS:
if (cursor.x > 0) {
- // according to vttest, backspace should go to col 79 if "hanging" after 80
+ // backspace should go to col 79 if "hanging" after 80 (as if it never actually left the 80th col)
if (cursor.hanging) {
cursor.hanging = false;
}
cursor.x--;
}
- // we should not wrap around
- // and apparently backspace should not even clear the cell
+ // we should not wrap around, and backspace should not even clear the cell (verified in xterm)
goto done;
default:
- if (ch[0] < ' ') {
+ if (ch[0] < SP) {
// Discard
warn("Ignoring control char %d", (int)ch[0]);
goto done;
@@ -902,7 +942,7 @@ screen_putchar(const char *ch)
if (cursor.hanging) {
// perform the scheduled wrap if hanging
- // if autowrap = off, it overwrites the last char
+ // if auto-wrap = off, it overwrites the last char
if (cursor.wraparound) {
cursor.x = 0;
cursor.y++;
@@ -1137,13 +1177,11 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data)
encode2B((u16) cursor.y, &w3);
encode2B((u16) cursor.x, &w4);
encode2B((u16) (
- cursor.fg |
- (cursor.bg<<4) |
- (cursor.visible ? 0x100 : 0) |
- (cursor.hanging ? 0x200 : 0) |
- (scr.cursors_alt_mode ? 0x400 : 0) |
- (scr.numpad_alt_mode ? 0x800 : 0) |
- (termconf->fn_alt_mode ? 0x1000 : 0)
+ (cursor.visible ? 0x01 : 0) |
+ (cursor.hanging ? 0x02 : 0) |
+ (scr.cursors_alt_mode ? 0x04 : 0) |
+ (scr.numpad_alt_mode ? 0x08 : 0) |
+ (termconf->fn_alt_mode ? 0x10 : 0)
)
, &w5);
@@ -1171,8 +1209,20 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data)
// No repeat
bool changeAttrs = cell0->attrs != ss->lastAttrs;
bool changeColors = (cell0->fg != ss->lastFg || cell0->bg != ss->lastBg);
+ Color fg, bg;
+
+ // Reverse fg and bg if we're in global reverse mode
+ if (! scr.reverse) {
+ fg = cell0->fg;
+ bg = cell0->bg;
+ }
+ else {
+ fg = cell0->bg;
+ bg = cell0->fg;
+ }
+
if (!changeAttrs && changeColors) {
- encode2B(cell0->fg | (cell0->bg<<4), &w1);
+ encode2B(fg | (bg<<4), &w1);
bufprint("\x03%c%c", w1.lsb, w1.msb);
}
else if (changeAttrs && !changeColors) {
@@ -1182,11 +1232,7 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data)
}
else if (changeAttrs && changeColors) {
// colors and attrs
- encode3B((u32) (
- cell0->fg |
- (cell0->bg<<4) |
- (cell0->attrs<<8))
- , &lw1);
+ encode3B((u32) (fg | (bg<<4) | (cell0->attrs<<8)), &lw1);
bufprint("\x01%c%c%c", lw1.lsb, lw1.msb, lw1.xsb);
}
diff --git a/user/screen.h b/user/screen.h
index d745c62..4f4d75e 100644
--- a/user/screen.h
+++ b/user/screen.h
@@ -41,19 +41,6 @@
#define TERM_BTN_LEN 10
#define TERM_TITLE_LEN 64
-typedef enum {
- CHANGE_CONTENT,
- CHANGE_LABELS,
-} ScreenNotifyChangeTopic;
-
-#define ATTR_BOLD (1<<0)
-#define ATTR_FAINT (1<<1)
-#define ATTR_ITALIC (1<<2)
-#define ATTR_UNDERLINE (1<<3)
-#define ATTR_BLINK (1<<4)
-#define ATTR_FRAKTUR (1<<5)
-#define ATTR_STRIKE (1<<6)
-
#define SCR_DEF_DISPLAY_TOUT_MS 20
#define SCR_DEF_PARSER_TOUT_MS 10
#define SCR_DEF_FN_ALT_MODE false
@@ -64,10 +51,12 @@ typedef enum {
/** Maximum screen size (determines size of the static data array) */
#define MAX_SCREEN_SIZE (80*25)
+// --- Persistent Settings ---
+
typedef struct {
u32 width;
u32 height;
- u8 default_bg;
+ u8 default_bg; // should be the Color typedef, but this way the size is more explicit
u8 default_fg;
char title[TERM_TITLE_LEN];
char btn[5][TERM_BTN_LEN];
@@ -86,21 +75,18 @@ extern TerminalConfigBundle * const termconf;
*/
extern TerminalConfigBundle termconf_scratch;
+/** Restore default settings to termconf. Does not apply or copy to scratch. */
void terminal_restore_defaults(void);
+/** Apply settings, redraw (clears the screen) */
void terminal_apply_settings(void);
-void terminal_apply_settings_noclear(void); // the same, but with no screen reset / init
-
-void screen_report_sgr(char *buffer);
-
-typedef enum {
- CLEAR_TO_CURSOR=0, CLEAR_FROM_CURSOR=1, CLEAR_ALL=2
-} ClearMode;
-
-typedef uint8_t Color;
-
-httpd_cgi_state screenSerializeToBuffer(char *buffer, size_t buf_len, void **data);
+/** Apply settings, redraw (no clear - not resized) */
+void terminal_apply_settings_noclear(void);
+/** Init the screen */
+void screen_init(void);
+/** Change the screen size */
+void screen_resize(int rows, int cols);
-void screenSerializeLabelsToBuffer(char *buffer, size_t buf_len);
+// --- Encoding ---
typedef struct {
u8 lsb;
@@ -116,15 +102,18 @@ typedef struct {
/** Encode number to two nice ASCII bytes */
void encode2B(u16 number, WordB2 *stru);
-/** Init the screen */
-void screen_init(void);
-/** Change the screen size */
-void screen_resize(int rows, int cols);
-/** Check if coord is valid */
-bool screen_isCoordValid(int y, int x);
+httpd_cgi_state screenSerializeToBuffer(char *buffer, size_t buf_len, void **data);
+
+void screenSerializeLabelsToBuffer(char *buffer, size_t buf_len);
// --- Clearing ---
+typedef enum {
+ CLEAR_TO_CURSOR = 0,
+ CLEAR_FROM_CURSOR = 1,
+ CLEAR_ALL = 2
+} ClearMode;
+
/** Screen reset to default state */
void screen_reset(void);
/** Clear entire screen */
@@ -133,18 +122,23 @@ void screen_clear(ClearMode mode);
void screen_clear_line(ClearMode mode);
/** Clear part of line */
void screen_clear_in_line(unsigned int count);
-/** Shift screen upwards */
-void screen_scroll_up(unsigned int lines);
-/** Shift screen downwards */
-void screen_scroll_down(unsigned int lines);
-/** esc # 8 - fill entire screen with E of default colors (DEC alignment display) */
-void screen_fill_with_E(void);
+/** Swap to alternate buffer (really what this does is backup terminal title, size and other global attributes) */
+void screen_swap_state(bool alternate);
// --- insert / delete ---
+
+/** Insert lines at cursor, shove down */
void screen_insert_lines(unsigned int lines);
+/** Delete lines at cursor, pull up */
void screen_delete_lines(unsigned int lines);
+/** Insert characters at cursor, shove right */
void screen_insert_characters(unsigned int count);
+/** Delete characters at cursor, pull left */
void screen_delete_characters(unsigned int count);
+/** Shift screen upwards */
+void screen_scroll_up(unsigned int lines);
+/** Shift screen downwards */
+void screen_scroll_down(unsigned int lines);
// --- Cursor control ---
@@ -156,51 +150,81 @@ void screen_cursor_get(int *y, int *x);
void screen_cursor_set_x(int x);
/** Set cursor Y position */
void screen_cursor_set_y(int y);
-/** Reset cursor attribs */
-void screen_reset_sgr(void);
/** Relative cursor move */
void screen_cursor_move(int dy, int dx, bool scroll);
/** Save the cursor pos */
void screen_cursor_save(bool withAttrs);
/** Restore the cursor pos */
void screen_cursor_restore(bool withAttrs);
-/** Enable cursor display */
-void screen_cursor_visible(bool visible);
-/** Enable auto wrap */
-void screen_wrap_enable(bool enable);
+
+// --- Cursor behavior setting ---
+
+/** Toggle INSERT / REPLACE */
+void screen_set_insert_mode(bool insert);
/** Enable CR auto */
void screen_set_newline_mode(bool nlm);
+/** Enable auto wrap */
+void screen_wrap_enable(bool enable);
+/** Set scrolling region */
+void screen_set_scrolling_region(int from, int to);
+/** Enable or disable origin remap to top left of scrolling region */
+void screen_set_origin_mode(bool region_origin);
-// --- Colors ---
+// --- Graphic rendition setting ---
+
+typedef uint8_t Color; // 0-16
+
+#define ATTR_BOLD (1<<0)
+#define ATTR_FAINT (1<<1)
+#define ATTR_ITALIC (1<<2)
+#define ATTR_UNDERLINE (1<<3)
+#define ATTR_BLINK (1<<4)
+#define ATTR_FRAKTUR (1<<5)
+#define ATTR_STRIKE (1<<6)
/** Set cursor foreground color */
void screen_set_fg(Color color);
/** Set cursor background coloor */
void screen_set_bg(Color color);
+/** Enable/disable attrs by bitmask */
+void screen_set_sgr(u8 attrs, bool ena);
+/** Set the inverse attribute */
+void screen_set_sgr_inverse(bool ena);
+/** Reset cursor attribs */
+void screen_reset_sgr(void);
-/** enable attrs by bitmask */
-void screen_attr_enable(u8 attrs);
-/** disable attrs by bitmask */
-void screen_attr_disable(u8 attrs);
-/** Set the inverse cursor attribute */
-void screen_inverse_enable(bool ena);
-/** Toggle INSERT / REPLACE */
-void screen_set_insert_mode(bool insert);
+// --- Global modes and attributes ---
+
+/** Enable cursor display */
+void screen_set_cursor_visible(bool visible);
/** Toggle application keypad mode */
void screen_set_numpad_alt_mode(bool app_mode);
/** Toggle application cursor mode */
void screen_set_cursors_alt_mode(bool app_mode);
+/** Set reverse video mode */
+void screen_set_reverse_video(bool reverse);
+
+// --- Charset ---
+/** Switch G0 <-> G1 */
void screen_set_charset_n(int Gx);
+/** Assign G0 or G1 */
void screen_set_charset(int Gx, char charset);
-// tabs
+// --- Tab stops ---
+/** Remove all tabs on the screen */
void screen_clear_all_tabs(void);
+/** Set tab at the current column */
void screen_set_tab(void);
+/** Remove tab at the current column (if any) */
void screen_clear_tab(void);
-void screen_tab_forward(void);
-void screen_tab_reverse(void);
+/** Move forward one tab */
+void screen_tab_forward(int count);
+/** Move backward one tab */
+void screen_tab_reverse(int count);
+
+// --- Printing characters ---
/**
* Set a character in the cursor color, move to right with wrap.
@@ -208,12 +232,31 @@ void screen_tab_reverse(void);
* unicode (then it can be 4 chars, or terminated by a zero)
*/
void screen_putchar(const char *ch);
+/**
+ * esc # 8 - fill entire screen with E of default colors
+ * (DEC alignment test mode)
+ */
+void screen_fill_with_E(void);
+
+// --- Queries ---
+
+/** Check if coord is valid */
+bool screen_isCoordValid(int y, int x);
+/** Report current SGR as num;num;... for DAC query */
+void screen_report_sgr(char *buffer);
-#if 0
-/** Debug dump */
-void screen_dd(void);
-#endif
+// --- Notify ---
+typedef enum {
+ CHANGE_CONTENT = 0,
+ CHANGE_LABELS = 1,
+} ScreenNotifyChangeTopic;
+
+/**
+ * Called when the screen content or settings change
+ * and the front-end should redraw / update.
+ * @param topic - what kind of change this is (chooses what message to send)
+ */
extern void screen_notifyChange(ScreenNotifyChangeTopic topic);
#endif // SCREEN_H
diff --git a/user/user_main.h b/user/user_main.h
index 5f5ad7d..8067be5 100644
--- a/user/user_main.h
+++ b/user/user_main.h
@@ -1,7 +1,12 @@
#ifndef USER_MAIN_H_H
#define USER_MAIN_H_H
-#define FIRMWARE_VERSION "0.6.7+" GIT_HASH
+#define FW_V_MAJOR 0
+#define FW_V_MINOR 6
+#define FW_V_PATCH 7
+
+#define FIRMWARE_VERSION STR(FW_V_MAJOR) "." STR(FW_V_MINOR) "." STR(FW_V_PATCH) "+" GIT_HASH
+#define FIRMWARE_VERSION_NUM (FW_V_MAJOR*10000 + FW_V_MINOR*100 + FW_V_PATCH) // this is used in ID queries
#define TERMINAL_GITHUB_REPO "https://github.com/MightyPork/esp-vt100-firmware"
#endif //USER_MAIN_H_H