Matches the README, which advertises Bluetooth support as new in 1.9.
The installer script is the only place carrying the app version.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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>
The core fix: the SC2026 firmware silently reverts to lizard mode (including
its autonomous click haptics) after a period without host feature reports,
which doubled up with software haptics as a crunchy burst. A keepalive now
re-asserts the lizard-off state every 2 seconds while game mode is active.
Haptics reliability and feel:
- Switch trackpad haptics from OUT_HAPTIC_PULSE (grip LRAs) to
OUT_HAPTIC_COMMAND (trackpad LRAs) for localized feel
- Click haptic latch: press fires off the debounced firmware click bit,
release only fires once contact area returns to idle, so force chatter
and mid-hold easing cannot re-fire
- Movement ticks: distance-based with motion deadzone, post-release and
first-touch grace windows, pressing/teleport gates (pause, not reset),
idle decay, and a 50ms send rate limit so firmware waveforms never queue
into a backlog
Handoff and mouse:
- EnableLizardMode now also sends LOAD_DEFAULT_SETTINGS so firmware mouse
emulation resumes immediately on disable instead of waiting for the
firmware revert timeout
- Trackpad mouse: carry sub-pixel movement remainders between frames and
retune sensitivity (0.015 -> 0.01125)
Also: shared/exclusive HID reopen support, local-only HapticTester tool
(gitignored, conditional CMake target), installer version bump to 1.7.
Co-Authored-By: Claude Fable 5 <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>
- 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>