From 2aa6360b3dc3026707c827c32ebfd24cbee040d3 Mon Sep 17 00:00:00 2001 From: Daniel Hammer Date: Sat, 3 Oct 2026 10:11:49 +0200 Subject: [PATCH] feat: switch text to UTF-8; add Unicode key events, dead keys & Czech layout; fix numpad navigation; add NumLock support --- kernel/src/Api/BuildNo.hpp | 2 +- kernel/src/Api/IoRedir.hpp | 23 +- kernel/src/Api/Keyboard.hpp | 159 ++++++- kernel/src/Api/Syscall.cpp | 16 +- kernel/src/Api/Syscall.hpp | 40 +- kernel/src/Drivers/PS2/Keyboard.cpp | 14 + kernel/src/Drivers/PS2/Keyboard.hpp | 10 + kernel/src/Drivers/USB/HidKeyboard.cpp | 16 +- kernel/src/Fs/Fat32.cpp | 108 ++++- kernel/src/Sched/Scheduler.cpp | 7 + kernel/src/Sched/Scheduler.hpp | 6 +- programs/data/osdata/keyboard-layouts.toml | 55 ++- programs/include/Api/Syscall.hpp | 40 +- programs/include/gui/canvas.hpp | 4 +- programs/include/gui/clipboard.hpp | 28 ++ programs/include/gui/font.hpp | 47 ++- programs/include/gui/mtk/widgets.hpp | 104 +++-- programs/include/gui/terminal.hpp | 82 +++- programs/include/gui/truetype.hpp | 164 ++++--- programs/include/gui/widgets.hpp | 51 ++- programs/include/libc/montauk.h | 390 ++++++++--------- programs/include/montauk/keyboard.h | 268 +++++++++--- programs/include/montauk/statuscodes.h | 29 +- programs/include/montauk/syscall.h | 22 +- programs/include/montauk/user.h | 23 +- programs/include/montauk/utf8.h | 399 ++++++++++++++++++ programs/lib/libc/libc.c | 19 +- programs/src/2048/main.cpp | 8 +- programs/src/audio/main.cpp | 4 +- programs/src/bluetooth/main.cpp | 2 + programs/src/capabilities/main.cpp | 5 +- programs/src/charmap/main.cpp | 354 +++++++++------- programs/src/crashpad/main.cpp | 4 +- .../src/desktop/apps/filemanager/events.cpp | 98 ++--- .../desktop/apps/filemanager/properties.cpp | 4 +- .../src/desktop/apps/filemanager/render.cpp | 21 +- programs/src/desktop/apps/settings/about.cpp | 2 +- programs/src/desktop/compose.cpp | 2 +- programs/src/desktop/consent.cpp | 6 +- programs/src/desktop/input.cpp | 16 +- programs/src/desktop/launcher.cpp | 17 +- programs/src/devexplorer/main.cpp | 8 +- programs/src/dialogs/filedialog.cpp | 11 +- programs/src/dialogs/messagebox.cpp | 3 +- programs/src/dialogs/printdialog.cpp | 4 +- programs/src/disks/main.cpp | 12 +- programs/src/disks/render.cpp | 2 + programs/src/display/main.cpp | 1 + programs/src/edit/main.cpp | 115 +++-- programs/src/fontpreview/main.cpp | 12 +- programs/src/imageviewer/main.cpp | 10 +- programs/src/installer/main.cpp | 4 +- programs/src/installer/render.cpp | 2 + programs/src/irc/main.cpp | 27 +- programs/src/keyboard/main.cpp | 22 +- programs/src/man/main.cpp | 2 +- programs/src/music/main.cpp | 37 +- programs/src/network/main.cpp | 5 +- programs/src/pdfviewer/main.cpp | 42 +- programs/src/pdfviewer/render.cpp | 4 +- programs/src/printd/test_page_jpeg.cpp | 14 +- programs/src/printers/main.cpp | 9 +- programs/src/procmgr/main.cpp | 12 +- programs/src/shell/main.cpp | 27 +- programs/src/shell/shell.h | 1 + programs/src/spreadsheet/main.cpp | 86 ++-- programs/src/sshd/main.cpp | 15 +- programs/src/tcpconnect/main.cpp | 14 +- programs/src/terminal/settings.cpp | 4 +- programs/src/texteditor/main.cpp | 161 +++---- programs/src/timezone/main.cpp | 15 +- programs/src/video/main.cpp | 6 +- programs/src/weather/main.cpp | 6 +- programs/src/wiki/main.cpp | 34 +- programs/src/wikipedia/main.cpp | 2 +- programs/src/wikipedia/text.cpp | 89 ++-- programs/src/wikipedia/wikipedia.h | 2 +- programs/src/wordprocessor/document.cpp | 2 +- programs/src/wordprocessor/input.cpp | 90 ++-- programs/src/wordprocessor/print_export.cpp | 5 +- programs/src/wordprocessor/render.cpp | 21 +- programs/src/wordprocessor/wordprocessor.hpp | 4 + template/sysroot/include/Api/Syscall.hpp | 40 +- template/sysroot/include/gui/canvas.hpp | 4 +- template/sysroot/include/gui/clipboard.hpp | 28 ++ template/sysroot/include/gui/desktop.hpp | 12 + template/sysroot/include/gui/font.hpp | 47 ++- template/sysroot/include/gui/mtk/widgets.hpp | 104 +++-- template/sysroot/include/gui/terminal.hpp | 82 +++- template/sysroot/include/gui/truetype.hpp | 164 ++++--- template/sysroot/include/gui/widgets.hpp | 51 ++- template/sysroot/include/libc/montauk.h | 390 ++++++++--------- template/sysroot/include/montauk/keyboard.h | 268 +++++++++--- .../sysroot/include/montauk/statuscodes.h | 91 +++- template/sysroot/include/montauk/syscall.h | 22 +- template/sysroot/include/montauk/user.h | 23 +- template/sysroot/include/montauk/utf8.h | 399 ++++++++++++++++++ template/sysroot/include/rtlsdr/rtlsdr.h | 36 -- template/sysroot/lib/libjpeg.a | Bin 330174 -> 330174 bytes template/sysroot/lib/liblibc.a | Bin 677502 -> 677558 bytes template/sysroot/lib/libtls.a | Bin 114598 -> 114598 bytes 101 files changed, 3733 insertions(+), 1639 deletions(-) create mode 100644 programs/include/montauk/utf8.h create mode 100644 template/sysroot/include/montauk/utf8.h delete mode 100644 template/sysroot/include/rtlsdr/rtlsdr.h diff --git a/kernel/src/Api/BuildNo.hpp b/kernel/src/Api/BuildNo.hpp index 9524fa8..dedc3a5 100644 --- a/kernel/src/Api/BuildNo.hpp +++ b/kernel/src/Api/BuildNo.hpp @@ -12,4 +12,4 @@ #pragma once -#define MONTAUK_BUILD_NUMBER 289 +#define MONTAUK_BUILD_NUMBER 296 diff --git a/kernel/src/Api/IoRedir.hpp b/kernel/src/Api/IoRedir.hpp index 6974e95..4195b0f 100644 --- a/kernel/src/Api/IoRedir.hpp +++ b/kernel/src/Api/IoRedir.hpp @@ -122,8 +122,9 @@ namespace montauk::abi { return WriteAllToStream(stream, (const uint8_t*)data, len); } - static int Sys_ChildIoWriteKey(int childPid, const KeyEvent* key) { - if (key == nullptr) return InvalidArgument; + // Queue a key event (raw bytes, `len` of them) on a redirected child's key + // mailbox. Readers accept both the 9-byte legacy and the full format. + static int ChildIoQueueKey(int childPid, const void* key, uint16_t len) { auto* child = Sched::GetProcessByPid(childPid); if (child == nullptr || child->parentPid != Sched::GetCurrentPid()) return PermissionDenied; @@ -133,7 +134,7 @@ namespace montauk::abi { for (;;) { uint64_t observedWake = Sched::ObserveObjectWake(mailbox); - int rc = Ipc::MailboxSend(mailbox, 0, key, sizeof(KeyEvent)); + int rc = Ipc::MailboxSend(mailbox, 0, key, len); if (rc < 0) return GenericFailure; if (rc == 0) { Sched::BlockOnObjectSince(mailbox, 0, observedWake); @@ -143,6 +144,22 @@ namespace montauk::abi { } } + static int Sys_ChildIoWriteKey(int childPid, const KeyEventV1* key) { + if (key == nullptr) return InvalidArgument; + KeyEventV1 copy = *key; + return ChildIoQueueKey(childPid, ©, sizeof(copy)); + } + + // Size-versioned: copies min(size, sizeof(KeyEvent)) bytes (validated + // readable by the dispatcher) and zero-fills the rest. + static int Sys_ChildIoWriteKeyEx(int childPid, const void* key, uint64_t size) { + if (key == nullptr || size < sizeof(KeyEventV1)) return InvalidArgument; + KeyEvent ev; + memset(&ev, 0, sizeof(ev)); + memcpy(&ev, key, size < sizeof(ev) ? size : sizeof(ev)); + return ChildIoQueueKey(childPid, &ev, sizeof(ev)); + } + static int Sys_ChildIoSetTermsz(int childPid, int cols, int rows) { auto* child = Sched::GetProcessByPid(childPid); if (child == nullptr || child->parentPid != Sched::GetCurrentPid()) diff --git a/kernel/src/Api/Keyboard.hpp b/kernel/src/Api/Keyboard.hpp index 989fbb8..8ad38dc 100644 --- a/kernel/src/Api/Keyboard.hpp +++ b/kernel/src/Api/Keyboard.hpp @@ -12,6 +12,107 @@ #include "Common.hpp" namespace montauk::abi { + // ---- Key text ---------------------------------------------------------- + // Keyboard layouts are applied in userspace (desktop, terminal), which send + // KeyEvents carrying the Unicode codepoint. Binaries built before that send + // 9-byte KeyEventV1s whose `ascii` is a Windows-1252 byte; both kinds share + // a redirected child's key mailbox, told apart by message length. + + static uint32_t KeyCp1252ToUnicode(uint8_t b) { + static constexpr uint16_t high[32] = { + 0x20AC, 0x81, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x8D, 0x017D, 0x8F, + 0x90, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x9D, 0x017E, 0x0178, + }; + return (b >= 0x80 && b <= 0x9F) ? high[b - 0x80] : b; + } + + // The character a key event types, or 0 for control/navigation keys. + static uint32_t KeyTextCodepoint(const KeyEvent& ev) { + if (ev.codepoint) return ev.codepoint; + uint8_t b = (uint8_t)ev.ascii; + if (b < 0x20 || b == 0x7F) return 0; + return KeyCp1252ToUnicode(b); + } + + static int KeyEncodeUtf8(uint32_t cp, uint8_t* out) { + if (cp > 0x10FFFF || (cp >= 0xD800 && cp <= 0xDFFF)) cp = 0xFFFD; + if (cp < 0x80) { out[0] = (uint8_t)cp; return 1; } + if (cp < 0x800) { + out[0] = (uint8_t)(0xC0 | (cp >> 6)); + out[1] = (uint8_t)(0x80 | (cp & 0x3F)); + return 2; + } + if (cp < 0x10000) { + out[0] = (uint8_t)(0xE0 | (cp >> 12)); + out[1] = (uint8_t)(0x80 | ((cp >> 6) & 0x3F)); + out[2] = (uint8_t)(0x80 | (cp & 0x3F)); + return 3; + } + out[0] = (uint8_t)(0xF0 | (cp >> 18)); + out[1] = (uint8_t)(0x80 | ((cp >> 12) & 0x3F)); + out[2] = (uint8_t)(0x80 | ((cp >> 6) & 0x3F)); + out[3] = (uint8_t)(0x80 | (cp & 0x3F)); + return 4; + } + + static void KeyFromDriver(const Drivers::PS2::Keyboard::KeyEvent& k, KeyEvent* out) { + memset(out, 0, sizeof(KeyEvent)); + out->scancode = k.Scancode; + out->ascii = k.Ascii; + out->pressed = k.Pressed; + out->shift = k.Shift; + out->ctrl = k.Ctrl; + out->alt = k.Alt; + out->capslock = k.CapsLock; + out->altgr = k.AltGr; + out->extended = k.Extended; + // The kernel's own scancode table is US ASCII. + uint8_t a = (uint8_t)k.Ascii; + out->codepoint = (a >= 0x20 && a < 0x7F) ? a : 0; + } + + // Receive one key from a redirected child's mailbox as a full KeyEvent, + // upgrading legacy 9-byte messages. Returns MailboxRecv's result. + static int KeyMailboxRecv(Ipc::Mailbox* mailbox, KeyEvent* out) { + memset(out, 0, sizeof(KeyEvent)); + uint16_t len = sizeof(KeyEvent); + int rc = Ipc::MailboxRecv(mailbox, nullptr, out, &len, true); + if (rc > 0 && len < sizeof(KeyEvent)) { + memset((uint8_t*)out + len, 0, sizeof(KeyEvent) - len); + out->codepoint = KeyTextCodepoint(*out); + } + return rc; + } + + // Turn a pressed key into the next getchar byte. Characters above ASCII are + // returned as UTF-8, one byte per call; the rest is parked in the process. + static bool KeyTakeChar(Sched::Process* proc, const KeyEvent& ev, char* out) { + if (!ev.pressed) return false; + uint32_t cp = KeyTextCodepoint(ev); + if (cp >= 0x80 && proc != nullptr) { + int n = KeyEncodeUtf8(cp, proc->getcharUtf8); + proc->getcharUtf8Len = (uint8_t)n; + proc->getcharUtf8Pos = 1; + *out = (char)proc->getcharUtf8[0]; + return true; + } + if (ev.ascii != 0 && ev.ascii != KEY_ASCII_SUBSTITUTE) { + *out = ev.ascii; + return true; + } + return false; + } + + static bool KeyPendingChar(Sched::Process* proc, char* out) { + if (proc == nullptr || proc->getcharUtf8Pos >= proc->getcharUtf8Len) return false; + *out = (char)proc->getcharUtf8[proc->getcharUtf8Pos++]; + return true; + } + + // ---- Syscalls ------------------------------------------------------------ + static bool Sys_IsKeyAvailable() { auto* proc = Sched::GetCurrentProcessPtr(); if (proc && proc->redirected) { @@ -27,8 +128,8 @@ namespace montauk::abi { return Drivers::PS2::Keyboard::IsKeyAvailable(); } - static void Sys_GetKey(KeyEvent* outEvent) { - if (outEvent == nullptr) return; + // Blocking read of the next key event, in the full format. + static void ReadKeyEvent(KeyEvent* outEvent) { auto* proc = Sched::GetCurrentProcessPtr(); if (proc && proc->redirected) { Ipc::HandleSnapshot snapshot; @@ -36,8 +137,7 @@ namespace montauk::abi { if (mailbox != nullptr) { for (;;) { uint64_t observedWake = Sched::ObserveObjectWake(mailbox); - uint16_t len = sizeof(KeyEvent); - int rc = Ipc::MailboxRecv(mailbox, nullptr, outEvent, &len, true); + int rc = KeyMailboxRecv(mailbox, outEvent); if (rc > 0) return; if (rc < 0) { memset(outEvent, 0, sizeof(KeyEvent)); @@ -47,20 +147,33 @@ namespace montauk::abi { } } } - auto k = Drivers::PS2::Keyboard::GetKey(); - outEvent->scancode = k.Scancode; - outEvent->ascii = k.Ascii; - outEvent->pressed = k.Pressed; - outEvent->shift = k.Shift; - outEvent->ctrl = k.Ctrl; - outEvent->alt = k.Alt; - outEvent->capslock = k.CapsLock; - outEvent->altgr = k.AltGr; - outEvent->extended = k.Extended; + KeyFromDriver(Drivers::PS2::Keyboard::GetKey(), outEvent); + } + + // SYS_GETKEY: legacy 9-byte event. A new-format event's first 9 bytes are + // already a valid KeyEventV1 (ascii holds the 1252 byte or SUB). + static void Sys_GetKey(KeyEventV1* outEvent) { + if (outEvent == nullptr) return; + KeyEvent ev; + ReadKeyEvent(&ev); + memcpy(outEvent, &ev, sizeof(KeyEventV1)); + } + + // SYS_GETKEY_EX: size-versioned. The caller's size was validated by the + // dispatcher (>= sizeof(KeyEventV1), writable). + static int Sys_GetKeyEx(void* outEvent, uint64_t size) { + KeyEvent ev; + ReadKeyEvent(&ev); + uint64_t n = size < sizeof(KeyEvent) ? size : sizeof(KeyEvent); + memcpy(outEvent, &ev, n); + if (size > n) memset((uint8_t*)outEvent + n, 0, size - n); + return Success; } static char Sys_GetChar() { auto* proc = Sched::GetCurrentProcessPtr(); + char pending; + if (KeyPendingChar(proc, &pending)) return pending; if (proc && proc->redirected) { Ipc::HandleSnapshot inputSnapshot; Ipc::HandleSnapshot mailboxSnapshot; @@ -78,11 +191,11 @@ namespace montauk::abi { } if (mailbox != nullptr) { - KeyEvent ev{}; - uint16_t len = sizeof(ev); - int rc = Ipc::MailboxRecv(mailbox, nullptr, &ev, &len, true); + KeyEvent ev; + int rc = KeyMailboxRecv(mailbox, &ev); if (rc > 0) { - if (ev.pressed && ev.ascii != 0) return ev.ascii; + char c; + if (KeyTakeChar(proc, ev, &c)) return c; continue; } if (rc < 0 && input == nullptr) return 0; @@ -115,6 +228,8 @@ namespace montauk::abi { */ static char Sys_GetCharNb() { auto* proc = Sched::GetCurrentProcessPtr(); + char pending; + if (KeyPendingChar(proc, &pending)) return pending; if (proc && proc->redirected) { Ipc::HandleSnapshot inputSnapshot; Ipc::HandleSnapshot mailboxSnapshot; @@ -127,10 +242,10 @@ namespace montauk::abi { } while (mailbox != nullptr) { - KeyEvent ev{}; - uint16_t len = sizeof(ev); - if (Ipc::MailboxRecv(mailbox, nullptr, &ev, &len, true) <= 0) break; - if (ev.pressed && ev.ascii != 0) return ev.ascii; + KeyEvent ev; + if (KeyMailboxRecv(mailbox, &ev) <= 0) break; + char c; + if (KeyTakeChar(proc, ev, &c)) return c; } return 0; } diff --git a/kernel/src/Api/Syscall.cpp b/kernel/src/Api/Syscall.cpp index c5433af..581ee2e 100644 --- a/kernel/src/Api/Syscall.cpp +++ b/kernel/src/Api/Syscall.cpp @@ -139,8 +139,8 @@ namespace montauk::abi { case SYS_ISKEYAVAILABLE: return (int64_t)Sys_IsKeyAvailable(); case SYS_GETKEY: - if (!UserMemory::Writable(frame->arg1)) return BadPointer; - Sys_GetKey((KeyEvent*)frame->arg1); + if (!UserMemory::Writable(frame->arg1)) return BadPointer; + Sys_GetKey((KeyEventV1*)frame->arg1); return Success; case SYS_GETCHAR: return (int64_t)Sys_GetChar(); @@ -365,8 +365,8 @@ namespace montauk::abi { if (!UserMemory::Range(frame->arg2, (uint64_t)frame->arg3, false)) return BadPointer; return (int64_t)Sys_ChildIoWrite((int)frame->arg1, (const char*)frame->arg2, (int)frame->arg3); case SYS_CHILDIO_WRITEKEY: - if (!UserMemory::Readable(frame->arg2)) return BadPointer; - return (int64_t)Sys_ChildIoWriteKey((int)frame->arg1, (const KeyEvent*)frame->arg2); + if (!UserMemory::Readable(frame->arg2)) return BadPointer; + return (int64_t)Sys_ChildIoWriteKey((int)frame->arg1, (const KeyEventV1*)frame->arg2); case SYS_CHILDIO_SETTERMSZ: return (int64_t)Sys_ChildIoSetTermsz((int)frame->arg1, (int)frame->arg2, (int)frame->arg3); case SYS_WINCREATE: @@ -527,6 +527,14 @@ namespace montauk::abi { return Sched::Consent::Next((ConsentRequest*)frame->arg1); case SYS_CONSENT_REPLY: return Sched::Consent::Reply(frame->arg1, (int)frame->arg2); + case SYS_GETKEY_EX: + if (frame->arg2 < sizeof(KeyEventV1) || frame->arg2 > 4096) return InvalidArgument; + if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return BadPointer; + return Sys_GetKeyEx((void*)frame->arg1, frame->arg2); + case SYS_CHILDIO_WRITEKEY_EX: + if (frame->arg3 < sizeof(KeyEventV1) || frame->arg3 > 4096) return InvalidArgument; + if (!UserMemory::Range(frame->arg2, frame->arg3, false)) return BadPointer; + return (int64_t)Sys_ChildIoWriteKeyEx((int)frame->arg1, (const void*)frame->arg2, frame->arg3); case SYS_THREAD_SPAWN: return Sys_ThreadSpawn(frame->arg1, frame->arg2, frame->arg3); case SYS_THREAD_EXIT: diff --git a/kernel/src/Api/Syscall.hpp b/kernel/src/Api/Syscall.hpp index 3306415..5cefc5e 100644 --- a/kernel/src/Api/Syscall.hpp +++ b/kernel/src/Api/Syscall.hpp @@ -358,6 +358,12 @@ namespace montauk::abi { static constexpr uint64_t SYS_CONSENT_NEXT = 192; // (ConsentRequest*) -> 1 delivered, 0 none queued static constexpr uint64_t SYS_CONSENT_REPLY = 193; // (requestId, CONSENT_ALLOW/DENY) -> 0, -1 stale id + /* Unicode key events. Size-versioned: the caller passes sizeof(its + KeyEvent); the kernel copies min(size, its own) bytes and zero-fills the + rest, so the struct can grow without another syscall. */ + static constexpr uint64_t SYS_GETKEY_EX = 194; // (KeyEvent*, size) -> 0; blocks like SYS_GETKEY + static constexpr uint64_t SYS_CHILDIO_WRITEKEY_EX = 195; // (childPid, const KeyEvent*, size) -> status + /* Kernel-owned process capabilities. User identities may namespace per-user resources, but never participate in authorization decisions. */ static constexpr uint64_t CAP_PROCESS_ADMIN = 1ULL << 0; @@ -600,7 +606,10 @@ namespace montauk::abi { uint64_t txPackets; }; - struct KeyEvent { + // Legacy 9-byte key event, read by SYS_GETKEY and written by + // SYS_CHILDIO_WRITEKEY. Kept so binaries built before codepoints still work. + // `ascii` is a Windows-1252 byte. + struct KeyEventV1 { uint8_t scancode; char ascii; bool pressed; @@ -616,6 +625,32 @@ namespace montauk::abi { bool extended; }; + // Key event with the Unicode text it types (SYS_GETKEY_EX, + // SYS_CHILDIO_WRITEKEY_EX, WinEvent). Its first 9 bytes ARE a KeyEventV1, so + // a legacy reader sees a valid event. `codepoint` is the character the key + // produces (0 for control/navigation keys and dead keys). `ascii` is its + // Windows-1252 byte, or KEY_ASCII_SUBSTITUTE when 1252 has none. + struct KeyEvent { + uint8_t scancode; + char ascii; + bool pressed; + bool shift; + bool ctrl; + bool alt; + bool capslock; + bool altgr; + bool extended; + uint8_t _reserved[3]; + uint32_t codepoint; + }; + static_assert(sizeof(KeyEventV1) == 9, "KeyEventV1 is frozen ABI"); + static_assert(sizeof(KeyEvent) == 16, "KeyEvent must fit the WinEvent union"); + + // ASCII SUB: `ascii` of a text key whose character has no Windows-1252 byte. + // A control character, so legacy code that only accepts ascii >= 0x20 skips + // it, while code testing `ascii == 0` for navigation keys is not confused. + static constexpr char KEY_ASCII_SUBSTITUTE = 0x1A; + struct MouseState { int32_t x; int32_t y; @@ -653,12 +688,13 @@ namespace montauk::abi { uint8_t type; // 0=key, 1=mouse, 2=resize, 3=close, 4=scale uint8_t _pad[3]; union { - KeyEvent key; + KeyEvent key; // 16 bytes: the union was already that size (mouse) struct { int32_t x, y, scroll; uint8_t buttons, prev_buttons; } mouse; struct { int32_t w, h; } resize; struct { int32_t scale; } scale; }; }; + static_assert(sizeof(WinEvent) == 20, "WinEvent layout is shared with existing binaries"); struct WinInfo { int32_t id; diff --git a/kernel/src/Drivers/PS2/Keyboard.cpp b/kernel/src/Drivers/PS2/Keyboard.cpp index c17c3c2..64cbe85 100644 --- a/kernel/src/Drivers/PS2/Keyboard.cpp +++ b/kernel/src/Drivers/PS2/Keyboard.cpp @@ -139,6 +139,7 @@ namespace Drivers::PS2::Keyboard { ack = Drivers::PS2::ReadData(); g_Modifiers = {}; + g_Modifiers.NumLock = true; // keypad types digits, as on most PCs g_BufferHead = 0; g_BufferTail = 0; g_ExtendedScancode = false; @@ -257,6 +258,9 @@ namespace Drivers::PS2::Keyboard { ascii = g_ScancodeToAscii[keycode]; } } + // Num Lock off: the keypad is navigation keys, which type nothing. + if (!g_Modifiers.NumLock && IsKeypadNavScancode(keycode)) + ascii = 0; KeyEvent event = { .Scancode = scancode, @@ -310,6 +314,12 @@ namespace Drivers::PS2::Keyboard { KeyEvent stamped = event; if (stamped.Scancode == ScCapsLock && stamped.Pressed) g_Modifiers.CapsLock = !g_Modifiers.CapsLock; + // Num Lock likewise. Like the PS/2 path, the lock key itself is not + // delivered to apps. + if (stamped.Scancode == ScNumLock) { + if (stamped.Pressed) g_Modifiers.NumLock = !g_Modifiers.NumLock; + return; + } stamped.CapsLock = g_Modifiers.CapsLock; PushAndNotify(stamped); } @@ -318,4 +328,8 @@ namespace Drivers::PS2::Keyboard { return g_Modifiers.CapsLock; } + bool GetNumLock() { + return g_Modifiers.NumLock; + } + }; diff --git a/kernel/src/Drivers/PS2/Keyboard.hpp b/kernel/src/Drivers/PS2/Keyboard.hpp index b023fed..b05f3bf 100644 --- a/kernel/src/Drivers/PS2/Keyboard.hpp +++ b/kernel/src/Drivers/PS2/Keyboard.hpp @@ -63,4 +63,14 @@ namespace Drivers::PS2::Keyboard { // compute ASCII, since the lock is toggled centrally here. bool GetCapsLock(); + // Current Num Lock state, owned here like Caps Lock. On (the default), the + // keypad types digits; off, it acts as the navigation keys printed on it. + bool GetNumLock(); + + // Set-1 scancodes of the keypad keys that are a digit/'.' with Num Lock on + // and Home/arrows/PgUp/End/PgDn/Ins/Del with it off (not '-' and '+'). + inline bool IsKeypadNavScancode(uint8_t keycode) { + return keycode >= 0x47 && keycode <= 0x53 && keycode != 0x4A && keycode != 0x4E; + } + }; diff --git a/kernel/src/Drivers/USB/HidKeyboard.cpp b/kernel/src/Drivers/USB/HidKeyboard.cpp index 1420d85..860ae63 100644 --- a/kernel/src/Drivers/USB/HidKeyboard.cpp +++ b/kernel/src/Drivers/USB/HidKeyboard.cpp @@ -223,6 +223,12 @@ namespace Drivers::USB::HidKeyboard { if (caps && base >= 'a' && base <= 'z') upper = !shift; ascii = upper ? g_ScancodeToAsciiShifted[scancode] : base; } + // Num Lock off: the keypad is navigation keys, which type nothing. + // (Only keypad usages get here with these scancodes: the dedicated + // navigation keys are nonChar already.) + if (!Drivers::PS2::Keyboard::GetNumLock() && + Drivers::PS2::Keyboard::IsKeypadNavScancode(scancode)) + ascii = 0; Drivers::PS2::Keyboard::KeyEvent event = { .Scancode = scancode, @@ -367,10 +373,14 @@ namespace Drivers::USB::HidKeyboard { uint8_t scancode = g_HidToScancode[key]; if (scancode != 0) { InjectKey(scancode, true, modifiers, IsNonCharKey(key), IsExtendedKey(key)); - g_RepeatKey = key; - g_RepeatStartMs = now; - g_LastRepeatMs = 0; newKeyPressed = true; + // Lock keys toggle once per press; repeating them while + // held would flip Caps/Num/Scroll Lock on and off. + if (key != 0x39 && key != 0x53 && key != 0x47) { + g_RepeatKey = key; + g_RepeatStartMs = now; + g_LastRepeatMs = 0; + } } } } diff --git a/kernel/src/Fs/Fat32.cpp b/kernel/src/Fs/Fat32.cpp index d66b565..60d048c 100644 --- a/kernel/src/Fs/Fat32.cpp +++ b/kernel/src/Fs/Fat32.cpp @@ -301,6 +301,53 @@ namespace Fs::Fat32 { // Short name generation and LFN helpers for Create // ========================================================================= + // ========================================================================= + // Name encoding: VFS names are UTF-8, LFN entries are UTF-16 + // ========================================================================= + + // Decode one UTF-8 character at s (NUL-terminated); stores its length. + // A byte that does not start a well-formed sequence is taken as one + // Latin-1 character, so legacy single-byte names still round-trip. + static uint32_t DecodeUtf8(const char* s, int* consumed) { + const uint8_t* u = (const uint8_t*)s; + uint8_t b0 = u[0]; + *consumed = 1; + if (b0 < 0x80) return b0; + int n; + uint32_t cp, min; + if (b0 >= 0xC2 && b0 <= 0xDF) { n = 2; cp = b0 & 0x1F; min = 0x80; } + else if (b0 >= 0xE0 && b0 <= 0xEF) { n = 3; cp = b0 & 0x0F; min = 0x800; } + else if (b0 >= 0xF0 && b0 <= 0xF4) { n = 4; cp = b0 & 0x07; min = 0x10000; } + else return b0; + for (int i = 1; i < n; i++) { + if ((u[i] & 0xC0) != 0x80) return b0; // also stops at NUL + cp = (cp << 6) | (u[i] & 0x3F); + } + if (cp < min || cp > 0x10FFFF || (cp >= 0xD800 && cp <= 0xDFFF)) return b0; + *consumed = n; + return cp; + } + + static int EncodeUtf8(uint32_t cp, char* out) { + if (cp < 0x80) { out[0] = (char)cp; return 1; } + if (cp < 0x800) { + out[0] = (char)(0xC0 | (cp >> 6)); + out[1] = (char)(0x80 | (cp & 0x3F)); + return 2; + } + if (cp < 0x10000) { + out[0] = (char)(0xE0 | (cp >> 12)); + out[1] = (char)(0x80 | ((cp >> 6) & 0x3F)); + out[2] = (char)(0x80 | (cp & 0x3F)); + return 3; + } + out[0] = (char)(0xF0 | (cp >> 18)); + out[1] = (char)(0x80 | ((cp >> 12) & 0x3F)); + out[2] = (char)(0x80 | ((cp >> 6) & 0x3F)); + out[3] = (char)(0x80 | (cp & 0x3F)); + return 4; + } + static void GenerateShortName(const char* longName, char* shortName) { memset(shortName, ' ', 11); @@ -315,9 +362,15 @@ namespace Fs::Fat32 { // Base name (up to 8 chars, uppercase, skip invalid chars) int baseEnd = (lastDot >= 0) ? lastDot : nameLen; int j = 0; + // A non-ASCII character becomes one '_' (8.3 names are OEM codepage; + // the real name lives in the LFN entries). for (int i = 0; i < baseEnd && j < 8; i++) { char c = longName[i]; if (c == ' ' || c == '.') continue; + if ((uint8_t)c >= 0x80) { + if (((uint8_t)c & 0xC0) == 0x80) continue; + c = '_'; + } if (c >= 'a' && c <= 'z') c -= 32; shortName[j++] = c; } @@ -327,6 +380,10 @@ namespace Fs::Fat32 { j = 0; for (int i = lastDot + 1; longName[i] && j < 3; i++) { char c = longName[i]; + if ((uint8_t)c >= 0x80) { + if (((uint8_t)c & 0xC0) == 0x80) continue; + c = '_'; + } if (c >= 'a' && c <= 'z') c -= 32; shortName[8 + j++] = c; } @@ -403,12 +460,22 @@ namespace Fs::Fat32 { // Returns the number of LFN entries. static int BuildLfnEntries(const char* longName, uint8_t checksum, uint8_t* outEntries) { - // Convert to UTF-16 - uint16_t utf16[MaxNameLen]; + // Convert UTF-8 to UTF-16 (LFN holds at most 255 code units) + uint16_t utf16[MaxNameLen + 13]; int len = 0; - while (longName[len] && len < MaxNameLen - 1) { - utf16[len] = (uint8_t)longName[len]; - len++; + for (const char* p = longName; *p;) { + int n; + uint32_t cp = DecodeUtf8(p, &n); + int units = cp >= 0x10000 ? 2 : 1; + if (len + units > 255) break; + if (units == 2) { + cp -= 0x10000; + utf16[len++] = (uint16_t)(0xD800 | (cp >> 10)); + utf16[len++] = (uint16_t)(0xDC00 | (cp & 0x3FF)); + } else { + utf16[len++] = (uint16_t)cp; + } + p += n; } utf16[len] = 0; @@ -464,9 +531,11 @@ namespace Fs::Fat32 { // Compare case-insensitively if (!StrEqualNoCase(longName, reconstructed)) return true; - // Check if long name has lowercase (short names are uppercase) + // Check if long name has lowercase (short names are uppercase) or + // characters the short name could not hold for (int i = 0; longName[i]; i++) { if (longName[i] >= 'a' && longName[i] <= 'z') return true; + if ((uint8_t)longName[i] >= 0x80) return true; } return false; } @@ -619,10 +688,24 @@ namespace Fs::Fat32 { for (int i = 0; i < 2; i++) memcpy(&out[11 + i], entry + 28 + i * 2, 2); } - static void Utf16ToAscii(const uint16_t* src, int maxLen, char* dst) { + // LFN UTF-16 -> UTF-8 name. Unpaired surrogates become U+FFFD; the name is + // cut on a character boundary if it does not fit MaxNameLen bytes. + static void Utf16ToUtf8(const uint16_t* src, int maxLen, char* dst, + int dstCap = MaxNameLen) { int j = 0; - for (int i = 0; i < maxLen && src[i] != 0 && j < MaxNameLen - 1; i++) { - dst[j++] = (src[i] < 128) ? (char)src[i] : '?'; + for (int i = 0; i < maxLen && src[i] != 0 && src[i] != 0xFFFF; i++) { + uint32_t cp = src[i]; + if (cp >= 0xD800 && cp <= 0xDBFF && i + 1 < maxLen && + src[i + 1] >= 0xDC00 && src[i + 1] <= 0xDFFF) { + cp = 0x10000 + ((cp - 0xD800) << 10) + (src[i + 1] - 0xDC00); + i++; + } else if (cp >= 0xD800 && cp <= 0xDFFF) { + cp = 0xFFFD; + } + char enc[4]; + int n = EncodeUtf8(cp, enc); + if (j + n > dstCap - 1) break; + for (int k = 0; k < n; k++) dst[j++] = enc[k]; } dst[j] = '\0'; } @@ -685,7 +768,7 @@ namespace Fs::Fat32 { pe.attributes = attr; if (hasLfn) { - Utf16ToAscii(lfnBuf, MaxNameLen, pe.name); + Utf16ToUtf8(lfnBuf, MaxNameLen, pe.name); } else { ParseShortName(e, pe.name); } @@ -752,7 +835,8 @@ namespace Fs::Fat32 { if (attr & ATTR_VOLUME_ID) { hasLfn = false; continue; } if (hasLfn) { - Utf16ToAscii(lfnBuf, MaxNameLen, outNames[count]); + // Leave room for the '/' appended to directory names + Utf16ToUtf8(lfnBuf, MaxNameLen, outNames[count], MaxNameLen - 1); } else { ParseShortName(e, outNames[count]); } @@ -848,7 +932,7 @@ namespace Fs::Fat32 { char entryName[MaxNameLen]; if (hasLfn) { - Utf16ToAscii(lfnBuf, MaxNameLen, entryName); + Utf16ToUtf8(lfnBuf, MaxNameLen, entryName); } else { ParseShortName(e, entryName); } diff --git a/kernel/src/Sched/Scheduler.cpp b/kernel/src/Sched/Scheduler.cpp index 2908bba..6e17530 100644 --- a/kernel/src/Sched/Scheduler.cpp +++ b/kernel/src/Sched/Scheduler.cpp @@ -324,6 +324,8 @@ namespace Sched { processTable[i].inTail = 0; processTable[i].keyHead = 0; processTable[i].keyTail = 0; + processTable[i].getcharUtf8Len = 0; + processTable[i].getcharUtf8Pos = 0; processTable[i].termCols = 0; processTable[i].termRows = 0; processTable[i].ioOutHandle = -1; @@ -654,6 +656,8 @@ namespace Sched { proc.inTail = 0; proc.keyHead = 0; proc.keyTail = 0; + proc.getcharUtf8Len = 0; + proc.getcharUtf8Pos = 0; proc.termCols = 0; proc.termRows = 0; proc.ioOutHandle = -1; @@ -835,6 +839,7 @@ namespace Sched { thr.outBuf = nullptr; thr.outHead = 0; thr.outTail = 0; thr.inBuf = nullptr; thr.inHead = 0; thr.inTail = 0; thr.keyHead = 0; thr.keyTail = 0; + thr.getcharUtf8Len = 0; thr.getcharUtf8Pos = 0; thr.termCols = 0; thr.termRows = 0; thr.ioOutHandle = -1; thr.ioInHandle = -1; thr.ioKeyHandle = -1; thr.ioWaitsetHandle = -1; @@ -1700,6 +1705,8 @@ namespace Sched { proc.inTail = 0; proc.keyHead = 0; proc.keyTail = 0; + proc.getcharUtf8Len = 0; + proc.getcharUtf8Pos = 0; proc.termCols = 0; proc.termRows = 0; proc.ioOutHandle = -1; diff --git a/kernel/src/Sched/Scheduler.hpp b/kernel/src/Sched/Scheduler.hpp index 6259827..f0b7568 100644 --- a/kernel/src/Sched/Scheduler.hpp +++ b/kernel/src/Sched/Scheduler.hpp @@ -135,9 +135,13 @@ namespace Sched { uint8_t* inBuf = nullptr; // 4KB ring: parent writes, child reads (getchar) volatile uint32_t inHead = 0; volatile uint32_t inTail = 0; - montauk::abi::KeyEvent keyBuf[64]; // parent injects, child reads (getkey/iskeyavailable) volatile uint32_t keyHead = 0; volatile uint32_t keyTail = 0; + // SYS_GETCHAR returns a key's UTF-8 encoding one byte per call; the + // bytes not handed out yet wait here. + uint8_t getcharUtf8[4] = {}; + uint8_t getcharUtf8Len = 0; + uint8_t getcharUtf8Pos = 0; static constexpr uint32_t IoBufSize = 4096; // GUI terminal dimensions (set by desktop, read by SYS_TERMSIZE) diff --git a/programs/data/osdata/keyboard-layouts.toml b/programs/data/osdata/keyboard-layouts.toml index 342d815..3b0b5bd 100644 --- a/programs/data/osdata/keyboard-layouts.toml +++ b/programs/data/osdata/keyboard-layouts.toml @@ -15,15 +15,10 @@ # base: character produced unshifted, one per scancode # shift: character produced with Shift held, one per scancode # altgr: character produced with AltGr held, one per scancode -# -# Characters are Windows-1252 byte values. -# -# A value of 0x00 means "no override" - the key keeps whatever the kernel's -# US scancode table produced. This is how a layout declares only the keys it -# actually changes. +# dead_keys: (optional) characters that are dead keys in this layout [registry] -layouts = ["en", "no", "sv", "da"] +layouts = ["en", "no", "sv", "da", "cs"] # ============================================================================= # LAYOUTS @@ -54,7 +49,7 @@ shift = [ ] altgr = [ 0x40, 0xA3, 0x24, 0x00, 0x7B, 0x5B, 0x5D, 0x7D, # @ GBP $ . { [ ] } - 0x00, 0xB4, 0x80, 0x00, 0x7E, 0x00, 0x00, 0x00, # . ' EUR . ~ . . . + 0x00, 0xB4, 0x20AC, 0x00, 0x7E, 0x00, 0x00, 0x00, # . ' EUR . ~ . . . 0x00, 0x00, 0x00, 0x00, 0x5C, # . . . . backslash ] @@ -77,8 +72,8 @@ shift = [ 0xBD, 0x2A, 0x3B, 0x3A, 0x5F, 0x3E, # 1/2 * ; : _ > ] altgr = [ - 0x40, 0xA3, 0x24, 0x80, 0xA5, 0x7B, 0x5B, 0x5D, # @ GBP $ EUR YEN { [ ] - 0x7D, 0x5C, 0xB1, 0x80, 0x00, 0x7E, 0xF8, 0xE6, # } bslash +- EUR . ~ o/ ae + 0x40, 0xA3, 0x24, 0x20AC, 0xA5, 0x7B, 0x5B, 0x5D, # @ GBP $ EUR YEN { [ ] + 0x7D, 0x5C, 0xB1, 0x20AC, 0x00, 0x7E, 0xF8, 0xE6, # } bslash +- EUR . ~ o/ ae 0xB6, 0xB4, 0x00, 0xB7, 0x00, 0x7C, # par ' . mid . | ] @@ -102,6 +97,44 @@ shift = [ ] altgr = [ 0x40, 0xA3, 0x24, 0xBD, 0xA5, 0x7B, 0x5B, 0x5D, # @ GBP $ 1/2 YEN { [ ] - 0x7D, 0xB1, 0x7C, 0x80, 0x00, 0x7E, 0xB4, 0x5E, # } +- | EUR . ~ ' ^ + 0x7D, 0xB1, 0x7C, 0x20AC, 0x00, 0x7E, 0xB4, 0x5E, # } +- | EUR . ~ ' ^ 0xBE, 0x00, 0x00, 0xB7, 0x00, 0x5C, # 3/4 . . mid . backslash ] + +[layouts.cs] +name = "Czech" +short_name = "cs" +# QWERTZ. The number row types accented letters (digits with Shift), and +# AltGr on the number row gives the dead accents. +scancodes = [ + 0x29, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x10, 0x11, 0x12, + 0x15, 0x1a, 0x1b, 0x21, 0x22, 0x25, 0x26, 0x27, + 0x28, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, + 0x33, 0x34, 0x35, 0x56, +] +base = [ + 0x3B, 0x2B, 0x11B, 0x161, 0x10D, 0x159, 0x17E, 0xFD, # ; + e-caron s-caron c-caron r-caron z-caron y-acute + 0xE1, 0xED, 0xE9, 0x3D, 0xB4, 0x00, 0x00, 0x00, # a-acute i-acute e-acute = (dead acute) . . . + 0x7A, 0xFA, 0x29, 0x00, 0x00, 0x00, 0x00, 0x16F, # z u-acute ) . . . . u-ring + 0xA7, 0xA8, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, # section (dead diaeresis) y . . . . . + 0x2C, 0x2E, 0x2D, 0x5C, # , . - backslash +] +shift = [ + 0xB0, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, # (dead ring) 1 2 3 4 5 6 7 + 0x38, 0x39, 0x30, 0x25, 0x2C7, 0x00, 0x00, 0x00, # 8 9 0 % (dead caron) . . . + 0x5A, 0x2F, 0x28, 0x00, 0x00, 0x00, 0x00, 0x22, # Z / ( . . . . " + 0x21, 0x27, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, # ! ' Y . . . . . + 0x3F, 0x3A, 0x5F, 0x7C, # ? : _ | +] +altgr = [ + 0x00, 0x7E, 0x2C7, 0x5E, 0x2D8, 0xB0, 0x2DB, 0x60, # . dead: tilde caron circumflex breve ring ogonek grave + 0x2D9, 0xB4, 0x2DD, 0xA8, 0xB8, 0x5C, 0x7C, 0x20AC, # dead: dot acute double-acute diaeresis cedilla; backslash | EUR + 0x00, 0xF7, 0xD7, 0x5B, 0x5D, 0x142, 0x141, 0x24, # . divide multiply [ ] l-stroke L-stroke $ + 0xDF, 0xA4, 0x00, 0x23, 0x26, 0x40, 0x7B, 0x7D, # sharp-s currency . # & @ { } + 0x3C, 0x3E, 0x2A, 0x00, # < > * . +] +dead_keys = [ + 0xB4, 0x2C7, 0xA8, 0xB0, 0x7E, 0x5E, + 0x2D8, 0x2DB, 0x60, 0x2D9, 0x2DD, 0xB8, +] diff --git a/programs/include/Api/Syscall.hpp b/programs/include/Api/Syscall.hpp index f513f59..a490c84 100644 --- a/programs/include/Api/Syscall.hpp +++ b/programs/include/Api/Syscall.hpp @@ -271,6 +271,12 @@ namespace montauk::abi { static constexpr uint64_t SYS_CONSENT_NEXT = 192; // (ConsentRequest*) -> 1 delivered, 0 none queued static constexpr uint64_t SYS_CONSENT_REPLY = 193; // (requestId, CONSENT_ALLOW/DENY) -> 0, -1 stale id + /* Unicode key events. Size-versioned: the caller passes sizeof(its + KeyEvent); the kernel copies min(size, its own) bytes and zero-fills the + rest, so the struct can grow without another syscall. */ + static constexpr uint64_t SYS_GETKEY_EX = 194; // (KeyEvent*, size) -> 0; blocks like SYS_GETKEY + static constexpr uint64_t SYS_CHILDIO_WRITEKEY_EX = 195; // (childPid, const KeyEvent*, size) -> status + /* Kernel-owned process capabilities. User identities may namespace per-user resources, but never participate in authorization decisions. */ static constexpr uint64_t CAP_PROCESS_ADMIN = 1ULL << 0; @@ -531,7 +537,10 @@ namespace montauk::abi { uint32_t buildNumber; // monotonic kernel build number }; - struct KeyEvent { + // Legacy 9-byte key event, read by SYS_GETKEY and written by + // SYS_CHILDIO_WRITEKEY. Kept so binaries built before codepoints still work. + // `ascii` is a Windows-1252 byte. + struct KeyEventV1 { uint8_t scancode; char ascii; bool pressed; @@ -547,6 +556,32 @@ namespace montauk::abi { bool extended; }; + // Key event with the Unicode text it types (SYS_GETKEY_EX, + // SYS_CHILDIO_WRITEKEY_EX, WinEvent). Its first 9 bytes ARE a KeyEventV1, so + // a legacy reader sees a valid event. `codepoint` is the character the key + // produces (0 for control/navigation keys and dead keys). `ascii` is its + // Windows-1252 byte, or KEY_ASCII_SUBSTITUTE when 1252 has none. + struct KeyEvent { + uint8_t scancode; + char ascii; + bool pressed; + bool shift; + bool ctrl; + bool alt; + bool capslock; + bool altgr; + bool extended; + uint8_t _reserved[3]; + uint32_t codepoint; + }; + static_assert(sizeof(KeyEventV1) == 9, "KeyEventV1 is frozen ABI"); + static_assert(sizeof(KeyEvent) == 16, "KeyEvent must fit the WinEvent union"); + + // ASCII SUB: `ascii` of a text key whose character has no Windows-1252 byte. + // A control character, so legacy code that only accepts ascii >= 0x20 skips + // it, while code testing `ascii == 0` for navigation keys is not confused. + static constexpr char KEY_ASCII_SUBSTITUTE = 0x1A; + struct MouseState { int32_t x; int32_t y; @@ -584,12 +619,13 @@ namespace montauk::abi { uint8_t type; // 0=key, 1=mouse, 2=resize, 3=close, 4=scale uint8_t _pad[3]; union { - KeyEvent key; + KeyEvent key; // 16 bytes: the union was already that size (mouse) struct { int32_t x, y, scroll; uint8_t buttons, prev_buttons; } mouse; struct { int32_t w, h; } resize; struct { int32_t scale; } scale; }; }; + static_assert(sizeof(WinEvent) == 20, "WinEvent layout is shared with existing binaries"); struct WinInfo { int32_t id; diff --git a/programs/include/gui/canvas.hpp b/programs/include/gui/canvas.hpp index c38c260..6bc125c 100644 --- a/programs/include/gui/canvas.hpp +++ b/programs/include/gui/canvas.hpp @@ -165,9 +165,9 @@ struct Canvas { if (!str || !font_data || scale <= 0) return; uint32_t pixel = c.to_pixel(); int cx = x; - for (int i = 0; str[i]; i++, cx += FONT_WIDTH * scale) { + for (const char* p = str; *p; cx += FONT_WIDTH * scale) { const uint8_t* glyph = - &font_data[(unsigned char)str[i] * FONT_HEIGHT]; + &font_data[cp437_index(montauk::utf8::next(&p)) * FONT_HEIGHT]; for (int row = 0; row < FONT_HEIGHT; row++) { uint8_t bits = glyph[row]; if (!bits) continue; diff --git a/programs/include/gui/clipboard.hpp b/programs/include/gui/clipboard.hpp index 614eaba..0a35535 100644 --- a/programs/include/gui/clipboard.hpp +++ b/programs/include/gui/clipboard.hpp @@ -9,12 +9,32 @@ #include #include #include +#include namespace gui { + // The clipboard carries UTF-8. Text that is not well-formed (legacy + // Windows-1252 bytes) is converted on the way in and on the way out, so + // every reader can assume valid UTF-8. + inline char* clipboard_utf8_copy(const char* text, int len, int* out_len) { + int cap = len * 3 + 1; // each stray byte grows to at most 3 + char* out = (char*)montauk::malloc(cap); + if (!out) return nullptr; + *out_len = montauk::utf8::normalize(text, len, out, cap); + return out; + } + inline bool clipboard_set_text(const char* text, int len) { if (len < 0) return false; if (len > 0 && text == nullptr) return false; + if (len > 0 && !montauk::utf8::valid(text, len)) { + int fixed_len = 0; + char* fixed = clipboard_utf8_copy(text, len, &fixed_len); + if (!fixed) return false; + bool ok = montauk::clipboard_set_text(fixed, (uint32_t)fixed_len) == 0; + montauk::mfree(fixed); + return ok; + } return montauk::clipboard_set_text(text, (uint32_t)len) == 0; } @@ -53,6 +73,14 @@ namespace gui { } text[actual_len] = '\0'; + if (!montauk::utf8::valid(text, (int)actual_len)) { + int fixed_len = 0; + char* fixed = clipboard_utf8_copy(text, (int)actual_len, &fixed_len); + montauk::mfree(text); + if (!fixed) return nullptr; + text = fixed; + actual_len = (uint32_t)fixed_len; + } if (out_len) *out_len = (int)actual_len; if (out_serial) *out_serial = serial; return text; diff --git a/programs/include/gui/font.hpp b/programs/include/gui/font.hpp index 4001c16..8d35da8 100644 --- a/programs/include/gui/font.hpp +++ b/programs/include/gui/font.hpp @@ -19,6 +19,34 @@ static constexpr int FONT_HEIGHT = 16; // TrueType fonts, while login/desktop can recover when TrueType setup fails. extern const uint8_t font_data[256 * 16] __attribute__((weak)); +// The bitmap fallback font is Code Page 437. Map a Unicode codepoint to its +// CP437 cell ('?' when it has none) so UTF-8 text still draws sensibly, +// including the box-drawing characters terminal programs use. +inline uint8_t cp437_index(uint32_t cp) { + if (cp < 0x80) return (uint8_t)cp; + static constexpr uint16_t high[128] = { + 0x00C7,0x00FC,0x00E9,0x00E2,0x00E4,0x00E0,0x00E5,0x00E7, + 0x00EA,0x00EB,0x00E8,0x00EF,0x00EE,0x00EC,0x00C4,0x00C5, + 0x00C9,0x00E6,0x00C6,0x00F4,0x00F6,0x00F2,0x00FB,0x00F9, + 0x00FF,0x00D6,0x00DC,0x00A2,0x00A3,0x00A5,0x20A7,0x0192, + 0x00E1,0x00ED,0x00F3,0x00FA,0x00F1,0x00D1,0x00AA,0x00BA, + 0x00BF,0x2310,0x00AC,0x00BD,0x00BC,0x00A1,0x00AB,0x00BB, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, + 0x2555,0x2563,0x2551,0x2557,0x255D,0x255C,0x255B,0x2510, + 0x2514,0x2534,0x252C,0x251C,0x2500,0x253C,0x255E,0x255F, + 0x255A,0x2554,0x2569,0x2566,0x2560,0x2550,0x256C,0x2567, + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256B, + 0x256A,0x2518,0x250C,0x2588,0x2584,0x258C,0x2590,0x2580, + 0x03B1,0x00DF,0x0393,0x03C0,0x03A3,0x03C3,0x00B5,0x03C4, + 0x03A6,0x0398,0x03A9,0x03B4,0x221E,0x03C6,0x03B5,0x2229, + 0x2261,0x00B1,0x2265,0x2264,0x2320,0x2321,0x00F7,0x2248, + 0x00B0,0x2219,0x00B7,0x221A,0x207F,0x00B2,0x25A0,0x00A0, + }; + for (int i = 0; i < 128; i++) + if (high[i] == cp) return (uint8_t)(0x80 + i); + return '?'; +} + // Dynamic font height: TTF line height or 16 (bitmap fallback) inline int system_font_height() { if (fonts::system_font && fonts::system_font->valid) @@ -74,8 +102,8 @@ inline void draw_text(Framebuffer& fb, int x, int y, const char* text, Color fg) fonts::system_font->draw(fb, x, y, text, fg, fonts::UI_SIZE); return; } - for (int i = 0; text[i]; i++) { - draw_char(fb, x + i * FONT_WIDTH, y, text[i], fg); + for (const char* p = text; *p; x += FONT_WIDTH) { + draw_char(fb, x, y, (char)cp437_index(montauk::utf8::next(&p)), fg); } } @@ -84,18 +112,23 @@ inline void draw_text_bg(Framebuffer& fb, int x, int y, const char* text, Color fonts::system_font->draw_bg(fb, x, y, text, fg, bg, fonts::UI_SIZE); return; } - for (int i = 0; text[i]; i++) { - draw_char_bg(fb, x + i * FONT_WIDTH, y, text[i], fg, bg); + for (const char* p = text; *p; x += FONT_WIDTH) { + draw_char_bg(fb, x, y, (char)cp437_index(montauk::utf8::next(&p)), fg, bg); } } +// Width of the first `len` bytes of a UTF-8 string in the UI font. +inline int text_width_n(const char* text, int len) { + if (fonts::system_font && fonts::system_font->valid) + return fonts::system_font->measure_text_n(text, len, fonts::UI_SIZE); + return montauk::utf8::count(text, len) * FONT_WIDTH; +} + inline int text_width(const char* text) { if (fonts::system_font && fonts::system_font->valid) { return fonts::system_font->measure_text(text, fonts::UI_SIZE); } - int len = 0; - while (text[len]) len++; - return len * FONT_WIDTH; + return montauk::utf8::count(text) * FONT_WIDTH; } } // namespace gui diff --git a/programs/include/gui/mtk/widgets.hpp b/programs/include/gui/mtk/widgets.hpp index f4ca3b0..07ff5b0 100644 --- a/programs/include/gui/mtk/widgets.hpp +++ b/programs/include/gui/mtk/widgets.hpp @@ -296,15 +296,13 @@ inline bool text_input_has_selection(const TextInputState& state, const char* te return text_input_selection_start(state, len) != text_input_selection_end(state, len); } +// Width of the first `count` bytes (a character boundary). Masked fields +// draw one '*' per character, however many bytes it takes. inline int text_input_prefix_width(const char* text, int count, bool masked) { - char prefix[512]; int len = 0; - while (text && text[len] && len < count && len < (int)sizeof(prefix) - 1) { - prefix[len] = masked ? '*' : text[len]; - len++; - } - prefix[len] = '\0'; - return text_width(prefix); + while (text && text[len] && len < count) len++; + if (!masked) return text_width_n(text, len); + return montauk::utf8::count(text, len) * text_width("*"); } inline int text_input_index_from_x(const Rect& bounds, const char* value, @@ -314,11 +312,13 @@ inline int text_input_index_from_x(const Rect& bounds, const char* value, int len = text_input_len(value); int prev_w = 0; - for (int i = 0; i < len; i++) { - int cur_w = text_input_prefix_width(value, i + 1, masked); + for (int i = 0; i < len;) { + int next = montauk::utf8::next_boundary(value, len, i); + int cur_w = text_input_prefix_width(value, next, masked); int midpoint = prev_w + (cur_w - prev_w) / 2; if (rel_x < midpoint) return i; prev_w = cur_w; + i = next; } return len; } @@ -360,8 +360,11 @@ inline int text_input_mouse(TextInputState& state, return TEXT_INPUT_NONE; } +// Bytes >= 0x80 (any non-ASCII character) count as word characters, so word +// jumps never stop inside a multi-byte sequence. inline bool text_input_word_char(char ch) { - return (ch >= 'a' && ch <= 'z') || + return (uint8_t)ch >= 0x80 || + (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_'; @@ -574,8 +577,10 @@ inline int text_input_key(TextInputState& state, if (!key.pressed || !text || cap <= 0) return TEXT_INPUT_NONE; int len = text_input_len(text, cap); - state.cursor = text_input_clamp_cursor(state.cursor, len); - state.selection_anchor = text_input_clamp_cursor(state.selection_anchor, len); + state.cursor = montauk::utf8::floor_boundary( + text, len, text_input_clamp_cursor(state.cursor, len)); + state.selection_anchor = montauk::utf8::floor_boundary( + text, len, text_input_clamp_cursor(state.selection_anchor, len)); if (state.context.open) { context_menu_close(state.context); @@ -606,20 +611,22 @@ inline int text_input_key(TextInputState& state, return TEXT_INPUT_CONSUMED | (changed ? TEXT_INPUT_CHANGED : 0); } - if (key.scancode == 0x4B || key.scancode == 0x4D || - key.scancode == 0x47 || key.scancode == 0x4F) { + if (montauk::nav_scancode(key) == 0x4B || montauk::nav_scancode(key) == 0x4D || + montauk::nav_scancode(key) == 0x47 || montauk::nav_scancode(key) == 0x4F) { int next = state.cursor; - if (!key.shift && sel_start != sel_end && key.scancode == 0x4B) + if (!key.shift && sel_start != sel_end && montauk::nav_scancode(key) == 0x4B) next = sel_start; - else if (!key.shift && sel_start != sel_end && key.scancode == 0x4D) + else if (!key.shift && sel_start != sel_end && montauk::nav_scancode(key) == 0x4D) next = sel_end; - else if (key.scancode == 0x4B) - next = key.ctrl ? text_input_prev_word_boundary(text, state.cursor) : state.cursor - 1; - else if (key.scancode == 0x4D) - next = key.ctrl ? text_input_next_word_boundary(text, state.cursor) : state.cursor + 1; - else if (key.scancode == 0x47) + else if (montauk::nav_scancode(key) == 0x4B) + next = key.ctrl ? text_input_prev_word_boundary(text, state.cursor) + : montauk::utf8::prev_boundary(text, state.cursor); + else if (montauk::nav_scancode(key) == 0x4D) + next = key.ctrl ? text_input_next_word_boundary(text, state.cursor) + : montauk::utf8::next_boundary(text, len, state.cursor); + else if (montauk::nav_scancode(key) == 0x47) next = 0; - else if (key.scancode == 0x4F) + else if (montauk::nav_scancode(key) == 0x4F) next = len; text_input_set_cursor(state, len, next, key.shift); @@ -641,15 +648,16 @@ inline int text_input_key(TextInputState& state, changed = true; } } else if (state.cursor > 0) { - text_input_delete_range(text, &len, state.cursor - 1, state.cursor); - state.cursor--; + int start = montauk::utf8::prev_boundary(text, state.cursor); + text_input_delete_range(text, &len, start, state.cursor); + state.cursor = start; changed = true; } state.selection_anchor = state.cursor; return TEXT_INPUT_CONSUMED | (changed ? TEXT_INPUT_CHANGED : 0); } - if (key.scancode == 0x53) { + if (montauk::nav_scancode(key) == 0x53) { if (sel_start != sel_end) { text_input_delete_range(text, &len, sel_start, sel_end); state.cursor = sel_start; @@ -661,15 +669,22 @@ inline int text_input_key(TextInputState& state, changed = true; } } else if (state.cursor < len) { - text_input_delete_range(text, &len, state.cursor, state.cursor + 1); + int end = montauk::utf8::next_boundary(text, len, state.cursor); + text_input_delete_range(text, &len, state.cursor, end); changed = true; } state.selection_anchor = state.cursor; return TEXT_INPUT_CONSUMED | (changed ? TEXT_INPUT_CHANGED : 0); } - if (key.ctrl || key.alt || !text_input_char_allowed(key.ascii, filter, userdata)) - return TEXT_INPUT_NONE; + // Typed text is inserted as UTF-8; the filter sees each encoded byte. + char typed[montauk::utf8::MAX_BYTES]; + int typed_len = key.ctrl || key.alt ? 0 : montauk::utf8::key_utf8(key, typed); + if (typed_len == 0) return TEXT_INPUT_NONE; + for (int i = 0; i < typed_len; i++) { + if (!text_input_char_allowed(typed[i], filter, userdata)) + return TEXT_INPUT_NONE; + } if (sel_start != sel_end) { text_input_delete_range(text, &len, sel_start, sel_end); @@ -677,11 +692,12 @@ inline int text_input_key(TextInputState& state, changed = true; } - if (len < cap - 1) { + if (len + typed_len < cap) { for (int i = len; i >= state.cursor; i--) - text[i + 1] = text[i]; - text[state.cursor++] = key.ascii; - len++; + text[i + typed_len] = text[i]; + for (int i = 0; i < typed_len; i++) + text[state.cursor++] = typed[i]; + len += typed_len; changed = true; } @@ -1251,22 +1267,34 @@ inline void draw_badge(Canvas& c, c.text(x + theme.gap_sm, y + 2, label, fg); } +// One '*' per UTF-8 character. inline const char* mask_text(const char* value, char* buffer, int cap) { int len = 0; - while (value && value[len] && len < cap - 1) { - buffer[len] = '*'; - len++; + const char* p = value ? value : ""; + while (*p && len < cap - 1) { + montauk::utf8::next(&p); + buffer[len++] = '*'; } buffer[len] = '\0'; return buffer; } +// First `count` bytes of value (a character boundary), or one '*' per +// character in them when masked. inline void copy_prefix(char* buffer, int cap, const char* value, int count, bool masked) { if (cap <= 0) return; int len = 0; - while (value && value[len] && len < count && len < cap - 1) { - buffer[len] = masked ? '*' : value[len]; - len++; + if (masked) { + const char* p = value ? value : ""; + while (*p && p - value < count && len < cap - 1) { + montauk::utf8::next(&p); + buffer[len++] = '*'; + } + } else { + while (value && value[len] && len < count && len < cap - 1) { + buffer[len] = value[len]; + len++; + } } buffer[len] = '\0'; } diff --git a/programs/include/gui/terminal.hpp b/programs/include/gui/terminal.hpp index 6534bcc..23c133b 100644 --- a/programs/include/gui/terminal.hpp +++ b/programs/include/gui/terminal.hpp @@ -9,13 +9,14 @@ #include "gui/font.hpp" #include #include +#include #include #include 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()); } } diff --git a/programs/include/gui/truetype.hpp b/programs/include/gui/truetype.hpp index f7d877e..361fc04 100644 --- a/programs/include/gui/truetype.hpp +++ b/programs/include/gui/truetype.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "gui/gui.hpp" #include "gui/framebuffer.hpp" @@ -41,39 +42,12 @@ namespace gui { +// Windows-1252 byte -> Unicode codepoint, for the remaining code that still +// handles single-byte text (PDF simple-font encodings). UTF-8 strings go +// through measure_text/draw, which decode with montauk::utf8. inline int decode_single_byte_codepoint(int codepoint) { if (codepoint < 0 || codepoint > 255) return codepoint; - - switch (codepoint) { - case 0x80: return 0x20AC; // Euro Sign - case 0x82: return 0x201A; // Single Low-9 Quotation Mark - case 0x83: return 0x0192; // Latin Small Letter F With Hook - case 0x84: return 0x201E; // Double Low-9 Quotation Mark - case 0x85: return 0x2026; // Horizontal Ellipsis - case 0x86: return 0x2020; // Dagger - case 0x87: return 0x2021; // Double Dagger - case 0x88: return 0x02C6; // Modifier Letter Circumflex Accent - case 0x89: return 0x2030; // Per Mille Sign - case 0x8A: return 0x0160; // Latin Capital Letter S With Caron - case 0x8B: return 0x2039; // Single Left-Pointing Angle Quotation Mark - case 0x8C: return 0x0152; // Latin Capital Ligature OE - case 0x8E: return 0x017D; // Latin Capital Letter Z With Caron - case 0x91: return 0x2018; // Left Single Quotation Mark - case 0x92: return 0x2019; // Right Single Quotation Mark - case 0x93: return 0x201C; // Left Double Quotation Mark - case 0x94: return 0x201D; // Right Double Quotation Mark - case 0x95: return 0x2022; // Bullet - case 0x96: return 0x2013; // En Dash - case 0x97: return 0x2014; // Em Dash - case 0x98: return 0x02DC; // Small Tilde - case 0x99: return 0x2122; // Trade Mark Sign - case 0x9A: return 0x0161; // Latin Small Letter S With Caron - case 0x9B: return 0x203A; // Single Right-Pointing Angle Quotation Mark - case 0x9C: return 0x0153; // Latin Small Ligature OE - case 0x9E: return 0x017E; // Latin Small Letter Z With Caron - case 0x9F: return 0x0178; // Latin Capital Letter Y With Diaeresis - default: return codepoint; - } + return (int)montauk::utf8::from_cp1252((uint8_t)codepoint); } struct CachedGlyph { @@ -84,8 +58,18 @@ struct CachedGlyph { bool loaded; }; +// Glyphs above U+00FF live in a small open-addressed table so CJK, symbols +// and the like cost nothing until they are drawn. +struct ExtGlyph { + uint32_t codepoint; // 0 = empty slot + CachedGlyph glyph; +}; + struct GlyphCache { - CachedGlyph glyphs[256]; // Single-byte text with Windows-1252 punctuation mapping + CachedGlyph glyphs[256]; // Unicode U+0000-U+00FF, indexed directly + ExtGlyph* ext; // everything above, hashed by codepoint + int ext_cap; // power of two, 0 until first use + int ext_count; int pixel_size; float scale; int ascent, descent, line_gap; @@ -142,8 +126,21 @@ struct TrueTypeFont { return true; } - void init_cache(GlyphCache* gc, int pixel_size) { - // Free any existing glyph bitmaps + static void free_ext(GlyphCache* gc) { + if (gc->ext) { + for (int i = 0; i < gc->ext_cap; i++) { + if (gc->ext[i].codepoint && gc->ext[i].glyph.bitmap) + montauk::mfree(gc->ext[i].glyph.bitmap); + } + montauk::mfree(gc->ext); + } + gc->ext = nullptr; + gc->ext_cap = 0; + gc->ext_count = 0; + } + + // Release every glyph bitmap in a cache (the cache stays usable). + static void free_cache(GlyphCache* gc) { for (int i = 0; i < 256; i++) { if (gc->glyphs[i].bitmap) { montauk::mfree(gc->glyphs[i].bitmap); @@ -151,6 +148,11 @@ struct TrueTypeFont { gc->glyphs[i].bitmap = nullptr; gc->glyphs[i].loaded = false; } + free_ext(gc); + } + + void init_cache(GlyphCache* gc, int pixel_size) { + free_cache(gc); gc->pixel_size = pixel_size; gc->scale = em_scaling @@ -179,11 +181,8 @@ struct TrueTypeFont { return gc; } - // Evict oldest cache (slot 0) — free its glyph bitmaps - for (int g = 0; g < 256; g++) { - if (caches[0].glyphs[g].bitmap) - montauk::mfree(caches[0].glyphs[g].bitmap); - } + // Evict oldest cache (slot 0) - free its glyph bitmaps + free_cache(&caches[0]); // Shift remaining caches down for (int i = 0; i < 3; i++) montauk::memcpy(&caches[i], &caches[i + 1], sizeof(GlyphCache)); @@ -192,13 +191,54 @@ struct TrueTypeFont { return &caches[3]; } + static constexpr int EXT_MAX = 2048; // flush the table beyond this + + CachedGlyph* ext_slot(GlyphCache* gc, uint32_t codepoint) { + if (gc->ext_cap == 0 || gc->ext_count * 4 >= gc->ext_cap * 3) { + int new_cap = gc->ext_cap ? gc->ext_cap * 2 : 64; + if (gc->ext_count >= EXT_MAX) { + // A document full of distinct glyphs: start over rather than + // grow without bound. Bitmaps are rebuilt on demand. + free_ext(gc); + new_cap = 64; + } + ExtGlyph* table = (ExtGlyph*)montauk::malloc(sizeof(ExtGlyph) * new_cap); + if (!table) return nullptr; + montauk::memset(table, 0, sizeof(ExtGlyph) * new_cap); + for (int i = 0; i < gc->ext_cap; i++) { + ExtGlyph& e = gc->ext[i]; + if (!e.codepoint) continue; + uint32_t h = (e.codepoint * 2654435761u) & (new_cap - 1); + while (table[h].codepoint) h = (h + 1) & (new_cap - 1); + table[h] = e; + } + if (gc->ext) montauk::mfree(gc->ext); + gc->ext = table; + gc->ext_cap = new_cap; + } + uint32_t mask = gc->ext_cap - 1; + uint32_t h = (codepoint * 2654435761u) & mask; + while (gc->ext[h].codepoint && gc->ext[h].codepoint != codepoint) + h = (h + 1) & mask; + if (!gc->ext[h].codepoint) { + gc->ext[h].codepoint = codepoint; + montauk::memset(&gc->ext[h].glyph, 0, sizeof(CachedGlyph)); + gc->ext_count++; + } + return &gc->ext[h].glyph; + } + + // Glyph for a Unicode codepoint. Codepoints the font lacks render as its + // .notdef box, so missing characters stay visible instead of vanishing. CachedGlyph* get_glyph(GlyphCache* gc, int codepoint) { - if (codepoint < 0 || codepoint >= 256) return nullptr; - CachedGlyph* g = &gc->glyphs[codepoint]; + if (codepoint < 0 || codepoint > 0x10FFFF) return nullptr; + CachedGlyph* g = codepoint < 256 ? &gc->glyphs[codepoint] + : ext_slot(gc, (uint32_t)codepoint); + if (!g) return nullptr; if (g->loaded) return g; g->loaded = true; - int font_codepoint = decode_single_byte_codepoint(codepoint); + int font_codepoint = codepoint; int advance, lsb; stbtt_GetCodepointHMetrics(&info, font_codepoint, &advance, &lsb); g->advance = (int)(advance * gc->scale); @@ -222,12 +262,34 @@ struct TrueTypeFont { return g; } + // Advance of one codepoint at a size (0 if the font is unusable). + int char_advance(int codepoint, int pixel_size) { + if (!valid) return 0; + CachedGlyph* g = get_glyph(get_cache(pixel_size), codepoint); + return g ? g->advance : 0; + } + + // Width of the first `len` bytes of a UTF-8 string. + int measure_text_n(const char* text, int len, int pixel_size) { + if (!valid) return 0; + GlyphCache* gc = get_cache(pixel_size); + int w = 0; + for (int pos = 0; pos < len && text[pos];) { + int n; + uint32_t cp = montauk::utf8::decode(text + pos, len - pos, &n); + CachedGlyph* g = get_glyph(gc, (int)cp); + if (g) w += g->advance; + pos += n; + } + return w; + } + int measure_text(const char* text, int pixel_size) { if (!valid) return 0; GlyphCache* gc = get_cache(pixel_size); int w = 0; - for (int i = 0; text[i]; i++) { - CachedGlyph* g = get_glyph(gc, (unsigned char)text[i]); + for (const char* p = text; *p;) { + CachedGlyph* g = get_glyph(gc, (int)montauk::utf8::next(&p)); if (g) w += g->advance; } return w; @@ -253,8 +315,8 @@ struct TrueTypeFont { uint32_t src_rgb = 0xFF000000 | ((uint32_t)color.r << 16) | ((uint32_t)color.g << 8) | color.b; - for (int i = 0; text[i]; i++) { - CachedGlyph* g = get_glyph(gc, (unsigned char)text[i]); + for (const char* p = text; *p;) { + CachedGlyph* g = get_glyph(gc, (int)montauk::utf8::next(&p)); if (!g) continue; if (g->bitmap) { @@ -325,8 +387,8 @@ struct TrueTypeFont { int baseline = y + gc->ascent; bool drew_pixel = false; - for (int i = 0; text[i]; i++) { - CachedGlyph* g = get_glyph(gc, (unsigned char)text[i]); + for (const char* p = text; *p;) { + CachedGlyph* g = get_glyph(gc, (int)montauk::utf8::next(&p)); if (!g) continue; if (g->bitmap) { @@ -378,8 +440,8 @@ struct TrueTypeFont { int clip_x2 = clip_x + clip_w; int clip_y2 = clip_y + clip_h; - for (int i = 0; text[i]; i++) { - CachedGlyph* g = get_glyph(gc, (unsigned char)text[i]); + for (const char* p = text; *p;) { + CachedGlyph* g = get_glyph(gc, (int)montauk::utf8::next(&p)); if (!g) continue; if (g->bitmap) { @@ -417,7 +479,7 @@ struct TrueTypeFont { } } - // Draw single character to buffer, returning advance width + // Draw one Unicode codepoint to buffer, returning advance width int draw_char_to_buffer(uint32_t* pixels, int buf_w, int buf_h, int x, int baseline, int codepoint, Color color, GlyphCache* gc) { diff --git a/programs/include/gui/widgets.hpp b/programs/include/gui/widgets.hpp index 5aa203d..e2de916 100644 --- a/programs/include/gui/widgets.hpp +++ b/programs/include/gui/widgets.hpp @@ -212,11 +212,7 @@ struct TextBox { // Draw cursor if focused if (focused) { - // Measure text up to cursor position for proportional fonts - char prefix[256]; - for (int i = 0; i < cursor && i < 255; i++) prefix[i] = text[i]; - prefix[cursor < 255 ? cursor : 255] = '\0'; - int cx = tx + text_width(prefix); + int cx = tx + text_width_n(text, cursor); draw_vline(fb, cx, ty, fh, cursor_color); } } @@ -230,34 +226,35 @@ struct TextBox { void handle_key(const montauk::abi::KeyEvent& key) { if (!focused || !key.pressed) return; + char typed[montauk::utf8::MAX_BYTES]; + int typed_len = montauk::utf8::key_utf8(key, typed); + if (key.ascii == '\b' || key.scancode == 0x0E) { - // Backspace + // Backspace: remove the whole character before the cursor if (cursor > 0) { - for (int i = cursor - 1; i < text_len - 1; i++) { - text[i] = text[i + 1]; - } - text_len--; - cursor--; - text[text_len] = '\0'; + int start = montauk::utf8::prev_boundary(text, cursor); + int n = cursor - start; + for (int i = start; i <= text_len - n; i++) + text[i] = text[i + n]; + text_len -= n; + cursor = start; } - } else if ((unsigned char)key.ascii >= 32 - && (unsigned char)key.ascii != 127) { - // Printable character - if (text_len < 254) { - for (int i = text_len; i > cursor; i--) { - text[i] = text[i - 1]; - } - text[cursor] = key.ascii; - cursor++; - text_len++; - text[text_len] = '\0'; + } else if (typed_len > 0) { + // Printable character, inserted as UTF-8 + if (text_len + typed_len <= 254) { + for (int i = text_len; i >= cursor; i--) + text[i + typed_len] = text[i]; + for (int i = 0; i < typed_len; i++) + text[cursor + i] = typed[i]; + cursor += typed_len; + text_len += typed_len; } - } else if (key.scancode == 0x4B) { + } else if (montauk::nav_scancode(key) == 0x4B) { // Left arrow - if (cursor > 0) cursor--; - } else if (key.scancode == 0x4D) { + cursor = montauk::utf8::prev_boundary(text, cursor); + } else if (montauk::nav_scancode(key) == 0x4D) { // Right arrow - if (cursor < text_len) cursor++; + cursor = montauk::utf8::next_boundary(text, text_len, cursor); } } }; diff --git a/programs/include/libc/montauk.h b/programs/include/libc/montauk.h index d08f457..7f02ad6 100644 --- a/programs/include/libc/montauk.h +++ b/programs/include/libc/montauk.h @@ -23,200 +23,202 @@ extern "C" { Generated from Api/Syscall.hpp by scripts/montauk-syscalls.py. Do not edit by hand; run 'make gen-syscalls' to refresh. Wrapper functions below are hand-written. */ -#define MTK_SYS_EXIT 0 -#define MTK_SYS_YIELD 1 -#define MTK_SYS_SLEEP_MS 2 -#define MTK_SYS_GETPID 3 -#define MTK_SYS_PRINT 4 -#define MTK_SYS_PUTCHAR 5 -#define MTK_SYS_OPEN 6 -#define MTK_SYS_READ 7 -#define MTK_SYS_GETSIZE 8 -#define MTK_SYS_CLOSE 9 -#define MTK_SYS_READDIR 10 -#define MTK_SYS_ALLOC 11 -#define MTK_SYS_FREE 12 -#define MTK_SYS_GETTICKS 13 -#define MTK_SYS_GETMILLISECONDS 14 -#define MTK_SYS_GETINFO 15 -#define MTK_SYS_ISKEYAVAILABLE 16 -#define MTK_SYS_GETKEY 17 -#define MTK_SYS_GETCHAR 18 -#define MTK_SYS_PING 19 -#define MTK_SYS_SPAWN 20 -#define MTK_SYS_FBINFO 21 -#define MTK_SYS_FBMAP 22 -#define MTK_SYS_WAITPID 23 -#define MTK_SYS_TERMSIZE 24 -#define MTK_SYS_GETARGS 25 -#define MTK_SYS_RESET 26 -#define MTK_SYS_SHUTDOWN 27 -#define MTK_SYS_GETTIME 28 -#define MTK_SYS_SOCKET 29 -#define MTK_SYS_CONNECT 30 -#define MTK_SYS_BIND 31 -#define MTK_SYS_LISTEN 32 -#define MTK_SYS_ACCEPT 33 -#define MTK_SYS_SEND 34 -#define MTK_SYS_RECV 35 -#define MTK_SYS_CLOSESOCK 36 -#define MTK_SYS_GETNETCFG 37 -#define MTK_SYS_SETNETCFG 38 -#define MTK_SYS_SENDTO 39 -#define MTK_SYS_RECVFROM 40 -#define MTK_SYS_FWRITE 41 -#define MTK_SYS_FCREATE 42 -#define MTK_SYS_TERMSCALE 43 -#define MTK_SYS_RESOLVE 44 -#define MTK_SYS_GETRANDOM 45 -#define MTK_SYS_LOG 46 -#define MTK_SYS_MOUSESTATE 47 -#define MTK_SYS_SETMOUSEBOUNDS 48 -#define MTK_SYS_SPAWN_REDIR 49 -#define MTK_SYS_CHILDIO_READ 50 -#define MTK_SYS_CHILDIO_WRITE 51 -#define MTK_SYS_CHILDIO_WRITEKEY 52 -#define MTK_SYS_CHILDIO_SETTERMSZ 53 -#define MTK_SYS_WINCREATE 54 -#define MTK_SYS_WINDESTROY 55 -#define MTK_SYS_WINPRESENT 56 -#define MTK_SYS_WINPOLL 57 -#define MTK_SYS_WINENUM 58 -#define MTK_SYS_WINMAP 59 -#define MTK_SYS_WINSENDEVENT 60 -#define MTK_SYS_PROCLIST 61 -#define MTK_SYS_KILL 62 -#define MTK_SYS_DEVLIST 63 -#define MTK_SYS_WINRESIZE 64 -#define MTK_SYS_WINSETSCALE 65 -#define MTK_SYS_WINGETSCALE 66 -#define MTK_SYS_MEMSTATS 67 -#define MTK_SYS_WINSETCURSOR 68 -#define MTK_SYS_DISKINFO 69 -#define MTK_SYS_PARTLIST 70 -#define MTK_SYS_DISKREAD 71 -#define MTK_SYS_DISKWRITE 72 -#define MTK_SYS_GPTINIT 73 -#define MTK_SYS_GPTADD 74 -#define MTK_SYS_FSMOUNT 75 -#define MTK_SYS_FSFORMAT 76 -#define MTK_SYS_FDELETE 77 -#define MTK_SYS_FMKDIR 78 -#define MTK_SYS_DRIVELIST 79 -#define MTK_SYS_AUDIOOPEN 80 -#define MTK_SYS_AUDIOCLOSE 81 -#define MTK_SYS_AUDIOWRITE 82 -#define MTK_SYS_AUDIOCTL 83 -#define MTK_SYS_BTSCAN 84 -#define MTK_SYS_BTCONNECT 85 -#define MTK_SYS_BTDISCONNECT 86 -#define MTK_SYS_BTLIST 87 -#define MTK_SYS_BTINFO 88 -#define MTK_SYS_SUSPEND 89 -#define MTK_SYS_SETTZ 90 -#define MTK_SYS_GETTZ 91 -#define MTK_SYS_SETUSER 92 -#define MTK_SYS_GETUSER 93 -#define MTK_SYS_FRENAME 94 -#define MTK_SYS_GETCWD 95 -#define MTK_SYS_CHDIR 96 -#define MTK_SYS_WINUNMAP 97 -#define MTK_SYS_DUPHANDLE 98 -#define MTK_SYS_WAIT_HANDLE 99 -#define MTK_SYS_STREAM_CREATE 100 -#define MTK_SYS_STREAM_READ 101 -#define MTK_SYS_STREAM_WRITE 102 -#define MTK_SYS_MAILBOX_CREATE 103 -#define MTK_SYS_MAILBOX_SEND 104 -#define MTK_SYS_MAILBOX_RECV 105 -#define MTK_SYS_WAITSET_CREATE 106 -#define MTK_SYS_WAITSET_ADD 107 -#define MTK_SYS_WAITSET_REMOVE 108 -#define MTK_SYS_WAITSET_WAIT 109 -#define MTK_SYS_PROC_OPEN 110 -#define MTK_SYS_SURFACE_CREATE 111 -#define MTK_SYS_SURFACE_MAP 112 -#define MTK_SYS_SURFACE_RESIZE 113 -#define MTK_SYS_LOAD_LIB 114 -#define MTK_SYS_UNLOAD_LIB 115 -#define MTK_SYS_DLSYM 116 -#define MTK_SYS_GETLIBBASE 117 -#define MTK_SYS_CRASH_REPORT 118 -#define MTK_SYS_CLIPBOARD_SET_TEXT 119 -#define MTK_SYS_CLIPBOARD_GET_INFO 120 -#define MTK_SYS_CLIPBOARD_GET_TEXT 121 -#define MTK_SYS_CLIPBOARD_CLEAR 122 -#define MTK_SYS_INPUT_WAIT 123 -#define MTK_SYS_DRIVELABEL 124 -#define MTK_SYS_NETSTATUS 125 -#define MTK_SYS_WINSETFLAGS 126 -#define MTK_SYS_DRIVEKIND 127 -#define MTK_SYS_AUDIOLIST 128 -#define MTK_SYS_AUDIOWAIT 129 -#define MTK_SYS_THREAD_SPAWN 130 -#define MTK_SYS_THREAD_EXIT 131 -#define MTK_SYS_THREAD_JOIN 132 -#define MTK_SYS_THREAD_SELF 133 -#define MTK_SYS_FS_SYNC 134 -#define MTK_SYS_POWER_REQUEST 135 -#define MTK_SYS_READDIR_AT 136 -#define MTK_SYS_BTSETADDR 137 -#define MTK_SYS_BTBONDS 138 -#define MTK_SYS_BTFORGET 139 -#define MTK_SYS_RESERVED_140 140 -#define MTK_SYS_RESERVED_141 141 -#define MTK_SYS_RESERVED_142 142 -#define MTK_SYS_RESERVED_143 143 -#define MTK_SYS_RESERVED_144 144 -#define MTK_SYS_RESERVED_145 145 -#define MTK_SYS_RESERVED_146 146 -#define MTK_SYS_RESERVED_147 147 -#define MTK_SYS_RESERVED_148 148 -#define MTK_SYS_POWERINFO 149 -#define MTK_SYS_FBFLIP 150 -#define MTK_SYS_GETEXECPATH 151 -#define MTK_SYS_STAT 152 -#define MTK_SYS_SETUNIXTIME 153 -#define MTK_SYS_DISPLAYINFO 154 -#define MTK_SYS_DISPLAYMODES 155 -#define MTK_SYS_DISPLAYSETMODE 156 -#define MTK_SYS_DISPLAYBRIGHTNESS 157 -#define MTK_SYS_WIFI_SCAN 158 -#define MTK_SYS_WIFI_INFO 159 -#define MTK_SYS_WIFI_CONNECT 160 -#define MTK_SYS_WIFI_DISCONNECT 161 -#define MTK_SYS_WIFI_SCAN_START 162 -#define MTK_SYS_WIFI_RESULTS 163 -#define MTK_SYS_WIFI_CONNECT_ASYNC 164 -#define MTK_SYS_NETIFS 165 -#define MTK_SYS_GETCHAR_NB 166 -#define MTK_SYS_UTIME 167 -#define MTK_SYS_MMAP_ANON 168 -#define MTK_SYS_MUNMAP 169 -#define MTK_SYS_MPROTECT 170 -#define MTK_SYS_GETENVIRON 171 -#define MTK_SYS_SETENVIRON 172 -#define MTK_SYS_SPAWN_ENV 173 -#define MTK_SYS_SETSESSION 174 -#define MTK_SYS_KILLSESSION 175 -#define MTK_SYS_LOG_WRITE 176 -#define MTK_SYS_TERMINAL_ATTACHED 177 -#define MTK_SYS_USB_LIST 178 -#define MTK_SYS_USB_CLAIM 179 -#define MTK_SYS_USB_CLOSE 180 -#define MTK_SYS_USB_CONTROL 181 -#define MTK_SYS_USB_BULK_IN_START 182 -#define MTK_SYS_USB_BULK_IN_STOP 183 -#define MTK_SYS_USB_BULK_IN_READ 184 -#define MTK_SYS_SPAWN_CAPS 185 -#define MTK_SYS_SPAWN_REDIR_CAPS 186 -#define MTK_SYS_ALLOC_EAGER 187 -#define MTK_SYS_BATTERYINFO 188 -#define MTK_SYS_GETCAPS 189 -#define MTK_SYS_VOLINFO 190 -#define MTK_SYS_CONSENT_REGISTER 191 -#define MTK_SYS_CONSENT_NEXT 192 -#define MTK_SYS_CONSENT_REPLY 193 +#define MTK_SYS_EXIT 0 +#define MTK_SYS_YIELD 1 +#define MTK_SYS_SLEEP_MS 2 +#define MTK_SYS_GETPID 3 +#define MTK_SYS_PRINT 4 +#define MTK_SYS_PUTCHAR 5 +#define MTK_SYS_OPEN 6 +#define MTK_SYS_READ 7 +#define MTK_SYS_GETSIZE 8 +#define MTK_SYS_CLOSE 9 +#define MTK_SYS_READDIR 10 +#define MTK_SYS_ALLOC 11 +#define MTK_SYS_FREE 12 +#define MTK_SYS_GETTICKS 13 +#define MTK_SYS_GETMILLISECONDS 14 +#define MTK_SYS_GETINFO 15 +#define MTK_SYS_ISKEYAVAILABLE 16 +#define MTK_SYS_GETKEY 17 +#define MTK_SYS_GETCHAR 18 +#define MTK_SYS_PING 19 +#define MTK_SYS_SPAWN 20 +#define MTK_SYS_FBINFO 21 +#define MTK_SYS_FBMAP 22 +#define MTK_SYS_WAITPID 23 +#define MTK_SYS_TERMSIZE 24 +#define MTK_SYS_GETARGS 25 +#define MTK_SYS_RESET 26 +#define MTK_SYS_SHUTDOWN 27 +#define MTK_SYS_GETTIME 28 +#define MTK_SYS_SOCKET 29 +#define MTK_SYS_CONNECT 30 +#define MTK_SYS_BIND 31 +#define MTK_SYS_LISTEN 32 +#define MTK_SYS_ACCEPT 33 +#define MTK_SYS_SEND 34 +#define MTK_SYS_RECV 35 +#define MTK_SYS_CLOSESOCK 36 +#define MTK_SYS_GETNETCFG 37 +#define MTK_SYS_SETNETCFG 38 +#define MTK_SYS_SENDTO 39 +#define MTK_SYS_RECVFROM 40 +#define MTK_SYS_FWRITE 41 +#define MTK_SYS_FCREATE 42 +#define MTK_SYS_TERMSCALE 43 +#define MTK_SYS_RESOLVE 44 +#define MTK_SYS_GETRANDOM 45 +#define MTK_SYS_LOG 46 +#define MTK_SYS_MOUSESTATE 47 +#define MTK_SYS_SETMOUSEBOUNDS 48 +#define MTK_SYS_SPAWN_REDIR 49 +#define MTK_SYS_CHILDIO_READ 50 +#define MTK_SYS_CHILDIO_WRITE 51 +#define MTK_SYS_CHILDIO_WRITEKEY 52 +#define MTK_SYS_CHILDIO_SETTERMSZ 53 +#define MTK_SYS_WINCREATE 54 +#define MTK_SYS_WINDESTROY 55 +#define MTK_SYS_WINPRESENT 56 +#define MTK_SYS_WINPOLL 57 +#define MTK_SYS_WINENUM 58 +#define MTK_SYS_WINMAP 59 +#define MTK_SYS_WINSENDEVENT 60 +#define MTK_SYS_PROCLIST 61 +#define MTK_SYS_KILL 62 +#define MTK_SYS_DEVLIST 63 +#define MTK_SYS_WINRESIZE 64 +#define MTK_SYS_WINSETSCALE 65 +#define MTK_SYS_WINGETSCALE 66 +#define MTK_SYS_MEMSTATS 67 +#define MTK_SYS_WINSETCURSOR 68 +#define MTK_SYS_DISKINFO 69 +#define MTK_SYS_PARTLIST 70 +#define MTK_SYS_DISKREAD 71 +#define MTK_SYS_DISKWRITE 72 +#define MTK_SYS_GPTINIT 73 +#define MTK_SYS_GPTADD 74 +#define MTK_SYS_FSMOUNT 75 +#define MTK_SYS_FSFORMAT 76 +#define MTK_SYS_FDELETE 77 +#define MTK_SYS_FMKDIR 78 +#define MTK_SYS_DRIVELIST 79 +#define MTK_SYS_AUDIOOPEN 80 +#define MTK_SYS_AUDIOCLOSE 81 +#define MTK_SYS_AUDIOWRITE 82 +#define MTK_SYS_AUDIOCTL 83 +#define MTK_SYS_BTSCAN 84 +#define MTK_SYS_BTCONNECT 85 +#define MTK_SYS_BTDISCONNECT 86 +#define MTK_SYS_BTLIST 87 +#define MTK_SYS_BTINFO 88 +#define MTK_SYS_SUSPEND 89 +#define MTK_SYS_SETTZ 90 +#define MTK_SYS_GETTZ 91 +#define MTK_SYS_SETUSER 92 +#define MTK_SYS_GETUSER 93 +#define MTK_SYS_FRENAME 94 +#define MTK_SYS_GETCWD 95 +#define MTK_SYS_CHDIR 96 +#define MTK_SYS_WINUNMAP 97 +#define MTK_SYS_DUPHANDLE 98 +#define MTK_SYS_WAIT_HANDLE 99 +#define MTK_SYS_STREAM_CREATE 100 +#define MTK_SYS_STREAM_READ 101 +#define MTK_SYS_STREAM_WRITE 102 +#define MTK_SYS_MAILBOX_CREATE 103 +#define MTK_SYS_MAILBOX_SEND 104 +#define MTK_SYS_MAILBOX_RECV 105 +#define MTK_SYS_WAITSET_CREATE 106 +#define MTK_SYS_WAITSET_ADD 107 +#define MTK_SYS_WAITSET_REMOVE 108 +#define MTK_SYS_WAITSET_WAIT 109 +#define MTK_SYS_PROC_OPEN 110 +#define MTK_SYS_SURFACE_CREATE 111 +#define MTK_SYS_SURFACE_MAP 112 +#define MTK_SYS_SURFACE_RESIZE 113 +#define MTK_SYS_LOAD_LIB 114 +#define MTK_SYS_UNLOAD_LIB 115 +#define MTK_SYS_DLSYM 116 +#define MTK_SYS_GETLIBBASE 117 +#define MTK_SYS_CRASH_REPORT 118 +#define MTK_SYS_CLIPBOARD_SET_TEXT 119 +#define MTK_SYS_CLIPBOARD_GET_INFO 120 +#define MTK_SYS_CLIPBOARD_GET_TEXT 121 +#define MTK_SYS_CLIPBOARD_CLEAR 122 +#define MTK_SYS_INPUT_WAIT 123 +#define MTK_SYS_DRIVELABEL 124 +#define MTK_SYS_NETSTATUS 125 +#define MTK_SYS_WINSETFLAGS 126 +#define MTK_SYS_DRIVEKIND 127 +#define MTK_SYS_AUDIOLIST 128 +#define MTK_SYS_AUDIOWAIT 129 +#define MTK_SYS_THREAD_SPAWN 130 +#define MTK_SYS_THREAD_EXIT 131 +#define MTK_SYS_THREAD_JOIN 132 +#define MTK_SYS_THREAD_SELF 133 +#define MTK_SYS_FS_SYNC 134 +#define MTK_SYS_POWER_REQUEST 135 +#define MTK_SYS_READDIR_AT 136 +#define MTK_SYS_BTSETADDR 137 +#define MTK_SYS_BTBONDS 138 +#define MTK_SYS_BTFORGET 139 +#define MTK_SYS_RESERVED_140 140 +#define MTK_SYS_RESERVED_141 141 +#define MTK_SYS_RESERVED_142 142 +#define MTK_SYS_RESERVED_143 143 +#define MTK_SYS_RESERVED_144 144 +#define MTK_SYS_RESERVED_145 145 +#define MTK_SYS_RESERVED_146 146 +#define MTK_SYS_RESERVED_147 147 +#define MTK_SYS_RESERVED_148 148 +#define MTK_SYS_POWERINFO 149 +#define MTK_SYS_FBFLIP 150 +#define MTK_SYS_GETEXECPATH 151 +#define MTK_SYS_STAT 152 +#define MTK_SYS_SETUNIXTIME 153 +#define MTK_SYS_DISPLAYINFO 154 +#define MTK_SYS_DISPLAYMODES 155 +#define MTK_SYS_DISPLAYSETMODE 156 +#define MTK_SYS_DISPLAYBRIGHTNESS 157 +#define MTK_SYS_WIFI_SCAN 158 +#define MTK_SYS_WIFI_INFO 159 +#define MTK_SYS_WIFI_CONNECT 160 +#define MTK_SYS_WIFI_DISCONNECT 161 +#define MTK_SYS_WIFI_SCAN_START 162 +#define MTK_SYS_WIFI_RESULTS 163 +#define MTK_SYS_WIFI_CONNECT_ASYNC 164 +#define MTK_SYS_NETIFS 165 +#define MTK_SYS_GETCHAR_NB 166 +#define MTK_SYS_UTIME 167 +#define MTK_SYS_MMAP_ANON 168 +#define MTK_SYS_MUNMAP 169 +#define MTK_SYS_MPROTECT 170 +#define MTK_SYS_GETENVIRON 171 +#define MTK_SYS_SETENVIRON 172 +#define MTK_SYS_SPAWN_ENV 173 +#define MTK_SYS_SETSESSION 174 +#define MTK_SYS_KILLSESSION 175 +#define MTK_SYS_LOG_WRITE 176 +#define MTK_SYS_TERMINAL_ATTACHED 177 +#define MTK_SYS_USB_LIST 178 +#define MTK_SYS_USB_CLAIM 179 +#define MTK_SYS_USB_CLOSE 180 +#define MTK_SYS_USB_CONTROL 181 +#define MTK_SYS_USB_BULK_IN_START 182 +#define MTK_SYS_USB_BULK_IN_STOP 183 +#define MTK_SYS_USB_BULK_IN_READ 184 +#define MTK_SYS_SPAWN_CAPS 185 +#define MTK_SYS_SPAWN_REDIR_CAPS 186 +#define MTK_SYS_ALLOC_EAGER 187 +#define MTK_SYS_BATTERYINFO 188 +#define MTK_SYS_GETCAPS 189 +#define MTK_SYS_VOLINFO 190 +#define MTK_SYS_CONSENT_REGISTER 191 +#define MTK_SYS_CONSENT_NEXT 192 +#define MTK_SYS_CONSENT_REPLY 193 +#define MTK_SYS_GETKEY_EX 194 +#define MTK_SYS_CHILDIO_WRITEKEY_EX 195 /* @SYSCALLS-END */ /* Syscall status codes (montauk/statuscodes.h for C++). */ diff --git a/programs/include/montauk/keyboard.h b/programs/include/montauk/keyboard.h index 74bb23a..ef5a1a6 100644 --- a/programs/include/montauk/keyboard.h +++ b/programs/include/montauk/keyboard.h @@ -8,27 +8,34 @@ #include #include +#include namespace montauk::keyboard { -inline constexpr int MAX_LAYOUTS = 8; -inline constexpr int MAX_KEYS = 64; +inline constexpr int MAX_LAYOUTS = 8; +inline constexpr int MAX_KEYS = 64; +inline constexpr int MAX_DEAD_KEYS = 16; -// One overridden key. Characters are Windows-1252 bytes to match the -// single-byte GUI text stack; 0 means "no override, keep the kernel's value". +// One overridden key. Characters are Unicode codepoints; translation stores +// them in KeyEvent::codepoint (and the Windows-1252 byte, if any, in ascii). +// 0 means "no override, keep the kernel's value". struct KeyMap { - uint8_t scancode; - uint8_t base; - uint8_t shift; - uint8_t altgr; + uint8_t scancode; + uint32_t base; + uint32_t shift; + uint32_t altgr; }; struct Layout { - char id[8]; - char name[48]; - char short_name[8]; - KeyMap keys[MAX_KEYS]; - int key_count; // 0 = passthrough (the kernel's US table) + char id[8]; + char name[48]; + char short_name[8]; + KeyMap keys[MAX_KEYS]; + int key_count; // 0 = passthrough (the kernel's US table) + // Characters that act as dead keys in this layout: pressing one types + // nothing and modifies the next character (see compose()). + uint32_t dead_keys[MAX_DEAD_KEYS]; + int dead_count; }; struct Registry { @@ -40,8 +47,71 @@ struct State { Registry registry; bool enabled[MAX_LAYOUTS]; int active; + uint32_t pending_dead; // dead key waiting for the next character, 0 = none }; +// ==== Dead-key composition ==== +// Keyed by the spacing form of the accent, which is what a layout puts on the +// dead key itself (and what dead key + Space types). + +struct ComposeEntry { + uint16_t dead; + uint16_t base; + uint16_t result; +}; + +inline constexpr ComposeEntry COMPOSE[] = { + // acute + {0x00B4,'a',0xE1},{0x00B4,'A',0xC1},{0x00B4,'e',0xE9},{0x00B4,'E',0xC9}, + {0x00B4,'i',0xED},{0x00B4,'I',0xCD},{0x00B4,'o',0xF3},{0x00B4,'O',0xD3}, + {0x00B4,'u',0xFA},{0x00B4,'U',0xDA},{0x00B4,'y',0xFD},{0x00B4,'Y',0xDD}, + {0x00B4,'c',0x107},{0x00B4,'C',0x106},{0x00B4,'l',0x13A},{0x00B4,'L',0x139}, + {0x00B4,'n',0x144},{0x00B4,'N',0x143},{0x00B4,'r',0x155},{0x00B4,'R',0x154}, + {0x00B4,'s',0x15B},{0x00B4,'S',0x15A},{0x00B4,'z',0x17A},{0x00B4,'Z',0x179}, + // caron + {0x02C7,'c',0x10D},{0x02C7,'C',0x10C},{0x02C7,'d',0x10F},{0x02C7,'D',0x10E}, + {0x02C7,'e',0x11B},{0x02C7,'E',0x11A},{0x02C7,'l',0x13E},{0x02C7,'L',0x13D}, + {0x02C7,'n',0x148},{0x02C7,'N',0x147},{0x02C7,'r',0x159},{0x02C7,'R',0x158}, + {0x02C7,'s',0x161},{0x02C7,'S',0x160},{0x02C7,'t',0x165},{0x02C7,'T',0x164}, + {0x02C7,'z',0x17E},{0x02C7,'Z',0x17D}, + // diaeresis + {0x00A8,'a',0xE4},{0x00A8,'A',0xC4},{0x00A8,'e',0xEB},{0x00A8,'E',0xCB}, + {0x00A8,'i',0xEF},{0x00A8,'I',0xCF},{0x00A8,'o',0xF6},{0x00A8,'O',0xD6}, + {0x00A8,'u',0xFC},{0x00A8,'U',0xDC},{0x00A8,'y',0xFF},{0x00A8,'Y',0x178}, + // ring above + {0x00B0,'u',0x16F},{0x00B0,'U',0x16E},{0x00B0,'a',0xE5},{0x00B0,'A',0xC5}, + // grave + {0x0060,'a',0xE0},{0x0060,'A',0xC0},{0x0060,'e',0xE8},{0x0060,'E',0xC8}, + {0x0060,'i',0xEC},{0x0060,'I',0xCC},{0x0060,'o',0xF2},{0x0060,'O',0xD2}, + {0x0060,'u',0xF9},{0x0060,'U',0xD9}, + // circumflex + {0x005E,'a',0xE2},{0x005E,'A',0xC2},{0x005E,'e',0xEA},{0x005E,'E',0xCA}, + {0x005E,'i',0xEE},{0x005E,'I',0xCE},{0x005E,'o',0xF4},{0x005E,'O',0xD4}, + {0x005E,'u',0xFB},{0x005E,'U',0xDB}, + // tilde + {0x007E,'a',0xE3},{0x007E,'A',0xC3},{0x007E,'n',0xF1},{0x007E,'N',0xD1}, + {0x007E,'o',0xF5},{0x007E,'O',0xD5}, + // breve + {0x02D8,'a',0x103},{0x02D8,'A',0x102},{0x02D8,'g',0x11F},{0x02D8,'G',0x11E}, + // ogonek + {0x02DB,'a',0x105},{0x02DB,'A',0x104},{0x02DB,'e',0x119},{0x02DB,'E',0x118}, + {0x02DB,'i',0x12F},{0x02DB,'I',0x12E},{0x02DB,'u',0x173},{0x02DB,'U',0x172}, + // dot above + {0x02D9,'z',0x17C},{0x02D9,'Z',0x17B},{0x02D9,'e',0x117},{0x02D9,'E',0x116}, + {0x02D9,'I',0x130}, + // double acute + {0x02DD,'o',0x151},{0x02DD,'O',0x150},{0x02DD,'u',0x171},{0x02DD,'U',0x170}, + // cedilla + {0x00B8,'c',0xE7},{0x00B8,'C',0xC7},{0x00B8,'s',0x15F},{0x00B8,'S',0x15E}, +}; + +// The composed character, or 0 if the accent does not combine with base. +inline uint32_t compose(uint32_t dead, uint32_t base) { + for (const ComposeEntry& e : COMPOSE) + if (e.dead == dead && e.base == base) return e.result; + return 0; +} + inline void build_key(char* out, int cap, const char* prefix, const char* id, const char* suffix = nullptr) { int pos = 0; @@ -54,10 +124,9 @@ inline void build_key(char* out, int cap, const char* prefix, out[pos] = '\0'; } -// Read an array of byte values from the layout table. +// Read an array of byte values (scancodes) from the layout table. // Returns the element count, or -1 if the key is missing or malformed. -inline int read_bytes(const toml::Doc& doc, const char* key, - uint8_t* out, int cap) { +inline int read_bytes(const toml::Doc& doc, const char* key, uint8_t* out, int cap) { toml::Value* arr = doc.get_array(key); if (!arr) return -1; if (arr->array.count > cap) return -1; @@ -70,6 +139,23 @@ inline int read_bytes(const toml::Doc& doc, const char* key, return arr->array.count; } +// Read an array of characters (Unicode codepoints). 0x80-0x9F are C1 control +// codes in Unicode, never key output, so they are read as the Windows-1252 +// bytes older layout files used (0x80 = euro sign). +inline int read_codepoints(const toml::Doc& doc, const char* key, uint32_t* out, int cap) { + toml::Value* arr = doc.get_array(key); + if (!arr) return -1; + if (arr->array.count > cap) return -1; + for (int i = 0; i < arr->array.count; i++) { + toml::Value* value = arr->array.items[i]; + if (!value || value->type != toml::Type::Int) return -1; + int64_t v = value->ival; + if (v < 0 || v > 0x10FFFF || (v >= 0xD800 && v <= 0xDFFF)) return -1; + out[i] = (v >= 0x80 && v <= 0x9F) ? utf8::from_cp1252((uint8_t)v) : (uint32_t)v; + } + return arr->array.count; +} + // Parse one [layouts.] table. Returns false if the layout declares key // overrides but they are inconsistent, in which case the caller skips it: a // malformed table must never produce a half-applied layout. @@ -85,10 +171,15 @@ inline bool load_layout(Layout* out, const char* id, const toml::Doc& doc) { montauk::strncpy(out->short_name, doc.get_string(key, id), sizeof(out->short_name)); - uint8_t scancodes[MAX_KEYS]; - uint8_t base[MAX_KEYS]; - uint8_t shift[MAX_KEYS]; - uint8_t altgr[MAX_KEYS] = {}; + build_key(key, sizeof(key), "layouts.", id, ".dead_keys"); + int dead = read_codepoints(doc, key, out->dead_keys, MAX_DEAD_KEYS); + if (dead < 0 && doc.get_array(key)) return false; // present but malformed + out->dead_count = dead < 0 ? 0 : dead; + + uint8_t scancodes[MAX_KEYS]; + uint32_t base[MAX_KEYS]; + uint32_t shift[MAX_KEYS]; + uint32_t altgr[MAX_KEYS] = {}; build_key(key, sizeof(key), "layouts.", id, ".scancodes"); int count = read_bytes(doc, key, scancodes, MAX_KEYS); @@ -99,11 +190,11 @@ inline bool load_layout(Layout* out, const char* id, const toml::Doc& doc) { } build_key(key, sizeof(key), "layouts.", id, ".base"); - if (read_bytes(doc, key, base, MAX_KEYS) != count) return false; + if (read_codepoints(doc, key, base, MAX_KEYS) != count) return false; build_key(key, sizeof(key), "layouts.", id, ".shift"); - if (read_bytes(doc, key, shift, MAX_KEYS) != count) return false; + if (read_codepoints(doc, key, shift, MAX_KEYS) != count) return false; build_key(key, sizeof(key), "layouts.", id, ".altgr"); - int altgr_count = read_bytes(doc, key, altgr, MAX_KEYS); + int altgr_count = read_codepoints(doc, key, altgr, MAX_KEYS); if (altgr_count >= 0 && altgr_count != count) return false; for (int i = 0; i < count; i++) { @@ -174,6 +265,7 @@ inline Registry load_registry() { // it reads one small file instead of re-parsing the whole layout table. inline void refresh_selection(State* state, const char* username) { if (!state) return; + state->pending_dead = 0; // a dead key never carries over a layout switch for (int i = 0; i < state->registry.count; i++) state->enabled[i] = false; toml::Doc doc = config::load_user(username, "keyboard"); @@ -237,57 +329,117 @@ inline int next_enabled(const State& state, int current) { } // Caps Lock is derived rather than declared per key: it applies only where -// base and shift are a Windows-1252 lower/upper letter pair. That covers the -// accented letters (aa 0xE5 / AA 0xC5) without wrongly upper-casing keys such -// as 2 / " where the shifted value is unrelated punctuation. -inline constexpr bool is_letter_pair(uint8_t base, uint8_t shift) { +// base and shift are the lower/upper case of one letter. That covers accented +// letters in any script (aa/AA, e-caron/E-caron) without wrongly upper-casing +// keys such as 2 / " where the shifted value is unrelated punctuation. +inline constexpr bool is_letter_pair(uint32_t base, uint32_t shift) { if (base == 0 || shift == 0) return false; - if (base < 0x61) return false; - if (base > 0x7A && base < 0xE0) return false; - if (base == 0xF7) return false; // division sign sits inside the range - return shift == (uint8_t)(base - 0x20); + return utf8::is_case_pair(base, shift); } -static_assert(is_letter_pair(0xE5, 0xC5)); // aa / AA -static_assert(is_letter_pair(0xF8, 0xD8)); // oe / OE -static_assert(is_letter_pair(0xE6, 0xC6)); // ae / AE +static_assert(is_letter_pair(0xE5, 0xC5)); // aa / AA +static_assert(is_letter_pair(0xF8, 0xD8)); // oe / OE +static_assert(is_letter_pair(0x11B, 0x11A)); // e-caron static_assert(is_letter_pair('a', 'A')); static_assert(!is_letter_pair('2', '"')); -static_assert(!is_letter_pair(0xF7, 0xD7)); // divide / multiply +static_assert(!is_letter_pair(0xF7, 0xD7)); // divide / multiply +static_assert(!is_letter_pair(0x11B, '2')); // Czech number row -inline void translate(const State& state, abi::KeyEvent* key) { +inline bool is_dead_key(const Layout& layout, uint32_t cp) { + if (cp == 0) return false; + for (int i = 0; i < layout.dead_count; i++) + if (layout.dead_keys[i] == cp) return true; + return false; +} + +// Keys that may be pressed between a dead key and its letter without +// cancelling it (Shift for a capital, AltGr, Caps Lock, ...). +inline constexpr bool is_modifier_scancode(uint8_t sc) { + return sc == 0x2A || sc == 0x36 || sc == 0x1D || sc == 0x38 || + sc == 0x3A || sc == 0x45 || sc == 0x46 || sc == 0x5B || sc == 0x5C; +} + +// Apply the active layout to a raw key event: the character it types goes to +// key->codepoint, its Windows-1252 byte (or KEY_ASCII_SUBSTITUTE) to +// key->ascii. Dead keys type nothing and modify the following character, so +// the state is updated on presses. +inline void translate(State& state, abi::KeyEvent* key) { if (!key) return; - if (state.active < 0 || state.active >= state.registry.count) return; - const Layout& layout = state.registry.items[state.active]; + const Layout* layout = (state.active >= 0 && state.active < state.registry.count) + ? &state.registry.items[state.active] : nullptr; + + uint8_t a = (uint8_t)key->ascii; + uint32_t cp = key->codepoint ? key->codepoint + : ((a >= 0x20 && a < 0x7F) ? a : 0); + uint8_t scancode = key->scancode & 0x7F; // Extended keys carry a main-block scancode with the E0 prefix stripped // (keypad "/" arrives as 0x35, the same as the main "/"), so translating // them would turn keypad "/" into whatever the layout puts on that key. - if (key->extended) return; + if (layout && !key->extended) { + for (int i = 0; i < layout->key_count; i++) { + const KeyMap& mapping = layout->keys[i]; + if (mapping.scancode != scancode) continue; - uint8_t scancode = key->scancode & 0x7F; - for (int i = 0; i < layout.key_count; i++) { - const KeyMap& mapping = layout.keys[i]; - if (mapping.scancode != scancode) continue; + uint32_t out; + if (key->altgr) { + out = mapping.altgr; + } else { + bool upper = key->shift; + if (is_letter_pair(mapping.base, mapping.shift)) + upper = key->shift != key->capslock; + out = upper ? mapping.shift : mapping.base; + } + if (out != 0) { + cp = out; + // An AltGr key that produced a character is text, not a + // shortcut. Apps gate insertion on !alt (and alt is + // LeftAlt||RightAlt), so leaving it set would silently swallow + // every AltGr character. + if (key->altgr) key->alt = false; + } + break; + } + } - uint8_t out; - if (key->altgr) { - out = mapping.altgr; - } else { - bool upper = key->shift; - if (is_letter_pair(mapping.base, mapping.shift)) - upper = key->shift != key->capslock; - out = upper ? mapping.shift : mapping.base; - } - if (out != 0) { - key->ascii = (char)out; - // An AltGr key that produced a character is text, not a shortcut. - // Apps gate insertion on !alt (and alt is LeftAlt||RightAlt), so - // leaving it set would silently swallow every AltGr character. - if (key->altgr) key->alt = false; + bool dead = layout && !key->extended && is_dead_key(*layout, cp); + bool shortcut = key->ctrl || (key->alt && !key->altgr); + if (dead && shortcut) dead = false; + + if (key->pressed && !shortcut) { + if (dead) { + if (state.pending_dead == cp) { + state.pending_dead = 0; // pressed twice: type the accent + dead = false; + } else { + state.pending_dead = cp; // wait for the next character + } + } else if (state.pending_dead) { + if (cp == ' ') { + cp = state.pending_dead; // accent + Space: the accent + state.pending_dead = 0; + } else if (cp) { + // The composed letter, or just the letter when the accent does + // not apply to it (one event can only carry one character). + uint32_t composed = compose(state.pending_dead, cp); + if (composed) cp = composed; + state.pending_dead = 0; + } else if (!is_modifier_scancode(scancode)) { + state.pending_dead = 0; // Enter, arrows, ... cancel it + } } + } + + if (dead) { + key->codepoint = 0; + key->ascii = 0; return; } + key->codepoint = cp; + if (cp != 0) { + uint8_t b = utf8::to_cp1252(cp); + key->ascii = b ? (char)b : abi::KEY_ASCII_SUBSTITUTE; + } } // ---- Direct keyboard readers ---- diff --git a/programs/include/montauk/statuscodes.h b/programs/include/montauk/statuscodes.h index 3c6acbf..e91813a 100644 --- a/programs/include/montauk/statuscodes.h +++ b/programs/include/montauk/statuscodes.h @@ -56,27 +56,28 @@ inline const char* GetStatusText(StatusCode statusCode) { } } +// Shared with C (libc.c), so no nullptr. inline const char* GetStatusExplanationText(StatusCode statusCode) { const char* explanationText[] = { - nullptr, // 0 - nullptr, // 1 - nullptr, // 2 - nullptr, // 3 + 0, // 0 + 0, // 1 + 0, // 2 + 0, // 3 "The path is protected by the system and cannot be modified.", // 4 - nullptr, // 5 - nullptr, // 6 - nullptr, // 7 - nullptr, // 8 - nullptr, // 9 - nullptr, // 10 - nullptr, // 11 - nullptr, // 12 + 0, // 5 + 0, // 6 + 0, // 7 + 0, // 8 + 0, // 9 + 0, // 10 + 0, // 11 + 0, // 12 "The buffer supplied by the caller is too small.", // 13 - nullptr, // 14 + 0, // 14 }; if (statusCode > 0 && statusCode <= 14) { - if (explanationText[statusCode] != nullptr) { + if (explanationText[statusCode] != 0) { return explanationText[statusCode]; } } diff --git a/programs/include/montauk/syscall.h b/programs/include/montauk/syscall.h index 5c9c188..b2ac9a1 100644 --- a/programs/include/montauk/syscall.h +++ b/programs/include/montauk/syscall.h @@ -7,6 +7,7 @@ #pragma once #include #include +#include namespace montauk { @@ -222,7 +223,23 @@ namespace montauk { // Keyboard inline bool is_key_available() { return (bool)syscall0(montauk::abi::SYS_ISKEYAVAILABLE); } - inline void getkey(montauk::abi::KeyEvent* out) { syscall1(montauk::abi::SYS_GETKEY, (uint64_t)out); } + // Scancode to use when checking for navigation keys (arrows, Home/End, + // PgUp/PgDn, Insert/Delete). The keypad shares those scancodes with its + // digit and '.' keys, so a keypad key that types a character reports 0 + // here: numpad 4 is text, not Left. Compare against this, not .scancode. + inline uint8_t nav_scancode(const montauk::abi::KeyEvent& key) { + uint8_t sc = key.scancode; + if (!key.extended && (sc & 0x7F) >= 0x47 && (sc & 0x7F) <= 0x53 && + montauk::utf8::key_codepoint(key) != 0) + return 0; + return sc; + } + + // Fills the full event, including the Unicode codepoint the key types. + inline void getkey(montauk::abi::KeyEvent* out) { + syscall2(montauk::abi::SYS_GETKEY_EX, (uint64_t)out, sizeof(*out)); + } + // Text keys arrive as UTF-8, one byte per call. inline char getchar() { return (char)syscall0(montauk::abi::SYS_GETCHAR); } // Returns 0 rather than blocking when no character is pending. inline char getchar_nb() { return (char)syscall0(montauk::abi::SYS_GETCHAR_NB); } @@ -496,7 +513,8 @@ namespace montauk { return (int)syscall3(montauk::abi::SYS_CHILDIO_WRITE, (uint64_t)childPid, (uint64_t)data, (uint64_t)len); } inline int childio_writekey(int childPid, const montauk::abi::KeyEvent* key) { - return (int)syscall2(montauk::abi::SYS_CHILDIO_WRITEKEY, (uint64_t)childPid, (uint64_t)key); + return (int)syscall3(montauk::abi::SYS_CHILDIO_WRITEKEY_EX, (uint64_t)childPid, + (uint64_t)key, sizeof(*key)); } inline int childio_settermsz(int childPid, int cols, int rows) { return (int)syscall3(montauk::abi::SYS_CHILDIO_SETTERMSZ, (uint64_t)childPid, (uint64_t)cols, (uint64_t)rows); diff --git a/programs/include/montauk/user.h b/programs/include/montauk/user.h index efff1e0..855d0a7 100644 --- a/programs/include/montauk/user.h +++ b/programs/include/montauk/user.h @@ -9,6 +9,7 @@ #include #include #include +#include #include namespace montauk { @@ -107,7 +108,7 @@ namespace user { bytes_to_hex(hash, 32, out_hex64); } - inline bool verify_password(const char* password, const char* salt_hex, const char* stored_hex64) { + inline bool verify_password_bytes(const char* password, const char* salt_hex, const char* stored_hex64) { char computed[65]; hash_password(password, salt_hex, computed); @@ -118,6 +119,26 @@ namespace user { return diff == 0; } + // Passwords are hashed as UTF-8. Before the switch to UTF-8, password + // fields stored typed characters as Windows-1252 bytes, so a non-ASCII + // password set back then only matches its 1252 form; try that too. + inline bool verify_password(const char* password, const char* salt_hex, const char* stored_hex64) { + if (verify_password_bytes(password, salt_hex, stored_hex64)) return true; + + char legacy[256]; + int o = 0; + bool non_ascii = false; + for (const char* p = password; *p;) { + uint32_t cp = montauk::utf8::next(&p); + uint8_t b = montauk::utf8::to_cp1252(cp); + if (b == 0 || o >= (int)sizeof(legacy) - 1) return false; + if (b >= 0x80) non_ascii = true; + legacy[o++] = (char)b; + } + legacy[o] = '\0'; + return non_ascii && verify_password_bytes(legacy, salt_hex, stored_hex64); + } + // ---- User database I/O ---- inline int load_users(UserInfo* buf, int max) { diff --git a/programs/include/montauk/utf8.h b/programs/include/montauk/utf8.h new file mode 100644 index 0000000..dae0f33 --- /dev/null +++ b/programs/include/montauk/utf8.h @@ -0,0 +1,399 @@ +/* + * utf8.h + * UTF-8 text encoding helpers with a Windows-1252 fallback + * Copyright (c) 2026 Daniel Hammer + */ + +#pragma once + +#include + +// MontaukOS text is UTF-8. Before this it was single-byte Windows-1252, so +// older files (and anything else that is not valid UTF-8) still turn up. The +// decoder never fails: a byte that does not start a well-formed sequence is +// read as ONE Windows-1252 character. Valid UTF-8 and plain ASCII are +// unaffected, and legacy text keeps rendering exactly as it used to. +// +// Character boundaries follow the same rule, so cursor movement, deletion and +// truncation all agree with what the renderer draws. + +namespace montauk::utf8 { + +inline constexpr uint32_t REPLACEMENT = 0xFFFD; +inline constexpr int MAX_BYTES = 4; + +// Windows-1252 byte -> Unicode codepoint. 0x80-0x9F carry the typographic +// punctuation; every other byte is identical to Latin-1 / Unicode. +inline constexpr uint32_t from_cp1252(uint8_t b) { + switch (b) { + case 0x80: return 0x20AC; // Euro Sign + case 0x82: return 0x201A; // Single Low-9 Quotation Mark + case 0x83: return 0x0192; // Latin Small Letter F With Hook + case 0x84: return 0x201E; // Double Low-9 Quotation Mark + case 0x85: return 0x2026; // Horizontal Ellipsis + case 0x86: return 0x2020; // Dagger + case 0x87: return 0x2021; // Double Dagger + case 0x88: return 0x02C6; // Modifier Letter Circumflex Accent + case 0x89: return 0x2030; // Per Mille Sign + case 0x8A: return 0x0160; // Latin Capital Letter S With Caron + case 0x8B: return 0x2039; // Single Left-Pointing Angle Quotation Mark + case 0x8C: return 0x0152; // Latin Capital Ligature OE + case 0x8E: return 0x017D; // Latin Capital Letter Z With Caron + case 0x91: return 0x2018; // Left Single Quotation Mark + case 0x92: return 0x2019; // Right Single Quotation Mark + case 0x93: return 0x201C; // Left Double Quotation Mark + case 0x94: return 0x201D; // Right Double Quotation Mark + case 0x95: return 0x2022; // Bullet + case 0x96: return 0x2013; // En Dash + case 0x97: return 0x2014; // Em Dash + case 0x98: return 0x02DC; // Small Tilde + case 0x99: return 0x2122; // Trade Mark Sign + case 0x9A: return 0x0161; // Latin Small Letter S With Caron + case 0x9B: return 0x203A; // Single Right-Pointing Angle Quotation Mark + case 0x9C: return 0x0153; // Latin Small Ligature OE + case 0x9E: return 0x017E; // Latin Small Letter Z With Caron + case 0x9F: return 0x0178; // Latin Capital Letter Y With Diaeresis + default: return b; + } +} + +// Unicode codepoint -> Windows-1252 byte, or 0 if it has none. Used where a +// single byte is still required (PDF WinAnsi output, legacy byte tables). +inline constexpr uint8_t to_cp1252(uint32_t cp) { + if (cp < 0x80 || (cp >= 0xA0 && cp <= 0xFF)) return (uint8_t)cp; + for (int b = 0x80; b <= 0x9F; b++) { + uint32_t m = from_cp1252((uint8_t)b); + if (m != (uint32_t)b && m == cp) return (uint8_t)b; + } + return 0; +} + +// Length of the well-formed UTF-8 sequence starting at s (at most `avail` +// bytes, stopping early at a NUL), or 0 if it is not one. Rejects overlong +// forms, surrogates and values above U+10FFFF. +inline int sequence_length(const char* s, int avail, uint32_t* out_cp = nullptr) { + if (avail <= 0) return 0; + const uint8_t* u = (const uint8_t*)s; + uint8_t b0 = u[0]; + if (b0 < 0x80) { + if (out_cp) *out_cp = b0; + return 1; + } + + int n; + uint32_t cp, min; + if (b0 >= 0xC2 && b0 <= 0xDF) { n = 2; cp = b0 & 0x1F; min = 0x80; } + else if (b0 >= 0xE0 && b0 <= 0xEF) { n = 3; cp = b0 & 0x0F; min = 0x800; } + else if (b0 >= 0xF0 && b0 <= 0xF4) { n = 4; cp = b0 & 0x07; min = 0x10000; } + else return 0; + + if (n > avail) return 0; + for (int i = 1; i < n; i++) { + uint8_t c = u[i]; + if ((c & 0xC0) != 0x80) return 0; // also catches NUL + cp = (cp << 6) | (c & 0x3F); + } + if (cp < min || cp > 0x10FFFF || (cp >= 0xD800 && cp <= 0xDFFF)) return 0; + if (out_cp) *out_cp = cp; + return n; +} + +// Decode one character from a buffer of `avail` bytes. Returns the codepoint +// and stores the number of bytes consumed (always >= 1 when avail > 0). +inline uint32_t decode(const char* s, int avail, int* consumed) { + if (avail <= 0) { if (consumed) *consumed = 0; return 0; } + uint32_t cp; + int n = sequence_length(s, avail, &cp); + if (n == 0) { + n = 1; + cp = from_cp1252((uint8_t)s[0]); + } + if (consumed) *consumed = n; + return cp; +} + +// Decode one character from a NUL-terminated string and advance *p past it. +// Returns 0 (without advancing) at the terminator. +inline uint32_t next(const char** p) { + const char* s = *p; + if (!*s) return 0; + int n; + // A sequence never spans the terminator: sequence_length stops at NUL + // because NUL is not a continuation byte. + uint32_t cp = decode(s, MAX_BYTES, &n); + *p = s + n; + return cp; +} + +// Encode a codepoint as UTF-8 into out (room for 4 bytes, NOT terminated). +// Returns the byte count. Invalid codepoints encode U+FFFD. +inline int encode(uint32_t cp, char* out) { + if (cp > 0x10FFFF || (cp >= 0xD800 && cp <= 0xDFFF)) cp = REPLACEMENT; + uint8_t* o = (uint8_t*)out; + if (cp < 0x80) { o[0] = (uint8_t)cp; return 1; } + if (cp < 0x800) { + o[0] = (uint8_t)(0xC0 | (cp >> 6)); + o[1] = (uint8_t)(0x80 | (cp & 0x3F)); + return 2; + } + if (cp < 0x10000) { + o[0] = (uint8_t)(0xE0 | (cp >> 12)); + o[1] = (uint8_t)(0x80 | ((cp >> 6) & 0x3F)); + o[2] = (uint8_t)(0x80 | (cp & 0x3F)); + return 3; + } + o[0] = (uint8_t)(0xF0 | (cp >> 18)); + o[1] = (uint8_t)(0x80 | ((cp >> 12) & 0x3F)); + o[2] = (uint8_t)(0x80 | ((cp >> 6) & 0x3F)); + o[3] = (uint8_t)(0x80 | (cp & 0x3F)); + return 4; +} + +inline int encoded_length(uint32_t cp) { + if (cp > 0x10FFFF || (cp >= 0xD800 && cp <= 0xDFFF)) return 3; // U+FFFD + return cp < 0x80 ? 1 : cp < 0x800 ? 2 : cp < 0x10000 ? 3 : 4; +} + +// ==== Case mapping ==== +// Simple one-to-one case mapping for the scripts MontaukOS keyboard layouts +// cover: ASCII, Latin-1, Latin Extended-A, Greek and Cyrillic. Anything else +// is returned unchanged. + +inline constexpr uint32_t to_upper(uint32_t c) { + if (c >= 'a' && c <= 'z') return c - 0x20; + if (c < 0x80) return c; + if (c >= 0xE0 && c <= 0xFE && c != 0xF7) return c - 0x20; + if (c == 0xFF) return 0x178; + if (c == 0xB5) return 0x39C; // micro -> Mu + // Latin Extended-A: pairs alternate upper/lower, except the two ranges + // where the alignment shifts by one (L-stroke..N-apostrophe, Z-acute..). + if (c == 0x131) return 'I'; // dotless i + if (c >= 0x100 && c <= 0x137 && c != 0x130) return (c & 1) ? c - 1 : c; + if (c >= 0x139 && c <= 0x148) return (c & 1) ? c : c - 1; + if (c >= 0x14A && c <= 0x177) return (c & 1) ? c - 1 : c; + if (c >= 0x179 && c <= 0x17E) return (c & 1) ? c : c - 1; + if (c == 0x17F) return 'S'; // long s + // Greek + if (c >= 0x3B1 && c <= 0x3C9 && c != 0x3C2) return c - 0x20; + if (c == 0x3C2) return 0x3A3; // final sigma + if (c == 0x3AC) return 0x386; + if (c >= 0x3AD && c <= 0x3AF) return c - 0x25; + if (c == 0x3CC) return 0x38C; + if (c == 0x3CD || c == 0x3CE) return c - 0x3F; + // Cyrillic + if (c >= 0x430 && c <= 0x44F) return c - 0x20; + if (c >= 0x450 && c <= 0x45F) return c - 0x50; + return c; +} + +inline constexpr uint32_t to_lower(uint32_t c) { + if (c >= 'A' && c <= 'Z') return c + 0x20; + if (c < 0x80) return c; + if (c >= 0xC0 && c <= 0xDE && c != 0xD7) return c + 0x20; + if (c == 0x178) return 0xFF; + if (c == 0x130) return 'i'; // dotted I + if (c >= 0x100 && c <= 0x137) return (c & 1) ? c : c + 1; + if (c >= 0x139 && c <= 0x148) return (c & 1) ? c + 1 : c; + if (c >= 0x14A && c <= 0x177) return (c & 1) ? c : c + 1; + if (c >= 0x179 && c <= 0x17E) return (c & 1) ? c + 1 : c; + if (c >= 0x391 && c <= 0x3A9 && c != 0x3A2) return c + 0x20; + if (c == 0x386) return 0x3AC; + if (c >= 0x388 && c <= 0x38A) return c + 0x25; + if (c == 0x38C) return 0x3CC; + if (c == 0x38E || c == 0x38F) return c + 0x3F; + if (c >= 0x410 && c <= 0x42F) return c + 0x20; + if (c >= 0x400 && c <= 0x40F) return c + 0x50; + return c; +} + +// True if lower/upper are the two cases of one letter. +inline constexpr bool is_case_pair(uint32_t lower, uint32_t upper) { + return lower != upper && to_upper(lower) == upper && to_lower(upper) == lower; +} + +// Text a key event types, as a codepoint (0 for control/non-text keys). +// KeyEvent::codepoint is filled by the kernel and by layout translation; +// events built by hand may leave it 0, so fall back to `ascii` (a +// Windows-1252 byte). +template +inline uint32_t key_codepoint(const Key& key) { + if (key.codepoint) { + uint32_t cp = key.codepoint; + return (cp < 0x20 || cp == 0x7F || (cp >= 0x80 && cp < 0xA0)) ? 0 : cp; + } + uint8_t b = (uint8_t)key.ascii; + if (b < 0x20 || b == 0x7F) return 0; + return from_cp1252(b); +} + +// Same, encoded as UTF-8 into out (4 bytes). Returns the length, 0 if none. +template +inline int key_utf8(const Key& key, char* out) { + uint32_t cp = key_codepoint(key); + return cp ? encode(cp, out) : 0; +} + +// Byte offset of the character after the one at `pos` (len = buffer length). +inline int next_boundary(const char* s, int len, int pos) { + if (pos >= len) return len; + if (pos < 0) return 0; + int n; + decode(s + pos, len - pos, &n); + return pos + n; +} + +// Byte offset of the character before `pos`. A run of continuation bytes is +// one character only if it completes a well-formed sequence ending exactly at +// pos; otherwise the previous byte stands alone (Windows-1252 fallback). +inline int prev_boundary(const char* s, int pos) { + if (pos <= 0) return 0; + for (int back = 2; back <= MAX_BYTES && back <= pos; back++) { + if (((uint8_t)s[pos - back + 1] & 0xC0) != 0x80) break; + int start = pos - back; + if (sequence_length(s + start, back) == back) return start; + } + return pos - 1; +} + +// Snap `pos` back onto a character boundary. Use before truncating a buffer +// or splitting at an arbitrary byte offset. +inline int floor_boundary(const char* s, int len, int pos) { + if (pos <= 0) return 0; + if (pos >= len) return len; + if (((uint8_t)s[pos] & 0xC0) != 0x80) return pos; + // pos is a continuation byte: it is inside a character only if a + // well-formed sequence starting up to 3 bytes earlier covers it. + for (int back = 1; back < MAX_BYTES && back <= pos; back++) { + int start = pos - back; + int n = sequence_length(s + start, len - start); + if (n > back) return start; + if (((uint8_t)s[start] & 0xC0) != 0x80) break; + } + return pos; +} + +// Number of characters in a NUL-terminated string. +inline int count(const char* s) { + int n = 0; + while (*s) { next(&s); n++; } + return n; +} + +// Number of characters in the first `len` bytes. +inline int count(const char* s, int len) { + int n = 0, pos = 0; + while (pos < len) { pos = next_boundary(s, len, pos); n++; } + return n; +} + +// Byte offset of the `index`th character (clamped to len). +inline int offset_of(const char* s, int len, int index) { + int pos = 0; + while (index-- > 0 && pos < len) pos = next_boundary(s, len, pos); + return pos; +} + +// True if the buffer is entirely well-formed UTF-8. +inline bool valid(const char* s, int len) { + for (int pos = 0; pos < len;) { + int n = sequence_length(s + pos, len - pos); + if (n == 0) return false; + pos += n; + } + return true; +} + +// Rewrite a buffer as well-formed UTF-8 (each stray byte becomes the +// character the Windows-1252 fallback would display). Returns the output +// length, truncated on a character boundary to fit cap - 1, NUL-terminated. +inline int normalize(const char* in, int len, char* out, int cap) { + if (cap <= 0) return 0; + int o = 0; + for (int pos = 0; pos < len;) { + int n; + uint32_t cp = decode(in + pos, len - pos, &n); + int need = encoded_length(cp); + if (o + need > cap - 1) break; + o += encode(cp, out + o); + pos += n; + } + out[o] = '\0'; + return o; +} + +// Copy src into dst (cap bytes incl. NUL) without splitting a character. +inline int copy(char* dst, int cap, const char* src) { + if (cap <= 0) return 0; + int len = 0; + while (src[len]) len++; + int n = len < cap - 1 ? len : floor_boundary(src, len, cap - 1); + for (int i = 0; i < n; i++) dst[i] = src[i]; + dst[n] = '\0'; + return n; +} + +// ==== Editing a NUL-terminated buffer with a byte cursor ==== +// `len` is the current length, `cap` the buffer size including the NUL. The +// cursor is a byte offset that is always kept on a character boundary. + +// Insert n bytes at *cursor. Returns false (buffer unchanged) if they don't fit. +inline bool insert(char* buf, int* len, int cap, int* cursor, + const char* s, int n) { + if (n <= 0 || *len + n >= cap) return false; + int at = *cursor < 0 ? 0 : (*cursor > *len ? *len : *cursor); + for (int i = *len; i >= at; i--) buf[i + n] = buf[i]; // moves the NUL + for (int i = 0; i < n; i++) buf[at + i] = s[i]; + *len += n; + *cursor = at + n; + return true; +} + +// Insert the text a key event types. Returns false if it types nothing or +// does not fit. +template +inline bool insert_key(char* buf, int* len, int cap, int* cursor, const Key& key) { + char t[MAX_BYTES]; + int n = key_utf8(key, t); + return n > 0 && insert(buf, len, cap, cursor, t, n); +} + +// Remove the bytes [start, end). +inline void erase(char* buf, int* len, int start, int end) { + if (start < 0) start = 0; + if (end > *len) end = *len; + if (start >= end) return; + int n = end - start; + for (int i = start; i + n <= *len; i++) buf[i] = buf[i + n]; // moves the NUL + *len -= n; +} + +// Backspace: delete the character before the cursor. +inline bool erase_before(char* buf, int* len, int* cursor) { + if (*cursor <= 0) return false; + int start = prev_boundary(buf, *cursor); + erase(buf, len, start, *cursor); + *cursor = start; + return true; +} + +// Delete: remove the character at the cursor. +inline bool erase_at(char* buf, int* len, int cursor) { + if (cursor >= *len) return false; + erase(buf, len, cursor, next_boundary(buf, *len, cursor)); + return true; +} + +// Append typed text at the end (simple line inputs without a cursor). +template +inline bool append_key(char* buf, int* len, int cap, const Key& key) { + int cursor = *len; + return insert_key(buf, len, cap, &cursor, key); +} + +// Backspace for append-only inputs: drop the last character. +inline bool erase_last(char* buf, int* len) { + int cursor = *len; + return erase_before(buf, len, &cursor); +} + +} // namespace montauk::utf8 diff --git a/programs/lib/libc/libc.c b/programs/lib/libc/libc.c index 52b63d8..a3bbc03 100644 --- a/programs/lib/libc/libc.c +++ b/programs/lib/libc/libc.c @@ -1712,7 +1712,10 @@ static int _stdin_pump(int block) { for (;;) { int c = block ? (int)_mtk_syscall0(SYS_GETCHAR) : (int)_mtk_syscall0(SYS_GETCHAR_NB); - if (c <= 0) { + /* The syscall returns a sign-extended char: bytes >= 0x80 arrive + negative and are real keys, only 0 means "nothing". */ + if (c < 0) c &= 0xFF; + if (c == 0) { if (block) continue; return 0; } @@ -1721,12 +1724,26 @@ static int _stdin_pump(int block) { if (c == '\b' || c == 127) { if (_stdin_line_len > 0) { + /* Drop the whole UTF-8 character: its continuation bytes, + then the lead byte. One terminal cell either way. */ + while (_stdin_line_len > 1 && + ((unsigned char)_stdin_linebuf[_stdin_line_len - 1] & 0xC0) == 0x80) + _stdin_line_len--; _stdin_line_len--; _stdin_echo_char('\b'); } continue; } + /* Bytes >= 0x80 are UTF-8: the kernel encodes typed characters, and + piped input is UTF-8 already. They are stored and echoed as-is. */ + if (c >= 0x80) { + if (_stdin_line_len + 2 >= sizeof(_stdin_linebuf)) continue; + _stdin_linebuf[_stdin_line_len++] = (char)c; + _stdin_echo_char((char)c); + continue; + } + if (c == '\n') { _stdin_linebuf[_stdin_line_len++] = (char)c; _stdin_echo_char((char)c); diff --git a/programs/src/2048/main.cpp b/programs/src/2048/main.cpp index 26942fb..01c6831 100644 --- a/programs/src/2048/main.cpp +++ b/programs/src/2048/main.cpp @@ -466,13 +466,13 @@ static bool handle_key(const montauk::abi::KeyEvent& key) { if (g_game.game_over) return false; - if (key.scancode == 0x4B || key.ascii == 'a' || key.ascii == 'A') + if (montauk::nav_scancode(key) == 0x4B || key.ascii == 'a' || key.ascii == 'A') return apply_move(DIR_LEFT); - if (key.scancode == 0x4D || key.ascii == 'd' || key.ascii == 'D') + if (montauk::nav_scancode(key) == 0x4D || key.ascii == 'd' || key.ascii == 'D') return apply_move(DIR_RIGHT); - if (key.scancode == 0x48 || key.ascii == 'w' || key.ascii == 'W') + if (montauk::nav_scancode(key) == 0x48 || key.ascii == 'w' || key.ascii == 'W') return apply_move(DIR_UP); - if (key.scancode == 0x50 || key.ascii == 's' || key.ascii == 'S') + if (montauk::nav_scancode(key) == 0x50 || key.ascii == 's' || key.ascii == 'S') return apply_move(DIR_DOWN); return false; diff --git a/programs/src/audio/main.cpp b/programs/src/audio/main.cpp index d13b3e9..9589696 100644 --- a/programs/src/audio/main.cpp +++ b/programs/src/audio/main.cpp @@ -469,12 +469,12 @@ static bool handle_key(const montauk::abi::KeyEvent& key) { g_win.closed = true; return false; } - if (key.scancode == 0x4D || key.ascii == '+' || key.ascii == '=') { + if (montauk::nav_scancode(key) == 0x4D || key.ascii == '+' || key.ascii == '=') { if (g_master_muted) toggle_master_mute(); apply_master_volume(g_master_vol + 5); return true; } - if (key.scancode == 0x4B || key.ascii == '-') { + if (montauk::nav_scancode(key) == 0x4B || key.ascii == '-') { if (g_master_muted) toggle_master_mute(); apply_master_volume(g_master_vol - 5); return true; diff --git a/programs/src/bluetooth/main.cpp b/programs/src/bluetooth/main.cpp index 8ee7b5e..c849d6a 100644 --- a/programs/src/bluetooth/main.cpp +++ b/programs/src/bluetooth/main.cpp @@ -224,6 +224,8 @@ static void draw_text_fit(Canvas& c, int x, int y, out++; } + out = montauk::utf8::floor_boundary(text, montauk::slen(text), out); + if (out <= 0) return; buf[out] = '.'; buf[out + 1] = '.'; diff --git a/programs/src/capabilities/main.cpp b/programs/src/capabilities/main.cpp index 722877b..733b855 100644 --- a/programs/src/capabilities/main.cpp +++ b/programs/src/capabilities/main.cpp @@ -400,6 +400,7 @@ static void fit_text(char* out, int outCap, const char* text, int maxWidth) { if (text_width(out) + text_width(ellipsis) > maxWidth) break; len++; } + len = montauk::utf8::floor_boundary(text, montauk::slen(text), len); out[len++] = '.'; out[len++] = '.'; out[len++] = '.'; @@ -798,8 +799,8 @@ static bool handle_key(const montauk::abi::KeyEvent& key) { return true; } int current = *selected_for_tab(); - if (key.scancode == 0x48) { select_index(current - 1); return true; } // Up - if (key.scancode == 0x50) { select_index(current + 1); return true; } // Down + if (montauk::nav_scancode(key) == 0x48) { select_index(current - 1); return true; } // Up + if (montauk::nav_scancode(key) == 0x50) { select_index(current + 1); return true; } // Down if (key.ascii == 'r' || key.ascii == 'R') { reload(); return true; diff --git a/programs/src/charmap/main.cpp b/programs/src/charmap/main.cpp index 4ba870d..955b564 100644 --- a/programs/src/charmap/main.cpp +++ b/programs/src/charmap/main.cpp @@ -5,13 +5,9 @@ * Browse curated sets of characters, click (or use the keyboard) to select, * and copy to the system clipboard for pasting into other apps. * - * Character model: MontaukOS's GUI text stack is single-byte (Windows-1252, - * with the 0x80-0x9F block mapped to typographic punctuation in - * gui::decode_single_byte_codepoint). The glyph cache only holds codepoints - * 0-255, so that byte range is exactly the set of glyphs the system font can - * render. We therefore present that set and copy the *raw byte* to the - * clipboard: it renders identically here and in every other Montauk app - * (copying multi-byte UTF-8 would render as mojibake in the single-byte stack). + * Character model: MontaukOS text is UTF-8. Each tile is a Unicode codepoint + * and Copy puts its UTF-8 encoding on the clipboard. The sets are limited to + * characters the system font (Roboto) actually has a glyph for. * * Copyright (c) 2026 Daniel Hammer */ @@ -37,7 +33,7 @@ using namespace gui; // ==== Character data ==== struct Glyph { - uint8_t byte; // Windows-1252 byte value (what gets copied / rendered) + uint32_t cp; // Unicode codepoint (copied as UTF-8) const char* name; // human-readable description }; @@ -49,141 +45,194 @@ struct CharSet { // Accented Latin letters and ligatures (things you can't easily type). static const Glyph LATIN[] = { - {0xC0, "Latin Capital Letter A With Grave"}, - {0xC1, "Latin Capital Letter A With Acute"}, - {0xC2, "Latin Capital Letter A With Circumflex"}, - {0xC3, "Latin Capital Letter A With Tilde"}, - {0xC4, "Latin Capital Letter A With Diaeresis"}, - {0xC5, "Latin Capital Letter A With Ring Above"}, - {0xC6, "Latin Capital Letter AE"}, - {0xC7, "Latin Capital Letter C With Cedilla"}, - {0xC8, "Latin Capital Letter E With Grave"}, - {0xC9, "Latin Capital Letter E With Acute"}, - {0xCA, "Latin Capital Letter E With Circumflex"}, - {0xCB, "Latin Capital Letter E With Diaeresis"}, - {0xCC, "Latin Capital Letter I With Grave"}, - {0xCD, "Latin Capital Letter I With Acute"}, - {0xCE, "Latin Capital Letter I With Circumflex"}, - {0xCF, "Latin Capital Letter I With Diaeresis"}, - {0xD0, "Latin Capital Letter Eth"}, - {0xD1, "Latin Capital Letter N With Tilde"}, - {0xD2, "Latin Capital Letter O With Grave"}, - {0xD3, "Latin Capital Letter O With Acute"}, - {0xD4, "Latin Capital Letter O With Circumflex"}, - {0xD5, "Latin Capital Letter O With Tilde"}, - {0xD6, "Latin Capital Letter O With Diaeresis"}, - {0xD8, "Latin Capital Letter O With Stroke"}, - {0xD9, "Latin Capital Letter U With Grave"}, - {0xDA, "Latin Capital Letter U With Acute"}, - {0xDB, "Latin Capital Letter U With Circumflex"}, - {0xDC, "Latin Capital Letter U With Diaeresis"}, - {0xDD, "Latin Capital Letter Y With Acute"}, - {0xDE, "Latin Capital Letter Thorn"}, - {0x8A, "Latin Capital Letter S With Caron"}, - {0x8C, "Latin Capital Ligature OE"}, - {0x8E, "Latin Capital Letter Z With Caron"}, - {0x9F, "Latin Capital Letter Y With Diaeresis"}, - {0xDF, "Latin Small Letter Sharp S"}, - {0xE0, "Latin Small Letter A With Grave"}, - {0xE1, "Latin Small Letter A With Acute"}, - {0xE2, "Latin Small Letter A With Circumflex"}, - {0xE3, "Latin Small Letter A With Tilde"}, - {0xE4, "Latin Small Letter A With Diaeresis"}, - {0xE5, "Latin Small Letter A With Ring Above"}, - {0xE6, "Latin Small Letter AE"}, - {0xE7, "Latin Small Letter C With Cedilla"}, - {0xE8, "Latin Small Letter E With Grave"}, - {0xE9, "Latin Small Letter E With Acute"}, - {0xEA, "Latin Small Letter E With Circumflex"}, - {0xEB, "Latin Small Letter E With Diaeresis"}, - {0xEC, "Latin Small Letter I With Grave"}, - {0xED, "Latin Small Letter I With Acute"}, - {0xEE, "Latin Small Letter I With Circumflex"}, - {0xEF, "Latin Small Letter I With Diaeresis"}, - {0xF0, "Latin Small Letter Eth"}, - {0xF1, "Latin Small Letter N With Tilde"}, - {0xF2, "Latin Small Letter O With Grave"}, - {0xF3, "Latin Small Letter O With Acute"}, - {0xF4, "Latin Small Letter O With Circumflex"}, - {0xF5, "Latin Small Letter O With Tilde"}, - {0xF6, "Latin Small Letter O With Diaeresis"}, - {0xF8, "Latin Small Letter O With Stroke"}, - {0xF9, "Latin Small Letter U With Grave"}, - {0xFA, "Latin Small Letter U With Acute"}, - {0xFB, "Latin Small Letter U With Circumflex"}, - {0xFC, "Latin Small Letter U With Diaeresis"}, - {0xFD, "Latin Small Letter Y With Acute"}, - {0xFE, "Latin Small Letter Thorn"}, - {0xFF, "Latin Small Letter Y With Diaeresis"}, - {0x9A, "Latin Small Letter S With Caron"}, - {0x9C, "Latin Small Ligature OE"}, - {0x9E, "Latin Small Letter Z With Caron"}, - {0x83, "Latin Small Letter F With Hook"}, + {0x00C0, "Latin Capital Letter A With Grave"}, + {0x00C1, "Latin Capital Letter A With Acute"}, + {0x00C2, "Latin Capital Letter A With Circumflex"}, + {0x00C3, "Latin Capital Letter A With Tilde"}, + {0x00C4, "Latin Capital Letter A With Diaeresis"}, + {0x00C5, "Latin Capital Letter A With Ring Above"}, + {0x00C6, "Latin Capital Letter AE"}, + {0x00C7, "Latin Capital Letter C With Cedilla"}, + {0x00C8, "Latin Capital Letter E With Grave"}, + {0x00C9, "Latin Capital Letter E With Acute"}, + {0x00CA, "Latin Capital Letter E With Circumflex"}, + {0x00CB, "Latin Capital Letter E With Diaeresis"}, + {0x00CC, "Latin Capital Letter I With Grave"}, + {0x00CD, "Latin Capital Letter I With Acute"}, + {0x00CE, "Latin Capital Letter I With Circumflex"}, + {0x00CF, "Latin Capital Letter I With Diaeresis"}, + {0x00D0, "Latin Capital Letter Eth"}, + {0x00D1, "Latin Capital Letter N With Tilde"}, + {0x00D2, "Latin Capital Letter O With Grave"}, + {0x00D3, "Latin Capital Letter O With Acute"}, + {0x00D4, "Latin Capital Letter O With Circumflex"}, + {0x00D5, "Latin Capital Letter O With Tilde"}, + {0x00D6, "Latin Capital Letter O With Diaeresis"}, + {0x00D8, "Latin Capital Letter O With Stroke"}, + {0x00D9, "Latin Capital Letter U With Grave"}, + {0x00DA, "Latin Capital Letter U With Acute"}, + {0x00DB, "Latin Capital Letter U With Circumflex"}, + {0x00DC, "Latin Capital Letter U With Diaeresis"}, + {0x00DD, "Latin Capital Letter Y With Acute"}, + {0x00DE, "Latin Capital Letter Thorn"}, + {0x0160, "Latin Capital Letter S With Caron"}, + {0x0152, "Latin Capital Ligature OE"}, + {0x017D, "Latin Capital Letter Z With Caron"}, + {0x0178, "Latin Capital Letter Y With Diaeresis"}, + {0x00DF, "Latin Small Letter Sharp S"}, + {0x00E0, "Latin Small Letter A With Grave"}, + {0x00E1, "Latin Small Letter A With Acute"}, + {0x00E2, "Latin Small Letter A With Circumflex"}, + {0x00E3, "Latin Small Letter A With Tilde"}, + {0x00E4, "Latin Small Letter A With Diaeresis"}, + {0x00E5, "Latin Small Letter A With Ring Above"}, + {0x00E6, "Latin Small Letter AE"}, + {0x00E7, "Latin Small Letter C With Cedilla"}, + {0x00E8, "Latin Small Letter E With Grave"}, + {0x00E9, "Latin Small Letter E With Acute"}, + {0x00EA, "Latin Small Letter E With Circumflex"}, + {0x00EB, "Latin Small Letter E With Diaeresis"}, + {0x00EC, "Latin Small Letter I With Grave"}, + {0x00ED, "Latin Small Letter I With Acute"}, + {0x00EE, "Latin Small Letter I With Circumflex"}, + {0x00EF, "Latin Small Letter I With Diaeresis"}, + {0x00F0, "Latin Small Letter Eth"}, + {0x00F1, "Latin Small Letter N With Tilde"}, + {0x00F2, "Latin Small Letter O With Grave"}, + {0x00F3, "Latin Small Letter O With Acute"}, + {0x00F4, "Latin Small Letter O With Circumflex"}, + {0x00F5, "Latin Small Letter O With Tilde"}, + {0x00F6, "Latin Small Letter O With Diaeresis"}, + {0x00F8, "Latin Small Letter O With Stroke"}, + {0x00F9, "Latin Small Letter U With Grave"}, + {0x00FA, "Latin Small Letter U With Acute"}, + {0x00FB, "Latin Small Letter U With Circumflex"}, + {0x00FC, "Latin Small Letter U With Diaeresis"}, + {0x00FD, "Latin Small Letter Y With Acute"}, + {0x00FE, "Latin Small Letter Thorn"}, + {0x00FF, "Latin Small Letter Y With Diaeresis"}, + {0x0161, "Latin Small Letter S With Caron"}, + {0x0153, "Latin Small Ligature OE"}, + {0x017E, "Latin Small Letter Z With Caron"}, + {0x0192, "Latin Small Letter F With Hook"}, }; // Typographic punctuation. static const Glyph PUNCT[] = { - {0xA1, "Inverted Exclamation Mark"}, - {0xBF, "Inverted Question Mark"}, - {0x91, "Left Single Quotation Mark"}, - {0x92, "Right Single Quotation Mark"}, - {0x93, "Left Double Quotation Mark"}, - {0x94, "Right Double Quotation Mark"}, - {0x82, "Single Low-9 Quotation Mark"}, - {0x84, "Double Low-9 Quotation Mark"}, - {0xAB, "Left-Pointing Double Angle Quotation Mark"}, - {0xBB, "Right-Pointing Double Angle Quotation Mark"}, - {0x8B, "Single Left-Pointing Angle Quotation Mark"}, - {0x9B, "Single Right-Pointing Angle Quotation Mark"}, - {0x96, "En Dash"}, - {0x97, "Em Dash"}, - {0x85, "Horizontal Ellipsis"}, - {0x95, "Bullet"}, - {0xB7, "Middle Dot"}, - {0x86, "Dagger"}, - {0x87, "Double Dagger"}, - {0xB6, "Pilcrow Sign"}, - {0xA7, "Section Sign"}, - {0x89, "Per Mille Sign"}, + {0x00A1, "Inverted Exclamation Mark"}, + {0x00BF, "Inverted Question Mark"}, + {0x2018, "Left Single Quotation Mark"}, + {0x2019, "Right Single Quotation Mark"}, + {0x201C, "Left Double Quotation Mark"}, + {0x201D, "Right Double Quotation Mark"}, + {0x201A, "Single Low-9 Quotation Mark"}, + {0x201E, "Double Low-9 Quotation Mark"}, + {0x00AB, "Left-Pointing Double Angle Quotation Mark"}, + {0x00BB, "Right-Pointing Double Angle Quotation Mark"}, + {0x2039, "Single Left-Pointing Angle Quotation Mark"}, + {0x203A, "Single Right-Pointing Angle Quotation Mark"}, + {0x2013, "En Dash"}, + {0x2014, "Em Dash"}, + {0x2026, "Horizontal Ellipsis"}, + {0x2022, "Bullet"}, + {0x00B7, "Middle Dot"}, + {0x2020, "Dagger"}, + {0x2021, "Double Dagger"}, + {0x00B6, "Pilcrow Sign"}, + {0x00A7, "Section Sign"}, + {0x2030, "Per Mille Sign"}, }; // Currency symbols. static const Glyph CURRENCY[] = { - {0x24, "Dollar Sign"}, - {0xA2, "Cent Sign"}, - {0xA3, "Pound Sign"}, - {0xA5, "Yen Sign"}, - {0x80, "Euro Sign"}, - {0xA4, "Currency Sign"}, - {0x83, "Latin Small Letter F With Hook (Florin)"}, + {0x0024, "Dollar Sign"}, + {0x00A2, "Cent Sign"}, + {0x00A3, "Pound Sign"}, + {0x00A5, "Yen Sign"}, + {0x20AC, "Euro Sign"}, + {0x00A4, "Currency Sign"}, + {0x0192, "Latin Small Letter F With Hook (Florin)"}, }; // Math, technical, and miscellaneous symbols. static const Glyph SYMBOLS[] = { - {0xA9, "Copyright Sign"}, - {0xAE, "Registered Sign"}, - {0x99, "Trade Mark Sign"}, - {0xB0, "Degree Sign"}, - {0xB1, "Plus-Minus Sign"}, - {0xD7, "Multiplication Sign"}, - {0xF7, "Division Sign"}, - {0xB5, "Micro Sign"}, - {0xAC, "Not Sign"}, - {0xBC, "Vulgar Fraction One Quarter"}, - {0xBD, "Vulgar Fraction One Half"}, - {0xBE, "Vulgar Fraction Three Quarters"}, - {0xB9, "Superscript One"}, - {0xB2, "Superscript Two"}, - {0xB3, "Superscript Three"}, - {0xAA, "Feminine Ordinal Indicator"}, - {0xBA, "Masculine Ordinal Indicator"}, - {0xA6, "Broken Bar"}, - {0xB4, "Acute Accent"}, - {0xA8, "Diaeresis"}, - {0xAF, "Macron"}, - {0xB8, "Cedilla"}, - {0x88, "Modifier Letter Circumflex Accent"}, - {0x98, "Small Tilde"}, + {0x00A9, "Copyright Sign"}, + {0x00AE, "Registered Sign"}, + {0x2122, "Trade Mark Sign"}, + {0x00B0, "Degree Sign"}, + {0x00B1, "Plus-Minus Sign"}, + {0x00D7, "Multiplication Sign"}, + {0x00F7, "Division Sign"}, + {0x00B5, "Micro Sign"}, + {0x00AC, "Not Sign"}, + {0x00BC, "Vulgar Fraction One Quarter"}, + {0x00BD, "Vulgar Fraction One Half"}, + {0x00BE, "Vulgar Fraction Three Quarters"}, + {0x00B9, "Superscript One"}, + {0x00B2, "Superscript Two"}, + {0x00B3, "Superscript Three"}, + {0x00AA, "Feminine Ordinal Indicator"}, + {0x00BA, "Masculine Ordinal Indicator"}, + {0x00A6, "Broken Bar"}, + {0x00B4, "Acute Accent"}, + {0x00A8, "Diaeresis"}, + {0x00AF, "Macron"}, + {0x00B8, "Cedilla"}, + {0x02C6, "Modifier Letter Circumflex Accent"}, + {0x02DC, "Small Tilde"}, +}; + +// Beyond the old single-byte range: Greek (Roboto covers the whole block). +static const Glyph GREEK[] = { + {0x0391, "Greek Capital Letter Alpha"}, + {0x0392, "Greek Capital Letter Beta"}, + {0x0393, "Greek Capital Letter Gamma"}, + {0x0394, "Greek Capital Letter Delta"}, + {0x0395, "Greek Capital Letter Epsilon"}, + {0x0396, "Greek Capital Letter Zeta"}, + {0x0397, "Greek Capital Letter Eta"}, + {0x0398, "Greek Capital Letter Theta"}, + {0x0399, "Greek Capital Letter Iota"}, + {0x039A, "Greek Capital Letter Kappa"}, + {0x039B, "Greek Capital Letter Lamda"}, + {0x039C, "Greek Capital Letter Mu"}, + {0x039D, "Greek Capital Letter Nu"}, + {0x039E, "Greek Capital Letter Xi"}, + {0x039F, "Greek Capital Letter Omicron"}, + {0x03A0, "Greek Capital Letter Pi"}, + {0x03A1, "Greek Capital Letter Rho"}, + {0x03A3, "Greek Capital Letter Sigma"}, + {0x03A4, "Greek Capital Letter Tau"}, + {0x03A5, "Greek Capital Letter Upsilon"}, + {0x03A6, "Greek Capital Letter Phi"}, + {0x03A7, "Greek Capital Letter Chi"}, + {0x03A8, "Greek Capital Letter Psi"}, + {0x03A9, "Greek Capital Letter Omega"}, + {0x03B1, "Greek Small Letter Alpha"}, + {0x03B2, "Greek Small Letter Beta"}, + {0x03B3, "Greek Small Letter Gamma"}, + {0x03B4, "Greek Small Letter Delta"}, + {0x03B5, "Greek Small Letter Epsilon"}, + {0x03B6, "Greek Small Letter Zeta"}, + {0x03B7, "Greek Small Letter Eta"}, + {0x03B8, "Greek Small Letter Theta"}, + {0x03B9, "Greek Small Letter Iota"}, + {0x03BA, "Greek Small Letter Kappa"}, + {0x03BB, "Greek Small Letter Lamda"}, + {0x03BC, "Greek Small Letter Mu"}, + {0x03BD, "Greek Small Letter Nu"}, + {0x03BE, "Greek Small Letter Xi"}, + {0x03BF, "Greek Small Letter Omicron"}, + {0x03C0, "Greek Small Letter Pi"}, + {0x03C1, "Greek Small Letter Rho"}, + {0x03C2, "Greek Small Letter Final Sigma"}, + {0x03C3, "Greek Small Letter Sigma"}, + {0x03C4, "Greek Small Letter Tau"}, + {0x03C5, "Greek Small Letter Upsilon"}, + {0x03C6, "Greek Small Letter Phi"}, + {0x03C7, "Greek Small Letter Chi"}, + {0x03C8, "Greek Small Letter Psi"}, + {0x03C9, "Greek Small Letter Omega"}, }; #define SET(arr, label) { label, arr, (int)(sizeof(arr) / sizeof(arr[0])) } @@ -192,6 +241,7 @@ static const CharSet SETS[] = { SET(PUNCT, "Punctuation"), SET(CURRENCY, "Currency"), SET(SYMBOLS, "Symbols"), + SET(GREEK, "Greek"), }; static constexpr int SET_COUNT = (int)(sizeof(SETS) / sizeof(SETS[0])); @@ -319,29 +369,26 @@ static void ensure_visible(const Layout& L) { // ==== Helpers ==== -static void glyph_str(uint8_t byte, char out[2]) { - out[0] = (char)byte; - out[1] = '\0'; -} - -static int codepoint_of(uint8_t byte) { - return decode_single_byte_codepoint((int)byte); +static int glyph_str(uint32_t cp, char out[5]) { + int n = montauk::utf8::encode(cp, out); + out[n] = '\0'; + return n; } static void copy_selected() { const Glyph& g = cur_set().glyphs[g_sel]; - char s[2]; - glyph_str(g.byte, s); - gui::clipboard_set_text(s, 1); + char s[5]; + int n = glyph_str(g.cp, s); + gui::clipboard_set_text(s, n); g_copied_until = montauk::get_milliseconds() + COPIED_MS; } // ==== Rendering ==== -static void draw_centered_glyph(Canvas& c, const Rect& r, uint8_t byte, +static void draw_centered_glyph(Canvas& c, const Rect& r, uint32_t cp, Color color, int size) { - char s[2]; - glyph_str(byte, s); + char s[5]; + glyph_str(cp, s); int tw = text_width(fonts::system_font, s, size); int th = text_height(fonts::system_font, size); draw_text(c, fonts::system_font, r.x + (r.w - tw) / 2, @@ -376,7 +423,7 @@ static void render(Canvas& c) { c.fill_rounded_rect(r.x, r.y, r.w, r.h, g_theme.radius_md, border); c.fill_rounded_rect(r.x + 1, r.y + 1, r.w - 2, r.h - 2, g_theme.radius_md > 0 ? g_theme.radius_md - 1 : 0, fill); - draw_centered_glyph(c, r, set.glyphs[i].byte, glyph, CELL_SIZE); + draw_centered_glyph(c, r, set.glyphs[i].cp, glyph, CELL_SIZE); } // ---- Scrollbar (shared MTK widget; no-ops when the set fits) ---- @@ -407,14 +454,21 @@ static void render(Canvas& c) { g_theme.radius_md, g_theme.border); c.fill_rounded_rect(preview.x + 1, preview.y + 1, preview.w - 2, preview.h - 2, g_theme.radius_md - 1, colors::WHITE); - draw_centered_glyph(c, preview, sg.byte, g_theme.text, PREVIEW_SIZE); + draw_centered_glyph(c, preview, sg.cp, g_theme.text, PREVIEW_SIZE); // Name + metadata, as a two-line block vertically centered on the preview. - int cp = codepoint_of(sg.byte); + int cp = (int)sg.cp; + char enc[5]; + int enc_len = glyph_str(sg.cp, enc); + char utf8_hex[16]; + int hp = 0; + for (int i = 0; i < enc_len; i++) + hp += snprintf(utf8_hex + hp, sizeof(utf8_hex) - hp, i ? " %02X" : "%02X", + (unsigned)(uint8_t)enc[i]); int text_x = preview.x + preview.w + 14; char meta[64]; - snprintf(meta, sizeof(meta), "U+%04X dec %d Alt 0%d", - cp, cp, (int)sg.byte); + snprintf(meta, sizeof(meta), "U+%04X dec %d UTF-8 %s", + cp, cp, utf8_hex); int name_h = text_height(title_font, NAME_SIZE); int meta_h = text_height(fonts::system_font, META_SIZE); @@ -527,7 +581,7 @@ static bool handle_key(const montauk::abi::KeyEvent& key, int w, int h) { const int count = cur_set().count; bool redraw = false; - switch (key.scancode) { + switch (montauk::nav_scancode(key)) { case 0x4B: // Left if (g_sel > 0) { g_sel--; ensure_visible(L); redraw = true; } break; diff --git a/programs/src/crashpad/main.cpp b/programs/src/crashpad/main.cpp index ad00a64..961e1cc 100644 --- a/programs/src/crashpad/main.cpp +++ b/programs/src/crashpad/main.cpp @@ -306,12 +306,12 @@ extern "C" void _start() { if (ev.type == 0 && ev.key.pressed) { if (ev.key.scancode == 0x01) break; // Escape - if (ev.key.scancode == 0x51) { + if (montauk::nav_scancode(ev.key) == 0x51) { // Page Down: scroll down g_scroll += 60; render(); } - if (ev.key.scancode == 0x49) { + if (montauk::nav_scancode(ev.key) == 0x49) { // Page Up: scroll up g_scroll -= 60; if (g_scroll < 0) g_scroll = 0; diff --git a/programs/src/desktop/apps/filemanager/events.cpp b/programs/src/desktop/apps/filemanager/events.cpp index 046950f..f5f31c7 100644 --- a/programs/src/desktop/apps/filemanager/events.cpp +++ b/programs/src/desktop/apps/filemanager/events.cpp @@ -351,36 +351,21 @@ void filemanager_on_key(Window* win, const montauk::abi::KeyEvent& key) { } else if (key.scancode == 0x01) { filemanager_cancel_pathbar(fm); } else if (key.ascii == '\b' || key.scancode == 0x0E) { - if (fm->pathbar_cursor > 0) { - for (int i = fm->pathbar_cursor - 1; i < fm->pathbar_len - 1; i++) - fm->pathbar_buf[i] = fm->pathbar_buf[i + 1]; - fm->pathbar_len--; - fm->pathbar_cursor--; - fm->pathbar_buf[fm->pathbar_len] = '\0'; - } - } else if (key.scancode == 0x53) { - if (fm->pathbar_cursor < fm->pathbar_len) { - for (int i = fm->pathbar_cursor; i < fm->pathbar_len - 1; i++) - fm->pathbar_buf[i] = fm->pathbar_buf[i + 1]; - fm->pathbar_len--; - fm->pathbar_buf[fm->pathbar_len] = '\0'; - } - } else if (key.scancode == 0x4B) { - if (fm->pathbar_cursor > 0) fm->pathbar_cursor--; - } else if (key.scancode == 0x4D) { - if (fm->pathbar_cursor < fm->pathbar_len) fm->pathbar_cursor++; - } else if (key.scancode == 0x47) { + montauk::utf8::erase_before(fm->pathbar_buf, &fm->pathbar_len, &fm->pathbar_cursor); + } else if (montauk::nav_scancode(key) == 0x53) { + montauk::utf8::erase_at(fm->pathbar_buf, &fm->pathbar_len, fm->pathbar_cursor); + } else if (montauk::nav_scancode(key) == 0x4B) { + fm->pathbar_cursor = montauk::utf8::prev_boundary(fm->pathbar_buf, fm->pathbar_cursor); + } else if (montauk::nav_scancode(key) == 0x4D) { + fm->pathbar_cursor = montauk::utf8::next_boundary(fm->pathbar_buf, fm->pathbar_len, + fm->pathbar_cursor); + } else if (montauk::nav_scancode(key) == 0x47) { fm->pathbar_cursor = 0; - } else if (key.scancode == 0x4F) { + } else if (montauk::nav_scancode(key) == 0x4F) { fm->pathbar_cursor = fm->pathbar_len; - } else if ((unsigned char)key.ascii >= 32 - && (unsigned char)key.ascii != 127 && fm->pathbar_len < 254) { - for (int i = fm->pathbar_len; i > fm->pathbar_cursor; i--) - fm->pathbar_buf[i] = fm->pathbar_buf[i - 1]; - fm->pathbar_buf[fm->pathbar_cursor] = key.ascii; - fm->pathbar_cursor++; - fm->pathbar_len++; - fm->pathbar_buf[fm->pathbar_len] = '\0'; + } else { + montauk::utf8::insert_key(fm->pathbar_buf, &fm->pathbar_len, 255, + &fm->pathbar_cursor, key); } return; } @@ -394,44 +379,27 @@ void filemanager_on_key(Window* win, const montauk::abi::KeyEvent& key) { filemanager_cancel_rename(fm); } else if (key.ascii == '\b' || key.scancode == 0x0E) { // Backspace - if (fm->rename_cursor > 0) { - for (int i = fm->rename_cursor - 1; i < fm->rename_len - 1; i++) - fm->rename_buf[i] = fm->rename_buf[i + 1]; - fm->rename_len--; - fm->rename_cursor--; - fm->rename_buf[fm->rename_len] = '\0'; - } - } else if (key.scancode == 0x53) { + montauk::utf8::erase_before(fm->rename_buf, &fm->rename_len, &fm->rename_cursor); + } else if (montauk::nav_scancode(key) == 0x53) { // Delete key - if (fm->rename_cursor < fm->rename_len) { - for (int i = fm->rename_cursor; i < fm->rename_len - 1; i++) - fm->rename_buf[i] = fm->rename_buf[i + 1]; - fm->rename_len--; - fm->rename_buf[fm->rename_len] = '\0'; - } - } else if (key.scancode == 0x4B) { + montauk::utf8::erase_at(fm->rename_buf, &fm->rename_len, fm->rename_cursor); + } else if (montauk::nav_scancode(key) == 0x4B) { // Left arrow - if (fm->rename_cursor > 0) fm->rename_cursor--; - } else if (key.scancode == 0x4D) { + fm->rename_cursor = montauk::utf8::prev_boundary(fm->rename_buf, fm->rename_cursor); + } else if (montauk::nav_scancode(key) == 0x4D) { // Right arrow - if (fm->rename_cursor < fm->rename_len) fm->rename_cursor++; - } else if (key.scancode == 0x47) { + fm->rename_cursor = montauk::utf8::next_boundary(fm->rename_buf, fm->rename_len, + fm->rename_cursor); + } else if (montauk::nav_scancode(key) == 0x47) { // Home fm->rename_cursor = 0; - } else if (key.scancode == 0x4F) { + } else if (montauk::nav_scancode(key) == 0x4F) { // End fm->rename_cursor = fm->rename_len; - } else if ((unsigned char)key.ascii >= 32 - && (unsigned char)key.ascii != 127) { + } else if (key.ascii != '/' && key.ascii != '\\') { // Printable character (reject / and other FS-unsafe chars) - if (key.ascii != '/' && key.ascii != '\\' && fm->rename_len < 62) { - for (int i = fm->rename_len; i > fm->rename_cursor; i--) - fm->rename_buf[i] = fm->rename_buf[i - 1]; - fm->rename_buf[fm->rename_cursor] = key.ascii; - fm->rename_cursor++; - fm->rename_len++; - fm->rename_buf[fm->rename_len] = '\0'; - } + montauk::utf8::insert_key(fm->rename_buf, &fm->rename_len, 63, + &fm->rename_cursor, key); } return; } @@ -466,7 +434,7 @@ void filemanager_on_key(Window* win, const montauk::abi::KeyEvent& key) { if (key.ascii == '\b' || key.scancode == 0x0E) { filemanager_go_up(fm); - } else if (key.scancode == 0x48) { + } else if (montauk::nav_scancode(key) == 0x48) { // Up arrow if (fm->grid_view) { Rect cr_r = win->content_rect(); @@ -477,7 +445,7 @@ void filemanager_on_key(Window* win, const montauk::abi::KeyEvent& key) { if (fm->selected > 0) fm->selected--; } filemanager_scroll_to_selected(win, fm); - } else if (key.scancode == 0x50) { + } else if (montauk::nav_scancode(key) == 0x50) { // Down arrow if (fm->grid_view) { Rect cr_r = win->content_rect(); @@ -488,22 +456,22 @@ void filemanager_on_key(Window* win, const montauk::abi::KeyEvent& key) { if (fm->selected < fm->entry_count - 1) fm->selected++; } filemanager_scroll_to_selected(win, fm); - } else if (key.scancode == 0x4B && !key.alt && fm->grid_view) { + } else if (montauk::nav_scancode(key) == 0x4B && !key.alt && fm->grid_view) { // Left arrow (grid view only) if (fm->selected > 0) fm->selected--; - } else if (key.scancode == 0x4D && !key.alt && fm->grid_view) { + } else if (montauk::nav_scancode(key) == 0x4D && !key.alt && fm->grid_view) { // Right arrow (grid view only) if (fm->selected < fm->entry_count - 1) fm->selected++; } else if (key.ascii == '\n' || key.ascii == '\r') { if (fm->selected >= 0 && fm->selected < fm->entry_count) filemanager_open_entry(fm, fm->selected); - } else if (key.scancode == 0x53) { + } else if (montauk::nav_scancode(key) == 0x53) { // Delete key filemanager_delete_selected(fm); - } else if (key.alt && key.scancode == 0x4B) { + } else if (key.alt && montauk::nav_scancode(key) == 0x4B) { // Alt+Left: go back filemanager_go_back(fm); - } else if (key.alt && key.scancode == 0x4D) { + } else if (key.alt && montauk::nav_scancode(key) == 0x4D) { // Alt+Right: go forward filemanager_go_forward(fm); } diff --git a/programs/src/desktop/apps/filemanager/properties.cpp b/programs/src/desktop/apps/filemanager/properties.cpp index 8c4a28d..3eb3e0f 100644 --- a/programs/src/desktop/apps/filemanager/properties.cpp +++ b/programs/src/desktop/apps/filemanager/properties.cpp @@ -65,10 +65,10 @@ static void props_fit_text(const char* src, char* out, int out_len, int max_w) { while (len > 0) { out[len] = '\0'; if (text_width(out) + ellipsis_w <= max_w) break; - len--; + len = montauk::utf8::prev_boundary(out, len); } - if (len > out_len - 4) len = out_len - 4; + if (len > out_len - 4) len = montauk::utf8::floor_boundary(out, len, out_len - 4); if (len < 0) len = 0; out[len] = '.'; out[len + 1] = '.'; diff --git a/programs/src/desktop/apps/filemanager/render.cpp b/programs/src/desktop/apps/filemanager/render.cpp index 402e46b..7922bab 100644 --- a/programs/src/desktop/apps/filemanager/render.cpp +++ b/programs/src/desktop/apps/filemanager/render.cpp @@ -32,12 +32,14 @@ static int fitted_prefix_len(const char* src, int max_w, int max_len) { char tmp[128]; int best = 0; int limit = max_len < 127 ? max_len : 127; - for (int len = 1; len <= limit; len++) { + for (int len = montauk::utf8::next_boundary(src, max_len, 0); len <= limit; + len = montauk::utf8::next_boundary(src, max_len, len)) { copy_label_range(tmp, sizeof(tmp), src, 0, len); if (text_width(tmp) > max_w) break; best = len; + if (len >= max_len) break; } - return best > 0 ? best : 1; + return best > 0 ? best : montauk::utf8::next_boundary(src, max_len, 0); } static void fit_label_with_ellipsis(char* dst, int dst_max, const char* src, int max_w) { @@ -49,10 +51,10 @@ static void fit_label_with_ellipsis(char* dst, int dst_max, const char* src, int while (len > 0) { dst[len] = '\0'; if (text_width(dst) + ellipsis_w <= max_w) break; - len--; + len = montauk::utf8::prev_boundary(dst, len); } - if (len > dst_max - 4) len = dst_max - 4; + if (len > dst_max - 4) len = montauk::utf8::floor_boundary(dst, len, dst_max - 4); if (len < 0) len = 0; dst[len] = '.'; dst[len + 1] = '.'; @@ -403,7 +405,7 @@ void filemanager_on_draw(Window* win, Framebuffer& fb) { // Draw rename text (truncated to cell width) char display[16]; int rlen = fm->rename_len; - if (rlen > 10) rlen = 10; + if (rlen > 10) rlen = montauk::utf8::floor_boundary(fm->rename_buf, fm->rename_len, 10); for (int k = 0; k < rlen; k++) display[k] = fm->rename_buf[k]; display[rlen] = '\0'; c.text(cell_x + 4, ty, display, colors::TEXT_COLOR); @@ -557,18 +559,19 @@ void filemanager_on_draw(Window* win, Framebuffer& fb) { int name_max_w = size_col_x - tx - 8; if (name_max_w < 20) name_max_w = c.w - FM_SCROLLBAR_W - tx - 8; char label[64]; - montauk::strncpy(label, name, 63); + montauk::utf8::copy(label, 64, name); if (text_width(label) > name_max_w && montauk::slen(name) > 3) { int ellipsis_w = text_width("..."); - int final_len = montauk::slen(name); + int final_len = montauk::slen(label); while (final_len > 1) { label[final_len] = '\0'; int w = text_width(label); if (w + ellipsis_w <= name_max_w) break; - final_len--; + final_len = montauk::utf8::prev_boundary(label, final_len); } - if (final_len > 60) final_len = 60; + if (final_len > 60) + final_len = montauk::utf8::floor_boundary(label, final_len, 60); label[final_len] = '.'; label[final_len + 1] = '.'; label[final_len + 2] = '.'; diff --git a/programs/src/desktop/apps/settings/about.cpp b/programs/src/desktop/apps/settings/about.cpp index 615ef64..8e18a81 100644 --- a/programs/src/desktop/apps/settings/about.cpp +++ b/programs/src/desktop/apps/settings/about.cpp @@ -44,7 +44,7 @@ void settings_draw_about(Canvas& c, SettingsState* st) { mtk::draw_separator(c, x, y, c.w - 2 * x, theme); y += 12; - c.text(x, y, "Copyright \xa9 2026 Montauk Operating System Project", theme.text_muted); + c.text(x, y, "Copyright \u00A9 2026 Montauk Operating System Project", theme.text_muted); } } // namespace settings_app diff --git a/programs/src/desktop/compose.cpp b/programs/src/desktop/compose.cpp index 3f47102..ac5a23e 100644 --- a/programs/src/desktop/compose.cpp +++ b/programs/src/desktop/compose.cpp @@ -103,7 +103,7 @@ void desktop_draw_lock_screen(DesktopState* ds) { // Masked password text (clipped to field width) char masked[65]; - int len = ds->lock_password_len; + int len = montauk::utf8::count(ds->lock_password); // one '*' per character if (len > 64) len = 64; int max_text_w = content_w - 10 - 10 - 2; // left pad, right pad, cursor // Show only the trailing portion that fits diff --git a/programs/src/desktop/consent.cpp b/programs/src/desktop/consent.cpp index 854a788..87a58db 100644 --- a/programs/src/desktop/consent.cpp +++ b/programs/src/desktop/consent.cpp @@ -105,7 +105,11 @@ int wrap_text(const char* text, int max_w, char (*lines)[LINE_CHARS], int max_li char* last = lines[max_lines - 1]; int len = montauk::slen(last); if (len > LINE_CHARS - 4) len = LINE_CHARS - 4; - while (len > 0 && text_width(last) + text_width("...") > max_w) last[--len] = '\0'; + last[len] = '\0'; + while (len > 0 && text_width(last) + text_width("...") > max_w) { + len = montauk::utf8::prev_boundary(last, len); + last[len] = '\0'; + } last[len] = '.'; last[len + 1] = '.'; last[len + 2] = '.'; last[len + 3] = '\0'; } return count; diff --git a/programs/src/desktop/input.cpp b/programs/src/desktop/input.cpp index cdc1dce..e5923ce 100644 --- a/programs/src/desktop/input.cpp +++ b/programs/src/desktop/input.cpp @@ -98,22 +98,12 @@ static void handle_lock_keyboard(DesktopState* ds, const montauk::abi::KeyEvent& // Backspace if (key.ascii == '\b' || key.scancode == 0x0E) { - if (ds->lock_password_len > 0) { - ds->lock_password_len--; - ds->lock_password[ds->lock_password_len] = '\0'; - } + montauk::utf8::erase_last(ds->lock_password, &ds->lock_password_len); return; } - // Printable characters - if ((unsigned char)key.ascii >= 0x20 - && (unsigned char)key.ascii != 0x7F) { - if (ds->lock_password_len < 63) { - ds->lock_password[ds->lock_password_len] = key.ascii; - ds->lock_password_len++; - ds->lock_password[ds->lock_password_len] = '\0'; - } - } + // Printable characters (stored as UTF-8) + montauk::utf8::append_key(ds->lock_password, &ds->lock_password_len, 64, key); } static void forward_external_mouse(gui::Window* win, diff --git a/programs/src/desktop/launcher.cpp b/programs/src/desktop/launcher.cpp index 69ef62a..cfcf10c 100644 --- a/programs/src/desktop/launcher.cpp +++ b/programs/src/desktop/launcher.cpp @@ -361,7 +361,7 @@ static void launcher_activate_selected(DesktopState* ds) { } static void launcher_update_super_state(DesktopState* ds, const montauk::abi::KeyEvent& key) { - uint8_t sc = key.scancode & 0x7F; + uint8_t sc = montauk::nav_scancode(key) & 0x7F; if (sc == 0x5B) { ds->super_left_down = key.pressed; } else if (sc == 0x5C) { @@ -371,7 +371,7 @@ static void launcher_update_super_state(DesktopState* ds, const montauk::abi::Ke static const char* fit_trailing_text(const char* text, int max_w) { const char* visible = text; - while (*visible && text_width(visible) > max_w) visible++; + while (*visible && text_width(visible) > max_w) montauk::utf8::next(&visible); return visible; } @@ -420,7 +420,7 @@ void desktop_close_launcher(DesktopState* ds) { bool desktop_handle_launcher_keyboard(DesktopState* ds, const montauk::abi::KeyEvent& key) { launcher_update_super_state(ds, key); - uint8_t sc = key.scancode & 0x7F; + uint8_t sc = montauk::nav_scancode(key) & 0x7F; if (sc == 0x5B || sc == 0x5C) { return true; @@ -456,11 +456,8 @@ bool desktop_handle_launcher_keyboard(DesktopState* ds, const montauk::abi::KeyE } if (key.ascii == '\b' || sc == 0x0E) { - if (ds->launcher_query_len > 0) { - ds->launcher_query_len--; - ds->launcher_query[ds->launcher_query_len] = '\0'; + if (montauk::utf8::erase_last(ds->launcher_query, &ds->launcher_query_len)) desktop_update_launcher_results(ds); - } return true; } @@ -495,12 +492,8 @@ bool desktop_handle_launcher_keyboard(DesktopState* ds, const montauk::abi::KeyE return true; } - if ((unsigned char)key.ascii >= 0x20 - && (unsigned char)key.ascii != 0x7F && ds->launcher_query_len < 63) { - ds->launcher_query[ds->launcher_query_len++] = key.ascii; - ds->launcher_query[ds->launcher_query_len] = '\0'; + if (montauk::utf8::append_key(ds->launcher_query, &ds->launcher_query_len, 64, key)) desktop_update_launcher_results(ds); - } return true; } diff --git a/programs/src/devexplorer/main.cpp b/programs/src/devexplorer/main.cpp index 5d0681d..66e6b85 100644 --- a/programs/src/devexplorer/main.cpp +++ b/programs/src/devexplorer/main.cpp @@ -280,7 +280,7 @@ static bool handle_key(const montauk::abi::KeyEvent& key) { int row_count = build_display_rows(&de, rows); if (row_count == 0) return true; - if (key.scancode == 0x48) { // Up + if (montauk::nav_scancode(key) == 0x48) { // Up if (de.selected_row <= 0) de.selected_row = 0; else de.selected_row--; // Scroll up just enough to bring the selected row's top into view. @@ -289,7 +289,7 @@ static bool handle_key(const montauk::abi::KeyEvent& key) { sel_top += (rows[i].type == ROW_CATEGORY) ? CAT_H : ITEM_H; if (sel_top < de.scroll_y) de.scroll_y = sel_top; - } else if (key.scancode == 0x50) { // Down + } else if (montauk::nav_scancode(key) == 0x50) { // Down if (de.selected_row < row_count - 1) de.selected_row++; // Scroll down just enough to bring the selected row's bottom into view. @@ -300,7 +300,7 @@ static bool handle_key(const montauk::abi::KeyEvent& key) { int list_h = g_win_h - TOOLBAR_H; if (sel_top + sel_h > de.scroll_y + list_h) de.scroll_y = sel_top + sel_h - list_h; - } else if (key.scancode == 0x4B) { // Left — collapse + } else if (montauk::nav_scancode(key) == 0x4B) { // Left — collapse if (de.selected_row >= 0 && de.selected_row < row_count) { int cat = rows[de.selected_row].category; if (!de.collapsed[cat]) { @@ -318,7 +318,7 @@ static bool handle_key(const montauk::abi::KeyEvent& key) { } } } - } else if (key.scancode == 0x4D) { // Right — expand + } else if (montauk::nav_scancode(key) == 0x4D) { // Right — expand if (de.selected_row >= 0 && de.selected_row < row_count) { int cat = rows[de.selected_row].category; de.collapsed[cat] = false; diff --git a/programs/src/dialogs/filedialog.cpp b/programs/src/dialogs/filedialog.cpp index ed465a5..0b7f21c 100644 --- a/programs/src/dialogs/filedialog.cpp +++ b/programs/src/dialogs/filedialog.cpp @@ -261,15 +261,16 @@ void fit_text_start(const char* src, char* out, int out_len, int max_px) { // Grid labels must fit their cell in pixels. Character-count truncation is // insufficient for the proportional system font and lets wide names paint // over the adjacent label. - int keep = montauk::slen(src); - if (keep > out_len - 3) keep = out_len - 3; + int slen = montauk::slen(src); + int keep = slen; + if (keep > out_len - 3) keep = montauk::utf8::floor_boundary(src, slen, out_len - 3); while (keep > 0) { for (int i = 0; i < keep; i++) out[i] = src[i]; out[keep] = '.'; out[keep + 1] = '.'; out[keep + 2] = '\0'; if (text_width(out) <= max_px) return; - keep--; + keep = montauk::utf8::prev_boundary(src, keep); } safe_copy(out, out_len, ".."); @@ -1216,14 +1217,14 @@ void handle_file_key(const montauk::abi::KeyEvent& key) { return; } - if (key.scancode == 0x4B || key.scancode == 0x48) { + if (montauk::nav_scancode(key) == 0x4B || montauk::nav_scancode(key) == 0x48) { if (st->selected > 0) st->selected--; else if (st->entry_count > 0) st->selected = 0; file_ensure_selected_visible(st); return; } - if (key.scancode == 0x4D || key.scancode == 0x50) { + if (montauk::nav_scancode(key) == 0x4D || montauk::nav_scancode(key) == 0x50) { if (st->selected < st->entry_count - 1) st->selected++; else if (st->entry_count > 0) st->selected = st->entry_count - 1; file_ensure_selected_visible(st); diff --git a/programs/src/dialogs/messagebox.cpp b/programs/src/dialogs/messagebox.cpp index 05de72e..e1eb71e 100644 --- a/programs/src/dialogs/messagebox.cpp +++ b/programs/src/dialogs/messagebox.cpp @@ -143,7 +143,8 @@ void fit_text_end(const char* src, char* out, int out_len, int max_px) { gui::dialogs::safe_copy(out, out_len, candidate); return; } - keep--; + // Drop one whole character from the front of the tail + keep = slen - montauk::utf8::next_boundary(src, slen, slen - keep); } gui::dialogs::safe_copy(out, out_len, "..."); diff --git a/programs/src/dialogs/printdialog.cpp b/programs/src/dialogs/printdialog.cpp index 7e7685f..b82ae3c 100644 --- a/programs/src/dialogs/printdialog.cpp +++ b/programs/src/dialogs/printdialog.cpp @@ -480,13 +480,13 @@ void handle_print_key(const montauk::abi::KeyEvent& key) { g_print.error[0] = '\0'; return; } - if ((key.scancode == 0x48 || key.scancode == 0x4B) && g_print.printer_count > 0) { + if ((montauk::nav_scancode(key) == 0x48 || montauk::nav_scancode(key) == 0x4B) && g_print.printer_count > 0) { if (g_print.selected_printer > 0) g_print.selected_printer--; else g_print.selected_printer = 0; g_print.error[0] = '\0'; return; } - if ((key.scancode == 0x50 || key.scancode == 0x4D) && g_print.printer_count > 0) { + if ((montauk::nav_scancode(key) == 0x50 || montauk::nav_scancode(key) == 0x4D) && g_print.printer_count > 0) { if (g_print.selected_printer < g_print.printer_count - 1) g_print.selected_printer++; else g_print.selected_printer = g_print.printer_count - 1; g_print.error[0] = '\0'; diff --git a/programs/src/disks/main.cpp b/programs/src/disks/main.cpp index cba8edd..1fd7ec3 100644 --- a/programs/src/disks/main.cpp +++ b/programs/src/disks/main.cpp @@ -339,9 +339,9 @@ static bool handle_key(const montauk::abi::KeyEvent& key) { if (dt.fmt_dlg.open) { if (key.scancode == 0x01) { // Escape close_format_dialog(); - } else if (key.scancode == 0x48 && dt.fmt_dlg.selected_fs > 0) { + } else if (montauk::nav_scancode(key) == 0x48 && dt.fmt_dlg.selected_fs > 0) { dt.fmt_dlg.selected_fs--; - } else if (key.scancode == 0x50 && dt.fmt_dlg.selected_fs < NUM_FS_TYPES - 1) { + } else if (montauk::nav_scancode(key) == 0x50 && dt.fmt_dlg.selected_fs < NUM_FS_TYPES - 1) { dt.fmt_dlg.selected_fs++; } else if (key.ascii == '\n' || key.ascii == '\r') { format_dialog_do_format(); @@ -354,14 +354,14 @@ static bool handle_key(const montauk::abi::KeyEvent& key) { if (key.scancode == 0x01) { // Escape return false; // signal quit - } else if (key.scancode == 0x48) { // Up + } else if (montauk::nav_scancode(key) == 0x48) { // Up if (dt.selected_part > 0) dt.selected_part--; else if (nparts > 0) dt.selected_part = 0; - } else if (key.scancode == 0x50) { // Down + } else if (montauk::nav_scancode(key) == 0x50) { // Down if (dt.selected_part < nparts - 1) dt.selected_part++; - } else if (key.scancode == 0x4B) { // Left + } else if (montauk::nav_scancode(key) == 0x4B) { // Left if (dt.selected_disk > 0) { dt.selected_disk--; dt.selected_part = -1; dt.scroll_y = 0; } - } else if (key.scancode == 0x4D) { // Right + } else if (montauk::nav_scancode(key) == 0x4D) { // Right if (dt.selected_disk < dt.disk_count - 1) { dt.selected_disk++; dt.selected_part = -1; dt.scroll_y = 0; } } else if (key.ascii == 'n' || key.ascii == 'N') { do_create_partition(); diff --git a/programs/src/disks/render.cpp b/programs/src/disks/render.cpp index 5b4e7e6..ababe6c 100644 --- a/programs/src/disks/render.cpp +++ b/programs/src/disks/render.cpp @@ -53,6 +53,8 @@ static void draw_text_fit(Canvas& c, int x, int y, out++; } + out = montauk::utf8::floor_boundary(text, montauk::slen(text), out); + if (out <= 0) return; buf[out] = '.'; buf[out + 1] = '.'; diff --git a/programs/src/display/main.cpp b/programs/src/display/main.cpp index 503a134..77455b2 100644 --- a/programs/src/display/main.cpp +++ b/programs/src/display/main.cpp @@ -252,6 +252,7 @@ static void fit_text(char* out, int outCap, const char* text, int maxWidth) { if (text_width(out) + text_width(ellipsis) > maxWidth) break; len++; } + len = montauk::utf8::floor_boundary(text, montauk::slen(text), len); out[len++] = '.'; out[len++] = '.'; out[len++] = '.'; diff --git a/programs/src/edit/main.cpp b/programs/src/edit/main.cpp index 1884a0a..9695220 100644 --- a/programs/src/edit/main.cpp +++ b/programs/src/edit/main.cpp @@ -7,6 +7,7 @@ #include #include #include +#include using montauk::slen; using montauk::memcpy; @@ -166,6 +167,16 @@ static void line_delete_char(Line* ln, int pos) { ln->data[ln->len] = '\0'; } +// Lines are UTF-8. cursorCol is a byte offset kept on a character boundary; +// the screen works in columns, one per character. +static int line_display_col(const Line* ln, int byteCol) { + return montauk::utf8::count(ln->data, byteCol < ln->len ? byteCol : ln->len); +} + +static int line_byte_col(const Line* ln, int displayCol) { + return montauk::utf8::offset_of(ln->data, ln->len, displayCol); +} + static void line_append(Line* ln, const char* s, int slen) { line_ensure(ln, ln->len + slen); memcpy(ln->data + ln->len, s, slen); @@ -300,6 +311,21 @@ static void load_file(const char* fname) { } montauk::close(handle); + // Pre-UTF-8 files are Windows-1252: convert once so edits never mix + // encodings and saving writes UTF-8. + bool converted = false; + if (buf && size > 0 && !montauk::utf8::valid((const char*)buf, (int)size)) { + int cap = (int)size * 3 + 1; + uint8_t* conv = (uint8_t*)montauk::malloc(cap); + if (conv) { + size = (uint64_t)montauk::utf8::normalize((const char*)buf, (int)size, + (char*)conv, cap); + montauk::mfree(buf); + buf = conv; + converted = true; + } + } + // Parse into lines numLines = 0; if (buf && size > 0) { @@ -325,7 +351,7 @@ static void load_file(const char* fname) { line_init(&lines[0]); } - set_status("File loaded"); + set_status(converted ? "File loaded (converted from Windows-1252 to UTF-8)" : "File loaded"); } static bool save_file() { @@ -413,14 +439,13 @@ static int prompt_input(const char* promptStr, char* out, int outMax) { } if (ev.ascii == '\b') { - if (pos > 0) { - pos--; + if (montauk::utf8::erase_last(out, &pos)) { putch('\b'); putch(' '); putch('\b'); } - } else if (ev.ascii >= ' ' && pos < outMax - 1) { - out[pos++] = ev.ascii; - out[pos] = '\0'; - putch(ev.ascii); + } else { + int before = pos; + if (montauk::utf8::append_key(out, &pos, outMax, ev)) + print(out + before); } } } @@ -506,14 +531,15 @@ static void draw_line(int screenRow, int docLine) { reset_attrs(); // Line content + // The visible window is leftCol..leftCol+maxChars in columns; convert + // it to a byte range so whole UTF-8 characters are emitted. Line* ln = &lines[docLine]; - int startCol = leftCol; + int startCol = line_byte_col(ln, leftCol); int maxChars = screenCols - gutterWidth; - int visibleLen = 0; - if (startCol < ln->len) { - visibleLen = ln->len - startCol; - if (visibleLen > maxChars) visibleLen = maxChars; - } + int endCol = startCol; + for (int n = 0; n < maxChars && endCol < ln->len; n++) + endCol = montauk::utf8::next_boundary(ln->data, ln->len, endCol); + int visibleLen = endCol - startCol; if (synLang != SYN_LANG_NONE) { // Tokenize the WHOLE line, not just the visible window: the @@ -577,7 +603,7 @@ static void render() { // Position cursor int screenY = cursorRow - topLine + 2; // +2 for status bar - int screenX = cursorCol - leftCol + gutterWidth; + int screenX = line_display_col(&lines[cursorRow], cursorCol) - leftCol + gutterWidth; cursor_to(screenY, screenX); show_cursor(); @@ -598,12 +624,13 @@ static void scroll() { // Horizontal scrolling int textCols = screenCols - gutterWidth; - if (cursorCol < leftCol) { - leftCol = cursorCol; + int displayCol = line_display_col(&lines[cursorRow], cursorCol); + if (displayCol < leftCol) { + leftCol = displayCol; fullRedraw = true; } - if (cursorCol >= leftCol + textCols) { - leftCol = cursorCol - textCols + 1; + if (displayCol >= leftCol + textCols) { + leftCol = displayCol - textCols + 1; fullRedraw = true; } } @@ -617,6 +644,10 @@ static void insert_char(char c) { fullRedraw = true; } +static void insert_bytes(const char* s, int n) { + for (int i = 0; i < n; i++) insert_char(s[i]); +} + static void insert_tab() { for (int i = 0; i < TAB_WIDTH; i++) { insert_char(' '); @@ -647,8 +678,11 @@ static void insert_newline() { static void delete_char_backspace() { if (cursorCol > 0) { - line_delete_char(&lines[cursorRow], cursorCol - 1); - cursorCol--; + int start = montauk::utf8::prev_boundary(lines[cursorRow].data, cursorCol); + while (cursorCol > start) { + line_delete_char(&lines[cursorRow], cursorCol - 1); + cursorCol--; + } modified = true; fullRedraw = true; } else if (cursorRow > 0) { @@ -665,7 +699,9 @@ static void delete_char_backspace() { static void delete_char_forward() { if (cursorCol < lines[cursorRow].len) { - line_delete_char(&lines[cursorRow], cursorCol); + Line* ln = &lines[cursorRow]; + int n = montauk::utf8::next_boundary(ln->data, ln->len, cursorCol) - cursorCol; + while (n-- > 0) line_delete_char(ln, cursorCol); modified = true; fullRedraw = true; } else if (cursorRow < numLines - 1) { @@ -793,26 +829,26 @@ static void handle_key(const montauk::abi::KeyEvent& ev) { // Non-ASCII keys (scancode-based) if (ev.ascii == 0) { - switch (ev.scancode) { + switch (montauk::nav_scancode(ev)) { case SC_UP: if (cursorRow > 0) { + int col = line_display_col(&lines[cursorRow], cursorCol); cursorRow--; - if (cursorCol > lines[cursorRow].len) - cursorCol = lines[cursorRow].len; + cursorCol = line_byte_col(&lines[cursorRow], col); fullRedraw = true; } return; case SC_DOWN: if (cursorRow < numLines - 1) { + int col = line_display_col(&lines[cursorRow], cursorCol); cursorRow++; - if (cursorCol > lines[cursorRow].len) - cursorCol = lines[cursorRow].len; + cursorCol = line_byte_col(&lines[cursorRow], col); fullRedraw = true; } return; case SC_LEFT: if (cursorCol > 0) { - cursorCol--; + cursorCol = montauk::utf8::prev_boundary(lines[cursorRow].data, cursorCol); } else if (cursorRow > 0) { cursorRow--; cursorCol = lines[cursorRow].len; @@ -821,7 +857,8 @@ static void handle_key(const montauk::abi::KeyEvent& ev) { return; case SC_RIGHT: if (cursorCol < lines[cursorRow].len) { - cursorCol++; + cursorCol = montauk::utf8::next_boundary(lines[cursorRow].data, + lines[cursorRow].len, cursorCol); } else if (cursorRow < numLines - 1) { cursorRow++; cursorCol = 0; @@ -836,20 +873,22 @@ static void handle_key(const montauk::abi::KeyEvent& ev) { cursorCol = lines[cursorRow].len; fullRedraw = true; return; - case SC_PGUP: + case SC_PGUP: { + int col = line_display_col(&lines[cursorRow], cursorCol); cursorRow -= editorRows; if (cursorRow < 0) cursorRow = 0; - if (cursorCol > lines[cursorRow].len) - cursorCol = lines[cursorRow].len; + cursorCol = line_byte_col(&lines[cursorRow], col); fullRedraw = true; return; - case SC_PGDN: + } + case SC_PGDN: { + int col = line_display_col(&lines[cursorRow], cursorCol); cursorRow += editorRows; if (cursorRow >= numLines) cursorRow = numLines - 1; - if (cursorCol > lines[cursorRow].len) - cursorCol = lines[cursorRow].len; + cursorCol = line_byte_col(&lines[cursorRow], col); fullRedraw = true; return; + } case SC_DELETE: delete_char_forward(); return; @@ -869,11 +908,11 @@ static void handle_key(const montauk::abi::KeyEvent& ev) { case '\t': insert_tab(); break; - default: - if (ev.ascii >= ' ') { - insert_char(ev.ascii); - } + default: { + char typed[montauk::utf8::MAX_BYTES]; + insert_bytes(typed, montauk::utf8::key_utf8(ev, typed)); break; + } } } diff --git a/programs/src/fontpreview/main.cpp b/programs/src/fontpreview/main.cpp index 8857eb1..1dd1110 100644 --- a/programs/src/fontpreview/main.cpp +++ b/programs/src/fontpreview/main.cpp @@ -402,12 +402,12 @@ extern "C" void _start() { if (ev.key.ascii == 'q' || ev.key.ascii == 'Q' || ev.key.scancode == 0x01) break; - if (ev.key.scancode == 0x48) { g_scroll_y -= SCROLL_STEP; redraw = true; } - if (ev.key.scancode == 0x50) { g_scroll_y += SCROLL_STEP; redraw = true; } - if (ev.key.scancode == 0x47) { g_scroll_y = 0; redraw = true; } - if (ev.key.scancode == 0x4F) { g_scroll_y = g_content_h; redraw = true; } - if (ev.key.scancode == 0x49) { g_scroll_y -= g_win_h; redraw = true; } - if (ev.key.scancode == 0x51) { g_scroll_y += g_win_h; redraw = true; } + if (montauk::nav_scancode(ev.key) == 0x48) { g_scroll_y -= SCROLL_STEP; redraw = true; } + if (montauk::nav_scancode(ev.key) == 0x50) { g_scroll_y += SCROLL_STEP; redraw = true; } + if (montauk::nav_scancode(ev.key) == 0x47) { g_scroll_y = 0; redraw = true; } + if (montauk::nav_scancode(ev.key) == 0x4F) { g_scroll_y = g_content_h; redraw = true; } + if (montauk::nav_scancode(ev.key) == 0x49) { g_scroll_y -= g_win_h; redraw = true; } + if (montauk::nav_scancode(ev.key) == 0x51) { g_scroll_y += g_win_h; redraw = true; } if (redraw) { clamp_scroll(); diff --git a/programs/src/imageviewer/main.cpp b/programs/src/imageviewer/main.cpp index ad6bdb8..34eb331 100644 --- a/programs/src/imageviewer/main.cpp +++ b/programs/src/imageviewer/main.cpp @@ -620,13 +620,13 @@ extern "C" void _start() { else if (key.ctrl && (key.ascii == '-' || key.ascii == 31)) { zoom_out(cx, cy); redraw = true; } // Arrow keys to pan - else if (key.scancode == 0x48) { g_pan_y += PAN_STEP; redraw = true; } - else if (key.scancode == 0x50) { g_pan_y -= PAN_STEP; redraw = true; } - else if (key.scancode == 0x4B) { g_pan_x += PAN_STEP; redraw = true; } - else if (key.scancode == 0x4D) { g_pan_x -= PAN_STEP; redraw = true; } + else if (montauk::nav_scancode(key) == 0x48) { g_pan_y += PAN_STEP; redraw = true; } + else if (montauk::nav_scancode(key) == 0x50) { g_pan_y -= PAN_STEP; redraw = true; } + else if (montauk::nav_scancode(key) == 0x4B) { g_pan_x += PAN_STEP; redraw = true; } + else if (montauk::nav_scancode(key) == 0x4D) { g_pan_x -= PAN_STEP; redraw = true; } // Home to center - else if (key.scancode == 0x47) { center_image(); redraw = true; } + else if (montauk::nav_scancode(key) == 0x47) { center_image(); redraw = true; } if (redraw && g_load_ok) clamp_pan(); } diff --git a/programs/src/installer/main.cpp b/programs/src/installer/main.cpp index 032147d..58b26d2 100644 --- a/programs/src/installer/main.cpp +++ b/programs/src/installer/main.cpp @@ -333,14 +333,14 @@ static bool handle_key(const montauk::abi::KeyEvent& key) { return true; } - if (key.scancode == 0x48) { // Up + if (montauk::nav_scancode(key) == 0x48) { // Up if (st.step == STEP_SELECT_DISK && st.selected_disk > 0) st.selected_disk--; else if (st.step == STEP_UPDATE_SELECT_PART && st.selected_part > 0) st.selected_part--; else if (st.step == STEP_PARTITION_SCHEME && st.partition_scheme > 0) st.partition_scheme--; - } else if (key.scancode == 0x50) { // Down + } else if (montauk::nav_scancode(key) == 0x50) { // Down if (st.step == STEP_SELECT_DISK && st.selected_disk < st.disk_count - 1) st.selected_disk++; else if (st.step == STEP_UPDATE_SELECT_PART && st.selected_part < st.part_count - 1) diff --git a/programs/src/installer/render.cpp b/programs/src/installer/render.cpp index 3f4c717..052bfc3 100644 --- a/programs/src/installer/render.cpp +++ b/programs/src/installer/render.cpp @@ -48,6 +48,8 @@ static void draw_text_fit(Canvas& c, int x, int y, out++; } + out = montauk::utf8::floor_boundary(text, montauk::slen(text), out); + if (out <= 0) return; buf[out] = '.'; buf[out + 1] = '.'; diff --git a/programs/src/irc/main.cpp b/programs/src/irc/main.cpp index 585d1fc..7b22017 100644 --- a/programs/src/irc/main.cpp +++ b/programs/src/irc/main.cpp @@ -7,6 +7,7 @@ #include #include +#include #include using montauk::slen; @@ -621,7 +622,7 @@ static void ui_render() { for (int i = 0; i < input.len; i++) sb_putc(input.buf[i]); // Position cursor at input insertion point - sb_cursor_to(term.rows, input.pos + 3); + sb_cursor_to(term.rows, montauk::utf8::count(input.buf, input.pos) + 3); // Single flush — entire screen in one print call sb_flush(); @@ -892,7 +893,7 @@ extern "C" void _start() { } // Handle special keys by scancode - switch (ev.scancode) { + switch (montauk::nav_scancode(ev)) { case 0x49: // Page Up if (msgBuf.scrollOffset < msgBuf.count - term.msgAreaRows) { msgBuf.scrollOffset += term.msgAreaRows / 2; @@ -922,22 +923,12 @@ extern "C" void _start() { input.len = 0; } } else if (ev.ascii == '\b') { - if (input.pos > 0) { - for (int j = input.pos - 1; j < input.len - 1; j++) { - input.buf[j] = input.buf[j + 1]; - } - input.pos--; - input.len--; - } - } else if (ev.ascii >= ' ' && ev.ascii <= '~') { - if (input.len < 510) { - for (int j = input.len; j > input.pos; j--) { - input.buf[j] = input.buf[j - 1]; - } - input.buf[input.pos] = ev.ascii; - input.pos++; - input.len++; - } + input.buf[input.len] = '\0'; + montauk::utf8::erase_before(input.buf, &input.len, &input.pos); + } else if (montauk::utf8::key_codepoint(ev)) { + // IRC text is UTF-8 + input.buf[input.len] = '\0'; + montauk::utf8::insert_key(input.buf, &input.len, 511, &input.pos, ev); } else { dirty = false; // Unhandled key, no redraw needed } diff --git a/programs/src/keyboard/main.cpp b/programs/src/keyboard/main.cpp index 98c5128..29d336c 100644 --- a/programs/src/keyboard/main.cpp +++ b/programs/src/keyboard/main.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -176,14 +177,16 @@ static void draw_layouts_tab(Canvas& c, const mtk::Theme& theme) { // Key Map tab: what the active layout actually remaps. Rows are identified by // the character the key produces unshifted, so no copy of the US scancode // table is needed here to name the physical keys. -static void draw_char_cell(Canvas& c, int x, int y, uint8_t byte, +static void draw_char_cell(Canvas& c, int x, int y, uint32_t cp, bool dead, const mtk::Theme& theme) { - char text[2] = {(char)byte, '\0'}; - if (byte == 0) { + if (cp == 0) { c.text(x, y, "-", theme.text_muted); - } else { - c.text(x, y, text, theme.text); + return; } + char text[5]; + text[montauk::utf8::encode(cp, text)] = '\0'; + // Dead keys (accents that combine with the next letter) in the accent color + c.text(x, y, text, dead ? theme.accent : theme.text); } static void draw_keymap_tab(Canvas& c, const mtk::Theme& theme) { @@ -220,9 +223,12 @@ static void draw_keymap_tab(Canvas& c, const mtk::Theme& theme) { if (index >= layout.key_count) break; const montauk::keyboard::KeyMap& key = layout.keys[index]; int y = list_y() + row * MAP_ROW_H; - draw_char_cell(c, gx + col[0], y, key.base, theme); - draw_char_cell(c, gx + col[1], y, key.shift, theme); - draw_char_cell(c, gx + col[2], y, key.altgr, theme); + draw_char_cell(c, gx + col[0], y, key.base, + montauk::keyboard::is_dead_key(layout, key.base), theme); + draw_char_cell(c, gx + col[1], y, key.shift, + montauk::keyboard::is_dead_key(layout, key.shift), theme); + draw_char_cell(c, gx + col[2], y, key.altgr, + montauk::keyboard::is_dead_key(layout, key.altgr), theme); } } diff --git a/programs/src/man/main.cpp b/programs/src/man/main.cpp index 7d9b303..b0659d7 100644 --- a/programs/src/man/main.cpp +++ b/programs/src/man/main.cpp @@ -319,7 +319,7 @@ extern "C" void _start() { break; default: // Handle scancodes for special keys - switch (ev.scancode) { + switch (montauk::nav_scancode(ev)) { case 0x48: // Up arrow if (scroll > 0) scroll--; break; diff --git a/programs/src/music/main.cpp b/programs/src/music/main.cpp index 766ff11..8ad53b1 100644 --- a/programs/src/music/main.cpp +++ b/programs/src/music/main.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -415,11 +416,6 @@ static char ascii_lower(char c) { return (c >= 'A' && c <= 'Z') ? (char)(c + 32) : c; } -static bool is_printable_byte(char c) { - unsigned char value = (unsigned char)c; - return value >= 32 && value != 127; -} - static bool str_contains_case_insensitive(const char* text, const char* needle) { if (!needle || !needle[0]) return true; if (!text || !text[0]) return false; @@ -516,19 +512,16 @@ static void rebuild_filtered_view() { ensure_selected_visible(); } -static void append_filter_char(char c) { +static void append_filter_key(const montauk::abi::KeyEvent& key) { int len = montauk::slen(g.filter_text); - if (len >= MAX_FILTER - 1) return; - g.filter_text[len] = c; - g.filter_text[len + 1] = '\0'; - rebuild_filtered_view(); + if (montauk::utf8::append_key(g.filter_text, &len, MAX_FILTER, key)) + rebuild_filtered_view(); } static void pop_filter_char() { int len = montauk::slen(g.filter_text); - if (len <= 0) return; - g.filter_text[len - 1] = '\0'; - rebuild_filtered_view(); + if (montauk::utf8::erase_last(g.filter_text, &len)) + rebuild_filtered_view(); } static void clear_filter() { @@ -1120,8 +1113,10 @@ static void render(uint32_t* pixels) { int qlen = montauk::slen(query); if (qlen > 15) { montauk::memcpy(filter_query, "...", 3); - montauk::memcpy(filter_query + 3, query + qlen - 15, 15); - filter_query[18] = '\0'; + int start = montauk::utf8::floor_boundary(query, qlen, qlen - 15); + if (start < qlen - 15) start = montauk::utf8::next_boundary(query, qlen, start); + montauk::memcpy(filter_query + 3, query + start, qlen - start); + filter_query[3 + qlen - start] = '\0'; query = filter_query; } @@ -1426,11 +1421,11 @@ static bool handle_key(const montauk::abi::KeyEvent& key, bool& quit) { return true; } - if (!g.show_visualizer && key.scancode == 0x48) { // Up + if (!g.show_visualizer && montauk::nav_scancode(key) == 0x48) { // Up move_selection(-1); return true; } - if (!g.show_visualizer && key.scancode == 0x50) { // Down + if (!g.show_visualizer && montauk::nav_scancode(key) == 0x50) { // Down move_selection(1); return true; } @@ -1449,8 +1444,8 @@ static bool handle_key(const montauk::abi::KeyEvent& key, bool& quit) { else g.filter_active = false; return true; } - if (!key.ctrl && !key.alt && is_printable_byte(key.ascii)) { - append_filter_char(key.ascii); + if (!key.ctrl && !key.alt && montauk::utf8::key_codepoint(key)) { + append_filter_key(key); return true; } return false; @@ -1479,11 +1474,11 @@ static bool handle_key(const montauk::abi::KeyEvent& key, bool& quit) { g.show_visualizer = !g.show_visualizer; return true; } - if (key.scancode == 0x4D) { // Right arrow + if (montauk::nav_scancode(key) == 0x4D) { // Right arrow next_track(false); return true; } - if (key.scancode == 0x4B) { // Left arrow + if (montauk::nav_scancode(key) == 0x4B) { // Left arrow prev_track(); return true; } diff --git a/programs/src/network/main.cpp b/programs/src/network/main.cpp index 2b8fc14..bc4947b 100644 --- a/programs/src/network/main.cpp +++ b/programs/src/network/main.cpp @@ -247,6 +247,7 @@ static void fit_text(char* out, int out_cap, const char* text, int max_w) { break; out_len++; } + out_len = montauk::utf8::floor_boundary(text, montauk::slen(text), out_len); out[out_len] = '.'; out[out_len + 1] = '.'; out[out_len + 2] = '.'; @@ -1216,8 +1217,8 @@ static bool handle_key(const montauk::abi::KeyEvent& key) { wifi_join_selected(); return true; } - if (key.scancode == 0x48 || key.scancode == 0x50) { // up / down - int step = key.scancode == 0x48 ? -1 : 1; + if (montauk::nav_scancode(key) == 0x48 || montauk::nav_scancode(key) == 0x50) { // up / down + int step = montauk::nav_scancode(key) == 0x48 ? -1 : 1; int next = g_wifi_selected < 0 ? 0 : g_wifi_selected + step; if (next < 0) next = 0; if (next >= g_wifi_count) next = g_wifi_count - 1; diff --git a/programs/src/pdfviewer/main.cpp b/programs/src/pdfviewer/main.cpp index ae0d425..36ae05d 100644 --- a/programs/src/pdfviewer/main.cpp +++ b/programs/src/pdfviewer/main.cpp @@ -235,25 +235,13 @@ extern "C" void _start() { } else if (key.scancode == 0x01) { g_pathbar_open = false; } else if (key.ascii == '\b' || key.scancode == 0x0E) { - if (g_pathbar_cursor > 0) { - for (int i = g_pathbar_cursor - 1; i < g_pathbar_len - 1; i++) - g_pathbar_text[i] = g_pathbar_text[i + 1]; - g_pathbar_len--; - g_pathbar_cursor--; - g_pathbar_text[g_pathbar_len] = '\0'; - } - } else if (key.scancode == 0x4B) { - if (g_pathbar_cursor > 0) g_pathbar_cursor--; - } else if (key.scancode == 0x4D) { - if (g_pathbar_cursor < g_pathbar_len) g_pathbar_cursor++; - } else if ((unsigned char)key.ascii >= 32 - && (unsigned char)key.ascii != 127 && g_pathbar_len < 254) { - for (int i = g_pathbar_len; i > g_pathbar_cursor; i--) - g_pathbar_text[i] = g_pathbar_text[i - 1]; - g_pathbar_text[g_pathbar_cursor] = key.ascii; - g_pathbar_cursor++; - g_pathbar_len++; - g_pathbar_text[g_pathbar_len] = '\0'; + montauk::utf8::erase_before(g_pathbar_text, &g_pathbar_len, &g_pathbar_cursor); + } else if (montauk::nav_scancode(key) == 0x4B) { + g_pathbar_cursor = montauk::utf8::prev_boundary(g_pathbar_text, g_pathbar_cursor); + } else if (montauk::nav_scancode(key) == 0x4D) { + g_pathbar_cursor = montauk::utf8::next_boundary(g_pathbar_text, g_pathbar_len, g_pathbar_cursor); + } else { + montauk::utf8::insert_key(g_pathbar_text, &g_pathbar_len, 255, &g_pathbar_cursor, key); } redraw = true; goto done_keys; @@ -274,9 +262,9 @@ extern "C" void _start() { redraw = true; } // Page Down / Right arrow: next page - else if (key.scancode == 0x51 || key.scancode == 0x4D) { + else if (montauk::nav_scancode(key) == 0x51 || montauk::nav_scancode(key) == 0x4D) { if (g_doc.valid) { - if (key.scancode == 0x4D && g_scroll_y < max_scroll()) { + if (montauk::nav_scancode(key) == 0x4D && g_scroll_y < max_scroll()) { // Right arrow scrolls down within page } else { go_to_page(g_current_page + 1); @@ -285,9 +273,9 @@ extern "C" void _start() { } } // Page Up / Left arrow: previous page - else if (key.scancode == 0x49 || key.scancode == 0x4B) { + else if (montauk::nav_scancode(key) == 0x49 || montauk::nav_scancode(key) == 0x4B) { if (g_doc.valid) { - if (key.scancode == 0x4B && g_scroll_y > 0) { + if (montauk::nav_scancode(key) == 0x4B && g_scroll_y > 0) { // Left arrow scrolls up within page } else { go_to_page(g_current_page - 1); @@ -296,23 +284,23 @@ extern "C" void _start() { } } // Up arrow: scroll up - else if (key.scancode == 0x48) { + else if (montauk::nav_scancode(key) == 0x48) { g_scroll_y -= SCROLL_STEP; clamp_scroll(); redraw = true; } // Down arrow: scroll down - else if (key.scancode == 0x50) { + else if (montauk::nav_scancode(key) == 0x50) { g_scroll_y += SCROLL_STEP; clamp_scroll(); redraw = true; } // Home: first page - else if (key.scancode == 0x47) { + else if (montauk::nav_scancode(key) == 0x47) { if (g_doc.valid) { go_to_page(0); redraw = true; } } // End: last page - else if (key.scancode == 0x4F) { + else if (montauk::nav_scancode(key) == 0x4F) { if (g_doc.valid) { go_to_page(g_doc.page_count - 1); redraw = true; } } // Ctrl++ or Ctrl+=: zoom in diff --git a/programs/src/pdfviewer/render.cpp b/programs/src/pdfviewer/render.cpp index 9b373d1..cd3d18a 100644 --- a/programs/src/pdfviewer/render.cpp +++ b/programs/src/pdfviewer/render.cpp @@ -71,7 +71,7 @@ static void draw_affine_text(uint32_t* pixels, const TextItem& item, by0>-0.0001f&&by0<0.0001f&&by1>-0.0001f&&by1<0.0001f) { float pen=0; for(int i=0;iget_glyph(cache,(uint8_t)text[i]); + CachedGlyph* glyph=font->get_glyph(cache,decode_single_byte_codepoint((uint8_t)text[i])); if(!glyph)continue; if(glyph->bitmap) { int gx=base_x+floor_pixel(pen*g_zoom+0.5f)+glyph->xoff; @@ -101,7 +101,7 @@ static void draw_affine_text(uint32_t* pixels, const TextItem& item, float pen = 0; for (int i = 0; i < text_len; i++) { - CachedGlyph* glyph = font->get_glyph(cache, (uint8_t)text[i]); + CachedGlyph* glyph = font->get_glyph(cache, decode_single_byte_codepoint((uint8_t)text[i])); if (!glyph) continue; if (glyph->bitmap) { float gx0 = (float)(pen + glyph->xoff); diff --git a/programs/src/printd/test_page_jpeg.cpp b/programs/src/printd/test_page_jpeg.cpp index fee9800..1fd40ca 100644 --- a/programs/src/printd/test_page_jpeg.cpp +++ b/programs/src/printd/test_page_jpeg.cpp @@ -143,14 +143,8 @@ static gui::TrueTypeFont* load_page_font(const char* path) { static void free_page_font(gui::TrueTypeFont* font) { if (!font) return; - for (int i = 0; i < font->cache_count; i++) { - for (int g = 0; g < 256; g++) { - if (font->caches[i].glyphs[g].bitmap) { - montauk::mfree(font->caches[i].glyphs[g].bitmap); - font->caches[i].glyphs[g].bitmap = nullptr; - } - } - } + for (int i = 0; i < font->cache_count; i++) + gui::TrueTypeFont::free_cache(&font->caches[i]); if (font->data) { montauk::free(font->data); font->data = nullptr; @@ -209,8 +203,8 @@ static void draw_text(uint8_t* rgb, PageFonts* fonts, bool bold, int cx = x; int baseline = y + gc->ascent; - for (int i = 0; text[i] != '\0'; i++) { - gui::CachedGlyph* glyph = font->get_glyph(gc, (unsigned char)text[i]); + for (const char* p = text; *p;) { + gui::CachedGlyph* glyph = font->get_glyph(gc, (int)montauk::utf8::next(&p)); if (!glyph) continue; if (glyph->bitmap) { diff --git a/programs/src/printers/main.cpp b/programs/src/printers/main.cpp index de25350..e1d38ed 100644 --- a/programs/src/printers/main.cpp +++ b/programs/src/printers/main.cpp @@ -230,7 +230,8 @@ static void text_fit(const char* src, char* out, int out_len, int max_w) { int keep = montauk::slen(src); while (keep > 0) { char tmp[MAX_DEBUG_LEN]; - int n = keep < (int)sizeof(tmp) - 4 ? keep : (int)sizeof(tmp) - 4; + int n = keep < (int)sizeof(tmp) - 4 ? keep + : montauk::utf8::floor_boundary(src, keep, (int)sizeof(tmp) - 4); for (int i = 0; i < n; i++) tmp[i] = src[i]; tmp[n] = '\0'; str_append(tmp, ell, (int)sizeof(tmp)); @@ -238,7 +239,7 @@ static void text_fit(const char* src, char* out, int out_len, int max_w) { montauk::strncpy(out, tmp, out_len - 1); return; } - keep--; + keep = montauk::utf8::prev_boundary(src, keep); } montauk::strncpy(out, ell, out_len - 1); } @@ -1162,12 +1163,12 @@ static void handle_key(const montauk::abi::KeyEvent& key) { return; } - if (key.scancode == 0x4B) { + if (montauk::nav_scancode(key) == 0x4B) { cycle_tab(-1); return; } - if (key.scancode == 0x4D) { + if (montauk::nav_scancode(key) == 0x4D) { cycle_tab(1); return; } diff --git a/programs/src/procmgr/main.cpp b/programs/src/procmgr/main.cpp index d88ffcd..841ef8a 100644 --- a/programs/src/procmgr/main.cpp +++ b/programs/src/procmgr/main.cpp @@ -527,6 +527,8 @@ static void draw_text_fit(Canvas& c, int x, int y, out++; } + out = montauk::utf8::floor_boundary(text, montauk::slen(text), out); + if (out <= 0) return; buf[out] = '.'; buf[out + 1] = '.'; @@ -852,24 +854,24 @@ static bool handle_key(const montauk::abi::KeyEvent& key) { return true; } - if (key.scancode == 0x4B) { + if (montauk::nav_scancode(key) == 0x4B) { cycle_tab(-1); return true; } - if (key.scancode == 0x4D) { + if (montauk::nav_scancode(key) == 0x4D) { cycle_tab(1); return true; } - if (key.scancode == 0x53) { + if (montauk::nav_scancode(key) == 0x53) { if (can_kill_selected()) { kill_selected(); return true; } } - if (key.scancode == 0x48) { + if (montauk::nav_scancode(key) == 0x48) { if (g_pm.active_tab == PM_TAB_PROCESSES) { if (g_pm.selected > 0) g_pm.selected--; else if (g_pm.proc_count > 0) g_pm.selected = 0; @@ -884,7 +886,7 @@ static bool handle_key(const montauk::abi::KeyEvent& key) { } } - if (key.scancode == 0x50) { + if (montauk::nav_scancode(key) == 0x50) { if (g_pm.active_tab == PM_TAB_PROCESSES) { if (g_pm.selected < g_pm.proc_count - 1) g_pm.selected++; else if (g_pm.selected < 0 && g_pm.proc_count > 0) g_pm.selected = 0; diff --git a/programs/src/shell/main.cpp b/programs/src/shell/main.cpp index 9da0029..1ef09e5 100644 --- a/programs/src/shell/main.cpp +++ b/programs/src/shell/main.cpp @@ -92,7 +92,9 @@ static void prompt() { // ---- Line editing ---- -static void erase_input(int len) { +// Erase the echoed input: one terminal cell per UTF-8 character. +static void erase_input(const char* line, int bytes) { + int len = montauk::utf8::count(line, bytes); for (int i = 0; i < len; i++) montauk::putchar('\b'); for (int i = 0; i < len; i++) montauk::putchar(' '); for (int i = 0; i < len; i++) montauk::putchar('\b'); @@ -100,9 +102,9 @@ static void erase_input(int len) { static void replace_line(char* line, int* pos, const char* newContent) { int oldLen = *pos; - erase_input(oldLen); + erase_input(line, oldLen); int newLen = slen(newContent); - if (newLen > 255) newLen = 255; + if (newLen > 255) newLen = montauk::utf8::floor_boundary(newContent, newLen, 255); for (int i = 0; i < newLen; i++) { line[i] = newContent[i]; montauk::putchar(newContent[i]); @@ -431,14 +433,14 @@ extern "C" void _start() { // Arrow keys: ascii == 0, check scancode if (ev.ascii == 0) { - if (ev.scancode == SC_UP) { + if (montauk::nav_scancode(ev) == SC_UP) { int next = hist_nav + 1; const char* entry = history_get(next); if (entry) { hist_nav = next; replace_line(line, &pos, entry); } - } else if (ev.scancode == SC_DOWN) { + } else if (montauk::nav_scancode(ev) == SC_DOWN) { if (hist_nav > 0) { hist_nav--; const char* entry = history_get(hist_nav); @@ -447,7 +449,7 @@ extern "C" void _start() { } } else if (hist_nav == 0) { hist_nav = -1; - erase_input(pos); + erase_input(line, pos); pos = 0; line[0] = '\0'; } @@ -496,15 +498,18 @@ extern "C" void _start() { hist_nav = -1; prompt(); } else if (ev.ascii == '\b') { - if (pos > 0) { - pos--; + // One terminal cell per character, however many UTF-8 bytes + line[pos] = '\0'; + if (montauk::utf8::erase_last(line, &pos)) { montauk::putchar('\b'); montauk::putchar(' '); montauk::putchar('\b'); } - } else if (ev.ascii >= ' ' && pos < 255) { - line[pos++] = ev.ascii; - montauk::putchar(ev.ascii); + } else { + line[pos] = '\0'; + int before = pos; + if (montauk::utf8::append_key(line, &pos, 256, ev)) + montauk::print(line + before); } } } diff --git a/programs/src/shell/shell.h b/programs/src/shell/shell.h index 86c52c1..b0350bb 100644 --- a/programs/src/shell/shell.h +++ b/programs/src/shell/shell.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/programs/src/spreadsheet/main.cpp b/programs/src/spreadsheet/main.cpp index 301af2e..18afade 100644 --- a/programs/src/spreadsheet/main.cpp +++ b/programs/src/spreadsheet/main.cpp @@ -415,25 +415,13 @@ extern "C" void _start() { } else if (key.scancode == 0x01) { g_pathbar_open = false; } else if (key.ascii == '\b' || key.scancode == 0x0E) { - if (g_pathbar_cursor > 0) { - for (int i = g_pathbar_cursor - 1; i < g_pathbar_len - 1; i++) - g_pathbar_text[i] = g_pathbar_text[i + 1]; - g_pathbar_len--; - g_pathbar_cursor--; - g_pathbar_text[g_pathbar_len] = '\0'; - } - } else if (key.scancode == 0x4B) { - if (g_pathbar_cursor > 0) g_pathbar_cursor--; - } else if (key.scancode == 0x4D) { - if (g_pathbar_cursor < g_pathbar_len) g_pathbar_cursor++; - } else if ((unsigned char)key.ascii >= 32 - && (unsigned char)key.ascii != 127 && g_pathbar_len < 254) { - for (int i = g_pathbar_len; i > g_pathbar_cursor; i--) - g_pathbar_text[i] = g_pathbar_text[i - 1]; - g_pathbar_text[g_pathbar_cursor] = key.ascii; - g_pathbar_cursor++; - g_pathbar_len++; - g_pathbar_text[g_pathbar_len] = '\0'; + montauk::utf8::erase_before(g_pathbar_text, &g_pathbar_len, &g_pathbar_cursor); + } else if (montauk::nav_scancode(key) == 0x4B) { + g_pathbar_cursor = montauk::utf8::prev_boundary(g_pathbar_text, g_pathbar_cursor); + } else if (montauk::nav_scancode(key) == 0x4D) { + g_pathbar_cursor = montauk::utf8::next_boundary(g_pathbar_text, g_pathbar_len, g_pathbar_cursor); + } else { + montauk::utf8::insert_key(g_pathbar_text, &g_pathbar_len, 255, &g_pathbar_cursor, key); } redraw = true; goto done_keys; @@ -441,12 +429,12 @@ extern "C" void _start() { // Autocomplete interaction (when editing with autocomplete open) if (g_ac_open && g_editing) { - if (key.scancode == 0x48) { // Up + if (montauk::nav_scancode(key) == 0x48) { // Up g_ac_sel = (g_ac_sel - 1 + g_ac_count) % g_ac_count; redraw = true; goto done_keys; } - if (key.scancode == 0x50) { // Down + if (montauk::nav_scancode(key) == 0x50) { // Down g_ac_sel = (g_ac_sel + 1) % g_ac_count; redraw = true; goto done_keys; @@ -498,7 +486,7 @@ extern "C" void _start() { redraw = true; } // Arrow keys (with Shift = extend selection) - else if (key.scancode == 0x48 && !g_editing) { // Up + else if (montauk::nav_scancode(key) == 0x48 && !g_editing) { // Up if (key.shift) { if (!g_has_selection) { g_anchor_col = g_sel_col; g_anchor_row = g_sel_row; g_has_selection = true; } if (g_sel_row > 0) g_sel_row--; @@ -509,7 +497,7 @@ extern "C" void _start() { ensure_sel_visible(); redraw = true; } - else if (key.scancode == 0x50 && !g_editing) { // Down + else if (montauk::nav_scancode(key) == 0x50 && !g_editing) { // Down if (key.shift) { if (!g_has_selection) { g_anchor_col = g_sel_col; g_anchor_row = g_sel_row; g_has_selection = true; } if (g_sel_row < MAX_ROWS - 1) g_sel_row++; @@ -520,7 +508,7 @@ extern "C" void _start() { ensure_sel_visible(); redraw = true; } - else if (key.scancode == 0x4B && !g_editing) { // Left + else if (montauk::nav_scancode(key) == 0x4B && !g_editing) { // Left if (key.shift) { if (!g_has_selection) { g_anchor_col = g_sel_col; g_anchor_row = g_sel_row; g_has_selection = true; } if (g_sel_col > 0) g_sel_col--; @@ -531,7 +519,7 @@ extern "C" void _start() { ensure_sel_visible(); redraw = true; } - else if (key.scancode == 0x4D && !g_editing) { // Right + else if (montauk::nav_scancode(key) == 0x4D && !g_editing) { // Right if (key.shift) { if (!g_has_selection) { g_anchor_col = g_sel_col; g_anchor_row = g_sel_row; g_has_selection = true; } if (g_sel_col < MAX_COLS - 1) g_sel_col++; @@ -545,14 +533,8 @@ extern "C" void _start() { // Backspace else if (key.ascii == '\b' || key.scancode == 0x0E) { if (g_editing) { - if (g_edit_cursor > 0) { - for (int i = g_edit_cursor - 1; i < g_edit_len - 1; i++) - g_edit_buf[i] = g_edit_buf[i + 1]; - g_edit_len--; - g_edit_cursor--; - g_edit_buf[g_edit_len] = '\0'; + if (montauk::utf8::erase_before(g_edit_buf, &g_edit_len, &g_edit_cursor)) update_autocomplete(); - } redraw = true; } else { undo_push(); @@ -567,15 +549,10 @@ extern "C" void _start() { } } // Delete key - else if (key.scancode == 0x53) { + else if (montauk::nav_scancode(key) == 0x53) { if (g_editing) { - if (g_edit_cursor < g_edit_len) { - for (int i = g_edit_cursor; i < g_edit_len - 1; i++) - g_edit_buf[i] = g_edit_buf[i + 1]; - g_edit_len--; - g_edit_buf[g_edit_len] = '\0'; + if (montauk::utf8::erase_at(g_edit_buf, &g_edit_len, g_edit_cursor)) update_autocomplete(); - } redraw = true; } else { undo_push(); @@ -590,18 +567,18 @@ extern "C" void _start() { } } // Edit mode arrow keys (cursor movement within formula bar) - else if (key.scancode == 0x4B && g_editing) { - if (g_edit_cursor > 0) g_edit_cursor--; + else if (montauk::nav_scancode(key) == 0x4B && g_editing) { + g_edit_cursor = montauk::utf8::prev_boundary(g_edit_buf, g_edit_cursor); update_autocomplete(); redraw = true; } - else if (key.scancode == 0x4D && g_editing) { - if (g_edit_cursor < g_edit_len) g_edit_cursor++; + else if (montauk::nav_scancode(key) == 0x4D && g_editing) { + g_edit_cursor = montauk::utf8::next_boundary(g_edit_buf, g_edit_len, g_edit_cursor); update_autocomplete(); redraw = true; } // Home key - else if (key.scancode == 0x47) { + else if (montauk::nav_scancode(key) == 0x47) { if (g_editing) { g_edit_cursor = 0; update_autocomplete(); @@ -613,7 +590,7 @@ extern "C" void _start() { redraw = true; } // End key - else if (key.scancode == 0x4F) { + else if (montauk::nav_scancode(key) == 0x4F) { if (g_editing) { g_edit_cursor = g_edit_len; update_autocomplete(); @@ -670,23 +647,16 @@ extern "C" void _start() { redraw = true; } // Printable character: start editing or insert - else if ((unsigned char)key.ascii >= 32 - && (unsigned char)key.ascii != 127 && !key.ctrl) { + else if (montauk::utf8::key_codepoint(key) && !key.ctrl) { if (!g_editing) { clear_selection(); g_editing = true; - g_edit_buf[0] = key.ascii; - g_edit_buf[1] = '\0'; - g_edit_len = 1; - g_edit_cursor = 1; - } else if (g_edit_len < CELL_TEXT_MAX - 1) { - for (int i = g_edit_len; i > g_edit_cursor; i--) - g_edit_buf[i] = g_edit_buf[i - 1]; - g_edit_buf[g_edit_cursor] = key.ascii; - g_edit_len++; - g_edit_cursor++; - g_edit_buf[g_edit_len] = '\0'; + g_edit_buf[0] = '\0'; + g_edit_len = 0; + g_edit_cursor = 0; } + montauk::utf8::insert_key(g_edit_buf, &g_edit_len, CELL_TEXT_MAX, + &g_edit_cursor, key); update_autocomplete(); redraw = true; } diff --git a/programs/src/sshd/main.cpp b/programs/src/sshd/main.cpp index 6144e89..057a7b3 100644 --- a/programs/src/sshd/main.cpp +++ b/programs/src/sshd/main.cpp @@ -7,6 +7,7 @@ #include #include +#include #include extern "C" { @@ -1009,8 +1010,20 @@ static void feed_child(int pid, const uint8_t* data, int size) { /* Remaining C0 codes are the control-modified letters. */ key.ascii = (char)('a' + value - 1); key.ctrl = true; - } else { + } else if (value < 0x80) { key.ascii = (char)value; + key.codepoint = value; + } else { + /* The client sends UTF-8; the key event carries the codepoint plus + its Windows-1252 byte for legacy readers. A keystroke's sequence + arrives in one packet, so splitting across feed_child calls is + ignored. */ + int n; + uint32_t cp = montauk::utf8::decode((const char*)data + i, size - i, &n); + i += n - 1; + uint8_t b = montauk::utf8::to_cp1252(cp); + key.codepoint = cp; + key.ascii = b ? (char)b : montauk::abi::KEY_ASCII_SUBSTITUTE; } montauk::childio_writekey(pid, &key); diff --git a/programs/src/tcpconnect/main.cpp b/programs/src/tcpconnect/main.cpp index 5b6ad53..de69e6c 100644 --- a/programs/src/tcpconnect/main.cpp +++ b/programs/src/tcpconnect/main.cpp @@ -5,6 +5,7 @@ */ #include +#include #include using montauk::skip_spaces; @@ -176,15 +177,18 @@ extern "C" void _start() { montauk::send(fd, sendBuf, sendPos); sendPos = 0; } else if (ev.ascii == '\b') { - if (sendPos > 0) { - sendPos--; + sendBuf[sendPos] = '\0'; + if (montauk::utf8::erase_last(sendBuf, &sendPos)) { montauk::putchar('\b'); montauk::putchar(' '); montauk::putchar('\b'); } - } else if (ev.ascii >= ' ' && sendPos < 254) { - sendBuf[sendPos++] = ev.ascii; - montauk::putchar(ev.ascii); + } else { + // Typed text is sent as UTF-8; leave room for the '\n' + sendBuf[sendPos] = '\0'; + int before = sendPos; + if (montauk::utf8::append_key(sendBuf, &sendPos, 255, ev)) + montauk::print(sendBuf + before); } } else { montauk::wait_handle(fd, montauk::abi::IPC_SIGNAL_READABLE | montauk::abi::IPC_SIGNAL_PEER_CLOSED, 10); diff --git a/programs/src/terminal/settings.cpp b/programs/src/terminal/settings.cpp index 15d3763..5d26d04 100644 --- a/programs/src/terminal/settings.cpp +++ b/programs/src/terminal/settings.cpp @@ -479,9 +479,9 @@ static void handle_key(const montauk::abi::KeyEvent& key) { step_font_size(FONT_SIZE_STEP); } else if (key.ascii == '-') { step_font_size(-FONT_SIZE_STEP); - } else if (key.scancode == 0x48) { // Up + } else if (montauk::nav_scancode(key) == 0x48) { // Up select_theme(g_panel.theme_index - 1); - } else if (key.scancode == 0x50) { // Down + } else if (montauk::nav_scancode(key) == 0x50) { // Down select_theme(g_panel.theme_index + 1); } } diff --git a/programs/src/texteditor/main.cpp b/programs/src/texteditor/main.cpp index 8ccaba0..b6b9271 100644 --- a/programs/src/texteditor/main.cpp +++ b/programs/src/texteditor/main.cpp @@ -94,7 +94,7 @@ int g_line_count = 0; // Cursor int g_cursor_pos = 0; // byte position int g_cursor_line = 0; -int g_cursor_col = 0; +int g_cursor_col = 0; // character (display) column, not bytes int g_scroll_y = 0; // first visible line int g_scroll_x = 0; // horizontal scroll in pixels bool g_scroll_dragging = false; @@ -264,7 +264,8 @@ static void update_cursor_pos() { break; } } - g_cursor_col = g_cursor_pos - g_line_offsets[g_cursor_line]; + int ls = g_line_offsets[g_cursor_line]; + g_cursor_col = montauk::utf8::count(g_buffer + ls, g_cursor_pos - ls); g_cursor_moved = true; } @@ -275,6 +276,12 @@ static int line_length(int line) { return end - start; } +// Byte offset of character column `col` on a line (clamped to its end). +static int line_col_to_pos(int line, int col) { + int start = g_line_offsets[line]; + return start + montauk::utf8::offset_of(g_buffer + start, line_length(line), col); +} + // ============================================================================ // Buffer operations // ============================================================================ @@ -294,17 +301,10 @@ static void delete_range(int start, int count) { g_buf_len -= count; } +static void insert_string(const char* s, int len); + static void insert_char(char c) { - if (g_buf_len >= MAX_CAP - 1) return; - ensure_capacity(1); - for (int i = g_buf_len; i > g_cursor_pos; i--) - g_buffer[i] = g_buffer[i - 1]; - g_buffer[g_cursor_pos] = c; - g_buf_len++; - g_cursor_pos++; - g_modified = true; - recompute_lines(); - update_cursor_pos(); + insert_string(&c, 1); } static void insert_string(const char* s, int len) { @@ -323,8 +323,9 @@ static void insert_string(const char* s, int len) { static void backspace() { if (g_cursor_pos <= 0) return; - g_cursor_pos--; - delete_range(g_cursor_pos, 1); + int start = montauk::utf8::prev_boundary(g_buffer, g_cursor_pos); + delete_range(start, g_cursor_pos - start); + g_cursor_pos = start; g_modified = true; recompute_lines(); update_cursor_pos(); @@ -332,7 +333,8 @@ static void backspace() { static void delete_char() { if (g_cursor_pos >= g_buf_len) return; - delete_range(g_cursor_pos, 1); + delete_range(g_cursor_pos, + montauk::utf8::next_boundary(g_buffer, g_buf_len, g_cursor_pos) - g_cursor_pos); g_modified = true; recompute_lines(); update_cursor_pos(); @@ -344,30 +346,28 @@ static void delete_char() { static void move_up() { if (g_cursor_line <= 0) return; - int col = g_cursor_col; - int prev = g_cursor_line - 1; - int len = line_length(prev); - if (col > len) col = len; - g_cursor_pos = g_line_offsets[prev] + col; + g_cursor_pos = line_col_to_pos(g_cursor_line - 1, g_cursor_col); update_cursor_pos(); } static void move_down() { if (g_cursor_line >= g_line_count - 1) return; - int col = g_cursor_col; - int next = g_cursor_line + 1; - int len = line_length(next); - if (col > len) col = len; - g_cursor_pos = g_line_offsets[next] + col; + g_cursor_pos = line_col_to_pos(g_cursor_line + 1, g_cursor_col); update_cursor_pos(); } static void move_left() { - if (g_cursor_pos > 0) { g_cursor_pos--; update_cursor_pos(); } + if (g_cursor_pos > 0) { + g_cursor_pos = montauk::utf8::prev_boundary(g_buffer, g_cursor_pos); + update_cursor_pos(); + } } static void move_right() { - if (g_cursor_pos < g_buf_len) { g_cursor_pos++; update_cursor_pos(); } + if (g_cursor_pos < g_buf_len) { + g_cursor_pos = montauk::utf8::next_boundary(g_buffer, g_buf_len, g_cursor_pos); + update_cursor_pos(); + } } static void move_home() { @@ -621,6 +621,25 @@ static bool load_file(const char* path) { return false; } + // Files written before MontaukOS moved to UTF-8 are Windows-1252. Convert + // them once on load, so edits (which insert UTF-8) never mix encodings + // and saving writes the whole file back as UTF-8. + bool converted = false; + if (!montauk::utf8::valid(temp, got)) { + int conv_cap = got * 3 + 1; + if (conv_cap > MAX_CAP) conv_cap = MAX_CAP; + char* conv = (char*)montauk::malloc(conv_cap); + if (!conv) { + montauk::mfree(temp); + set_status("Out of memory while opening file"); + return false; + } + got = montauk::utf8::normalize(temp, got, conv, conv_cap); + montauk::mfree(temp); + temp = conv; + converted = true; + } + if (got >= g_buf_cap) { int new_cap = got + 1024; if (new_cap > MAX_CAP) new_cap = MAX_CAP; @@ -649,7 +668,7 @@ static bool load_file(const char* path) { g_syntax_language = syn_detect_language(g_filepath); clear_selection(); - set_status(""); + set_status(converted ? "Converted from Windows-1252 to UTF-8" : ""); recompute_lines(); update_cursor_pos(); @@ -686,10 +705,8 @@ static int hit_test(int mx, int my, int editor_y) { int clicked_col = (mx - LINE_NUM_W - 4 + g_scroll_x + cell_w / 2) / cell_w; if (clicked_col < 0) clicked_col = 0; - int ll = line_length(clicked_line); - if (clicked_col > ll) clicked_col = ll; - return g_line_offsets[clicked_line] + clicked_col; + return line_col_to_pos(clicked_line, clicked_col); } static void draw_context_menu(uint32_t* pixels, int W, int H) { @@ -861,14 +878,19 @@ static void render(uint32_t* pixels) { syn_highlight_line(g_buffer + line_start, line_len, syn_line_buf, SYN_LINE_BUF_CAP, g_syntax_language, syn_state); - for (int ci = 0; ci < line_len; ci++) { - int px_x = text_start_x + ci * cell_w - g_scroll_x; + // One monospace cell per character; ci walks bytes, col walks cells. + for (int ci = 0, col = 0; ci < line_len; col++) { + int ch_bytes; + uint32_t ch = montauk::utf8::decode(g_buffer + line_start + ci, + line_len - ci, &ch_bytes); + int byte_pos = line_start + ci; + int syn_index = ci; + ci += ch_bytes; + + int px_x = text_start_x + col * cell_w - g_scroll_x; if (px_x + cell_w <= LINE_NUM_W + 1) continue; if (px_x >= text_area_w) break; - int byte_pos = line_start + ci; - char ch = g_buffer[byte_pos]; - // Selection highlight if (g_has_selection && byte_pos >= sel_s && byte_pos < sel_e) { int hl_h = cell_h; @@ -878,22 +900,24 @@ static void render(uint32_t* pixels) { } Color char_color = TEXT_COLOR; - if (g_syntax_language != SYN_LANG_NONE && ci < syn_len) - char_color = syn_color(syn_line_buf[ci]); + if (g_syntax_language != SYN_LANG_NONE && syn_index < syn_len) + char_color = syn_color(syn_line_buf[syn_index]); - if (ch >= 32 || ch < 0) { + if (ch >= 32) { if (gc) { g_font_mono->draw_char_to_buffer(pixels, W, H, px_x, py + gc->ascent, - ch, char_color, gc); + (int)ch, char_color, gc); } } } + // Selection highlight for newline at end of line if (g_has_selection && line + 1 < g_line_count) { int nl_pos = line_start + line_len; if (nl_pos >= sel_s && nl_pos < sel_e) { - int px_x = text_start_x + line_len * cell_w - g_scroll_x; + int line_cols = montauk::utf8::count(g_buffer + line_start, line_len); + int px_x = text_start_x + line_cols * cell_w - g_scroll_x; if (px_x > LINE_NUM_W && px_x < text_area_w) { int hl_h = cell_h; if (py + hl_h > editor_y + text_area_h) hl_h = editor_y + text_area_h - py; @@ -1052,25 +1076,12 @@ static bool handle_key(montauk::abi::KeyEvent& key, int win_id) { return true; } if (key.ascii == '\b' || key.scancode == 0x0E) { - if (g_pathbar_cursor > 0) { - for (int i = g_pathbar_cursor - 1; i < g_pathbar_len - 1; i++) - g_pathbar_text[i] = g_pathbar_text[i + 1]; - g_pathbar_len--; - g_pathbar_cursor--; - g_pathbar_text[g_pathbar_len] = '\0'; - } + montauk::utf8::erase_before(g_pathbar_text, &g_pathbar_len, &g_pathbar_cursor); return true; } - if (key.scancode == 0x4B) { if (g_pathbar_cursor > 0) g_pathbar_cursor--; return true; } - if (key.scancode == 0x4D) { if (g_pathbar_cursor < g_pathbar_len) g_pathbar_cursor++; return true; } - if ((unsigned char)key.ascii >= 32 - && (unsigned char)key.ascii != 127 && g_pathbar_len < 254) { - for (int i = g_pathbar_len; i > g_pathbar_cursor; i--) - g_pathbar_text[i] = g_pathbar_text[i - 1]; - g_pathbar_text[g_pathbar_cursor] = key.ascii; - g_pathbar_cursor++; - g_pathbar_len++; - g_pathbar_text[g_pathbar_len] = '\0'; + if (montauk::nav_scancode(key) == 0x4B) { g_pathbar_cursor = montauk::utf8::prev_boundary(g_pathbar_text, g_pathbar_cursor); return true; } + if (montauk::nav_scancode(key) == 0x4D) { g_pathbar_cursor = montauk::utf8::next_boundary(g_pathbar_text, g_pathbar_len, g_pathbar_cursor); return true; } + if (montauk::utf8::insert_key(g_pathbar_text, &g_pathbar_len, 255, &g_pathbar_cursor, key)) { return true; } return false; @@ -1123,19 +1134,19 @@ static bool handle_key(montauk::abi::KeyEvent& key, int win_id) { } // Arrow keys - if (key.scancode == 0x48) { // Up + if (montauk::nav_scancode(key) == 0x48) { // Up if (key.shift) start_selection(); else if (g_has_selection) clear_selection(); move_up(); if (key.shift) update_selection(); return true; } - if (key.scancode == 0x50) { // Down + if (montauk::nav_scancode(key) == 0x50) { // Down if (key.shift) start_selection(); else if (g_has_selection) clear_selection(); move_down(); if (key.shift) update_selection(); return true; } - if (key.scancode == 0x4B) { // Left + if (montauk::nav_scancode(key) == 0x4B) { // Left if (key.shift) { start_selection(); move_left(); update_selection(); } else if (g_has_selection) { @@ -1144,7 +1155,7 @@ static bool handle_key(montauk::abi::KeyEvent& key, int win_id) { } else move_left(); return true; } - if (key.scancode == 0x4D) { // Right + if (montauk::nav_scancode(key) == 0x4D) { // Right if (key.shift) { start_selection(); move_right(); update_selection(); } else if (g_has_selection) { @@ -1155,14 +1166,14 @@ static bool handle_key(montauk::abi::KeyEvent& key, int win_id) { } // Home - if (key.scancode == 0x47) { + if (montauk::nav_scancode(key) == 0x47) { if (key.shift) start_selection(); else if (g_has_selection) clear_selection(); move_home(); if (key.shift) update_selection(); return true; } // End - if (key.scancode == 0x4F) { + if (montauk::nav_scancode(key) == 0x4F) { if (key.shift) start_selection(); else if (g_has_selection) clear_selection(); move_end(); if (key.shift) update_selection(); @@ -1170,7 +1181,7 @@ static bool handle_key(montauk::abi::KeyEvent& key, int win_id) { } // Page Up - if (key.scancode == 0x49) { + if (montauk::nav_scancode(key) == 0x49) { if (key.shift) start_selection(); else if (g_has_selection) clear_selection(); int cell_h = font_cell_h(); int vis = cell_h > 0 ? (g_win_h - TOOLBAR_H - STATUS_H) / cell_h : 20; @@ -1179,7 +1190,7 @@ static bool handle_key(montauk::abi::KeyEvent& key, int win_id) { return true; } // Page Down - if (key.scancode == 0x51) { + if (montauk::nav_scancode(key) == 0x51) { if (key.shift) start_selection(); else if (g_has_selection) clear_selection(); int cell_h = font_cell_h(); int vis = cell_h > 0 ? (g_win_h - TOOLBAR_H - STATUS_H) / cell_h : 20; @@ -1189,7 +1200,7 @@ static bool handle_key(montauk::abi::KeyEvent& key, int win_id) { } // Delete - if (key.scancode == 0x53) { + if (montauk::nav_scancode(key) == 0x53) { if (g_has_selection) delete_selection(); else delete_char(); return true; } @@ -1214,10 +1225,12 @@ static bool handle_key(montauk::abi::KeyEvent& key, int win_id) { return true; } - // Printable - if ((unsigned char)key.ascii >= 32 && (unsigned char)key.ascii != 127) { + // Printable (inserted as UTF-8) + char typed[montauk::utf8::MAX_BYTES]; + int typed_len = montauk::utf8::key_utf8(key, typed); + if (typed_len > 0) { if (g_has_selection) delete_selection(); - insert_char(key.ascii); + insert_string(typed, typed_len); return true; } @@ -1404,12 +1417,8 @@ static bool handle_mouse(montauk::abi::WinEvent& ev, int win_id) { if (new_line >= g_scroll_y + visible_lines) new_line = g_scroll_y + visible_lines - 1; if (new_line < 0) new_line = 0; if (new_line >= g_line_count) new_line = g_line_count - 1; - int col = g_cursor_col; - int ll = line_length(new_line); - if (col > ll) col = ll; - g_cursor_pos = g_line_offsets[new_line] + col; - g_cursor_line = new_line; - g_cursor_col = col; + g_cursor_pos = line_col_to_pos(new_line, g_cursor_col); + update_cursor_pos(); } return true; } diff --git a/programs/src/timezone/main.cpp b/programs/src/timezone/main.cpp index 6f8a8f5..2cb79dd 100644 --- a/programs/src/timezone/main.cpp +++ b/programs/src/timezone/main.cpp @@ -455,7 +455,8 @@ static void fit_text(char* out, int cap, const char* text, int max_w) { static constexpr const char* ellipsis = "..."; int len = montauk::slen(out); while (len > 0) { - out[--len] = '\0'; + len = montauk::utf8::prev_boundary(out, len); + out[len] = '\0'; char candidate[160]; snprintf(candidate, sizeof(candidate), "%s%s", out, ellipsis); if (text_width(candidate) <= max_w) { @@ -1051,12 +1052,12 @@ static bool handle_key(const montauk::abi::KeyEvent& key) { int old_country = g_selected_country; - if (key.scancode == 0x4B) g_focus_pane = 0; // Left - else if (key.scancode == 0x4D) g_focus_pane = 1; // Right - else if (key.scancode == 0x48 && *selected > 0) (*selected)--; // Up - else if (key.scancode == 0x50 && *selected < count - 1) (*selected)++; // Down - else if (key.scancode == 0x49) *selected = gui_max(0, *selected - 8); // Page Up - else if (key.scancode == 0x51) *selected = gui_min(count - 1, *selected + 8); // Page Down + if (montauk::nav_scancode(key) == 0x4B) g_focus_pane = 0; // Left + else if (montauk::nav_scancode(key) == 0x4D) g_focus_pane = 1; // Right + else if (montauk::nav_scancode(key) == 0x48 && *selected > 0) (*selected)--; // Up + else if (montauk::nav_scancode(key) == 0x50 && *selected < count - 1) (*selected)++; // Down + else if (montauk::nav_scancode(key) == 0x49) *selected = gui_max(0, *selected - 8); // Page Up + else if (montauk::nav_scancode(key) == 0x51) *selected = gui_min(count - 1, *selected + 8); // Page Down else return false; if (old_country != g_selected_country) { diff --git a/programs/src/video/main.cpp b/programs/src/video/main.cpp index 38f492e..68d9415 100644 --- a/programs/src/video/main.cpp +++ b/programs/src/video/main.cpp @@ -297,7 +297,7 @@ static void copy_text_fit(char* out, int out_cap, const char* text, int max_w, i int len = montauk::slen(out); const char* ellipsis = "..."; while (len > 0) { - len--; + len = montauk::utf8::prev_boundary(out, len); out[len] = '\0'; char trial[160]; montauk::strncpy(trial, out, (int)sizeof(trial)); @@ -1235,14 +1235,14 @@ static bool handle_key(const montauk::abi::KeyEvent& key, bool& quit) { return true; } - if (key.scancode == 0x4B) { + if (montauk::nav_scancode(key) == 0x4B) { uint64_t cur = current_time_us(); if (cur > 5000000ull) cur -= 5000000ull; else cur = 0; seek_to_time(cur); return true; } - if (key.scancode == 0x4D) { + if (montauk::nav_scancode(key) == 0x4D) { seek_to_time(current_time_us() + 5000000ull); return true; } diff --git a/programs/src/weather/main.cpp b/programs/src/weather/main.cpp index 5cf1327..5e9bd93 100644 --- a/programs/src/weather/main.cpp +++ b/programs/src/weather/main.cpp @@ -251,9 +251,9 @@ static void do_fetch() { extract_array_value(body, bodyLen, "\"areaName\"", area, sizeof(area)); extract_array_value(body, bodyLen, "\"country\"", country, sizeof(country)); - // Degree sign is U+00B0 = 0xB0 in Latin-1 (single byte, within the 256-entry glyph cache) - snprintf(g_temp, sizeof(g_temp), "%s\xb0""C", temp_raw); - snprintf(g_feels, sizeof(g_feels), "Feels like: %s\xb0""C", feels_raw); + // Degree sign U+00B0 (UTF-8) + snprintf(g_temp, sizeof(g_temp), "%s\u00B0C", temp_raw); + snprintf(g_feels, sizeof(g_feels), "Feels like: %s\u00B0C", feels_raw); if (area[0] && country[0]) snprintf(g_location, sizeof(g_location), "%s, %s", area, country); diff --git a/programs/src/wiki/main.cpp b/programs/src/wiki/main.cpp index 13022ea..c142264 100644 --- a/programs/src/wiki/main.cpp +++ b/programs/src/wiki/main.cpp @@ -10,6 +10,7 @@ #include #include +#include #include extern "C" { @@ -177,12 +178,23 @@ static int extract_json_string(const char* buf, int len, const char* key, else if (h >= 'A' && h <= 'F') val |= h - 'A' + 10; } p += 4; - if (val < 128) out[j++] = (char)val; - else if (val == 0x2013 || val == 0x2014) out[j++] = '-'; - else if (val == 0x2018 || val == 0x2019) out[j++] = '\''; - else if (val == 0x201C || val == 0x201D) out[j++] = '"'; - else if (val == 0x2026) { out[j++] = '.'; out[j++] = '.'; out[j++] = '.'; } - else out[j++] = '?'; + // The terminal renders UTF-8; join surrogate pairs + if (val >= 0xD800 && val <= 0xDBFF && p + 6 < len && + buf[p + 1] == '\\' && buf[p + 2] == 'u') { + unsigned lo = 0; + for (int k = 3; k <= 6; k++) { + char h = buf[p + k]; + lo <<= 4; + if (h >= '0' && h <= '9') lo |= h - '0'; + else if (h >= 'a' && h <= 'f') lo |= h - 'a' + 10; + else if (h >= 'A' && h <= 'F') lo |= h - 'A' + 10; + } + if (lo >= 0xDC00 && lo <= 0xDFFF) { + val = 0x10000 + ((val - 0xD800) << 10) + (lo - 0xDC00); + p += 6; + } + } + j += montauk::utf8::encode(val, out + j); } break; } @@ -219,9 +231,12 @@ static int wrap_paragraph(const char* text, int textLen, int cols, const char* lastSpace = nullptr; int col = 0; + // One terminal column per UTF-8 character while (p < end && col < cols) { if (*p == ' ') lastSpace = p; - p++; + int n; + montauk::utf8::decode(p, (int)(end - p), &n); + p += n; col++; } @@ -376,8 +391,7 @@ static void render_pager(WikiLine* lines, int totalLines, int scroll, int maxW = cols; if (ln.type == LINE_SECTION && ln.level > 2) maxW -= (ln.level - 2) * 2; - int printLen = ln.len; - if (printLen > maxW) printLen = maxW; + int printLen = montauk::utf8::offset_of(ln.text, ln.len, maxW < 0 ? 0 : maxW); for (int c = 0; c < printLen; c++) sb_putc(ln.text[c]); @@ -463,7 +477,7 @@ static void run_pager(WikiLine* lines, int totalLines, const char* title, case 'g': scroll = 0; break; case 'G': scroll = maxScroll; break; default: - switch (ev.scancode) { + switch (montauk::nav_scancode(ev)) { case 0x48: if (scroll > 0) scroll--; break; // Up case 0x50: if (scroll < maxScroll) scroll++; break; // Down case 0x49: scroll -= contentRows; if (scroll < 0) scroll = 0; break; // PgUp diff --git a/programs/src/wikipedia/main.cpp b/programs/src/wikipedia/main.cpp index a256773..ad20a80 100644 --- a/programs/src/wikipedia/main.cpp +++ b/programs/src/wikipedia/main.cpp @@ -41,7 +41,7 @@ static bool init_buffers_and_fonts() { static void handle_key_event(const montauk::abi::WinEvent& ev, bool& search_pending) { uint8_t ascii = ev.key.ascii; - uint8_t scan = ev.key.scancode; + uint8_t scan = montauk::nav_scancode(ev.key); if (g_search_focused) { if (ascii == '\n' || ascii == '\r') { diff --git a/programs/src/wikipedia/text.cpp b/programs/src/wikipedia/text.cpp index 70095bb..70e4447 100644 --- a/programs/src/wikipedia/text.cpp +++ b/programs/src/wikipedia/text.cpp @@ -10,64 +10,12 @@ // Codepoint and UTF-8 helpers // ============================================================================ -int encode_single_byte_codepoint(unsigned codepoint) { - if (codepoint < 0x80) return (int)codepoint; - if (codepoint >= 0xA0 && codepoint <= 0xFF) return (int)codepoint; - - switch (codepoint) { - case 0x20AC: return 0x80; - case 0x201A: return 0x82; - case 0x0192: return 0x83; - case 0x201E: return 0x84; - case 0x2026: return 0x85; - case 0x2020: return 0x86; - case 0x2021: return 0x87; - case 0x02C6: return 0x88; - case 0x2030: return 0x89; - case 0x0160: return 0x8A; - case 0x2039: return 0x8B; - case 0x0152: return 0x8C; - case 0x017D: return 0x8E; - case 0x2018: return 0x91; - case 0x2019: return 0x92; - case 0x201C: return 0x93; - case 0x201D: return 0x94; - case 0x2022: return 0x95; - case 0x2013: return 0x96; - case 0x2014: return 0x97; - case 0x02DC: return 0x98; - case 0x2122: return 0x99; - case 0x0161: return 0x9A; - case 0x203A: return 0x9B; - case 0x0153: return 0x9C; - case 0x017E: return 0x9E; - case 0x0178: return 0x9F; - default: return -1; - } -} - +// Article text is kept as UTF-8, which the renderer draws directly. void append_codepoint(char* out, int* j, int maxOut, unsigned codepoint) { - if (!out || !j || *j >= maxOut - 1) return; - - int encoded = encode_single_byte_codepoint(codepoint); - if (encoded >= 0) { - out[(*j)++] = (char)encoded; - return; - } - - switch (codepoint) { - case 0x00A0: - out[(*j)++] = ' '; - return; - case 0x2010: - case 0x2011: - case 0x2212: - out[(*j)++] = '-'; - return; - default: - out[(*j)++] = '?'; - return; - } + if (!out || !j) return; + int n = montauk::utf8::encoded_length(codepoint); + if (*j + n > maxOut - 1) return; + *j += montauk::utf8::encode(codepoint, out + *j); } void underscores_to_spaces(char* text) { @@ -205,14 +153,27 @@ int extract_json_string(const char* buf, int len, const char* key, case '/': out[j++] = '/'; break; case 'u': { if (p + 4 < len) { - unsigned val = 0; - for (int k = 1; k <= 4; k++) { - char h = buf[p + k]; val <<= 4; - if (h>='0'&&h<='9') val |= h-'0'; - else if (h>='a'&&h<='f') val |= h-'a'+10; - else if (h>='A'&&h<='F') val |= h-'A'+10; - } + auto hex4 = [&](int at) { + unsigned val = 0; + for (int k = 0; k < 4; k++) { + char h = buf[at + k]; val <<= 4; + if (h>='0'&&h<='9') val |= h-'0'; + else if (h>='a'&&h<='f') val |= h-'a'+10; + else if (h>='A'&&h<='F') val |= h-'A'+10; + } + return val; + }; + unsigned val = hex4(p + 1); p += 4; + // A character outside the BMP is a \uD8xx\uDCxx pair + if (val >= 0xD800 && val <= 0xDBFF && p + 6 < len && + buf[p + 1] == '\\' && buf[p + 2] == 'u') { + unsigned lo = hex4(p + 3); + if (lo >= 0xDC00 && lo <= 0xDFFF) { + val = 0x10000 + ((val - 0xD800) << 10) + (lo - 0xDC00); + p += 6; + } + } append_codepoint(out, &j, maxOut, val); } break; diff --git a/programs/src/wikipedia/wikipedia.h b/programs/src/wikipedia/wikipedia.h index c13fd4e..a3246a3 100644 --- a/programs/src/wikipedia/wikipedia.h +++ b/programs/src/wikipedia/wikipedia.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -184,7 +185,6 @@ int document_top_pad(); // text.cpp -- encoding, HTTP/URL/JSON parsing // ============================================================================ -int encode_single_byte_codepoint(unsigned codepoint); void append_codepoint(char* out, int* j, int maxOut, unsigned codepoint); void underscores_to_spaces(char* text); bool is_main_page_query(const char* query); diff --git a/programs/src/wordprocessor/document.cpp b/programs/src/wordprocessor/document.cpp index f5e52e2..16c2505 100644 --- a/programs/src/wordprocessor/document.cpp +++ b/programs/src/wordprocessor/document.cpp @@ -263,7 +263,7 @@ static int wp_char_advance_at(WordProcessorState* wp, int abs_pos, int layout_dp wp_font_at(wp, abs_pos, layout_dpi, &font, &gc); if (!font || !gc) return wp_points_to_pixels(6, layout_dpi); - CachedGlyph* g = font->get_glyph(gc, (unsigned char)ch); + CachedGlyph* g = font->get_glyph(gc, decode_single_byte_codepoint((unsigned char)ch)); return g ? g->advance : wp_points_to_pixels(6, layout_dpi); } diff --git a/programs/src/wordprocessor/input.cpp b/programs/src/wordprocessor/input.cpp index d16358b..d2914c1 100644 --- a/programs/src/wordprocessor/input.cpp +++ b/programs/src/wordprocessor/input.cpp @@ -14,17 +14,46 @@ static void wp_set_status(WordProcessorState* wp, const char* msg) { wp->status_msg[sizeof(wp->status_msg) - 1] = '\0'; } +// Documents store text as Windows-1252 (one byte per character, matching the +// WinAnsi fonts used for PDF export); the clipboard is UTF-8. Convert both ways. +static char* wp_cp1252_to_utf8_alloc(const char* text, int len, int* out_len) { + char* out = (char*)montauk::malloc(len * 3 + 1); + if (!out) return nullptr; + int o = 0; + for (int i = 0; i < len; i++) + o += montauk::utf8::encode(montauk::utf8::from_cp1252((uint8_t)text[i]), out + o); + out[o] = '\0'; + *out_len = o; + return out; +} + +// Characters with no Windows-1252 form become '?'. +static int wp_utf8_to_cp1252_inplace(char* text, int len) { + int o = 0; + for (int pos = 0; pos < len;) { + int n; + uint32_t cp = montauk::utf8::decode(text + pos, len - pos, &n); + pos += n; + uint8_t b = cp == 0 ? 0 : montauk::utf8::to_cp1252(cp); + text[o++] = b ? (char)b : '?'; + } + text[o] = '\0'; + return o; +} + static bool wp_copy_selection_to_clipboard(WordProcessorState* wp) { int len = 0; - char* text = wp_selection_plain_text_alloc(wp, &len); - if (text == nullptr || len <= 0) { - if (text) montauk::mfree(text); + char* raw = wp_selection_plain_text_alloc(wp, &len); + if (raw == nullptr || len <= 0) { + if (raw) montauk::mfree(raw); wp_set_status(wp, "Nothing selected"); return false; } - bool ok = gui::clipboard_set_text(text, len); - montauk::mfree(text); + char* text = wp_cp1252_to_utf8_alloc(raw, len, &len); + montauk::mfree(raw); + bool ok = text && gui::clipboard_set_text(text, len); + if (text) montauk::mfree(text); if (!ok) { wp_set_status(wp, "Copy failed"); return false; @@ -52,6 +81,7 @@ static bool wp_paste_from_clipboard(WordProcessorState* wp) { wp_set_status(wp, "Clipboard is empty"); return false; } + len = wp_utf8_to_cp1252_inplace(text, len); bool ok = wp_replace_selection_with_text(wp, text, len); montauk::mfree(text); @@ -263,7 +293,7 @@ static int wp_hit_test_text(WordProcessorState* wp, int local_x, int local_y, in for (int ci = 0; ci < to_check; ci++) { char ch = r->text[ro + ci]; CachedGlyph* g = (ch >= 32 || ch < 0) && ch != '\n' - ? font->get_glyph(gc, (unsigned char)ch) : nullptr; + ? font->get_glyph(gc, decode_single_byte_codepoint((unsigned char)ch)) : nullptr; int char_w = g ? g->advance : 0; if (x + char_w / 2 > click_x) return best_abs; @@ -611,32 +641,18 @@ void wp_handle_key(const montauk::abi::KeyEvent& key) { return; } if (key.ascii == '\b' || key.scancode == 0x0E) { - if (wp->pathbar_cursor > 0) { - for (int i = wp->pathbar_cursor - 1; i < wp->pathbar_len - 1; i++) - wp->pathbar_text[i] = wp->pathbar_text[i + 1]; - wp->pathbar_len--; - wp->pathbar_cursor--; - wp->pathbar_text[wp->pathbar_len] = '\0'; - } + montauk::utf8::erase_before(wp->pathbar_text, &wp->pathbar_len, &wp->pathbar_cursor); return; } - if (key.scancode == 0x4B) { - if (wp->pathbar_cursor > 0) wp->pathbar_cursor--; + if (montauk::nav_scancode(key) == 0x4B) { + wp->pathbar_cursor = montauk::utf8::prev_boundary(wp->pathbar_text, wp->pathbar_cursor); return; } - if (key.scancode == 0x4D) { - if (wp->pathbar_cursor < wp->pathbar_len) wp->pathbar_cursor++; + if (montauk::nav_scancode(key) == 0x4D) { + wp->pathbar_cursor = montauk::utf8::next_boundary(wp->pathbar_text, wp->pathbar_len, wp->pathbar_cursor); return; } - if ((unsigned char)key.ascii >= 32 - && (unsigned char)key.ascii != 127 && wp->pathbar_len < 254) { - for (int i = wp->pathbar_len; i > wp->pathbar_cursor; i--) - wp->pathbar_text[i] = wp->pathbar_text[i - 1]; - wp->pathbar_text[wp->pathbar_cursor] = key.ascii; - wp->pathbar_cursor++; - wp->pathbar_len++; - wp->pathbar_text[wp->pathbar_len] = '\0'; - } + montauk::utf8::insert_key(wp->pathbar_text, &wp->pathbar_len, 255, &wp->pathbar_cursor, key); return; } @@ -736,22 +752,22 @@ void wp_handle_key(const montauk::abi::KeyEvent& key) { return; } - if (key.ctrl && key.alt && key.scancode == 0x48) { + if (key.ctrl && key.alt && montauk::nav_scancode(key) == 0x48) { wp_adjust_paragraph_spacing_before(wp, -WP_SPACE_STEP); wp_history_checkpoint(wp); return; } - if (key.ctrl && key.alt && key.scancode == 0x50) { + if (key.ctrl && key.alt && montauk::nav_scancode(key) == 0x50) { wp_adjust_paragraph_spacing_before(wp, WP_SPACE_STEP); wp_history_checkpoint(wp); return; } - if (key.ctrl && key.shift && key.scancode == 0x48) { + if (key.ctrl && key.shift && montauk::nav_scancode(key) == 0x48) { wp_adjust_paragraph_spacing_after(wp, -WP_SPACE_STEP); wp_history_checkpoint(wp); return; } - if (key.ctrl && key.shift && key.scancode == 0x50) { + if (key.ctrl && key.shift && montauk::nav_scancode(key) == 0x50) { wp_adjust_paragraph_spacing_after(wp, WP_SPACE_STEP); wp_history_checkpoint(wp); return; @@ -783,21 +799,21 @@ void wp_handle_key(const montauk::abi::KeyEvent& key) { return; } - if (key.scancode == 0x48) { + if (montauk::nav_scancode(key) == 0x48) { if (key.shift) wp_start_selection(wp); else wp_clear_selection(wp); wp_cursor_up(wp); if (key.shift) wp_update_selection_to_cursor(wp); return; } - if (key.scancode == 0x50) { + if (montauk::nav_scancode(key) == 0x50) { if (key.shift) wp_start_selection(wp); else wp_clear_selection(wp); wp_cursor_down(wp); if (key.shift) wp_update_selection_to_cursor(wp); return; } - if (key.scancode == 0x4B) { + if (montauk::nav_scancode(key) == 0x4B) { if (key.shift) wp_start_selection(wp); else if (wp->has_selection) { int s, e; @@ -810,7 +826,7 @@ void wp_handle_key(const montauk::abi::KeyEvent& key) { if (key.shift) wp_update_selection_to_cursor(wp); return; } - if (key.scancode == 0x4D) { + if (montauk::nav_scancode(key) == 0x4D) { if (key.shift) wp_start_selection(wp); else if (wp->has_selection) { int s, e; @@ -824,7 +840,7 @@ void wp_handle_key(const montauk::abi::KeyEvent& key) { return; } - if (key.scancode == 0x47) { + if (montauk::nav_scancode(key) == 0x47) { if (key.shift) wp_start_selection(wp); else wp_clear_selection(wp); int abs = wp_abs_pos(wp, wp->cursor_run, wp->cursor_offset); @@ -834,7 +850,7 @@ void wp_handle_key(const montauk::abi::KeyEvent& key) { if (key.shift) wp_update_selection_to_cursor(wp); return; } - if (key.scancode == 0x4F) { + if (montauk::nav_scancode(key) == 0x4F) { if (key.shift) wp_start_selection(wp); else wp_clear_selection(wp); int abs = wp_abs_pos(wp, wp->cursor_run, wp->cursor_offset); @@ -858,7 +874,7 @@ void wp_handle_key(const montauk::abi::KeyEvent& key) { return; } - if (key.scancode == 0x53) { + if (montauk::nav_scancode(key) == 0x53) { if (wp->has_selection) wp_delete_selection(wp); else wp_delete_char(wp); wp_history_checkpoint(wp); diff --git a/programs/src/wordprocessor/print_export.cpp b/programs/src/wordprocessor/print_export.cpp index 1253078..64b2bc4 100644 --- a/programs/src/wordprocessor/print_export.cpp +++ b/programs/src/wordprocessor/print_export.cpp @@ -217,7 +217,7 @@ static void wp_draw_print_list_marker(Canvas& c, WordProcessorState* wp, WrapLin if (!font) font = g_ui_font; int th = text_height(font, font_px); int top_y = py + (wl->height - th) / 2; - char bullet[2] = { '\x95', '\0' }; + const char* bullet = "\u2022"; draw_text(c, font, bullet_x, top_y, bullet, colors::BLACK, font_px); return; } @@ -293,7 +293,8 @@ static bool wp_encode_print_page(WordProcessorState* wp, if (ch != '\n' && (ch >= 32 || ch < 0)) { int adv = font->draw_char_to_buffer( - c.pixels, c.w, c.h, x, baseline, (unsigned char)ch, colors::BLACK, gc); + c.pixels, c.w, c.h, x, baseline, + decode_single_byte_codepoint((unsigned char)ch), colors::BLACK, gc); x += adv; } char_idx++; diff --git a/programs/src/wordprocessor/render.cpp b/programs/src/wordprocessor/render.cpp index 8add383..754ea6f 100644 --- a/programs/src/wordprocessor/render.cpp +++ b/programs/src/wordprocessor/render.cpp @@ -111,7 +111,8 @@ static void wp_fit_ui_text(const char* src, char* out, int out_len, int max_w) { if (text_width(g_ui_font, out, fonts::UI_SIZE) <= max_w) return; int slen = montauk::slen(src); - for (int keep = slen; keep > 1; keep--) { + for (int keep = slen; keep > 1; + keep = slen - montauk::utf8::next_boundary(src, slen, slen - keep)) { char candidate[256]; candidate[0] = '.'; candidate[1] = '.'; @@ -138,7 +139,8 @@ static void wp_fit_ui_text_end(const char* src, char* out, int out_len, int max_ out[out_len - 1] = '\0'; if (text_width(g_ui_font, out, fonts::UI_SIZE) <= max_w) return; - for (int keep = montauk::slen(src); keep > 0; keep--) { + for (int keep = montauk::slen(src); keep > 0; + keep = montauk::utf8::prev_boundary(src, keep)) { char candidate[256]; if (keep > (int)sizeof(candidate) - 3) continue; montauk::memcpy(candidate, src, keep); @@ -225,7 +227,7 @@ static void wp_draw_list_marker(Canvas& c, WordProcessorState* wp, WrapLine* wl, if (!font) font = g_ui_font; int th = text_height(font, bullet_size); int top_y = py + (wl->height - th) / 2; - char bullet[2] = { '\x95', '\0' }; + const char* bullet = "\u2022"; draw_text(c, font, bullet_x, top_y, bullet, colors::TEXT_COLOR, bullet_size); return; } @@ -346,7 +348,7 @@ void wp_render() { Color special_bg = wp->special_char_flyout_open ? btn_active : btn_bg; c.fill_rounded_rect(WP_BTN_SECTION_X, 6, 24, 24, 3, special_bg); { - char section[2] = { (char)0xA7, '\0' }; + const char* section = "\u00A7"; TrueTypeFont* font = wp_get_font(wp_default_font_id(), 0); draw_text(c, font ? font : g_ui_font, WP_BTN_SECTION_X + 6, 8, section, colors::TEXT_COLOR, fonts::UI_SIZE); } @@ -355,7 +357,7 @@ void wp_render() { Color pageview_bg = wp->page_view_mode ? btn_active : btn_bg; c.fill_rounded_rect(WP_BTN_PAGEVIEW_X, 6, 24, 24, 3, pageview_bg); - wp_draw_ui_icon_button(c, WP_BTN_PAGEVIEW_X, 6, 24, 24, g_icon_page_view, "\xA7", + wp_draw_ui_icon_button(c, WP_BTN_PAGEVIEW_X, 6, 24, 24, g_icon_page_view, "\u00A7", pageview_bg, colors::TEXT_COLOR); c.hline(0, WP_TOOLBAR_H - 1, c.w, colors::BORDER); @@ -506,7 +508,7 @@ void wp_render() { int char_adv = 0; if (ch != '\n' && (ch >= 32 || ch < 0)) { - CachedGlyph* g = font->get_glyph(gc, (unsigned char)ch); + CachedGlyph* g = font->get_glyph(gc, decode_single_byte_codepoint((unsigned char)ch)); char_adv = g ? g->advance : 8; } @@ -558,7 +560,8 @@ void wp_render() { Color text_col = (wp->has_selection && abs_ch >= sel_s && abs_ch < sel_e) ? Color::from_rgb(0x10, 0x10, 0x10) : colors::TEXT_COLOR; int adv = font->draw_char_to_buffer( - c.pixels, c.w, c.h, x, baseline, (unsigned char)ch, text_col, gc); + c.pixels, c.w, c.h, x, baseline, + decode_single_byte_codepoint((unsigned char)ch), text_col, gc); x += adv; } else { x += char_adv; @@ -717,7 +720,9 @@ void wp_render() { c.rect(dx, dy, dw, dh, colors::BORDER); for (int i = 0; i < WP_SPECIAL_CHAR_OPTION_COUNT; i++) { int iy = dy + 2 + i * WP_SPECIAL_CHAR_ROW_H; - char glyph[2] = { (char)WP_SPECIAL_CHAR_OPTIONS[i].code, '\0' }; + char glyph[5]; + glyph[montauk::utf8::encode(montauk::utf8::from_cp1252( + WP_SPECIAL_CHAR_OPTIONS[i].code), glyph)] = '\0'; c.fill_rect(dx + 2, iy, dw - 4, WP_SPECIAL_CHAR_ROW_H - 2, colors::MENU_BG); draw_text(c, glyph_font ? glyph_font : g_ui_font, dx + 8, iy + (WP_SPECIAL_CHAR_ROW_H - sfh) / 2, diff --git a/programs/src/wordprocessor/wordprocessor.hpp b/programs/src/wordprocessor/wordprocessor.hpp index 7df81dd..66caf4f 100644 --- a/programs/src/wordprocessor/wordprocessor.hpp +++ b/programs/src/wordprocessor/wordprocessor.hpp @@ -193,6 +193,10 @@ struct WPFontTable { bool loaded; }; +// Document text is Windows-1252, one byte per character, unlike the rest of +// MontaukOS (UTF-8). It matches the MWP1 file format and the WinAnsi-encoded +// fonts of PDF export. Convert at the edges: decode_single_byte_codepoint() +// for glyphs, and UTF-8 <-> 1252 for the clipboard (input.cpp). struct StyledRun { char* text; int len; diff --git a/template/sysroot/include/Api/Syscall.hpp b/template/sysroot/include/Api/Syscall.hpp index f513f59..a490c84 100644 --- a/template/sysroot/include/Api/Syscall.hpp +++ b/template/sysroot/include/Api/Syscall.hpp @@ -271,6 +271,12 @@ namespace montauk::abi { static constexpr uint64_t SYS_CONSENT_NEXT = 192; // (ConsentRequest*) -> 1 delivered, 0 none queued static constexpr uint64_t SYS_CONSENT_REPLY = 193; // (requestId, CONSENT_ALLOW/DENY) -> 0, -1 stale id + /* Unicode key events. Size-versioned: the caller passes sizeof(its + KeyEvent); the kernel copies min(size, its own) bytes and zero-fills the + rest, so the struct can grow without another syscall. */ + static constexpr uint64_t SYS_GETKEY_EX = 194; // (KeyEvent*, size) -> 0; blocks like SYS_GETKEY + static constexpr uint64_t SYS_CHILDIO_WRITEKEY_EX = 195; // (childPid, const KeyEvent*, size) -> status + /* Kernel-owned process capabilities. User identities may namespace per-user resources, but never participate in authorization decisions. */ static constexpr uint64_t CAP_PROCESS_ADMIN = 1ULL << 0; @@ -531,7 +537,10 @@ namespace montauk::abi { uint32_t buildNumber; // monotonic kernel build number }; - struct KeyEvent { + // Legacy 9-byte key event, read by SYS_GETKEY and written by + // SYS_CHILDIO_WRITEKEY. Kept so binaries built before codepoints still work. + // `ascii` is a Windows-1252 byte. + struct KeyEventV1 { uint8_t scancode; char ascii; bool pressed; @@ -547,6 +556,32 @@ namespace montauk::abi { bool extended; }; + // Key event with the Unicode text it types (SYS_GETKEY_EX, + // SYS_CHILDIO_WRITEKEY_EX, WinEvent). Its first 9 bytes ARE a KeyEventV1, so + // a legacy reader sees a valid event. `codepoint` is the character the key + // produces (0 for control/navigation keys and dead keys). `ascii` is its + // Windows-1252 byte, or KEY_ASCII_SUBSTITUTE when 1252 has none. + struct KeyEvent { + uint8_t scancode; + char ascii; + bool pressed; + bool shift; + bool ctrl; + bool alt; + bool capslock; + bool altgr; + bool extended; + uint8_t _reserved[3]; + uint32_t codepoint; + }; + static_assert(sizeof(KeyEventV1) == 9, "KeyEventV1 is frozen ABI"); + static_assert(sizeof(KeyEvent) == 16, "KeyEvent must fit the WinEvent union"); + + // ASCII SUB: `ascii` of a text key whose character has no Windows-1252 byte. + // A control character, so legacy code that only accepts ascii >= 0x20 skips + // it, while code testing `ascii == 0` for navigation keys is not confused. + static constexpr char KEY_ASCII_SUBSTITUTE = 0x1A; + struct MouseState { int32_t x; int32_t y; @@ -584,12 +619,13 @@ namespace montauk::abi { uint8_t type; // 0=key, 1=mouse, 2=resize, 3=close, 4=scale uint8_t _pad[3]; union { - KeyEvent key; + KeyEvent key; // 16 bytes: the union was already that size (mouse) struct { int32_t x, y, scroll; uint8_t buttons, prev_buttons; } mouse; struct { int32_t w, h; } resize; struct { int32_t scale; } scale; }; }; + static_assert(sizeof(WinEvent) == 20, "WinEvent layout is shared with existing binaries"); struct WinInfo { int32_t id; diff --git a/template/sysroot/include/gui/canvas.hpp b/template/sysroot/include/gui/canvas.hpp index c38c260..6bc125c 100644 --- a/template/sysroot/include/gui/canvas.hpp +++ b/template/sysroot/include/gui/canvas.hpp @@ -165,9 +165,9 @@ struct Canvas { if (!str || !font_data || scale <= 0) return; uint32_t pixel = c.to_pixel(); int cx = x; - for (int i = 0; str[i]; i++, cx += FONT_WIDTH * scale) { + for (const char* p = str; *p; cx += FONT_WIDTH * scale) { const uint8_t* glyph = - &font_data[(unsigned char)str[i] * FONT_HEIGHT]; + &font_data[cp437_index(montauk::utf8::next(&p)) * FONT_HEIGHT]; for (int row = 0; row < FONT_HEIGHT; row++) { uint8_t bits = glyph[row]; if (!bits) continue; diff --git a/template/sysroot/include/gui/clipboard.hpp b/template/sysroot/include/gui/clipboard.hpp index 614eaba..0a35535 100644 --- a/template/sysroot/include/gui/clipboard.hpp +++ b/template/sysroot/include/gui/clipboard.hpp @@ -9,12 +9,32 @@ #include #include #include +#include namespace gui { + // The clipboard carries UTF-8. Text that is not well-formed (legacy + // Windows-1252 bytes) is converted on the way in and on the way out, so + // every reader can assume valid UTF-8. + inline char* clipboard_utf8_copy(const char* text, int len, int* out_len) { + int cap = len * 3 + 1; // each stray byte grows to at most 3 + char* out = (char*)montauk::malloc(cap); + if (!out) return nullptr; + *out_len = montauk::utf8::normalize(text, len, out, cap); + return out; + } + inline bool clipboard_set_text(const char* text, int len) { if (len < 0) return false; if (len > 0 && text == nullptr) return false; + if (len > 0 && !montauk::utf8::valid(text, len)) { + int fixed_len = 0; + char* fixed = clipboard_utf8_copy(text, len, &fixed_len); + if (!fixed) return false; + bool ok = montauk::clipboard_set_text(fixed, (uint32_t)fixed_len) == 0; + montauk::mfree(fixed); + return ok; + } return montauk::clipboard_set_text(text, (uint32_t)len) == 0; } @@ -53,6 +73,14 @@ namespace gui { } text[actual_len] = '\0'; + if (!montauk::utf8::valid(text, (int)actual_len)) { + int fixed_len = 0; + char* fixed = clipboard_utf8_copy(text, (int)actual_len, &fixed_len); + montauk::mfree(text); + if (!fixed) return nullptr; + text = fixed; + actual_len = (uint32_t)fixed_len; + } if (out_len) *out_len = (int)actual_len; if (out_serial) *out_serial = serial; return text; diff --git a/template/sysroot/include/gui/desktop.hpp b/template/sysroot/include/gui/desktop.hpp index 54b948c..8f76ee5 100644 --- a/template/sysroot/include/gui/desktop.hpp +++ b/template/sysroot/include/gui/desktop.hpp @@ -227,6 +227,18 @@ struct DesktopState { montauk::abi::BatteryInfo battery_info; uint64_t battery_last_poll; + // Display brightness. Present only while the active output has a + // controllable backlight (laptop panel, or a monitor answering DDC/CI). + SvgIcon icon_brightness; + bool brightness_present; + bool brightness_popup_open; + Rect brightness_icon_rect; + int brightness_level; // 0-100, as shown on the slider + bool brightness_dragging; + int brightness_pending; // drag sample not yet sent, -1 none + uint64_t brightness_last_send; + uint64_t brightness_last_poll; + bool vol_popup_open; Rect vol_icon_rect; int vol_level; // 0-100 diff --git a/template/sysroot/include/gui/font.hpp b/template/sysroot/include/gui/font.hpp index 4001c16..8d35da8 100644 --- a/template/sysroot/include/gui/font.hpp +++ b/template/sysroot/include/gui/font.hpp @@ -19,6 +19,34 @@ static constexpr int FONT_HEIGHT = 16; // TrueType fonts, while login/desktop can recover when TrueType setup fails. extern const uint8_t font_data[256 * 16] __attribute__((weak)); +// The bitmap fallback font is Code Page 437. Map a Unicode codepoint to its +// CP437 cell ('?' when it has none) so UTF-8 text still draws sensibly, +// including the box-drawing characters terminal programs use. +inline uint8_t cp437_index(uint32_t cp) { + if (cp < 0x80) return (uint8_t)cp; + static constexpr uint16_t high[128] = { + 0x00C7,0x00FC,0x00E9,0x00E2,0x00E4,0x00E0,0x00E5,0x00E7, + 0x00EA,0x00EB,0x00E8,0x00EF,0x00EE,0x00EC,0x00C4,0x00C5, + 0x00C9,0x00E6,0x00C6,0x00F4,0x00F6,0x00F2,0x00FB,0x00F9, + 0x00FF,0x00D6,0x00DC,0x00A2,0x00A3,0x00A5,0x20A7,0x0192, + 0x00E1,0x00ED,0x00F3,0x00FA,0x00F1,0x00D1,0x00AA,0x00BA, + 0x00BF,0x2310,0x00AC,0x00BD,0x00BC,0x00A1,0x00AB,0x00BB, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, + 0x2555,0x2563,0x2551,0x2557,0x255D,0x255C,0x255B,0x2510, + 0x2514,0x2534,0x252C,0x251C,0x2500,0x253C,0x255E,0x255F, + 0x255A,0x2554,0x2569,0x2566,0x2560,0x2550,0x256C,0x2567, + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256B, + 0x256A,0x2518,0x250C,0x2588,0x2584,0x258C,0x2590,0x2580, + 0x03B1,0x00DF,0x0393,0x03C0,0x03A3,0x03C3,0x00B5,0x03C4, + 0x03A6,0x0398,0x03A9,0x03B4,0x221E,0x03C6,0x03B5,0x2229, + 0x2261,0x00B1,0x2265,0x2264,0x2320,0x2321,0x00F7,0x2248, + 0x00B0,0x2219,0x00B7,0x221A,0x207F,0x00B2,0x25A0,0x00A0, + }; + for (int i = 0; i < 128; i++) + if (high[i] == cp) return (uint8_t)(0x80 + i); + return '?'; +} + // Dynamic font height: TTF line height or 16 (bitmap fallback) inline int system_font_height() { if (fonts::system_font && fonts::system_font->valid) @@ -74,8 +102,8 @@ inline void draw_text(Framebuffer& fb, int x, int y, const char* text, Color fg) fonts::system_font->draw(fb, x, y, text, fg, fonts::UI_SIZE); return; } - for (int i = 0; text[i]; i++) { - draw_char(fb, x + i * FONT_WIDTH, y, text[i], fg); + for (const char* p = text; *p; x += FONT_WIDTH) { + draw_char(fb, x, y, (char)cp437_index(montauk::utf8::next(&p)), fg); } } @@ -84,18 +112,23 @@ inline void draw_text_bg(Framebuffer& fb, int x, int y, const char* text, Color fonts::system_font->draw_bg(fb, x, y, text, fg, bg, fonts::UI_SIZE); return; } - for (int i = 0; text[i]; i++) { - draw_char_bg(fb, x + i * FONT_WIDTH, y, text[i], fg, bg); + for (const char* p = text; *p; x += FONT_WIDTH) { + draw_char_bg(fb, x, y, (char)cp437_index(montauk::utf8::next(&p)), fg, bg); } } +// Width of the first `len` bytes of a UTF-8 string in the UI font. +inline int text_width_n(const char* text, int len) { + if (fonts::system_font && fonts::system_font->valid) + return fonts::system_font->measure_text_n(text, len, fonts::UI_SIZE); + return montauk::utf8::count(text, len) * FONT_WIDTH; +} + inline int text_width(const char* text) { if (fonts::system_font && fonts::system_font->valid) { return fonts::system_font->measure_text(text, fonts::UI_SIZE); } - int len = 0; - while (text[len]) len++; - return len * FONT_WIDTH; + return montauk::utf8::count(text) * FONT_WIDTH; } } // namespace gui diff --git a/template/sysroot/include/gui/mtk/widgets.hpp b/template/sysroot/include/gui/mtk/widgets.hpp index f4ca3b0..07ff5b0 100644 --- a/template/sysroot/include/gui/mtk/widgets.hpp +++ b/template/sysroot/include/gui/mtk/widgets.hpp @@ -296,15 +296,13 @@ inline bool text_input_has_selection(const TextInputState& state, const char* te return text_input_selection_start(state, len) != text_input_selection_end(state, len); } +// Width of the first `count` bytes (a character boundary). Masked fields +// draw one '*' per character, however many bytes it takes. inline int text_input_prefix_width(const char* text, int count, bool masked) { - char prefix[512]; int len = 0; - while (text && text[len] && len < count && len < (int)sizeof(prefix) - 1) { - prefix[len] = masked ? '*' : text[len]; - len++; - } - prefix[len] = '\0'; - return text_width(prefix); + while (text && text[len] && len < count) len++; + if (!masked) return text_width_n(text, len); + return montauk::utf8::count(text, len) * text_width("*"); } inline int text_input_index_from_x(const Rect& bounds, const char* value, @@ -314,11 +312,13 @@ inline int text_input_index_from_x(const Rect& bounds, const char* value, int len = text_input_len(value); int prev_w = 0; - for (int i = 0; i < len; i++) { - int cur_w = text_input_prefix_width(value, i + 1, masked); + for (int i = 0; i < len;) { + int next = montauk::utf8::next_boundary(value, len, i); + int cur_w = text_input_prefix_width(value, next, masked); int midpoint = prev_w + (cur_w - prev_w) / 2; if (rel_x < midpoint) return i; prev_w = cur_w; + i = next; } return len; } @@ -360,8 +360,11 @@ inline int text_input_mouse(TextInputState& state, return TEXT_INPUT_NONE; } +// Bytes >= 0x80 (any non-ASCII character) count as word characters, so word +// jumps never stop inside a multi-byte sequence. inline bool text_input_word_char(char ch) { - return (ch >= 'a' && ch <= 'z') || + return (uint8_t)ch >= 0x80 || + (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_'; @@ -574,8 +577,10 @@ inline int text_input_key(TextInputState& state, if (!key.pressed || !text || cap <= 0) return TEXT_INPUT_NONE; int len = text_input_len(text, cap); - state.cursor = text_input_clamp_cursor(state.cursor, len); - state.selection_anchor = text_input_clamp_cursor(state.selection_anchor, len); + state.cursor = montauk::utf8::floor_boundary( + text, len, text_input_clamp_cursor(state.cursor, len)); + state.selection_anchor = montauk::utf8::floor_boundary( + text, len, text_input_clamp_cursor(state.selection_anchor, len)); if (state.context.open) { context_menu_close(state.context); @@ -606,20 +611,22 @@ inline int text_input_key(TextInputState& state, return TEXT_INPUT_CONSUMED | (changed ? TEXT_INPUT_CHANGED : 0); } - if (key.scancode == 0x4B || key.scancode == 0x4D || - key.scancode == 0x47 || key.scancode == 0x4F) { + if (montauk::nav_scancode(key) == 0x4B || montauk::nav_scancode(key) == 0x4D || + montauk::nav_scancode(key) == 0x47 || montauk::nav_scancode(key) == 0x4F) { int next = state.cursor; - if (!key.shift && sel_start != sel_end && key.scancode == 0x4B) + if (!key.shift && sel_start != sel_end && montauk::nav_scancode(key) == 0x4B) next = sel_start; - else if (!key.shift && sel_start != sel_end && key.scancode == 0x4D) + else if (!key.shift && sel_start != sel_end && montauk::nav_scancode(key) == 0x4D) next = sel_end; - else if (key.scancode == 0x4B) - next = key.ctrl ? text_input_prev_word_boundary(text, state.cursor) : state.cursor - 1; - else if (key.scancode == 0x4D) - next = key.ctrl ? text_input_next_word_boundary(text, state.cursor) : state.cursor + 1; - else if (key.scancode == 0x47) + else if (montauk::nav_scancode(key) == 0x4B) + next = key.ctrl ? text_input_prev_word_boundary(text, state.cursor) + : montauk::utf8::prev_boundary(text, state.cursor); + else if (montauk::nav_scancode(key) == 0x4D) + next = key.ctrl ? text_input_next_word_boundary(text, state.cursor) + : montauk::utf8::next_boundary(text, len, state.cursor); + else if (montauk::nav_scancode(key) == 0x47) next = 0; - else if (key.scancode == 0x4F) + else if (montauk::nav_scancode(key) == 0x4F) next = len; text_input_set_cursor(state, len, next, key.shift); @@ -641,15 +648,16 @@ inline int text_input_key(TextInputState& state, changed = true; } } else if (state.cursor > 0) { - text_input_delete_range(text, &len, state.cursor - 1, state.cursor); - state.cursor--; + int start = montauk::utf8::prev_boundary(text, state.cursor); + text_input_delete_range(text, &len, start, state.cursor); + state.cursor = start; changed = true; } state.selection_anchor = state.cursor; return TEXT_INPUT_CONSUMED | (changed ? TEXT_INPUT_CHANGED : 0); } - if (key.scancode == 0x53) { + if (montauk::nav_scancode(key) == 0x53) { if (sel_start != sel_end) { text_input_delete_range(text, &len, sel_start, sel_end); state.cursor = sel_start; @@ -661,15 +669,22 @@ inline int text_input_key(TextInputState& state, changed = true; } } else if (state.cursor < len) { - text_input_delete_range(text, &len, state.cursor, state.cursor + 1); + int end = montauk::utf8::next_boundary(text, len, state.cursor); + text_input_delete_range(text, &len, state.cursor, end); changed = true; } state.selection_anchor = state.cursor; return TEXT_INPUT_CONSUMED | (changed ? TEXT_INPUT_CHANGED : 0); } - if (key.ctrl || key.alt || !text_input_char_allowed(key.ascii, filter, userdata)) - return TEXT_INPUT_NONE; + // Typed text is inserted as UTF-8; the filter sees each encoded byte. + char typed[montauk::utf8::MAX_BYTES]; + int typed_len = key.ctrl || key.alt ? 0 : montauk::utf8::key_utf8(key, typed); + if (typed_len == 0) return TEXT_INPUT_NONE; + for (int i = 0; i < typed_len; i++) { + if (!text_input_char_allowed(typed[i], filter, userdata)) + return TEXT_INPUT_NONE; + } if (sel_start != sel_end) { text_input_delete_range(text, &len, sel_start, sel_end); @@ -677,11 +692,12 @@ inline int text_input_key(TextInputState& state, changed = true; } - if (len < cap - 1) { + if (len + typed_len < cap) { for (int i = len; i >= state.cursor; i--) - text[i + 1] = text[i]; - text[state.cursor++] = key.ascii; - len++; + text[i + typed_len] = text[i]; + for (int i = 0; i < typed_len; i++) + text[state.cursor++] = typed[i]; + len += typed_len; changed = true; } @@ -1251,22 +1267,34 @@ inline void draw_badge(Canvas& c, c.text(x + theme.gap_sm, y + 2, label, fg); } +// One '*' per UTF-8 character. inline const char* mask_text(const char* value, char* buffer, int cap) { int len = 0; - while (value && value[len] && len < cap - 1) { - buffer[len] = '*'; - len++; + const char* p = value ? value : ""; + while (*p && len < cap - 1) { + montauk::utf8::next(&p); + buffer[len++] = '*'; } buffer[len] = '\0'; return buffer; } +// First `count` bytes of value (a character boundary), or one '*' per +// character in them when masked. inline void copy_prefix(char* buffer, int cap, const char* value, int count, bool masked) { if (cap <= 0) return; int len = 0; - while (value && value[len] && len < count && len < cap - 1) { - buffer[len] = masked ? '*' : value[len]; - len++; + if (masked) { + const char* p = value ? value : ""; + while (*p && p - value < count && len < cap - 1) { + montauk::utf8::next(&p); + buffer[len++] = '*'; + } + } else { + while (value && value[len] && len < count && len < cap - 1) { + buffer[len] = value[len]; + len++; + } } buffer[len] = '\0'; } diff --git a/template/sysroot/include/gui/terminal.hpp b/template/sysroot/include/gui/terminal.hpp index 6534bcc..23c133b 100644 --- a/template/sysroot/include/gui/terminal.hpp +++ b/template/sysroot/include/gui/terminal.hpp @@ -9,13 +9,14 @@ #include "gui/font.hpp" #include #include +#include #include #include 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()); } } diff --git a/template/sysroot/include/gui/truetype.hpp b/template/sysroot/include/gui/truetype.hpp index f7d877e..361fc04 100644 --- a/template/sysroot/include/gui/truetype.hpp +++ b/template/sysroot/include/gui/truetype.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "gui/gui.hpp" #include "gui/framebuffer.hpp" @@ -41,39 +42,12 @@ namespace gui { +// Windows-1252 byte -> Unicode codepoint, for the remaining code that still +// handles single-byte text (PDF simple-font encodings). UTF-8 strings go +// through measure_text/draw, which decode with montauk::utf8. inline int decode_single_byte_codepoint(int codepoint) { if (codepoint < 0 || codepoint > 255) return codepoint; - - switch (codepoint) { - case 0x80: return 0x20AC; // Euro Sign - case 0x82: return 0x201A; // Single Low-9 Quotation Mark - case 0x83: return 0x0192; // Latin Small Letter F With Hook - case 0x84: return 0x201E; // Double Low-9 Quotation Mark - case 0x85: return 0x2026; // Horizontal Ellipsis - case 0x86: return 0x2020; // Dagger - case 0x87: return 0x2021; // Double Dagger - case 0x88: return 0x02C6; // Modifier Letter Circumflex Accent - case 0x89: return 0x2030; // Per Mille Sign - case 0x8A: return 0x0160; // Latin Capital Letter S With Caron - case 0x8B: return 0x2039; // Single Left-Pointing Angle Quotation Mark - case 0x8C: return 0x0152; // Latin Capital Ligature OE - case 0x8E: return 0x017D; // Latin Capital Letter Z With Caron - case 0x91: return 0x2018; // Left Single Quotation Mark - case 0x92: return 0x2019; // Right Single Quotation Mark - case 0x93: return 0x201C; // Left Double Quotation Mark - case 0x94: return 0x201D; // Right Double Quotation Mark - case 0x95: return 0x2022; // Bullet - case 0x96: return 0x2013; // En Dash - case 0x97: return 0x2014; // Em Dash - case 0x98: return 0x02DC; // Small Tilde - case 0x99: return 0x2122; // Trade Mark Sign - case 0x9A: return 0x0161; // Latin Small Letter S With Caron - case 0x9B: return 0x203A; // Single Right-Pointing Angle Quotation Mark - case 0x9C: return 0x0153; // Latin Small Ligature OE - case 0x9E: return 0x017E; // Latin Small Letter Z With Caron - case 0x9F: return 0x0178; // Latin Capital Letter Y With Diaeresis - default: return codepoint; - } + return (int)montauk::utf8::from_cp1252((uint8_t)codepoint); } struct CachedGlyph { @@ -84,8 +58,18 @@ struct CachedGlyph { bool loaded; }; +// Glyphs above U+00FF live in a small open-addressed table so CJK, symbols +// and the like cost nothing until they are drawn. +struct ExtGlyph { + uint32_t codepoint; // 0 = empty slot + CachedGlyph glyph; +}; + struct GlyphCache { - CachedGlyph glyphs[256]; // Single-byte text with Windows-1252 punctuation mapping + CachedGlyph glyphs[256]; // Unicode U+0000-U+00FF, indexed directly + ExtGlyph* ext; // everything above, hashed by codepoint + int ext_cap; // power of two, 0 until first use + int ext_count; int pixel_size; float scale; int ascent, descent, line_gap; @@ -142,8 +126,21 @@ struct TrueTypeFont { return true; } - void init_cache(GlyphCache* gc, int pixel_size) { - // Free any existing glyph bitmaps + static void free_ext(GlyphCache* gc) { + if (gc->ext) { + for (int i = 0; i < gc->ext_cap; i++) { + if (gc->ext[i].codepoint && gc->ext[i].glyph.bitmap) + montauk::mfree(gc->ext[i].glyph.bitmap); + } + montauk::mfree(gc->ext); + } + gc->ext = nullptr; + gc->ext_cap = 0; + gc->ext_count = 0; + } + + // Release every glyph bitmap in a cache (the cache stays usable). + static void free_cache(GlyphCache* gc) { for (int i = 0; i < 256; i++) { if (gc->glyphs[i].bitmap) { montauk::mfree(gc->glyphs[i].bitmap); @@ -151,6 +148,11 @@ struct TrueTypeFont { gc->glyphs[i].bitmap = nullptr; gc->glyphs[i].loaded = false; } + free_ext(gc); + } + + void init_cache(GlyphCache* gc, int pixel_size) { + free_cache(gc); gc->pixel_size = pixel_size; gc->scale = em_scaling @@ -179,11 +181,8 @@ struct TrueTypeFont { return gc; } - // Evict oldest cache (slot 0) — free its glyph bitmaps - for (int g = 0; g < 256; g++) { - if (caches[0].glyphs[g].bitmap) - montauk::mfree(caches[0].glyphs[g].bitmap); - } + // Evict oldest cache (slot 0) - free its glyph bitmaps + free_cache(&caches[0]); // Shift remaining caches down for (int i = 0; i < 3; i++) montauk::memcpy(&caches[i], &caches[i + 1], sizeof(GlyphCache)); @@ -192,13 +191,54 @@ struct TrueTypeFont { return &caches[3]; } + static constexpr int EXT_MAX = 2048; // flush the table beyond this + + CachedGlyph* ext_slot(GlyphCache* gc, uint32_t codepoint) { + if (gc->ext_cap == 0 || gc->ext_count * 4 >= gc->ext_cap * 3) { + int new_cap = gc->ext_cap ? gc->ext_cap * 2 : 64; + if (gc->ext_count >= EXT_MAX) { + // A document full of distinct glyphs: start over rather than + // grow without bound. Bitmaps are rebuilt on demand. + free_ext(gc); + new_cap = 64; + } + ExtGlyph* table = (ExtGlyph*)montauk::malloc(sizeof(ExtGlyph) * new_cap); + if (!table) return nullptr; + montauk::memset(table, 0, sizeof(ExtGlyph) * new_cap); + for (int i = 0; i < gc->ext_cap; i++) { + ExtGlyph& e = gc->ext[i]; + if (!e.codepoint) continue; + uint32_t h = (e.codepoint * 2654435761u) & (new_cap - 1); + while (table[h].codepoint) h = (h + 1) & (new_cap - 1); + table[h] = e; + } + if (gc->ext) montauk::mfree(gc->ext); + gc->ext = table; + gc->ext_cap = new_cap; + } + uint32_t mask = gc->ext_cap - 1; + uint32_t h = (codepoint * 2654435761u) & mask; + while (gc->ext[h].codepoint && gc->ext[h].codepoint != codepoint) + h = (h + 1) & mask; + if (!gc->ext[h].codepoint) { + gc->ext[h].codepoint = codepoint; + montauk::memset(&gc->ext[h].glyph, 0, sizeof(CachedGlyph)); + gc->ext_count++; + } + return &gc->ext[h].glyph; + } + + // Glyph for a Unicode codepoint. Codepoints the font lacks render as its + // .notdef box, so missing characters stay visible instead of vanishing. CachedGlyph* get_glyph(GlyphCache* gc, int codepoint) { - if (codepoint < 0 || codepoint >= 256) return nullptr; - CachedGlyph* g = &gc->glyphs[codepoint]; + if (codepoint < 0 || codepoint > 0x10FFFF) return nullptr; + CachedGlyph* g = codepoint < 256 ? &gc->glyphs[codepoint] + : ext_slot(gc, (uint32_t)codepoint); + if (!g) return nullptr; if (g->loaded) return g; g->loaded = true; - int font_codepoint = decode_single_byte_codepoint(codepoint); + int font_codepoint = codepoint; int advance, lsb; stbtt_GetCodepointHMetrics(&info, font_codepoint, &advance, &lsb); g->advance = (int)(advance * gc->scale); @@ -222,12 +262,34 @@ struct TrueTypeFont { return g; } + // Advance of one codepoint at a size (0 if the font is unusable). + int char_advance(int codepoint, int pixel_size) { + if (!valid) return 0; + CachedGlyph* g = get_glyph(get_cache(pixel_size), codepoint); + return g ? g->advance : 0; + } + + // Width of the first `len` bytes of a UTF-8 string. + int measure_text_n(const char* text, int len, int pixel_size) { + if (!valid) return 0; + GlyphCache* gc = get_cache(pixel_size); + int w = 0; + for (int pos = 0; pos < len && text[pos];) { + int n; + uint32_t cp = montauk::utf8::decode(text + pos, len - pos, &n); + CachedGlyph* g = get_glyph(gc, (int)cp); + if (g) w += g->advance; + pos += n; + } + return w; + } + int measure_text(const char* text, int pixel_size) { if (!valid) return 0; GlyphCache* gc = get_cache(pixel_size); int w = 0; - for (int i = 0; text[i]; i++) { - CachedGlyph* g = get_glyph(gc, (unsigned char)text[i]); + for (const char* p = text; *p;) { + CachedGlyph* g = get_glyph(gc, (int)montauk::utf8::next(&p)); if (g) w += g->advance; } return w; @@ -253,8 +315,8 @@ struct TrueTypeFont { uint32_t src_rgb = 0xFF000000 | ((uint32_t)color.r << 16) | ((uint32_t)color.g << 8) | color.b; - for (int i = 0; text[i]; i++) { - CachedGlyph* g = get_glyph(gc, (unsigned char)text[i]); + for (const char* p = text; *p;) { + CachedGlyph* g = get_glyph(gc, (int)montauk::utf8::next(&p)); if (!g) continue; if (g->bitmap) { @@ -325,8 +387,8 @@ struct TrueTypeFont { int baseline = y + gc->ascent; bool drew_pixel = false; - for (int i = 0; text[i]; i++) { - CachedGlyph* g = get_glyph(gc, (unsigned char)text[i]); + for (const char* p = text; *p;) { + CachedGlyph* g = get_glyph(gc, (int)montauk::utf8::next(&p)); if (!g) continue; if (g->bitmap) { @@ -378,8 +440,8 @@ struct TrueTypeFont { int clip_x2 = clip_x + clip_w; int clip_y2 = clip_y + clip_h; - for (int i = 0; text[i]; i++) { - CachedGlyph* g = get_glyph(gc, (unsigned char)text[i]); + for (const char* p = text; *p;) { + CachedGlyph* g = get_glyph(gc, (int)montauk::utf8::next(&p)); if (!g) continue; if (g->bitmap) { @@ -417,7 +479,7 @@ struct TrueTypeFont { } } - // Draw single character to buffer, returning advance width + // Draw one Unicode codepoint to buffer, returning advance width int draw_char_to_buffer(uint32_t* pixels, int buf_w, int buf_h, int x, int baseline, int codepoint, Color color, GlyphCache* gc) { diff --git a/template/sysroot/include/gui/widgets.hpp b/template/sysroot/include/gui/widgets.hpp index 5aa203d..e2de916 100644 --- a/template/sysroot/include/gui/widgets.hpp +++ b/template/sysroot/include/gui/widgets.hpp @@ -212,11 +212,7 @@ struct TextBox { // Draw cursor if focused if (focused) { - // Measure text up to cursor position for proportional fonts - char prefix[256]; - for (int i = 0; i < cursor && i < 255; i++) prefix[i] = text[i]; - prefix[cursor < 255 ? cursor : 255] = '\0'; - int cx = tx + text_width(prefix); + int cx = tx + text_width_n(text, cursor); draw_vline(fb, cx, ty, fh, cursor_color); } } @@ -230,34 +226,35 @@ struct TextBox { void handle_key(const montauk::abi::KeyEvent& key) { if (!focused || !key.pressed) return; + char typed[montauk::utf8::MAX_BYTES]; + int typed_len = montauk::utf8::key_utf8(key, typed); + if (key.ascii == '\b' || key.scancode == 0x0E) { - // Backspace + // Backspace: remove the whole character before the cursor if (cursor > 0) { - for (int i = cursor - 1; i < text_len - 1; i++) { - text[i] = text[i + 1]; - } - text_len--; - cursor--; - text[text_len] = '\0'; + int start = montauk::utf8::prev_boundary(text, cursor); + int n = cursor - start; + for (int i = start; i <= text_len - n; i++) + text[i] = text[i + n]; + text_len -= n; + cursor = start; } - } else if ((unsigned char)key.ascii >= 32 - && (unsigned char)key.ascii != 127) { - // Printable character - if (text_len < 254) { - for (int i = text_len; i > cursor; i--) { - text[i] = text[i - 1]; - } - text[cursor] = key.ascii; - cursor++; - text_len++; - text[text_len] = '\0'; + } else if (typed_len > 0) { + // Printable character, inserted as UTF-8 + if (text_len + typed_len <= 254) { + for (int i = text_len; i >= cursor; i--) + text[i + typed_len] = text[i]; + for (int i = 0; i < typed_len; i++) + text[cursor + i] = typed[i]; + cursor += typed_len; + text_len += typed_len; } - } else if (key.scancode == 0x4B) { + } else if (montauk::nav_scancode(key) == 0x4B) { // Left arrow - if (cursor > 0) cursor--; - } else if (key.scancode == 0x4D) { + cursor = montauk::utf8::prev_boundary(text, cursor); + } else if (montauk::nav_scancode(key) == 0x4D) { // Right arrow - if (cursor < text_len) cursor++; + cursor = montauk::utf8::next_boundary(text, text_len, cursor); } } }; diff --git a/template/sysroot/include/libc/montauk.h b/template/sysroot/include/libc/montauk.h index d08f457..7f02ad6 100644 --- a/template/sysroot/include/libc/montauk.h +++ b/template/sysroot/include/libc/montauk.h @@ -23,200 +23,202 @@ extern "C" { Generated from Api/Syscall.hpp by scripts/montauk-syscalls.py. Do not edit by hand; run 'make gen-syscalls' to refresh. Wrapper functions below are hand-written. */ -#define MTK_SYS_EXIT 0 -#define MTK_SYS_YIELD 1 -#define MTK_SYS_SLEEP_MS 2 -#define MTK_SYS_GETPID 3 -#define MTK_SYS_PRINT 4 -#define MTK_SYS_PUTCHAR 5 -#define MTK_SYS_OPEN 6 -#define MTK_SYS_READ 7 -#define MTK_SYS_GETSIZE 8 -#define MTK_SYS_CLOSE 9 -#define MTK_SYS_READDIR 10 -#define MTK_SYS_ALLOC 11 -#define MTK_SYS_FREE 12 -#define MTK_SYS_GETTICKS 13 -#define MTK_SYS_GETMILLISECONDS 14 -#define MTK_SYS_GETINFO 15 -#define MTK_SYS_ISKEYAVAILABLE 16 -#define MTK_SYS_GETKEY 17 -#define MTK_SYS_GETCHAR 18 -#define MTK_SYS_PING 19 -#define MTK_SYS_SPAWN 20 -#define MTK_SYS_FBINFO 21 -#define MTK_SYS_FBMAP 22 -#define MTK_SYS_WAITPID 23 -#define MTK_SYS_TERMSIZE 24 -#define MTK_SYS_GETARGS 25 -#define MTK_SYS_RESET 26 -#define MTK_SYS_SHUTDOWN 27 -#define MTK_SYS_GETTIME 28 -#define MTK_SYS_SOCKET 29 -#define MTK_SYS_CONNECT 30 -#define MTK_SYS_BIND 31 -#define MTK_SYS_LISTEN 32 -#define MTK_SYS_ACCEPT 33 -#define MTK_SYS_SEND 34 -#define MTK_SYS_RECV 35 -#define MTK_SYS_CLOSESOCK 36 -#define MTK_SYS_GETNETCFG 37 -#define MTK_SYS_SETNETCFG 38 -#define MTK_SYS_SENDTO 39 -#define MTK_SYS_RECVFROM 40 -#define MTK_SYS_FWRITE 41 -#define MTK_SYS_FCREATE 42 -#define MTK_SYS_TERMSCALE 43 -#define MTK_SYS_RESOLVE 44 -#define MTK_SYS_GETRANDOM 45 -#define MTK_SYS_LOG 46 -#define MTK_SYS_MOUSESTATE 47 -#define MTK_SYS_SETMOUSEBOUNDS 48 -#define MTK_SYS_SPAWN_REDIR 49 -#define MTK_SYS_CHILDIO_READ 50 -#define MTK_SYS_CHILDIO_WRITE 51 -#define MTK_SYS_CHILDIO_WRITEKEY 52 -#define MTK_SYS_CHILDIO_SETTERMSZ 53 -#define MTK_SYS_WINCREATE 54 -#define MTK_SYS_WINDESTROY 55 -#define MTK_SYS_WINPRESENT 56 -#define MTK_SYS_WINPOLL 57 -#define MTK_SYS_WINENUM 58 -#define MTK_SYS_WINMAP 59 -#define MTK_SYS_WINSENDEVENT 60 -#define MTK_SYS_PROCLIST 61 -#define MTK_SYS_KILL 62 -#define MTK_SYS_DEVLIST 63 -#define MTK_SYS_WINRESIZE 64 -#define MTK_SYS_WINSETSCALE 65 -#define MTK_SYS_WINGETSCALE 66 -#define MTK_SYS_MEMSTATS 67 -#define MTK_SYS_WINSETCURSOR 68 -#define MTK_SYS_DISKINFO 69 -#define MTK_SYS_PARTLIST 70 -#define MTK_SYS_DISKREAD 71 -#define MTK_SYS_DISKWRITE 72 -#define MTK_SYS_GPTINIT 73 -#define MTK_SYS_GPTADD 74 -#define MTK_SYS_FSMOUNT 75 -#define MTK_SYS_FSFORMAT 76 -#define MTK_SYS_FDELETE 77 -#define MTK_SYS_FMKDIR 78 -#define MTK_SYS_DRIVELIST 79 -#define MTK_SYS_AUDIOOPEN 80 -#define MTK_SYS_AUDIOCLOSE 81 -#define MTK_SYS_AUDIOWRITE 82 -#define MTK_SYS_AUDIOCTL 83 -#define MTK_SYS_BTSCAN 84 -#define MTK_SYS_BTCONNECT 85 -#define MTK_SYS_BTDISCONNECT 86 -#define MTK_SYS_BTLIST 87 -#define MTK_SYS_BTINFO 88 -#define MTK_SYS_SUSPEND 89 -#define MTK_SYS_SETTZ 90 -#define MTK_SYS_GETTZ 91 -#define MTK_SYS_SETUSER 92 -#define MTK_SYS_GETUSER 93 -#define MTK_SYS_FRENAME 94 -#define MTK_SYS_GETCWD 95 -#define MTK_SYS_CHDIR 96 -#define MTK_SYS_WINUNMAP 97 -#define MTK_SYS_DUPHANDLE 98 -#define MTK_SYS_WAIT_HANDLE 99 -#define MTK_SYS_STREAM_CREATE 100 -#define MTK_SYS_STREAM_READ 101 -#define MTK_SYS_STREAM_WRITE 102 -#define MTK_SYS_MAILBOX_CREATE 103 -#define MTK_SYS_MAILBOX_SEND 104 -#define MTK_SYS_MAILBOX_RECV 105 -#define MTK_SYS_WAITSET_CREATE 106 -#define MTK_SYS_WAITSET_ADD 107 -#define MTK_SYS_WAITSET_REMOVE 108 -#define MTK_SYS_WAITSET_WAIT 109 -#define MTK_SYS_PROC_OPEN 110 -#define MTK_SYS_SURFACE_CREATE 111 -#define MTK_SYS_SURFACE_MAP 112 -#define MTK_SYS_SURFACE_RESIZE 113 -#define MTK_SYS_LOAD_LIB 114 -#define MTK_SYS_UNLOAD_LIB 115 -#define MTK_SYS_DLSYM 116 -#define MTK_SYS_GETLIBBASE 117 -#define MTK_SYS_CRASH_REPORT 118 -#define MTK_SYS_CLIPBOARD_SET_TEXT 119 -#define MTK_SYS_CLIPBOARD_GET_INFO 120 -#define MTK_SYS_CLIPBOARD_GET_TEXT 121 -#define MTK_SYS_CLIPBOARD_CLEAR 122 -#define MTK_SYS_INPUT_WAIT 123 -#define MTK_SYS_DRIVELABEL 124 -#define MTK_SYS_NETSTATUS 125 -#define MTK_SYS_WINSETFLAGS 126 -#define MTK_SYS_DRIVEKIND 127 -#define MTK_SYS_AUDIOLIST 128 -#define MTK_SYS_AUDIOWAIT 129 -#define MTK_SYS_THREAD_SPAWN 130 -#define MTK_SYS_THREAD_EXIT 131 -#define MTK_SYS_THREAD_JOIN 132 -#define MTK_SYS_THREAD_SELF 133 -#define MTK_SYS_FS_SYNC 134 -#define MTK_SYS_POWER_REQUEST 135 -#define MTK_SYS_READDIR_AT 136 -#define MTK_SYS_BTSETADDR 137 -#define MTK_SYS_BTBONDS 138 -#define MTK_SYS_BTFORGET 139 -#define MTK_SYS_RESERVED_140 140 -#define MTK_SYS_RESERVED_141 141 -#define MTK_SYS_RESERVED_142 142 -#define MTK_SYS_RESERVED_143 143 -#define MTK_SYS_RESERVED_144 144 -#define MTK_SYS_RESERVED_145 145 -#define MTK_SYS_RESERVED_146 146 -#define MTK_SYS_RESERVED_147 147 -#define MTK_SYS_RESERVED_148 148 -#define MTK_SYS_POWERINFO 149 -#define MTK_SYS_FBFLIP 150 -#define MTK_SYS_GETEXECPATH 151 -#define MTK_SYS_STAT 152 -#define MTK_SYS_SETUNIXTIME 153 -#define MTK_SYS_DISPLAYINFO 154 -#define MTK_SYS_DISPLAYMODES 155 -#define MTK_SYS_DISPLAYSETMODE 156 -#define MTK_SYS_DISPLAYBRIGHTNESS 157 -#define MTK_SYS_WIFI_SCAN 158 -#define MTK_SYS_WIFI_INFO 159 -#define MTK_SYS_WIFI_CONNECT 160 -#define MTK_SYS_WIFI_DISCONNECT 161 -#define MTK_SYS_WIFI_SCAN_START 162 -#define MTK_SYS_WIFI_RESULTS 163 -#define MTK_SYS_WIFI_CONNECT_ASYNC 164 -#define MTK_SYS_NETIFS 165 -#define MTK_SYS_GETCHAR_NB 166 -#define MTK_SYS_UTIME 167 -#define MTK_SYS_MMAP_ANON 168 -#define MTK_SYS_MUNMAP 169 -#define MTK_SYS_MPROTECT 170 -#define MTK_SYS_GETENVIRON 171 -#define MTK_SYS_SETENVIRON 172 -#define MTK_SYS_SPAWN_ENV 173 -#define MTK_SYS_SETSESSION 174 -#define MTK_SYS_KILLSESSION 175 -#define MTK_SYS_LOG_WRITE 176 -#define MTK_SYS_TERMINAL_ATTACHED 177 -#define MTK_SYS_USB_LIST 178 -#define MTK_SYS_USB_CLAIM 179 -#define MTK_SYS_USB_CLOSE 180 -#define MTK_SYS_USB_CONTROL 181 -#define MTK_SYS_USB_BULK_IN_START 182 -#define MTK_SYS_USB_BULK_IN_STOP 183 -#define MTK_SYS_USB_BULK_IN_READ 184 -#define MTK_SYS_SPAWN_CAPS 185 -#define MTK_SYS_SPAWN_REDIR_CAPS 186 -#define MTK_SYS_ALLOC_EAGER 187 -#define MTK_SYS_BATTERYINFO 188 -#define MTK_SYS_GETCAPS 189 -#define MTK_SYS_VOLINFO 190 -#define MTK_SYS_CONSENT_REGISTER 191 -#define MTK_SYS_CONSENT_NEXT 192 -#define MTK_SYS_CONSENT_REPLY 193 +#define MTK_SYS_EXIT 0 +#define MTK_SYS_YIELD 1 +#define MTK_SYS_SLEEP_MS 2 +#define MTK_SYS_GETPID 3 +#define MTK_SYS_PRINT 4 +#define MTK_SYS_PUTCHAR 5 +#define MTK_SYS_OPEN 6 +#define MTK_SYS_READ 7 +#define MTK_SYS_GETSIZE 8 +#define MTK_SYS_CLOSE 9 +#define MTK_SYS_READDIR 10 +#define MTK_SYS_ALLOC 11 +#define MTK_SYS_FREE 12 +#define MTK_SYS_GETTICKS 13 +#define MTK_SYS_GETMILLISECONDS 14 +#define MTK_SYS_GETINFO 15 +#define MTK_SYS_ISKEYAVAILABLE 16 +#define MTK_SYS_GETKEY 17 +#define MTK_SYS_GETCHAR 18 +#define MTK_SYS_PING 19 +#define MTK_SYS_SPAWN 20 +#define MTK_SYS_FBINFO 21 +#define MTK_SYS_FBMAP 22 +#define MTK_SYS_WAITPID 23 +#define MTK_SYS_TERMSIZE 24 +#define MTK_SYS_GETARGS 25 +#define MTK_SYS_RESET 26 +#define MTK_SYS_SHUTDOWN 27 +#define MTK_SYS_GETTIME 28 +#define MTK_SYS_SOCKET 29 +#define MTK_SYS_CONNECT 30 +#define MTK_SYS_BIND 31 +#define MTK_SYS_LISTEN 32 +#define MTK_SYS_ACCEPT 33 +#define MTK_SYS_SEND 34 +#define MTK_SYS_RECV 35 +#define MTK_SYS_CLOSESOCK 36 +#define MTK_SYS_GETNETCFG 37 +#define MTK_SYS_SETNETCFG 38 +#define MTK_SYS_SENDTO 39 +#define MTK_SYS_RECVFROM 40 +#define MTK_SYS_FWRITE 41 +#define MTK_SYS_FCREATE 42 +#define MTK_SYS_TERMSCALE 43 +#define MTK_SYS_RESOLVE 44 +#define MTK_SYS_GETRANDOM 45 +#define MTK_SYS_LOG 46 +#define MTK_SYS_MOUSESTATE 47 +#define MTK_SYS_SETMOUSEBOUNDS 48 +#define MTK_SYS_SPAWN_REDIR 49 +#define MTK_SYS_CHILDIO_READ 50 +#define MTK_SYS_CHILDIO_WRITE 51 +#define MTK_SYS_CHILDIO_WRITEKEY 52 +#define MTK_SYS_CHILDIO_SETTERMSZ 53 +#define MTK_SYS_WINCREATE 54 +#define MTK_SYS_WINDESTROY 55 +#define MTK_SYS_WINPRESENT 56 +#define MTK_SYS_WINPOLL 57 +#define MTK_SYS_WINENUM 58 +#define MTK_SYS_WINMAP 59 +#define MTK_SYS_WINSENDEVENT 60 +#define MTK_SYS_PROCLIST 61 +#define MTK_SYS_KILL 62 +#define MTK_SYS_DEVLIST 63 +#define MTK_SYS_WINRESIZE 64 +#define MTK_SYS_WINSETSCALE 65 +#define MTK_SYS_WINGETSCALE 66 +#define MTK_SYS_MEMSTATS 67 +#define MTK_SYS_WINSETCURSOR 68 +#define MTK_SYS_DISKINFO 69 +#define MTK_SYS_PARTLIST 70 +#define MTK_SYS_DISKREAD 71 +#define MTK_SYS_DISKWRITE 72 +#define MTK_SYS_GPTINIT 73 +#define MTK_SYS_GPTADD 74 +#define MTK_SYS_FSMOUNT 75 +#define MTK_SYS_FSFORMAT 76 +#define MTK_SYS_FDELETE 77 +#define MTK_SYS_FMKDIR 78 +#define MTK_SYS_DRIVELIST 79 +#define MTK_SYS_AUDIOOPEN 80 +#define MTK_SYS_AUDIOCLOSE 81 +#define MTK_SYS_AUDIOWRITE 82 +#define MTK_SYS_AUDIOCTL 83 +#define MTK_SYS_BTSCAN 84 +#define MTK_SYS_BTCONNECT 85 +#define MTK_SYS_BTDISCONNECT 86 +#define MTK_SYS_BTLIST 87 +#define MTK_SYS_BTINFO 88 +#define MTK_SYS_SUSPEND 89 +#define MTK_SYS_SETTZ 90 +#define MTK_SYS_GETTZ 91 +#define MTK_SYS_SETUSER 92 +#define MTK_SYS_GETUSER 93 +#define MTK_SYS_FRENAME 94 +#define MTK_SYS_GETCWD 95 +#define MTK_SYS_CHDIR 96 +#define MTK_SYS_WINUNMAP 97 +#define MTK_SYS_DUPHANDLE 98 +#define MTK_SYS_WAIT_HANDLE 99 +#define MTK_SYS_STREAM_CREATE 100 +#define MTK_SYS_STREAM_READ 101 +#define MTK_SYS_STREAM_WRITE 102 +#define MTK_SYS_MAILBOX_CREATE 103 +#define MTK_SYS_MAILBOX_SEND 104 +#define MTK_SYS_MAILBOX_RECV 105 +#define MTK_SYS_WAITSET_CREATE 106 +#define MTK_SYS_WAITSET_ADD 107 +#define MTK_SYS_WAITSET_REMOVE 108 +#define MTK_SYS_WAITSET_WAIT 109 +#define MTK_SYS_PROC_OPEN 110 +#define MTK_SYS_SURFACE_CREATE 111 +#define MTK_SYS_SURFACE_MAP 112 +#define MTK_SYS_SURFACE_RESIZE 113 +#define MTK_SYS_LOAD_LIB 114 +#define MTK_SYS_UNLOAD_LIB 115 +#define MTK_SYS_DLSYM 116 +#define MTK_SYS_GETLIBBASE 117 +#define MTK_SYS_CRASH_REPORT 118 +#define MTK_SYS_CLIPBOARD_SET_TEXT 119 +#define MTK_SYS_CLIPBOARD_GET_INFO 120 +#define MTK_SYS_CLIPBOARD_GET_TEXT 121 +#define MTK_SYS_CLIPBOARD_CLEAR 122 +#define MTK_SYS_INPUT_WAIT 123 +#define MTK_SYS_DRIVELABEL 124 +#define MTK_SYS_NETSTATUS 125 +#define MTK_SYS_WINSETFLAGS 126 +#define MTK_SYS_DRIVEKIND 127 +#define MTK_SYS_AUDIOLIST 128 +#define MTK_SYS_AUDIOWAIT 129 +#define MTK_SYS_THREAD_SPAWN 130 +#define MTK_SYS_THREAD_EXIT 131 +#define MTK_SYS_THREAD_JOIN 132 +#define MTK_SYS_THREAD_SELF 133 +#define MTK_SYS_FS_SYNC 134 +#define MTK_SYS_POWER_REQUEST 135 +#define MTK_SYS_READDIR_AT 136 +#define MTK_SYS_BTSETADDR 137 +#define MTK_SYS_BTBONDS 138 +#define MTK_SYS_BTFORGET 139 +#define MTK_SYS_RESERVED_140 140 +#define MTK_SYS_RESERVED_141 141 +#define MTK_SYS_RESERVED_142 142 +#define MTK_SYS_RESERVED_143 143 +#define MTK_SYS_RESERVED_144 144 +#define MTK_SYS_RESERVED_145 145 +#define MTK_SYS_RESERVED_146 146 +#define MTK_SYS_RESERVED_147 147 +#define MTK_SYS_RESERVED_148 148 +#define MTK_SYS_POWERINFO 149 +#define MTK_SYS_FBFLIP 150 +#define MTK_SYS_GETEXECPATH 151 +#define MTK_SYS_STAT 152 +#define MTK_SYS_SETUNIXTIME 153 +#define MTK_SYS_DISPLAYINFO 154 +#define MTK_SYS_DISPLAYMODES 155 +#define MTK_SYS_DISPLAYSETMODE 156 +#define MTK_SYS_DISPLAYBRIGHTNESS 157 +#define MTK_SYS_WIFI_SCAN 158 +#define MTK_SYS_WIFI_INFO 159 +#define MTK_SYS_WIFI_CONNECT 160 +#define MTK_SYS_WIFI_DISCONNECT 161 +#define MTK_SYS_WIFI_SCAN_START 162 +#define MTK_SYS_WIFI_RESULTS 163 +#define MTK_SYS_WIFI_CONNECT_ASYNC 164 +#define MTK_SYS_NETIFS 165 +#define MTK_SYS_GETCHAR_NB 166 +#define MTK_SYS_UTIME 167 +#define MTK_SYS_MMAP_ANON 168 +#define MTK_SYS_MUNMAP 169 +#define MTK_SYS_MPROTECT 170 +#define MTK_SYS_GETENVIRON 171 +#define MTK_SYS_SETENVIRON 172 +#define MTK_SYS_SPAWN_ENV 173 +#define MTK_SYS_SETSESSION 174 +#define MTK_SYS_KILLSESSION 175 +#define MTK_SYS_LOG_WRITE 176 +#define MTK_SYS_TERMINAL_ATTACHED 177 +#define MTK_SYS_USB_LIST 178 +#define MTK_SYS_USB_CLAIM 179 +#define MTK_SYS_USB_CLOSE 180 +#define MTK_SYS_USB_CONTROL 181 +#define MTK_SYS_USB_BULK_IN_START 182 +#define MTK_SYS_USB_BULK_IN_STOP 183 +#define MTK_SYS_USB_BULK_IN_READ 184 +#define MTK_SYS_SPAWN_CAPS 185 +#define MTK_SYS_SPAWN_REDIR_CAPS 186 +#define MTK_SYS_ALLOC_EAGER 187 +#define MTK_SYS_BATTERYINFO 188 +#define MTK_SYS_GETCAPS 189 +#define MTK_SYS_VOLINFO 190 +#define MTK_SYS_CONSENT_REGISTER 191 +#define MTK_SYS_CONSENT_NEXT 192 +#define MTK_SYS_CONSENT_REPLY 193 +#define MTK_SYS_GETKEY_EX 194 +#define MTK_SYS_CHILDIO_WRITEKEY_EX 195 /* @SYSCALLS-END */ /* Syscall status codes (montauk/statuscodes.h for C++). */ diff --git a/template/sysroot/include/montauk/keyboard.h b/template/sysroot/include/montauk/keyboard.h index 74bb23a..ef5a1a6 100644 --- a/template/sysroot/include/montauk/keyboard.h +++ b/template/sysroot/include/montauk/keyboard.h @@ -8,27 +8,34 @@ #include #include +#include namespace montauk::keyboard { -inline constexpr int MAX_LAYOUTS = 8; -inline constexpr int MAX_KEYS = 64; +inline constexpr int MAX_LAYOUTS = 8; +inline constexpr int MAX_KEYS = 64; +inline constexpr int MAX_DEAD_KEYS = 16; -// One overridden key. Characters are Windows-1252 bytes to match the -// single-byte GUI text stack; 0 means "no override, keep the kernel's value". +// One overridden key. Characters are Unicode codepoints; translation stores +// them in KeyEvent::codepoint (and the Windows-1252 byte, if any, in ascii). +// 0 means "no override, keep the kernel's value". struct KeyMap { - uint8_t scancode; - uint8_t base; - uint8_t shift; - uint8_t altgr; + uint8_t scancode; + uint32_t base; + uint32_t shift; + uint32_t altgr; }; struct Layout { - char id[8]; - char name[48]; - char short_name[8]; - KeyMap keys[MAX_KEYS]; - int key_count; // 0 = passthrough (the kernel's US table) + char id[8]; + char name[48]; + char short_name[8]; + KeyMap keys[MAX_KEYS]; + int key_count; // 0 = passthrough (the kernel's US table) + // Characters that act as dead keys in this layout: pressing one types + // nothing and modifies the next character (see compose()). + uint32_t dead_keys[MAX_DEAD_KEYS]; + int dead_count; }; struct Registry { @@ -40,8 +47,71 @@ struct State { Registry registry; bool enabled[MAX_LAYOUTS]; int active; + uint32_t pending_dead; // dead key waiting for the next character, 0 = none }; +// ==== Dead-key composition ==== +// Keyed by the spacing form of the accent, which is what a layout puts on the +// dead key itself (and what dead key + Space types). + +struct ComposeEntry { + uint16_t dead; + uint16_t base; + uint16_t result; +}; + +inline constexpr ComposeEntry COMPOSE[] = { + // acute + {0x00B4,'a',0xE1},{0x00B4,'A',0xC1},{0x00B4,'e',0xE9},{0x00B4,'E',0xC9}, + {0x00B4,'i',0xED},{0x00B4,'I',0xCD},{0x00B4,'o',0xF3},{0x00B4,'O',0xD3}, + {0x00B4,'u',0xFA},{0x00B4,'U',0xDA},{0x00B4,'y',0xFD},{0x00B4,'Y',0xDD}, + {0x00B4,'c',0x107},{0x00B4,'C',0x106},{0x00B4,'l',0x13A},{0x00B4,'L',0x139}, + {0x00B4,'n',0x144},{0x00B4,'N',0x143},{0x00B4,'r',0x155},{0x00B4,'R',0x154}, + {0x00B4,'s',0x15B},{0x00B4,'S',0x15A},{0x00B4,'z',0x17A},{0x00B4,'Z',0x179}, + // caron + {0x02C7,'c',0x10D},{0x02C7,'C',0x10C},{0x02C7,'d',0x10F},{0x02C7,'D',0x10E}, + {0x02C7,'e',0x11B},{0x02C7,'E',0x11A},{0x02C7,'l',0x13E},{0x02C7,'L',0x13D}, + {0x02C7,'n',0x148},{0x02C7,'N',0x147},{0x02C7,'r',0x159},{0x02C7,'R',0x158}, + {0x02C7,'s',0x161},{0x02C7,'S',0x160},{0x02C7,'t',0x165},{0x02C7,'T',0x164}, + {0x02C7,'z',0x17E},{0x02C7,'Z',0x17D}, + // diaeresis + {0x00A8,'a',0xE4},{0x00A8,'A',0xC4},{0x00A8,'e',0xEB},{0x00A8,'E',0xCB}, + {0x00A8,'i',0xEF},{0x00A8,'I',0xCF},{0x00A8,'o',0xF6},{0x00A8,'O',0xD6}, + {0x00A8,'u',0xFC},{0x00A8,'U',0xDC},{0x00A8,'y',0xFF},{0x00A8,'Y',0x178}, + // ring above + {0x00B0,'u',0x16F},{0x00B0,'U',0x16E},{0x00B0,'a',0xE5},{0x00B0,'A',0xC5}, + // grave + {0x0060,'a',0xE0},{0x0060,'A',0xC0},{0x0060,'e',0xE8},{0x0060,'E',0xC8}, + {0x0060,'i',0xEC},{0x0060,'I',0xCC},{0x0060,'o',0xF2},{0x0060,'O',0xD2}, + {0x0060,'u',0xF9},{0x0060,'U',0xD9}, + // circumflex + {0x005E,'a',0xE2},{0x005E,'A',0xC2},{0x005E,'e',0xEA},{0x005E,'E',0xCA}, + {0x005E,'i',0xEE},{0x005E,'I',0xCE},{0x005E,'o',0xF4},{0x005E,'O',0xD4}, + {0x005E,'u',0xFB},{0x005E,'U',0xDB}, + // tilde + {0x007E,'a',0xE3},{0x007E,'A',0xC3},{0x007E,'n',0xF1},{0x007E,'N',0xD1}, + {0x007E,'o',0xF5},{0x007E,'O',0xD5}, + // breve + {0x02D8,'a',0x103},{0x02D8,'A',0x102},{0x02D8,'g',0x11F},{0x02D8,'G',0x11E}, + // ogonek + {0x02DB,'a',0x105},{0x02DB,'A',0x104},{0x02DB,'e',0x119},{0x02DB,'E',0x118}, + {0x02DB,'i',0x12F},{0x02DB,'I',0x12E},{0x02DB,'u',0x173},{0x02DB,'U',0x172}, + // dot above + {0x02D9,'z',0x17C},{0x02D9,'Z',0x17B},{0x02D9,'e',0x117},{0x02D9,'E',0x116}, + {0x02D9,'I',0x130}, + // double acute + {0x02DD,'o',0x151},{0x02DD,'O',0x150},{0x02DD,'u',0x171},{0x02DD,'U',0x170}, + // cedilla + {0x00B8,'c',0xE7},{0x00B8,'C',0xC7},{0x00B8,'s',0x15F},{0x00B8,'S',0x15E}, +}; + +// The composed character, or 0 if the accent does not combine with base. +inline uint32_t compose(uint32_t dead, uint32_t base) { + for (const ComposeEntry& e : COMPOSE) + if (e.dead == dead && e.base == base) return e.result; + return 0; +} + inline void build_key(char* out, int cap, const char* prefix, const char* id, const char* suffix = nullptr) { int pos = 0; @@ -54,10 +124,9 @@ inline void build_key(char* out, int cap, const char* prefix, out[pos] = '\0'; } -// Read an array of byte values from the layout table. +// Read an array of byte values (scancodes) from the layout table. // Returns the element count, or -1 if the key is missing or malformed. -inline int read_bytes(const toml::Doc& doc, const char* key, - uint8_t* out, int cap) { +inline int read_bytes(const toml::Doc& doc, const char* key, uint8_t* out, int cap) { toml::Value* arr = doc.get_array(key); if (!arr) return -1; if (arr->array.count > cap) return -1; @@ -70,6 +139,23 @@ inline int read_bytes(const toml::Doc& doc, const char* key, return arr->array.count; } +// Read an array of characters (Unicode codepoints). 0x80-0x9F are C1 control +// codes in Unicode, never key output, so they are read as the Windows-1252 +// bytes older layout files used (0x80 = euro sign). +inline int read_codepoints(const toml::Doc& doc, const char* key, uint32_t* out, int cap) { + toml::Value* arr = doc.get_array(key); + if (!arr) return -1; + if (arr->array.count > cap) return -1; + for (int i = 0; i < arr->array.count; i++) { + toml::Value* value = arr->array.items[i]; + if (!value || value->type != toml::Type::Int) return -1; + int64_t v = value->ival; + if (v < 0 || v > 0x10FFFF || (v >= 0xD800 && v <= 0xDFFF)) return -1; + out[i] = (v >= 0x80 && v <= 0x9F) ? utf8::from_cp1252((uint8_t)v) : (uint32_t)v; + } + return arr->array.count; +} + // Parse one [layouts.] table. Returns false if the layout declares key // overrides but they are inconsistent, in which case the caller skips it: a // malformed table must never produce a half-applied layout. @@ -85,10 +171,15 @@ inline bool load_layout(Layout* out, const char* id, const toml::Doc& doc) { montauk::strncpy(out->short_name, doc.get_string(key, id), sizeof(out->short_name)); - uint8_t scancodes[MAX_KEYS]; - uint8_t base[MAX_KEYS]; - uint8_t shift[MAX_KEYS]; - uint8_t altgr[MAX_KEYS] = {}; + build_key(key, sizeof(key), "layouts.", id, ".dead_keys"); + int dead = read_codepoints(doc, key, out->dead_keys, MAX_DEAD_KEYS); + if (dead < 0 && doc.get_array(key)) return false; // present but malformed + out->dead_count = dead < 0 ? 0 : dead; + + uint8_t scancodes[MAX_KEYS]; + uint32_t base[MAX_KEYS]; + uint32_t shift[MAX_KEYS]; + uint32_t altgr[MAX_KEYS] = {}; build_key(key, sizeof(key), "layouts.", id, ".scancodes"); int count = read_bytes(doc, key, scancodes, MAX_KEYS); @@ -99,11 +190,11 @@ inline bool load_layout(Layout* out, const char* id, const toml::Doc& doc) { } build_key(key, sizeof(key), "layouts.", id, ".base"); - if (read_bytes(doc, key, base, MAX_KEYS) != count) return false; + if (read_codepoints(doc, key, base, MAX_KEYS) != count) return false; build_key(key, sizeof(key), "layouts.", id, ".shift"); - if (read_bytes(doc, key, shift, MAX_KEYS) != count) return false; + if (read_codepoints(doc, key, shift, MAX_KEYS) != count) return false; build_key(key, sizeof(key), "layouts.", id, ".altgr"); - int altgr_count = read_bytes(doc, key, altgr, MAX_KEYS); + int altgr_count = read_codepoints(doc, key, altgr, MAX_KEYS); if (altgr_count >= 0 && altgr_count != count) return false; for (int i = 0; i < count; i++) { @@ -174,6 +265,7 @@ inline Registry load_registry() { // it reads one small file instead of re-parsing the whole layout table. inline void refresh_selection(State* state, const char* username) { if (!state) return; + state->pending_dead = 0; // a dead key never carries over a layout switch for (int i = 0; i < state->registry.count; i++) state->enabled[i] = false; toml::Doc doc = config::load_user(username, "keyboard"); @@ -237,57 +329,117 @@ inline int next_enabled(const State& state, int current) { } // Caps Lock is derived rather than declared per key: it applies only where -// base and shift are a Windows-1252 lower/upper letter pair. That covers the -// accented letters (aa 0xE5 / AA 0xC5) without wrongly upper-casing keys such -// as 2 / " where the shifted value is unrelated punctuation. -inline constexpr bool is_letter_pair(uint8_t base, uint8_t shift) { +// base and shift are the lower/upper case of one letter. That covers accented +// letters in any script (aa/AA, e-caron/E-caron) without wrongly upper-casing +// keys such as 2 / " where the shifted value is unrelated punctuation. +inline constexpr bool is_letter_pair(uint32_t base, uint32_t shift) { if (base == 0 || shift == 0) return false; - if (base < 0x61) return false; - if (base > 0x7A && base < 0xE0) return false; - if (base == 0xF7) return false; // division sign sits inside the range - return shift == (uint8_t)(base - 0x20); + return utf8::is_case_pair(base, shift); } -static_assert(is_letter_pair(0xE5, 0xC5)); // aa / AA -static_assert(is_letter_pair(0xF8, 0xD8)); // oe / OE -static_assert(is_letter_pair(0xE6, 0xC6)); // ae / AE +static_assert(is_letter_pair(0xE5, 0xC5)); // aa / AA +static_assert(is_letter_pair(0xF8, 0xD8)); // oe / OE +static_assert(is_letter_pair(0x11B, 0x11A)); // e-caron static_assert(is_letter_pair('a', 'A')); static_assert(!is_letter_pair('2', '"')); -static_assert(!is_letter_pair(0xF7, 0xD7)); // divide / multiply +static_assert(!is_letter_pair(0xF7, 0xD7)); // divide / multiply +static_assert(!is_letter_pair(0x11B, '2')); // Czech number row -inline void translate(const State& state, abi::KeyEvent* key) { +inline bool is_dead_key(const Layout& layout, uint32_t cp) { + if (cp == 0) return false; + for (int i = 0; i < layout.dead_count; i++) + if (layout.dead_keys[i] == cp) return true; + return false; +} + +// Keys that may be pressed between a dead key and its letter without +// cancelling it (Shift for a capital, AltGr, Caps Lock, ...). +inline constexpr bool is_modifier_scancode(uint8_t sc) { + return sc == 0x2A || sc == 0x36 || sc == 0x1D || sc == 0x38 || + sc == 0x3A || sc == 0x45 || sc == 0x46 || sc == 0x5B || sc == 0x5C; +} + +// Apply the active layout to a raw key event: the character it types goes to +// key->codepoint, its Windows-1252 byte (or KEY_ASCII_SUBSTITUTE) to +// key->ascii. Dead keys type nothing and modify the following character, so +// the state is updated on presses. +inline void translate(State& state, abi::KeyEvent* key) { if (!key) return; - if (state.active < 0 || state.active >= state.registry.count) return; - const Layout& layout = state.registry.items[state.active]; + const Layout* layout = (state.active >= 0 && state.active < state.registry.count) + ? &state.registry.items[state.active] : nullptr; + + uint8_t a = (uint8_t)key->ascii; + uint32_t cp = key->codepoint ? key->codepoint + : ((a >= 0x20 && a < 0x7F) ? a : 0); + uint8_t scancode = key->scancode & 0x7F; // Extended keys carry a main-block scancode with the E0 prefix stripped // (keypad "/" arrives as 0x35, the same as the main "/"), so translating // them would turn keypad "/" into whatever the layout puts on that key. - if (key->extended) return; + if (layout && !key->extended) { + for (int i = 0; i < layout->key_count; i++) { + const KeyMap& mapping = layout->keys[i]; + if (mapping.scancode != scancode) continue; - uint8_t scancode = key->scancode & 0x7F; - for (int i = 0; i < layout.key_count; i++) { - const KeyMap& mapping = layout.keys[i]; - if (mapping.scancode != scancode) continue; + uint32_t out; + if (key->altgr) { + out = mapping.altgr; + } else { + bool upper = key->shift; + if (is_letter_pair(mapping.base, mapping.shift)) + upper = key->shift != key->capslock; + out = upper ? mapping.shift : mapping.base; + } + if (out != 0) { + cp = out; + // An AltGr key that produced a character is text, not a + // shortcut. Apps gate insertion on !alt (and alt is + // LeftAlt||RightAlt), so leaving it set would silently swallow + // every AltGr character. + if (key->altgr) key->alt = false; + } + break; + } + } - uint8_t out; - if (key->altgr) { - out = mapping.altgr; - } else { - bool upper = key->shift; - if (is_letter_pair(mapping.base, mapping.shift)) - upper = key->shift != key->capslock; - out = upper ? mapping.shift : mapping.base; - } - if (out != 0) { - key->ascii = (char)out; - // An AltGr key that produced a character is text, not a shortcut. - // Apps gate insertion on !alt (and alt is LeftAlt||RightAlt), so - // leaving it set would silently swallow every AltGr character. - if (key->altgr) key->alt = false; + bool dead = layout && !key->extended && is_dead_key(*layout, cp); + bool shortcut = key->ctrl || (key->alt && !key->altgr); + if (dead && shortcut) dead = false; + + if (key->pressed && !shortcut) { + if (dead) { + if (state.pending_dead == cp) { + state.pending_dead = 0; // pressed twice: type the accent + dead = false; + } else { + state.pending_dead = cp; // wait for the next character + } + } else if (state.pending_dead) { + if (cp == ' ') { + cp = state.pending_dead; // accent + Space: the accent + state.pending_dead = 0; + } else if (cp) { + // The composed letter, or just the letter when the accent does + // not apply to it (one event can only carry one character). + uint32_t composed = compose(state.pending_dead, cp); + if (composed) cp = composed; + state.pending_dead = 0; + } else if (!is_modifier_scancode(scancode)) { + state.pending_dead = 0; // Enter, arrows, ... cancel it + } } + } + + if (dead) { + key->codepoint = 0; + key->ascii = 0; return; } + key->codepoint = cp; + if (cp != 0) { + uint8_t b = utf8::to_cp1252(cp); + key->ascii = b ? (char)b : abi::KEY_ASCII_SUBSTITUTE; + } } // ---- Direct keyboard readers ---- diff --git a/template/sysroot/include/montauk/statuscodes.h b/template/sysroot/include/montauk/statuscodes.h index 1185349..e91813a 100644 --- a/template/sysroot/include/montauk/statuscodes.h +++ b/template/sysroot/include/montauk/statuscodes.h @@ -6,29 +6,84 @@ #pragma once -// Userspace mirror of kernel/src/Common/StatusCodes.hpp. Also usable from C -// (the libc includes it), where the enumerators are unqualified. +// Userspace status codes. +// Analogous to kernel/src/Common/StatusCodes.hpp, but positive numbers are used. #ifdef __cplusplus namespace montauk { #endif -enum StatusCode { +typedef enum { Success = 0, - GenericFailure = -1, - PermissionDenied = -2, - CapabilityDenied = -3, - SystemIntegrityError = -4, - BadPointer = -5, - InvalidArgument = -6, - UnsupportedOp = -7, - NoDevice = -8, - IoFailure = -9, - BadInvocation = -10, - NoSuchPath = -11, - Busy = -12, - BufferTooSmall = -13, - OutOfMemory = -14 -}; + GenericFailure = 1, + PermissionDenied = 2, + CapabilityDenied = 3, + SystemIntegrityError = 4, + BadPointer = 5, + InvalidArgument = 6, + UnsupportedOp = 7, + NoDevice = 8, + IoFailure = 9, + BadInvocation = 10, + NoSuchPath = 11, + Busy = 12, + BufferTooSmall = 13, + OutOfMemory = 14 +} StatusCode; + +inline const char* GetStatusText(StatusCode statusCode) { + const char* statusText[] = { + "Success", // 0 + "Generic failure", // 1 + "Permission denied", // 2 + "Capability denied", // 3 + "System integrity error", // 4 + "Bad pointer", // 5 + "Invalid argument", // 6 + "Unsupported operation", // 7 + "No device", // 8 + "I/O failure", // 9 + "Bad invocation", // 10 + "No such path", // 11 + "Busy", // 12 + "Buffer too small", // 13 + "Out of memory", // 14 + }; + + if (statusCode > 0 && statusCode <= 14) { + return statusText[statusCode]; + } else { + return "Unknown error"; + } +} + +// Shared with C (libc.c), so no nullptr. +inline const char* GetStatusExplanationText(StatusCode statusCode) { + const char* explanationText[] = { + 0, // 0 + 0, // 1 + 0, // 2 + 0, // 3 + "The path is protected by the system and cannot be modified.", // 4 + 0, // 5 + 0, // 6 + 0, // 7 + 0, // 8 + 0, // 9 + 0, // 10 + 0, // 11 + 0, // 12 + "The buffer supplied by the caller is too small.", // 13 + 0, // 14 + }; + + if (statusCode > 0 && statusCode <= 14) { + if (explanationText[statusCode] != 0) { + return explanationText[statusCode]; + } + } + + return GetStatusText(statusCode); +} #ifdef __cplusplus } diff --git a/template/sysroot/include/montauk/syscall.h b/template/sysroot/include/montauk/syscall.h index 5c9c188..b2ac9a1 100644 --- a/template/sysroot/include/montauk/syscall.h +++ b/template/sysroot/include/montauk/syscall.h @@ -7,6 +7,7 @@ #pragma once #include #include +#include namespace montauk { @@ -222,7 +223,23 @@ namespace montauk { // Keyboard inline bool is_key_available() { return (bool)syscall0(montauk::abi::SYS_ISKEYAVAILABLE); } - inline void getkey(montauk::abi::KeyEvent* out) { syscall1(montauk::abi::SYS_GETKEY, (uint64_t)out); } + // Scancode to use when checking for navigation keys (arrows, Home/End, + // PgUp/PgDn, Insert/Delete). The keypad shares those scancodes with its + // digit and '.' keys, so a keypad key that types a character reports 0 + // here: numpad 4 is text, not Left. Compare against this, not .scancode. + inline uint8_t nav_scancode(const montauk::abi::KeyEvent& key) { + uint8_t sc = key.scancode; + if (!key.extended && (sc & 0x7F) >= 0x47 && (sc & 0x7F) <= 0x53 && + montauk::utf8::key_codepoint(key) != 0) + return 0; + return sc; + } + + // Fills the full event, including the Unicode codepoint the key types. + inline void getkey(montauk::abi::KeyEvent* out) { + syscall2(montauk::abi::SYS_GETKEY_EX, (uint64_t)out, sizeof(*out)); + } + // Text keys arrive as UTF-8, one byte per call. inline char getchar() { return (char)syscall0(montauk::abi::SYS_GETCHAR); } // Returns 0 rather than blocking when no character is pending. inline char getchar_nb() { return (char)syscall0(montauk::abi::SYS_GETCHAR_NB); } @@ -496,7 +513,8 @@ namespace montauk { return (int)syscall3(montauk::abi::SYS_CHILDIO_WRITE, (uint64_t)childPid, (uint64_t)data, (uint64_t)len); } inline int childio_writekey(int childPid, const montauk::abi::KeyEvent* key) { - return (int)syscall2(montauk::abi::SYS_CHILDIO_WRITEKEY, (uint64_t)childPid, (uint64_t)key); + return (int)syscall3(montauk::abi::SYS_CHILDIO_WRITEKEY_EX, (uint64_t)childPid, + (uint64_t)key, sizeof(*key)); } inline int childio_settermsz(int childPid, int cols, int rows) { return (int)syscall3(montauk::abi::SYS_CHILDIO_SETTERMSZ, (uint64_t)childPid, (uint64_t)cols, (uint64_t)rows); diff --git a/template/sysroot/include/montauk/user.h b/template/sysroot/include/montauk/user.h index efff1e0..855d0a7 100644 --- a/template/sysroot/include/montauk/user.h +++ b/template/sysroot/include/montauk/user.h @@ -9,6 +9,7 @@ #include #include #include +#include #include namespace montauk { @@ -107,7 +108,7 @@ namespace user { bytes_to_hex(hash, 32, out_hex64); } - inline bool verify_password(const char* password, const char* salt_hex, const char* stored_hex64) { + inline bool verify_password_bytes(const char* password, const char* salt_hex, const char* stored_hex64) { char computed[65]; hash_password(password, salt_hex, computed); @@ -118,6 +119,26 @@ namespace user { return diff == 0; } + // Passwords are hashed as UTF-8. Before the switch to UTF-8, password + // fields stored typed characters as Windows-1252 bytes, so a non-ASCII + // password set back then only matches its 1252 form; try that too. + inline bool verify_password(const char* password, const char* salt_hex, const char* stored_hex64) { + if (verify_password_bytes(password, salt_hex, stored_hex64)) return true; + + char legacy[256]; + int o = 0; + bool non_ascii = false; + for (const char* p = password; *p;) { + uint32_t cp = montauk::utf8::next(&p); + uint8_t b = montauk::utf8::to_cp1252(cp); + if (b == 0 || o >= (int)sizeof(legacy) - 1) return false; + if (b >= 0x80) non_ascii = true; + legacy[o++] = (char)b; + } + legacy[o] = '\0'; + return non_ascii && verify_password_bytes(legacy, salt_hex, stored_hex64); + } + // ---- User database I/O ---- inline int load_users(UserInfo* buf, int max) { diff --git a/template/sysroot/include/montauk/utf8.h b/template/sysroot/include/montauk/utf8.h new file mode 100644 index 0000000..dae0f33 --- /dev/null +++ b/template/sysroot/include/montauk/utf8.h @@ -0,0 +1,399 @@ +/* + * utf8.h + * UTF-8 text encoding helpers with a Windows-1252 fallback + * Copyright (c) 2026 Daniel Hammer + */ + +#pragma once + +#include + +// MontaukOS text is UTF-8. Before this it was single-byte Windows-1252, so +// older files (and anything else that is not valid UTF-8) still turn up. The +// decoder never fails: a byte that does not start a well-formed sequence is +// read as ONE Windows-1252 character. Valid UTF-8 and plain ASCII are +// unaffected, and legacy text keeps rendering exactly as it used to. +// +// Character boundaries follow the same rule, so cursor movement, deletion and +// truncation all agree with what the renderer draws. + +namespace montauk::utf8 { + +inline constexpr uint32_t REPLACEMENT = 0xFFFD; +inline constexpr int MAX_BYTES = 4; + +// Windows-1252 byte -> Unicode codepoint. 0x80-0x9F carry the typographic +// punctuation; every other byte is identical to Latin-1 / Unicode. +inline constexpr uint32_t from_cp1252(uint8_t b) { + switch (b) { + case 0x80: return 0x20AC; // Euro Sign + case 0x82: return 0x201A; // Single Low-9 Quotation Mark + case 0x83: return 0x0192; // Latin Small Letter F With Hook + case 0x84: return 0x201E; // Double Low-9 Quotation Mark + case 0x85: return 0x2026; // Horizontal Ellipsis + case 0x86: return 0x2020; // Dagger + case 0x87: return 0x2021; // Double Dagger + case 0x88: return 0x02C6; // Modifier Letter Circumflex Accent + case 0x89: return 0x2030; // Per Mille Sign + case 0x8A: return 0x0160; // Latin Capital Letter S With Caron + case 0x8B: return 0x2039; // Single Left-Pointing Angle Quotation Mark + case 0x8C: return 0x0152; // Latin Capital Ligature OE + case 0x8E: return 0x017D; // Latin Capital Letter Z With Caron + case 0x91: return 0x2018; // Left Single Quotation Mark + case 0x92: return 0x2019; // Right Single Quotation Mark + case 0x93: return 0x201C; // Left Double Quotation Mark + case 0x94: return 0x201D; // Right Double Quotation Mark + case 0x95: return 0x2022; // Bullet + case 0x96: return 0x2013; // En Dash + case 0x97: return 0x2014; // Em Dash + case 0x98: return 0x02DC; // Small Tilde + case 0x99: return 0x2122; // Trade Mark Sign + case 0x9A: return 0x0161; // Latin Small Letter S With Caron + case 0x9B: return 0x203A; // Single Right-Pointing Angle Quotation Mark + case 0x9C: return 0x0153; // Latin Small Ligature OE + case 0x9E: return 0x017E; // Latin Small Letter Z With Caron + case 0x9F: return 0x0178; // Latin Capital Letter Y With Diaeresis + default: return b; + } +} + +// Unicode codepoint -> Windows-1252 byte, or 0 if it has none. Used where a +// single byte is still required (PDF WinAnsi output, legacy byte tables). +inline constexpr uint8_t to_cp1252(uint32_t cp) { + if (cp < 0x80 || (cp >= 0xA0 && cp <= 0xFF)) return (uint8_t)cp; + for (int b = 0x80; b <= 0x9F; b++) { + uint32_t m = from_cp1252((uint8_t)b); + if (m != (uint32_t)b && m == cp) return (uint8_t)b; + } + return 0; +} + +// Length of the well-formed UTF-8 sequence starting at s (at most `avail` +// bytes, stopping early at a NUL), or 0 if it is not one. Rejects overlong +// forms, surrogates and values above U+10FFFF. +inline int sequence_length(const char* s, int avail, uint32_t* out_cp = nullptr) { + if (avail <= 0) return 0; + const uint8_t* u = (const uint8_t*)s; + uint8_t b0 = u[0]; + if (b0 < 0x80) { + if (out_cp) *out_cp = b0; + return 1; + } + + int n; + uint32_t cp, min; + if (b0 >= 0xC2 && b0 <= 0xDF) { n = 2; cp = b0 & 0x1F; min = 0x80; } + else if (b0 >= 0xE0 && b0 <= 0xEF) { n = 3; cp = b0 & 0x0F; min = 0x800; } + else if (b0 >= 0xF0 && b0 <= 0xF4) { n = 4; cp = b0 & 0x07; min = 0x10000; } + else return 0; + + if (n > avail) return 0; + for (int i = 1; i < n; i++) { + uint8_t c = u[i]; + if ((c & 0xC0) != 0x80) return 0; // also catches NUL + cp = (cp << 6) | (c & 0x3F); + } + if (cp < min || cp > 0x10FFFF || (cp >= 0xD800 && cp <= 0xDFFF)) return 0; + if (out_cp) *out_cp = cp; + return n; +} + +// Decode one character from a buffer of `avail` bytes. Returns the codepoint +// and stores the number of bytes consumed (always >= 1 when avail > 0). +inline uint32_t decode(const char* s, int avail, int* consumed) { + if (avail <= 0) { if (consumed) *consumed = 0; return 0; } + uint32_t cp; + int n = sequence_length(s, avail, &cp); + if (n == 0) { + n = 1; + cp = from_cp1252((uint8_t)s[0]); + } + if (consumed) *consumed = n; + return cp; +} + +// Decode one character from a NUL-terminated string and advance *p past it. +// Returns 0 (without advancing) at the terminator. +inline uint32_t next(const char** p) { + const char* s = *p; + if (!*s) return 0; + int n; + // A sequence never spans the terminator: sequence_length stops at NUL + // because NUL is not a continuation byte. + uint32_t cp = decode(s, MAX_BYTES, &n); + *p = s + n; + return cp; +} + +// Encode a codepoint as UTF-8 into out (room for 4 bytes, NOT terminated). +// Returns the byte count. Invalid codepoints encode U+FFFD. +inline int encode(uint32_t cp, char* out) { + if (cp > 0x10FFFF || (cp >= 0xD800 && cp <= 0xDFFF)) cp = REPLACEMENT; + uint8_t* o = (uint8_t*)out; + if (cp < 0x80) { o[0] = (uint8_t)cp; return 1; } + if (cp < 0x800) { + o[0] = (uint8_t)(0xC0 | (cp >> 6)); + o[1] = (uint8_t)(0x80 | (cp & 0x3F)); + return 2; + } + if (cp < 0x10000) { + o[0] = (uint8_t)(0xE0 | (cp >> 12)); + o[1] = (uint8_t)(0x80 | ((cp >> 6) & 0x3F)); + o[2] = (uint8_t)(0x80 | (cp & 0x3F)); + return 3; + } + o[0] = (uint8_t)(0xF0 | (cp >> 18)); + o[1] = (uint8_t)(0x80 | ((cp >> 12) & 0x3F)); + o[2] = (uint8_t)(0x80 | ((cp >> 6) & 0x3F)); + o[3] = (uint8_t)(0x80 | (cp & 0x3F)); + return 4; +} + +inline int encoded_length(uint32_t cp) { + if (cp > 0x10FFFF || (cp >= 0xD800 && cp <= 0xDFFF)) return 3; // U+FFFD + return cp < 0x80 ? 1 : cp < 0x800 ? 2 : cp < 0x10000 ? 3 : 4; +} + +// ==== Case mapping ==== +// Simple one-to-one case mapping for the scripts MontaukOS keyboard layouts +// cover: ASCII, Latin-1, Latin Extended-A, Greek and Cyrillic. Anything else +// is returned unchanged. + +inline constexpr uint32_t to_upper(uint32_t c) { + if (c >= 'a' && c <= 'z') return c - 0x20; + if (c < 0x80) return c; + if (c >= 0xE0 && c <= 0xFE && c != 0xF7) return c - 0x20; + if (c == 0xFF) return 0x178; + if (c == 0xB5) return 0x39C; // micro -> Mu + // Latin Extended-A: pairs alternate upper/lower, except the two ranges + // where the alignment shifts by one (L-stroke..N-apostrophe, Z-acute..). + if (c == 0x131) return 'I'; // dotless i + if (c >= 0x100 && c <= 0x137 && c != 0x130) return (c & 1) ? c - 1 : c; + if (c >= 0x139 && c <= 0x148) return (c & 1) ? c : c - 1; + if (c >= 0x14A && c <= 0x177) return (c & 1) ? c - 1 : c; + if (c >= 0x179 && c <= 0x17E) return (c & 1) ? c : c - 1; + if (c == 0x17F) return 'S'; // long s + // Greek + if (c >= 0x3B1 && c <= 0x3C9 && c != 0x3C2) return c - 0x20; + if (c == 0x3C2) return 0x3A3; // final sigma + if (c == 0x3AC) return 0x386; + if (c >= 0x3AD && c <= 0x3AF) return c - 0x25; + if (c == 0x3CC) return 0x38C; + if (c == 0x3CD || c == 0x3CE) return c - 0x3F; + // Cyrillic + if (c >= 0x430 && c <= 0x44F) return c - 0x20; + if (c >= 0x450 && c <= 0x45F) return c - 0x50; + return c; +} + +inline constexpr uint32_t to_lower(uint32_t c) { + if (c >= 'A' && c <= 'Z') return c + 0x20; + if (c < 0x80) return c; + if (c >= 0xC0 && c <= 0xDE && c != 0xD7) return c + 0x20; + if (c == 0x178) return 0xFF; + if (c == 0x130) return 'i'; // dotted I + if (c >= 0x100 && c <= 0x137) return (c & 1) ? c : c + 1; + if (c >= 0x139 && c <= 0x148) return (c & 1) ? c + 1 : c; + if (c >= 0x14A && c <= 0x177) return (c & 1) ? c : c + 1; + if (c >= 0x179 && c <= 0x17E) return (c & 1) ? c + 1 : c; + if (c >= 0x391 && c <= 0x3A9 && c != 0x3A2) return c + 0x20; + if (c == 0x386) return 0x3AC; + if (c >= 0x388 && c <= 0x38A) return c + 0x25; + if (c == 0x38C) return 0x3CC; + if (c == 0x38E || c == 0x38F) return c + 0x3F; + if (c >= 0x410 && c <= 0x42F) return c + 0x20; + if (c >= 0x400 && c <= 0x40F) return c + 0x50; + return c; +} + +// True if lower/upper are the two cases of one letter. +inline constexpr bool is_case_pair(uint32_t lower, uint32_t upper) { + return lower != upper && to_upper(lower) == upper && to_lower(upper) == lower; +} + +// Text a key event types, as a codepoint (0 for control/non-text keys). +// KeyEvent::codepoint is filled by the kernel and by layout translation; +// events built by hand may leave it 0, so fall back to `ascii` (a +// Windows-1252 byte). +template +inline uint32_t key_codepoint(const Key& key) { + if (key.codepoint) { + uint32_t cp = key.codepoint; + return (cp < 0x20 || cp == 0x7F || (cp >= 0x80 && cp < 0xA0)) ? 0 : cp; + } + uint8_t b = (uint8_t)key.ascii; + if (b < 0x20 || b == 0x7F) return 0; + return from_cp1252(b); +} + +// Same, encoded as UTF-8 into out (4 bytes). Returns the length, 0 if none. +template +inline int key_utf8(const Key& key, char* out) { + uint32_t cp = key_codepoint(key); + return cp ? encode(cp, out) : 0; +} + +// Byte offset of the character after the one at `pos` (len = buffer length). +inline int next_boundary(const char* s, int len, int pos) { + if (pos >= len) return len; + if (pos < 0) return 0; + int n; + decode(s + pos, len - pos, &n); + return pos + n; +} + +// Byte offset of the character before `pos`. A run of continuation bytes is +// one character only if it completes a well-formed sequence ending exactly at +// pos; otherwise the previous byte stands alone (Windows-1252 fallback). +inline int prev_boundary(const char* s, int pos) { + if (pos <= 0) return 0; + for (int back = 2; back <= MAX_BYTES && back <= pos; back++) { + if (((uint8_t)s[pos - back + 1] & 0xC0) != 0x80) break; + int start = pos - back; + if (sequence_length(s + start, back) == back) return start; + } + return pos - 1; +} + +// Snap `pos` back onto a character boundary. Use before truncating a buffer +// or splitting at an arbitrary byte offset. +inline int floor_boundary(const char* s, int len, int pos) { + if (pos <= 0) return 0; + if (pos >= len) return len; + if (((uint8_t)s[pos] & 0xC0) != 0x80) return pos; + // pos is a continuation byte: it is inside a character only if a + // well-formed sequence starting up to 3 bytes earlier covers it. + for (int back = 1; back < MAX_BYTES && back <= pos; back++) { + int start = pos - back; + int n = sequence_length(s + start, len - start); + if (n > back) return start; + if (((uint8_t)s[start] & 0xC0) != 0x80) break; + } + return pos; +} + +// Number of characters in a NUL-terminated string. +inline int count(const char* s) { + int n = 0; + while (*s) { next(&s); n++; } + return n; +} + +// Number of characters in the first `len` bytes. +inline int count(const char* s, int len) { + int n = 0, pos = 0; + while (pos < len) { pos = next_boundary(s, len, pos); n++; } + return n; +} + +// Byte offset of the `index`th character (clamped to len). +inline int offset_of(const char* s, int len, int index) { + int pos = 0; + while (index-- > 0 && pos < len) pos = next_boundary(s, len, pos); + return pos; +} + +// True if the buffer is entirely well-formed UTF-8. +inline bool valid(const char* s, int len) { + for (int pos = 0; pos < len;) { + int n = sequence_length(s + pos, len - pos); + if (n == 0) return false; + pos += n; + } + return true; +} + +// Rewrite a buffer as well-formed UTF-8 (each stray byte becomes the +// character the Windows-1252 fallback would display). Returns the output +// length, truncated on a character boundary to fit cap - 1, NUL-terminated. +inline int normalize(const char* in, int len, char* out, int cap) { + if (cap <= 0) return 0; + int o = 0; + for (int pos = 0; pos < len;) { + int n; + uint32_t cp = decode(in + pos, len - pos, &n); + int need = encoded_length(cp); + if (o + need > cap - 1) break; + o += encode(cp, out + o); + pos += n; + } + out[o] = '\0'; + return o; +} + +// Copy src into dst (cap bytes incl. NUL) without splitting a character. +inline int copy(char* dst, int cap, const char* src) { + if (cap <= 0) return 0; + int len = 0; + while (src[len]) len++; + int n = len < cap - 1 ? len : floor_boundary(src, len, cap - 1); + for (int i = 0; i < n; i++) dst[i] = src[i]; + dst[n] = '\0'; + return n; +} + +// ==== Editing a NUL-terminated buffer with a byte cursor ==== +// `len` is the current length, `cap` the buffer size including the NUL. The +// cursor is a byte offset that is always kept on a character boundary. + +// Insert n bytes at *cursor. Returns false (buffer unchanged) if they don't fit. +inline bool insert(char* buf, int* len, int cap, int* cursor, + const char* s, int n) { + if (n <= 0 || *len + n >= cap) return false; + int at = *cursor < 0 ? 0 : (*cursor > *len ? *len : *cursor); + for (int i = *len; i >= at; i--) buf[i + n] = buf[i]; // moves the NUL + for (int i = 0; i < n; i++) buf[at + i] = s[i]; + *len += n; + *cursor = at + n; + return true; +} + +// Insert the text a key event types. Returns false if it types nothing or +// does not fit. +template +inline bool insert_key(char* buf, int* len, int cap, int* cursor, const Key& key) { + char t[MAX_BYTES]; + int n = key_utf8(key, t); + return n > 0 && insert(buf, len, cap, cursor, t, n); +} + +// Remove the bytes [start, end). +inline void erase(char* buf, int* len, int start, int end) { + if (start < 0) start = 0; + if (end > *len) end = *len; + if (start >= end) return; + int n = end - start; + for (int i = start; i + n <= *len; i++) buf[i] = buf[i + n]; // moves the NUL + *len -= n; +} + +// Backspace: delete the character before the cursor. +inline bool erase_before(char* buf, int* len, int* cursor) { + if (*cursor <= 0) return false; + int start = prev_boundary(buf, *cursor); + erase(buf, len, start, *cursor); + *cursor = start; + return true; +} + +// Delete: remove the character at the cursor. +inline bool erase_at(char* buf, int* len, int cursor) { + if (cursor >= *len) return false; + erase(buf, len, cursor, next_boundary(buf, *len, cursor)); + return true; +} + +// Append typed text at the end (simple line inputs without a cursor). +template +inline bool append_key(char* buf, int* len, int cap, const Key& key) { + int cursor = *len; + return insert_key(buf, len, cap, &cursor, key); +} + +// Backspace for append-only inputs: drop the last character. +inline bool erase_last(char* buf, int* len) { + int cursor = *len; + return erase_before(buf, len, &cursor); +} + +} // namespace montauk::utf8 diff --git a/template/sysroot/include/rtlsdr/rtlsdr.h b/template/sysroot/include/rtlsdr/rtlsdr.h deleted file mode 100644 index bebc465..0000000 --- a/template/sysroot/include/rtlsdr/rtlsdr.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include -#ifdef __cplusplus -extern "C" { -#endif -typedef struct rtlsdr_device rtlsdr_device; -typedef struct rtlsdr_device_info { - char name[64]; - char tuner[32]; - char serial[32]; - uint64_t freq_min; - uint64_t freq_max; - uint32_t sample_rate_min; - uint32_t sample_rate_max; - uint32_t num_gains; - int32_t gains[32]; -} rtlsdr_device_info; -int rtlsdr_count(void); -int rtlsdr_get_device_info(int index, rtlsdr_device_info* out); -int rtlsdr_open(rtlsdr_device** out, int index); -int rtlsdr_close(rtlsdr_device* dev); -int rtlsdr_set_center_freq(rtlsdr_device* dev, uint64_t hz); -uint64_t rtlsdr_get_center_freq(const rtlsdr_device* dev); -int rtlsdr_set_sample_rate(rtlsdr_device* dev, uint32_t hz); -uint32_t rtlsdr_get_sample_rate(const rtlsdr_device* dev); -int rtlsdr_set_tuner_gain_mode(rtlsdr_device* dev, int manual); -int rtlsdr_set_tuner_gain(rtlsdr_device* dev, int tenths_db); -int rtlsdr_set_freq_correction(rtlsdr_device* dev, int ppm); -int rtlsdr_set_agc_mode(rtlsdr_device* dev, int on); -int rtlsdr_set_direct_sampling(rtlsdr_device* dev, int mode); -int rtlsdr_start(rtlsdr_device* dev); -int rtlsdr_stop(rtlsdr_device* dev); -int rtlsdr_read(rtlsdr_device* dev, void* data, uint32_t length); -#ifdef __cplusplus -} -#endif diff --git a/template/sysroot/lib/libjpeg.a b/template/sysroot/lib/libjpeg.a index 1b4f7280fb0460cd8f05a383520230f7d941ba3d..df67214a1fc9117f69634ec5cc2f1fa58c0ea23b 100644 GIT binary patch delta 55 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�!3xPso@Dqjse^IQ?82lv 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 z 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