Skip to content
Draft
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
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,17 @@ behind backend implementations.

- Gamepad profiles for generic HID, Xbox 360, Xbox One, Xbox Series,
DualShock 4, DualSense, and Nintendo Switch Pro-style controllers.
- Descriptor-driven PlayStation and Switch Pro gamepads through Linux `uhid`;
Generic and Xbox gamepads plus keyboard, mouse, touchscreen, trackpad, and
pen tablet devices through `uinput`.
- Descriptor-driven PlayStation and Switch Pro gamepads, plus Xbox One and Xbox
Series GIP transports, 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 a user-mode
UMDF2 control driver backed by Virtual HID Framework, with Win32 keyboard and
mouse fallbacks when the licensed driver path is unavailable.
- Output callbacks for profile-specific feedback such as rumble, RGB and player
LEDs, adaptive triggers, and raw HID output reports when available.
- 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.
- 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
34 changes: 17 additions & 17 deletions docs/end-user-gamepad-guide.md

Large diffs are not rendered by default.

85 changes: 56 additions & 29 deletions docs/platform-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,30 +109,49 @@ and signing details.

The Linux backend uses standard user-space kernel interfaces:

- `uhid` for descriptor-driven PlayStation and Switch Pro gamepads.
- `uinput` for Generic, Xbox 360, Xbox One, and Xbox Series gamepads, plus
keyboard, mouse, touchscreen, trackpad, and pen tablet devices.
- `uhid` for descriptor-driven PlayStation and Switch Pro gamepads and for Xbox
One and Xbox Series GIP transports.
- `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.
- `libevdev` internally for uinput device construction.
- X11/XTest only as a keyboard and mouse fallback when `uinput` cannot be used
and an X11 session is available.

Gamepad support normally prefers `uhid` because descriptors, raw HID identity,
feature reports, and output reports matter for controller compatibility.
Generic and Xbox-family profiles instead use `uinput` so SDL,
Steam, browser Gamepad API implementations, and other evdev consumers receive
canonical Linux gamepad events. Face buttons, shoulders, menu buttons, stick
clicks, and Guide use their native evdev codes; sticks use absolute axes. Every
uinput gamepad exposes its directional pad through `ABS_HAT0X` and `ABS_HAT0Y`.
Generic and Xbox triggers remain independent analog `ABS_Z` and `ABS_RZ` axes.
Profiles with rumble support normalize rumble, constant, periodic, and ramp
uinput force-feedback effects back into the public callback. Each requested playback repetition
restarts the effect's ramp and envelope timing. A zero-length effect remains
active until its explicit stop event, matching the infinite-effect contract used
by SDL and Steam. The Linux backend lets a new uinput device settle before
reading those effects, so an early poll error cannot disable feedback for the
device lifetime. Generated UHID nodes are correlated by stable physical and
unique identifiers when available, with device-name matching used only as a
fallback. PlayStation rumble is read from native UHID interrupt-channel output
feature reports, and output reports matter for controller compatibility. Xbox
One and Xbox Series use a minimal Game Pad application collection containing
only opaque vendor reports to create a `hidraw` transport. The application usage
allows HIDAPI gamepad drivers to discover the device, while the absence of
generic button and axis fields prevents Linux from interpreting the GIP payload
as an unrelated evdev controller. Controller identity, initialization, input,
Guide, and four-motor output are carried as Game Input Protocol (GIP) packets,
allowing HIDAPI consumers to expose both ordinary and trigger rumble.
The UHID transport is tagged as Bluetooth because Linux HIDAPI implementations
require a physical USB parent for `BUS_USB` hidraw devices, which a user-space
UHID device cannot provide. The Microsoft vendor/product identity still selects
SDL's wired GIP parser and does not change the public profile's USB identity.

Generic and Xbox 360 profiles use `uinput` so SDL, Steam, browser Gamepad API
implementations, and other evdev consumers receive canonical Linux gamepad
events. Xbox One and Xbox Series use the same path only as a fallback when
`/dev/uhid` cannot be opened or initialized. Face buttons, shoulders, menu
buttons, stick clicks, and Guide use their native evdev codes; sticks use
absolute axes. Every uinput gamepad exposes its directional pad through
`ABS_HAT0X` and `ABS_HAT0Y`. Generic and Xbox triggers remain independent analog
`ABS_Z` and `ABS_RZ` axes. Profiles with rumble support normalize rumble,
constant, periodic, and ramp uinput force-feedback effects back into the public
callback. Each requested playback repetition restarts the effect's ramp and
envelope timing. A zero-length effect remains active until its explicit stop
event, matching the infinite-effect contract used by SDL and Steam. The Linux
backend lets a new uinput device settle before reading those effects, so an
early poll error cannot disable feedback for the device lifetime.

Generated UHID nodes are correlated by stable physical and unique identifiers
when available, with device-name matching used only as a fallback. UHID
identities include the virtual profile's vendor and product IDs so applications
do not reuse metadata from another profile after the same virtual slot changes
profiles. PlayStation rumble is read from native UHID interrupt-channel output
reports.

The Generic profile keeps its public `0x1209:0x0001` identity, USB bus, and
Expand All @@ -142,16 +161,24 @@ which avoids changing the raw button capability surface. It uses a compact
Generic button layout rather than the sparse Xbox button slots.

Xbox 360 retains its `0x045E:0x028E` identity, while its Linux uinput device uses
the Bluetooth bus, so consumers select the sparse button mapping.
Xbox One and Xbox Series retain their public USB identities, but their Linux
uinput devices use the corresponding Bluetooth product identities (`0x0B20`
and `0x0B13`, respectively), whose standard consumer mappings match the events
that uinput exposes. Those three Xbox profiles preserve the 15-slot
Linux gamepad button sequence: unused `BTN_C`, `BTN_Z`, `BTN_TL2`, and `BTN_TR2`
slots are advertised but never pressed, keeping face buttons, shoulders, menu
buttons, Guide, L3, and R3 at their expected indices. D-pad directions are
reported through the hat axes and exposed as logical buttons by standard
gamepad consumers.
the Bluetooth bus, so consumers select the sparse button mapping. The Xbox One
and Xbox Series UHID transports retain their public USB identities and speak
wired GIP over `hidraw`. They announce their identity, answer GIP metadata
requests, send canonical low-latency input and separate Guide packets, and
decode direct-motor output into ordinary and independent trigger-rumble
callbacks.

If UHID is unavailable, the Xbox One and Xbox Series uinput fallbacks use the
corresponding Bluetooth product identities (`0x0B20` and `0x0B13`, respectively),
whose standard consumer mappings match the events that uinput exposes. The Xbox
uinput profiles preserve the 15-slot Linux gamepad button sequence: unused
`BTN_C`, `BTN_Z`, `BTN_TL2`, and `BTN_TR2` slots are advertised but never
pressed, keeping face buttons, shoulders, menu buttons, Guide, L3, and R3 at
their expected indices. D-pad directions are reported through the hat axes and
exposed as logical buttons by standard gamepad consumers. The fallback retains
all of those controls, analog trigger input, and ordinary force feedback, but
Linux uinput cannot expose independent trigger motors, so its effective profile
clears trigger-rumble support.

DualShock 4 and DualSense remain on `uhid` so their descriptors, motion,
touchpad, battery, feature reports, and profile-specific output reports stay
Expand Down
6 changes: 4 additions & 2 deletions docs/streaming-host-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@ 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 and Switch Pro gamepads through `uhid`, Generic/Xbox
gamepads through `uinput`, and `uinput` keyboard/pointer devices.
- Linux PlayStation and Switch Pro gamepads plus Xbox One and Xbox Series GIP
transports through `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.
- Linux DualSense and DualShock 4 USB/Bluetooth report handling.
Expand Down
4 changes: 3 additions & 1 deletion docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,9 @@ 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.
features. Xbox One and Xbox Series advertise `supports_trigger_rumble`; the
Linux UHID GIP transport preserves that capability, while the uinput fallback
clears it and retains ordinary rumble.
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.
1 change: 1 addition & 0 deletions src/core/gamepad_adapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ namespace lvh {
}

