From 16c0329a2a4bbde0af73d669d45287c2e2f717aa Mon Sep 17 00:00:00 2001 From: Nintorch <92302738+Nintorch@users.noreply.github.com> Date: Sat, 16 Aug 2025 16:08:22 +0500 Subject: [PATCH] Add Emscripten joystick rumble support Adds support for Emscripten (Web) joystick rumble support via EM_ASM_INT macros and HTML5's Gamepad API. (cherry picked from commit 1fbed16cb0512e08651b99f7b0a6c1db4b0b61c6) --- src/joystick/emscripten/SDL_sysjoystick.c | 41 ++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/joystick/emscripten/SDL_sysjoystick.c b/src/joystick/emscripten/SDL_sysjoystick.c index b481d5da73..cddd975a71 100644 --- a/src/joystick/emscripten/SDL_sysjoystick.c +++ b/src/joystick/emscripten/SDL_sysjoystick.c @@ -305,6 +305,7 @@ static SDL_JoystickID EMSCRIPTEN_JoystickGetDeviceInstanceID(int device_index) static bool EMSCRIPTEN_JoystickOpen(SDL_Joystick *joystick, int device_index) { SDL_joylist_item *item = JoystickByDeviceIndex(device_index); + bool rumble_available = false; if (!item) { return SDL_SetError("No such device"); @@ -323,6 +324,22 @@ static bool EMSCRIPTEN_JoystickOpen(SDL_Joystick *joystick, int device_index) joystick->nbuttons = item->nbuttons; joystick->naxes = item->naxes; + rumble_available = EM_ASM_INT({ + let gamepads = navigator['getGamepads'](); + if (!gamepads) { + return 0; + } + let gamepad = gamepads[$0]; + if (!gamepad || !gamepad['vibrationActuator']) { + return 0; + } + return 1; + }, item->index); + + if (rumble_available) { + SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true); + } + return true; } @@ -390,7 +407,29 @@ static SDL_GUID EMSCRIPTEN_JoystickGetDeviceGUID(int device_index) static bool EMSCRIPTEN_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) { - return SDL_Unsupported(); + SDL_joylist_item *item = (SDL_joylist_item *)joystick->hwdata; + + // clang-format off + bool result = EM_ASM_INT({ + let gamepads = navigator['getGamepads'](); + if (!gamepads) { + return 0; + } + let gamepad = gamepads[$0]; + if (!gamepad || !gamepad['vibrationActuator']) { + return 0; + } + + gamepad['vibrationActuator']['playEffect']('dual-rumble', { + 'startDelay': 0, + 'duration': 3000, + 'weakMagnitude': $1 / 0xFFFF, + 'strongMagnitude': $2 / 0xFFFF, + }); + return 1; + }, item->index, low_frequency_rumble, high_frequency_rumble); + + return result; } static bool EMSCRIPTEN_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)