English | 简体中文
Turns a Bluetooth DualSense into a local virtual USB DualSense, so games treat it as a wired controller. Lightbar, adaptive triggers, rumble, speaker audio and haptics all come back to the physical pad.
-
Extract
OpenDS-…-windows-x64.zipto a local disk and keep every file. For a fixed install, runscripts/Install-OpenDS.ps1in PowerShell. -
Pair the DualSense in Windows Bluetooth settings and close any other tool that claims it. If the controller was paired to another device before, put it in pairing mode first:
Make sure the player indicator is off — hold the PS button until it goes dark — and unplug any USB cable. Hold the Create button and press the PS button until the light bar starts blinking. Then pick the controller in Windows Bluetooth settings.
These steps come from Sony's official pairing guide. Apple's support page shows where the Create button sits; the button combination is the same.
-
Double-click
opends.exe. If drivers are missing, follow the prompt to install USB/IP Win2 and HidHide, then reboot. -
Select the controller under Connection & Feedback, save, then click Start Bridge on the overview.
-
Launch the game. Start the bridge first — the controller is only seen as a full device if it is present when the game starts.
Closing the settings window keeps OpenDS in the tray. Stopping the bridge or exiting from the tray releases keys, removes the virtual device and makes the controller visible again.
Start collection in Live monitor to record button, stick-direction and strength changes below the controller. Right-stick recording is off by default; turn it on in Input history settings, where source labels (text, icon or hidden), thresholds and colors are also configurable. Source labels are hidden by default. Content size supports 50% to 500%, scaling text, icons and row heights together. Narrow windows place the duration below the combination. Touchpad contact and motion are excluded; its physical click is recorded.
The current input state stays pinned at the top with a live duration, and each older row shows how long that state lasted. Times display 99+ s past 99 seconds. Disconnect and reconnect appear as plug events.
LS, RS, L2 and R2 each offer Distinguish strength (on by default). Turning it off records activation, release and stick direction changes without strength transitions, in both the table and command CSV. Tier controls are disabled while dead zones remain editable. Each ungraded color is independent and initially matches the full-strength color. Trigger dead zones use raw values 0–255, defaulting to 0; values at or below the dead zone are released. Other thresholds remain raw values. CSV strength fields use 0 for released, 1–3 for tiers and 4 for ungraded active input; raw input values are retained.
Separators between complete records support light/dark colors, opacity and flat, fading or tapered ends. The overlay fits complete records to its window height by default; turn off automatic rows to set a fixed count.
Open Overlay for an independent table with optional always-on-top, adjustable size, separate background and content opacity, and light/dark themes. Locking enables mouse passthrough; unlock from the panel, the tray menu, or Restore overlay. With automatic colors off, light and dark palettes can be set separately.
Record file also writes a matching .commands.csv with each input and connection event, the classification settings and the raw timestamp.
Input history has independent minimum-duration filters: display defaults to 16.67 ms, while the command file defaults to 0 ms (off). Both values are configurable; 0 disables filtering. A state appears or is written after reaching the threshold, retaining its original start time. Short excursions between identical combinations merge into one duration. Filtering applies per state, so two consecutive different states that both fall below the threshold are dropped rather than summed. Connection, disconnection and gap events always pass. Waveform recording is unaffected.
Times are based on received input, rather than game frame counts.
The GUI covers everyday use. The commands are for scripting, batch changes, and letting an AI agent inspect or configure the bridge — doctor, list and startup status all print plain text that can be fed to a model directly.
.\opends.exe # open the settings window
.\opends.exe tray # background mode, tray icon only
.\opends.exe bridge # bridge directly, Ctrl+C to stop
.\opends.exe bridge 30 # bridge for 30 seconds
.\opends.exe list # list paired Bluetooth controllers
.\opends.exe doctor # check dependencies
.\opends.exe restore # restore a hidden controllerStarting with 0.3.2, Diagnostics lets you select installation directories for USB/IP Win2 and HidHide. Selections are saved and checked immediately; Auto clears a manual selection. USB/IP requires usbip.exe. The HidHide directory locates its optional configuration client and does not install the driver. Stop bridging before changing directories.
| Component | Purpose |
|---|---|
| USB/IP Win2 | creates the virtual USB device |
| HidHide | hides the physical controller so games see one device |
scripts/Install-Drivers.ps1 pulls both installers from their upstream GitHub releases and verifies the SHA-256 and publisher signature before running them:
| Driver | Upstream repository |
|---|---|
| USB/IP Win2 | vadimgrn/usbip-win2 |
| HidHide | nefarius/HidHide |
File names, URLs and digests are listed in scripts/drivers.json.
.\scripts\Install-Drivers.ps1 # download
.\scripts\Install-Drivers.ps1 -Install # download and install
.\scripts\Install-Drivers.ps1 -Proxy http://127.0.0.1:7890
.\scripts\Install-Drivers.ps1 -ManualDirectory D:\Downloads -InstallRelease archives already include libVIIPER and Opus.
Settings default to %LOCALAPPDATA%\OpenDS\opends.ini. An opends.ini next to the executable takes precedence, which gives you portable mode.
[ds5]
port=3240
buffer=64
audio=1
haptics_gain=10| Key | Meaning |
|---|---|
port |
virtual device port |
buffer |
speaker/haptics buffer blocks, 1–128, about 10.7 ms each. More is not better: fewer blocks means less lag but breaks up on a jittery link, more survives stalls but pushes sound and rumble behind the picture. Pick by trying it — on some setups a single block is the most stable |
audio |
speaker audio toggle |
haptics_gain |
haptic intensity, 10–20 |
microphone_gain_db |
microphone gain, 0–50 dB, peak-limited |
microphone_buffer_ms |
microphone jitter buffer, 16–512 ms |
monitor_sample_hz |
monitor sample rate, 20 / 50 / 100 / 200 |
monitor_fps |
monitor refresh rate, 15 / 30 / 60 |
monitor_seconds |
monitor time span, 30–900 s |
language |
UI language, auto follows the system, or a code such as zh-CN |
theme |
appearance, system / light / dark |
close_action |
what closing the window does, ask / tray / exit |
Restart the bridge after changing anything.
Open General settings and tick Run in tray when Windows starts. You can also set it during installation:
.\scripts\Install-OpenDS.ps1 -StartupFor scripting:
.\opends.exe startup enable
.\opends.exe startup status
.\opends.exe startup disableStartup uses the current user's Run key and needs no administrator rights.
The controller is missing from Device Manager
HidHide is hiding it. Exiting OpenDS restores it; after a crash, run opends.exe restore.
No rumble in game
Start OpenDS before launching the game. Games usually probe the controller type and its capabilities at startup. A controller connected later is still recognized as an input device, but the capability probe does not run again — rumble, adaptive triggers and lighting may stay inactive.
Rumble but no sound
The controller speaker has its own volume, set by the game through the output report. Without a game-side option it keeps its previous level. Make sure audio=1.
Audio stutters
Check the buffer block count first. More is not better — extra blocks push sound and rumble further behind the picture. Work up from small values (1, 16, 32, 64), playing the Classic rumble test and Native haptics test in Connection and feedback after each change, and keep whichever feels most responsive. When the link is steady, fewer blocks are often the steadier choice — one block is enough on some setups.
Steam games misbehave
Disable Steam Input. It takes over the controller and bypasses the virtual device.
The magnifier or on-screen keyboard opens by itself
Steam's guide chords turn PS button combinations into system shortcuts — magnifier, on-screen keyboard, screen recording. Turn it off in Steam: Settings → Controller → Advanced Settings → clear "Enable controller guide chords".
If it only happens occasionally, you can also disable the individual Windows accessibility shortcuts.
How do I troubleshoot a connection problem?
Logs are in %LOCALAPPDATA%\OpenDS\logs\opends.log, shared by startup and manual launches. They record connections, disconnects, bridge errors and audio statistics. Each file is capped at 1 MiB, with opends.log.1 and opends.log.2 kept as history. Every line starts with a Unix timestamp in seconds.
Supports DualSense and DualSense Edge. Edge uses the Edge PID by default; set edge_as_ds=true to present it as a standard DualSense. One controller at a time.
The microphone is experimental and off by default, with adjustable gain and jitter buffering — see Microphone.
The Live monitor page shows controller input alongside speaker, haptic and microphone waveforms — see Live monitor.
Requires the Rust MSVC toolchain, the Windows SDK and Git.
cargo fetch --locked
cargo test --locked --offline
.\scripts\Build-Release.ps1The optional bundled-opus feature compiles a static Opus with CMake; CMake 4 needs $env:CMAKE_POLICY_VERSION_MINIMUM='3.5'.
Rebuilding the DLL after changing vendor/viiper-source needs Go 1.27.3 and a Windows C compiler:
.\scripts\Build-VIIPER.ps1 -Compiler <path-to-gcc.exe>Each version ships four files:
| File | Contents |
|---|---|
OpenDS-<version>-windows-x64.zip |
executables, DLLs and scripts |
OpenDS-<version>-source.zip |
full source: Rust code, vendor/viiper-source, dependency licence notices |
SHA256SUMS.txt |
checksums for every asset |
TAG-SIGNATURE.json |
receipt for the signed tag |
The "Source code (zip)" and "Source code (tar.gz)" links on the GitHub page are generated by the platform and only contain Git-tracked files; dependency licence notices and the VIIPER source archive are missing from them. Download source.zip when you need the source.
The release pipeline checks that the VIIPER source in source.zip matches the DLL shipped in the binary archive.
GPL-3.0-or-later. Full text in LICENSE; third-party components in THIRD-PARTY.md.
When distributing binaries, include vendor/viiper-source; the release script packages it automatically.
- User guide
- Live monitor
- General settings
- Microphone
- Developer guide
- Protocol notes
- Resident mode
- Changelog
Runtime dependencies
| Project | Role |
|---|---|
| VIIPER | virtual USB DualSense device (GPL-3.0-or-later) |
| USB/IP Win2 | creates the virtual USB device |
| HidHide | hides the physical controller |
| Opus | audio codec (BSD-3-Clause) |
| native-windows-gui | settings UI (MIT) |
Design references
- input-overlay: DualSense layout reference; the presets are CC0
- 3d-controller-overlay: visual reference for the three-dimensional handset (MIT)
Ideas
- zhonghuihong on Bilibili: his documentation clarified how the DualSense behaves on PC and how to approach debugging it. That software is closed source; no code from it is used here.
DualSense and PlayStation are registered trademarks of Sony Interactive Entertainment Inc. (SIE).
This is an unofficial third-party project. It is not affiliated with, authorized, sponsored, or endorsed by SIE. Other trademarks are the property of their respective owners.