The receiver stopped working after a controller firmware update. Original diagnosis and fix by @danbosscher; extended here for Bluetooth, Steam handoff, and several defects found during QA on the hardware. The puck publishes a controller interface per slot plus a management endpoint, and on current firmware an empty slot rejects the lizard-mode command outright. - Enumerate only the controller collection (FF00:0001), excluding the puck's management endpoint at FF00:0002 - Wait for a live 0x42/0x45 state report before sending feature commands, and skip slots that never produce one - Prefer an exclusive claim but accept a shared handle when Windows keeps a compatible write handle open — only while Steam is absent, since a handle held with Steam running is probably Steam's, and driving the controller alongside it is worse than refusing. Refusing is what escalates to the device cycle that takes the handle back. - Add the Nereid receiver PID (0x1305) Defects found by QA and fixed here: - The battery payload is [chargeState, percent] on every transport, not just Bluetooth. A 92% battery was reported, and fed to the DS4 battery level, as 1%. - Game mode could not tell an idle receiver from a contested one, so a controller that was merely switched off triggered three device cycles, restarting the receiver's devnodes for nothing. - A receiver raises no device event when a slot becomes occupied, so waking a controller went unnoticed for as long as it was left. Poll for it instead. - Overlapping cycles undid successful claims: a cycle is asynchronous, and the arrivals it generated re-entered the acquire path and fired another on top of it, ripping the device back out a second after game mode came up. Cycles are now spaced. - Failure was announced while the last cycle was still landing — the alert fired one second before success. The verdict now waits out a grace period. Verified on the puck, Bluetooth, and wired: handoff to Steam on game launch, reclaim afterwards, and no duplicate input. Reclaiming takes around nine seconds on a four-slot receiver, dominated by SetupDiCallClassInstaller tearing down each interface in turn. Three attempts to shorten it (batching the cycle, a shorter settle, cycling only the contested interface) all regressed the reclaim and were reverted; it needs to be worked out against hardware rather than reasoned about. Co-Authored-By: Dan Bosscher <danbosscher@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SteamlessController
A lightweight Windows system tray app that lets you use a Steam Controller as a standard gamepad — without Steam running.
When Steamless Mode is active, the app disables the controller's built-in keyboard/mouse emulation (lizard mode) and exposes it as a virtual Xbox 360 controller via ViGEmBus, making it compatible with any game that supports XInput or the Xbox controller.
Features
- NEW in 1.9 - Bluetooth! Use the controller wired, through the dongle, or paired over Bluetooth LE
- NEW in 1.8 - Automatically enable/disable based on if Steam is running, or a Steam game is running!
- NEW in 1.8 - Advanced debugging and local logging to help diagnose issues
- Rumble Support v2.0
- Support for multiple Steam Controllers! Long live split screen!
- New shiny UI for remapping L4/L5 R4/L5 back buttons!
- Support for Xbox OR PlayStation controllers - with PS Touchpad and Gyro plumbing.
- System tray icon shows connection and mode status
- Steamless Mode — disables lizard mode and exposes controller as Xbox 360 gamepad
- Trackpad Mouse — use the right (or left) trackpad as a mouse cursor
- Back Buttons for Clicking — map R4/R5 (or L4/L5) to left/right mouse click
- Use Left Trackpad Instead — mirror all trackpad/back-button functionality to the left side for left-handed users
- Start with Windows — launch automatically at login
- Settings persist across restarts
Requirements
To run
- Windows 10 or later (64-bit)
- ViGEmBus driver installed
- Steam Controller — wired USB (PID
0x1302), wireless dongle (PID0x1304), or Bluetooth LE (PID0x1303, pair via Windows Bluetooth settings) - Steam closed (Steam claims the controller when running)
To build
- Visual Studio 2022 with the Desktop development with C++ workload
- CMake 3.20 or later (included with Visual Studio, or install separately)
- Windows SDK 10.0.22000 or later (installed via Visual Studio Installer)
Building
git clone https://github.com/your-username/SteamlessController.git
cd SteamlessController
cmake -B build
cmake --build build --target SteamlessController
The executable will be at build\Debug\SteamlessController.exe.
For a release build:
cmake -B build/release -G "Visual Studio 18 2025"
cmake --build build/release --config Release --target SteamlessController
If you have Visual Studio 2022, replace
"Visual Studio 18 2025"with"Visual Studio 17 2022".
CMake Targets
| Target | Description |
|---|---|
SteamlessController |
Main system tray application |
SteamProbe |
Console diagnostic tool — dumps raw HID report bytes as you interact with the controller. Useful for protocol research. |
RawControllerProbe |
Checks whether Windows.Gaming.Input.RawGameController can enumerate the Steam Controller (requires WinRT). |
How it works
The Steam Controller exposes a vendor HID collection (usage page 0xFF00) that carries all game input in a 54-byte report (ID 0x42) at ~60 Hz. By default the firmware runs in lizard mode, emulating a keyboard and mouse so the controller works without drivers.
SteamlessController sends HID feature reports to disable lizard mode, then reads the raw input reports and translates them into a virtual Xbox 360 controller via ViGEmBus. A background heartbeat re-sends the disable command every 800 ms to keep lizard mode off.
The full input report layout is documented in src/steam/SteamController.h.
Third-party
- ViGEmClient — MIT License, built from source as a static library