Commit Graph

8 Commits

Author SHA1 Message Date
cf7e0c783a M1: UI-fit instrumentation + headless ui_fit_test + first overflow fixes
Add panel overflow instrumentation (record_panel_fit reading ImGui ScrollMax),
a forced layout-reference + debug-aware center split, and host harness commands
(uisize/uifit). New headless ui_fit_test drives the real Controllers + Audio
panels at reference resolutions with Debug details on and asserts no panel
overflows its assigned size; the Audio panel gains a demo mode so its richest
content renders without a live mirror.

Fixes from the measured overflow: widen the center column (was too narrow ->
horizontal overflow), merge the Controllers poll/round-trip tables and fold the
trigger line into the slot line, and make the center height split
Debug-details-aware (Video's height is mirroring-driven, not debug-driven, so a
static split can't serve both modes). Controllers + Audio now fit at 1920x1080
with max info. Video/Injection/Log fit is finalized at the end via the live
uifit harness (M1 stays open until then).

15/15 ctest.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 11:14:31 +02:00
f673eb660c Drop stale Controllers-panel hint ("Esc: quit")
The inline hint still claimed Esc quits (no longer true) and duplicated the
F1 shortcut + RPT-capture note that the Help menu already lists. Remove the
redundant block; the Help menu is the single source for those.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 00:09:47 +02:00
4121ad4373 Move input polling to its own thread; fixed-width fast-changing UI numbers
Input thread: controller polling, pad publishing, and rumble forwarding were
driven by the render loop, so a low/synced frame rate throttled how often guest
input reached the game. New InputWorker owns the InputSource and runs poll +
IPC publish + rumble on a dedicated ~1 kHz thread, independent of rendering. The
UI thread reads a copy-safe InputSnapshot for the Controllers panel and relays the
Steam-Input request/active/failed state to/from the worker (Steam init/shutdown now
happen on the worker thread). IpcServer gained a mutex so the worker's publish() /
hook_status() can't race the UI thread starting/stopping the shared-memory channel
(use-after-unmap); InjectionPanel::test_input_ is now atomic. ControllersPanel::draw
takes an InputSnapshot instead of the live InputSource.

Fixed-width numbers: fast-changing readouts (menu-bar FPS/ms, Video pipeline rates +
latency + graph legend, controller poll rates + round-trip sticks, audio buffered ms
+ frames/s) printed with %.0f etc., so they shifted/blurred as values crossed digit
thresholds (99 -> 100) each frame. Padded them to fixed field widths so they stay put.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 12:51:00 +02:00
327ba1f394 Add per-backend input debug visualization + round-trip view
Makes it possible to isolate an input->tool problem from a tool->game one in the
Controllers panel (under Debug details):
- which backend fed each slot is already shown via the per-pad source tag
  ("XInput #0" / "Steam Input") in the Incoming section;
- a new "Round-trip" table shows, per slot, the state we forwarded (the active
  backend's pad) next to what the game actually read back, highlighting matches.

For the round-trip, the XInput hook now echoes the state it returns to the game into
the status (protocol v9->v10: per-slot read_state in HookStatus).

Verified: hook_selftest (x64 + x86) asserts the hook records the game-read state;
full build x64 + x86 clean; ctest x64 9/9, x86 3/3.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 05:15:07 +02:00
a32e78ffef Move the synthetic-input toggle to Controllers under Debug details
"Forward synthetic test input" is a controller-debug aid, so it now lives in the
Controllers panel (gated behind Debug details, disabled until the XInput hook is
attached) instead of the Injection panel. ControllersPanel owns the flag and exposes
test_input(); main feeds it into InjectionPanel::set_test_input each frame, so the
existing synthetic-pad substitution in publish() is unchanged.

Verified: x64 build green; review (default view no longer shows it in Injection;
appears in Controllers under Debug details).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 01:23:41 +02:00
37d0f64e23 Lay out the overlay panels in a fixed 3-column scheme
Panels used to Begin at cascade positions, so they overlapped and clipped. A new
apply_panel_layout() in app_chrome positions/sizes each panel from the main
viewport work area (ImGuiCond_FirstUseEver, still movable): Injection left column
full height (room for hook diagnostics), Controllers/Video/Audio stacked in the
center column, Log right edge full height (max room for the log stream). Added a
"View -> Reset layout" menu item (request_layout_reset / apply_layout_end_frame
re-apply the defaults once via ImGuiCond_Always). Each panel now calls
apply_panel_layout(Panel::X) instead of its own ad-hoc SetNextWindowPos/Size.

Verified live: captured the host overlay -- Injection (left, full height),
Controllers/Video/Audio (center stack), Log (right, full height), no overlap among
the panels. x64 build + ctest green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 01:19:45 +02:00
914dba4d25 Fix input forwarding: default to XInput, make Steam Input opt-in
Making Steam Input the default backend silently broke input forwarding. Merely
initializing Steam Input activates Steam's in-process XInput interception, which
hides controllers from XInputGetState unless they're bound to our action set for
the running appid. With no such binding (the normal case for a donor appid) Steam
Input reports zero controllers AND XInput now sees nothing -> no input at all.

Reproduced with coop_steam_input_probe: without Steam, XInput slot 0 is seen;
with Steam Input initialized, 0 Steam controllers and the XInput fallback goes
empty.

Default to XInput (RPT delivers guest pads there and it works) and make Steam
Input an opt-in Controllers-panel toggle that switches the backend at runtime;
turning it off restores XInput. All 6 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 14:25:43 +02:00
565934e8cf Move controller-poll info from Injection to Controllers panel
The per-slot XInput poll rates and the "game reading controller" summary
describe the controller, not the injection mechanism, so move them to the
Controllers panel (renamed from debug_overlay -> ControllersPanel, now a class
that owns the poll-rate sampling). The panel now shows both directions: the
guest pads the host receives from RPT, and what the injected game reads back.

The Injection panel keeps the hook attach state, focus spoof, focus-API
counts, and input-path diagnostics, and points to the Controllers panel for
poll rates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 20:00:30 +02:00