Files
VRIO/.claude/skills/verify/SKILL.md
T
CydandClaude Fable 5 a1b7dae3da vPLASMA: companion app emulating the cockpit plasma display
The cockpit's second serial device joins vRIO: the 128x32 dot-matrix
plasma on COM2 (9600 8N1) that the game draws mission text and status
graphics on. VPlasma.App opens the device end of a COM port, decodes
the display's command stream, and renders the matrix in plasma orange.

The command set is recovered from two Tesla 4.10 artifacts: the game's
driver (L4PLASMA.CPP — ESC P packed-bitmap row writes, ESC G 0 cursor
hide at boot) and the factory test tool PLASMA.EXE, whose data segment
pairs each command literal with its printf description (BS/HT/LF/VT/CR
motion, ESC @ clear, ESC L home, ESC G cursor, ESC K fonts, ESC H
attributes: intensity/underline/reverse/flash). Text renders through
the classic public-domain 5x7 set standing in for the lost ROM glyphs;
fonts 0-3 give 21x4 cells, fonts 4-7 the doubled 10x2. A Self test
cycles banner/charset/graphics pages through the same parser the wire
feeds, and the wire log shows every decoded command.

Verified end-to-end over the second com0com pair (host writing COM2,
vPLASMA listening on COM12). The verify skill gains the cross-process
combo-box lesson: string-carrying CB_* messages hang across processes,
so select ports by locally computed index via CB_SETCURSEL.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 14:22:00 -05:00

3.3 KiB
Raw Blame History

name, description
name description
verify Build, launch, and drive the vRIO WinForms app to verify changes at the GUI surface — screenshots via PrintWindow, input via PostMessage, no focus stealing.

Verifying vRIO changes

Build + tests (tests are CI's job; run the app for verification):

dotnet build vrio.sln -v q -nologo          # Debug
# exe: src\VRio.App\bin\Debug\net48\VRio.App.exe
# exe: src\VPlasma.App\bin\Debug\net48\VPlasma.App.exe   (companion display)

Everything below applies to vPLASMA too. Its serial path can be tested end-to-end on this machine: vPLASMA opens COM12, the script plays the game writing COM2 (second com0com pair; vRIO/RIOJoy use COM1⇄COM11). Killing a writer mid-stream can leave stale bytes queued in the com0com buffer — the next session's byte counter will run high; re-run clean before trusting counts.

Driving the GUI without touching the user's desktop

This is the user's live desktop — never use SetForegroundWindow + SendKeys/mouse_event: focus-stealing prevention leaves the app behind VS Code and your clicks land in the user's windows. Instead:

  • Screenshots: PrintWindow(hwnd, dc, 2) (PW_RENDERFULLCONTENT) — captures the window even when occluded. CopyFromScreen captures whatever is on top; don't use it.
  • Canvas input (stick drags, cell clicks): PostMessage WM_LBUTTONDOWN/WM_MOUSEMOVE/WM_LBUTTONUP straight to the canvas child HWND. Find it by descending RealChildWindowFromPoint from the form. Canvas geometry is compile-time constant (PanelCanvas.cs): CellW=66, BoxXY = x 416..496, y 6..74 (X/Y stick box). The first posted drag after launch can half-land (only the button-down registers); do a throwaway drag first, then the measured one, screenshot while held (spring-back recenters on up).
  • Checkboxes/buttons: WinForms controls expose no UIA TogglePattern (they surface as bare Panes) and don't answer BM_GETCHECK — but SendMessage(hwnd, BM_CLICK, 0, 0) works. Get the HWND from the UIA element's NativeWindowHandle (find by Name).
  • Combo boxes (COM port pickers): string-carrying messages (CB_FINDSTRINGEXACT, CB_GETLBTEXT) do not marshal across processes — the SendMessage hangs. Compute the item index locally (both apps fill from SerialPort.GetPortNames() sorted OrdinalIgnoreCase) and send index-only CB_SETCURSEL; the apps read SelectedItem lazily so no CBN_SELCHANGE notification is needed. Find the combo child HWND via EnumChildWindows + GetClassName containing COMBOBOX (UIA ClassName "ComboBox" doesn't match).
  • Pattern that works: Add-Type user32 P/Invokes, Start-Process the exe, drive via messages, PrintWindow screenshot to the scratchpad, kill the process in finally.

Environment gotchas

  • Bindings load from %APPDATA%\vRIO\bindings.txt (the user's file), not the built-in defaults — arrow keys are bound to Hat buttons, not the joystick axis. Drive axes via the X/Y box.
  • A real XInput gamepad is connected on this machine ("Controller #1 connected"); the router only writes an axis when its composed value changes, so a centered pad won't fight a canvas drag.
  • The wire readout (top center, green) shows GetWireAxis values — joystick Y is natively negated on the wire (stick up = 80) unless "Invert Y" is checked.