/utf-8 enforces UTF-8 source encoding, which makes C4828 fire on
ViGEmClient.h (non-UTF-8 bytes in its comments). Only SteamlessController
includes ViGEm headers (via VirtualController.cpp), so /wd4828 is needed
there specifically. Other targets remain clean.
Co-Authored-By: Dylan Deverill <ddeverill@gmail.com>
Conflicts resolved:
- ControllerManager.cpp: take main's slot-based EnableGameMode/
DisableGameMode dispatch; wire the rumble callback into
EnableGameModeSlot and add SetRumble(0,0) to DisableGameModeSlot
so rumble stops cleanly before vc is torn down.
- VirtualController.h: keep both RumbleCallback/OnRumble (ours) and
the new Update(backCfg, backMouseEnabled) signature (main's).
Co-Authored-By: Dylan Deverill <ddeverill@gmail.com>
Same latent use-after-free as WriteOutputReport: after CancelIo, the
kernel can still complete the IRP and write into the stack OVERLAPPED
after the function returns. Block with GetOverlappedResult(..., TRUE)
to drain before ov goes out of scope.
Co-Authored-By: Dylan Deverill <ddeverill@gmail.com>
- Drop Tick()/m_wantsGameMode auto-enable machinery (out of scope for
this PR — belongs in a separate submission)
- Remove unused CMD_TRIGGER_RUMBLE constant
- Fix WriteOutputReport comment to accurately describe padding behaviour
- Fix CancelIo OVERLAPPED use-after-free: drain with GetOverlappedResult
before the stack OVERLAPPED goes out of scope
- Strip redundant /wd4819 /wd4828 MSVC flags; /utf-8 already covers them
- Add comment to HeartbeatLoop explaining the 40 ms tick rationale
Co-Authored-By: Dylan Deverill <ddeverill@gmail.com>
Introduces a WebView2-based remap window (double-click tray icon or
'Remap Back Buttons...' context menu) that lets users assign any of
L4/L5/R4/R5 to a face button, bumper, trigger, d-pad direction, stick
click, Menu/View, mouse button, or 'none' (natural behavior).
- BackButtonConfig: new enum + struct; values stable as registry DWORDs
- RemapWindow: chromeless WebView2 window with a button picker and
press-to-detect capture mode; settings persist across launches
- ControllerManager: StartButtonCapture/StopButtonCapture API with
rising-edge HID detection for all mappable targets
- VirtualController: ApplyBackAction injects the mapped XInput button
each frame; mouse-button actions are edge-detected in the read loop
- TrackpadMouse: back-button mouse-click handling decoupled from remap
- TrayApp: wires up the remap window, saves/loads all back button
settings to HKCU\Software\SteamlessController
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each connected controller now gets its own virtual Xbox 360 device via
ViGEmBus, mapping to separate XInput player slots (1, 2, 3...).
Key changes:
- SteamController: add EnumerateAll() to probe and return all live
device paths across wired (0x1302) and dongle (0x1304) PIDs; add
Open(path) overload to open a specific already-validated path.
- ControllerManager: replace single-controller state with a vector of
Slot structs, each owning its own SteamController, VirtualController,
TrackpadMouse, and read thread. SyncDevices() diffs live paths against
current slots on every device-change event, adding new controllers and
removing disconnected ones. Controllers hot-plugged while game mode is
active are automatically brought into game mode.
- Bump installer version to 1.3.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
A Valve firmware update changed the main STATE report ID from 0x42 to
0x45. REPORT_STATE is updated to match; the now-redundant REPORT_EXTENDED
constant (which previously held 0x45) is removed.
Also adds better probe diagnostics to Open() — distinguishes between an
unexpected report ID (firmware mismatch) and a read timeout (empty slot).
Fixes a stale debug flag in SteamProbe: FORCE_SHOW_BYTES_16_17 reverted
to false (right joystick Y, not X).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Steam Controller Puck exposes up to four FF00/0001 HID interfaces
(one per paired controller slot). Previously, Open() blindly picked the
first interface, which could be an empty slot — feature reports sent to
it were silently ignored, so lizard mode was never disabled.
Now Open() iterates all FF00/0001 interfaces for both the wired PID
(0x1302) and the dongle PID (0x1304), reads a single input report with
a 500 ms timeout, and latches onto the first interface that responds
with a live 0x42 STATE report.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Added EnumerateAllValveDevices() to SteamProbe which lists every HID
interface with VID=0x28DE at startup — printing PID, usage page, usage,
and product string. This makes it easy to identify the wireless dongle's
PID without needing Device Manager.
Updated HidDevice::Enumerate to treat pid=0 as a wildcard so callers
can enumerate all devices for a given vendor.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Start with Windows toggle in tray menu — writes/removes the Run registry
key so the app launches automatically at login
- Inno Setup installer script for packaging the release exe
- CMakePresets.json for named debug/release build configurations
- README updated with correct Visual Studio 2025 build commands and a
note for VS 2022 users
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>