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
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ 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 Linux gamepads through `uhid`, plus keyboard, mouse,
touchscreen, trackpad, and pen tablet devices through `uinput`.
- Descriptor-driven PlayStation gamepads through Linux `uhid`; Generic, Xbox,
and Switch Pro gamepads plus keyboard, mouse, touchscreen, trackpad, and pen
tablet devices through `uinput`.
- Windows gamepads through a user-mode UMDF2 control driver backed by Virtual
HID Framework, with keyboard and mouse support through normal Win32 APIs.
- Output callbacks for profile-specific feedback such as rumble, LEDs,
Expand Down
49 changes: 43 additions & 6 deletions docs/platform-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,52 @@ and signing details.
The Linux backend uses standard user-space kernel interfaces:

- `uhid` for descriptor-driven HID gamepads.
- `uinput` for keyboard, mouse, touchscreen, trackpad, and pen tablet devices.
- `uinput` for Generic, Xbox 360, Xbox One, Xbox Series, and Switch Pro
gamepads, plus 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 prefers `uhid` because descriptors, raw HID identity, feature
reports, and output reports matter for controller compatibility. Keyboard and
pointer devices prefer `uinput` because those devices map naturally to Linux
input devices.
Gamepad support normally prefers `uhid` because descriptors, raw HID identity,
feature reports, and output reports matter for controller compatibility.
Generic, Xbox-family, and Switch Pro 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 only through `ABS_HAT0X` and
`ABS_HAT0Y`, giving consumers one unambiguous D-pad representation. Generic and
Xbox triggers remain independent analog `ABS_Z` and `ABS_RZ` axes. Switch Pro
uses the Nintendo face-button positions, button events for ZL/ZR, and `BTN_Z`
for Capture. Profiles with rumble support normalize rumble, constant, periodic,
and ramp uinput force-feedback effects back into the public callback. 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. PlayStation
`SET_REPORT` feedback restores the separately supplied UHID report number before
parsing.

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 four sparse-layout 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.

DualShock 4 and DualSense remain on `uhid` so their descriptors, motion,
touchpad, battery, feature reports, and profile-specific output reports stay
available. The backend accepts PlayStation output through both UHID interrupt
and control channels, including control reports whose report number is supplied
separately from the payload.

Switch Pro keeps its Nintendo identity on the Linux uinput path. This follows
the evdev layout used by Linux-native virtual-controller implementations and
allows standard `FF_RUMBLE` effects without emulating the physical controller's
proprietary initialization handshake.

The optional `virtualhid_control` diagnostic UI uses SDL3 and Dear ImGui through
the repository CPM lockfile. It is intended to stay on the same UI framework for
Expand Down Expand Up @@ -87,7 +124,7 @@ KERNEL=="hidraw*", ATTRS{name}=="Your App Controller*", GROUP="input", MODE="066
SUBSYSTEMS=="input", ATTRS{name}=="Your App Controller*", GROUP="input", MODE="0660", TAG+="uaccess"
```

For `uhid` gamepad support, install a modules-load entry such as
For descriptor-driven `uhid` gamepad support, install a modules-load entry such as
`/etc/modules-load.d/60-libvirtualhid.conf`:

```text
Expand Down
3 changes: 2 additions & 1 deletion docs/streaming-host-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ The core API and adapter shape cover the major streaming-host requirements:
- Rich controller metadata.
- Gamepad output callbacks.
- Keyboard and mouse input paths.
- Linux `uhid` gamepads and `uinput` keyboard/pointer devices.
- Linux PlayStation gamepads through `uhid`, Generic/Xbox/Switch Pro gamepads
through `uinput`, and `uinput` keyboard/pointer devices.
- Linux DualSense and DualShock 4 USB/Bluetooth report handling.
- Linux touchscreen, trackpad, and pen tablet device types.
- Windows UMDF/VHF gamepad creation through an installed driver package.
Expand Down
27 changes: 18 additions & 9 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,17 +164,26 @@ touch, motion, battery, feedback, and lifecycle updates onto the platform-neutra

## Built-In Profiles

Built-in gamepad profiles include:

- Generic HID gamepad.
- Xbox 360.
- Xbox One.
- Xbox Series.
- DualShock 4 USB and Bluetooth.
- DualSense USB and Bluetooth.
- Nintendo Switch Pro.
Built-in gamepad profiles and their platform-neutral default device names are:

| Profile | Default device name |
| --- | --- |
| Generic HID gamepad | `(libvirtualhid) Generic Controller` |
| Xbox 360 | `(libvirtualhid) X-Box 360 Controller` |
| Xbox One | `(libvirtualhid) X-Box One Controller` |
| Xbox Series | `(libvirtualhid) X-Box Series Controller` |
| DualShock 4 USB and Bluetooth | `(libvirtualhid) PS4 Controller` |
| DualSense USB and Bluetooth | `(libvirtualhid) PS5 Controller` |
| Nintendo Switch Pro | `(libvirtualhid) Nintendo Pro Controller` |

Consumers may replace `DeviceProfile::name` before creating a gamepad, for
example to prepend an application name while preserving the default controller
identity across platform backends.

Profiles advertise support for features such as rumble, trigger rumble, RGB
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.
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.
5 changes: 4 additions & 1 deletion src/core/backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ namespace lvh::detail {
*/
class FakeGamepad final: public BackendGamepad {
public:
OperationStatus submit(const std::vector<std::uint8_t> & /*report*/) override {
OperationStatus submit(
const GamepadState & /*state*/,
const std::vector<std::uint8_t> & /*report*/
) override {
return OperationStatus::success();
}

Expand Down
8 changes: 6 additions & 2 deletions src/core/backend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,16 @@ namespace lvh::detail {
virtual ~BackendGamepad() = default;

/**
* @brief Submit a packed input report to the backend.
* @brief Submit normalized state and its packed input report to the backend.
*
* HID backends consume @p report, while native platform input backends may
* consume @p state.
*
* @param state Normalized gamepad state.
* @param report Packed HID input report.
* @return Submit status.
*/
virtual OperationStatus submit(const std::vector<std::uint8_t> &report) = 0;
virtual OperationStatus submit(const GamepadState &state, const std::vector<std::uint8_t> &report) = 0;

/**
* @brief Get platform-visible nodes associated with this backend device.
Expand Down
4 changes: 2 additions & 2 deletions src/core/gamepad_adapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ namespace lvh {
using enum GamepadProfileKind;

case generic:
case xbox_360:
case xbox_one:
case xbox_series:
case dualsense:
case switch_pro:
return true;
case xbox_360:
case xbox_one:
case dualshock4:
return false;
}
Expand Down
Loading
Loading