diff --git a/src/joystick/emscripten/SDL_sysjoystick.c b/src/joystick/emscripten/SDL_sysjoystick.c index 5d831bddbb..15d116f725 100644 --- a/src/joystick/emscripten/SDL_sysjoystick.c +++ b/src/joystick/emscripten/SDL_sysjoystick.c @@ -448,7 +448,6 @@ 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"); @@ -466,22 +465,24 @@ static bool EMSCRIPTEN_JoystickOpen(SDL_Joystick *joystick, int device_index) joystick->nbuttons = item->nbuttons; joystick->naxes = item->naxes; - rumble_available = MAIN_THREAD_EM_ASM_INT({ - let gamepads = navigator['getGamepads'](); - if (!gamepads) { - return 0; - } - let gamepad = gamepads[$0]; - if (!gamepad || !gamepad['vibrationActuator']) { - return 0; - } - return 1; + item->rumble_available = MAIN_THREAD_EM_ASM_INT({ + let gamepad = navigator['getGamepads']()[$0]; + return gamepad && gamepad['vibrationActuator'] && gamepad['vibrationActuator']['effects']['includes']('dual-rumble'); }, item->index); - if (rumble_available) { + if (item->rumble_available) { SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true); } + item->trigger_rumble_available = MAIN_THREAD_EM_ASM_INT({ + let gamepad = navigator['getGamepads']()[$0]; + return gamepad && gamepad['vibrationActuator'] && gamepad['vibrationActuator']['effects']['includes']('trigger-rumble'); + }, item->index); + + if (item->trigger_rumble_available) { + SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_TRIGGER_RUMBLE_BOOLEAN, true); + } + return true; } @@ -582,36 +583,49 @@ static SDL_GUID EMSCRIPTEN_JoystickGetDeviceGUID(int device_index) return JoystickByDeviceIndex(device_index)->guid; } -static bool EMSCRIPTEN_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) +static bool Emscripten_UpdateRumble(SDL_joylist_item *item) { - SDL_joylist_item *item = (SDL_joylist_item *)joystick->hwdata; - - // clang-format off bool result = MAIN_THREAD_EM_ASM_INT({ - let gamepads = navigator['getGamepads'](); - if (!gamepads) { - return 0; + let gamepad = navigator['getGamepads']()[$0]; + if (!gamepad) { + return false; } - let gamepad = gamepads[$0]; - if (!gamepad || !gamepad['vibrationActuator']) { - return 0; - } - + // We check if rumble is available in EMSCRIPTEN_JoystickRumble() and EMSCRIPTEN_JoystickRumbleTriggers(). + // From my testing using "dual-rumble" here covers both main rumble and trigger rumble. gamepad['vibrationActuator']['playEffect']('dual-rumble', { 'startDelay': 0, 'duration': 3000, - 'weakMagnitude': $2 / 0xFFFF, - 'strongMagnitude': $1 / 0xFFFF, + 'weakMagnitude': $1 / 0xFFFF, + 'strongMagnitude': $2 / 0xFFFF, + 'leftTrigger': $3 / 0xFFFF, + 'rightTrigger': $4 / 0xFFFF, }); - return 1; - }, item->index, low_frequency_rumble, high_frequency_rumble); + return true; + }, item->index, item->weak_magnitude_rumble, item->strong_magnitude_rumble, item->left_trigger_rumble, item->right_trigger_rumble); return result; } +static bool EMSCRIPTEN_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) +{ + SDL_joylist_item *item = (SDL_joylist_item *)joystick->hwdata; + if (!item || !item->rumble_available) { + return SDL_Unsupported(); + } + item->strong_magnitude_rumble = low_frequency_rumble; + item->weak_magnitude_rumble = high_frequency_rumble; + return Emscripten_UpdateRumble(item); +} + static bool EMSCRIPTEN_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) { - return SDL_Unsupported(); + SDL_joylist_item *item = (SDL_joylist_item *)joystick->hwdata; + if (!item || !item->trigger_rumble_available) { + return SDL_Unsupported(); + } + item->left_trigger_rumble = left_rumble; + item->right_trigger_rumble = right_rumble; + return Emscripten_UpdateRumble(item); } static bool EMSCRIPTEN_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) diff --git a/src/joystick/emscripten/SDL_sysjoystick_c.h b/src/joystick/emscripten/SDL_sysjoystick_c.h index df1fda85ae..c23d544748 100644 --- a/src/joystick/emscripten/SDL_sysjoystick_c.h +++ b/src/joystick/emscripten/SDL_sysjoystick_c.h @@ -46,6 +46,12 @@ typedef struct SDL_joylist_item double analogButton[64]; EM_BOOL digitalButton[64]; Uint8 hat; // there is (currently) only ever one of these, faked from the d-pad buttons. + bool rumble_available; + bool trigger_rumble_available; + Uint16 weak_magnitude_rumble; + Uint16 strong_magnitude_rumble; + Uint16 left_trigger_rumble; + Uint16 right_trigger_rumble; struct SDL_joylist_item *next; } SDL_joylist_item;