From 8c95bd814bf1cf0ea1f12aa724938176a7dfd780 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 13 Jun 2023 22:40:51 -0700 Subject: [PATCH] Allow switching licensed Nintendo Switch Pro controllers into gyro input mode --- src/joystick/hidapi/SDL_hidapi_switch.c | 56 +++++++++++++++---------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c index 080f682b5..e01f13daf 100644 --- a/src/joystick/hidapi/SDL_hidapi_switch.c +++ b/src/joystick/hidapi/SDL_hidapi_switch.c @@ -717,13 +717,35 @@ static void SDLCALL SDL_PlayerLEDHintChanged(void *userdata, const char *name, c } } +static Uint8 GetDefaultInputMode(SDL_DriverSwitch_Context *ctx) +{ + Uint8 input_mode; + + /* Determine the desired input mode */ + if (ctx->device->is_bluetooth) { + input_mode = k_eSwitchInputReportIDs_SimpleControllerState; + } else { + input_mode = k_eSwitchInputReportIDs_FullControllerState; + } + + /* The official Nintendo Switch Pro Controller supports FullControllerState over Bluetooth + * just fine. We really should use that, or else the epowerlevel code in HandleFullControllerState + * is completely pointless. We need full state if we want battery level and we only care about + * battery level over Bluetooth anyway. + */ + if (ctx->device->vendor_id == USB_VENDOR_NINTENDO) { + input_mode = k_eSwitchInputReportIDs_FullControllerState; + } + return input_mode; +} + static SDL_bool SetIMUEnabled(SDL_DriverSwitch_Context *ctx, SDL_bool enabled) { Uint8 imu_data = enabled ? 1 : 0; return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_EnableIMU, &imu_data, sizeof(imu_data), NULL); } -static SDL_bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx, Uint8 input_mode) +static SDL_bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx) { Uint8 *pLeftStickCal; Uint8 *pRightStickCal; @@ -1296,7 +1318,6 @@ static void HIDAPI_DriverSwitch_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, static SDL_bool HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context; - Uint8 input_mode; SDL_AssertJoysticksLocked(); @@ -1316,24 +1337,7 @@ static SDL_bool HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_ } } - /* Determine the desired input mode (needed before loading stick calibration) */ - if (device->is_bluetooth) { - input_mode = k_eSwitchInputReportIDs_SimpleControllerState; - } else { - input_mode = k_eSwitchInputReportIDs_FullControllerState; - } - - /* The official Nintendo Switch Pro Controller supports FullControllerState over bluetooth - * just fine. We really should use that, or else the epowerlevel code in - * HandleFullControllerState is completely pointless. We need full state if we want battery - * level and we only care about battery level over bluetooth anyway. - */ - if (device->vendor_id == USB_VENDOR_NINTENDO) { - input_mode = k_eSwitchInputReportIDs_FullControllerState; - } - - if (input_mode == k_eSwitchInputReportIDs_FullControllerState && - ctx->m_eControllerType != k_eSwitchDeviceInfoControllerType_NESLeft && + if (ctx->m_eControllerType != k_eSwitchDeviceInfoControllerType_NESLeft && ctx->m_eControllerType != k_eSwitchDeviceInfoControllerType_NESRight && ctx->m_eControllerType != k_eSwitchDeviceInfoControllerType_SNES && ctx->m_eControllerType != k_eSwitchDeviceInfoControllerType_N64 && @@ -1356,7 +1360,7 @@ static SDL_bool HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_ } } - if (!LoadStickCalibration(ctx, input_mode)) { + if (!LoadStickCalibration(ctx)) { SDL_SetError("Couldn't load stick calibration"); return SDL_FALSE; } @@ -1372,7 +1376,7 @@ static SDL_bool HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_ } /* Set desired input mode */ - if (!SetInputMode(ctx, input_mode)) { + if (!SetInputMode(ctx, GetDefaultInputMode(ctx))) { SDL_SetError("Couldn't set input mode"); return SDL_FALSE; } @@ -1604,6 +1608,14 @@ static int HIDAPI_DriverSwitch_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL static int HIDAPI_DriverSwitch_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled) { SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context; + Uint8 input_mode; + + if (enabled) { + input_mode = k_eSwitchInputReportIDs_FullControllerState; + } else { + input_mode = GetDefaultInputMode(ctx); + } + SetInputMode(ctx, input_mode); SetIMUEnabled(ctx, enabled); ctx->m_bReportSensors = enabled;