From 3d4b29d9b980789771ff1d1bd7274ac4024cf322 Mon Sep 17 00:00:00 2001 From: patchzyy <64382339+patchzyy@users.noreply.github.com> Date: Sun, 18 Oct 2026 11:34:19 +0200 Subject: [PATCH] Fix soft-drift --- aurora-main/cmake/AuroraSDL3Patches.cmake | 38 +++++++++++++++++++++++ runtime/src/wii_remote_input.cpp | 37 +++++++++++++++------- 2 files changed, 63 insertions(+), 12 deletions(-) diff --git a/aurora-main/cmake/AuroraSDL3Patches.cmake b/aurora-main/cmake/AuroraSDL3Patches.cmake index 7af051e..cea23c1 100644 --- a/aurora-main/cmake/AuroraSDL3Patches.cmake +++ b/aurora-main/cmake/AuroraSDL3Patches.cmake @@ -118,6 +118,44 @@ static void UpdateDeviceIdentity(SDL_HIDAPI_Device *device) now = SDL_GetTicks(); ]==]) + + # Classic Controller sticks: the stock path stretches each half-range by learned min/max; + # this posts WPAD's linear value (raw - first-report centre) * unit, times 64. + _aurora_sdl3_replace("${_wii}" "Wii Classic Controller linear sticks (helper)" +[==[static void HandleGamepadControllerButtonData(SDL_DriverWii_Context *ctx, SDL_Joystick *joystick, const WiiButtonData *data) +{ +]==] +[==[/* WiiCompiled: axis = (raw - centre) * unit * 64, y inverted; see AuroraSDL3Patches.cmake */ +static void PostClassicStickLinear(Uint64 timestamp, SDL_Joystick *joystick, StickCalibrationData *calibration, Uint8 axis, Uint16 data, int unit) +{ + int value; + + if (!calibration->center) { + // Center on first read + calibration->center = data; + return; + } + value = ((int)data - (int)calibration->center) * unit * 64; + if (axis == SDL_GAMEPAD_AXIS_LEFTY || axis == SDL_GAMEPAD_AXIS_RIGHTY) { + value = -value; + } + SDL_SendJoystickAxis(timestamp, joystick, axis, (Sint16)SDL_clamp(value, SDL_JOYSTICK_AXIS_MIN, SDL_JOYSTICK_AXIS_MAX)); +} + +static void HandleGamepadControllerButtonData(SDL_DriverWii_Context *ctx, SDL_Joystick *joystick, const WiiButtonData *data) +{ +]==]) + _aurora_sdl3_replace("${_wii}" "Wii Classic Controller linear sticks (axes)" +[==[ PostStickCalibrated(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[0], SDL_GAMEPAD_AXIS_LEFTX, lx); + PostStickCalibrated(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[1], SDL_GAMEPAD_AXIS_LEFTY, ly); + PostStickCalibrated(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[2], SDL_GAMEPAD_AXIS_RIGHTX, rx); + PostStickCalibrated(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[3], SDL_GAMEPAD_AXIS_RIGHTY, ry); +]==] +[==[ PostClassicStickLinear(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[0], SDL_GAMEPAD_AXIS_LEFTX, lx, 16); + PostClassicStickLinear(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[1], SDL_GAMEPAD_AXIS_LEFTY, ly, 16); + PostClassicStickLinear(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[2], SDL_GAMEPAD_AXIS_RIGHTX, rx, 32); + PostClassicStickLinear(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[3], SDL_GAMEPAD_AXIS_RIGHTY, ry, 32); +]==]) endfunction() # Script mode (FetchContent PATCH_COMMAND). diff --git a/runtime/src/wii_remote_input.cpp b/runtime/src/wii_remote_input.cpp index 8cd9753..84b7ede 100644 --- a/runtime/src/wii_remote_input.cpp +++ b/runtime/src/wii_remote_input.cpp @@ -602,15 +602,30 @@ void FillGraceSample(uint32_t chan, Kind kind, KpadSample& sample) { sample.hasClassic = kind == Kind::RemoteWithClassic; } -// SDL's stick axis (-32767..32767, y down) as WPADCLStatus carries it: WPAD -// normalises every Classic Controller stick, whatever the report's resolution, -// to a signed 10-bit value, -512..511 with 0 at the centre and +y up (RVL SDK -// WPAD.h; wut's WPADStatusClassic documents the same range). +// The patched SDL Wii driver posts Classic Controller sticks as WPAD's own +// value times 64 (aurora-main/cmake/AuroraSDL3Patches.cmake), so WPADCLStatus +// is the axis divided back: signed, 0 at the centre, -512..511, +y up. int16_t ClassicStickRaw(Sint16 axis, bool invert) { - float value = static_cast(axis) / 32767.0f; - if (invert) value = -value; - value = std::clamp(value, -1.0f, 1.0f); - return static_cast(std::clamp(std::lround(value * 512.0f), -512L, 511L)); + const long value = invert ? -static_cast(axis) : axis; + return static_cast(std::clamp(std::lround(value / 64.0), -512L, 511L)); +} + +// KPAD's default Classic Controller stick limits; the game uses the cross clamp. +constexpr float kKpadStickMin = 60.0f; +constexpr float kKpadStickMax = 308.0f; + +// KPAD cross clamp: per-axis dead zone and scale, then the unit circle. +void ClassicStickFloat(const int16_t raw[2], float out[2]) { + for (int i = 0; i < 2; ++i) { + const float magnitude = std::fabs(static_cast(raw[i])); + const float scaled = std::clamp((magnitude - kKpadStickMin) / (kKpadStickMax - kKpadStickMin), 0.0f, 1.0f); + out[i] = raw[i] < 0 ? -scaled : scaled; + } + const float length = std::sqrt(out[0] * out[0] + out[1] * out[1]); + if (length > 1.0f) { + out[0] /= length; + out[1] /= length; + } } // Samples buttons, accelerometers and the extension of the remote on a port. @@ -696,14 +711,12 @@ bool ReadKpadSample(uint32_t chan, KpadSample& sample) { const Sint16 ly = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTY); const Sint16 rx = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTX); const Sint16 ry = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTY); - sample.clLStick[0] = std::clamp(static_cast(lx) / 32767.0f, -1.0f, 1.0f); - sample.clLStick[1] = std::clamp(-static_cast(ly) / 32767.0f, -1.0f, 1.0f); - sample.clRStick[0] = std::clamp(static_cast(rx) / 32767.0f, -1.0f, 1.0f); - sample.clRStick[1] = std::clamp(-static_cast(ry) / 32767.0f, -1.0f, 1.0f); sample.clLStickRaw[0] = ClassicStickRaw(lx, false); sample.clLStickRaw[1] = ClassicStickRaw(ly, true); sample.clRStickRaw[0] = ClassicStickRaw(rx, false); sample.clRStickRaw[1] = ClassicStickRaw(ry, true); + ClassicStickFloat(sample.clLStickRaw, sample.clLStick); + ClassicStickFloat(sample.clRStickRaw, sample.clRStick); // Only the full-press click of L/R reaches SDL; report it as a full pull. sample.clTriggerL = (sample.clHold & kClL) ? 255 : 0; sample.clTriggerR = (sample.clHold & kClR) ? 255 : 0;