From 767473d1cf49e35752304ef1757dc2bfbd268681 Mon Sep 17 00:00:00 2001 From: Cyd Date: Tue, 7 Jul 2026 09:47:35 -0500 Subject: [PATCH] Project verify skill: drive the GUI via PostMessage + PrintWindow Co-Authored-By: Claude Fable 5 --- .claude/skills/verify/SKILL.md | 50 ++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .claude/skills/verify/SKILL.md diff --git a/.claude/skills/verify/SKILL.md b/.claude/skills/verify/SKILL.md new file mode 100644 index 0000000..5e81f5d --- /dev/null +++ b/.claude/skills/verify/SKILL.md @@ -0,0 +1,50 @@ +--- +name: verify +description: 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): + +```powershell +dotnet build vrio.sln -v q -nologo # Debug +# exe: src\VRio.App\bin\Debug\net48\VRio.App.exe +``` + +## 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). +- 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.