Skip to content

Commit

Permalink
PAD: Add anti-deadzone and stuff.
Browse files Browse the repository at this point in the history
  • Loading branch information
KrossX committed Jul 29, 2023
1 parent dbdc74f commit 0da9a33
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 65 deletions.
8 changes: 6 additions & 2 deletions pcsx2/SIO/Pad/Pad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,17 @@ void Pad::LoadConfig(const SettingsInterface& si)
pad = Pad::ChangePadType(i, ci->type);
}

const bool axis_linear_dz = si.GetBoolValue(section.c_str(), "LinearDZ", false);
const bool axis_linear_adz = si.GetBoolValue(section.c_str(), "LinearADZ", false);
const float axis_deadzone = si.GetFloatValue(section.c_str(), "Deadzone", Pad::DEFAULT_STICK_DEADZONE);
const float axis_antideadzone = si.GetFloatValue(section.c_str(), "Antideadzone", Pad::DEFAULT_STICK_DEADZONE);
const float axis_scale = si.GetFloatValue(section.c_str(), "AxisScale", Pad::DEFAULT_STICK_SCALE);
const float trigger_deadzone = si.GetFloatValue(section.c_str(), "TriggerDeadzone", Pad::DEFAULT_TRIGGER_DEADZONE);
const float trigger_antideadzone = si.GetFloatValue(section.c_str(), "TriggerAntideadzone", DEFAULT_TRIGGER_DEADZONE);
const float trigger_scale = si.GetFloatValue(section.c_str(), "TriggerScale", Pad::DEFAULT_TRIGGER_SCALE);
const float button_deadzone = si.GetFloatValue(section.c_str(), "ButtonDeadzone", Pad::DEFAULT_BUTTON_DEADZONE);
pad->SetAxisScale(axis_deadzone, axis_scale);
pad->SetTriggerScale(trigger_deadzone, trigger_scale);
pad->SetAxisScale(axis_linear_dz, axis_linear_adz, axis_deadzone, axis_antideadzone, axis_scale);
pad->SetTriggerScale(trigger_deadzone, trigger_antideadzone, trigger_scale);
pad->SetButtonDeadzone(button_deadzone);

