From 296f0cc825b85db7f18e9d7abc9404f9ffa3e381 Mon Sep 17 00:00:00 2001 From: Nintorch <92302738+Nintorch@users.noreply.github.com> Date: Fri, 12 Jun 2026 21:51:32 +0500 Subject: [PATCH] Add flexible Emscripten joystick mapping --- src/joystick/SDL_gamepad_db.h | 7 +- src/joystick/emscripten/SDL_sysjoystick.c | 110 +++++++++++++++++++++- 2 files changed, 115 insertions(+), 2 deletions(-) diff --git a/src/joystick/SDL_gamepad_db.h b/src/joystick/SDL_gamepad_db.h index b38c66a84dd12..ef977f3eae740 100644 --- a/src/joystick/SDL_gamepad_db.h +++ b/src/joystick/SDL_gamepad_db.h @@ -862,7 +862,12 @@ static const char *s_GamepadMappings[] = { "050000005e040000e0020000ff070000,Xbox Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,", #endif #ifdef SDL_JOYSTICK_EMSCRIPTEN - "default,*,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,", + // The mapping rules: + // If the controller has a standard mapping (the second to last digit of the GUID is 0x8 or greater), a custom SDL mapping shouldn't be created for forwards-compatibility reasons. If you believe the standard mapping provided by the browser is incorrect, please file a bug report to the browser. + // If the user's OS is not recognized (the last digit of the GUID is 0), a custom SDL mapping shouldn't be created, because it might conflict with other OSes that also might not get recognized. If that happens to you and you would like to create a custom mapping, please create an issue in SDL's GitHub repository. + // In other cases, the same rules as on other platforms apply. + + // No mappings here yet #endif #ifdef SDL_JOYSTICK_PS2 "0000000050533220436f6e74726f6c00,PS2 Controller,crc:ed87,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,", diff --git a/src/joystick/emscripten/SDL_sysjoystick.c b/src/joystick/emscripten/SDL_sysjoystick.c index 3c58004fee625..da8d47dafed92 100644 --- a/src/joystick/emscripten/SDL_sysjoystick.c +++ b/src/joystick/emscripten/SDL_sysjoystick.c @@ -683,7 +683,115 @@ static bool EMSCRIPTEN_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 lef static bool EMSCRIPTEN_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) { - return false; + SDL_joylist_item *item = JoystickByDeviceIndex(device_index); + Uint16 vendor, product; + + if (!item) { + // Controller was disconnected? + return false; + } + + // Here we don't check if the controller's mapping is "standard" to preserve the previous behavior + + // if ((item->guid.data[15] & 0x80) == 0) { + // return false; + // } + + SDL_GetJoystickGUIDInfo(item->guid, &vendor, &product, NULL, NULL); + + // Standard web mapping, with SDL changes described in the code (see Emscripten_JoyStickConnected) + out->a.kind = EMappingKind_Button; + out->a.target = 0; + + out->b.kind = EMappingKind_Button; + out->b.target = 1; + + out->x.kind = EMappingKind_Button; + out->x.target = 2; + + out->y.kind = EMappingKind_Button; + out->y.target = 3; + + out->back.kind = EMappingKind_Button; + out->back.target = 6; + + out->guide.kind = EMappingKind_Button; + out->guide.target = 10; + + out->start.kind = EMappingKind_Button; + out->start.target = 7; + + out->leftstick.kind = EMappingKind_Button; + out->leftstick.target = 8; + + out->rightstick.kind = EMappingKind_Button; + out->rightstick.target = 9; + + out->leftshoulder.kind = EMappingKind_Button; + out->leftshoulder.target = 4; + + out->rightshoulder.kind = EMappingKind_Button; + out->rightshoulder.target = 5; + + out->dpup.kind = EMappingKind_Hat; + out->dpup.target = SDL_HAT_UP; + + out->dpdown.kind = EMappingKind_Hat; + out->dpdown.target = SDL_HAT_DOWN; + + out->dpleft.kind = EMappingKind_Hat; + out->dpleft.target = SDL_HAT_LEFT; + + out->dpright.kind = EMappingKind_Hat; + out->dpright.target = SDL_HAT_RIGHT; + + out->leftx.kind = EMappingKind_Axis; + out->leftx.target = 0; + + out->lefty.kind = EMappingKind_Axis; + out->lefty.target = 1; + + out->rightx.kind = EMappingKind_Axis; + out->rightx.target = 2; + + out->righty.kind = EMappingKind_Axis; + out->righty.target = 3; + + out->lefttrigger.kind = EMappingKind_Axis; + out->lefttrigger.target = 4; + + out->righttrigger.kind = EMappingKind_Axis; + out->righttrigger.target = 5; + + // Non-standard buttons + if (item->nbuttons >= 12) { + SDL_InputMapping *misc_buttons[] = { + &out->misc1, + &out->misc2, + &out->misc3, + &out->misc4, + &out->misc5, + &out->misc6, + }; + + if (SDL_IsJoystickPS4(vendor, product) || SDL_IsJoystickPS5(vendor, product)) { + // This button describes the touchpad, tested in Chromium and Firefox + misc_buttons[0] = &out->touchpad; + } + + const int start_button = 11; + int misc_button_count = item->nbuttons - 11; + if (misc_button_count > SDL_arraysize(misc_buttons)) { + misc_button_count = SDL_arraysize(misc_buttons); + } + + for (int i = 0; i < misc_button_count; i++) { + misc_buttons[i]->kind = EMappingKind_Button; + misc_buttons[i]->target = start_button + i; + } + } + + return true; } static bool EMSCRIPTEN_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)