Skip to content

Latest commit

 

History

History
300 lines (254 loc) · 78.4 KB

File metadata and controls

300 lines (254 loc) · 78.4 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. A 🟡 means the feature may be supported in a dev build or future release of the client.

Compatibility Matrix

The backend columns summarize host-backend capability across the recorded tests. The client columns record client-specific results; footnotes identify platform, version, connection, or host-backend qualifiers.

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 1 2
Battery state 8 3 9 9 10 🟡20
Xbox Series
Standard buttons, sticks, and D-pad
Analog trigger input (0 to 1)
Basic rumble
Impulse Triggers 1 2
Battery state 8 3 9 9 10 🟡20
Share button 11 🟡21 🟡22
DualShock 4
Standard buttons, sticks, and D-pad
Analog trigger input (0 to 1)
Basic rumble 4 4 5
Motion/gyro 6 2
Touchpad position 12 2
Touchpad click 12 2
Light bar (RGB/player color) 7 2
Battery state 8
DualSense
Standard buttons, sticks, and D-pad
Analog trigger input (0 to 1)
Basic rumble 4 4 5
Motion/gyro 6
Touchpad position 12 2
Touchpad click 12 2
Light bar (RGB) 7 2
Battery state 8
Adaptive triggers 24 🟡23 12
Player indicator 13 13
MUTE button
MUTE button LED 13 13 14
Nintendo Switch Pro Controller
Standard buttons, sticks, and D-pad
Digital trigger input (0 or 1)
Basic rumble
Motion/gyro
Battery state 8
HOME LED 15 15 16
Player LED 17 17 18 18 18
Capture button 19 2

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 connection and settings Xbox Series Impulse Triggers worked when the physical gamepad was connected to the Android client over USB and Override native Xbox gamepad support was enabled. They did not work with the same gamepad connected over Bluetooth. The successful USB override path does not establish a minimum Android version. For the native input-device path, Moonlight's four-vibrator detection requires Android 12 (API level 31) or later. Moonlight Android USB override setting, trigger-rumble routing, Xbox USB output packet, and native four-vibrator gate
2 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
3 Linux host backend and external consumer Testing with the battery-capable Moonlight Xbox build through Sunshine on Linux confirmed that the virtual Xbox controller exposes the reported battery level through the Linux power-supply interface. The tested Steam client still did not display that battery level.
4 Host and external consumer Steam may not dispatch PlayStation rumble until its controller settings or calibration page initializes the controller. libvirtualhid issue #80 and Steam for Linux issue #13435
5 Client platform Android rumble depends on device vibration APIs and compatible motors. Moonlight Android vibration handling
6 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
7 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
8 Windows host backend and external consumers Current source carries battery updates through Windows HID input reports, and SDL3 consumer tests receive the Windows DualShock 4, DualSense, and Switch Pro values. The current Steam client hides its battery indicator for Windows VHF devices because it only renders the indicator for controllers classified as Bluetooth or wireless, while VHF exposes a wired virtual transport. For Xbox, a tested Windows desktop returned disconnected/empty from XInputGetBatteryInformation even while XInputGetState received the controller, while headless Windows CI did not expose an XInput slot for the same device; neither path exposes the submitted remote battery through XInput. Steam also did not show battery for the tested physical Xbox Series controller; Windows Game Bar showed its Bluetooth battery but not the virtual controller. libvirtualhid issue #107, XInput battery information, and Virtual HID Framework configuration
9 Client battery reporting Moonlight Qt and Android did not forward Xbox One or Xbox Series battery state in the recorded tests. libvirtualhid issue #107
10 Client platform In the recorded iOS tests, Xbox One and Xbox Series battery reporting remained at 100% even when the physical controller's actual charge was substantially lower. Moonlight iOS battery reporting
11 Windows host backend Steam does not expose the Xbox Series Share button through Virtual HID Driver on Windows. libvirtualhid issue #106
12 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
13 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. libvirtualhid pull request #97 and Sunshine pull request #5537
14 Client platform 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
15 Host output callback Both host backends decode Switch Pro Set HOME Light output as a grayscale LED callback. End-to-end output remains unavailable because no tested client advertised compatible HOME-light support to Sunshine. libvirtualhid Switch Pro output handling
16 Client capability and output pipeline 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 Host 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. The full host-to-client path is not available in released software. libvirtualhid issue #113 and Sunshine player-LED integration
18 Client output protocol Released moonlight-common-c and Moonlight clients do not consume the Switch Pro player-light extension, so testing with Moonlight Qt v6.1.0 leaves the physical player LEDs unchanged. libvirtualhid issue #113 and Sunshine player-LED integration
19 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
20 Client battery reporting The changes in Moonlight Xbox pull request #291 forward the physical controller's battery capability and charge updates. The released client does not yet include this support. Moonlight Xbox pull request #291
21 Client platform, version, and connection Moonlight Qt v6.1.0 on Windows did not forward Share from the tested Xbox Series controller to a Linux host, while Moonlight Android forwarded Share through the same host backend. The Bluetooth test log identified the controller as 045e:0b13, but its SDL mapping omitted misc1. Moonlight Qt already maps SDL_CONTROLLER_BUTTON_MISC1 to the Moonlight MISC_FLAG, so the observed failure is in the released client's SDL2 Windows controller mapping or input path, not in the streaming protocol, Sunshine, or the Linux libvirtualhid backend. Moonlight Qt master has moved to SDL3 through sdl2-compat, but that unreleased path has not been tested here. Moonlight Qt v6.1.0 gamepad mapping, Moonlight Qt v6.1.0 release, and SDL Xbox Series Share mapping issue
22 Client platform On the tested Xbox console, the Xbox operating system captured the Share button instead of delivering it to Moonlight Xbox. The client reads Windows.Gaming.Input.GamepadReading, whose GamepadButtons bitfield has no Share value, so Moonlight Xbox cannot forward this input to Sunshine. Moonlight Xbox pull request #289, Moonlight Xbox gamepad-reading path, and Windows GamepadButtons
23 Client release Moonlight Qt adaptive-trigger support and its protocol and Sunshine dependencies are merged, but the latest published Moonlight Qt release predates them. Moonlight Qt pull request #1561, moonlight-common-c pull request #102, Sunshine pull request #3738, and Moonlight Qt v6.1.0
24 Windows host backend Adaptive triggers have not been validated end to end through the Windows backend with the merged Moonlight and Sunshine protocol path. Moonlight Qt pull request #1561, moonlight-common-c pull request #102, and Sunshine pull request #3738

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.

Previous Next
Overview Usage and API