if (ci->vibration_caps != Pad::VibrationCapabilities::NoVibration)
Expand Down
5 changes: 3 additions & 2 deletions pcsx2/SIO/Pad/PadBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class PadBase
{
protected:
std::array<u8, 32> rawInputs;
std::array<float, 8> axisValue;
u8 unifiedSlot;
bool isInConfig = false;
Pad::Mode currentMode = Pad::Mode::NOT_SET;
Expand All @@ -44,8 +45,8 @@ class PadBase

virtual void Set(u32 index, float value) = 0;
virtual void SetRawAnalogs(const std::tuple<u8, u8> left, const std::tuple<u8, u8> right) = 0;
virtual void SetAxisScale(float deadzone, float scale) = 0;
virtual void SetTriggerScale(float deadzone, float scale) = 0;
virtual void SetAxisScale(bool linear_dz, bool linear_adz, float deadzone, float antideadzone, float scale) = 0;
virtual void SetTriggerScale(float deadzone, float antideadzone, float scale) = 0;
virtual float GetVibrationScale(u32 motor) const = 0;
virtual void SetVibrationScale(u32 motor, float scale) = 0;
virtual float GetPressureModifier() const = 0;
Expand Down
166 changes: 115 additions & 51 deletions pcsx2/SIO/Pad/PadDualshock2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,38 @@ static const SettingInfo s_settings[] = {
{SettingInfo::Type::IntegerList, "InvertR", TRANSLATE_NOOP("Pad", "Invert Right Stick"),
TRANSLATE_NOOP("Pad", "Inverts the direction of the right analog stick."), "0", "0", "3", nullptr, nullptr,
s_invert_options, nullptr, 0.0f},
{SettingInfo::Type::Boolean, "LinearDZ", TRANSLATE_NOOP("Pad", "Linear Deadzone"),
TRANSLATE_NOOP("Pad",
"If enabled, analog deadzone is calculated per axis instead of per stick."),
"0", "0", "0", nullptr, nullptr, nullptr, nullptr, 0},
{SettingInfo::Type::Float, "Deadzone", TRANSLATE_NOOP("Pad", "Analog Deadzone"),
TRANSLATE_NOOP(
"Pad", "Sets the analog stick deadzone, i.e. the fraction of the stick movement which will be ignored."),
"0.00", "0.00", "1.00", "0.01", "%.0f%%", nullptr, nullptr, 100.0f},
{SettingInfo::Type::Boolean, "LinearADZ", TRANSLATE_NOOP("Pad", "Linear Anti-Deadzone"),
TRANSLATE_NOOP("Pad",
"If enabled, analog anti-deadzone is calculated per axis instead of per stick."),
"0", "0", "0", nullptr, nullptr, nullptr, nullptr, 0},
{SettingInfo::Type::Float, "Antideadzone", TRANSLATE_NOOP("Pad", "Analog Anti-Deadzone"),
TRANSLATE_NOOP("Pad",
"Sets the analog stick anti-deadzone, i.e. the fraction of the analog stick movement to be added to overcome a game's deadzone."),
"0.00", "0.00", "1.00", "0.01", "%.0f%%", nullptr, nullptr, 100.0f},
{SettingInfo::Type::Float, "AxisScale", TRANSLATE_NOOP("Pad", "Analog Sensitivity"),
TRANSLATE_NOOP("Pad",
"Sets the analog stick axis scaling factor. A value between 1.30 and 1.40 is recommended when using recent "
"controllers, e.g. DualShock 4, Xbox One Controller."),
"1.33", "0.01", "2.00", "0.01", "%.0f%%", nullptr, nullptr, 100.0f},
{SettingInfo::Type::Float, "TriggerDeadzone", TRANSLATE_NOOP("Pad", "Trigger Deadzone"),
TRANSLATE_NOOP("Pad",
"Sets the deadzone for activating triggers, i.e. the fraction of the trigger press which will be ignored."),
"0.00", "0.00", "1.00", "0.01", "%.0f%%", nullptr, nullptr, 100.0f},
{SettingInfo::Type::Float, "TriggerAntideadzone", TRANSLATE_NOOP("Pad", "Trigger Anti-Deadzone"),
TRANSLATE_NOOP("Pad",
"Sets the anti-deadzone for triggers, i.e. the fraction of the trigger press to be added to overcome a game's deadzone."),
"0.00", "0.00", "1.00", "0.01", "%.0f%%", nullptr, nullptr, 100.0f},
{SettingInfo::Type::Float, "TriggerScale", TRANSLATE_NOOP("Pad", "Trigger Sensitivity"),
TRANSLATE_NOOP("Pad", "Sets the trigger scaling factor."), "1.00", "0.01", "2.00", "0.01", "%.0f%%", nullptr,
nullptr, 100.0f},
{SettingInfo::Type::Float, "LargeMotorScale", TRANSLATE_NOOP("Pad", "Large Motor Vibration Scale"),
TRANSLATE_NOOP("Pad", "Increases or decreases the intensity of low frequency vibration sent by the game."),
"1.00", "0.00", "2.00", "0.01", "%.0f%%", nullptr, nullptr, 100.0f},
Expand Down Expand Up @@ -483,8 +506,15 @@ void PadDualshock2::Init()
}

this->axisScale = 1.0f;
this->axisAntideadzone = 0.0f;
this->axisDeadzone = 0.0f;

this->axisLinearADZ = false;
this->axisLinearDZ = false;

this->triggerScale = 1.0f;
this->triggerAntideadzone = 0.0f;
this->triggerDeadzone = 0.0f;

this->vibrationScale[0] = 0.0f;
this->vibrationScale[1] = 1.0f;

Expand Down Expand Up @@ -534,85 +564,115 @@ void PadDualshock2::Set(u32 index, float value)

if (IsAnalogKey(index))
{
this->rawInputs[index] = static_cast<u8>(std::clamp(value * this->axisScale * 255.0f, 0.0f, 255.0f));
float pos_x, pos_y;
this->axisValue[index - PAD_L_UP] = value * this->axisScale;

// Left -> -- -> Right
// Value range : FFFF8002 -> 0 -> 7FFE
// Force range : 80 -> 0 -> 7F
// Force range : 80 -> 0 -> 7F
// Normal mode : expect value 0 -> 80 -> FF
// Reverse mode: expect value FF -> 7F -> 0

// merge left/right or up/down into rx or ry

#define MERGE(pos, neg) ((this->rawInputs[pos] != 0) ? (127u + ((this->rawInputs[pos] + 1u) / 2u)) : (127u - (this->rawInputs[neg] / 2u)))
if (index <= Inputs::PAD_L_LEFT)
#define MERGE_F(pos, neg) (this->axisValue[pos - PAD_L_UP] - this->axisValue[neg - PAD_L_UP])
if (index <= PAD_L_LEFT)
{
// Left Stick
this->analogs.lx = this->analogs.lxInvert ? MERGE(Inputs::PAD_L_LEFT, Inputs::PAD_L_RIGHT) : MERGE(Inputs::PAD_L_RIGHT, Inputs::PAD_L_LEFT);
this->analogs.ly = this->analogs.lyInvert ? MERGE(Inputs::PAD_L_UP, Inputs::PAD_L_DOWN) : MERGE(Inputs::PAD_L_DOWN, Inputs::PAD_L_UP);
pos_x = this->analogs.lxInvert ? MERGE_F(PAD_L_LEFT, PAD_L_RIGHT) : MERGE_F(PAD_L_RIGHT, PAD_L_LEFT);
pos_y = this->analogs.lyInvert ? MERGE_F(PAD_L_UP, PAD_L_DOWN) : MERGE_F(PAD_L_DOWN, PAD_L_UP);
}
else
{
// Right Stick
this->analogs.rx = this->analogs.rxInvert ? MERGE(Inputs::PAD_R_LEFT, Inputs::PAD_R_RIGHT) : MERGE(Inputs::PAD_R_RIGHT, Inputs::PAD_R_LEFT);
this->analogs.ry = this->analogs.ryInvert ? MERGE(Inputs::PAD_R_UP, Inputs::PAD_R_DOWN) : MERGE(Inputs::PAD_R_DOWN, Inputs::PAD_R_UP);
pos_x = this->analogs.rxInvert ? MERGE_F(PAD_R_LEFT, PAD_R_RIGHT) : MERGE_F(PAD_R_RIGHT, PAD_R_LEFT);
pos_y = this->analogs.ryInvert ? MERGE_F(PAD_R_UP, PAD_R_DOWN) : MERGE_F(PAD_R_DOWN, PAD_R_UP);
}
#undef MERGE

// Deadzone computation.
const float dz = this->axisDeadzone;
float sign_x = pos_x < 0 ? -1.0f : 1.0f;
float sign_y = pos_y < 0 ? -1.0f : 1.0f;

pos_x *= sign_x;
pos_y *= sign_y;

bool force_linear = pos_x == 0 || pos_y == 0;

float dz = this->axisDeadzone;
float adz = this->axisAntideadzone;

if (dz > 0.0f)
{
#define MERGE_F(pos, neg) ((this->rawInputs[pos] != 0) ? (static_cast<float>(this->rawInputs[pos]) / 255.0f) : (static_cast<float>(this->rawInputs[neg]) / -255.0f))
float posX, posY;
if (index <= Inputs::PAD_L_LEFT)
#define DZ_CHECK(x) (x < dz ? 0.0f : (x - dz) / (1.0f - dz))
if (force_linear || this->axisLinearDZ)
{
posX = this->analogs.lxInvert ? MERGE_F(Inputs::PAD_L_LEFT, Inputs::PAD_L_RIGHT) : MERGE_F(Inputs::PAD_L_RIGHT, Inputs::PAD_L_LEFT);
posY = this->analogs.lyInvert ? MERGE_F(Inputs::PAD_L_UP, Inputs::PAD_L_DOWN) : MERGE_F(Inputs::PAD_L_DOWN, Inputs::PAD_L_UP);
pos_x = DZ_CHECK(pos_x);
pos_y = DZ_CHECK(pos_y);
}
else
{
posX = this->analogs.rxInvert ? MERGE_F(Inputs::PAD_R_LEFT, Inputs::PAD_R_RIGHT) : MERGE_F(Inputs::PAD_R_RIGHT, Inputs::PAD_R_LEFT);
posY = this->analogs.ryInvert ? MERGE_F(Inputs::PAD_R_UP, Inputs::PAD_R_DOWN) : MERGE_F(Inputs::PAD_R_DOWN, Inputs::PAD_R_UP);
float radius = sqrt(pos_x * pos_x + pos_y * pos_y);

pos_x /= radius;
pos_y /= radius;

radius = DZ_CHECK(radius);

pos_x *= radius;
pos_y *= radius;
}
#undef DZ_CHECK
}

// No point checking if we're at dead center (usually keyboard with no buttons pressed).
if (posX != 0.0f || posY != 0.0f)
if (adz > 0.0f)
{
#define ADZ_CHECK(x) (x > 0.0f ? adz + x * (1.0f - adz) : 0.0f)
if (force_linear || this->axisLinearADZ)
{
// Compute the angle at the given position in the stick's square bounding box.
const float theta = std::atan2(posY, posX);
pos_x = ADZ_CHECK(pos_x);
pos_y = ADZ_CHECK(pos_y);
}
else
{
float radius = sqrt(pos_x * pos_x + pos_y * pos_y);

// Compute the position that the edge of the circle would be at, given the angle.
const float dzX = std::cos(theta) * dz;
const float dzY = std::sin(theta) * dz;
pos_x /= radius;
pos_y /= radius;

// We're in the deadzone if our position is less than the circle edge.
const bool inX = (posX < 0.0f) ? (posX > dzX) : (posX <= dzX);
const bool inY = (posY < 0.0f) ? (posY > dzY) : (posY <= dzY);

if (inX && inY)
{
// In deadzone. Set to 127 (center).
if (index <= Inputs::PAD_L_LEFT)
{
this->analogs.lx = this->analogs.ly = 127;
}
else
{
this->analogs.rx = this->analogs.ry = 127;
}
}
radius = ADZ_CHECK(radius);

pos_x *= radius;
pos_y *= radius;
}
#undef MERGE_F
#undef ADZ_CHECK
}

pos_x = std::clamp(pos_x, 0.0f, 1.0f) * sign_x + 1.0f;
pos_y = std::clamp(pos_y, 0.0f, 1.0f) * sign_y + 1.0f;

if (index <= PAD_L_LEFT)
{
this->analogs.lx = static_cast<u8>(pos_x * 127.5);
this->analogs.ly = static_cast<u8>(pos_y * 127.5);
}
else
{
this->analogs.rx = static_cast<u8>(pos_x * 127.5);
this->analogs.ry = static_cast<u8>(pos_y * 127.5);
}
}
else if (IsTriggerKey(index))
{
const float s_value = std::clamp(value * this->triggerScale, 0.0f, 1.0f);
const float dz_value = (this->triggerDeadzone > 0.0f && s_value < this->triggerDeadzone) ? 0.0f : s_value;
this->rawInputs[index] = static_cast<u8>(dz_value * 255.0f);
if (dz_value > 0.0f)
float svalue = value * this->triggerScale;
float dz =this->triggerDeadzone;
float adz = this->triggerAntideadzone;

if (dz > 0.0f && svalue < dz)
svalue = 0;

if (adz > 0.0f && svalue > 0.0f)
svalue = adz + svalue * (1.0f - adz);

svalue = std::clamp(svalue, 0.0f, 1.0f);
this->rawInputs[index] = static_cast<u8>(svalue * 255.0f);
if (svalue > 0.0f)
this->buttons &= ~(1u << bitmaskMapping[index]);
else
this->buttons |= (1u << bitmaskMapping[index]);
Expand Down Expand Up @@ -691,15 +751,19 @@ void PadDualshock2::SetRawAnalogs(const std::tuple<u8, u8> left, const std::tupl
this->analogs.ry = std::get<1>(right);
}

void PadDualshock2::SetAxisScale(float deadzone, float scale)
void PadDualshock2::SetAxisScale(bool linear_dz, bool linear_adz, float deadzone, float antideadzone, float scale)
{
this->axisLinearDZ = linear_dz;
this->axisLinearADZ = linear_adz;
this->axisDeadzone = deadzone;
this->axisAntideadzone = antideadzone;
this->axisScale = scale;
}

void PadDualshock2::SetTriggerScale(float deadzone, float scale)
void PadDualshock2::SetTriggerScale(float deadzone, float antideadzone, float scale)
{
this->triggerDeadzone = deadzone;
this->triggerAntideadzone = antideadzone;
this->triggerScale = scale;
}

Expand Down
8 changes: 6 additions & 2 deletions pcsx2/SIO/Pad/PadDualshock2.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,14 @@ class PadDualshock2 final : public PadBase
u32 responseBytes;
std::array<u8, PRESSURE_BUTTONS> pressures;
std::array<u8, VIBRATION_MOTORS> vibrationMotors;
bool axisLinearDZ;
bool axisLinearADZ;
float axisScale;
float axisDeadzone;
float axisAntideadzone;
float triggerScale;
float triggerDeadzone;
float triggerAntideadzone;
std::array<float, 2> vibrationScale;
// When the pressure modifier binding is activated, this is multiplied against
// all values in pressures, to artificially reduce pressures and give players
Expand Down Expand Up @@ -132,8 +136,8 @@ class PadDualshock2 final : public PadBase
const Pad::ControllerInfo& GetInfo() const override;
void Set(u32 index, float value) override;
void SetRawAnalogs(const std::tuple<u8, u8> left, const std::tuple<u8, u8> right) override;
void SetAxisScale(float deadzone, float scale) override;
void SetTriggerScale(float deadzone, float scale) override;
void SetAxisScale(bool linear_dz, bool linear_adz, float deadzone, float antideadzone, float scale) override;
void SetTriggerScale(float deadzone, float antideadzone, float scale) override;
float GetVibrationScale(u32 motor) const override;
void SetVibrationScale(u32 motor, float scale) override;
float GetPressureModifier() const override;
Expand Down
4 changes: 2 additions & 2 deletions pcsx2/SIO/Pad/PadGuitar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,13 +331,13 @@ void PadGuitar::SetRawAnalogs(const std::tuple<u8, u8> left, const std::tuple<u8
{
}

void PadGuitar::SetAxisScale(float deadzone, float scale)
void PadGuitar::SetAxisScale(bool linear_dz, bool linear_adz, float deadzone, float antideadzone, float scale)
{
this->whammyDeadzone = deadzone;
this->whammyAxisScale = scale;
}

void PadGuitar::SetTriggerScale(float deadzone, float scale)
void PadGuitar::SetTriggerScale(float deadzone, float antideadzone, float scale)
{

}
Expand Down
4 changes: 2 additions & 2 deletions pcsx2/SIO/Pad/PadGuitar.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ class PadGuitar final : public PadBase
const Pad::ControllerInfo& GetInfo() const override;
void Set(u32 index, float value) override;
void SetRawAnalogs(const std::tuple<u8, u8> left, const std::tuple<u8, u8> right) override;
void SetAxisScale(float deadzone, float scale) override;
void SetTriggerScale(float deadzone, float scale) override;
void SetAxisScale(bool linear_dz, bool linear_adz, float deadzone, float antideadzone, float scale) override;
void SetTriggerScale(float deadzone, float antideadzone, float scale) override;
float GetVibrationScale(u32 motor) const override;
void SetVibrationScale(u32 motor, float scale) override;
float GetPressureModifier() const override;
Expand Down
4 changes: 2 additions & 2 deletions pcsx2/SIO/Pad/PadNotConnected.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ void PadNotConnected::SetRawAnalogs(const std::tuple<u8, u8> left, const std::tu

}

void PadNotConnected::SetAxisScale(float deadzone, float scale)
void PadNotConnected::SetAxisScale(bool linear_dz, bool linear_adz, float deadzone, float antideadzone, float scale)
{

}

void PadNotConnected::SetTriggerScale(float deadzone, float scale)
void PadNotConnected::SetTriggerScale(float deadzone, float antideadzone, float scale)
{

}
Expand Down
4 changes: 2 additions & 2 deletions pcsx2/SIO/Pad/PadNotConnected.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ class PadNotConnected final : public PadBase
const Pad::ControllerInfo& GetInfo() const override;
void Set(u32 index, float value) override;
void SetRawAnalogs(const std::tuple<u8, u8> left, const std::tuple<u8, u8> right) override;
void SetAxisScale(float deadzone, float scale) override;
void SetTriggerScale(float deadzone, float scale) override;
void SetAxisScale(bool linear_dz, bool linear_adz, float deadzone, float antideadzone, float scale) override;
void SetTriggerScale(float deadzone, float antideadzone, float scale) override;
float GetVibrationScale(u32 motor) const override;
void SetVibrationScale(u32 motor, float scale) override;
float GetPressureModifier() const override;
Expand Down

0 comments on commit 0da9a33

Please sign in to comment.