Control modes (tray 'Control Mode' submenu, persisted):
- Manual: tray toggle only (grayed labels now explain why when disabled)
- Auto - Off while Steam running: yield the controller whenever steam.exe
runs; reclaim ~6s after it exits (debounced against Steam self-restarts)
- Auto - Off ONLY while in Steam game: yield only while RunningAppID != 0
SteamWatcher polls the Steam process and RunningAppID every 2s with
asymmetric debounce: transitions toward more Steam activity are reported
immediately (yield fast), transitions away must hold ~6s.
Taking the device from a running Steam requires invalidating its HID write
handle. A new elevated helper (SteamlessDeviceCycle.exe) restarts the
controller device node (unplug/replug equivalent) on demand via a
highest-privileges scheduled task, registered by the installer or a one-time
UAC prompt. The tray app itself NEVER runs elevated: an elevated foreground
window blocks unelevated SendInput via UIPI, which froze Steam Input's
desktop cursor whenever the tray menu was open. The same cycle mechanism
hands the device to an already-running Steam on game launch (Steam only
opens controllers on arrival events).
Crash safety: an unhandled-exception filter best-effort restores lizard
mode without taking locks; the firmware's own revert timeout remains the
final fallback. ClaimExclusive now restores shared access on failure
instead of leaving the device handle closed.
Diagnostics for field disconnect reports:
- Event log at %LOCALAPPDATA%\SteamlessController\events.log (512KB
rotation, read-shareable): connect/disconnect causes, game mode
transitions with failure reasons, battery changes, stalls, keepalive
failures, auto-mode decisions. 'Open Event Log' in the tray menu.
- Silent-stall detection: no reports for 4s while enumerated (battery
death, sleep, wireless drop) is now detected, logged, and alerted with
the last battery reading.
- Disconnect/stall alert balloons, suppressed for intentional handoffs,
with a 'Disconnect Notifications' toggle for users with odd setups.
Startup reverts to the plain HKCU Run key (the elevated-logon-task variant
from an interim build is migrated back and cleaned up). Installer ships and
registers the helper and unregisters it on uninstall; version 1.8.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Introduces a ControllerPlatform enum (Xbox, PlayStation) and a full
DualShock 4 translation path alongside the existing Xbox 360 one.
Switching platforms live tears down and recreates the virtual device.
The selection persists in the registry and is exposed via a
"Controller Platform" submenu in the tray context menu.
DS4 translation maps face buttons to Cross/Circle/Square/Triangle,
encodes the D-pad as a HAT switch (with diagonal support), converts
signed 16-bit axes to uint8 with Y-axis inversion, and routes right
trackpad clicks to the DS4 touchpad button.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.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>
- 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>
- 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>