Skip to content

Latest commit

 

History

History
283 lines (240 loc) · 56.5 KB

File metadata and controls

283 lines (240 loc) · 56.5 KB

End-User Gamepad Guide

This page is for people using an application that embeds libvirtualhid, such as Sunshine. You do not normally run or configure libvirtualhid directly. The streaming host uses it to create the virtual controller that Windows, Linux, FreeBSD, Steam, and games see.

Understand the Input Path

Standard input and controller-specific features must pass through several independent layers:

physical controller -> Moonlight client -> Sunshine -> libvirtualhid -> game
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.

The capabilities advertised by a libvirtualhid profile describe what the host-side virtual controller can represent. They do not guarantee that a Moonlight client can read the feature from the physical controller, transmit it, or play feedback on the client device. The game and any compatibility layer, such as Steam Input, must support the feature too.

Prepare the Physical Controller

Before troubleshooting the stream, update the controller firmware and confirm that ordinary buttons and sticks work on the client device. Use the controller manufacturer's instructions:

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 that Moonlight client.

Configure Sunshine

Use the current Sunshine and Virtual HID Driver versions recommended by the Sunshine release you installed. On Windows, the Virtual HID Driver must be installed and have a valid machine license before Sunshine can create a driver-backed controller. After installing or updating the driver, restart Windows.

In Sunshine's Web UI, confirm that controller input is enabled and review the selected virtual gamepad under Configuration > Input. auto lets Sunshine choose a host-side profile from the features reported by the client. Selecting a profile manually changes what the game sees; it cannot add data that the client did not send.

Restart Sunshine, then reconnect the stream after changing the profile or updating the client, host, or driver. Sunshine creates the virtual gamepad for the streaming session.

See the Sunshine documentation for the current host-specific setup:

End-to-End Compatibility

These results describe the complete path through a Moonlight client, Sunshine, libvirtualhid, and the selected host backend. They do not describe what a Moonlight client can support by itself.

Moonlight is available as several clients with platform-specific input implementations. Their controller behavior can differ because the client platform, operating-system input APIs, controller connection, and Moonlight implementation expose different capabilities. Results from one client device should not be treated as proof for another, even when both run Android or use the same physical controller.

These observations are snapshots, not a permanent compatibility guarantee. The feature rows include the controller capabilities relevant to streaming, including manufacturer-specific features that are not yet implemented end to end. ✅ means that the complete path was observed working, ❌ means that it did not work, ❓ means that it was not tested, and ➖ means that the client does not support that virtual profile.

Compatibility Matrix

The backend columns use Moonlight Qt as the common test client. The client columns compare the existing Windows Virtual HID Driver results.

Feature Backend: Windows via Virtual HID Driver Backend: Linux via libvirtualhid Client: Moonlight Qt Client: Moonlight Android Client: Moonlight iOS Client: Moonlight Xbox
Xbox 360
Standard buttons, sticks, and D-pad
Analog trigger input (0 to 1)
Basic rumble
Xbox One
Standard buttons, sticks, and D-pad
Analog trigger input (0 to 1)
Basic rumble
Impulse Triggers 11 15
Battery state 4 4 4 4 4 4
Xbox Series
Standard buttons, sticks, and D-pad
Analog trigger input (0 to 1)
Basic rumble
Impulse Triggers 11 15
Battery state
Share button 3 8 3 3 3 3
DualShock 4
Standard buttons, sticks, and D-pad
Analog trigger input (0 to 1)
Basic rumble 5
Motion/gyro 1 15
Touchpad position 2 15
Touchpad click 2 15
Light bar (RGB/player color) 6 15
Battery state
DualSense
Standard buttons, sticks, and D-pad
Analog trigger input (0 to 1)
Basic rumble 5
Motion/gyro 1
Touchpad position 2 15
Touchpad click 2 15
Light bar (RGB) 6 15
Battery state
Adaptive triggers 12 12 12 2
Player indicator 7 7 7 7
MUTE button
MUTE button LED 7 7 7 7
Nintendo Switch Pro Controller
Standard buttons, sticks, and D-pad
Digital trigger input (0 or 1)
Basic rumble
Motion/gyro 9 17 9
Battery state
HOME LED 16 16 16
Player LED 14 14 14 14 14
Capture button 10 15

When a backend is marked ❌, that path cannot establish whether an additional client-side limitation exists. The owner below identifies the first known layer that prevents the feature from working end to end.

