diff --git a/rpcs3/Emu/Io/PadHandler.cpp b/rpcs3/Emu/Io/PadHandler.cpp index 4e62d1c451..0afdc2305a 100644 --- a/rpcs3/Emu/Io/PadHandler.cpp +++ b/rpcs3/Emu/Io/PadHandler.cpp @@ -32,19 +32,52 @@ s32 PadHandlerBase::MultipliedInput(s32 raw_value, s32 multiplier) return (multiplier * raw_value) / 100; } -// Get new scaled value between 0 and 255 based on its minimum and maximum -f32 PadHandlerBase::ScaledInput(s32 raw_value, int minimum, int maximum, f32 range) +// Get new scaled value between 0 and range based on its minimum and maximum +f32 PadHandlerBase::ScaledInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range) { - // value based on max range converted to [0, 1] - const f32 val = static_cast(std::clamp(raw_value, minimum, maximum) - minimum) / (abs(maximum) + abs(minimum)); + if (deadzone > 0 && deadzone > minimum) + { + // adjust minimum so we smoothly start at 0 when we surpass the deadzone value + minimum = deadzone; + } + + // convert [min, max] to [0, 1] + const f32 val = static_cast(std::clamp(raw_value, minimum, maximum) - minimum) / (maximum - minimum); + + // convert [0, 1] to [0, range] return range * val; } -// Get new scaled value between -255 and 255 based on its minimum and maximum -f32 PadHandlerBase::ScaledInput2(s32 raw_value, int minimum, int maximum, f32 range) +// Get new scaled value between -range and range based on its minimum and maximum +f32 PadHandlerBase::ScaledAxisInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range) { - // value based on max range converted to [0, 1] - const f32 val = static_cast(std::clamp(raw_value, minimum, maximum) - minimum) / (abs(maximum) + abs(minimum)); + // convert [min, max] to [0, 1] + f32 val = static_cast(std::clamp(raw_value, minimum, maximum) - minimum) / (maximum - minimum); + + if (deadzone > 0) + { + // convert [0, 1] to [-0.5, 0.5] + val -= 0.5f; + + // Convert deadzone to [0, 0.5] + deadzone = std::max(0.0f, std::min(1.0f, deadzone / maximum)) / 2.0f; + + if (val >= 0.0f) + { + // Apply deadzone. The result will be [0, 0.5] + val = ScaledInput(val, 0.0f, 0.5f, deadzone, 0.5f); + } + else + { + // Apply deadzone. The result will be [-0.5, 0] + val = ScaledInput(std::abs(val), 0, 0.5f, deadzone, 0.5f) * -1.0f; + } + + // convert [-0.5, 0.5] back to [0, 1] + val += 0.5f; + } + + // convert [0, 1] to [-range, range] return (2.0f * range * val) - range; } @@ -56,33 +89,19 @@ u16 PadHandlerBase::NormalizeTriggerInput(u16 value, int threshold) const return static_cast(0); } - if (threshold <= trigger_min) - { - return static_cast(ScaledInput(value, trigger_min, trigger_max)); - } - - const s32 val = static_cast(static_cast(trigger_max) * (value - threshold) / (trigger_max - threshold)); - return static_cast(ScaledInput(val, trigger_min, trigger_max)); + return static_cast(ScaledInput(value, trigger_min, trigger_max, threshold)); } // normalizes a directed input, meaning it will correspond to a single "button" and not an axis with two directions // the input values must lie in 0+ u16 PadHandlerBase::NormalizeDirectedInput(s32 raw_value, s32 threshold, s32 maximum) const { - if (threshold >= maximum || maximum <= 0) + if (threshold >= maximum || maximum <= 0 || raw_value < 0) { return static_cast(0); } - const f32 val = static_cast(std::clamp(raw_value, 0, maximum)) / maximum; // value based on max range converted to [0, 1] - - if (threshold <= 0) - { - return static_cast(255.0f * val); - } - - const f32 thresh = static_cast(threshold) / maximum; // threshold converted to [0, 1] - return static_cast(255.0f * std::clamp((val - thresh) / (1.0f - thresh), 0.0f, 1.0f)); + return static_cast(ScaledInput(raw_value, 0, maximum, threshold)); } u16 PadHandlerBase::NormalizeStickInput(u16 raw_value, int threshold, int multiplier, bool ignore_threshold) const @@ -91,10 +110,10 @@ u16 PadHandlerBase::NormalizeStickInput(u16 raw_value, int threshold, int multip if (ignore_threshold) { - return static_cast(ScaledInput(scaled_value, 0, thumb_max)); + threshold = 0; } - return NormalizeDirectedInput(scaled_value, threshold, thumb_max); + return static_cast(ScaledInput(scaled_value, 0, thumb_max, threshold)); } // This function normalizes stick deadzone based on the DS3's deadzone, which is ~13% diff --git a/rpcs3/Emu/Io/PadHandler.h b/rpcs3/Emu/Io/PadHandler.h index 5b164b9f25..217661e91a 100644 --- a/rpcs3/Emu/Io/PadHandler.h +++ b/rpcs3/Emu/Io/PadHandler.h @@ -208,10 +208,10 @@ protected: static s32 MultipliedInput(s32 raw_value, s32 multiplier); // Get new scaled value between 0 and 255 based on its minimum and maximum - static f32 ScaledInput(s32 raw_value, int minimum, int maximum, f32 range = 255.0f); + static f32 ScaledInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range = 255.0f); // Get new scaled value between -255 and 255 based on its minimum and maximum - static f32 ScaledInput2(s32 raw_value, int minimum, int maximum, f32 range = 255.0f); + static f32 ScaledAxisInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range = 255.0f); // Get normalized trigger value based on the range defined by a threshold u16 NormalizeTriggerInput(u16 value, int threshold) const; diff --git a/rpcs3/Input/evdev_joystick_handler.cpp b/rpcs3/Input/evdev_joystick_handler.cpp index 1db4233653..894eed7256 100644 --- a/rpcs3/Input/evdev_joystick_handler.cpp +++ b/rpcs3/Input/evdev_joystick_handler.cpp @@ -261,16 +261,17 @@ std::unordered_map> evdev_joystick_handler::GetButtonV const int min = libevdev_get_abs_minimum(dev, code); const int max = libevdev_get_abs_maximum(dev, code); + const int flat = libevdev_get_abs_flat(dev, code); // Triggers do not need handling of negative values if (min >= 0 && !m_positive_axis.contains(code)) { - const float fvalue = ScaledInput(val, min, max); + const float fvalue = ScaledInput(val, min, max, flat); button_values.emplace(code, std::make_pair(static_cast(fvalue), false)); continue; } - const float fvalue = ScaledInput2(val, min, max); + const float fvalue = ScaledAxisInput(val, min, max, flat); if (fvalue < 0) button_values.emplace(code, std::make_pair(static_cast(std::abs(fvalue)), true)); else @@ -939,6 +940,7 @@ void evdev_joystick_handler::get_mapping(const pad_ensemble& binding) { axis_wrapper->min = libevdev_get_abs_minimum(dev, evt.code); axis_wrapper->max = libevdev_get_abs_maximum(dev, evt.code); + axis_wrapper->flat = libevdev_get_abs_flat(dev, evt.code); axis_wrapper->is_initialized = true; // Triggers do not need handling of negative values @@ -951,7 +953,7 @@ void evdev_joystick_handler::get_mapping(const pad_ensemble& binding) // Triggers do not need handling of negative values if (axis_wrapper->is_trigger) { - const u16 new_value = static_cast(ScaledInput(evt.value, axis_wrapper->min, axis_wrapper->max)); + const u16 new_value = static_cast(ScaledInput(evt.value, axis_wrapper->min, axis_wrapper->max, axis_wrapper->flat)); u16& key_value = axis_wrapper->values[false]; if (key_value != new_value) @@ -962,7 +964,7 @@ void evdev_joystick_handler::get_mapping(const pad_ensemble& binding) } else { - const float fvalue = ScaledInput2(evt.value, axis_wrapper->min, axis_wrapper->max); + const float fvalue = ScaledAxisInput(evt.value, axis_wrapper->min, axis_wrapper->max, axis_wrapper->flat); const bool is_negative = fvalue < 0; const u16 new_value_0 = static_cast(std::abs(fvalue)); @@ -1054,8 +1056,9 @@ u16 evdev_joystick_handler::get_sensor_value(const libevdev* dev, const AnalogSe { const int min = libevdev_get_abs_minimum(dev, evt.code); const int max = libevdev_get_abs_maximum(dev, evt.code); + const int flat = libevdev_get_abs_flat(dev, evt.code); - s16 value = ScaledInput(evt.value, min, max, 1023.0f); + s16 value = ScaledInput(evt.value, min, max, flat, 1023.0f); if (sensor.m_mirrored) { diff --git a/rpcs3/Input/evdev_joystick_handler.h b/rpcs3/Input/evdev_joystick_handler.h index 52245a6d2a..e7ab8b5c28 100644 --- a/rpcs3/Input/evdev_joystick_handler.h +++ b/rpcs3/Input/evdev_joystick_handler.h @@ -371,6 +371,7 @@ class evdev_joystick_handler final : public PadHandlerBase bool is_trigger{}; int min{}; int max{}; + int flat{}; }; struct EvdevDevice : public PadDevice diff --git a/rpcs3/Input/mm_joystick_handler.cpp b/rpcs3/Input/mm_joystick_handler.cpp index 7e2de631cb..206b08b764 100644 --- a/rpcs3/Input/mm_joystick_handler.cpp +++ b/rpcs3/Input/mm_joystick_handler.cpp @@ -420,7 +420,8 @@ std::unordered_map mm_joystick_handler::GetButtonValues(const JOYINFOE auto add_axis_value = [&](DWORD axis, UINT min, UINT max, u64 pos, u64 neg) { - const float val = ScaledInput2(axis, min, max); + constexpr int deadzone = 0; + const float val = ScaledAxisInput(axis, min, max, deadzone); if (val < 0) { button_values.emplace(pos, 0);