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
@@ -5787,7 +5787,7 @@ document and committing that amendment as its own item.*
|
||||
> (`logs/20260811-225514/aarch64/`), riscv64 (`logs/20260811-225903/riscv64/`) — `Failed: 0`
|
||||
> all three.
|
||||
|
||||
- [ ] **4.4r — Toggle word: hide/show the scroll box.** A FORTH word that hides the 640×480
|
||||
- [x] **4.4r — Toggle word: hide/show the scroll box.** A FORTH word that hides the 640×480
|
||||
scroll box, revealing the rest of CANVAS beneath it for drawing; showing it again restores
|
||||
the scroll-box content undisturbed, no scrollback loss. Depends on 4.4o/4.4p (geometry),
|
||||
4.4q (scrollback), 4.4t (confinement — the box must be real before it can be hidden), 4.4v
|
||||
@@ -5798,6 +5798,19 @@ document and committing that amendment as its own item.*
|
||||
three-arch QEMU boot + logs per CLAUDE.md.
|
||||
*Refs:* §27.8.
|
||||
|
||||
> **REFRAMED AND DONE 2026-08-12, by 4.4ab.** "Hide/show the scroll box" stopped meaning
|
||||
> anything once 4.4ab removed the box — there is only the full-screen terminal now. The
|
||||
> underlying need survives in a more general shape: a text/graphics mode switch for the
|
||||
> *whole screen*, which is what got built. `vt100_toggle_graphics()` (`vt100.c`) is a
|
||||
> two-state machine (VISIBLE/HIDDEN) — hiding stops every terminal draw call from touching
|
||||
> the framebuffer (logical state, cursor, and scrollback keep advancing normally so nothing
|
||||
> is lost), showing again wipes whatever graphics drew and reuses the existing
|
||||
> `scrollback_redraw()` to repaint the terminal's current content exactly, restored rather
|
||||
> than merely redrawn from a stale snapshot. Reachable two ways, both driving the same
|
||||
> single transition function: physically via Alt+TAB (`repl.c`'s `sk_kbd_getc()`) and
|
||||
> programmatically via the new `ALT+TAB` FORTH word (`keyboard_words.c`) — the "toggle word"
|
||||
> this item originally asked for, just not scoped to a box anymore.
|
||||
|
||||
- [ ] **4.4s — `(user)` prompt segment — scoped, blocked, not started.** Extends 4.4's prompt
|
||||
to `[VM name] (user) ok>`, e.g. `[Hera] (zuse) ok>`. **Blocked:** `zuse_session`
|
||||
(`include/vm.h:393`) is a boolean only — no username/identity string exists anywhere in the
|
||||
@@ -5892,7 +5905,7 @@ document and committing that amendment as its own item.*
|
||||
> verified against real `TTF-TEXT` rendering, per the note directly above; 4.4x/4.4z carry
|
||||
> that verification forward as their own done-when, not re-litigated here.
|
||||
|
||||
- [ ] **4.4v — M8 scope, precisely bounded: keyboard-to-REPL bridge.** Surfaced while
|
||||
- [x] **4.4v — M8 scope, precisely bounded: keyboard-to-REPL bridge.** Surfaced while
|
||||
discussing 4.4u's TAB-toggle binding — Captain Bob's recollection was that keyboard input
|
||||
already works end-to-end; checked against the code rather than assumed either way.
|
||||
**What's real and already done** (confirmed by reading the code, not from milestone
|
||||
@@ -5928,6 +5941,21 @@ document and committing that amendment as its own item.*
|
||||
CLAUDE.md.
|
||||
*Refs:* §27.8, 4.3.5 series, 4.4r, 4.4u, `docs/lithosananke/ROADMAP.md` M8 section.
|
||||
|
||||
> **DONE 2026-08-12.** Reused item 4.3.5f's `KEY-EVENT` convergence work rather than building
|
||||
> two per-arch tables from scratch (`kbw_key_event`'s FORTH-word logic was refactored into a
|
||||
> new shared C function, `sk_key_event_poll()`, exported from `keyboard_words.c` — same
|
||||
> single-implementation discipline as everywhere else in this codebase) — one keycode-to-ASCII
|
||||
> translation table (Linux input-event-codes.h namespace, confirmed against this build host's
|
||||
> own header, not guessed) covers all three architectures instead of amd64 needing a separate
|
||||
> XT-scancode table. `sk_kbd_getc()` (`repl.c`) tracks shift state, decodes the standard
|
||||
> US-QWERTY printable range plus Enter/Backspace, and `sk_readline()` polls it as a second
|
||||
> source alongside `console_getc()` exactly as scoped. Verified two ways: QEMU monitor
|
||||
> `sendkey` injection, and — better evidence than planned for — Captain Bob typing directly
|
||||
> into the live QEMU window over real emulated PS/2 hardware, producing `1 1 + .` → `2 ok`
|
||||
> and a clean `BYE` shutdown, confirmed by him mid-session. Superseded detail: the original
|
||||
> done-when named "landed in the REPL strip" — the strip itself was later reverted (4.4ab);
|
||||
> this item's actual keyboard-bridge substance is unaffected by that reversion.
|
||||
|
||||
- [x] **4.4w — Pin 4.4u's open numbers with Bob.** Design-only, no code. Three specific values
|
||||
4.4u left as working/placeholder, not final: (1) exact gray RGB for the two REPL-strip
|
||||
border lines — 4.4u only says "a mid-gray, not chosen"; (2) the REPL input-line's character
|
||||
@@ -6027,6 +6055,15 @@ document and committing that amendment as its own item.*
|
||||
|
||||
> **DECIDED 2026-08-12 — Ctrl+TAB.** Chosen by Captain Bob directly. 4.4v's interception
|
||||
> code intercepts this specific combination, not bare TAB.
|
||||
>
|
||||
> **REVISED 2026-08-12, same session — Alt+TAB.** Captain Bob changed the choice while 4.4v
|
||||
> was being built, once the toggle's actual purpose was reframed by 4.4ab from "hide/show
|
||||
> the scroll box" to "switch the whole screen between text and graphics mode" — Alt+TAB
|
||||
> reads more naturally for a mode switch than Ctrl+TAB does. `repl.c`'s interception
|
||||
> (`SK_KEY_LEFTALT`=56/`SK_KEY_RIGHTALT`=100, Linux input-event-codes.h, confirmed not
|
||||
> guessed) was updated to match before this item's own done-when was ever exercised, so there
|
||||
> was no built-then-discarded Ctrl+TAB code path — only the design note above was briefly
|
||||
> wrong.
|
||||
|
||||
- [x] **4.4z — Draw the scroll box's visible border.** 4.4t confined REPL text to the 640×480
|
||||
box's coordinate space but never stroked a visible rectangle outline on it — the box's edges
|
||||
@@ -6051,6 +6088,32 @@ document and committing that amendment as its own item.*
|
||||
> (`logs/screendump-4.4z/amd64-border.png`) shows a full rectangle outline around the box,
|
||||
> visually distinct from the strip below it.
|
||||
|
||||
- [x] **4.4ab — Simplify: the whole framebuffer is one full-screen vt100 terminal; drop the
|
||||
CANVAS box and REPL strip.** Reverted 2026-08-12, Captain Bob's explicit call: "let's just
|
||||
rather simplify things and make the entire framebuffer a vt100 terminal. That'll be much
|
||||
easier." **Supersedes the box/strip mechanism 4.4o/4.4t/4.4x/4.4z built** — those items stay
|
||||
checked as historical record of what was built and why, not edited in place, per this
|
||||
document's own discipline. The 640×480 centered box (4.4o), its text confinement (4.4t),
|
||||
the split into an independent bottom strip plus derived box geometry (4.4x), and the box's
|
||||
drawn border (4.4z) are all removed in favor of the simplest possible shape: `g_vt.cols`/
|
||||
`g_vt.rows` are `fb_width()/cell_w()` and `fb_height()/cell_h()` — the full screen, no
|
||||
origin offset, no separate strip render path. The REPL prompt is just the terminal's last
|
||||
scrolling line, exactly like any ordinary terminal.
|
||||
**What this keeps, unaffected:** scrollback (4.4q), TTF rendering (4.4j), SGR/ANSI color
|
||||
(4.4h/4.4k), and the keyboard bridge (4.4v, see below) — none of those are box-specific,
|
||||
and all continue to work against the full-screen grid without modification beyond
|
||||
`px_of()`/`py_of()` dropping their now-zero origin offset.
|
||||
*Done when:* three-arch QEMU boot + logs clean; amd64 screendump shows REPL text spanning
|
||||
the full screen width with no box/strip artifacts.
|
||||
*Refs:* §27.8, 4.4o, 4.4t, 4.4x, 4.4z.
|
||||
|
||||
> **DONE 2026-08-12.** Three-arch QEMU boot + logs clean (`logs/20260812-153337/amd64`,
|
||||
> `logs/20260812-153423/aarch64`, `logs/20260812-153532/riscv64`). amd64 screendump
|
||||
> (`logs/screendump-fullscreen/amd64-fullscreen.png`) — taken after Captain Bob typed
|
||||
> directly into the QEMU window over real emulated PS/2 hardware (`: STAR 42 EMIT ;` /
|
||||
> `: MARGIN 30 SPACES CR ;`, both echoed correctly including shift-key punctuation) —
|
||||
> confirms full-width text with no box confinement, no strip, no border artifacts.
|
||||
|
||||
- [ ] **4.5 — URGENT, flagged by Captain Bob 2026-08-11: the kernel build has never used any
|
||||
compiler optimization.** **Blocking priority, set by Captain Bob 2026-08-11: no other
|
||||
punch-list item is worked until 4.5a–4.5f are done**, ahead of whatever would otherwise
|
||||
|
||||
@@ -91,12 +91,12 @@ void console_fb_scroll_back(uint32_t n);
|
||||
void console_fb_scroll_fwd(uint32_t n);
|
||||
|
||||
/**
|
||||
* FABRIC.md items 4.4u/4.4w/4.4x: thin wrapper over vt100_strip_draw() --
|
||||
* see that function's doc comment for the full contract (the REPL
|
||||
* prompt/input strip, independent of the scrollback box). No-op if the
|
||||
* framebuffer console was never initialized.
|
||||
* FABRIC.md item 4.4y-revised: thin wrapper over vt100_toggle_graphics()
|
||||
* -- see that function's doc comment for the full contract (the
|
||||
* Alt+TAB graphics/text state machine). No-op if the framebuffer console
|
||||
* was never initialized.
|
||||
*/
|
||||
void console_fb_strip_draw(const char *text);
|
||||
void console_fb_toggle_graphics(void);
|
||||
|
||||
/**
|
||||
* Write a single character to serial console
|
||||
|
||||
@@ -101,16 +101,14 @@ void vt100_putc(char c);
|
||||
void vt100_puts(const char *s);
|
||||
|
||||
/**
|
||||
* FABRIC.md items 4.4u/4.4w/4.4x: draw the REPL prompt/input strip -- a
|
||||
* single-line region pinned to the bottom of the screen, independent of
|
||||
* the scrollback box and its grid/cursor. @p text is the full line to
|
||||
* show (prompt plus whatever has been typed so far), plain text with no
|
||||
* ANSI/SGR codes -- the strip renders everything in one fixed color
|
||||
* (bright white on black, 4.4u). Horizontally scrolls (tail-anchored)
|
||||
* once @p text exceeds the strip's width. No-op before TTF mode is
|
||||
* active (vt100_enable_ttf() must have run first).
|
||||
* FABRIC.md item 4.4y-revised: toggle the full-screen vt100 terminal
|
||||
* between visible (normal operation) and hidden (graphics mode -- the
|
||||
* terminal stops drawing, letting direct framebuffer/TTF-TEXT calls show
|
||||
* through undisturbed). Toggling back to visible does a full redraw of
|
||||
* the terminal's current on-screen content, restoring it exactly as it
|
||||
* was. No-op before TTF mode is active.
|
||||
*/
|
||||
void vt100_strip_draw(const char *text);
|
||||
void vt100_toggle_graphics(void);
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
* Queries
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 8.5 KiB |
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
qemu: terminating on signal 15 from pid 133155 (/bin/bash)
|
||||
@@ -317,10 +317,10 @@ void console_fb_scroll_fwd(uint32_t n)
|
||||
}
|
||||
}
|
||||
|
||||
void console_fb_strip_draw(const char *text)
|
||||
void console_fb_toggle_graphics(void)
|
||||
{
|
||||
if (fb_is_available()) {
|
||||
vt100_strip_draw(text);
|
||||
vt100_toggle_graphics();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+76
-176
@@ -81,47 +81,28 @@ static ttf_font_t g_ttf_font;
|
||||
static int g_ttf_ready = 0;
|
||||
static ttf_raster_cache_t g_ttf_cache;
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
* FABRIC.md item 4.4t: confine REPL text (TTF mode only) to the 640x480
|
||||
* CANVAS box computed in 4.4o and pixel-verified in 4.4p. Boot/POST
|
||||
* (bitmap mode) is untouched -- g_origin_x/g_origin_y default to (0,0)
|
||||
* and only change once vt100_enable_ttf() runs.
|
||||
*
|
||||
* FABRIC.md item 4.4x: origin is now DERIVED from fb_width()/fb_height()
|
||||
* at vt100_enable_ttf() time rather than hardcoded per-arch literals --
|
||||
* both the old per-arch numbers (320/104 amd64, 80/4 aarch64+riscv64) and
|
||||
* the new ones below check out against the same formula, so this is a
|
||||
* strict generalization, not a behavior change for X. Y changes because
|
||||
* 4.4u/4.4w replaced 4.4m's 96px/4-line REPL strip with a single-line
|
||||
* strip pinned to the bottom of the screen (see VT100_STRIP_* below) --
|
||||
* the box now sits directly above that strip instead of assuming 96px.
|
||||
* origin_x = (fb_width() - VT100_BOX_W) / 2 -- horizontal center
|
||||
* origin_y = fb_height() - VT100_BOX_H -- box bottom edge
|
||||
* - VT100_STRIP_BOX_GAP_PX -- gap above strip
|
||||
* - (2*VT100_STRIP_GAP_PX + 1) -- strip height
|
||||
* --------------------------------------------------------------------- */
|
||||
#define VT100_BOX_W 640u
|
||||
#define VT100_BOX_H 480u
|
||||
#define VT100_BOX_COLS 53u /* 640 / VT100_TTF_CELL_W_PX, exact */
|
||||
#define VT100_BOX_ROWS 20u /* 480 / VT100_TTF_CELL_H_PX, exact */
|
||||
/* FABRIC.md item 4.4y-revised: Alt+TAB graphics/text toggle. When 0, every
|
||||
* terminal draw call (put_char's glyph blit, erase, scroll) becomes a
|
||||
* pure logical update -- g_vt's cursor/attributes and the scrollback
|
||||
* shadow still advance normally, only the actual framebuffer write is
|
||||
* skipped -- so direct framebuffer/TTF-TEXT drawing shows through
|
||||
* undisturbed, and vt100_toggle_graphics() can restore the terminal
|
||||
* exactly as it logically stands once toggled back. Always 1 in bitmap
|
||||
* mode (boot/POST never hides). */
|
||||
static int g_terminal_visible = 1;
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
* FABRIC.md items 4.4u/4.4w/4.4x: the REPL prompt/input strip -- a
|
||||
* single-line region pinned to the bottom of the screen, independent of
|
||||
* the scrollback box's own grid (see vt100_strip_draw() below). Numbers
|
||||
* pinned by Captain Bob directly, 2026-08-12 (4.4w).
|
||||
* FABRIC.md items 4.4t/4.4o/4.4u/4.4w/4.4x/4.4z tried a 640x480 CANVAS
|
||||
* box with a separate single-line REPL strip pinned below it -- a
|
||||
* confined region plus independent border-drawing/geometry bookkeeping
|
||||
* for both. Reverted 2026-08-12, simplified back to what this comment
|
||||
* block now describes: the entire framebuffer is one vt100 terminal,
|
||||
* full width and full height, in both bitmap and TTF glyph modes. No
|
||||
* origin offset, no box, no strip, no border drawing -- cols/rows are
|
||||
* simply fb_width()/cell_w() and fb_height()/cell_h(). The REPL prompt is
|
||||
* just the terminal's last line, exactly like any other scrolling
|
||||
* terminal, not a separately-rendered region.
|
||||
* --------------------------------------------------------------------- */
|
||||
#define VT100_STRIP_GAP_PX 15u /* baseline-to-border-line gap, both sides, mirrored */
|
||||
#define VT100_STRIP_BOX_GAP_PX 8u /* gap between the strip's top border and the box's bottom edge */
|
||||
#define VT100_BORDER_GRAY FB_RGB(0xAA, 0xAA, 0xAA) /* FB_ANSI_PALETTE[7]; shared by the
|
||||
strip's border lines (4.4x) and
|
||||
the box's own border (4.4z) --
|
||||
same pinned decision (4.4w) */
|
||||
#define VT100_STRIP_TEXT_WHITE FB_RGB(0xFF, 0xFF, 0xFF)
|
||||
#define VT100_STRIP_LEFT_MARGIN_PX(fbw) (((fbw) - VT100_BOX_W) / 2u) /* aligned under the box */
|
||||
|
||||
static uint32_t g_origin_x = 0; /* box top-left, TTF mode only; 0 in bitmap mode */
|
||||
static uint32_t g_origin_y = 0;
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
* FABRIC.md item 4.4q: REPL scrollback. Text-only (not pixel snapshots --
|
||||
@@ -239,11 +220,9 @@ static void apply_sgr(void);
|
||||
static uint32_t cell_w(void) { return g_glyph_mode == VT_GLYPH_TTF ? VT100_TTF_CELL_W_PX : fb_cell_w(); }
|
||||
static uint32_t cell_h(void) { return g_glyph_mode == VT_GLYPH_TTF ? VT100_TTF_CELL_H_PX : fb_cell_h(); }
|
||||
|
||||
/* Pixel position of the top-left corner of character cell (cx, cy),
|
||||
* offset by the box origin (4.4t) -- (0,0) in bitmap mode, so boot/POST
|
||||
* is unaffected. */
|
||||
static uint32_t px_of(uint32_t col) { return g_origin_x + col * cell_w(); }
|
||||
static uint32_t py_of(uint32_t row) { return g_origin_y + row * cell_h(); }
|
||||
/* Pixel position of the top-left corner of character cell (cx, cy). */
|
||||
static uint32_t px_of(uint32_t col) { return col * cell_w(); }
|
||||
static uint32_t py_of(uint32_t row) { return row * cell_h(); }
|
||||
|
||||
/* Effective fg / bg accounting for reverse video */
|
||||
static uint32_t eff_fg(void) { return g_vt.reverse ? g_vt.bg : g_vt.fg; }
|
||||
@@ -289,68 +268,6 @@ static void ttf_draw_glyph_cell(uint32_t cell_px, uint32_t cell_py, uint8_t ch,
|
||||
}
|
||||
}
|
||||
|
||||
/* FABRIC.md items 4.4u/4.4w/4.4x: draw the REPL prompt/input strip -- a
|
||||
* single-line region pinned to the bottom of the screen, independent of
|
||||
* the scrollback box's own grid and cursor state (this function never
|
||||
* touches g_vt, and nothing in the box's own put_char()/scroll_up() path
|
||||
* touches the strip). Reuses ttf_draw_glyph_cell() for the actual glyph
|
||||
* blit -- same rasterizer, same cache, as the box's own grid -- rather
|
||||
* than a second text-drawing path.
|
||||
*
|
||||
* Horizontal scroll (4.4u step 4): @p text is drawn tail-anchored once it
|
||||
* exceeds the strip's width. That is equivalent to cursor-anchored
|
||||
* scrolling because the caller (repl.c) only ever appends at, or
|
||||
* backspaces from, the end of the line -- there is no mid-line cursor
|
||||
* movement in this REPL, so "keep the cursor visible" and "keep the tail
|
||||
* visible" are the same window.
|
||||
*
|
||||
* Border lines are drawn LAST, after the glyph loop, not first: a glyph
|
||||
* cell's own opaque background fill (cell_h()=24px) can extend a few
|
||||
* pixels past the strip's 15px baseline-to-line gap for full-ascender
|
||||
* characters -- 4.4u's own record already flags these gap numbers as
|
||||
* "informal... need to be re-checked once actually built." Drawing the
|
||||
* borders last means an oversized cell can never erase them; it can only
|
||||
* be visually clipped by them, which is the correct failure direction.
|
||||
*
|
||||
* No-op before TTF mode is active. */
|
||||
void vt100_strip_draw(const char *text)
|
||||
{
|
||||
uint32_t fbw, fbh, bottom_line_y, top_line_y, baseline_y, cell_py;
|
||||
uint32_t margin_x, avail_px, avail_cols, len, start, i;
|
||||
|
||||
if (!g_ttf_ready || g_glyph_mode != VT_GLYPH_TTF) return;
|
||||
if (!text) text = "";
|
||||
|
||||
fbw = fb_width();
|
||||
fbh = fb_height();
|
||||
bottom_line_y = fbh - 1u;
|
||||
top_line_y = bottom_line_y - (2u * VT100_STRIP_GAP_PX);
|
||||
baseline_y = bottom_line_y - VT100_STRIP_GAP_PX;
|
||||
cell_py = baseline_y - VT100_TTF_SIZE_PX;
|
||||
margin_x = VT100_STRIP_LEFT_MARGIN_PX(fbw);
|
||||
|
||||
/* Clear the whole strip first -- both border lines get redrawn every
|
||||
* call regardless, so clearing border-to-border is simpler than
|
||||
* clearing just the interior and no less correct. */
|
||||
fb_fill_rect(0, top_line_y, fbw, bottom_line_y - top_line_y + 1u, VT100_DEFAULT_BG);
|
||||
|
||||
avail_px = (fbw > 2u * margin_x) ? (fbw - 2u * margin_x) : 0u;
|
||||
avail_cols = cell_w() ? (avail_px / cell_w()) : 0u;
|
||||
|
||||
len = (uint32_t)strlen(text);
|
||||
start = (len > avail_cols) ? (len - avail_cols) : 0u;
|
||||
|
||||
for (i = start; i < len; i++) {
|
||||
uint32_t col = i - start;
|
||||
ttf_draw_glyph_cell(margin_x + col * cell_w(), cell_py,
|
||||
(uint8_t)text[i],
|
||||
VT100_STRIP_TEXT_WHITE, VT100_DEFAULT_BG);
|
||||
}
|
||||
|
||||
fb_fill_rect(0, top_line_y, fbw, 1u, VT100_BORDER_GRAY);
|
||||
fb_fill_rect(0, bottom_line_y, fbw, 1u, VT100_BORDER_GRAY);
|
||||
}
|
||||
|
||||
static void draw_cursor_glyph(uint8_t ch)
|
||||
{
|
||||
uint32_t f = eff_fg();
|
||||
@@ -373,6 +290,9 @@ static void draw_cursor_glyph(uint8_t ch)
|
||||
f = FB_RGB(r, g, bv);
|
||||
}
|
||||
|
||||
if (!g_terminal_visible) return; /* 4.4y-revised: graphics mode -- logical state
|
||||
* only (already updated above), no framebuffer write */
|
||||
|
||||
if (g_glyph_mode == VT_GLYPH_TTF) {
|
||||
ttf_draw_glyph_cell(px_of(g_vt.cx), py_of(g_vt.cy), ch, f, b);
|
||||
} else {
|
||||
@@ -469,28 +389,18 @@ void vt100_enable_ttf(void)
|
||||
|
||||
g_glyph_mode = VT_GLYPH_TTF;
|
||||
|
||||
/* FABRIC.md item 4.4t: switch to the box-confined coordinate system
|
||||
* before anything below derives cols/rows/stride from it -- the
|
||||
* scrollback allocation block just below depends on g_vt.cols via
|
||||
* g_line_stride, so origin/cols/rows MUST be set first or every
|
||||
* shadow/ring index silently corrupts instead of crashing. */
|
||||
/* FABRIC.md item 4.4x: derived from the real framebuffer size, not a
|
||||
* hardcoded per-arch literal -- see the formula in this file's header
|
||||
* comment above VT100_BOX_W. */
|
||||
g_origin_x = VT100_STRIP_LEFT_MARGIN_PX(fb_width());
|
||||
g_origin_y = fb_height() - VT100_BOX_H - VT100_STRIP_BOX_GAP_PX
|
||||
- (2u * VT100_STRIP_GAP_PX + 1u);
|
||||
g_vt.cols = VT100_BOX_COLS;
|
||||
g_vt.rows = VT100_BOX_ROWS;
|
||||
/* Full-screen grid, TTF cell size -- see this file's header comment.
|
||||
* cols/rows MUST be set before anything below derives stride from
|
||||
* them via g_line_stride. */
|
||||
g_vt.cols = fb_width() / cell_w();
|
||||
g_vt.rows = fb_height() / cell_h();
|
||||
g_vt.cx = g_vt.cy = 0;
|
||||
|
||||
/* One-time full-screen clear at the bitmap-to-TTF transition: the boot/
|
||||
* POST scroll left the whole framebuffer covered in font_8x16 text, and
|
||||
* from here on erase_display(2) is box-scoped (see its mode-aware
|
||||
* branch below) -- without this, that debris would sit frozen outside
|
||||
* the box forever instead of leaving clean CANVAS around it. This is
|
||||
* the one and only whole-framebuffer wipe in TTF mode; every later
|
||||
* ESC[2J stays box-scoped. */
|
||||
* POST scroll left the whole framebuffer covered in font_8x16 text.
|
||||
* erase_display(2) below would cover this on its own now that it's
|
||||
* always full-screen, but the explicit fill stays as the "clean slate
|
||||
* before anything else runs" step it always was. */
|
||||
fb_fill_rect(0, 0, fb_width(), fb_height(), g_vt.def_bg);
|
||||
erase_display(2);
|
||||
|
||||
@@ -502,17 +412,6 @@ void vt100_enable_ttf(void)
|
||||
{
|
||||
uint32_t i;
|
||||
g_line_stride = g_vt.cols + 1u;
|
||||
/* 4.4t: cols is now the fixed box width (53) -- verify the stride
|
||||
* came out right rather than assuming the ordering above landed
|
||||
* correctly (advisor-flagged failure mode: silent corruption, not
|
||||
* a crash, if this ever drifts). */
|
||||
if (g_line_stride != VT100_BOX_COLS + 1u) {
|
||||
log_message(LOG_ERROR, "vt100: unexpected line_stride=%u (want %u), scrollback unavailable",
|
||||
g_line_stride, VT100_BOX_COLS + 1u);
|
||||
g_shadow = (void *)0;
|
||||
g_ring = (void *)0;
|
||||
return;
|
||||
}
|
||||
g_shadow = (char *)kmalloc((size_t)g_vt.rows * g_line_stride);
|
||||
g_ring = (char *)kmalloc((size_t)VT100_SCROLLBACK_MAX_LINES * g_line_stride);
|
||||
if (!g_shadow || !g_ring) {
|
||||
@@ -572,6 +471,40 @@ static void scrollback_redraw(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* FABRIC.md item 4.4y-revised: Alt+TAB graphics/text toggle, a two-state
|
||||
* machine (VISIBLE <-> HIDDEN) with exactly one transition function --
|
||||
* both the physical Alt+TAB interception (repl.c) and the ALT+TAB FORTH
|
||||
* word (keyboard_words.c) call this same function, so there is exactly
|
||||
* one place the state actually flips, not two call sites each doing it
|
||||
* independently.
|
||||
*
|
||||
* VISIBLE -> HIDDEN: flip the flag only. draw_cursor_glyph()/
|
||||
* erase_line_range()/erase_display()/scroll_up() all check
|
||||
* g_terminal_visible and skip their framebuffer writes from this point
|
||||
* on, while still advancing g_vt's cursor/attributes and the g_shadow/
|
||||
* g_ring scrollback state normally -- graphics-mode drawing (direct
|
||||
* framebuffer or TTF-TEXT calls) is then free to use the whole screen,
|
||||
* and the terminal's logical state stays perfectly consistent with what
|
||||
* it would have been had it stayed visible.
|
||||
*
|
||||
* HIDDEN -> VISIBLE: flip the flag, then wipe whatever graphics drew and
|
||||
* reuse scrollback_redraw() to repaint the terminal's current on-screen
|
||||
* content from that untouched logical state -- restored exactly as it
|
||||
* logically stood, not merely as it last looked on screen. */
|
||||
void vt100_toggle_graphics(void)
|
||||
{
|
||||
if (!g_ttf_ready || g_glyph_mode != VT_GLYPH_TTF) return;
|
||||
|
||||
if (g_terminal_visible) {
|
||||
g_terminal_visible = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
g_terminal_visible = 1;
|
||||
fb_fill_rect(0, 0, fb_width(), fb_height(), g_vt.def_bg);
|
||||
scrollback_redraw();
|
||||
}
|
||||
|
||||
void vt100_scroll_back(uint32_t n)
|
||||
{
|
||||
if (!g_shadow || !g_ring) return;
|
||||
@@ -654,13 +587,9 @@ static void scroll_up(uint32_t lines)
|
||||
}
|
||||
}
|
||||
|
||||
/* 4.4t: box-scoped scroll in TTF mode (fb_scroll_rows() is a
|
||||
* whole-framebuffer blit and would drag pixels from outside the box);
|
||||
* bitmap mode (boot/POST) keeps the original full-framebuffer path. */
|
||||
if (g_glyph_mode == VT_GLYPH_TTF) {
|
||||
fb_scroll_rect(g_origin_x, g_origin_y, VT100_BOX_W, VT100_BOX_H,
|
||||
lines * cell_h(), g_vt.def_bg);
|
||||
} else {
|
||||
/* Full-framebuffer scroll -- both glyph modes cover the whole screen
|
||||
* now, so there is no box to scope this to. */
|
||||
if (g_terminal_visible) {
|
||||
fb_scroll_rows(lines, g_vt.def_bg);
|
||||
}
|
||||
}
|
||||
@@ -679,29 +608,10 @@ static void scroll_up(uint32_t lines)
|
||||
static void erase_line_range(uint32_t row, uint32_t c0, uint32_t c1)
|
||||
{
|
||||
if (c1 <= c0) return;
|
||||
if (!g_terminal_visible) return; /* 4.4y-revised: graphics mode */
|
||||
fb_fill_rect(px_of(c0), py_of(row), (c1 - c0) * cell_w(), cell_h(), g_vt.bg);
|
||||
}
|
||||
|
||||
/* FABRIC.md item 4.4z: stroke the scroll box's own visible border. 4.4t
|
||||
* confined text to the box's coordinate space but never drew a rectangle
|
||||
* outline on it -- the edges were implicit (where text stops), not
|
||||
* drawn. Four thin edges, 1px each, same gray as the strip's border
|
||||
* lines (4.4x/4.4w -- one shared color, one design decision). Called
|
||||
* from erase_display()'s box-scoped branch below, so the border survives
|
||||
* every box clear (the initial one at vt100_enable_ttf() time and any
|
||||
* later ESC[2J), not just the first. */
|
||||
static void draw_box_border(void)
|
||||
{
|
||||
fb_fill_rect(g_origin_x, g_origin_y,
|
||||
VT100_BOX_W, 1u, VT100_BORDER_GRAY);
|
||||
fb_fill_rect(g_origin_x, g_origin_y + VT100_BOX_H - 1u,
|
||||
VT100_BOX_W, 1u, VT100_BORDER_GRAY);
|
||||
fb_fill_rect(g_origin_x, g_origin_y,
|
||||
1u, VT100_BOX_H, VT100_BORDER_GRAY);
|
||||
fb_fill_rect(g_origin_x + VT100_BOX_W - 1u, g_origin_y,
|
||||
1u, VT100_BOX_H, VT100_BORDER_GRAY);
|
||||
}
|
||||
|
||||
static void erase_display(int mode)
|
||||
{
|
||||
if (mode == 0) {
|
||||
@@ -719,13 +629,8 @@ static void erase_display(int mode)
|
||||
}
|
||||
erase_line_range(g_vt.cy, 0, g_vt.cx + 1);
|
||||
} else {
|
||||
/* erase entire screen -- 4.4t: box-scoped in TTF mode (a
|
||||
* full-framebuffer wipe here would blank CANVAS outside the box),
|
||||
* full-screen in bitmap mode as before (boot/POST unaffected). */
|
||||
if (g_glyph_mode == VT_GLYPH_TTF) {
|
||||
fb_fill_rect(g_origin_x, g_origin_y, VT100_BOX_W, VT100_BOX_H, g_vt.def_bg);
|
||||
draw_box_border();
|
||||
} else {
|
||||
/* erase entire screen -- full framebuffer, both glyph modes. */
|
||||
if (g_terminal_visible) {
|
||||
fb_fill_rect(0, 0, fb_width(), fb_height(), g_vt.def_bg);
|
||||
}
|
||||
g_vt.cx = g_vt.cy = 0;
|
||||
@@ -972,13 +877,8 @@ void vt100_putc(char raw)
|
||||
/* RI reverse index: scroll down (insert line at top) */
|
||||
if (g_vt.cy == 0) {
|
||||
/* Scroll display down: not trivially done without a
|
||||
* full back-buffer; fill top row with bg instead.
|
||||
* 4.4t: box-scoped in TTF mode, full-width in bitmap mode. */
|
||||
if (g_glyph_mode == VT_GLYPH_TTF) {
|
||||
fb_fill_rect(g_origin_x, g_origin_y, VT100_BOX_W, cell_h(), g_vt.def_bg);
|
||||
} else {
|
||||
fb_fill_rect(0, 0, fb_width(), cell_h(), g_vt.def_bg);
|
||||
}
|
||||
* full back-buffer; fill top row with bg instead. */
|
||||
fb_fill_rect(0, 0, fb_width(), cell_h(), g_vt.def_bg);
|
||||
} else {
|
||||
g_vt.cy--;
|
||||
}
|
||||
|
||||
+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));
|
||||
|
||||
@@ -50,9 +50,29 @@
|
||||
* -- see the implementation's own doc comment), pressed is 1 or 0. This is
|
||||
* the word the later REPL keyboard-input work (M8) is expected to build
|
||||
* on; KBD-SCAN/VKBD-EVENT remain as lower-level per-device diagnostics.
|
||||
*
|
||||
* @par ALT+TAB ( -- )
|
||||
* FABRIC.md item 4.4y-revised. Programmatic equivalent of the physical
|
||||
* Alt+TAB graphics/text toggle -- calls the same state-machine transition
|
||||
* (console_fb_toggle_graphics() / vt100_toggle_graphics()) the keyboard
|
||||
* interception in repl.c uses, so there is exactly one place the toggle
|
||||
* actually happens.
|
||||
* @}
|
||||
*/
|
||||
|
||||
void register_keyboard_words(VM *vm);
|
||||
|
||||
/**
|
||||
* FABRIC.md item 4.4v: shared C-level poll, one converged event stream
|
||||
* (Linux input keycode namespace, all three architectures) -- see
|
||||
* KEY-EVENT's doc comment above for the full per-arch translation
|
||||
* rationale. Used by both kbw_key_event() (the FORTH word) and the REPL
|
||||
* keyboard bridge (repl.c), so there is exactly one implementation.
|
||||
*
|
||||
* @param keycode Written with the Linux input keycode on success.
|
||||
* @param pressed Written with 1 (press/repeat) or 0 (release) on success.
|
||||
* @return 1 if an event was available, 0 otherwise.
|
||||
*/
|
||||
int sk_key_event_poll(uint16_t *keycode, int *pressed);
|
||||
|
||||
#endif /* KEYBOARD_WORDS_H */
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
#include "starkernel/virtio_input.h"
|
||||
#endif
|
||||
|
||||
#if defined(__STARKERNEL__)
|
||||
#include "starkernel/console.h"
|
||||
#endif
|
||||
|
||||
/* KBD-SCAN ( -- c -1 | 0 ) */
|
||||
static void kbw_scan(VM *vm)
|
||||
{
|
||||
@@ -117,29 +121,60 @@ static void kbw_vdebug(VM *vm)
|
||||
* field already lives in the same Linux keycode namespace; `value` is
|
||||
* mapped 1:1 except autorepeat (value=2), folded into "still pressed"
|
||||
* here since this checkpoint's shape only distinguishes press/release. */
|
||||
static void kbw_key_event(VM *vm)
|
||||
/* FABRIC.md item 4.4v: shared C-level implementation, so the REPL
|
||||
* keyboard bridge (repl.c) and the KEY-EVENT FORTH word below poll the
|
||||
* exact same converged event stream rather than each re-deriving the
|
||||
* per-arch translation kbw_key_event's own doc comment already explains
|
||||
* (XT Set-1 make code == Linux keycode for the non-extended range; break
|
||||
* codes set bit 7 instead of carrying a separate field). */
|
||||
int sk_key_event_poll(uint16_t *keycode, int *pressed)
|
||||
{
|
||||
#if defined(__STARKERNEL__) && defined(ARCH_AMD64)
|
||||
uint8_t sc;
|
||||
if (i8042_pop_scancode(&sc)) {
|
||||
vm_push(vm, (cell_t)(sc & 0x7Fu));
|
||||
vm_push(vm, (cell_t)((sc & 0x80u) ? 0 : 1));
|
||||
vm_push(vm, -1);
|
||||
} else {
|
||||
vm_push(vm, 0);
|
||||
*keycode = (uint16_t)(sc & 0x7Fu);
|
||||
*pressed = (sc & 0x80u) ? 0 : 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
#elif defined(__STARKERNEL__) && (defined(ARCH_RISCV64) || defined(ARCH_AARCH64))
|
||||
uint16_t code;
|
||||
uint32_t value;
|
||||
if (virtio_input_pop_event(&code, &value)) {
|
||||
vm_push(vm, (cell_t)code);
|
||||
vm_push(vm, (cell_t)(value == 0u ? 0 : 1));
|
||||
*keycode = code;
|
||||
*pressed = (value == 0u) ? 0 : 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
(void)keycode; (void)pressed;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void kbw_key_event(VM *vm)
|
||||
{
|
||||
uint16_t keycode;
|
||||
int pressed;
|
||||
|
||||
if (sk_key_event_poll(&keycode, &pressed)) {
|
||||
vm_push(vm, (cell_t)keycode);
|
||||
vm_push(vm, (cell_t)pressed);
|
||||
vm_push(vm, -1);
|
||||
} else {
|
||||
vm_push(vm, 0);
|
||||
}
|
||||
#else
|
||||
vm_push(vm, 0);
|
||||
}
|
||||
|
||||
/* ALT+TAB ( -- ): FABRIC.md item 4.4y-revised. Programmatic equivalent of
|
||||
* the physical Alt+TAB interception (repl.c's sk_kbd_getc()) -- both call
|
||||
* console_fb_toggle_graphics(), so there is exactly one state-machine
|
||||
* transition, invoked two ways. */
|
||||
static void kbw_alt_tab(VM *vm)
|
||||
{
|
||||
(void)vm;
|
||||
#if defined(__STARKERNEL__)
|
||||
console_fb_toggle_graphics();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -150,4 +185,5 @@ void register_keyboard_words(VM *vm)
|
||||
register_word(vm, "VKBD-EVENT", kbw_vevent);
|
||||
register_word(vm, "VKBD-DEBUG", kbw_vdebug);
|
||||
register_word(vm, "KEY-EVENT", kbw_key_event);
|
||||
register_word(vm, "ALT+TAB", kbw_alt_tab);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user