From 043b0a437c154a8aabbfec9ac4d6508a16ab0890 Mon Sep 17 00:00:00 2001 From: David Cottingham Date: Sat, 16 May 2026 19:09:25 -1000 Subject: [PATCH 1/2] Add Steam Input-style advanced deadzone controls to analog calibration --- Core/Config.cpp | 8 ++++ Core/Config.h | 15 ++++++ Core/ControlMapper.cpp | 92 +++++++++++++++++++++++++++++++++---- UI/ControlMappingScreen.cpp | 36 ++++++++++++++- UI/JoystickHistoryView.cpp | 57 +++++++++++++++++++++++ 5 files changed, 198 insertions(+), 10 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index e7fd30d525..dc2a080a7a 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1023,6 +1023,14 @@ static const ConfigSetting controlSettings[] = { ConfigSetting("AnalogIsCircular", SETTING(g_Config, bAnalogIsCircular), false, CfgFlag::PER_GAME), ConfigSetting("AnalogAutoRotSpeed", SETTING(g_Config, fAnalogAutoRotSpeed), 8.0f, CfgFlag::PER_GAME), + // Advanced analog deadzone settings. + ConfigSetting("AnalogDeadzoneShape", SETTING(g_Config, iAnalogDeadzoneShape), 1, CfgFlag::PER_GAME), // Default 1 (Square) matches legacy max-norm behavior + ConfigSetting("AnalogAxialDeadzone", SETTING(g_Config, fAnalogAxialDeadzone), 0.0f, CfgFlag::PER_GAME), + ConfigSetting("AnalogOuterDeadzone", SETTING(g_Config, fAnalogOuterDeadzone), 0.0f, CfgFlag::PER_GAME), + ConfigSetting("AnalogOutputAntiDeadzone", SETTING(g_Config, fAnalogOutputAntiDeadzone), 0.0f, CfgFlag::PER_GAME), + ConfigSetting("AnalogOutputAntiDeadzoneBuffer", SETTING(g_Config, fAnalogOutputAntiDeadzoneBuffer), 0.0f, CfgFlag::PER_GAME), + ConfigSetting("AnalogResponseCurve", SETTING(g_Config, iAnalogResponseCurve), 0, CfgFlag::PER_GAME), + ConfigSetting("AnalogLimiterDeadzone", SETTING(g_Config, fAnalogLimiterDeadzone), 0.6f, CfgFlag::DEFAULT), ConfigSetting("AnalogTriggerThreshold", SETTING(g_Config, fAnalogTriggerThreshold), 0.75f, CfgFlag::DEFAULT), ConfigSetting("AnalogStickThreshold", SETTING(g_Config, fAnalogStickThreshold), 0.75f, CfgFlag::DEFAULT), diff --git a/Core/Config.h b/Core/Config.h index 87f9f4d4d1..4802cf51a8 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -515,6 +515,21 @@ public: // Auto rotation speed float fAnalogAutoRotSpeed; + // Advanced analog deadzone settings (Steam Input-style). + // Deadzone shape: 0 = Circle, 1 = Square (default, matches legacy max-norm), 2 = Cross + int iAnalogDeadzoneShape; + // Cross-shaped axial anti-deadzone. Boosts small off-axis values past this threshold, + // making the output skip the zone near each cardinal axis to prevent axis snapping. + float fAnalogAxialDeadzone; + // Outer deadzone: defines where 100% output is reached. Shrinks the effective stick range. + float fAnalogOuterDeadzone; + // Output anti-deadzone: minimum output floor to bypass game-internal deadzones. + float fAnalogOutputAntiDeadzone; + // Anti-deadzone buffer: re-adds a small safe zone after anti-deadzone is applied. + float fAnalogOutputAntiDeadzoneBuffer; + // Response curve type: 0 = Linear, 1 = Aggressive, 2 = Relaxed, 3 = Wide + int iAnalogResponseCurve; + // Sets up how much the analog limiter button restricts digital->analog input. float fAnalogLimiterDeadzone; diff --git a/Core/ControlMapper.cpp b/Core/ControlMapper.cpp index 8b0e4759d9..97981e2653 100644 --- a/Core/ControlMapper.cpp +++ b/Core/ControlMapper.cpp @@ -105,28 +105,91 @@ static bool IsSignedAxis(int axis) { } } +// Apply a response curve to a 0-1 magnitude value. +static float ApplyResponseCurve(float v, int curveType) { + switch (curveType) { + case 1: // Aggressive - fast response, reaches high output quickly + return sqrtf(v); + case 2: // Relaxed - more range devoted to fine/slow movement + return v * v; + case 3: // Wide - even more precision at low end + return v * v * v; + default: // Linear (0) - 1:1 mapping + return v; + } +} + +// Apply axial anti-deadzone to a single axis value. +// For non-zero inputs, boosts the output to at least the threshold value. +// This makes the output "skip" the zone near each axis, preventing the stick +// from lingering in the near-cardinal region. Pure cardinal (0.0) is still reachable. +static float ApplyAxialAntiDeadzone(float v, float antiDZ) { + if (antiDZ <= 0.0f || v == 0.0f) + return v; + float sign = v >= 0.0f ? 1.0f : -1.0f; + float absV = fabsf(v); + // Remap (0, 1] -> [antiDZ, 1]: any non-zero input jumps past the anti-deadzone threshold. + float remapped = antiDZ + absV * (1.0f - antiDZ); + return sign * Clamp(remapped, 0.0f, 1.0f); +} + // This is applied on the circular radius, not directly on the axes. -// TODO: Share logic with tilt? +// Now includes outer deadzone, response curve, and output anti-deadzone stages. static float MapAxisValue(float v) { const float deadzone = g_Config.fAnalogDeadzone; const float invDeadzone = g_Config.fAnalogInverseDeadzone; const float sensitivity = g_Config.fAnalogSensitivity; + const float outerDeadzone = g_Config.fAnalogOuterDeadzone; + const float outputAntiDZ = g_Config.fAnalogOutputAntiDeadzone; + const float outputADBuffer = g_Config.fAnalogOutputAntiDeadzoneBuffer; + const int responseCurve = g_Config.iAnalogResponseCurve; const float sign = v >= 0.0f ? 1.0f : -1.0f; - // Apply deadzone. - v = Clamp((fabsf(v) - deadzone) / (1.0f - deadzone), 0.0f, 1.0f); + float absV = fabsf(v); - // Apply sensitivity and inverse deadzone. - if (v != 0.0f) { - v = Clamp(invDeadzone + v * (sensitivity - invDeadzone), 0.0f, 1.0f); + // Stage 1: Apply inner deadzone and rescale to [0, 1]. + // The effective range is [deadzone, 1 - outerDeadzone]. + float effectiveMax = 1.0f - outerDeadzone; + float effectiveRange = effectiveMax - deadzone; + if (effectiveRange <= 0.0f) { + // Degenerate case: deadzone + outerDeadzone >= 1.0. Output is either 0 or 1. + absV = (absV > deadzone) ? 1.0f : 0.0f; + } else { + absV = Clamp((absV - deadzone) / effectiveRange, 0.0f, 1.0f); } - return sign * v; + // Stage 2: Apply sensitivity (legacy, works the same as before when new settings are at defaults). + if (absV != 0.0f) { + absV = Clamp(invDeadzone + absV * (sensitivity - invDeadzone), 0.0f, 1.0f); + } + + // Stage 3: Apply response curve. + if (absV != 0.0f) { + absV = ApplyResponseCurve(absV, responseCurve); + } + + // Stage 4: Apply output anti-deadzone with buffer. + // Anti-deadzone sets a minimum output floor so that even the smallest + // stick input past the deadzone produces enough signal to overcome + // game-internal deadzones. The buffer re-adds a small safe zone so + // resting your thumb on the stick doesn't cause unintended drift. + if (absV != 0.0f && outputAntiDZ > 0.0f) { + // Remap [0, 1] -> [outputAntiDZ, 1] + absV = outputAntiDZ + absV * (1.0f - outputAntiDZ); + } + if (outputADBuffer > 0.0f && absV > 0.0f && absV < outputAntiDZ + outputADBuffer) { + // Within the buffer zone past the anti-deadzone floor: zero it out. + absV = 0.0f; + } + + return sign * Clamp(absV, 0.0f, 1.0f); } void ConvertAnalogStick(float x, float y, float *outX, float *outY) { const bool isCircular = g_Config.bAnalogIsCircular; + const int deadzoneShape = g_Config.iAnalogDeadzoneShape; + const float axialDZ = g_Config.fAnalogAxialDeadzone; float norm = std::max(fabsf(x), fabsf(y)); if (norm == 0.0f) { @@ -135,17 +198,30 @@ void ConvertAnalogStick(float x, float y, float *outX, float *outY) { return; } - if (isCircular) { + if (isCircular || deadzoneShape == 0) { + // Circle shape or legacy circular mode: use Euclidean norm. float newNorm = sqrtf(x * x + y * y); float factor = newNorm / norm; x *= factor; y *= factor; norm = newNorm; } + // deadzoneShape == 1 (Square) uses max norm (the default path, no conversion needed). + // deadzoneShape == 2 (Cross) also uses max norm for the radial processing. float mappedNorm = MapAxisValue(norm); *outX = Clamp(x / norm * mappedNorm, -1.0f, 1.0f); *outY = Clamp(y / norm * mappedNorm, -1.0f, 1.0f); + + // Final stage: Apply cross-shaped axial anti-deadzone. + // This boosts small non-zero axis values past the threshold, making the output + // "skip" the zone near each cardinal axis. This prevents the stick from lingering + // near cardinals and opens up the full diagonal range. + // Pure cardinals (0.0 on an axis) are still reachable. + if (deadzoneShape == 2 && axialDZ > 0.0f) { + *outX = ApplyAxialAntiDeadzone(*outX, axialDZ); + *outY = ApplyAxialAntiDeadzone(*outY, axialDZ); + } } void ControlMapper::SetPSPAxis(int device, int stick, char axis, float value) { diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 48f2a771e6..43ec0c346f 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -551,9 +551,34 @@ void AnalogCalibrationScreen::CreateSettingsViews(UI::ViewGroup *scrollContents) scrollContents->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogDeadzone, 0.0f, 0.5f, 0.15f, co->T("Deadzone radius"), 0.01f, screenManager(), "/ 1.0")); scrollContents->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogInverseDeadzone, 0.0f, 1.0f, 0.0f, co->T("Low end radius"), 0.01f, screenManager(), "/ 1.0")); scrollContents->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogSensitivity, 0.0f, 2.0f, 1.1f, co->T("Sensitivity (scale)", "Sensitivity"), 0.01f, screenManager(), "x")); - // TODO: This should probably be a slider. - scrollContents->Add(new CheckBox(&g_Config.bAnalogIsCircular, co->T("Circular stick input"))); + // Legacy circular toggle. Disabled when deadzone shape is set to Circle, since that already provides circular behavior. + CheckBox *circularCheck = scrollContents->Add(new CheckBox(&g_Config.bAnalogIsCircular, co->T("Circular stick input"))); + circularCheck->SetEnabledFunc([] { + return g_Config.iAnalogDeadzoneShape != 0; // Disabled when shape is Circle (redundant) + }); scrollContents->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogAutoRotSpeed, 0.1f, 20.0f, 8.0f, co->T("Auto-rotation speed"), 1.0f, screenManager())); + + // Advanced deadzone settings (Steam Input-style). + scrollContents->Add(new ItemHeader(co->T("Advanced Deadzone Settings"))); + + static const char *deadzoneShapes[] = { "Circle", "Square", "Cross" }; + scrollContents->Add(new PopupMultiChoice(&g_Config.iAnalogDeadzoneShape, co->T("Deadzone shape"), deadzoneShapes, 0, ARRAY_SIZE(deadzoneShapes), I18NCat::CONTROLS, screenManager())); + + PopupSliderChoiceFloat *axialDZ = scrollContents->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogAxialDeadzone, 0.0f, 0.5f, 0.0f, co->T("Axial anti-deadzone"), 0.01f, screenManager(), "/ 1.0")); + axialDZ->SetEnabledFunc([] { + return g_Config.iAnalogDeadzoneShape == 2; // Only enabled for Cross shape + }); + + scrollContents->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogOuterDeadzone, 0.0f, 0.3f, 0.0f, co->T("Outer deadzone"), 0.01f, screenManager(), "/ 1.0")); + scrollContents->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogOutputAntiDeadzone, 0.0f, 0.5f, 0.0f, co->T("Output anti-deadzone"), 0.01f, screenManager(), "/ 1.0")); + PopupSliderChoiceFloat *adBuffer = scrollContents->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogOutputAntiDeadzoneBuffer, 0.0f, 0.2f, 0.0f, co->T("Anti-deadzone buffer"), 0.01f, screenManager(), "/ 1.0")); + adBuffer->SetEnabledFunc([] { + return g_Config.fAnalogOutputAntiDeadzone > 0.0f; // Buffer only makes sense with anti-deadzone active + }); + + static const char *responseCurves[] = { "Linear", "Aggressive", "Relaxed", "Wide" }; + scrollContents->Add(new PopupMultiChoice(&g_Config.iAnalogResponseCurve, co->T("Response curve"), responseCurves, 0, ARRAY_SIZE(responseCurves), I18NCat::CONTROLS, screenManager())); + scrollContents->Add(new Choice(co->T("Reset to defaults")))->OnClick.Handle(this, &AnalogCalibrationScreen::OnResetToDefaults); } @@ -576,6 +601,13 @@ void AnalogCalibrationScreen::OnResetToDefaults(UI::EventParams &e) { g_Config.fAnalogSensitivity = 1.1f; g_Config.bAnalogIsCircular = false; g_Config.fAnalogAutoRotSpeed = 8.0f; + // Advanced settings + g_Config.iAnalogDeadzoneShape = 1; // Square (matches legacy default) + g_Config.fAnalogAxialDeadzone = 0.0f; + g_Config.fAnalogOuterDeadzone = 0.0f; + g_Config.fAnalogOutputAntiDeadzone = 0.0f; + g_Config.fAnalogOutputAntiDeadzoneBuffer = 0.0f; + g_Config.iAnalogResponseCurve = 0; } class Backplate : public UI::InertView { diff --git a/UI/JoystickHistoryView.cpp b/UI/JoystickHistoryView.cpp index a7794ed3b5..8250f8e019 100644 --- a/UI/JoystickHistoryView.cpp +++ b/UI/JoystickHistoryView.cpp @@ -1,10 +1,13 @@ #include +#include #include "UI/JoystickHistoryView.h" +#include "Common/Math/math_util.h" #include "Common/UI/Context.h" #include "Common/UI/UI.h" +#include "Core/Config.h" #include "Core/ControlMapper.h" void JoystickHistoryView::Draw(UIContext &dc) { @@ -20,6 +23,22 @@ void JoystickHistoryView::Draw(UIContext &dc) { dc.Flush(); dc.BeginNoTex(); dc.Draw()->RectOutline(bounds_.centerX() - minRadius, bounds_.centerY() - minRadius, minRadius * 2.0f, minRadius * 2.0f, 0x80FFFFFF); + + // Draw cross-shaped deadzone strip outlines on the raw input view (untextured geometry). + if (type_ == StickHistoryViewType::INPUT) { + float cx = bounds_.centerX(); + float cy = bounds_.centerY(); + + // Cross-shaped (axial) deadzone strips. + if (g_Config.iAnalogDeadzoneShape == 2 && g_Config.fAnalogAxialDeadzone > 0.0f) { + float axialW = g_Config.fAnalogAxialDeadzone * minRadius; + // Vertical strip (X axis deadzone — zeroes X when |x| < threshold). + dc.Draw()->RectOutline(cx - axialW, cy - minRadius, axialW * 2.0f, minRadius * 2.0f, 0x604488FF); + // Horizontal strip (Y axis deadzone — zeroes Y when |y| < threshold). + dc.Draw()->RectOutline(cx - minRadius, cy - axialW, minRadius * 2.0f, axialW * 2.0f, 0x604488FF); + } + } + dc.Flush(); dc.Begin(); @@ -74,6 +93,44 @@ void JoystickHistoryView::Draw(UIContext &dc) { } + // Draw circular deadzone overlays on the raw input view (on top of the grid, textured context). + if (type_ == StickHistoryViewType::INPUT) { + float cx = bounds_.centerX(); + float cy = bounds_.centerY(); + + // Inner deadzone circle. + float innerDZ = g_Config.fAnalogDeadzone; + if (innerDZ > 0.0f) { + float innerR = innerDZ * minRadius; + const int segments = 32; + for (int i = 0; i < segments; i++) { + float a1 = (float)i / (float)segments * 2.0f * (float)M_PI; + float a2 = (float)(i + 1) / (float)segments * 2.0f * (float)M_PI; + float x1 = cx + cosf(a1) * innerR; + float y1 = cy + sinf(a1) * innerR; + float x2 = cx + cosf(a2) * innerR; + float y2 = cy + sinf(a2) * innerR; + dc.Draw()->Line(dc.GetTheme().whiteImage, x1, y1, x2, y2, 1.5f, 0x60FF6666); + } + } + + // Outer deadzone ring. + float outerDZ = g_Config.fAnalogOuterDeadzone; + if (outerDZ > 0.0f) { + float outerR = (1.0f - outerDZ) * minRadius; + const int segments = 32; + for (int i = 0; i < segments; i++) { + float a1 = (float)i / (float)segments * 2.0f * (float)M_PI; + float a2 = (float)(i + 1) / (float)segments * 2.0f * (float)M_PI; + float x1 = cx + cosf(a1) * outerR; + float y1 = cy + sinf(a1) * outerR; + float x2 = cx + cosf(a2) * outerR; + float y2 = cy + sinf(a2) * outerR; + dc.Draw()->Line(dc.GetTheme().whiteImage, x1, y1, x2, y2, 1.5f, 0x6066FF66); + } + } + } + int a = maxCount_ - (int)locations_.size(); for (auto iter = locations_.begin(); iter != locations_.end(); ++iter) { float x = bounds_.centerX() + minRadius * iter->x; From b585a1fcf4420ec0291655a050c4c34aad88f0e5 Mon Sep 17 00:00:00 2001 From: David Cottingham Date: Fri, 22 May 2026 18:51:08 -1000 Subject: [PATCH 2/2] Address review: remove redundant outer/output anti-deadzone controls --- Core/Config.cpp | 3 --- Core/Config.h | 6 ------ Core/ControlMapper.cpp | 31 +++--------------------------- UI/ControlMappingScreen.cpp | 10 ---------- UI/JoystickHistoryView.cpp | 38 ------------------------------------- 5 files changed, 3 insertions(+), 85 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index dc2a080a7a..46ef3334dc 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1026,9 +1026,6 @@ static const ConfigSetting controlSettings[] = { // Advanced analog deadzone settings. ConfigSetting("AnalogDeadzoneShape", SETTING(g_Config, iAnalogDeadzoneShape), 1, CfgFlag::PER_GAME), // Default 1 (Square) matches legacy max-norm behavior ConfigSetting("AnalogAxialDeadzone", SETTING(g_Config, fAnalogAxialDeadzone), 0.0f, CfgFlag::PER_GAME), - ConfigSetting("AnalogOuterDeadzone", SETTING(g_Config, fAnalogOuterDeadzone), 0.0f, CfgFlag::PER_GAME), - ConfigSetting("AnalogOutputAntiDeadzone", SETTING(g_Config, fAnalogOutputAntiDeadzone), 0.0f, CfgFlag::PER_GAME), - ConfigSetting("AnalogOutputAntiDeadzoneBuffer", SETTING(g_Config, fAnalogOutputAntiDeadzoneBuffer), 0.0f, CfgFlag::PER_GAME), ConfigSetting("AnalogResponseCurve", SETTING(g_Config, iAnalogResponseCurve), 0, CfgFlag::PER_GAME), ConfigSetting("AnalogLimiterDeadzone", SETTING(g_Config, fAnalogLimiterDeadzone), 0.6f, CfgFlag::DEFAULT), diff --git a/Core/Config.h b/Core/Config.h index 4802cf51a8..43ea24c239 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -521,12 +521,6 @@ public: // Cross-shaped axial anti-deadzone. Boosts small off-axis values past this threshold, // making the output skip the zone near each cardinal axis to prevent axis snapping. float fAnalogAxialDeadzone; - // Outer deadzone: defines where 100% output is reached. Shrinks the effective stick range. - float fAnalogOuterDeadzone; - // Output anti-deadzone: minimum output floor to bypass game-internal deadzones. - float fAnalogOutputAntiDeadzone; - // Anti-deadzone buffer: re-adds a small safe zone after anti-deadzone is applied. - float fAnalogOutputAntiDeadzoneBuffer; // Response curve type: 0 = Linear, 1 = Aggressive, 2 = Relaxed, 3 = Wide int iAnalogResponseCurve; diff --git a/Core/ControlMapper.cpp b/Core/ControlMapper.cpp index 97981e2653..b3264fb699 100644 --- a/Core/ControlMapper.cpp +++ b/Core/ControlMapper.cpp @@ -134,32 +134,21 @@ static float ApplyAxialAntiDeadzone(float v, float antiDZ) { } // This is applied on the circular radius, not directly on the axes. -// Now includes outer deadzone, response curve, and output anti-deadzone stages. +// Adds a response curve stage on top of the legacy inner-deadzone + sensitivity processing. static float MapAxisValue(float v) { const float deadzone = g_Config.fAnalogDeadzone; const float invDeadzone = g_Config.fAnalogInverseDeadzone; const float sensitivity = g_Config.fAnalogSensitivity; - const float outerDeadzone = g_Config.fAnalogOuterDeadzone; - const float outputAntiDZ = g_Config.fAnalogOutputAntiDeadzone; - const float outputADBuffer = g_Config.fAnalogOutputAntiDeadzoneBuffer; const int responseCurve = g_Config.iAnalogResponseCurve; const float sign = v >= 0.0f ? 1.0f : -1.0f; float absV = fabsf(v); // Stage 1: Apply inner deadzone and rescale to [0, 1]. - // The effective range is [deadzone, 1 - outerDeadzone]. - float effectiveMax = 1.0f - outerDeadzone; - float effectiveRange = effectiveMax - deadzone; - if (effectiveRange <= 0.0f) { - // Degenerate case: deadzone + outerDeadzone >= 1.0. Output is either 0 or 1. - absV = (absV > deadzone) ? 1.0f : 0.0f; - } else { - absV = Clamp((absV - deadzone) / effectiveRange, 0.0f, 1.0f); - } + absV = Clamp((absV - deadzone) / (1.0f - deadzone), 0.0f, 1.0f); - // Stage 2: Apply sensitivity (legacy, works the same as before when new settings are at defaults). + // Stage 2: Apply sensitivity (legacy, matches prior behavior when response curve is Linear). if (absV != 0.0f) { absV = Clamp(invDeadzone + absV * (sensitivity - invDeadzone), 0.0f, 1.0f); } @@ -169,20 +158,6 @@ static float MapAxisValue(float v) { absV = ApplyResponseCurve(absV, responseCurve); } - // Stage 4: Apply output anti-deadzone with buffer. - // Anti-deadzone sets a minimum output floor so that even the smallest - // stick input past the deadzone produces enough signal to overcome - // game-internal deadzones. The buffer re-adds a small safe zone so - // resting your thumb on the stick doesn't cause unintended drift. - if (absV != 0.0f && outputAntiDZ > 0.0f) { - // Remap [0, 1] -> [outputAntiDZ, 1] - absV = outputAntiDZ + absV * (1.0f - outputAntiDZ); - } - if (outputADBuffer > 0.0f && absV > 0.0f && absV < outputAntiDZ + outputADBuffer) { - // Within the buffer zone past the anti-deadzone floor: zero it out. - absV = 0.0f; - } - return sign * Clamp(absV, 0.0f, 1.0f); } diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 43ec0c346f..c9d5516541 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -569,13 +569,6 @@ void AnalogCalibrationScreen::CreateSettingsViews(UI::ViewGroup *scrollContents) return g_Config.iAnalogDeadzoneShape == 2; // Only enabled for Cross shape }); - scrollContents->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogOuterDeadzone, 0.0f, 0.3f, 0.0f, co->T("Outer deadzone"), 0.01f, screenManager(), "/ 1.0")); - scrollContents->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogOutputAntiDeadzone, 0.0f, 0.5f, 0.0f, co->T("Output anti-deadzone"), 0.01f, screenManager(), "/ 1.0")); - PopupSliderChoiceFloat *adBuffer = scrollContents->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogOutputAntiDeadzoneBuffer, 0.0f, 0.2f, 0.0f, co->T("Anti-deadzone buffer"), 0.01f, screenManager(), "/ 1.0")); - adBuffer->SetEnabledFunc([] { - return g_Config.fAnalogOutputAntiDeadzone > 0.0f; // Buffer only makes sense with anti-deadzone active - }); - static const char *responseCurves[] = { "Linear", "Aggressive", "Relaxed", "Wide" }; scrollContents->Add(new PopupMultiChoice(&g_Config.iAnalogResponseCurve, co->T("Response curve"), responseCurves, 0, ARRAY_SIZE(responseCurves), I18NCat::CONTROLS, screenManager())); @@ -604,9 +597,6 @@ void AnalogCalibrationScreen::OnResetToDefaults(UI::EventParams &e) { // Advanced settings g_Config.iAnalogDeadzoneShape = 1; // Square (matches legacy default) g_Config.fAnalogAxialDeadzone = 0.0f; - g_Config.fAnalogOuterDeadzone = 0.0f; - g_Config.fAnalogOutputAntiDeadzone = 0.0f; - g_Config.fAnalogOutputAntiDeadzoneBuffer = 0.0f; g_Config.iAnalogResponseCurve = 0; } diff --git a/UI/JoystickHistoryView.cpp b/UI/JoystickHistoryView.cpp index 8250f8e019..72f171a29b 100644 --- a/UI/JoystickHistoryView.cpp +++ b/UI/JoystickHistoryView.cpp @@ -93,44 +93,6 @@ void JoystickHistoryView::Draw(UIContext &dc) { } - // Draw circular deadzone overlays on the raw input view (on top of the grid, textured context). - if (type_ == StickHistoryViewType::INPUT) { - float cx = bounds_.centerX(); - float cy = bounds_.centerY(); - - // Inner deadzone circle. - float innerDZ = g_Config.fAnalogDeadzone; - if (innerDZ > 0.0f) { - float innerR = innerDZ * minRadius; - const int segments = 32; - for (int i = 0; i < segments; i++) { - float a1 = (float)i / (float)segments * 2.0f * (float)M_PI; - float a2 = (float)(i + 1) / (float)segments * 2.0f * (float)M_PI; - float x1 = cx + cosf(a1) * innerR; - float y1 = cy + sinf(a1) * innerR; - float x2 = cx + cosf(a2) * innerR; - float y2 = cy + sinf(a2) * innerR; - dc.Draw()->Line(dc.GetTheme().whiteImage, x1, y1, x2, y2, 1.5f, 0x60FF6666); - } - } - - // Outer deadzone ring. - float outerDZ = g_Config.fAnalogOuterDeadzone; - if (outerDZ > 0.0f) { - float outerR = (1.0f - outerDZ) * minRadius; - const int segments = 32; - for (int i = 0; i < segments; i++) { - float a1 = (float)i / (float)segments * 2.0f * (float)M_PI; - float a2 = (float)(i + 1) / (float)segments * 2.0f * (float)M_PI; - float x1 = cx + cosf(a1) * outerR; - float y1 = cy + sinf(a1) * outerR; - float x2 = cx + cosf(a2) * outerR; - float y2 = cy + sinf(a2) * outerR; - dc.Draw()->Line(dc.GetTheme().whiteImage, x1, y1, x2, y2, 1.5f, 0x6066FF66); - } - } - } - int a = maxCount_ - (int)locations_.size(); for (auto iter = locations_.begin(); iter != locations_.end(); ++iter) { float x = bounds_.centerX() + minRadius * iter->x;