diff --git a/user/ansi_parser_callbacks.c b/user/ansi_parser_callbacks.c index d034323..7718426 100644 --- a/user/ansi_parser_callbacks.c +++ b/user/ansi_parser_callbacks.c @@ -65,10 +65,12 @@ apars_handle_plainchar(char c) } else { if (c == 14) { + // ShiftIN screen_set_charset_n(1); return; } if (c == 15) { + // ShiftOUT screen_set_charset_n(0); return; } @@ -97,6 +99,7 @@ apars_handle_characterSet(char leadchar, char c) { if (leadchar == '(') screen_set_charset(0, c); else if (leadchar == ')') screen_set_charset(1, c); + // other alternatives * + . - / not implemented } void ICACHE_FLASH_ATTR @@ -119,6 +122,7 @@ apars_handle_CSI(char leadchar, int *params, int count, char keychar) int n2 = params[1]; int n3 = params[2]; static char buf[20]; + bool yn = 0; // for ? l h // defaults switch (keychar) { @@ -224,7 +228,6 @@ apars_handle_CSI(char leadchar, int *params, int count, char keychar) case 'n': // queries if (n1 == 6) { // Query cursor position - char buf[20]; int x, y; screen_cursor_get(&y, &x); sprintf(buf, "\033[%d;%dR", y+1, x+1); @@ -242,43 +245,31 @@ apars_handle_CSI(char leadchar, int *params, int count, char keychar) // DECTCEM feature enable / disable case 'h': // feature enable - if (leadchar == '?') { - if (n1 == 25) screen_cursor_enable(1); - else if (n1 == 7) screen_wrap_enable(1); - else if (n1 == 1) { - // TODO something with arrow keys?? - } - else { - ansi_warn("NOIMPL DEC opt %d", n1); - } - } - else { - if (n1 == 4) { - // TODO insert mode, i think this is to suppress user input - } - else { - ansi_warn("NOIMPL flag %d", n1); - } - } - break; - + yn = 1; case 'l': // feature disable - if (leadchar == '?') { - if (n1 == 25) screen_cursor_enable(0); - else if (n1 == 7) screen_wrap_enable(0); - else if (n1 == 1) { - // TODO see above - } - else { - ansi_warn("NOIMPL DEC opt %d", n1); - } - } - else { - if (n1 == 4) { - // TODO see above + for (int i = 0; i < count; i++) { + int n = params[i]; + if (leadchar == '?') { + if (n == 25) { + screen_cursor_enable(yn); + } + else if (n == 7) { + screen_wrap_enable(yn); + } + else if (n == 1) { + screen_set_cursor_application_mode(yn); + } + else { + ansi_warn("NOIMPL DEC opt %d", n); + } } else { - ansi_warn("NOIMPL flag %d", n1); + if (n == 4) { + screen_set_insert_mode(yn); + } + else { + ansi_warn("NOIMPL flag %d", n); + } } } break; @@ -320,7 +311,7 @@ apars_handle_CSI(char leadchar, int *params, int count, char keychar) else if (n >= 90 && n <= 97) screen_set_fg((Color) (n - 90 + 8)); // AIX bright fg else if (n >= 100 && n <= 107) screen_set_bg((Color) (n - 100 + 8)); // AIX bright bg else { - ansi_warn("NOIMPL SGR attr %d", n); + ansi_warn("NOIMPL SGR attr %d", n); } } break; @@ -379,19 +370,14 @@ apars_handle_CSI(char leadchar, int *params, int count, char keychar) ansi_warn("NOIMPL cursor back tab"); break; - case 'q': - // TODO setmode (??) - ansi_warn("NOIMPL CSI setmode %d", n1); - break; - case 'p': if (leadchar == '!') { info("SOFT RESET!"); - system_restart(); + screen_reset(); // TODO do soft reset } break; - case 'c': + case 'c': // CSI-c // report capabilities (pretend we're vt4xx) UART_WriteString(UART0, "\033[?64;22;c", UART_TIMEOUT_US); break; @@ -449,17 +435,16 @@ void ICACHE_FLASH_ATTR apars_handle_shortCode(char c) // ansi_warn("NOIMPL set tab"); break; - // TODO those don't seem to do anything case '>': -// ansi_warn("NOIMPL NUMKP"); + screen_set_keypad_application_mode(false); break; case '<': -// ansi_warn("NOIMPL SETANSI"); + // "Enter ANSI / VT100 mode" - no-op break; case '=': -// ansi_warn("NOIMPL ALTKP"); + screen_set_keypad_application_mode(true); break; default: diff --git a/user/screen.c b/user/screen.c index ec08fab..c152bdf 100644 --- a/user/screen.c +++ b/user/screen.c @@ -14,44 +14,6 @@ static void utf8_remap(char* out, char g, char table); #define W termconf_scratch.width #define H termconf_scratch.height -/** - * Restore hard defaults - */ -void terminal_restore_defaults(void) -{ - termconf->default_bg = 0; - termconf->default_fg = 7; - termconf->width = 26; - termconf->height = 10; - termconf->parser_tout_ms = 10; - sprintf(termconf->title, "ESPTerm"); - for(int i=1; i <= 5; i++) { - sprintf(termconf->btn[i-1], "%d", i); - } -} - -/** - * Apply settings after eg. restore from defaults - */ -void terminal_apply_settings(void) -{ - terminal_apply_settings_noclear(); - screen_init(); -} - -void terminal_apply_settings_noclear(void) -{ - memcpy(&termconf_scratch, termconf, sizeof(TerminalConfigBundle)); - if (W*H >= MAX_SCREEN_SIZE) { - error("BAD SCREEN SIZE: %d rows x %d cols", H, W); - error("reverting terminal settings to default"); - terminal_restore_defaults(); - persist_store(); - memcpy(&termconf_scratch, termconf, sizeof(TerminalConfigBundle)); - screen_init(); - } -} - /** * Highest permissible value of the color attribute */ @@ -79,6 +41,12 @@ static struct { int x; //!< X coordinate int y; //!< Y coordinate bool autowrap; //!< Wrapping when EOL + bool insert_mode; //!< Insert mode (move rest of the line to the right) + + // TODO use those for input processing + bool kp_alternate; //!< Application Mode - affects how user input of control keys is sent + bool curs_alternate; //!< Application mode for cursor keys + bool visible; //!< Visible (not attribute, DEC special) bool inverse; u8 attrs; @@ -121,6 +89,45 @@ static volatile int notifyLock = 0; if (notifyLock == 0) screen_notifyChange(CHANGE_CONTENT); \ } while(0) +/** + * Restore hard defaults + */ +void terminal_restore_defaults(void) +{ + termconf->default_bg = 0; + termconf->default_fg = 7; + termconf->width = 26; + termconf->height = 10; + termconf->parser_tout_ms = 10; + sprintf(termconf->title, "ESPTerm"); + for(int i=1; i <= 5; i++) { + sprintf(termconf->btn[i-1], "%d", i); + } +} + +/** + * Apply settings after eg. restore from defaults + */ +void terminal_apply_settings(void) +{ + terminal_apply_settings_noclear(); + screen_init(); +} + +/** this is used when changing terminal settings that do not affect the screen size */ +void terminal_apply_settings_noclear(void) +{ + memcpy(&termconf_scratch, termconf, sizeof(TerminalConfigBundle)); + if (W*H >= MAX_SCREEN_SIZE) { + error("BAD SCREEN SIZE: %d rows x %d cols", H, W); + error("reverting terminal settings to default"); + terminal_restore_defaults(); + persist_store(); + memcpy(&termconf_scratch, termconf, sizeof(TerminalConfigBundle)); + screen_init(); + } +} + /** * Clear range, inclusive */ @@ -151,6 +158,8 @@ clear_range(unsigned int from, unsigned int to) static void ICACHE_FLASH_ATTR cursor_reset(void) { + // TODO this should probably be public and invoked by "soft reset" + cursor.x = 0; cursor.y = 0; cursor.fg = termconf_scratch.default_fg; @@ -158,6 +167,10 @@ cursor_reset(void) cursor.visible = 1; cursor.autowrap = 1; cursor.attrs = 0; + cursor.insert_mode = 0; + + cursor.kp_alternate = 0; + cursor.curs_alternate = 0; cursor.charset0 = 'B'; cursor.charset1 = '0'; @@ -657,13 +670,27 @@ void ICACHE_FLASH_ATTR screen_set_charset(int Gx, char charset) if (Gx == 1) cursor.charset1 = charset; } +void ICACHE_FLASH_ATTR screen_set_insert_mode(bool insert) +{ + cursor.insert_mode = insert; +} + +void ICACHE_FLASH_ATTR screen_set_keypad_application_mode(bool app_mode) +{ + cursor.kp_alternate = app_mode; +} + +void ICACHE_FLASH_ATTR screen_set_cursor_application_mode(bool app_mode) +{ + cursor.curs_alternate = app_mode; +} + /** * Set a character in the cursor color, move to right with wrap. */ void ICACHE_FLASH_ATTR screen_putchar(const char *ch) { - char buf[4]; NOTIFY_LOCK(); Cell *c = &screen[cursor.x + cursor.y * W]; @@ -681,18 +708,13 @@ screen_putchar(const char *ch) case 8: // BS if (cursor.x > 0) { cursor.x--; - } else { - // wrap around start of line - if (cursor.autowrap && cursor.y>0) { - cursor.x=W-1; - cursor.y--; - } } - // apparently backspace should not clear the cell + // we should not wrap around + // and apparently backspace should not even clear the cell goto done; case 9: // TAB - // TODO change if tab setting is ever implemented + // TODO change to "go to next tab stop" if (cursor.x<((W-1)-(W-1)%4)) { c->c[0] = ' '; c->c[1] = 0; @@ -712,6 +734,9 @@ screen_putchar(const char *ch) } } + // move the rest of the line if we're in Insert Mode + if (cursor.x < W-1 && cursor.insert_mode) screen_insert_characters(1); + if (ch[1] == 0 && ch[0] <= 0x7f) { // we have len=1 and ASCII utf8_remap(c->c, ch[0], (cursor.charsetN == 0) ? cursor.charset0 : cursor.charset1); @@ -801,29 +826,36 @@ utf8_remap(char *out, char g, char table) utf = vt100_to_unicode[g - 0x41]; } break; + case 'A': /* UK, replaces # with GBP */ if (g == '#') utf = 0x20a4; break; + + default: + // no remap + utf = (unsigned char)g; + break; } + // Encode to UTF-8 if (utf > 0x7F) { // formulas taken from: https://gist.github.com/yamamushi/5823402 if ((utf >= 0x80) && (utf <= 0x07FF)) { + // 2-byte unicode out[0] = (char) ((utf >> 0x06) ^ 0xC0); out[1] = (char) (((utf ^ 0xFFC0) | 0x80) & ~0x40); out[2]=0; } - else if ((utf >= 0x0800) && (utf <= 0xFFFF)) { + else { + // 3-byte unicode out[0] = (char) (((utf ^ 0xFC0FFF) >> 0x0C) | 0xE0); out[1] = (char) ((((utf ^ 0xFFF03F) >> 0x06) | 0x80) & ~0x40); out[2] = (char) (((utf ^ 0xFFFC0) | 0x80) & ~0x40); out[3]=0; - } else { - out[0] = g; - out[1] = 0; } } else { - out[0] = g; + // low ASCII + out[0] = (char) utf; out[1] = 0; } } diff --git a/user/screen.h b/user/screen.h index 4920d62..b401dbe 100644 --- a/user/screen.h +++ b/user/screen.h @@ -172,10 +172,18 @@ void screen_set_fg(Color color); /** Set cursor background coloor */ void screen_set_bg(Color color); -// enable or disable attrs by bitmask +/** 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); +/** Toggle application keypad mode */ +void screen_set_keypad_application_mode(bool app_mode); +/** Toggle application cursor mode */ +void screen_set_cursor_application_mode(bool app_mode); void screen_set_charset_n(int Gx); void screen_set_charset(int Gx, char charset);