mirror of
https://github.com/stenzek/duckstation.git
synced 2026-07-11 01:24:11 +02:00
Controller: Make center a distinct value
Instead of attaching 128 to one side of the axis, make 128 the all-zeros/center position, which leaves exactly 127 positions on either side. Fixes the center not being reported as center in padtest.
This commit is contained in:
@@ -186,40 +186,36 @@ void AnalogController::SetBindState(u32 index, float value)
|
||||
|
||||
m_half_axis_state[sub_index] = u8_value;
|
||||
|
||||
#define MERGE(pos, neg) \
|
||||
((m_half_axis_state[static_cast<u32>(pos)] != 0) ? (127u + ((m_half_axis_state[static_cast<u32>(pos)] + 1u) / 2u)) : \
|
||||
(127u - (m_half_axis_state[static_cast<u32>(neg)] / 2u)))
|
||||
|
||||
const auto prev_axis_state = m_axis_state;
|
||||
|
||||
switch (static_cast<HalfAxis>(sub_index))
|
||||
{
|
||||
case HalfAxis::LLeft:
|
||||
case HalfAxis::LRight:
|
||||
m_axis_state[static_cast<u8>(Axis::LeftX)] = ((m_invert_left_stick & 1u) != 0u) ?
|
||||
MERGE(HalfAxis::LLeft, HalfAxis::LRight) :
|
||||
MERGE(HalfAxis::LRight, HalfAxis::LLeft);
|
||||
m_axis_state[static_cast<u8>(Axis::LeftX)] =
|
||||
MergeHalfAxes(m_half_axis_state[static_cast<size_t>(HalfAxis::LLeft)],
|
||||
m_half_axis_state[static_cast<size_t>(HalfAxis::LRight)], (m_invert_left_stick & 1));
|
||||
break;
|
||||
|
||||
case HalfAxis::LDown:
|
||||
case HalfAxis::LUp:
|
||||
m_axis_state[static_cast<u8>(Axis::LeftY)] = ((m_invert_left_stick & 2u) != 0u) ?
|
||||
MERGE(HalfAxis::LUp, HalfAxis::LDown) :
|
||||
MERGE(HalfAxis::LDown, HalfAxis::LUp);
|
||||
m_axis_state[static_cast<u8>(Axis::LeftY)] =
|
||||
MergeHalfAxes(m_half_axis_state[static_cast<size_t>(HalfAxis::LUp)],
|
||||
m_half_axis_state[static_cast<size_t>(HalfAxis::LDown)], (m_invert_left_stick & 2));
|
||||
break;
|
||||
|
||||
case HalfAxis::RLeft:
|
||||
case HalfAxis::RRight:
|
||||
m_axis_state[static_cast<u8>(Axis::RightX)] = ((m_invert_right_stick & 1u) != 0u) ?
|
||||
MERGE(HalfAxis::RLeft, HalfAxis::RRight) :
|
||||
MERGE(HalfAxis::RRight, HalfAxis::RLeft);
|
||||
m_axis_state[static_cast<u8>(Axis::RightX)] =
|
||||
MergeHalfAxes(m_half_axis_state[static_cast<size_t>(HalfAxis::RLeft)],
|
||||
m_half_axis_state[static_cast<size_t>(HalfAxis::RRight)], (m_invert_right_stick & 1));
|
||||
break;
|
||||
|
||||
case HalfAxis::RDown:
|
||||
case HalfAxis::RUp:
|
||||
m_axis_state[static_cast<u8>(Axis::RightY)] = ((m_invert_right_stick & 2u) != 0u) ?
|
||||
MERGE(HalfAxis::RUp, HalfAxis::RDown) :
|
||||
MERGE(HalfAxis::RDown, HalfAxis::RUp);
|
||||
m_axis_state[static_cast<u8>(Axis::RightY)] =
|
||||
MergeHalfAxes(m_half_axis_state[static_cast<size_t>(HalfAxis::RUp)],
|
||||
m_half_axis_state[static_cast<size_t>(HalfAxis::RDown)], (m_invert_right_stick & 2));
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -228,43 +224,38 @@ void AnalogController::SetBindState(u32 index, float value)
|
||||
|
||||
if (m_analog_deadzone > 0.0f)
|
||||
{
|
||||
#define MERGE_F(pos, neg) \
|
||||
((m_half_axis_state[static_cast<u32>(pos)] != 0) ? \
|
||||
(static_cast<float>(m_half_axis_state[static_cast<u32>(pos)]) / 255.0f) : \
|
||||
(static_cast<float>(m_half_axis_state[static_cast<u32>(neg)]) / -255.0f))
|
||||
|
||||
float pos_x, pos_y;
|
||||
if (static_cast<HalfAxis>(sub_index) < HalfAxis::RLeft)
|
||||
{
|
||||
pos_x = ((m_invert_left_stick & 1u) != 0u) ? MERGE_F(HalfAxis::LLeft, HalfAxis::LRight) :
|
||||
MERGE_F(HalfAxis::LRight, HalfAxis::LLeft);
|
||||
pos_y = ((m_invert_left_stick & 2u) != 0u) ? MERGE_F(HalfAxis::LUp, HalfAxis::LDown) :
|
||||
MERGE_F(HalfAxis::LDown, HalfAxis::LUp);
|
||||
pos_x =
|
||||
MergeHalfAxesToFloat(m_half_axis_state[static_cast<size_t>(HalfAxis::LLeft)],
|
||||
m_half_axis_state[static_cast<size_t>(HalfAxis::LRight)], (m_invert_left_stick & 1));
|
||||
pos_y =
|
||||
MergeHalfAxesToFloat(m_half_axis_state[static_cast<size_t>(HalfAxis::LUp)],
|
||||
m_half_axis_state[static_cast<size_t>(HalfAxis::LDown)], (m_invert_left_stick & 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
pos_x = ((m_invert_right_stick & 1u) != 0u) ? MERGE_F(HalfAxis::RLeft, HalfAxis::RRight) :
|
||||
MERGE_F(HalfAxis::RRight, HalfAxis::RLeft);
|
||||
pos_y = ((m_invert_right_stick & 2u) != 0u) ? MERGE_F(HalfAxis::RUp, HalfAxis::RDown) :
|
||||
MERGE_F(HalfAxis::RDown, HalfAxis::RUp);
|
||||
pos_x =
|
||||
MergeHalfAxesToFloat(m_half_axis_state[static_cast<size_t>(HalfAxis::RLeft)],
|
||||
m_half_axis_state[static_cast<size_t>(HalfAxis::RRight)], (m_invert_right_stick & 1));
|
||||
pos_y =
|
||||
MergeHalfAxesToFloat(m_half_axis_state[static_cast<size_t>(HalfAxis::RUp)],
|
||||
m_half_axis_state[static_cast<size_t>(HalfAxis::RDown)], (m_invert_right_stick & 2));
|
||||
}
|
||||
|
||||
if (InCircularDeadzone(m_analog_deadzone, pos_x, pos_y))
|
||||
{
|
||||
// Set to 127 (center).
|
||||
if (static_cast<HalfAxis>(sub_index) < HalfAxis::RLeft)
|
||||
m_axis_state[static_cast<u8>(Axis::LeftX)] = m_axis_state[static_cast<u8>(Axis::LeftY)] = 127;
|
||||
m_axis_state[static_cast<u8>(Axis::LeftX)] = m_axis_state[static_cast<u8>(Axis::LeftY)] = AXIS_CENTER;
|
||||
else
|
||||
m_axis_state[static_cast<u8>(Axis::RightX)] = m_axis_state[static_cast<u8>(Axis::RightY)] = 127;
|
||||
m_axis_state[static_cast<u8>(Axis::RightX)] = m_axis_state[static_cast<u8>(Axis::RightY)] = AXIS_CENTER;
|
||||
}
|
||||
#undef MERGE_F
|
||||
}
|
||||
|
||||
if (std::memcmp(m_axis_state.data(), prev_axis_state.data(), m_axis_state.size()) != 0)
|
||||
System::SetRunaheadReplayFlag(true);
|
||||
|
||||
#undef MERGE
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -106,40 +106,36 @@ void AnalogJoystick::SetBindState(u32 index, float value)
|
||||
|
||||
m_half_axis_state[sub_index] = u8_value;
|
||||
|
||||
#define MERGE(pos, neg) \
|
||||
((m_half_axis_state[static_cast<u32>(pos)] != 0) ? (127u + ((m_half_axis_state[static_cast<u32>(pos)] + 1u) / 2u)) : \
|
||||
(127u - (m_half_axis_state[static_cast<u32>(neg)] / 2u)))
|
||||
|
||||
const auto prev_axis_state = m_axis_state;
|
||||
|
||||
switch (static_cast<HalfAxis>(sub_index))
|
||||
{
|
||||
case HalfAxis::LLeft:
|
||||
case HalfAxis::LRight:
|
||||
m_axis_state[static_cast<u8>(Axis::LeftX)] = ((m_invert_left_stick & 1u) != 0u) ?
|
||||
MERGE(HalfAxis::LLeft, HalfAxis::LRight) :
|
||||
MERGE(HalfAxis::LRight, HalfAxis::LLeft);
|
||||
m_axis_state[static_cast<u8>(Axis::LeftX)] =
|
||||
MergeHalfAxes(m_half_axis_state[static_cast<size_t>(HalfAxis::LLeft)],
|
||||
m_half_axis_state[static_cast<size_t>(HalfAxis::LRight)], (m_invert_left_stick & 1));
|
||||
break;
|
||||
|
||||
case HalfAxis::LDown:
|
||||
case HalfAxis::LUp:
|
||||
m_axis_state[static_cast<u8>(Axis::LeftY)] = ((m_invert_left_stick & 2u) != 0u) ?
|
||||
MERGE(HalfAxis::LUp, HalfAxis::LDown) :
|
||||
MERGE(HalfAxis::LDown, HalfAxis::LUp);
|
||||
m_axis_state[static_cast<u8>(Axis::LeftY)] =
|
||||
MergeHalfAxes(m_half_axis_state[static_cast<size_t>(HalfAxis::LUp)],
|
||||
m_half_axis_state[static_cast<size_t>(HalfAxis::LDown)], (m_invert_left_stick & 2));
|
||||
break;
|
||||
|
||||
case HalfAxis::RLeft:
|
||||
case HalfAxis::RRight:
|
||||
m_axis_state[static_cast<u8>(Axis::RightX)] = ((m_invert_right_stick & 1u) != 0u) ?
|
||||
MERGE(HalfAxis::RLeft, HalfAxis::RRight) :
|
||||
MERGE(HalfAxis::RRight, HalfAxis::RLeft);
|
||||
m_axis_state[static_cast<u8>(Axis::RightX)] =
|
||||
MergeHalfAxes(m_half_axis_state[static_cast<size_t>(HalfAxis::RLeft)],
|
||||
m_half_axis_state[static_cast<size_t>(HalfAxis::RRight)], (m_invert_right_stick & 1));
|
||||
break;
|
||||
|
||||
case HalfAxis::RDown:
|
||||
case HalfAxis::RUp:
|
||||
m_axis_state[static_cast<u8>(Axis::RightY)] = ((m_invert_right_stick & 2u) != 0u) ?
|
||||
MERGE(HalfAxis::RUp, HalfAxis::RDown) :
|
||||
MERGE(HalfAxis::RDown, HalfAxis::RUp);
|
||||
m_axis_state[static_cast<u8>(Axis::RightY)] =
|
||||
MergeHalfAxes(m_half_axis_state[static_cast<size_t>(HalfAxis::RUp)],
|
||||
m_half_axis_state[static_cast<size_t>(HalfAxis::RDown)], (m_invert_right_stick & 2));
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -148,43 +144,38 @@ void AnalogJoystick::SetBindState(u32 index, float value)
|
||||
|
||||
if (m_analog_deadzone > 0.0f)
|
||||
{
|
||||
#define MERGE_F(pos, neg) \
|
||||
((m_half_axis_state[static_cast<u32>(pos)] != 0) ? \
|
||||
(static_cast<float>(m_half_axis_state[static_cast<u32>(pos)]) / 255.0f) : \
|
||||
(static_cast<float>(m_half_axis_state[static_cast<u32>(neg)]) / -255.0f))
|
||||
|
||||
float pos_x, pos_y;
|
||||
if (static_cast<HalfAxis>(sub_index) < HalfAxis::RLeft)
|
||||
{
|
||||
pos_x = ((m_invert_left_stick & 1u) != 0u) ? MERGE_F(HalfAxis::LLeft, HalfAxis::LRight) :
|
||||
MERGE_F(HalfAxis::LRight, HalfAxis::LLeft);
|
||||
pos_y = ((m_invert_left_stick & 2u) != 0u) ? MERGE_F(HalfAxis::LUp, HalfAxis::LDown) :
|
||||
MERGE_F(HalfAxis::LDown, HalfAxis::LUp);
|
||||
pos_x =
|
||||
MergeHalfAxesToFloat(m_half_axis_state[static_cast<size_t>(HalfAxis::LLeft)],
|
||||
m_half_axis_state[static_cast<size_t>(HalfAxis::LRight)], (m_invert_left_stick & 1));
|
||||
pos_y =
|
||||
MergeHalfAxesToFloat(m_half_axis_state[static_cast<size_t>(HalfAxis::LUp)],
|
||||
m_half_axis_state[static_cast<size_t>(HalfAxis::LDown)], (m_invert_left_stick & 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
pos_x = ((m_invert_right_stick & 1u) != 0u) ? MERGE_F(HalfAxis::RLeft, HalfAxis::RRight) :
|
||||
MERGE_F(HalfAxis::RRight, HalfAxis::RLeft);
|
||||
pos_y = ((m_invert_right_stick & 2u) != 0u) ? MERGE_F(HalfAxis::RUp, HalfAxis::RDown) :
|
||||
MERGE_F(HalfAxis::RDown, HalfAxis::RUp);
|
||||
pos_x =
|
||||
MergeHalfAxesToFloat(m_half_axis_state[static_cast<size_t>(HalfAxis::RLeft)],
|
||||
m_half_axis_state[static_cast<size_t>(HalfAxis::RRight)], (m_invert_right_stick & 1));
|
||||
pos_y =
|
||||
MergeHalfAxesToFloat(m_half_axis_state[static_cast<size_t>(HalfAxis::RUp)],
|
||||
m_half_axis_state[static_cast<size_t>(HalfAxis::RDown)], (m_invert_right_stick & 2));
|
||||
}
|
||||
|
||||
if (InCircularDeadzone(m_analog_deadzone, pos_x, pos_y))
|
||||
{
|
||||
// Set to 127 (center).
|
||||
if (static_cast<HalfAxis>(sub_index) < HalfAxis::RLeft)
|
||||
m_axis_state[static_cast<u8>(Axis::LeftX)] = m_axis_state[static_cast<u8>(Axis::LeftY)] = 127;
|
||||
m_axis_state[static_cast<u8>(Axis::LeftX)] = m_axis_state[static_cast<u8>(Axis::LeftY)] = AXIS_CENTER;
|
||||
else
|
||||
m_axis_state[static_cast<u8>(Axis::RightX)] = m_axis_state[static_cast<u8>(Axis::RightY)] = 127;
|
||||
m_axis_state[static_cast<u8>(Axis::RightX)] = m_axis_state[static_cast<u8>(Axis::RightY)] = AXIS_CENTER;
|
||||
}
|
||||
#undef MERGE_F
|
||||
}
|
||||
|
||||
if (std::memcmp(m_axis_state.data(), prev_axis_state.data(), m_axis_state.size()) != 0)
|
||||
System::SetRunaheadReplayFlag(true);
|
||||
|
||||
#undef MERGE
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -239,3 +239,17 @@ bool Controller::CanStartInAnalogMode(ControllerType ctype)
|
||||
return ((dbentry->supported_controllers & (1u << static_cast<u8>(ctype))) != 0 &&
|
||||
!dbentry->HasTrait(GameDatabase::Trait::DisableAutoAnalogMode));
|
||||
}
|
||||
|
||||
u8 Controller::MergeHalfAxes(u8 neg_value, u8 pos_value, bool invert)
|
||||
{
|
||||
if (invert)
|
||||
std::swap(neg_value, pos_value);
|
||||
|
||||
return static_cast<u8>(128 + (static_cast<u32>(pos_value) / 2) - ((static_cast<u32>(neg_value) + 1) / 2));
|
||||
}
|
||||
|
||||
float Controller::MergeHalfAxesToFloat(u8 neg_value, u8 pos_value, bool invert)
|
||||
{
|
||||
const float result = (static_cast<s32>(pos_value) - static_cast<s32>(neg_value)) / 255.0f;
|
||||
return (invert ? -result : result);
|
||||
}
|
||||
|
||||
@@ -53,6 +53,9 @@ public:
|
||||
static constexpr float DEFAULT_STICK_SENSITIVITY = 1.33f;
|
||||
static constexpr float DEFAULT_BUTTON_DEADZONE = 0.25f;
|
||||
|
||||
/// Center position when dealing with axis values.
|
||||
static constexpr u8 AXIS_CENTER = 0x80;
|
||||
|
||||
explicit Controller(u32 index);
|
||||
virtual ~Controller();
|
||||
|
||||
@@ -119,6 +122,12 @@ public:
|
||||
/// Returns true if automatic analog mode can be used.
|
||||
static bool CanStartInAnalogMode(ControllerType ctype);
|
||||
|
||||
/// Converts a 0..255 half-axis value to an unsigned 8-bit value, with 128 indicating center.
|
||||
static u8 MergeHalfAxes(u8 neg_value, u8 pos_value, bool invert);
|
||||
|
||||
/// Converts a 0..255 half-axis value to a normalized floating-point value, with 0 indicating center.
|
||||
static float MergeHalfAxesToFloat(u8 neg_value, u8 pos_value, bool invert);
|
||||
|
||||
protected:
|
||||
u32 m_index;
|
||||
};
|
||||
|
||||
@@ -171,10 +171,9 @@ void NeGconRumble::SetBindState(u32 index, float value)
|
||||
m_half_axis_state[index - static_cast<u32>(Button::Count)] =
|
||||
static_cast<u8>(std::clamp(value * 255.0f, 0.0f, 255.0f));
|
||||
|
||||
// Merge left/right. Seems to be inverted.
|
||||
m_axis_state[static_cast<u32>(Axis::Steering)] =
|
||||
((m_half_axis_state[1] != 0) ? (127u + ((m_half_axis_state[1] + 1u) / 2u)) :
|
||||
(127u - (m_half_axis_state[0] / 2u)));
|
||||
MergeHalfAxes(m_half_axis_state[static_cast<size_t>(HalfAxis::SteeringLeft)],
|
||||
m_half_axis_state[static_cast<size_t>(HalfAxis::SteeringRight)], false);
|
||||
}
|
||||
else if (index >= static_cast<u32>(Button::Count))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user