Skip to content

Commit 3c5f1f9

Browse files
fix(steam-deck): preserve native SDL ownership
1 parent e48fc2e commit 3c5f1f9

5 files changed

Lines changed: 20 additions & 13 deletions

File tree

docs/platform-support.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -150,15 +150,14 @@ provides it separately on the UHID event.
150150

151151
Steam Deck retains Valve's native identity and emits the 64-byte Deck state
152152
packet periodically so SDL's direct HIDAPI path can initialize before the first
153-
client input arrives. Its UHID endpoint keeps Valve's USB transport identity so
154-
Linux `hid-steam` can expose the dedicated hidraw client expected by SDL. When
155-
that client opens, `hid-steam` hands the native report stream to userspace; the
156-
Generic Desktop/Game Pad descriptor remains available as an evdev fallback when
157-
no direct HID client owns it. The backend answers the unit-serial feature query
158-
used during Linux registration, accepts the desktop-mapping/settings commands
159-
used by SDL, and forwards native `0xEB` rumble requests through the portable
160-
output callback. Each submitted native packet carries an advancing sequence
161-
number.
153+
client input arrives. Linux exposes that endpoint as Bluetooth HID so SDL can
154+
own the native hidraw stream directly; advertising it as USB would make the
155+
kernel's `hid-steam` driver claim the virtual endpoint and substitute an evdev
156+
controller. The Generic Desktop/Game Pad descriptor remains available as an
157+
evdev fallback. The backend answers the unit-serial feature query, accepts the
158+
desktop-mapping/settings commands used by SDL, and forwards native `0xEB`
159+
rumble requests through the portable output callback. Each submitted native
160+
packet carries an advancing sequence number.
162161

163162
The backend opens `/dev/uhid` in nonblocking mode, matching the original
164163
asynchronous gamepad registration path. Its event reader is active before

src/platform/linux/uhid_backend.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,12 @@ namespace lvh::detail {
324324
// virtual endpoint.
325325
return BUS_VIRTUAL;
326326
}
327+
if (profile.gamepad_kind == GamepadProfileKind::steam_deck) {
328+
// hid-steam claims USB endpoints with Valve's Deck VID/PID and
329+
// publishes its own evdev device. Use a HID transport SDL accepts but
330+
// hid-steam does not match so SDL can own the native hidraw stream.
331+
return BUS_BLUETOOTH;
332+
}
327333
return to_uhid_bus(profile.bus_type);
328334
}
329335

tests/fixtures/linux_backend_test_hooks.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1695,7 +1695,7 @@ namespace lvh::detail::test {
16951695
options.metadata.stable_id = "linux-steam-deck";
16961696

16971697
UhidGamepad gamepad {descriptors[0]};
1698-
auto event = create_started_profile_uhid_gamepad(gamepad, 11, options, descriptors[1], BUS_USB, result);
1698+
auto event = create_started_profile_uhid_gamepad(gamepad, 11, options, descriptors[1], BUS_BLUETOOTH, result);
16991699
gamepad.set_output_callback([&result](const GamepadOutput &output) {
17001700
if (output.kind == GamepadOutputKind::rumble) {
17011701
++result.output.callback_count;

tests/unit/test_linux_backend.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ TEST_F(LinuxBackendTest, TranslatesMouseButtonsAndBusTypes) {
124124
EXPECT_EQ(lvh::detail::test::linux_uhid_bus(lvh::BusType::bluetooth), BUS_BLUETOOTH);
125125
EXPECT_EQ(lvh::detail::test::linux_gamepad_uhid_bus(lvh::GamepadProfileKind::xbox_series), BUS_USB);
126126
EXPECT_EQ(lvh::detail::test::linux_gamepad_uhid_bus(lvh::GamepadProfileKind::switch_pro), BUS_VIRTUAL);
127-
EXPECT_EQ(lvh::detail::test::linux_gamepad_uhid_bus(lvh::GamepadProfileKind::steam_deck), BUS_USB);
127+
EXPECT_EQ(lvh::detail::test::linux_gamepad_uhid_bus(lvh::GamepadProfileKind::steam_deck), BUS_BLUETOOTH);
128128
EXPECT_EQ(lvh::detail::test::linux_uinput_bus(lvh::BusType::bluetooth), BUS_BLUETOOTH);
129129

130130
EXPECT_EQ(lvh::detail::test::linux_pen_tool(lvh::PenToolType::pen), BTN_TOOL_PEN);

tests/unit/test_windows_consumers.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -437,8 +437,10 @@ namespace {
437437
SDL_GetGamepadProductForID(gamepad_id) == product_id
438438
) {
439439
auto *opened = SDL_OpenGamepad(gamepad_id);
440-
SDL_free(gamepads);
441-
return {opened, &SDL_CloseGamepad};
440+
if (opened != nullptr) {
441+
SDL_free(gamepads);
442+
return {opened, &SDL_CloseGamepad};
443+
}
442444
}
443445
}
444446
SDL_free(gamepads);

0 commit comments

Comments
 (0)