support.supports_rumble = profile.capabilities.supports_rumble;
support.supports_trigger_rumble = profile.capabilities.supports_trigger_rumble;
support.supports_rgb_led = profile.capabilities.supports_rgb_led;
support.supports_adaptive_triggers = profile.capabilities.supports_adaptive_triggers;
support.supports_player_leds = profile.capabilities.supports_player_leds;
Expand Down
6 changes: 5 additions & 1 deletion src/core/profiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1958,7 +1958,11 @@ namespace lvh::profiles {
profile.output_report_size = pid_rumble_payload_size;
profile.name = std::move(name);
profile.manufacturer = "Microsoft";
profile.capabilities = {.supports_rumble = true, .supports_battery = include_share_button};
profile.capabilities = {
.supports_rumble = true,
.supports_trigger_rumble = true,
.supports_battery = include_share_button,
};
profile.report_descriptor = make_xbox_gip_report_descriptor(include_share_button);
return profile;
}
Expand Down
5 changes: 5 additions & 0 deletions src/include/libvirtualhid/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,11 @@ namespace lvh {
*/
bool supports_rumble = false;

/**
* @brief Whether the profile supports independent trigger rumble output.
*/
bool supports_trigger_rumble = false;

/**
* @brief Whether the profile exposes motion sensors.
*/
Expand Down
Loading
Loading