Skip to content

Use SDL for joypad input on Linux#87925

Closed
EIREXE wants to merge 1 commit intogodotengine:masterfrom
EIRTeam:SDL_penguins
Closed

Use SDL for joypad input on Linux#87925
EIREXE wants to merge 1 commit intogodotengine:masterfrom
EIRTeam:SDL_penguins

Conversation

@EIREXE
Copy link
Contributor

@EIREXE EIREXE commented Feb 4, 2024

SDL is loaded in the same way other Linux system libraries are loaded by using a wrapped and dlopen.

Optionally, SDL can be dynamically linked into the binary.

Currently for Linux only since that platform direly needs it, but should be easy to make work on Windows once stable.

Proposal at: godotengine/godot-proposals#9000

P.S: I've made sure to strip the files as much as possible, but unless you want to be pulling your hair out by stripping files individually this is the best we can do IMO.

@EIREXE EIREXE requested review from a team as code owners February 4, 2024 04:38
@EIREXE EIREXE force-pushed the SDL_penguins branch 6 times, most recently from 775a09f to 87d9d91 Compare February 4, 2024 09:34
@AThousandShips AThousandShips added this to the 4.x milestone Feb 4, 2024
@AThousandShips AThousandShips requested a review from a team February 4, 2024 09:59
@Calinou
Copy link
Member

Calinou commented Feb 5, 2024

Does this PR support using a more recent SDL library if it's statically linked using an environment variable? See #86180 (comment).

@EIREXE
Copy link
Contributor Author

EIREXE commented Feb 5, 2024

Does this PR support using a more recent SDL library if it's statically linked using an environment variable? See #86180 (comment).

This PR doesn't do static linking at all, it instead either does normal linux shared linking (without use_sowrap) or dynamic loading (if use_sowrap is enabled).

As far as I understand, SDL_DYNAMIC_API is something SDL itself takes care of, not ourselves. (assuming the SDL we are linking or loading is built with dynamic api support that is).

@EIREXE
Copy link
Contributor Author

EIREXE commented Feb 21, 2024

After some testing in production for Project Heartbeat I realised I made a mistake and was polling constantly, which is no bueno for CPU usage, so I switched to waiting with a timeout (so we can do the exit condition properly when the input thread is disposed of).

@EIREXE EIREXE force-pushed the SDL_penguins branch 2 times, most recently from 8b6b8c2 to 52eff38 Compare February 21, 2024 17:11
Copy link
Member

@Calinou Calinou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested locally (rebased on top of master f040a35) on Fedora 39 X11, it works as expected. All controllers were tested in wired mode only.

In terms of out-of-the-box functionality, this PR is a big improvement for many reasons:

  • My motherboard's LED controller is no longer recognized as the first controller ID (it's properly ignored). This meant the first connected controller was previously always on device ID 1, not 0. This PR effectively fixes #59250.
  • Switch Pro Controller works out of the box with correct mappings on Linux in USB-C, whereas it was previously not recognized at all.
  • A DualSense controller was previously seen as 2 devices (the second device was likely for motion reporting but was ineffective in Godot). This also broke controller IDs if you had multiple controllers connected if you had at least one DualSense and it wasn't the last connected controller. This PR fixes this and makes only one DualSense appear.
    • With this PR, the controller name also changed from PS5 Controller to DualSense Wireless Controller which is more accurate.
  • With this PR, Xbox One V3 controller is now called Xbox One S Controller instead of Xbox One Controller which is also more accurate.

There are 2 issues I noticed though:

  • Weak and strong vibration motors seem to be inverted, at least on the Xbox One V3 controller. Setting weak vibration to 0 and keeping strong vibration to 1 will result in a weak vibration with this PR, whereas it'd result in a strong vibration in master.
  • I can't use Ctrl + C in a terminal to exit the project anymore with this PR. This occurs even if no controllers are ever connected before or during the project's runtime.

Controller UUIDs reported for reference:

Controller master This PR
DualSense 030000004c050000e60c000011810000 4475616c53656e736520576972656c65
Xbox One V3 030000005e040000ea02000001030000 58626f78204f6e65205320436f6e7472
Switch Pro Controller 030000007e0500000920000011810000 4e696e74656e646f2053776974636820

Binary sizes (Linux x86_64 stripped release export template with LTO):

  • master: 64,166,088 bytes
  • This PR: 64,186,568 bytes (+20 KB)

