From 98e0329ad90ca41f75de4253b2316b1615a74b1e Mon Sep 17 00:00:00 2001 From: Eri the Switch Date: Mon, 24 Aug 2026 11:38:03 +0300 Subject: [PATCH] joystick: Accept partial user calibration for sticks on Switch controllers This allows user stick calibration to be applied on JoyCons and possibly partially user calibrated Pro controllers. (cherry picked from commit fb8a32cc75b228030220ecfbca95b08999db0ec6) --- src/joystick/hidapi/SDL_hidapi_switch.c | 31 ++++++++++++++++--------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c index 8b56dcee01..4ac546964a 100644 --- a/src/joystick/hidapi/SDL_hidapi_switch.c +++ b/src/joystick/hidapi/SDL_hidapi_switch.c @@ -960,14 +960,14 @@ static bool SetIMUEnabled(SDL_DriverSwitch_Context *ctx, bool enabled) static bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx) { - Uint8 *pLeftStickCal = NULL; - Uint8 *pRightStickCal = NULL; + Uint8 pLeftStickCal[9]; + Uint8 pRightStickCal[9]; + bool have_left_stick_cal = false, have_right_stick_cal = false; size_t stick, axis; SwitchSubcommandInputPacket_t *user_reply = NULL; SwitchSubcommandInputPacket_t *factory_reply = NULL; SwitchSPIOpData_t readUserParams; SwitchSPIOpData_t readFactoryParams; - Uint8 userParamsReadSuccessCount = 0; // Read User Calibration Info readUserParams.unAddress = k_unSPIStickUserCalibrationStartOffset; @@ -982,17 +982,17 @@ static bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx) // Automatically select the user calibration if magic bytes are set if (user_reply && user_reply->stickUserCalibration.rgucLeftMagic[0] == 0xB2 && user_reply->stickUserCalibration.rgucLeftMagic[1] == 0xA1) { - userParamsReadSuccessCount += 1; - pLeftStickCal = user_reply->stickUserCalibration.rgucLeftCalibration; + have_left_stick_cal = true; + SDL_memcpy(pLeftStickCal, user_reply->stickUserCalibration.rgucLeftCalibration, sizeof(pLeftStickCal)); } if (user_reply && user_reply->stickUserCalibration.rgucRightMagic[0] == 0xB2 && user_reply->stickUserCalibration.rgucRightMagic[1] == 0xA1) { - userParamsReadSuccessCount += 1; - pRightStickCal = user_reply->stickUserCalibration.rgucRightCalibration; + have_right_stick_cal = true; + SDL_memcpy(pRightStickCal, user_reply->stickUserCalibration.rgucRightCalibration, sizeof(pRightStickCal)); } // Only read the factory calibration info if we failed to receive the correct magic bytes - if (userParamsReadSuccessCount < 2) { + if (!have_left_stick_cal || !have_right_stick_cal) { // Read Factory Calibration Info readFactoryParams.unAddress = k_unSPIStickFactoryCalibrationStartOffset; readFactoryParams.ucLength = k_unSPIStickFactoryCalibrationLength; @@ -1005,8 +1005,17 @@ static bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx) if (factory_reply->stickFactoryCalibration.opData.unAddress == k_unSPIStickFactoryCalibrationStartOffset) { // We successfully read the calibration data - pLeftStickCal = factory_reply->stickFactoryCalibration.rgucLeftCalibration; - pRightStickCal = factory_reply->stickFactoryCalibration.rgucRightCalibration; + // Avoid overriding user calibration if it's present for only one stick (known to happen on JoyCons) + if (!have_left_stick_cal) { + have_left_stick_cal = true; + SDL_memcpy(pLeftStickCal, user_reply->stickFactoryCalibration.rgucLeftCalibration, sizeof(pLeftStickCal)); + } + + if (!have_right_stick_cal) { + have_right_stick_cal = true; + SDL_memcpy(pRightStickCal, user_reply->stickFactoryCalibration.rgucRightCalibration, sizeof(pRightStickCal)); + } + break; } @@ -1017,7 +1026,7 @@ static bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx) } // If we still don't have calibration data, return false - if (pLeftStickCal == NULL || pRightStickCal == NULL) + if (!have_left_stick_cal || !have_right_stick_cal) { return false; }