Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,20 @@ companion stay behind backend implementations.
## 🎮 Capabilities

- Gamepad profiles for generic HID, Xbox 360, Xbox One, Xbox Series,
DualShock 4, DualSense, and Nintendo Switch Pro-style controllers.
- Descriptor-driven PlayStation, Switch Pro, Xbox One, and Xbox Series gamepads
through Linux `uhid`; Generic and Xbox 360 gamepads plus keyboard, mouse,
touchscreen, trackpad, and pen tablet devices through `uinput`. Xbox One and
Xbox Series fall back to `uinput` when `uhid` is unavailable.
DualShock 4, DualSense, Nintendo Switch Pro-style, and 2026 Steam
controllers.
- Descriptor-driven PlayStation, Switch Pro, Steam Controller, Xbox One, and
Xbox Series gamepads through Linux `uhid`; Generic and Xbox 360 gamepads plus
keyboard, mouse, touchscreen, trackpad, and pen tablet devices through
`uinput`. Xbox One and Xbox Series fall back to `uinput` when `uhid` is
unavailable.
- Windows gamepads, keyboards, and Raw Input-visible mice through user-mode
UMDF2 drivers. Xbox 360 uses a broker-owned XUSB software-device personality;
the other profiles use Virtual HID Framework. Win32 keyboard and mouse
fallbacks remain available when the licensed driver path is unavailable.
- Output callbacks for profile-specific feedback such as ordinary and trigger
rumble, RGB and player LEDs, adaptive triggers, and raw HID output reports
when available.
rumble, addressable haptics, RGB and player LEDs, adaptive triggers, and raw
HID output reports when available.
- An optional `virtualhid_control` native UI tool for creating, removing,
controlling, and inspecting test gamepads and mice through the public C++ API.
- CMake consumption through installed packages, vendored source,
Expand Down Expand Up @@ -156,6 +158,7 @@ Alternatives exist if `libvirtualhid` does not meet your needs.
| DualShock 4 gamepad | ✅ | ✅ | ✅ | ❌ | ✅<sup><a href="#alternatives-note-4">4</a></sup> |
| DualSense gamepad | ✅ | ❌ | ✅ | ✅ | ✅<sup><a href="#alternatives-note-4">4</a></sup> |
| Nintendo Switch Pro-style gamepad | ✅ | ❌ | ✅ | ✅ | ✅<sup><a href="#alternatives-note-4">4</a></sup> |
| Steam Controller (2026) | ✅ | ❌ | ✅ | ❌ | ✅<sup><a href="#alternatives-note-4">4</a></sup> |
| Rumble or output callbacks | ✅ | ❌ | ✅ | ✅ | ✅<sup><a href="#alternatives-note-4">4</a></sup> |
| Data-driven profiles | ❌ | ❌ | ✅ | ❌ | ❌ |
| Actively developed | ✅ | ❌ | ✅ | ✅ | ✅ |
Expand Down
10 changes: 7 additions & 3 deletions docs/end-user-gamepad-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ physical controller <- Moonlight client <- Sunshine <- libvirtualhid <- game
```

Buttons, sticks, triggers, touch, motion, and battery state travel toward the
host. Rumble, Xbox Impulse Triggers, DualSense adaptive-trigger effects, and
LEDs travel back toward the client. A feature works end to end only when every
layer in its direction supports it.
host. Rumble, Steam Controller pad haptics, Xbox Impulse Triggers, DualSense
adaptive-trigger effects, and LEDs travel back toward the client. A feature
works end to end only when every layer in its direction supports it.

The capabilities advertised by a `libvirtualhid` profile describe what the
host-side virtual controller can represent. They do not guarantee that a
Expand Down Expand Up @@ -49,6 +49,10 @@ manufacturer's instructions:
[pair, use, and troubleshoot the controller](https://www.nintendo.com/my/support/switch/controller/nintendoswitchpro.html)
and
[update the controller firmware](https://en-americas-support.nintendo.com/app/answers/detail/a_id/26321/~/how-to-update-the-controller-firmware).
- Steam Controller (2026): confirm both trackpads, their clicks, all four rear
buttons, trigger clicks, stick/grip touch sensors, and both haptic actuators
locally before testing the streaming path. A generic client mapping may omit
these extended controls even when its ordinary gamepad input works.

A controller working locally proves only the physical controller-to-client
part of the path. It does not prove that an extended feature is implemented by
Expand Down
57 changes: 45 additions & 12 deletions docs/platform-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,21 @@ streams native `0x30` reports every 15 milliseconds. This coalesces separate
acceleration and gyroscope API updates into the three-sample report cadence used
by a physical USB controller.

The 2026 Steam Controller profile uses Valve's native wired USB identity and HID
descriptor. The Windows client caches normalized controller state and streams
native `0x42` reports at the controller's 4.032-millisecond cadence so sequence
and sensor timestamps advance while controls are held. Separate `0x43` battery
reports carry charge state and percentage. The driver accepts both native
feature-report channels, including the lizard-mode settings request, and can
return native-shaped attribute and string replies when queried. Native ordinary
rumble and the controller's targeted pulse, command, tone, logarithmic-sweep,
and script outputs are normalized into the creating runtime's callbacks.

For every gamepad report ID, the VHF driver caches the newest complete input
report and answers synchronous `GetInputReport` requests from that cache. This
lets Windows HID consumers retrieve the current battery state for Xbox One,
Xbox Series, DualShock 4, DualSense, and Switch Pro instead of relying only on
the asynchronous input stream.
Xbox Series, DualShock 4, DualSense, Switch Pro, and Steam Controller instead of
relying only on the asynchronous input stream.

That HID report does not change the XInput battery classification of the Xbox
One and Xbox Series VHF devices. On a Windows desktop where XInput enumerated
Expand Down Expand Up @@ -145,8 +155,8 @@ and signing details.

The Linux backend uses standard user-space kernel interfaces:

- `uhid` for descriptor-driven PlayStation, Switch Pro, Xbox One, and Xbox
Series gamepads.
- `uhid` for descriptor-driven PlayStation, Switch Pro, Steam Controller, Xbox
One, and Xbox Series gamepads.
- `uinput` for Generic and Xbox 360 gamepads, for Xbox One and Xbox Series when
`uhid` is unavailable, and for keyboard, mouse, touchscreen, trackpad, and pen
tablet devices.
Expand Down Expand Up @@ -286,6 +296,22 @@ The public acceleration and gyroscope units remain meters per second squared
and degrees per second; the packer converts them to Nintendo's coordinate
system and sensor scales.

Steam Controller (2026) also remains on Linux `uhid` so the kernel exposes its
native Valve `0x28DE:0x1302` identity, full descriptor, raw feature channels,
separate battery report, and output reports. As with Switch Pro, the Linux-only
UHID identity uses the Bluetooth bus so SDL/HIDAPI does not require a physical
USB parent; the public profile and native wired report framing stay unchanged.
State report `0x42`
carries ordinary controls, four rear buttons, digital trigger clicks,
capacitive stick and grip touch, two pressure-sensitive trackpads and their
clicks, motion, sequence, and sensor timestamp fields. The backend republishes
the latest complete state every 4.032 milliseconds and serializes periodic and
application submissions. Report `0x80` becomes ordinary two-channel rumble;
reports `0x81` through `0x85` become targeted `haptics` callbacks while keeping
their raw bytes available. The layouts and initialization behavior follow
SDL's [Steam Controller report definitions](https://github.com/libsdl-org/SDL/blob/main/src/joystick/hidapi/steam/controller_structs.h)
and [Triton HIDAPI driver](https://github.com/libsdl-org/SDL/blob/main/src/joystick/hidapi/SDL_hidapi_steam_triton.c).

Linux touchscreen and trackpad contacts use the lowest available multitouch
slot while they are active. A newly placed contact receives a new tracking ID,
including when it reuses a slot released by another contact, so replacing one
Expand Down Expand Up @@ -315,6 +341,11 @@ Mouse buttons are momentary. A delayed browser-test mode queues an action long
enough to switch focus to an external event tester, sending button actions as a
single press-and-release click.

Gamepad navigation is disabled, and keyboard navigation is enabled only while
the mouse controls are selected. Losing focus or pointer presence releases any
momentary UI-controlled buttons so virtual input cannot remain held while a
system overlay is active.

### Permissions

Linux deployment requires both device-node permissions and the kernel modules
Expand Down Expand Up @@ -401,8 +432,8 @@ The FreeBSD backend uses the native evdev compatibility stack through
FreeBSD path, and `/dev/uinput` for environments that provide the Linux-style
alias. It supports the same uinput device categories as the Linux backend:

- Generic, Xbox 360, Xbox One, Xbox Series, DualShock 4, DualSense, and Switch
Pro gamepads.
- Generic, Xbox 360, Xbox One, Xbox Series, DualShock 4, DualSense, Switch Pro,
and Steam Controller gamepads.
- Keyboard and mouse devices, with X11/XTest available as a fallback.
- Touchscreen, trackpad, and pen tablet devices.

Expand All @@ -414,16 +445,18 @@ with the kernel HID bus. FreeBSD CUSE applications such as
a `uhid(4)`-compatible character device for direct consumers, but that is a
different integration surface and is not used by the current backend.

Generic, Xbox-family, Switch Pro, DualShock 4, and DualSense behavior therefore
uses uinput. Ordinary buttons, sticks, analog triggers, and rumble are available,
but raw HID reports and descriptor-driven features are not.
Generic, Xbox-family, Switch Pro, Steam Controller, DualShock 4, and DualSense
behavior therefore uses uinput. Ordinary buttons, sticks, analog triggers, and
rumble are available, but raw HID reports and descriptor-driven features are not.

For each created gamepad, `Gamepad::profile()` reports the effective FreeBSD
uinput capability subset. Motion, touchpad contacts and click, battery state,
RGB LED output, adaptive-trigger output, and raw HID output reports are disabled.
This includes Switch Pro motion and battery state as well as the
PlayStation-specific features. Streaming-host adapters can reject those
operations instead of silently accepting state that uinput cannot expose.
This includes Switch Pro and Steam Controller motion and battery state, Steam
Controller trackpads, rear buttons, trigger clicks, capacitive sensors and
haptics, and the PlayStation-specific features. Streaming-host adapters can
reject those operations instead of silently accepting state that uinput cannot
expose.

The `uinput` kernel module and a writable uinput device node are required.

Expand Down
24 changes: 17 additions & 7 deletions docs/streaming-host-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ A streaming host should be able to:
indexes.
- Submit incremental button, axis, trigger, touchpad, motion, and battery
updates without recreating a device.
- Receive output callbacks for rumble, RGB and player LEDs, adaptive triggers,
trigger rumble, and raw output reports where the selected profile supports
them.
- Receive output callbacks for rumble, addressable haptics, RGB and player
LEDs, adaptive triggers, trigger rumble, and raw output reports where the
selected profile supports them.
- Query profile and backend capabilities before warning users about unsupported
client features.
- Read device nodes and platform paths when a downstream consumer or diagnostic
Expand Down Expand Up @@ -57,14 +57,24 @@ The core API and adapter shape cover the major streaming-host requirements:
- Rich controller metadata.
- Gamepad output callbacks.
- Keyboard and mouse input paths.
- Linux PlayStation, Switch Pro, Xbox One, and Xbox Series gamepads through
descriptor-driven `uhid`, Generic and Xbox 360 gamepads through `uinput`,
Xbox One and Xbox Series uinput fallbacks, and `uinput` keyboard/pointer
devices.
- Linux PlayStation, Switch Pro, Steam Controller, Xbox One, and Xbox Series
gamepads through descriptor-driven `uhid`, Generic and Xbox 360 gamepads
through `uinput`, Xbox One and Xbox Series uinput fallbacks, and `uinput`
keyboard/pointer devices.
- Native Switch Pro motion, initialization replies, rumble, HOME-light, and
player-light output handling on Linux and Windows descriptor-driven backends.
- Native 2026 Steam Controller state, battery, feature-report initialization,
ordinary rumble, and addressable pad-haptic handling on Linux and Windows.
- Linux DualSense and DualShock 4 USB/Bluetooth report handling.
- Linux touchscreen, trackpad, and pen tablet device types.
- FreeBSD uinput gamepads and pointer devices, with basic PlayStation input and
rumble but without Linux UHID-only PlayStation features.
- Windows UMDF/VHF gamepad creation through an installed driver package.

For Steam Controller clients, preserve both pad contacts and pressure values,
all four rear buttons, digital trigger clicks, and capacitive stick/grip touch
states instead of collapsing them into a generic controller packet. Forward
`GamepadOutputKind::haptics` separately from ordinary rumble so a client can
retain the controller's actuator target and effect parameters. A host that has
no extended haptic message may still forward `raw_report`, but should not
reinterpret addressable effects as a two-motor rumble packet.
40 changes: 32 additions & 8 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,14 @@ disabled, or mismatched entitlement invalidates the license and removes all
licensed virtual HID devices.
Purchase and account-management buttons use the compiled URLs in
`src/platform/windows/shared/lvh_windows_broker_config.hpp`.
Enable `Lock buttons` to click-to-toggle behavior for held inputs.
Enable `Lock buttons` for click-to-toggle behavior for held inputs. Momentary
buttons are released if the control window loses focus or the pointer leaves it,
preventing a system-overlay transition from leaving a button held.
The resizable window supports a compact width. Its device and control panels
stack, and the button grid reflows to keep controls usable when it is narrowed.
The UI intentionally does not use gamepad navigation, so virtual devices created
by the tool cannot drive the tool's own controls.
The UI intentionally does not open gamepads for navigation and enables keyboard
navigation only for mouse controls, so virtual gamepads created by the tool
cannot drive the tool's own controls.

External devices created by another process, such as Sunshine, are not
enumerated yet. That requires backend protocol support, so the Windows driver or
Expand Down Expand Up @@ -215,6 +218,7 @@ Built-in gamepad profiles and their platform-neutral default device names are:
| DualShock 4 USB and Bluetooth | `(libvirtualhid) PS4 Controller` |
| DualSense USB and Bluetooth | `(libvirtualhid) PS5 Controller` |
| Nintendo Switch Pro | `(libvirtualhid) Nintendo Pro Controller` |
| Steam Controller (2026) | `Steam Controller` |

Consumers may replace `DeviceProfile::name` before creating a gamepad, for
example, to prepend an application name while preserving the default controller
Expand All @@ -230,11 +234,12 @@ through 16 in the input report. Linux may still route that profile through
standard `ABS_HAT0X` and `ABS_HAT0Y` axes.

Profiles advertise support for features such as rumble, trigger rumble, RGB and
player LEDs, adaptive triggers, motion sensors, touchpads, battery state,
profile-specific buttons, and raw output reports. Consumers should query
profile and backend capabilities before warning users about unsupported client
features. Xbox One and Xbox Series advertise `supports_trigger_rumble` and
`supports_battery`; the Linux UHID Bluetooth transport preserves both
player LEDs, adaptive triggers, addressable haptics, motion sensors, touchpads,
battery state, profile-specific buttons, and raw output reports. Consumers
should query profile and backend capabilities before warning users about
unsupported client features. Xbox One and Xbox Series advertise
`supports_trigger_rumble` and `supports_battery`; the Linux UHID Bluetooth
transport preserves both
capabilities, while the uinput fallback clears them and retains ordinary
rumble. The Linux Xbox transport includes its battery descriptor only when
`CreateGamepadOptions::metadata.has_battery` is true, and it emits battery
Expand All @@ -248,3 +253,22 @@ for every profile.
The `misc1` button represents Share/Capture/Mic Mute-style controls and is
available on the generic, Xbox Series, DualSense, and Switch Pro profiles; Xbox
360 and Xbox One do not advertise that extra button.

`profiles::steam_controller_2026()` exposes Valve's wired `0x28DE:0x1302`
native profile. `touchpad_contacts[0]` is the left pad and
`touchpad_contacts[1]` is the right pad; each contact accepts normalized
position and pressure. The pad clicks use `left_touchpad` and
`right_touchpad`. `paddle1`/`paddle2` are R4/L4 and `paddle3`/`paddle4` are
R5/L5. The profile also accepts `left_trigger_click`, `right_trigger_click`,
the two stick-touch states, and the two grip-touch states in addition to the
ordinary gamepad buttons, sticks, analog triggers, motion, and battery fields.
Releasing a touchpad contact clears its active state and pressure while retaining
its last position, avoiding a spurious full-pad motion on the release report.

Steam Controller output report `0x80` is normalized to the ordinary `rumble`
callback. Native reports `0x81` through `0x85` produce `haptics` callbacks with
the selected left, right, or paired actuator and the decoded pulse, tone,
command, sweep, or script parameters. The unchanged bytes remain available in
`GamepadOutput::raw_report`. Both Windows VHF and Linux UHID also answer the
controller's two 64-byte feature-report channels used for initialization and
lizard-mode settings.
Loading
Loading