emscripten: Fix navigator.getGamepads crash in worker threads

The three EM_JS functions (SDL_GetEmscriptenJoystickVendor,
SDL_GetEmscriptenJoystickProduct, SDL_IsEmscriptenJoystickXInput)
call navigator.getGamepads() which is only available on the main
browser thread. With PROXY_TO_PTHREAD, the joystick callbacks are
dispatched to a worker where the Gamepad API is not available,
causing a TypeError.

Convert these from EM_JS to static functions using
MAIN_THREAD_EM_ASM_INT, which proxies the JavaScript execution to
the main browser thread. This matches the pattern already used by
other navigator.getGamepads() calls in the same file.
This commit is contained in:
Christian Semmler
2026-04-02 19:17:02 -07:00
committed by Sam Lantinga
parent 3c11b43e59
commit be8643f739

View File

@@ -35,9 +35,11 @@ static SDL_joylist_item *SDL_joylist = NULL;
static SDL_joylist_item *SDL_joylist_tail = NULL; static SDL_joylist_item *SDL_joylist_tail = NULL;
static int numjoysticks = 0; static int numjoysticks = 0;
EM_JS(int, SDL_GetEmscriptenJoystickVendor, (int device_index), { static int SDL_GetEmscriptenJoystickVendor(int device_index)
{
// Let's assume that if we're calling these function then the gamepad object definitely exists // Let's assume that if we're calling these function then the gamepad object definitely exists
let gamepad = navigator['getGamepads']()[device_index]; return MAIN_THREAD_EM_ASM_INT({
let gamepad = navigator['getGamepads']()[$0];
// Chrome, Edge, Opera: Wireless Controller (STANDARD GAMEPAD Vendor: 054c Product: 09cc) // Chrome, Edge, Opera: Wireless Controller (STANDARD GAMEPAD Vendor: 054c Product: 09cc)
let vendor_str = 'Vendor: '; let vendor_str = 'Vendor: ';
@@ -53,10 +55,13 @@ EM_JS(int, SDL_GetEmscriptenJoystickVendor, (int device_index), {
} }
return 0; return 0;
}); }, device_index);
}
EM_JS(int, SDL_GetEmscriptenJoystickProduct, (int device_index), { static int SDL_GetEmscriptenJoystickProduct(int device_index)
let gamepad = navigator['getGamepads']()[device_index]; {
return MAIN_THREAD_EM_ASM_INT({
let gamepad = navigator['getGamepads']()[$0];
// Chrome, Edge, Opera: Wireless Controller (STANDARD GAMEPAD Vendor: 054c Product: 09cc) // Chrome, Edge, Opera: Wireless Controller (STANDARD GAMEPAD Vendor: 054c Product: 09cc)
let product_str = 'Product: '; let product_str = 'Product: ';
@@ -72,16 +77,20 @@ EM_JS(int, SDL_GetEmscriptenJoystickProduct, (int device_index), {
} }
return 0; return 0;
}); }, device_index);
}
EM_JS(int, SDL_IsEmscriptenJoystickXInput, (int device_index), { static int SDL_IsEmscriptenJoystickXInput(int device_index)
let gamepad = navigator['getGamepads']()[device_index]; {
return MAIN_THREAD_EM_ASM_INT({
let gamepad = navigator['getGamepads']()[$0];
// Chrome, Edge, Opera: Xbox 360 Controller (XInput STANDARD GAMEPAD) // Chrome, Edge, Opera: Xbox 360 Controller (XInput STANDARD GAMEPAD)
// Firefox: xinput // Firefox: xinput
// TODO: Safari // TODO: Safari
return gamepad['id']['toLowerCase']()['indexOf']('xinput') >= 0; return gamepad['id']['toLowerCase']()['indexOf']('xinput') >= 0;
}); }, device_index);
}
static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
{ {