Skip to content

Fix Sunshine/Apollo virtual DualSense mapping on Linux (triggers read as right stick) - #263

Open
TechnicallyComputers wants to merge 1 commit into
JRickey:mainfrom
TechnicallyComputers:hotfix/sunshine-virtual-dualsense-linux
Open

Fix Sunshine/Apollo virtual DualSense mapping on Linux (triggers read as right stick)#263
TechnicallyComputers wants to merge 1 commit into
JRickey:mainfrom
TechnicallyComputers:hotfix/sunshine-virtual-dualsense-linux

Conversation

@TechnicallyComputers

@TechnicallyComputers TechnicallyComputers commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

This fixes an issue with trigger axes for Moonlight/Apollo/Sunshine's virtual DualSense controller spoofing a ps5 to have proper input handling, instead of treating L/R trigger axes as right analog stick.

Symptom

Playing over Moonlight with Sunshine's virtual DualSense on a Linux host, both triggers drive the right analog stick and the right stick drives the triggers. Face buttons are wrong too: a reads circle, x reads cross, and guide/leftstick/rightstick land on R3/PS/L3.

It's not the client-side hardware — it reproduces with every physical controller attached to the streaming client, and evtest on the host shows the axes reported correctly.

Root cause

Sunshine creates its virtual DualSense through uhid, so it enumerates as a genuine HID device — bus 0x0005 (Bluetooth), Sony's real DualSense VID/PID 054c:0ce6 — but with bcdDevice = 0x8111.

A physical Bluetooth DualSense reports 0x8100, which matches the existing gamecontrollerdb.txt entry. 0x8111 matches nothing, so SDL falls back to its built-in PS5 mapping — and that fallback assumes hid-generic descriptor order.

Modern kernels bind hid-playstation instead, which normalizes the axes to ABS_X/Y/Z/RX/RY/RZ. The two layouts disagree exactly where it hurts:

Built-in mapping says hid-playstation actually reports Result
rightx:a2 ABS_Z = L2 left trigger → right stick X
righty:a5 ABS_RZ = R2 right trigger → right stick Y
lefttrigger:a3 ABS_RX right stick → left trigger
righttrigger:a4 ABS_RY right stick → right trigger

This is Linux-only because osContInit sets SDL_HINT_JOYSTICK_HIDAPI=0 there (issue #193 — udev stall plus rumble regressions), so gamepads arrive over evdev. On Windows the HIDAPI PS5 driver parses the HID reports itself and never sees the kernel's axis numbering, so it's unaffected.

The fix

One platform:Linux entry for 054c:0ce6 version 0x8111 matching the hid-playstation layout. No code changes.

The CRC field is deliberately zeroed so the entry matches on VID/PID/version regardless of the device name string — Sunshine forks that keep the same uhid emulation are covered even if they rename the pad.

Verification

Loaded the repo's gamecontrollerdb.txt through SDL_GameControllerAddMappingsFromFile with SDL_JOYSTICK_HIDAPI=0 — the same call and hint state osContInit uses — and confirmed SDL resolves this entry for the live device instead of its built-in fallback. Gameplay then confirmed by hand over Moonlight: sticks, triggers, and face buttons all correct.

Environment: kernel 7.1.4, SDL 2.32.70, Sunshine virtual DualSense.

Scope note

Verified against Sunshine. Apollo is a Sunshine fork and inherits the same uhid emulation, so it should present identical IDs, but I have not confirmed that on real hardware. Sunshine's virtual DS4 and X360 pads were not tested and may have the same version-mismatch problem.

…t stick)

Sunshine and its Apollo fork create their virtual DualSense through uhid, so
it enumerates as a real HID device: bus 0x0005 (Bluetooth), Sony's genuine
DualSense VID/PID 054c:0ce6 -- but bcdDevice 0x8111. A physical Bluetooth
DualSense reports 0x8100 and matches the existing gamecontrollerdb entry;
0x8111 matches nothing, so SDL falls back to its built-in PS5 mapping.

That fallback assumes hid-generic descriptor order (a2=RX, a3=L2, a4=R2,
a5=RY). Modern kernels bind hid-playstation instead, which normalizes the
axes to ABS_X/Y/Z/RX/RY/RZ -- a2=L2, a3=RX, a4=RY, a5=R2. The built-in
mapping therefore reads both triggers as the right analog stick and the
right stick as the triggers. Face buttons are wrong too: `a` reads circle,
`x` reads cross, and guide/leftstick/rightstick point at R3/PS/L3.

This only bites on Linux because osContInit sets SDL_HINT_JOYSTICK_HIDAPI=0
there (issue JRickey#193), so gamepads arrive over evdev rather than SDL's HIDAPI
PS5 driver -- the latter parses the HID reports itself and never sees the
kernel's axis numbering.

Add a platform:Linux entry for 054c:0ce6 version 0x8111 matching the
hid-playstation layout. The CRC field is zeroed, so the entry matches on
VID/PID/version regardless of the device name string; any Sunshine fork that
keeps the same uhid emulation is covered even if it renames the pad.

Verified on kernel 7.1.4 / SDL 2.32.70 by loading the repo's
gamecontrollerdb.txt through SDL_GameControllerAddMappingsFromFile with
SDL_JOYSTICK_HIDAPI=0 -- the same call and hint state osContInit uses -- and
confirming SDL resolves this entry for the live device instead of its
built-in fallback. Gameplay confirmed over Moonlight.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLkH9mM9ppQ9iekbeuJvXn
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant