diff --git a/src/joystick/SDL_gamepad_db.h b/src/joystick/SDL_gamepad_db.h index 74b58e59ef..072d96c1a3 100644 --- a/src/joystick/SDL_gamepad_db.h +++ b/src/joystick/SDL_gamepad_db.h @@ -897,7 +897,7 @@ 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,Standard Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,", + "default,Standard Gamepad,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,", #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 31a1de6140..1a4bdf50aa 100644 --- a/src/joystick/emscripten/SDL_sysjoystick.c +++ b/src/joystick/emscripten/SDL_sysjoystick.c @@ -66,36 +66,59 @@ static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamep goto done; } + const int real_button_count = gamepadEvent->numButtons; + const int real_axis_count = gamepadEvent->numAxes; + int first_trigger_button = -1; int first_hat_button = -1; int num_buttons = gamepadEvent->numButtons; - if ((SDL_strcmp(gamepadEvent->mapping, "standard") == 0) && (num_buttons >= 16)) { // maps to a game console gamepad layout, turn the d-pad into a hat. - num_buttons -= 4; + int num_axes = gamepadEvent->numAxes; + bool triggers_are_buttons = false; + if ((SDL_strcmp(gamepadEvent->mapping, "standard") == 0) && (num_buttons >= 16)) { // maps to a game console gamepad layout, turn the d-pad into a hat, treat triggers as analog. + num_buttons -= 4; // 4 dpad buttons become a hat. first_hat_button = 12; + + if (num_axes == 4) { // Chrome gives the triggers analog button values, Firefox exposes them as extra axes. Both have the digital buttons. + num_axes += 2; // the two trigger "buttons" + triggers_are_buttons = true; + } + + // dump the digital trigger buttons in any case. + first_trigger_button = 6; + num_buttons -= 2; } item->first_hat_button = first_hat_button; + item->first_trigger_button = first_trigger_button; + item->triggers_are_buttons = triggers_are_buttons; item->nhats = (first_hat_button >= 0) ? 1 : 0; - item->naxes = gamepadEvent->numAxes; + item->naxes = num_axes; item->nbuttons = num_buttons; item->device_instance = SDL_GetNextObjectID(); item->timestamp = gamepadEvent->timestamp; - for (i = 0; i < item->naxes; i++) { - item->axis[i] = gamepadEvent->axis[i]; - } - int buttonidx = 0; - for (i = 0; i < item->nbuttons; i++, buttonidx++) { + for (i = 0; i < real_button_count; i++, buttonidx++) { if (buttonidx == first_hat_button) { - buttonidx += 3; // skip these buttons, we're treating them as hat input. + buttonidx += 4; // skip these buttons, we're treating them as hat input. + } else if (buttonidx == first_trigger_button) { + buttonidx += 2; // skip these buttons, we're treating them as axes. } item->analogButton[i] = gamepadEvent->analogButton[buttonidx]; item->digitalButton[i] = gamepadEvent->digitalButton[buttonidx]; } + for (i = 0; i < real_axis_count; i++) { + item->axis[i] = gamepadEvent->axis[i]; + } + + if (item->triggers_are_buttons) { + item->axis[real_axis_count] = (gamepadEvent->analogButton[first_trigger_button] * 2.0f) - 1.0f; + item->axis[real_axis_count+1] = (gamepadEvent->analogButton[first_trigger_button+1] * 2.0f) - 1.0f; + } + SDL_assert(item->nhats <= 1); // there is (currently) only ever one of these, faked from the d-pad buttons. - if (item->nhats) { + if (first_hat_button != -1) { Uint8 value = SDL_HAT_CENTERED; // this currently expects the first button to be up, then down, then left, then right. if (gamepadEvent->digitalButton[first_hat_button + 0]) { @@ -393,14 +416,19 @@ static void EMSCRIPTEN_JoystickUpdate(SDL_Joystick *joystick) if (result == EMSCRIPTEN_RESULT_SUCCESS) { if (gamepadState.timestamp == 0 || gamepadState.timestamp != item->timestamp) { const int first_hat_button = item->first_hat_button; + const int first_trigger_button = item->first_trigger_button; + const int real_button_count = gamepadState.numButtons; + const int real_axis_count = gamepadState.numAxes; int buttonidx = 0; - for (i = 0; i < item->nbuttons; i++, buttonidx++) { + for (i = 0; i < real_button_count; i++, buttonidx++) { if (buttonidx == first_hat_button) { buttonidx += 4; // skip these buttons, we're treating them as hat input. + } else if (buttonidx == first_trigger_button) { + buttonidx += 2; // skip these buttons, we're treating them as axes. } if (item->digitalButton[i] != gamepadState.digitalButton[buttonidx]) { - bool down = (gamepadState.digitalButton[buttonidx] != 0); + const bool down = (gamepadState.digitalButton[buttonidx] != 0); SDL_SendJoystickButton(timestamp, item->joystick, i, down); } @@ -409,15 +437,20 @@ static void EMSCRIPTEN_JoystickUpdate(SDL_Joystick *joystick) item->digitalButton[i] = gamepadState.digitalButton[buttonidx]; } - for (i = 0; i < item->naxes; i++) { + for (i = 0; i < real_axis_count; i++) { if (item->axis[i] != gamepadState.axis[i]) { - // do we need to do conversion? - SDL_SendJoystickAxis(timestamp, item->joystick, i, - (Sint16)(32767. * gamepadState.axis[i])); + SDL_SendJoystickAxis(timestamp, item->joystick, i, (Sint16)(32767.0f * gamepadState.axis[i])); + item->axis[i] = gamepadState.axis[i]; } + } - // store to compare in next update - item->axis[i] = gamepadState.axis[i]; + if (item->triggers_are_buttons) { + for (i = 0; i < 2; i++) { + if (item->axis[real_axis_count+i] != gamepadState.analogButton[first_trigger_button+i]) { + SDL_SendJoystickAxis(timestamp, item->joystick, real_axis_count+i, (Sint16)(32767.0f * ((gamepadState.analogButton[first_trigger_button+i] * 2.0f) - 1.0f))); + item->axis[real_axis_count+i] = gamepadState.analogButton[first_trigger_button+i]; + } + } } SDL_assert(item->nhats <= 1); // there is (currently) only ever one of these, faked from the d-pad buttons. diff --git a/src/joystick/emscripten/SDL_sysjoystick_c.h b/src/joystick/emscripten/SDL_sysjoystick_c.h index 991959a759..751a303b00 100644 --- a/src/joystick/emscripten/SDL_sysjoystick_c.h +++ b/src/joystick/emscripten/SDL_sysjoystick_c.h @@ -35,11 +35,13 @@ typedef struct SDL_joylist_item SDL_JoystickID device_instance; SDL_Joystick *joystick; int first_hat_button; + int first_trigger_button; + bool triggers_are_buttons; int nhats; int nbuttons; int naxes; double timestamp; - double axis[64]; + double axis[64]; // !!! FIXME: don't hardcode 64 on all of these. double analogButton[64]; EM_BOOL digitalButton[64]; Uint8 hat; // there is (currently) only ever one of these, faked from the d-pad buttons.