Note Owner Limitation or status Tracker or reference
1 Client platform Moonlight Android exposes gamepad motion on Android 12 or later when motion is enabled and the Android device exposes the controller sensors. Available settings can differ between devices. Moonlight Android motion settings
2 Client platform Android may expose a PlayStation touchpad as a mouse instead of a native controller touchpad. Leave Gamepad touchpad as mouse disabled when native forwarding is available. DualSense support requires Android 12 or later, and Sony documents that adaptive triggers are unavailable on Android mobile devices. Sony Android requirements and Moonlight Android touchpad handling
3 Windows host backend Steam does not expose the Xbox Series Share button through Virtual HID Driver on Windows. libvirtualhid issue #106
4 Host profile The Xbox One profile rejects battery updates independently of the client. libvirtualhid issue #107
5 Client platform and external consumer Android rumble depends on device vibration APIs and compatible motors. Steam may not dispatch PlayStation rumble until its controller settings or calibration page initializes the controller. Moonlight Android vibration handling, libvirtualhid issue #80, and Steam for Linux issue #13435
6 Client platform Moonlight Android uses the RGB lights API available on Android 12 or later. It worked on tested newer devices but was unavailable on NVIDIA Shield running Android 11. Moonlight Android RGB-light detection
7 Host output pipeline DualSense player-indicator and MUTE-button LED forwarding is covered by open host pull requests. This note applies only to the LEDs; the MUTE button input works through both host backends with Moonlight Qt. When a DualSense is connected to Android, its physical MUTE-button LED works locally, but that LED state is not forwarded to the virtual controller on the host. libvirtualhid pull request #97 and Sunshine pull request #5537
8 Linux host backend Steam exposes the Xbox Series Share button through the Linux uinput device, but pressing it does not change the button state. libvirtualhid issue #110
9 Windows host validation A physical Switch Pro connected to Moonlight Qt v6.1.0 on Windows delivered gyro through Sunshine on Linux, but the same client and controller did not deliver usable gyro through Sunshine on Windows. The Windows installed-driver SDL3 test receives live virtual Switch motion, so the failure is specific to the Windows VHF-to-Steam path rather than Moonlight's sensor transport. Neither advancing only the full-state counter nor unifying the counter across input and subcommand replies fixed Steam. The Windows client backend now caches separate motion updates and streams one complete native input report every 15 milliseconds; another Windows Steam retest is required. libvirtualhid issue #111
10 Client Moonlight Android exposes the tested Switch Pro Capture input as A instead of Capture. A broader Android Switch Pro mapping issue exists, but the exact Capture symptom is not explicitly tracked. Moonlight Android issue #842
11 Host backend The Linux uinput/evdev Xbox One and Xbox Series profiles support basic rumble but cannot deliver independent Impulse Triggers. libvirtualhid issue #109
12 Client and protocol; resolved upstream, unreleased Moonlight Qt adaptive-trigger support and its protocol and Sunshine dependencies are merged, but the latest published Moonlight Qt release predates them. The feature has not yet been validated with these backends. Moonlight Qt pull request #1561, moonlight-common-c pull request #102, Sunshine pull request #3738, and Moonlight Qt v6.1.0
13 Linux host backend The Linux backend uses descriptor-driven UHID for Switch Pro, advertises a backend-only Bluetooth transport identity that SDL2 HIDAPI accepts for virtual devices, answers its initialization protocol, and carries live native motion reports. Motion and battery were validated end to end from Moonlight Qt v6.1.0 on Windows through Sunshine on Linux into Steam. libvirtualhid issue #112 and closed Sunshine issue #3838
14 Streaming host and client output pipeline Both host backends decode Switch Pro Set Player Lights output into solid and flashing player-indicator callbacks, and Sunshine can serialize those masks through its proposed protocol extension. Released moonlight-common-c and Moonlight clients do not consume that extension, so testing with Moonlight Qt v6.1.0 leaves the physical player LEDs unchanged on both host backends. libvirtualhid issue #113 and Sunshine player-LED integration
15 Client platform and version The marked features worked when tested with Moonlight on an iPhone running iOS 18.7.10, but did not work on an Apple TV 4K running tvOS 26.6. Moonlight enables these extended features only when Apple's Game Controller framework exposes the corresponding buttons, haptics localities, motion sensors, or light. Moonlight capability detection, Apple controller-haptics capabilities, and Apple controller-motion capabilities
16 Client capability and output pipeline Both host backends decode Switch Pro Set HOME Light output as a grayscale LED callback. Moonlight Qt v6.1.0 uses SDL2's RGB-style LED capability check, and the tested controller reported no LED. Moonlight Qt master uses SDL3 through sdl2-compat; SDL3 identifies HOME as a mono LED, but the compatibility check maps only the RGB capability. Neither path advertises LED support to Sunshine, so it never sends the HOME-light command. Moonlight Qt LED capability check, SDL Switch HOME-light capability, and sdl2-compat LED mapping
17 Moonlight Android controller lifecycle With Moonlight Android v12.1 on Android 14, a USB Switch Pro repeatedly disconnected and reconnected in Steam through Sunshine on Linux, and opening Steam's gyro-calibration page triggered an immediate disconnect. Enabling motion makes Moonlight register Android input-device sensor listeners, while Android device removal is forwarded immediately. An Android event log is still needed to prove whether sensor activation causes remove/add events; issue #1497 separately tracks incorrect type handling for sensor-capable Nintendo controllers. Moonlight Android v12.1 sensor handling, device removal handling, and Moonlight Android issue #1497

