feat: switch text to UTF-8; add Unicode key events, dead keys & Czech layout; fix numpad navigation; add NumLock support
This commit is contained in:
1 parent
32660ddd1a
commit
2aa6360b3d
101 files changed
+3733
-1639
No files matched your search
@@ -9,13 +9,14 @@
|
||||
#include "gui/font.hpp"
|
||||
#include <montauk/syscall.h>
|
||||
#include <montauk/string.h>
|
||||
#include <montauk/utf8.h>
|
||||
#include <Api/Syscall.hpp>
|
||||
#include <montauk/capabilities.h>
|
||||
|
||||
namespace gui {
|
||||
|
||||
struct TermCell {
|
||||
char ch;
|
||||
uint32_t ch; // Unicode codepoint (every cell is one column wide)
|
||||
Color fg;
|
||||
Color bg;
|
||||
};
|
||||
@@ -58,6 +59,11 @@ struct TerminalState {
|
||||
int csi_params[8];
|
||||
int csi_param_count;
|
||||
int csi_current_param;
|
||||
|
||||
// Partial UTF-8 sequence carried across terminal_feed calls (child output
|
||||
// arrives in arbitrary chunks, so a character can straddle two reads).
|
||||
char utf8_pending[4];
|
||||
int utf8_pending_len;
|
||||
};
|
||||
|
||||
// ==== Palette ====
|
||||
@@ -244,6 +250,7 @@ static inline void terminal_init_cells(TerminalState* t, int cols, int rows, int
|
||||
t->csi_private = false;
|
||||
t->csi_param_count = 0;
|
||||
t->csi_current_param = 0;
|
||||
t->utf8_pending_len = 0;
|
||||
t->child_pid = 0;
|
||||
|
||||
int total_cells = (rows + max_sb) * cols;
|
||||
@@ -275,7 +282,7 @@ static inline void terminal_init(TerminalState* t, int cols, int rows) {
|
||||
montauk::childio_settermsz(t->child_pid, cols, rows);
|
||||
}
|
||||
|
||||
static inline void terminal_put_char(TerminalState* t, char ch) {
|
||||
static inline void terminal_put_char(TerminalState* t, uint32_t ch) {
|
||||
if (t->cursor_x >= t->cols) {
|
||||
t->cursor_x = 0;
|
||||
t->cursor_y++;
|
||||
@@ -549,11 +556,61 @@ static inline void terminal_process_csi(TerminalState* t, char cmd) {
|
||||
}
|
||||
}
|
||||
|
||||
// Emit pending bytes that did not form a valid UTF-8 sequence: each one is a
|
||||
// Windows-1252 character, matching how the GUI renders legacy text.
|
||||
static inline void terminal_flush_utf8(TerminalState* t) {
|
||||
for (int i = 0; i < t->utf8_pending_len; i++)
|
||||
terminal_put_char(t, montauk::utf8::from_cp1252((uint8_t)t->utf8_pending[i]));
|
||||
t->utf8_pending_len = 0;
|
||||
}
|
||||
|
||||
static inline int terminal_utf8_expected(uint8_t lead) {
|
||||
if (lead >= 0xC2 && lead <= 0xDF) return 2;
|
||||
if (lead >= 0xE0 && lead <= 0xEF) return 3;
|
||||
if (lead >= 0xF0 && lead <= 0xF4) return 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Feed one byte >= 0x80 of printable text through the UTF-8 assembler.
|
||||
static inline void terminal_feed_high(TerminalState* t, uint8_t b) {
|
||||
if (t->utf8_pending_len > 0) {
|
||||
if ((b & 0xC0) == 0x80) {
|
||||
t->utf8_pending[t->utf8_pending_len++] = (char)b;
|
||||
int want = terminal_utf8_expected((uint8_t)t->utf8_pending[0]);
|
||||
uint32_t cp = 0;
|
||||
int n = montauk::utf8::sequence_length(t->utf8_pending,
|
||||
t->utf8_pending_len, &cp);
|
||||
if (n == want) {
|
||||
terminal_put_char(t, cp);
|
||||
t->utf8_pending_len = 0;
|
||||
} else if (t->utf8_pending_len >= want) {
|
||||
terminal_flush_utf8(t); // overlong / surrogate / out of range
|
||||
}
|
||||
return;
|
||||
}
|
||||
terminal_flush_utf8(t);
|
||||
}
|
||||
if (terminal_utf8_expected(b)) {
|
||||
t->utf8_pending[0] = (char)b;
|
||||
t->utf8_pending_len = 1;
|
||||
} else {
|
||||
terminal_put_char(t, montauk::utf8::from_cp1252(b));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void terminal_feed(TerminalState* t, const char* data, int len) {
|
||||
if (len > 0) t->dirty = true;
|
||||
for (int i = 0; i < len; i++) {
|
||||
char ch = data[i];
|
||||
|
||||
if (t->parse_state == TerminalState::STATE_NORMAL) {
|
||||
if ((uint8_t)ch >= 0x80) {
|
||||
terminal_feed_high(t, (uint8_t)ch);
|
||||
continue;
|
||||
}
|
||||
if (t->utf8_pending_len > 0) terminal_flush_utf8(t);
|
||||
}
|
||||
|
||||
switch (t->parse_state) {
|
||||
case TerminalState::STATE_NORMAL:
|
||||
if (ch == '\033') {
|
||||
@@ -575,9 +632,8 @@ static inline void terminal_feed(TerminalState* t, const char* data, int len) {
|
||||
while (t->cursor_x < next) {
|
||||
terminal_put_char(t, ' ');
|
||||
}
|
||||
} else if (ch >= 32 || ch < 0) {
|
||||
// Printable character (also treat high-bit chars as printable)
|
||||
terminal_put_char(t, ch);
|
||||
} else if (ch >= 32) {
|
||||
terminal_put_char(t, (uint8_t)ch);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -641,9 +697,9 @@ static inline void terminal_fill_pixel_rect(uint32_t* pixels, int pw, int ph,
|
||||
}
|
||||
|
||||
static inline void terminal_draw_bitmap_char(uint32_t* pixels, int pw, int ph,
|
||||
int x, int y, unsigned char ch,
|
||||
int x, int y, uint32_t ch,
|
||||
uint32_t color) {
|
||||
const uint8_t* glyph = &font_data[ch * FONT_HEIGHT];
|
||||
const uint8_t* glyph = &font_data[cp437_index(ch) * FONT_HEIGHT];
|
||||
for (int fy = 0; fy < FONT_HEIGHT; fy++) {
|
||||
int dy = y + fy;
|
||||
if (dy >= ph) break;
|
||||
@@ -669,14 +725,14 @@ static inline void terminal_draw_cell_pixels(const TermCell& cell,
|
||||
cell.bg.to_pixel());
|
||||
}
|
||||
|
||||
if (cell.ch <= 32 && cell.ch >= 0) return;
|
||||
if (cell.ch <= 32) return;
|
||||
|
||||
if (use_ttf) {
|
||||
int baseline = py + gc->ascent;
|
||||
fonts::mono->draw_char_to_buffer(pixels, pw, ph,
|
||||
px, baseline, (unsigned char)cell.ch, cell.fg, gc);
|
||||
px, baseline, (int)cell.ch, cell.fg, gc);
|
||||
} else {
|
||||
terminal_draw_bitmap_char(pixels, pw, ph, px, py, (unsigned char)cell.ch,
|
||||
terminal_draw_bitmap_char(pixels, pw, ph, px, py, cell.ch,
|
||||
cell.fg.to_pixel());
|
||||
}
|
||||
}
|
||||
@@ -691,14 +747,14 @@ static inline void terminal_draw_cursor_pixels(const TermCell& cell,
|
||||
terminal_fill_pixel_rect(pixels, pw, ph, px, py, cell_w, cell_h,
|
||||
g_term_palette.cursor.to_pixel());
|
||||
|
||||
if (cell.ch <= 32 && cell.ch >= 0) return;
|
||||
if (cell.ch <= 32) return;
|
||||
|
||||
if (use_ttf) {
|
||||
int baseline = py + gc->ascent;
|
||||
fonts::mono->draw_char_to_buffer(pixels, pw, ph,
|
||||
px, baseline, (unsigned char)cell.ch, g_term_palette.bg, gc);
|
||||
px, baseline, (int)cell.ch, g_term_palette.bg, gc);
|
||||
} else {
|
||||
terminal_draw_bitmap_char(pixels, pw, ph, px, py, (unsigned char)cell.ch,
|
||||
terminal_draw_bitmap_char(pixels, pw, ph, px, py, cell.ch,
|
||||
g_term_palette.bg.to_pixel());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user