From 2ceb9942f3e0c8a08fa3f6b600cc5166be9af8f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 22 May 2023 10:13:57 +0200 Subject: [PATCH] Tilt: Add back inverse deadzone (low end radius). Allow choosing circular or per-axis. --- Core/Config.cpp | 1 + Core/Config.h | 2 ++ Core/TiltEventProcessor.cpp | 25 ++++++++++++++++++++++++- UI/TiltAnalogSettingsScreen.cpp | 2 ++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 8a3b0f36f7..7134ba3611 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -681,6 +681,7 @@ static const ConfigSetting controlSettings[] = { ConfigSetting("TiltSensitivityX", &g_Config.iTiltSensitivityX, 60, CfgFlag::PER_GAME), ConfigSetting("TiltSensitivityY", &g_Config.iTiltSensitivityY, 60, CfgFlag::PER_GAME), ConfigSetting("TiltAnalogDeadzoneRadius", &g_Config.fTiltAnalogDeadzoneRadius, 0.0f, CfgFlag::PER_GAME), + ConfigSetting("TiltInverseDeadzone", &g_Config.fTiltInverseDeadzone, 0.0f, CfgFlag::PER_GAME), ConfigSetting("TiltInputType", &g_Config.iTiltInputType, 0, CfgFlag::PER_GAME), #endif diff --git a/Core/Config.h b/Core/Config.h index 1d36130b49..4b60575d64 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -279,6 +279,8 @@ public: int iTiltSensitivityY; // The deadzone radius of the tilt. Only used in the analog mapping. float fTiltAnalogDeadzoneRadius; + float fTiltInverseDeadzone; // An inverse deadzone for the output, counteracting excessive deadzones applied by games. See #17483. + bool bTiltCircularInverseDeadzone; // Type of tilt input currently selected: Defined in TiltEventProcessor.h // 0 - no tilt, 1 - analog stick, 2 - D-Pad, 3 - Action Buttons (Tri, Cross, Square, Circle) int iTiltInputType; diff --git a/Core/TiltEventProcessor.cpp b/Core/TiltEventProcessor.cpp index 9b4bdecdab..14486e84bd 100644 --- a/Core/TiltEventProcessor.cpp +++ b/Core/TiltEventProcessor.cpp @@ -40,6 +40,24 @@ inline float ApplyDeadzone(float x, float deadzone) { } } +// Also clamps to -1.0..1.0. +// This applies a (circular if desired) inverse deadzone. +inline void ApplyInverseDeadzone(float x, float y, float *outX, float *outY, float inverseDeadzone, bool circular) { + if (inverseDeadzone == 0.0f) { + *outX = Clamp(x, -1.0f, 1.0f); + *outY = Clamp(y, -1.0f, 1.0f); + } + if (circular) { + float magnitude = sqrtf(x * x + y * y); + magnitude = (magnitude + inverseDeadzone) / magnitude; + *outX = Clamp(x * magnitude, -1.0f, 1.0f); + *outY = Clamp(y * magnitude, -1.0f, 1.0f); + } else { + *outX = Clamp(x + copysignf(inverseDeadzone, x), -1.0f, 1.0f); + *outY = Clamp(y + copysignf(inverseDeadzone, y), -1.0f, 1.0f); + } +} + void ProcessTilt(bool landscape, float calibrationAngle, float x, float y, float z, bool invertX, bool invertY, float xSensitivity, float ySensitivity) { if (g_Config.iTiltInputType == TILT_NULL) { // Turned off - nothing to do. @@ -79,9 +97,14 @@ void ProcessTilt(bool landscape, float calibrationAngle, float x, float y, float if (g_Config.iTiltInputType == TILT_ANALOG) { // Only analog mappings use the deadzone. - float adjustedTiltX = ApplyDeadzone(tiltX, g_Config.fTiltAnalogDeadzoneRadius); float adjustedTiltY = ApplyDeadzone(tiltY, g_Config.fTiltAnalogDeadzoneRadius); + + // Unlike regular deadzone, where per-axis is okay, inverse deadzone (to compensate for game deadzones) really needs to be + // applied on the two axes together. + // TODO: Share this code with the joystick code. For now though, we keep it separate. + ApplyInverseDeadzone(adjustedTiltX, adjustedTiltY, &adjustedTiltX, &adjustedTiltY, g_Config.fTiltInverseDeadzone, g_Config.bTiltCircularInverseDeadzone); + rawTiltAnalogX = adjustedTiltX; rawTiltAnalogY = adjustedTiltY; GenerateAnalogStickEvent(adjustedTiltX, adjustedTiltY); diff --git a/UI/TiltAnalogSettingsScreen.cpp b/UI/TiltAnalogSettingsScreen.cpp index 97430af42c..73cb24e37d 100644 --- a/UI/TiltAnalogSettingsScreen.cpp +++ b/UI/TiltAnalogSettingsScreen.cpp @@ -123,6 +123,8 @@ void TiltAnalogSettingsScreen::CreateViews() { settings->Add(new ItemHeader(co->T("Sensitivity"))); if (g_Config.iTiltInputType == 1) { settings->Add(new PopupSliderChoiceFloat(&g_Config.fTiltAnalogDeadzoneRadius, 0.0f, 0.8f, 0.0f, co->T("Deadzone radius"), 0.01f, screenManager(), "/ 1.0"))->SetEnabledFunc(enabledFunc); + settings->Add(new PopupSliderChoiceFloat(&g_Config.fTiltInverseDeadzone, 0.0f, 0.8f, 0.0f, co->T("Low end radius"), 0.0f, screenManager(), "/ 1.0"))->SetEnabledFunc(enabledFunc); + settings->Add(new CheckBox(&g_Config.bTiltCircularInverseDeadzone, co->T("Circular low end radius")))->SetEnabledFunc(enabledFunc); } settings->Add(new PopupSliderChoice(&g_Config.iTiltSensitivityX, 0, 100, 60, co->T("Tilt Sensitivity along X axis"), screenManager(), "%"))->SetEnabledFunc(enabledFunc); settings->Add(new PopupSliderChoice(&g_Config.iTiltSensitivityY, 0, 100, 60, co->T("Tilt Sensitivity along Y axis"), screenManager(), "%"))->SetEnabledFunc(enabledFunc);