Analog trigger input reports intermediate values between 0 and 1. Switch Pro ZL/ZR input is digital and reports only 0 or 1. Trigger input is also separate from feedback: basic rumble, Xbox Impulse Triggers, and DualSense adaptive triggers are distinct features. One working does not imply that the others work. Likewise, a client may forward motion while omitting battery or LED data.

Troubleshoot by Symptom

The host does not see a controller

  1. Confirm that the physical controller works on the client before starting Moonlight.
  2. Confirm that controller input is enabled in Sunshine.
  3. On Windows, check the Virtual HID Driver version and license status on Sunshine's Troubleshooting page.
  4. End and reconnect the stream, then check whether the host operating system sees a newly created controller.
  5. Review the Sunshine log for controller creation, driver, permission, or license errors.

On Windows, joy.cpl is useful for checking ordinary buttons, sticks, and triggers. Browser testers, Steam, and individual games use different controller APIs and mappings, so do not use any one of them as the only compatibility test.

Buttons work but an extended feature does not

  1. Identify the direction of the missing feature. Motion and touch travel from the client to the host; rumble and LEDs travel from the game back to the client.
  2. Check whether the physical-controller vendor documents the feature for the client operating system and USB or Bluetooth connection being used.
  3. Check the client-specific observations above and the issue tracker for that Moonlight client.
  4. Confirm that Sunshine selected a virtual profile that represents the feature. A game seeing an Xbox controller will not gain PlayStation motion or adaptive-trigger support.
  5. Test with a game or tool known to use that exact feature. Standard rumble is not a valid test for Xbox Impulse Triggers or DualSense adaptive triggers.
  6. If Steam is involved, test once with Steam Input enabled and once with it disabled. Record which path works instead of treating Steam calibration or remapping as a driver fix.

The controller works in Steam but not in a game

The game may support a different controller API or profile than Steam. Check the game's controller requirements, try Steam Input both enabled and disabled, and verify that the Sunshine virtual-gamepad selection matches a controller the game supports. Disconnect unused host-side controllers if the game always opens the first controller slot.

Gyro, LEDs, or rumble do not work in Steam

Steam may need a one-time gyro calibration before its controller tester or Steam Input fully initializes a virtual DualShock 4 or DualSense controller's gyro, light bar, and rumble. Open Steam's controller settings and complete the gyro calibration, then test the features again. This has only been observed with Steam's handling of virtual DualShock 4 and DualSense controllers and may be a Steam bug rather than a remaining controller-protocol failure. See ValveSoftware/steam-for-linux issue #13435 for a related DualSense rumble report.

For Switch Pro, first confirm that rumble is enabled in the game and complete Steam's controller setup or calibration once. A reported Linux test began receiving rumble after the game-side rumble option was enabled; that observation does not establish that every game or Steam configuration uses the same output path.

If Steam repeatedly treats the virtual controller as a new device, disabling Sunshine's Randomize virtual controller MAC option may help it retain the controller's calibration and settings. Restart Sunshine and reconnect the stream after changing the option. A stable MAC can cause different physical controllers that reuse the same client controller slot to share Steam's per-controller settings.

Report a Compatibility Problem

Include enough information to identify which layer failed:

  • Moonlight client name and exact version.
  • Client device, operating-system version, and whether the controller uses USB, Bluetooth, a wireless adapter, or a built-in connection.
  • Physical controller model and firmware version.
  • Sunshine version, host operating system, and selected virtual-gamepad profile.
  • Virtual HID Driver version on Windows.
  • Game or test tool, whether Steam Input is enabled, and whether standard input works.
  • The exact missing feature and its direction, such as Switch Pro motion to the host or Xbox Impulse Triggers back to the client.
  • Relevant Sunshine logs and a comparison with another Moonlight client, when available.

Report client capture or playback problems to the relevant Moonlight client. Report streaming-session mapping or forwarding problems to Sunshine. Report a libvirtualhid issue when the same host-side virtual profile can be reproduced without Moonlight and Sunshine, or when Sunshine logs show the expected data reaching the library but the virtual device reports it incorrectly.

The Moonlight setup guide links the official clients and their support resources.