diff --git a/include/SDL_hints.h b/include/SDL_hints.h index 10171c445..9e8295b48 100644 --- a/include/SDL_hints.h +++ b/include/SDL_hints.h @@ -672,6 +672,17 @@ extern "C" { */ #define SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS "SDL_JOYSTICK_HIDAPI_COMBINE_JOY_CONS" +/** + * \brief A variable controlling whether Nintendo Switch Joy-Con controllers will be in vertical mode when using the HIDAPI driver + * + * This variable can be set to the following values: + * "0" - Left and right Joy-Con controllers will not be in vertical mode (the default) + * "1" - Left and right Joy-Con controllers will be in vertical mode + * + * This hint must be set before calling SDL_Init(SDL_INIT_GAMECONTROLLER) + */ +#define SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS "SDL_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS" + /** * \brief A variable controlling whether the HIDAPI driver for Amazon Luna controllers connected via Bluetooth should be used. * diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c index b764980e9..60446877d 100644 --- a/src/joystick/SDL_gamecontroller.c +++ b/src/joystick/SDL_gamecontroller.c @@ -606,8 +606,17 @@ static ControllerMapping_t *SDL_CreateMappingForHIDAPIController(SDL_JoystickGUI } break; default: - /* Mini gamepad mode */ - SDL_strlcat(mapping_string, "a:b0,b:b1,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,", sizeof(mapping_string)); + if (SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS, SDL_FALSE)) { + /* Vertical mode */ + if (guid.data[15] == k_eSwitchDeviceInfoControllerType_JoyConLeft) { + SDL_strlcat(mapping_string, "back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b15,", sizeof(mapping_string)); + } else { + SDL_strlcat(mapping_string, "a:b0,b:b1,guide:b5,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,", sizeof(mapping_string)); + } + } else { + /* Mini gamepad mode */ + SDL_strlcat(mapping_string, "a:b0,b:b1,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,", sizeof(mapping_string)); + } break; } } else { diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c index f441c79c9..ff2930c3d 100644 --- a/src/joystick/hidapi/SDL_hidapi_switch.c +++ b/src/joystick/hidapi/SDL_hidapi_switch.c @@ -262,6 +262,7 @@ typedef struct { Uint32 m_unIMUSamples; Uint32 m_unIMUUpdateIntervalUS; Uint64 m_ulTimestampUS; + SDL_bool m_bVerticalMode; SwitchInputOnlyControllerStatePacket_t m_lastInputOnlyState; SwitchSimpleStatePacket_t m_lastSimpleState; @@ -1410,7 +1411,7 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti SDL_PlayerLEDHintChanged, ctx); /* Initialize the joystick capabilities */ - joystick->nbuttons = 16; + joystick->nbuttons = 20; joystick->naxes = SDL_CONTROLLER_AXIS_MAX; joystick->epowerlevel = device->is_bluetooth ? SDL_JOYSTICK_POWER_UNKNOWN : SDL_JOYSTICK_POWER_WIRED; @@ -1419,6 +1420,9 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti ctx->m_unLastIMUReset = ctx->m_unLastInput = SDL_GetTicks(); ctx->m_unIMUUpdateIntervalUS = 5 * 1000; /* Start off at 5 ms update rate */ + /* Set up for vertical mode */ + ctx->m_bVerticalMode = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS, SDL_FALSE); + return SDL_TRUE; } @@ -1824,6 +1828,8 @@ static void HandleCombinedControllerStateL(SDL_Joystick *joystick, SDL_DriverSwi SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED); SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED); SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED); + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_PADDLE2, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED); + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_PADDLE1, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED); SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED); axis = (data & 0x80) ? 32767 : -32768; SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis); @@ -1857,6 +1863,9 @@ static void HandleMiniControllerStateL(SDL_Joystick *joystick, SDL_DriverSwitch_ SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_B), (data & 0x08) ? SDL_PRESSED : SDL_RELEASED); SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED); SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED); + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_PADDLE1, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED); + axis = (data & 0x80) ? 32767 : -32768; + SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis); } axis = packet->controllerState.rgucJoystickLeft[0] | ((packet->controllerState.rgucJoystickLeft[1] & 0xF) << 8); @@ -1878,6 +1887,8 @@ static void HandleCombinedControllerStateR(SDL_Joystick *joystick, SDL_DriverSwi SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_B), (data & 0x04) ? SDL_PRESSED : SDL_RELEASED); SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_X), (data & 0x02) ? SDL_PRESSED : SDL_RELEASED); SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_Y), (data & 0x01) ? SDL_PRESSED : SDL_RELEASED); + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_PADDLE4, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED); + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_PADDLE3, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED); SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED); axis = (data & 0x80) ? 32767 : -32768; SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis); @@ -1911,6 +1922,9 @@ static void HandleMiniControllerStateR(SDL_Joystick *joystick, SDL_DriverSwitch_ SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_X), (data & 0x01) ? SDL_PRESSED : SDL_RELEASED); SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED); SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED); + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_PADDLE4, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED); + axis = (data & 0x80) ? 32767 : -32768; + SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis); } if (packet->controllerState.rgucButtons[1] != ctx->m_lastFullState.controllerState.rgucButtons[1]) { @@ -1932,13 +1946,13 @@ static void HandleMiniControllerStateR(SDL_Joystick *joystick, SDL_DriverSwitch_ static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchStatePacket_t *packet) { if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConLeft) { - if (ctx->device->parent) { + if (ctx->device->parent || ctx->m_bVerticalMode) { HandleCombinedControllerStateL(joystick, ctx, packet); } else { HandleMiniControllerStateL(joystick, ctx, packet); } } else if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) { - if (ctx->device->parent) { + if (ctx->device->parent || ctx->m_bVerticalMode) { HandleCombinedControllerStateR(joystick, ctx, packet); } else { HandleMiniControllerStateR(joystick, ctx, packet);