Skip to content

API: make keyboard key events actually reach the emulated C64; add run/frames for deterministic replay - #121

Open
arekbr wants to merge 1 commit into
slajerek:masterfrom
arekbr:fix/api-snapshot-keydown-runframes
Open

API: make keyboard key events actually reach the emulated C64; add run/frames for deterministic replay#121
arekbr wants to merge 1 commit into
slajerek:masterfrom
arekbr:fix/api-snapshot-keydown-runframes

Conversation

@arekbr

@arekbr arekbr commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Problem 1: keyboard endpoints never pressed a key

input/keyDown / input/keyUp replied 200 but no key ever reached the emulated machine ($CB stayed $40), and the newer input/key/down / input/key/up always replied 406 because CDebugInterfaceVice::KeyboardDown/Up unconditionally returned false after queueing the task.

Two root causes:

  • the queued task called raw keyboard_key_pressed(mtKeyCode), which is a silent no-op when the keyconvmap lookup misses, and even on a hit the latch goes through the randomized KEYBOARD_RAND() alarm — bad for cycle-deterministic tooling;
  • the queueing path had no way to report failure, so both endpoint families lied.

Fix

KeyboardDown/Up resolve the MTKEY code through C64KeyMapGetDefault()->FindKeyCode() at queue time and pass the resolved (matrixRow, matrixCol, shift) into the task. ExecuteTask presses the matrix position using the same immediate-latch sequence the virtual keyboard view already uses (CViewC64KeyMap::SelectKey): keyboard_key_pressed_matrix + keyboard_set_latch_keyarr + c64d_keyboard_key_down_latch (negative rows go through keyboard_set_keyarr_any). Unmapped keys and missing/invalid params now return 406; successfully queued events return 202 {"queued":true}. Both endpoint families are fixed (the legacy names are also used by the MCP bridge).

Problem 2: no deterministic N-frame run

There was no API way to run an exact number of frames (external tooling had to drive VICE with -limitcycles instead of this debugger).

Fix

New <platform>/run/frames {"count":N} generalizes the existing frame-step mechanism: RunEmulationForFrames(numFrames) sets frameStepTargetFrameNumber = current + N (RunEmulationForOneFrame now delegates with N=1, so GUI/test behavior is unchanged; the completion-wait budget scales with N). The endpoint is synchronous — the reply arrives after the frames have run, carrying frameStart and the final frame counter — and requires a paused machine (406 otherwise, since computing current+N on a running machine would race the emulation thread).

Verification (macOS arm64, Xcode 16.4, build-macos.sh)

14-point WebSocket gate against the built app, including negative controls:

  • run/frames {count:50} twice from pause: frame counter advances exactly +50 each time, frameStart/frame consistent with cpu/counters/read; called while running → 406
  • input/keyDown {keyCode:97} → 202 {queued:true}; after run/frames {count:3} zeropage $CB reads 10 ('A' matrix code); keyUp → $CB back to 64 (no key)
  • unmapped keyCode → 406; missing param → 406
  • screen/snapshot (PNG + metadata) unaffected

Commit is on top of current master (af8f1d2).

…dpoint

- input keyDown/keyUp (legacy and key/down|key/up) resolve the MTKEY code
  through C64KeyMap and press the resolved matrix position inside the queued
  CPU-interrupt task, using the same immediate-latch sequence as the virtual
  keyboard view (no randomized KEYBOARD_RAND latch delay). Unmapped keys and
  missing params return 406; queued events return 202 {queued:true}.
- CDebugInterfaceVice::KeyboardDown/Up report queueing success instead of
  always returning false.
- new <platform>/run/frames {count:N}: runs exactly N frames from a paused
  machine and pauses again (generalizes the existing frame-step mechanism);
  blocks until finished and returns frameStart/frame counters.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant