From 4f031ea5da370762469f977ee115a4d874d3de63 Mon Sep 17 00:00:00 2001
From: Nintorch <[EMAIL REDACTED]>
Date: Fri, 12 Jun 2026 12:06:32 +0500
Subject: [PATCH] Fix Xbox One controller detection on the web
---
src/joystick/emscripten/SDL_sysjoystick.c | 40 ++++++++++++++---------
1 file changed, 25 insertions(+), 15 deletions(-)
diff --git a/src/joystick/emscripten/SDL_sysjoystick.c b/src/joystick/emscripten/SDL_sysjoystick.c
index 2ff71d07858ed..3c58004fee625 100644
--- a/src/joystick/emscripten/SDL_sysjoystick.c
+++ b/src/joystick/emscripten/SDL_sysjoystick.c
@@ -147,15 +147,18 @@ static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamep
vendor = SDL_GetEmscriptenJoystickVendor(gamepadEvent->index);
product = SDL_GetEmscriptenJoystickProduct(gamepadEvent->index);
is_xinput = SDL_IsEmscriptenJoystickXInput(gamepadEvent->index);
-
- // Use a generic VID/PID representing an XInput controller
- if (!vendor && !product && is_xinput) {
- vendor = USB_VENDOR_MICROSOFT;
- product = USB_PRODUCT_XBOX360_XUSB_CONTROLLER;
- }
os_id = SDL_GetEmscriptenOSID();
+ item->trigger_rumble_available = MAIN_THREAD_EM_ASM_INT({
+ let gamepad = navigator['getGamepads']()[$0];
+ // This effect is not supported in Safari, so it's okay for us to check the vibrationActuator.effects array here for the browsers that do support it
+ if (!gamepad || !gamepad['vibrationActuator'] || !gamepad['vibrationActuator']['effects'] || !gamepad['vibrationActuator']['effects']['includes']('trigger-rumble')) {
+ return false;
+ }
+ return true;
+ }, item->index);
+
if (os_id != 0) {
if (os_id == 1 || os_id == 3) { // Android or iOS (mobile)
bus = SDL_HARDWARE_BUS_BLUETOOTH;
@@ -164,6 +167,21 @@ static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamep
}
}
+ if (!vendor && !product && is_xinput) {
+ // Use a generic VID/PID representing an XInput controller
+ vendor = USB_VENDOR_MICROSOFT;
+ product = USB_PRODUCT_XBOX360_XUSB_CONTROLLER;
+
+ if (item->trigger_rumble_available) {
+ // Assume Xbox One S Controller
+ if (bus == SDL_HARDWARE_BUS_BLUETOOTH) {
+ product = USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH;
+ } else {
+ product = USB_PRODUCT_XBOX_ONE_S;
+ }
+ }
+ }
+
if (SDL_strcmp(gamepadEvent->mapping, "standard") == 0) {
// We should differentiate between devices that are mapped or unmapped by the browser.
os_id += 0x80;
@@ -513,15 +531,7 @@ static bool EMSCRIPTEN_JoystickOpen(SDL_Joystick *joystick, int device_index)
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];
- // This effect is not supported in Safari, so it's okay for us to check the vibrationActuator.effects array here for the browsers that do support it
- if (!gamepad || !gamepad['vibrationActuator'] || !gamepad['vibrationActuator']['effects'] || !gamepad['vibrationActuator']['effects']['includes']('trigger-rumble')) {
- return false;
- }
- return true;
- }, item->index);
-
+ // item->trigger_rumble_available is set in Emscripten_JoyStickConnected
if (item->trigger_rumble_available) {
SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_TRIGGER_RUMBLE_BOOLEAN, true);
}