20 KB sounds pretty reasonable considering how much this improves controller usability and paves the way for gyro support. Of course, this will be higher on platforms where we can't rely on system-provided SDL if we decide to use SDL for input on other platforms as well.

@tdaven
Copy link
Contributor

tdaven commented Mar 11, 2024

SDL by default adds handlers for sigint/sigquit. You can use SDL_SetHint to disable that behavior before SDL_Init.

For example:
https://github.com/mpv-player/mpv-examples/blob/master/libmpv/sdl/main.c#L53

@EIREXE
Copy link
Contributor Author

EIREXE commented Mar 12, 2024

SDL by default adds handlers for sigint/sigquit. You can use SDL_SetHint to disable that behavior before SDL_Init.

For example: https://github.com/mpv-player/mpv-examples/blob/master/libmpv/sdl/main.c#L53

I'll implement these changes today, ty

@EIREXE
Copy link
Contributor Author

EIREXE commented Mar 15, 2024

Changes should be done now

@johnlogostini
Copy link

johnlogostini commented Apr 18, 2024

I Had a problem wear Gamepads on Linux were being reported twice but not on Windows [90795] however this Pull Request [87925] from my testing has fixed all issues

Output from 4.2.1 - Gentoo Linux
Gamepad 0 = PS5 Controller
Gamepad 1 = PS5 Controller
Gamepad 2 = PS4 Controller
Gamepad 3 = PS4 Controller
Gamepad 4 =
Gamepad 5 =

Output from 4.3 PR [52eff38] - Gentoo Linux
Gamepad 0 = DualSense Wireless Controller
Gamepad 1 = PS4 Controller
Gamepad 2 =
Gamepad 3 =
Gamepad 4 =
Gamepad 5 =

@johnlogostini
Copy link

I am uncertain if this is intended behavior or a bug ether way if I connected my Left Joycon via Bluetooth it's eating 2 device slots causing issues with split-screen input

Gamepad 0 = Joy-Con (L)
Gamepad 1 = Joy-Con (L) (IMU)
Gamepad 2 =
Gamepad 3 =
Gamepad 4 =
Gamepad 5 =

@EIREXE
Copy link
Contributor Author

EIREXE commented Apr 20, 2024

I am uncertain if this is intended behavior or a bug ether way if I connected my Left Joycon via Bluetooth it's eating 2 device slots causing issues with split-screen input

Gamepad 0 = Joy-Con (L) Gamepad 1 = Joy-Con (L) (IMU) Gamepad 2 = Gamepad 3 = Gamepad 4 = Gamepad 5 =

What version of SDL are you running in your OS? from what I can tell that issue was fixed in SDL two years ago.

@johnlogostini
Copy link

johnlogostini commented Apr 23, 2024

I am on Gentoo Linux everything is up to date and I am running SDL 2.30.2

@bemug
Copy link

bemug commented May 2, 2024

I just ran some tests.
As expected this makes my WiiU Gamecube adapter to work, as it is supported correctly in SDL. It won't work without this PR.

I agree with the discussion and think this offers huge benefits in term of controller support and code re-usability.
This feature is important for me. I will follow this PR closely.

Thank you for your work.

SDL is loaded in the same way other Linux system libraries are loaded by using a wrapped and dlopen.

Optionally, SDL can be dynamically linked into the binary.

Currently for Linux only since that platform direly needs it, but should be easy to make work on Windows once stable.

Proposal at: godotengine/godot-proposals#9000
@EIREXE
Copy link
Contributor Author

EIREXE commented Oct 1, 2024

What do you want me to do with the SDL library? Should it be in thirdparty like all other builtin libraries?

@EIREXE
Copy link
Contributor Author

EIREXE commented Oct 1, 2024

Nevermind, it's going to be big trouble to get it to compile inside godot, so we should just make static builds like we do with nir.

@KeyboardDanni
Copy link
Contributor

  • If we're building SDL and linking it statically for all platforms, we should assess how much of SDL we actually need to build/include. It might be that we just need to reuse hidapi, or their input code, without pulling in the whole framework.

Worth noting that SDL's buildsystem lets you avoid building any subsystems you're not interested in using. So we could just build the input subsystem and that should result in a smaller binary.

@autione
Copy link

autione commented Jan 20, 2025

