The window is now just the display: 640x160 dot field (5 px pitch, 4 px bezel) plus the title bar, which carries the port status. COM12 — the device end of the plasma's null-modem pair — is hardwired and opened at startup, with a retry timer that keeps trying while the port is missing or busy and reopens it if it dies. The control strip, port picker, counters, and wire log are gone; the glass keeps two gestures: double-click cycles the self-test pages, right-click resets the display to its power-on state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3.4 KiB
3.4 KiB
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. It auto-opens COM12 on launch (hardwired; status in the title bar), so its serial path tests end-to-end with no UI driving: the script just plays the game writing COM2 (second com0com pair; vRIO/RIOJoy use COM1⇄COM11). Double-click the glass = self-test pages, right-click = reset. 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_LBUTTONUPstraight to the canvas child HWND. Find it by descendingRealChildWindowFromPointfrom 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 fromSerialPort.GetPortNames()sorted OrdinalIgnoreCase) and send index-onlyCB_SETCURSEL; the apps readSelectedItemlazily so no CBN_SELCHANGE notification is needed. Find the combo child HWND via EnumChildWindows + GetClassName containingCOMBOBOX(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
GetWireAxisvalues — joystick Y is natively negated on the wire (stick up = −80) unless "Invert Y" is checked.