Skip to content

Conversation

Nintorch
Copy link
Contributor

@Nintorch Nintorch commented Aug 15, 2025

Follow-up to #106218

Closes #47656
Closes #96985

This PR adds support for SDL joystick input for the rest of the platforms Godot Engine supports. Previously it was only available on desktop platforms (Windows, Linux and macOS).

I also decided to refactor joypad_sdl.cpp a little bit and add joystick vibration feature to the web platform in this PR :D

I have tested this PR on Android and web, I haven't tested it on iOS and visionOS, but judging by how SDL input was integrated on macOS I hope this approach works for iOS and visionOS too.
I haven't made Android use HIDAPI yet (which was used for new joypad features in my other PR: #107967 ), I'm not sure I can, because I'm not an Android developer and it was tiring to make SDL's Android Java code work properly in Godot's build system 😅
(EDIT: It can't be done properly: libsdl-org/SDL@e3cf2e4 https://github.com/libsdl-org/SDL/blob/main/src/hidapi/android/hid.cpp#L1052 )

This PR also fixes 3 issues on Android (tested with my DualShock 4 on the master branch using this script):

1. Trigger axes values were not reset after the user stops pressing on them;

I'm not pressing any buttons on the screenshot:
image
Relevant issues #79263 #108982

The same situation after my PR:
image

2. Pressing the left trigger caused the Share button (or JoyButton::BACK) to be pressed as well;

I'm only pressing the left and right triggers on the screenshot:
image
Pressing Share on the controller didn't trigger anything, but after releasing the left trigger the BACK button stopped being red.
After my PR Godot can properly detect the Share button being pressed:
image

3. Fingerpring scanners were recognized as joypads.

Relevant issue: #47656
Before my PR:
image
After my PR:
image

There's also another Android issue ( #56181 ), but I can't reproduce it on master with my DualShock 4, so I can't test if it was fixed by my PR.
There's another problem, I haven't tested it on master yet but after this PR the joypad triggers are now digital (just 0.0 or 1.0) on web (EDIT: I hope it's now fixed), related SDL issue: libsdl-org/SDL#13051

TODO:

@bruvzg
Copy link
Member

bruvzg commented Aug 20, 2025

Web seems to be extremely buggy:

  • all controllers register as "Standard controller"
  • d-pad doesn't work
  • mapping for face buttons are wrong
  • triggers register only binary states and not as full axis
  • vibration doesn't work
  • there's high input lag, and some presses aren't registered at all

Android is crashing instantly, in SDL_InitSubSystem.

      #00 pc 000000000005ba84  /apex/com.android.runtime/lib64/bionic/libc.so (abort+156) (BuildId: 95e892805867a9df9d038d9e274fce41)
      #01 pc 000000000071f970  /apex/com.android.art/lib64/libart.so (art::Runtime::Abort(char const*)+236) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #02 pc 0000000000014d1c  /apex/com.android.art/lib64/libbase.so (android::base::SetAborter(std::__1::function<void (char const*)>&&)::$_0::__invoke(char const*)+80) (BuildId: 13d29229303b4debf34deaa44f74426b)
      #03 pc 00000000000142dc  /apex/com.android.art/lib64/libbase.so (android::base::LogMessage::~LogMessage()+524) (BuildId: 13d29229303b4debf34deaa44f74426b)
      #04 pc 000000000044fc8c  /apex/com.android.art/lib64/libart.so (art::JavaVMExt::JniAbort(char const*, char const*)+1268) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #05 pc 000000000044f754  /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::ScopedCheck::AbortF(char const*, ...) (.__uniq.99033978352804627313491551960229047428)+180) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #06 pc 00000000004555e0  /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::ScopedCheck::CheckInstance(art::ScopedObjectAccess&, art::(anonymous namespace)::ScopedCheck::InstanceKind, _jobject*, bool) (.__uniq.99033978352804627313491551960229047428)+1028) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #07 pc 000000000045a7cc  /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::ScopedCheck::Check(art::ScopedObjectAccess&, bool, char const*, art::(anonymous namespace)::JniValueType*) (.__uniq.99033978352804627313491551960229047428)+1396) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #08 pc 0000000000456e34  /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::CheckJNI::CallMethodV(char const*, _JNIEnv*, _jobject*, _jclass*, _jmethodID*, std::__va_list, art::Primitive::Type, art::InvokeType) (.__uniq.99033978352804627313491551960229047428)+248) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #09 pc 00000000008a16ac  /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::CheckJNI::CallStaticVoidMethod(_JNIEnv*, _jclass*, _jmethodID*, ...) (.__uniq.99033978352804627313491551960229047428.llvm.11128407671067317354)+152) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #10 pc 000000000214ba20  /data/app/~~T6jtuVVyaq82WXRErTJHSw==/com.example.joypads-WM8eoIB890EcL0eVln4mZA==/base.apk!libgodot_android.so (offset 0x3bc000)
      #11 pc 000000000211d208  /data/app/~~T6jtuVVyaq82WXRErTJHSw==/com.example.joypads-WM8eoIB890EcL0eVln4mZA==/base.apk!libgodot_android.so (offset 0x3bc000)
      #12 pc 000000000213c928  /data/app/~~T6jtuVVyaq82WXRErTJHSw==/com.example.joypads-WM8eoIB890EcL0eVln4mZA==/base.apk!libgodot_android.so (offset 0x3bc000) (SDL_InitSubSystem+496)
      #13 pc 000000000211c190  /data/app/~~T6jtuVVyaq82WXRErTJHSw==/com.example.joypads-WM8eoIB890EcL0eVln4mZA==/base.apk!libgodot_android.so (offset 0x3bc000)
      #14 pc 00000000011fa464  /data/app/~~T6jtuVVyaq82WXRErTJHSw==/com.example.joypads-WM8eoIB890EcL0eVln4mZA==/base.apk!libgodot_android.so (offset 0x3bc000)
      #15 pc 0000000001259d24  /data/app/~~T6jtuVVyaq82WXRErTJHSw==/com.example.joypads-WM8eoIB890EcL0eVln4mZA==/base.apk!libgodot_android.so (offset 0x3bc000)
      #16 pc 00000000012160fc  /data/app/~~T6jtuVVyaq82WXRErTJHSw==/com.example.joypads-WM8eoIB890EcL0eVln4mZA==/base.apk!libgodot_android.so (offset 0x3bc000) (Java_org_godotengine_godot_GodotLib_step+108)
      #17 pc 0000000000386d00  /apex/com.android.art/lib64/libart.so (art_quick_generic_jni_trampoline+144) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #18 pc 000000000036fc60  /apex/com.android.art/lib64/libart.so (art_quick_invoke_static_stub+640) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #19 pc 0000000000885da0  /apex/com.android.art/lib64/libart.so (bool art::interpreter::DoCall<false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, bool, art::JValue*)+1808) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #20 pc 000000000078fba4  /apex/com.android.art/lib64/libart.so (void art::interpreter::ExecuteSwitchImplCpp<false>(art::interpreter::SwitchImplContext*)+10828) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #21 pc 0000000000393548  /apex/com.android.art/lib64/libart.so (ExecuteSwitchImplAsm+8) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #22 pc 0000000000004e1c  [anon:dalvik-classes12.dex extracted in memory from /data/app/~~T6jtuVVyaq82WXRErTJHSw==/com.example.joypads-WM8eoIB890EcL0eVln4mZA==/base.apk] (org.godotengine.godot.gl.GodotRenderer.onDrawFrame+0)
      #23 pc 0000000000393194  /apex/com.android.art/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+548) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #24 pc 0000000000885d8c  /apex/com.android.art/lib64/libart.so (bool art::interpreter::DoCall<false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, bool, art::JValue*)+1788) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #25 pc 000000000078fc7c  /apex/com.android.art/lib64/libart.so (void art::interpreter::ExecuteSwitchImplCpp<false>(art::interpreter::SwitchImplContext*)+11044) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #26 pc 0000000000393548  /apex/com.android.art/lib64/libart.so (ExecuteSwitchImplAsm+8) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #27 pc 0000000000003c78  [anon:dalvik-classes12.dex extracted in memory from /data/app/~~T6jtuVVyaq82WXRErTJHSw==/com.example.joypads-WM8eoIB890EcL0eVln4mZA==/base.apk] (org.godotengine.godot.gl.GLSurfaceView$GLThread.guardedRun+0)
      #28 pc 0000000000393194  /apex/com.android.art/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+548) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #29 pc 0000000000885d8c  /apex/com.android.art/lib64/libart.so (bool art::interpreter::DoCall<false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, bool, art::JValue*)+1788) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #30 pc 000000000078fba4  /apex/com.android.art/lib64/libart.so (void art::interpreter::ExecuteSwitchImplCpp<false>(art::interpreter::SwitchImplContext*)+10828) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #31 pc 0000000000393548  /apex/com.android.art/lib64/libart.so (ExecuteSwitchImplAsm+8) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #32 pc 0000000000004580  [anon:dalvik-classes12.dex extracted in memory from /data/app/~~T6jtuVVyaq82WXRErTJHSw==/com.example.joypads-WM8eoIB890EcL0eVln4mZA==/base.apk] (org.godotengine.godot.gl.GLSurfaceView$GLThread.run+0)
      #33 pc 00000000003939c4  /apex/com.android.art/lib64/libart.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*)+636) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #34 pc 00000000003929b4  /apex/com.android.art/lib64/libart.so (artQuickToInterpreterBridge+988) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #35 pc 0000000000386e38  /apex/com.android.art/lib64/libart.so (art_quick_to_interpreter_bridge+88) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #36 pc 000000000036f994  /apex/com.android.art/lib64/libart.so (art_quick_invoke_stub+612) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #37 pc 000000000035a9bc  /apex/com.android.art/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+136) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #38 pc 00000000004fe240  /apex/com.android.art/lib64/libart.so (art::Thread::CreateCallback(void*)+1004) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #39 pc 000000000006b768  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+184) (BuildId: 95e892805867a9df9d038d9e274fce41)
      #40 pc 000000000005ea18  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: 95e892805867a9df9d038d9e274fce41)

Will check iOS later.

@Nintorch
Copy link
Contributor Author

Web seems to be extremely buggy:

  • all controllers register as "Standard controller"
  • d-pad doesn't work
  • mapping for face buttons are wrong
  • triggers register only binary states and not as full axis
  • vibration doesn't work
  • there's high input lag, and some presses aren't registered at all

Android is crashing instantly, in SDL_InitSubSystem.

      #00 pc 000000000005ba84  /apex/com.android.runtime/lib64/bionic/libc.so (abort+156) (BuildId: 95e892805867a9df9d038d9e274fce41)
      #01 pc 000000000071f970  /apex/com.android.art/lib64/libart.so (art::Runtime::Abort(char const*)+236) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #02 pc 0000000000014d1c  /apex/com.android.art/lib64/libbase.so (android::base::SetAborter(std::__1::function<void (char const*)>&&)::$_0::__invoke(char const*)+80) (BuildId: 13d29229303b4debf34deaa44f74426b)
      #03 pc 00000000000142dc  /apex/com.android.art/lib64/libbase.so (android::base::LogMessage::~LogMessage()+524) (BuildId: 13d29229303b4debf34deaa44f74426b)
      #04 pc 000000000044fc8c  /apex/com.android.art/lib64/libart.so (art::JavaVMExt::JniAbort(char const*, char const*)+1268) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #05 pc 000000000044f754  /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::ScopedCheck::AbortF(char const*, ...) (.__uniq.99033978352804627313491551960229047428)+180) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #06 pc 00000000004555e0  /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::ScopedCheck::CheckInstance(art::ScopedObjectAccess&, art::(anonymous namespace)::ScopedCheck::InstanceKind, _jobject*, bool) (.__uniq.99033978352804627313491551960229047428)+1028) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #07 pc 000000000045a7cc  /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::ScopedCheck::Check(art::ScopedObjectAccess&, bool, char const*, art::(anonymous namespace)::JniValueType*) (.__uniq.99033978352804627313491551960229047428)+1396) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #08 pc 0000000000456e34  /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::CheckJNI::CallMethodV(char const*, _JNIEnv*, _jobject*, _jclass*, _jmethodID*, std::__va_list, art::Primitive::Type, art::InvokeType) (.__uniq.99033978352804627313491551960229047428)+248) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #09 pc 00000000008a16ac  /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::CheckJNI::CallStaticVoidMethod(_JNIEnv*, _jclass*, _jmethodID*, ...) (.__uniq.99033978352804627313491551960229047428.llvm.11128407671067317354)+152) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #10 pc 000000000214ba20  /data/app/~~T6jtuVVyaq82WXRErTJHSw==/com.example.joypads-WM8eoIB890EcL0eVln4mZA==/base.apk!libgodot_android.so (offset 0x3bc000)
      #11 pc 000000000211d208  /data/app/~~T6jtuVVyaq82WXRErTJHSw==/com.example.joypads-WM8eoIB890EcL0eVln4mZA==/base.apk!libgodot_android.so (offset 0x3bc000)
      #12 pc 000000000213c928  /data/app/~~T6jtuVVyaq82WXRErTJHSw==/com.example.joypads-WM8eoIB890EcL0eVln4mZA==/base.apk!libgodot_android.so (offset 0x3bc000) (SDL_InitSubSystem+496)
      #13 pc 000000000211c190  /data/app/~~T6jtuVVyaq82WXRErTJHSw==/com.example.joypads-WM8eoIB890EcL0eVln4mZA==/base.apk!libgodot_android.so (offset 0x3bc000)
      #14 pc 00000000011fa464  /data/app/~~T6jtuVVyaq82WXRErTJHSw==/com.example.joypads-WM8eoIB890EcL0eVln4mZA==/base.apk!libgodot_android.so (offset 0x3bc000)
      #15 pc 0000000001259d24  /data/app/~~T6jtuVVyaq82WXRErTJHSw==/com.example.joypads-WM8eoIB890EcL0eVln4mZA==/base.apk!libgodot_android.so (offset 0x3bc000)
      #16 pc 00000000012160fc  /data/app/~~T6jtuVVyaq82WXRErTJHSw==/com.example.joypads-WM8eoIB890EcL0eVln4mZA==/base.apk!libgodot_android.so (offset 0x3bc000) (Java_org_godotengine_godot_GodotLib_step+108)
      #17 pc 0000000000386d00  /apex/com.android.art/lib64/libart.so (art_quick_generic_jni_trampoline+144) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #18 pc 000000000036fc60  /apex/com.android.art/lib64/libart.so (art_quick_invoke_static_stub+640) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #19 pc 0000000000885da0  /apex/com.android.art/lib64/libart.so (bool art::interpreter::DoCall<false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, bool, art::JValue*)+1808) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #20 pc 000000000078fba4  /apex/com.android.art/lib64/libart.so (void art::interpreter::ExecuteSwitchImplCpp<false>(art::interpreter::SwitchImplContext*)+10828) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #21 pc 0000000000393548  /apex/com.android.art/lib64/libart.so (ExecuteSwitchImplAsm+8) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #22 pc 0000000000004e1c  [anon:dalvik-classes12.dex extracted in memory from /data/app/~~T6jtuVVyaq82WXRErTJHSw==/com.example.joypads-WM8eoIB890EcL0eVln4mZA==/base.apk] (org.godotengine.godot.gl.GodotRenderer.onDrawFrame+0)
      #23 pc 0000000000393194  /apex/com.android.art/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+548) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #24 pc 0000000000885d8c  /apex/com.android.art/lib64/libart.so (bool art::interpreter::DoCall<false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, bool, art::JValue*)+1788) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #25 pc 000000000078fc7c  /apex/com.android.art/lib64/libart.so (void art::interpreter::ExecuteSwitchImplCpp<false>(art::interpreter::SwitchImplContext*)+11044) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #26 pc 0000000000393548  /apex/com.android.art/lib64/libart.so (ExecuteSwitchImplAsm+8) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #27 pc 0000000000003c78  [anon:dalvik-classes12.dex extracted in memory from /data/app/~~T6jtuVVyaq82WXRErTJHSw==/com.example.joypads-WM8eoIB890EcL0eVln4mZA==/base.apk] (org.godotengine.godot.gl.GLSurfaceView$GLThread.guardedRun+0)
      #28 pc 0000000000393194  /apex/com.android.art/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+548) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #29 pc 0000000000885d8c  /apex/com.android.art/lib64/libart.so (bool art::interpreter::DoCall<false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, bool, art::JValue*)+1788) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #30 pc 000000000078fba4  /apex/com.android.art/lib64/libart.so (void art::interpreter::ExecuteSwitchImplCpp<false>(art::interpreter::SwitchImplContext*)+10828) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #31 pc 0000000000393548  /apex/com.android.art/lib64/libart.so (ExecuteSwitchImplAsm+8) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #32 pc 0000000000004580  [anon:dalvik-classes12.dex extracted in memory from /data/app/~~T6jtuVVyaq82WXRErTJHSw==/com.example.joypads-WM8eoIB890EcL0eVln4mZA==/base.apk] (org.godotengine.godot.gl.GLSurfaceView$GLThread.run+0)
      #33 pc 00000000003939c4  /apex/com.android.art/lib64/libart.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*)+636) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #34 pc 00000000003929b4  /apex/com.android.art/lib64/libart.so (artQuickToInterpreterBridge+988) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #35 pc 0000000000386e38  /apex/com.android.art/lib64/libart.so (art_quick_to_interpreter_bridge+88) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #36 pc 000000000036f994  /apex/com.android.art/lib64/libart.so (art_quick_invoke_stub+612) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #37 pc 000000000035a9bc  /apex/com.android.art/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+136) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #38 pc 00000000004fe240  /apex/com.android.art/lib64/libart.so (art::Thread::CreateCallback(void*)+1004) (BuildId: 29de2213ce2448a49b79fc75574aeaf2)
      #39 pc 000000000006b768  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+184) (BuildId: 95e892805867a9df9d038d9e274fce41)
      #40 pc 000000000005ea18  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: 95e892805867a9df9d038d9e274fce41)

Will check iOS later.

Thank you for testing, bruvzg! That's weird, for me on Windows on web I didn't have problems with dpad, face buttons, vibration and input lag with Dualshock 4 (the other problems did happen, I will try to fix them), and I didn't have crashes on Android. May I ask if there's any other information about the Android crash you're experiencing?

@bruvzg
Copy link
Member

bruvzg commented Aug 20, 2025

Some extra info:

  • dpad issue is reproducible with dual sense controller.
  • dpad, wrong mapping, and input lag issue seems to be Firefox specific issue
  • vibration works in Safari, but not in Chrome or Firefox (all on macOS).
  • some Issus also reproducible with beta5
beta 5 this PR
Firefox - Dual Sense controller not detected input lag, no dpad, wrong face buttons, no trigger axis, no vibration
Firefox - XBox One input lag, no vibration input lag, no trigger axis, no vibration
Chrome - Dual Sense controller not detected no trigger axis, no vibration
Chrome - XBox One no vibration no trigger axis, no vibration
Safari - Dual Sense no vibration no trigger axis
Safari - XBox One no vibration no trigger axis

@bruvzg
Copy link
Member

bruvzg commented Aug 20, 2025

On iOS, linking fails due to following missing symbols:

Undefined symbol: _SDL_SYS_HapticClose
Undefined symbol: _SDL_SYS_HapticDestroyEffect
Undefined symbol: _SDL_SYS_HapticInit
Undefined symbol: _SDL_SYS_HapticQuit

@Nintorch
Copy link
Contributor Author

On iOS, linking fails due to following missing symbols:

Undefined symbol: _SDL_SYS_HapticClose
Undefined symbol: _SDL_SYS_HapticDestroyEffect
Undefined symbol: _SDL_SYS_HapticInit
Undefined symbol: _SDL_SYS_HapticQuit

Oh, that's also strange, because the check in this PR for iOS export template passed.

@bruvzg
Copy link
Member

bruvzg commented Aug 20, 2025

Oh, that's also strange, because the check in this PR for iOS export template passed.

CI only build a static library, linking is done when project is exported.

@bruvzg
Copy link
Member

bruvzg commented Aug 20, 2025

May I ask if there's any other information about the Android crash you're experiencing?

It's crashing on start, tested with "Joypads" demo on Pixel 8 Pro (Android 16) and POCO F3 (LineageOS, Android 15).

@Nintorch
Copy link
Contributor Author

May I ask if there's any other information about the Android crash you're experiencing?

It's crashing on start, tested with "Joypads" demo on Pixel 8 Pro (Android 16) and POCO F3 (LineageOS, Android 15).

Hm, is there any exception thrown or a JNI error shown?

@bruvzg
Copy link
Member

bruvzg commented Aug 20, 2025

Hm, is there any exception thrown or a JNI error shown?

'JNI DETECTED ERROR IN APPLICATION: CallStaticVoidMethod received NULL jclass

Here's full logcat output - https://gist.github.com/bruvzg/9822262842e885170289d40572fc4002

@Nintorch
Copy link
Contributor Author

Nintorch commented Aug 20, 2025

I see, thank you! I will try to fix it

@bruvzg
Copy link
Member

bruvzg commented Aug 20, 2025

A fix for iOS:

diff --git a/drivers/sdl/SCsub b/drivers/sdl/SCsub
index 3cd3761c4b..8bed438fe6 100644
--- a/drivers/sdl/SCsub
+++ b/drivers/sdl/SCsub
@@ -217,6 +217,7 @@ if env["builtin_sdl"]:
         thirdparty_sources += [
             "core/unix/SDL_appid.c",
             "core/unix/SDL_poll.c",
+            "haptic/dummy/SDL_syshaptic.c",
             "joystick/apple/SDL_mfijoystick.m",
             "thread/pthread/SDL_syscond.c",
             "thread/pthread/SDL_sysmutex.c",
diff --git a/drivers/sdl/SDL_build_config_private.h b/drivers/sdl/SDL_build_config_private.h
index 54c60f32a5..512894146e 100644
--- a/drivers/sdl/SDL_build_config_private.h
+++ b/drivers/sdl/SDL_build_config_private.h
@@ -155,6 +155,7 @@
 #define HAVE_STDIO_H 1
 #define HAVE_LIBC 1
 #define SDL_JOYSTICK_MFI 1
+#define SDL_HAPTIC_DUMMY 1
 #define SDL_TIMER_UNIX 1
 #define SDL_THREAD_PTHREAD 1

With this fix, everything seems to work.

@Nintorch
Copy link
Contributor Author

Thank you! Also, may I ask if the Android crash happened while running the editor build of Godot on your devices or the exported games? I just realized that I only initialize SDL in platform\android\java\editor\src\main\java\org\godotengine\editor\BaseGodotEditor.kt (i.e. only in the editor, I assume), and not in platform\android\java\app\src\com\godot\game\GodotApp.java (which is used in the exported app, I assume), which is probably the reason the crash happened.

@Nintorch Nintorch force-pushed the more-sdl-joypad-platforms branch from 4e9de1a to ddf3952 Compare August 20, 2025 08:06
@bruvzg
Copy link
Member

bruvzg commented Aug 20, 2025

Also, may I ask if the Android crash happened while running the editor build of Godot on your devices or the exported games?

Exported game, I have not checked the editor.

@bruvzg
Copy link
Member

bruvzg commented Aug 20, 2025

Tested Android editor, and most stuff seems to be working. Vibration works with XBox One controller, but not with Dual Sense.

@Nintorch Nintorch force-pushed the more-sdl-joypad-platforms branch from ddf3952 to 6e8c7d4 Compare August 20, 2025 13:25
This commit adds support for SDL joystick input for the rest of the platforms Godot Engine supports. Previously it was only available on desktop platforms (Windows, Linux and macOS). This commit also adds joystick vibration feature to the web platform in browsers that support this feature.
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.

Controller vibration not working in HTML5 Gamepad support: Device 0 already taken by fingerprint reader on Android
3 participants