FABRIC.md items 4.4v/4.4r/4.4ab: keyboard bridge, and simplify to a
full-screen vt100 terminal 4.4v -- keyboard-to-REPL bridge, real and tested: Refactored KEY-EVENT's per-arch translation logic (keyboard_words.c) into a shared C function, sk_key_event_poll(), so the REPL bridge reuses item 4.3.5f's already-converged Linux-keycode-namespace event stream instead of building separate amd64/aarch64/riscv64 tables. repl.c's sk_kbd_getc() decodes the standard US-QWERTY printable range plus Enter/Backspace/Shift against that stream; sk_readline() polls it as a second source alongside console_getc(). Verified via QEMU monitor sendkey injection, and by Captain Bob typing directly into the live QEMU window over real emulated PS/2 hardware mid-session (1 1 + . -> 2 ok, then a clean BYE shutdown). 4.4ab -- simplify to a full-screen terminal: Captain Bob's call, reverting the 640x480 CANVAS box + independent REPL strip (4.4o/4.4t/4.4x/4.4z) in favor of the simplest shape: the entire framebuffer is one vt100 terminal, g_vt.cols/rows = fb_width()/fb_height() divided by cell size, no origin offset, no box, no strip, no border drawing. The REPL prompt is just the terminal's last scrolling line. Scrollback, TTF rendering, and SGR color are all box-agnostic and keep working unmodified. 4.4r -- reframed as a text/graphics mode toggle: "Hide/show the scroll box" stopped meaning anything once the box was removed; the underlying need survives as a whole-screen mode switch. vt100_toggle_graphics() is a two-state machine (VISIBLE/HIDDEN) -- hidden mode stops the terminal from touching the framebuffer while its logical state keeps advancing, so direct framebuffer/TTF-TEXT drawing can use the whole screen; showing again wipes and reuses scrollback_redraw() to restore the terminal exactly. Reachable two ways, one transition function: physically via Alt+TAB (4.4y revised from Ctrl+TAB) and programmatically via the new ALT+TAB FORTH word. Verified: three-arch clean QEMU boot + logs; amd64 screendump confirms full-width text with no box/strip artifacts. Punch list §25 items 4.4v/4.4r/4.4ab complete; 4.4y revised. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
b21aa50a14
commit
af20efaa15
+98
-70
@@ -34,6 +34,7 @@
|
||||
#include "version.h"
|
||||
#include "starkernel/timer.h"
|
||||
#include "starkernel/arch.h"
|
||||
#include "word_source/include/keyboard_words.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -45,71 +46,6 @@
|
||||
|
||||
const char lithos_version[64] = LITHOS_VERSION_STR;
|
||||
|
||||
/*===========================================================================
|
||||
* FABRIC.md items 4.4u/4.4w/4.4x: the bottom REPL strip -- a plain-text
|
||||
* (no ANSI/SGR) mirror of "[VMName] ok> <input so far>", refreshed into
|
||||
* console_fb_strip_draw() on every keystroke. Built separately from
|
||||
* SK_PROMPT_TEXT rather than derived from it, since the strip renders in
|
||||
* one fixed color (4.4u) and has no SGR parser of its own -- the ANSI
|
||||
* version keeps going to console_puts() exactly as before, unaffected,
|
||||
* for serial and for the scrollback box's own history.
|
||||
*===========================================================================*/
|
||||
|
||||
#define SK_STRIP_PROMPT_MAX 80u
|
||||
|
||||
static char g_strip_prompt[SK_STRIP_PROMPT_MAX] = "ok> ";
|
||||
|
||||
/* Builds "[VMName] ok> " or "[VMName] zuse)ok> " (no VM name -> just the
|
||||
* suffix) into g_strip_prompt, bounded, no strcat -- mirrors emit_prefix()'s
|
||||
* bracket format (console.c) so the strip and the box agree on what a
|
||||
* prompt looks like, minus the ANSI color codes the strip doesn't use. */
|
||||
static void set_strip_prompt(VM *vm)
|
||||
{
|
||||
const char *vn = console_get_vm_name();
|
||||
char *p = g_strip_prompt;
|
||||
size_t room = sizeof(g_strip_prompt) - 1u;
|
||||
size_t n;
|
||||
const char *suffix;
|
||||
size_t used, left, sn;
|
||||
|
||||
if (vn && vn[0]) {
|
||||
n = strlen(vn);
|
||||
if (n > room) n = room;
|
||||
*p++ = '[';
|
||||
memcpy(p, vn, n);
|
||||
p += n;
|
||||
*p++ = ']';
|
||||
*p++ = ' ';
|
||||
}
|
||||
|
||||
suffix = (vm && vm->zuse_session) ? "zuse)ok> " : "ok> ";
|
||||
used = (size_t)(p - g_strip_prompt);
|
||||
left = (used < room) ? (room - used) : 0u;
|
||||
sn = strlen(suffix);
|
||||
if (sn > left) sn = left;
|
||||
memcpy(p, suffix, sn);
|
||||
p += sn;
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
/* Concatenates g_strip_prompt + input_so_far (bounded, no strcat) and
|
||||
* hands the result to the strip renderer. Called once with an empty
|
||||
* input_so_far right after set_strip_prompt(), then again on every
|
||||
* keystroke from sk_readline() below. */
|
||||
static void strip_refresh(const char *input_so_far)
|
||||
{
|
||||
char combined[INPUT_BUFFER_SIZE + SK_STRIP_PROMPT_MAX];
|
||||
size_t plen = strlen(g_strip_prompt);
|
||||
size_t ilen = strlen(input_so_far);
|
||||
|
||||
if (plen >= sizeof(combined)) plen = sizeof(combined) - 1u;
|
||||
memcpy(combined, g_strip_prompt, plen);
|
||||
if (plen + ilen >= sizeof(combined)) ilen = sizeof(combined) - 1u - plen;
|
||||
memcpy(combined + plen, input_so_far, ilen);
|
||||
combined[plen + ilen] = '\0';
|
||||
|
||||
console_fb_strip_draw(combined);
|
||||
}
|
||||
|
||||
/*===========================================================================
|
||||
* USE-word dispatch: which VM receives REPL input.
|
||||
@@ -144,6 +80,102 @@ static void sk_repl_idle(void)
|
||||
(void)0;
|
||||
}
|
||||
|
||||
/*===========================================================================
|
||||
* FABRIC.md item 4.4v: keyboard-to-REPL bridge.
|
||||
*
|
||||
* Translates sk_key_event_poll()'s converged Linux-keycode-namespace
|
||||
* stream (keyboard_words.c -- one implementation shared with KEY-EVENT,
|
||||
* live-verified on all three architectures per item 4.3.5f) into the same
|
||||
* byte stream sk_readline() already reads from console_getc(): -1 for
|
||||
* "nothing ready", else a raw ASCII byte with '\n'/0x7F meaning the same
|
||||
* thing they mean for the serial path below.
|
||||
*
|
||||
* Table covers exactly the keys a line editor needs -- letters, digits,
|
||||
* the standard US-QWERTY punctuation row, space, enter, backspace, tab
|
||||
* (for the Ctrl+TAB toggle interception, 4.4y/4.4u step 8) -- not full
|
||||
* keyboard coverage. Keycodes are Linux input-event-codes.h values,
|
||||
* confirmed against this build host's own header, not guessed (§25.0
|
||||
* rule 4). Index 0 means "no mapping"; arrows/F-keys/etc. fall through
|
||||
* unmapped and are silently dropped, consistent with this REPL's
|
||||
* append/backspace-only editing model (4.4u: no mid-line cursor
|
||||
* movement).
|
||||
*===========================================================================*/
|
||||
|
||||
#define SK_KBD_TABLE_SIZE 98u /* highest keycode used below is KEY_RIGHTCTRL=97 */
|
||||
|
||||
static const char sk_kbd_unshifted[SK_KBD_TABLE_SIZE] = {
|
||||
[2]='1',[3]='2',[4]='3',[5]='4',[6]='5',[7]='6',[8]='7',[9]='8',[10]='9',[11]='0',
|
||||
[12]='-',[13]='=',
|
||||
[16]='q',[17]='w',[18]='e',[19]='r',[20]='t',[21]='y',[22]='u',[23]='i',[24]='o',[25]='p',
|
||||
[26]='[',[27]=']',
|
||||
[30]='a',[31]='s',[32]='d',[33]='f',[34]='g',[35]='h',[36]='j',[37]='k',[38]='l',
|
||||
[39]=';',[40]='\'',[41]='`',[43]='\\',
|
||||
[44]='z',[45]='x',[46]='c',[47]='v',[48]='b',[49]='n',[50]='m',
|
||||
[51]=',',[52]='.',[53]='/',
|
||||
[57]=' ',
|
||||
};
|
||||
|
||||
static const char sk_kbd_shifted[SK_KBD_TABLE_SIZE] = {
|
||||
[2]='!',[3]='@',[4]='#',[5]='$',[6]='%',[7]='^',[8]='&',[9]='*',[10]='(',[11]=')',
|
||||
[12]='_',[13]='+',
|
||||
[16]='Q',[17]='W',[18]='E',[19]='R',[20]='T',[21]='Y',[22]='U',[23]='I',[24]='O',[25]='P',
|
||||
[26]='{',[27]='}',
|
||||
[30]='A',[31]='S',[32]='D',[33]='F',[34]='G',[35]='H',[36]='J',[37]='K',[38]='L',
|
||||
[39]=':',[40]='"',[41]='~',[43]='|',
|
||||
[44]='Z',[45]='X',[46]='C',[47]='V',[48]='B',[49]='N',[50]='M',
|
||||
[51]='<',[52]='>',[53]='?',
|
||||
[57]=' ',
|
||||
};
|
||||
|
||||
#define SK_KEY_BACKSPACE 14u
|
||||
#define SK_KEY_TAB 15u
|
||||
#define SK_KEY_ENTER 28u
|
||||
#define SK_KEY_LEFTSHIFT 42u
|
||||
#define SK_KEY_RIGHTSHIFT 54u
|
||||
#define SK_KEY_LEFTALT 56u
|
||||
#define SK_KEY_RIGHTALT 100u
|
||||
|
||||
static int g_kbd_shift_down; /* zero-initialized (BSS) */
|
||||
static int g_kbd_alt_down;
|
||||
|
||||
/* Drains and translates one physically-typed key. Modifier state persists
|
||||
* across calls (a real keyboard's shift/alt state is global, not
|
||||
* per-line). Alt+TAB is intercepted here and drives the graphics/text
|
||||
* toggle directly (console_fb_toggle_graphics(), the same state-machine
|
||||
* transition the ALT+TAB FORTH word calls) -- never reaches the line
|
||||
* buffer as a character either way. */
|
||||
static int sk_kbd_getc(void)
|
||||
{
|
||||
uint16_t keycode;
|
||||
int pressed;
|
||||
|
||||
while (sk_key_event_poll(&keycode, &pressed)) {
|
||||
if (keycode == SK_KEY_LEFTSHIFT || keycode == SK_KEY_RIGHTSHIFT) {
|
||||
g_kbd_shift_down = pressed;
|
||||
continue;
|
||||
}
|
||||
if (keycode == SK_KEY_LEFTALT || keycode == SK_KEY_RIGHTALT) {
|
||||
g_kbd_alt_down = pressed;
|
||||
continue;
|
||||
}
|
||||
if (!pressed) continue; /* only act on press/repeat */
|
||||
|
||||
if (keycode == SK_KEY_TAB) {
|
||||
if (g_kbd_alt_down) console_fb_toggle_graphics();
|
||||
continue; /* bare TAB: not mapped, same as arrows/F-keys */
|
||||
}
|
||||
if (keycode == SK_KEY_ENTER) return '\n';
|
||||
if (keycode == SK_KEY_BACKSPACE) return 0x7F;
|
||||
|
||||
if (keycode < SK_KBD_TABLE_SIZE) {
|
||||
char c = g_kbd_shift_down ? sk_kbd_shifted[keycode] : sk_kbd_unshifted[keycode];
|
||||
if (c) return (unsigned char)c;
|
||||
}
|
||||
/* unmapped keycode -- drop and keep draining */
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*===========================================================================
|
||||
* sk_readline - line read from serial console with echo
|
||||
*
|
||||
@@ -158,10 +190,10 @@ static int sk_readline(char *buf, int size)
|
||||
int n = 0;
|
||||
|
||||
buf[0] = '\0';
|
||||
strip_refresh(buf); /* FABRIC.md 4.4x: show the bare prompt before any input */
|
||||
|
||||
for (;;) {
|
||||
int c = console_getc(); /* non-blocking poll */
|
||||
if (c < 0) c = sk_kbd_getc(); /* FABRIC.md 4.4v: second source, same buffer */
|
||||
|
||||
if (c < 0) {
|
||||
/* Service the heartbeat bottom half every idle iteration, not
|
||||
@@ -203,7 +235,6 @@ static int sk_readline(char *buf, int size)
|
||||
console_putc('\b');
|
||||
console_putc(' ');
|
||||
console_putc('\b');
|
||||
strip_refresh(buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -213,7 +244,6 @@ static int sk_readline(char *buf, int size)
|
||||
buf[n++] = (char)c;
|
||||
buf[n] = '\0';
|
||||
console_putc((char)c); /* echo */
|
||||
strip_refresh(buf);
|
||||
}
|
||||
|
||||
buf[n] = '\0';
|
||||
@@ -268,7 +298,6 @@ int sk_repl_step(VM *vm)
|
||||
int is_hera = (!vn || (vn[0]=='H' && vn[1]=='e' && vn[2]=='r' && vn[3]=='a' && vn[4]=='\0'));
|
||||
vm->emergency_console = is_hera ? (vm->zuse_session ? 0 : 1) : 0;
|
||||
console_puts(SK_PROMPT_TEXT);
|
||||
set_strip_prompt(vm); /* FABRIC.md 4.4x: bottom strip mirrors the same prompt */
|
||||
}
|
||||
|
||||
sk_readline(input, sizeof(input));
|
||||
@@ -316,7 +345,6 @@ void sk_repl_run(VM *vm)
|
||||
int is_hera = (!vn || (vn[0]=='H' && vn[1]=='e' && vn[2]=='r' && vn[3]=='a' && vn[4]=='\0'));
|
||||
active->emergency_console = is_hera ? (active->zuse_session ? 0 : 1) : 0;
|
||||
console_puts(SK_PROMPT_TEXT);
|
||||
set_strip_prompt(active); /* FABRIC.md 4.4x: bottom strip mirrors the same prompt */
|
||||
}
|
||||
|
||||
sk_readline(input, sizeof(input));
|
||||
|
||||
Reference in New Issue
Block a user