mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 18:53:28 +01:00
input/evdev: handle flatness deadzone value
This may fix issues with sticky axis on evdev. Also refactors some redundant axis scaling functions.
This commit is contained in:
parent
7c9a38e0f3
commit
57cc7037f6
@ -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<f32>(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<f32>(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<f32>(std::clamp(raw_value, minimum, maximum) - minimum) / (abs(maximum) + abs(minimum));
|
||||
// convert [min, max] to [0, 1]
|
||||
f32 val = static_cast<f32>(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<u16>(0);
|
||||
}
|
||||
|
||||
if (threshold <= trigger_min)
|
||||
{
|
||||
return static_cast<u16>(ScaledInput(value, trigger_min, trigger_max));
|
||||
}
|
||||
|
||||
const s32 val = static_cast<s32>(static_cast<f32>(trigger_max) * (value - threshold) / (trigger_max - threshold));
|
||||
return static_cast<u16>(ScaledInput(val, trigger_min, trigger_max));
|
||||
return static_cast<u16>(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<u16>(0);
|
||||
}
|
||||
|
||||
const f32 val = static_cast<f32>(std::clamp(raw_value, 0, maximum)) / maximum; // value based on max range converted to [0, 1]
|
||||
|
||||
if (threshold <= 0)
|
||||
{
|
||||
return static_cast<u16>(255.0f * val);
|
||||
}
|
||||
|
||||
const f32 thresh = static_cast<f32>(threshold) / maximum; // threshold converted to [0, 1]
|
||||
return static_cast<u16>(255.0f * std::clamp((val - thresh) / (1.0f - thresh), 0.0f, 1.0f));
|
||||
return static_cast<u16>(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<u16>(ScaledInput(scaled_value, 0, thumb_max));
|
||||
threshold = 0;
|
||||
}
|
||||
|
||||
return NormalizeDirectedInput(scaled_value, threshold, thumb_max);
|
||||
return static_cast<u16>(ScaledInput(scaled_value, 0, thumb_max, threshold));
|
||||
}
|
||||
|
||||
// This function normalizes stick deadzone based on the DS3's deadzone, which is ~13%
|
||||
|
@ -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;
|
||||
|
@ -261,16 +261,17 @@ std::unordered_map<u64, std::pair<u16, bool>> 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<u16, bool>(static_cast<u16>(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<u16, bool>(static_cast<u16>(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<u16>(ScaledInput(evt.value, axis_wrapper->min, axis_wrapper->max));
|
||||
const u16 new_value = static_cast<u16>(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<u16>(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)
|
||||
{
|
||||
|
@ -371,6 +371,7 @@ class evdev_joystick_handler final : public PadHandlerBase
|
||||
bool is_trigger{};
|
||||
int min{};
|
||||
int max{};
|
||||
int flat{};
|
||||
};
|
||||
|
||||
struct EvdevDevice : public PadDevice
|
||||
|
@ -420,7 +420,8 @@ std::unordered_map<u64, u16> 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);
|
||||
|
Loading…
Reference in New Issue
Block a user