Would this also bundle new GDScript APIs for leveraging additional features for gamepads, such as DualSense's adaptive triggers, or Switch's gyro movements? It would be a missed opportunity to not implement those given the capabilities this PR provides.

@Calinou
Copy link
Member

Calinou commented Jan 20, 2025

Would this also bundle new GDScript APIs for leveraging additional features for gamepads, such as DualSense's adaptive triggers, or Switch's gyro movements? It would be a missed opportunity to not implement those given the capabilities this PR provides.

To my knowledge, this is not planned as part of this PR, but it can be done in future PRs. See godotengine/godot-proposals#2829 and #88590.

@QuinnLeavitt
Copy link
Contributor

Not sure how much work it would take to transition this to SDL 3 but SDL 3.2 stable has been released.

xsellier added a commit to xsellier/godot that referenced this pull request Mar 21, 2025
- Get the initial work from this PR: godotengine#87925
- Add source code of SDL but keep only Joypad related items
- Add implementation for Linux
xsellier added a commit to xsellier/godot that referenced this pull request Mar 22, 2025
- Get the initial work from this PR: godotengine#87925
- Add source code of SDL but keep only Joypad related items
- Add implementation for Linux
@vaartis
Copy link
Contributor

vaartis commented Apr 30, 2025

Can confirm that this works correctly for the DualSense (PS5) controller. The issue of having both the touchpad and the gamepad itself as two separate controllers is gone, now there is only the controller.

@Nintorch
Copy link
Contributor

Nintorch commented May 1, 2025

I've noticed that a person named "xsellier" mentioned this PR in their commit about adding SDL3 input support for their fork of Godot, and I've noticed that static linking of SDL hasn't yet been done by anyone so this inspired me to do that myself (but only for Windows for now, I will try to setup a Linux VM later to make sure Linux support works too).
I've grabbed the code from both EIREXE, xsellier (I hope they wouldn't mind...) and the source code of SDL3, modified the scons files to include just the required files and compile just the required subsystems and I've managed to compile Godot with SDL and sdl input driver.
I can confirm that this SDL input driver indeed works because when I print Input.get_joy_guid(0) on Godot without SDL driver it prints "030000004c050000cc09000000000000" for my Dualshock 4 gamepad and with SDL driver it prints "50533420436f6e74726f6c6c6572", and I've also tried to enable gamepad gyroscope support inside the JoypadSDL class (via SDL_SetGamepadSensorEnabled(game_controller, SDL_SENSOR_GYRO, true);) and query the gyroscope data (via SDL_EVENT_GAMEPAD_SENSOR_UPDATE event) and it does print out values for gyro, if I rotate my controller the values change, so SDL input must be working correctly.
I also had to modify some SDL files to correctly compile with MSVC compiler but I'm sure we can later make it compile without changing the SDL source code.
I hope my work would be useful for this PR.

https://github.com/Nintorch/godot

I also tried to test the Nintendo Switch Pro controller compatibility by using 8bitdo's adapter to convert my Dualshock 4 inputs into Switch Pro Controller inputs but Godot couldn't register the button presses or anything anymore, I'm not sure why it can't, but my guess is either SDL isn't configured to work with 8bitdo adapter or I missed some setup code for it (most likely this).

EDIT: I've managed to compile SDL inside of Godot without modifying SDL's source code! Nintorch@bf6f10b

@Nintorch
Copy link
Contributor

Nintorch commented May 1, 2025

Also, I know this PR is only about adding SDL and not about adding gyroscope, etc., but when SDL input driver is merged I would love to add support for new gamepad features SDL provides such as gyroscope, accelerometer, touchpads and lightbars

@Nintorch
Copy link
Contributor

Nintorch commented May 3, 2025

Sorry for triple post, but I've managed to add Linux support back to my fork. I've managed to compile it in WSL and it runs correctly, when I print my gamepad's guid "536f6e7920496e746572616374697665" is being printed.
Nintorch@41030e2
I also want to add MacOS support because it was requested in this thread by Calinou. I've never used either a Mac or Docker but I will try my best to setup MacOS inside of Docker if that's possible and legal because I can't afford a Mac :D
I will keep you guys updated

@akien-mga
Copy link
Member

Superseded by #106218. Thanks for the contribution!

@akien-mga akien-mga closed this Jun 24, 2025
@akien-mga akien-mga removed this from the 4.x milestone Jun 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Switch to SDL as the main gamepad input driver Laptop touchpads are seen as gamepads