Several terminal fixes.

This commit is contained in:
Scott Duensing 2026-03-11 20:32:13 -05:00
parent 3cc942a4d4
commit eeb6541af3
4 changed files with 225 additions and 142 deletions

View file

@ -845,12 +845,6 @@ static void pollKeyboard(AppContextT *ctx) {
int32_t scancode = (r.x.ax >> 8) & 0xFF;
int32_t ascii = r.x.ax & 0xFF;
// ESC = quit
if (ascii == 0x1B) {
dvxQuit(ctx);
return;
}
// Send to focused window
if (ctx->stack.focusedIdx >= 0) {
WindowT *win = ctx->stack.windows[ctx->stack.focusedIdx];

View file

@ -10,70 +10,70 @@
// ============================================================
static const uint8_t font8x14[256 * 14] = {
// Char 0: NULL (empty box)
0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD, 0x99, 0x81, 0x7E, 0x00, 0x00, 0x00,
// Char 1: Smiley (filled)
0x00, 0x00, 0x7E, 0xFF, 0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E, 0x00, 0x00, 0x00,
// Char 2: Smiley (outline) / filled hearts
0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
// Char 3: Heart
0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
// Char 4: Diamond
0x00, 0x00, 0x18, 0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00,
// Char 5: Club
0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00,
// Char 6: Spade
0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 7: Bullet (inverse)
0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
// Char 8: Circle (outline)
0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 9: Circle (inverse)
0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
// Char 10: Male sign
0x00, 0x00, 0x1E, 0x0E, 0x1A, 0x32, 0x78, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00,
// Char 11: Female sign
0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00,
// Char 12: Note single
0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00,
// Char 13: Note double
0x00, 0x00, 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00,
// Char 14: Sun
0x00, 0x00, 0x18, 0xDB, 0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 15: Right triangle
0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00,
// Char 16: Left triangle
0x00, 0x00, 0x02, 0x06, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00,
// Char 17: Up-down arrow
0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
// Char 18: Double exclamation
0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
// Char 19: Paragraph
0x00, 0x00, 0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00,
// Char 20: Section
0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0x6C, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00,
// Char 21: Bottom bar
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00,
// Char 22: Up-down arrow with base
0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00,
// Char 23: Up arrow
0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
// Char 24: Down arrow
0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
// Char 25: Right arrow
0x00, 0x00, 0x00, 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 26: Left arrow
0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 27: Right angle
0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 28: Left-right arrow
0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 29: Up triangle
0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00,
// Char 30: Down triangle
0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
// Char 31: (blank)
// Char 0: NULL (blank)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 1: Smiley (outline)
0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD, 0x99, 0x81, 0x7E, 0x00, 0x00, 0x00,
// Char 2: Smiley (filled)
0x00, 0x00, 0x7E, 0xFF, 0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E, 0x00, 0x00, 0x00,
// Char 3: Heart
0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
// Char 4: Diamond
0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
// Char 5: Club
0x00, 0x00, 0x18, 0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00,
// Char 6: Spade
0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00,
// Char 7: Bullet
0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 8: Inverse bullet
0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
// Char 9: Circle (outline)
0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 10: Inverse circle
0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
// Char 11: Male sign
0x00, 0x00, 0x1E, 0x0E, 0x1A, 0x32, 0x78, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00,
// Char 12: Female sign
0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00,
// Char 13: Note single
0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00,
// Char 14: Note double
0x00, 0x00, 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00,
// Char 15: Sun
0x00, 0x00, 0x18, 0xDB, 0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 16: Right triangle
0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00,
// Char 17: Left triangle
0x00, 0x00, 0x02, 0x06, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00,
// Char 18: Up-down arrow
0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
// Char 19: Double exclamation
0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
// Char 20: Paragraph
0x00, 0x00, 0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00,
// Char 21: Section
0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0x6C, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00,
// Char 22: Bottom bar
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00,
// Char 23: Up-down arrow with base
0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00,
// Char 24: Up arrow
0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
// Char 25: Down arrow
0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
// Char 26: Right arrow
0x00, 0x00, 0x00, 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 27: Left arrow
0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 28: Right angle
0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 29: Left-right arrow
0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 30: Up triangle
0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00,
// Char 31: Down triangle
0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
// Char 32: Space
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -532,70 +532,70 @@ static const uint8_t font8x14[256 * 14] = {
// ============================================================
static const uint8_t font8x16[256 * 16] = {
// Char 0: NULL (empty box)
0x00, 0x00, 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD, 0x99, 0x81, 0x7E, 0x00, 0x00, 0x00,
// Char 1: Smiley (filled)
0x00, 0x00, 0x00, 0x00, 0x7E, 0xFF, 0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E, 0x00, 0x00, 0x00,
// Char 2: Hearts
0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
// Char 3: Diamond
0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 4: Club
0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
// Char 5: Spade
0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00,
// Char 6: Bullet
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 7: Inverse bullet
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
// Char 8: Circle outline
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 9: Inverse circle
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
// Char 10: Male sign
0x00, 0x00, 0x00, 0x1E, 0x0E, 0x1A, 0x32, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00,
// Char 11: Female sign
0x00, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
// Char 12: Note single
0x00, 0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00,
// Char 13: Note double
0x00, 0x00, 0x00, 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00, 0x00,
// Char 14: Sun
0x00, 0x00, 0x00, 0x18, 0xDB, 0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 15: Right triangle
0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFE, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00,
// Char 16: Left triangle
0x00, 0x00, 0x02, 0x06, 0x0E, 0x1E, 0x3E, 0xFE, 0x3E, 0x1E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00,
// Char 17: Up-down arrow
0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
// Char 18: Double exclamation
0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
// Char 19: Paragraph
0x00, 0x00, 0x00, 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00,
// Char 20: Section
0x00, 0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00,
// Char 21: Bottom bar
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00,
// Char 22: Up-down arrow with base
0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00,
// Char 23: Up arrow
0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
// Char 24: Down arrow
0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
// Char 25: Right arrow
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 26: Left arrow
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 27: Right angle
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 28: Left-right arrow
0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 29: Up triangle (filled)
0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 30: Down triangle (filled)
0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 31: (blank)
// Char 0: NULL (blank)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 1: Smiley (outline)
0x00, 0x00, 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD, 0x99, 0x81, 0x7E, 0x00, 0x00, 0x00,
// Char 2: Smiley (filled)
0x00, 0x00, 0x00, 0x00, 0x7E, 0xFF, 0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E, 0x00, 0x00, 0x00,
// Char 3: Heart
0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
// Char 4: Diamond
0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 5: Club
0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
// Char 6: Spade
0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00,
// Char 7: Bullet
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 8: Inverse bullet
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
// Char 9: Circle outline
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 10: Inverse circle
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
// Char 11: Male sign
0x00, 0x00, 0x00, 0x1E, 0x0E, 0x1A, 0x32, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00,
// Char 12: Female sign
0x00, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
// Char 13: Note single
0x00, 0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00,
// Char 14: Note double
0x00, 0x00, 0x00, 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00, 0x00,
// Char 15: Sun
0x00, 0x00, 0x00, 0x18, 0xDB, 0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 16: Right triangle
0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFE, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00,
// Char 17: Left triangle
0x00, 0x00, 0x02, 0x06, 0x0E, 0x1E, 0x3E, 0xFE, 0x3E, 0x1E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00,
// Char 18: Up-down arrow
0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
// Char 19: Double exclamation
0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
// Char 20: Paragraph
0x00, 0x00, 0x00, 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00,
// Char 21: Section
0x00, 0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00,
// Char 22: Bottom bar
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00,
// Char 23: Up-down arrow with base
0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00,
// Char 24: Up arrow
0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
// Char 25: Down arrow
0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
// Char 26: Right arrow
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 27: Left arrow
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 28: Right angle
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 29: Left-right arrow
0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 30: Up triangle (filled)
0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 31: Down triangle (filled)
0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
// Char 32: Space
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

View file

@ -4,6 +4,8 @@
#include "dvxTypes.h"
#include <time.h>
// Forward declaration
struct AppContextT;
@ -307,6 +309,12 @@ typedef struct WidgetT {
int32_t scrollbackCount; // current number of lines stored
int32_t scrollbackHead; // write position (circular index)
int32_t scrollPos; // view position (scrollbackCount = live)
// Blink support
bool blinkVisible; // current blink phase (true = text visible)
clock_t blinkTime; // timestamp of last blink toggle
// Cursor blink
bool cursorOn; // current cursor blink phase
clock_t cursorTime; // timestamp of last cursor toggle
// Dirty tracking for fast repaint
uint32_t dirtyRows; // bitmask of rows needing repaint
int32_t lastCursorRow; // cursor row at last repaint

View file

@ -19,6 +19,15 @@
// Default attribute: light gray on black
#define ANSI_DEFAULT_ATTR 0x07
// Attribute byte: bit 7 = blink, bits 6-4 = bg (0-7), bits 3-0 = fg (0-15)
#define ATTR_BLINK_BIT 0x80
#define ATTR_BG_MASK 0x70
#define ATTR_FG_MASK 0x0F
// Blink/cursor rates in milliseconds
#define BLINK_MS 500
#define CURSOR_MS 250
// ============================================================
// CGA palette (RGB values for 16 standard colors)
// ============================================================
@ -540,7 +549,9 @@ static void ansiTermProcessByte(WidgetT *w, uint8_t ch) {
}
} else if (ch == '\a') {
// Bell — ignored
} else if (ch >= 32 || ch >= 128) {
} else {
// CP437 graphic characters (smileys, card suits, etc.)
// and all printable characters
ansiTermPutChar(w, ch);
}
break;
@ -614,8 +625,11 @@ static void ansiTermProcessSgr(WidgetT *w) {
w->as.ansiTerm.bold = true;
fg |= 8;
} else if (code == 5) {
// Blink — use bright background
// Blink — sets bit 7 of attr byte via bg bit 3
bg |= 8;
} else if (code == 25) {
// Blink off
bg &= 7;
} else if (code == 7) {
// Reverse video
uint8_t tmp = fg;
@ -632,7 +646,7 @@ static void ansiTermProcessSgr(WidgetT *w) {
fg |= 8;
}
} else if (code >= 40 && code <= 47) {
bg = (uint8_t)sAnsiToCga[code - 40];
bg = (uint8_t)(sAnsiToCga[code - 40] | (bg & 8));
} else if (code >= 90 && code <= 97) {
// Bright foreground
fg = (uint8_t)(sAnsiToCga[code - 90] | 8);
@ -793,6 +807,13 @@ WidgetT *wgtAnsiTerm(WidgetT *parent, int32_t cols, int32_t rows) {
w->as.ansiTerm.commCtx = NULL;
w->as.ansiTerm.commRead = NULL;
w->as.ansiTerm.commWrite = NULL;
w->as.ansiTerm.blinkVisible = true;
w->as.ansiTerm.blinkTime = clock();
w->as.ansiTerm.cursorOn = true;
w->as.ansiTerm.cursorTime = clock();
w->as.ansiTerm.dirtyRows = 0xFFFFFFFF;
w->as.ansiTerm.lastCursorRow = -1;
w->as.ansiTerm.lastCursorCol = -1;
memset(w->as.ansiTerm.params, 0, sizeof(w->as.ansiTerm.params));
@ -875,7 +896,49 @@ void wgtAnsiTermSetScrollback(WidgetT *w, int32_t maxLines) {
// ============================================================
int32_t wgtAnsiTermPoll(WidgetT *w) {
if (!w || w->type != WidgetAnsiTermE || !w->as.ansiTerm.commRead) {
if (!w || w->type != WidgetAnsiTermE) {
return 0;
}
// Text blink timer — toggle visibility and dirty rows with blinking cells
clock_t now = clock();
clock_t blinkInterval = (clock_t)BLINK_MS * CLOCKS_PER_SEC / 1000;
clock_t curInterval = (clock_t)CURSOR_MS * CLOCKS_PER_SEC / 1000;
if ((now - w->as.ansiTerm.blinkTime) >= blinkInterval) {
w->as.ansiTerm.blinkTime = now;
w->as.ansiTerm.blinkVisible = !w->as.ansiTerm.blinkVisible;
// Dirty any rows that contain cells with blink attribute
int32_t cols = w->as.ansiTerm.cols;
int32_t rows = w->as.ansiTerm.rows;
for (int32_t row = 0; row < rows && row < 32; row++) {
for (int32_t col = 0; col < cols; col++) {
uint8_t attr = w->as.ansiTerm.cells[(row * cols + col) * 2 + 1];
if (attr & ATTR_BLINK_BIT) {
w->as.ansiTerm.dirtyRows |= (1U << row);
break;
}
}
}
}
// Cursor blink timer
if ((now - w->as.ansiTerm.cursorTime) >= curInterval) {
w->as.ansiTerm.cursorTime = now;
w->as.ansiTerm.cursorOn = !w->as.ansiTerm.cursorOn;
int32_t cRow = w->as.ansiTerm.cursorRow;
if (cRow >= 0 && cRow < 32) {
w->as.ansiTerm.dirtyRows |= (1U << cRow);
}
}
// Read from comm
if (!w->as.ansiTerm.commRead) {
return 0;
}
@ -977,10 +1040,15 @@ int32_t wgtAnsiTermRepaint(WidgetT *w) {
uint8_t ch = lineData[col * 2];
uint8_t attr = lineData[col * 2 + 1];
uint32_t fg = palette[attr & 0x0F];
uint32_t bg = palette[(attr >> 4) & 0x0F];
uint32_t fg = palette[attr & ATTR_FG_MASK];
uint32_t bg = palette[(attr >> 4) & 0x07];
if (viewingLive && w->as.ansiTerm.cursorVisible && w->focused &&
// Blink: hide text during off phase
if ((attr & ATTR_BLINK_BIT) && !w->as.ansiTerm.blinkVisible) {
fg = bg;
}
if (viewingLive && w->as.ansiTerm.cursorVisible && w->as.ansiTerm.cursorOn &&
row == w->as.ansiTerm.cursorRow && col == w->as.ansiTerm.cursorCol) {
uint32_t tmp = fg;
fg = bg;
@ -1062,6 +1130,14 @@ void widgetAnsiTermOnKey(WidgetT *w, int32_t key) {
// Printable ASCII
buf[0] = (uint8_t)key;
len = 1;
} else if (key == 0x1B) {
// Escape
buf[0] = 0x1B;
len = 1;
} else if (key == 0x09) {
// Tab
buf[0] = 0x09;
len = 1;
} else if (key == 13 || key == 10) {
// Enter
buf[0] = '\r';
@ -1232,11 +1308,16 @@ void widgetAnsiTermPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const Bit
uint8_t ch = lineData[col * 2];
uint8_t attr = lineData[col * 2 + 1];
uint32_t fg = palette[attr & 0x0F];
uint32_t bg = palette[(attr >> 4) & 0x0F];
uint32_t fg = palette[attr & ATTR_FG_MASK];
uint32_t bg = palette[(attr >> 4) & 0x07];
// Blink: hide text during off phase
if ((attr & ATTR_BLINK_BIT) && !w->as.ansiTerm.blinkVisible) {
fg = bg;
}
// Draw cursor as inverse block (only when viewing live terminal)
if (viewingLive && w->as.ansiTerm.cursorVisible && w->focused &&
if (viewingLive && w->as.ansiTerm.cursorVisible && w->as.ansiTerm.cursorOn &&
row == w->as.ansiTerm.cursorRow && col == w->as.ansiTerm.cursorCol) {
uint32_t tmp = fg;
fg = bg;