Skip to content

Commit

Permalink
Joystick input: Ignore in-deadzone events from a different device tha…
Browse files Browse the repository at this point in the history
…n previous events

Fixes #15465
  • Loading branch information
hrydgard committed Nov 23, 2022
1 parent f4c88e0 commit 5230fc7
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 71 deletions.
1 change: 1 addition & 0 deletions Common/Input/InputState.h
Expand Up @@ -33,6 +33,7 @@ enum {
DEVICE_ID_ACCELEROMETER = 30,
DEVICE_ID_XR_CONTROLLER_LEFT = 40,
DEVICE_ID_XR_CONTROLLER_RIGHT = 41,
DEVICE_ID_TOUCH = 42,
};

//number of contiguous generic joypad IDs
Expand Down
115 changes: 70 additions & 45 deletions Core/ControlMapper.cpp
Expand Up @@ -15,6 +15,7 @@ static float MapAxisValue(float v) {
const float invDeadzone = g_Config.fAnalogInverseDeadzone;
const float sensitivity = g_Config.fAnalogSensitivity;
const float sign = v >= 0.0f ? 1.0f : -1.0f;

return sign * Clamp(invDeadzone + (abs(v) - deadzone) / (1.0f - deadzone) * (sensitivity - invDeadzone), 0.0f, 1.0f);
}

Expand Down Expand Up @@ -49,24 +50,48 @@ void ControlMapper::SetRawCallback(std::function<void(int, float, float)> setRaw
setRawAnalog_ = setRawAnalog;
}


void ControlMapper::SetPSPAxis(char axis, float value, int stick) {
static float history[2][2] = {};

void ControlMapper::SetPSPAxis(int device, char axis, float value, int stick) {
int axisId = axis == 'X' ? 0 : 1;

history[stick][axisId] = value;
float position[2];
position[0] = history[stick][0];
position[1] = history[stick][1];

float x = history[stick][0];
float y = history[stick][1];
position[axisId] = value;

float x = position[0];
float y = position[1];

if (setRawAnalog_) {
setRawAnalog_(stick, x, y);
}

ConvertAnalogStick(x, y);
// NOTE: We need to use single-axis checks, since the other axis might be from another device,
// so we'll add a little leeway.
bool inDeadZone = fabsf(value) < g_Config.fAnalogDeadzone * 0.7f;

bool ignore = false;

if (inDeadZone && lastNonDeadzoneDeviceID_[stick] != device) {
// Ignore this event! See issue #15465
NOTICE_LOG(COMMON, "Ignoring deadzone event from device %d (%d, %f)", device, axis, value);
ignore = true;
}

if (!inDeadZone) {
NOTICE_LOG(COMMON, "Got a non deadzone event from device %d (%d, %f > %f)", device, axis, value, g_Config.fAnalogDeadzone);
lastNonDeadzoneDeviceID_[stick] = device;
}

if (!ignore) {
history[stick][axisId] = value;

float x = history[stick][0];
float y = history[stick][1];

setPSPAnalog_(stick, x, y);
ConvertAnalogStick(x, y);
setPSPAnalog_(stick, x, y);
}
}

bool ControlMapper::Key(const KeyInput &key, bool *pauseTrigger) {
Expand All @@ -79,7 +104,7 @@ bool ControlMapper::Key(const KeyInput &key, bool *pauseTrigger) {
}

for (size_t i = 0; i < pspKeys.size(); i++) {
pspKey(pspKeys[i], key.flags);
pspKey(key.deviceId, pspKeys[i], key.flags);
}

DEBUG_LOG(SYSTEM, "Key: %d DeviceId: %d", key.keyCode, key.deviceId);
Expand Down Expand Up @@ -155,7 +180,7 @@ static int RotatePSPKeyCode(int x) {
}
}

void ControlMapper::setVKeyAnalog(char axis, int stick, int virtualKeyMin, int virtualKeyMax, bool setZero) {
void ControlMapper::setVKeyAnalog(int deviceId, char axis, int stick, int virtualKeyMin, int virtualKeyMax, bool setZero) {
// The down events can repeat, so just trust the virtKeys array.
bool minDown = virtKeys[virtualKeyMin - VIRTKEY_FIRST];
bool maxDown = virtKeys[virtualKeyMax - VIRTKEY_FIRST];
Expand All @@ -167,11 +192,11 @@ void ControlMapper::setVKeyAnalog(char axis, int stick, int virtualKeyMin, int v
if (maxDown)
value += scale;
if (setZero || minDown || maxDown) {
SetPSPAxis(axis, value, stick);
SetPSPAxis(deviceId, axis, value, stick);
}
}

void ControlMapper::pspKey(int pspKeyCode, int flags) {
void ControlMapper::pspKey(int deviceId, int pspKeyCode, int flags) {
int rotations = 0;
switch (g_Config.iInternalScreenRotation) {
case ROTATION_LOCKED_HORIZONTAL180:
Expand All @@ -193,11 +218,11 @@ void ControlMapper::pspKey(int pspKeyCode, int flags) {
int vk = pspKeyCode - VIRTKEY_FIRST;
if (flags & KEY_DOWN) {
virtKeys[vk] = true;
onVKeyDown(pspKeyCode);
onVKeyDown(deviceId, pspKeyCode);
}
if (flags & KEY_UP) {
virtKeys[vk] = false;
onVKeyUp(pspKeyCode);
onVKeyUp(deviceId, pspKeyCode);
}
} else {
// INFO_LOG(SYSTEM, "pspKey %i %i", pspKeyCode, flags);
Expand All @@ -208,32 +233,32 @@ void ControlMapper::pspKey(int pspKeyCode, int flags) {
}
}

void ControlMapper::onVKeyDown(int vkey) {
void ControlMapper::onVKeyDown(int deviceId, int vkey) {
switch (vkey) {

case VIRTKEY_AXIS_X_MIN:
case VIRTKEY_AXIS_X_MAX:
setVKeyAnalog('X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX);
setVKeyAnalog(deviceId, 'X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX);
break;
case VIRTKEY_AXIS_Y_MIN:
case VIRTKEY_AXIS_Y_MAX:
setVKeyAnalog('Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX);
setVKeyAnalog(deviceId, 'Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX);
break;

case VIRTKEY_AXIS_RIGHT_X_MIN:
case VIRTKEY_AXIS_RIGHT_X_MAX:
setVKeyAnalog('X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX);
setVKeyAnalog(deviceId, 'X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX);
break;
case VIRTKEY_AXIS_RIGHT_Y_MIN:
case VIRTKEY_AXIS_RIGHT_Y_MAX:
setVKeyAnalog('Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX);
setVKeyAnalog(deviceId, 'Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX);
break;

case VIRTKEY_ANALOG_LIGHTLY:
setVKeyAnalog('X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX, false);
setVKeyAnalog('Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX, false);
setVKeyAnalog('X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX, false);
setVKeyAnalog('Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX, false);
setVKeyAnalog(deviceId, 'X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX, false);
setVKeyAnalog(deviceId, 'Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX, false);
setVKeyAnalog(deviceId, 'X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX, false);
setVKeyAnalog(deviceId, 'Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX, false);
break;

case VIRTKEY_ANALOG_ROTATE_CW:
Expand All @@ -252,32 +277,32 @@ void ControlMapper::onVKeyDown(int vkey) {
}
}

void ControlMapper::onVKeyUp(int vkey) {
void ControlMapper::onVKeyUp(int deviceId, int vkey) {
switch (vkey) {

case VIRTKEY_AXIS_X_MIN:
case VIRTKEY_AXIS_X_MAX:
setVKeyAnalog('X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX);
setVKeyAnalog(deviceId, 'X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX);
break;
case VIRTKEY_AXIS_Y_MIN:
case VIRTKEY_AXIS_Y_MAX:
setVKeyAnalog('Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX);
setVKeyAnalog(deviceId, 'Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX);
break;

case VIRTKEY_AXIS_RIGHT_X_MIN:
case VIRTKEY_AXIS_RIGHT_X_MAX:
setVKeyAnalog('X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX);
setVKeyAnalog(deviceId, 'X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX);
break;
case VIRTKEY_AXIS_RIGHT_Y_MIN:
case VIRTKEY_AXIS_RIGHT_Y_MAX:
setVKeyAnalog('Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX);
setVKeyAnalog(deviceId, 'Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX);
break;

case VIRTKEY_ANALOG_LIGHTLY:
setVKeyAnalog('X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX, false);
setVKeyAnalog('Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX, false);
setVKeyAnalog('X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX, false);
setVKeyAnalog('Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX, false);
setVKeyAnalog(deviceId, 'X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX, false);
setVKeyAnalog(deviceId, 'Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX, false);
setVKeyAnalog(deviceId, 'X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX, false);
setVKeyAnalog(deviceId, 'Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX, false);
break;

case VIRTKEY_ANALOG_ROTATE_CW:
Expand Down Expand Up @@ -312,29 +337,29 @@ void ControlMapper::processAxis(const AxisInput &axis, int direction) {
float value = fabs(axis.value) * scale;
switch (result) {
case VIRTKEY_AXIS_X_MIN:
SetPSPAxis('X', -value, CTRL_STICK_LEFT);
SetPSPAxis(axis.deviceId, 'X', -value, CTRL_STICK_LEFT);
break;
case VIRTKEY_AXIS_X_MAX:
SetPSPAxis('X', value, CTRL_STICK_LEFT);
SetPSPAxis(axis.deviceId, 'X', value, CTRL_STICK_LEFT);
break;
case VIRTKEY_AXIS_Y_MIN:
SetPSPAxis('Y', -value, CTRL_STICK_LEFT);
SetPSPAxis(axis.deviceId, 'Y', -value, CTRL_STICK_LEFT);
break;
case VIRTKEY_AXIS_Y_MAX:
SetPSPAxis('Y', value, CTRL_STICK_LEFT);
SetPSPAxis(axis.deviceId, 'Y', value, CTRL_STICK_LEFT);
break;

case VIRTKEY_AXIS_RIGHT_X_MIN:
SetPSPAxis('X', -value, CTRL_STICK_RIGHT);
SetPSPAxis(axis.deviceId, 'X', -value, CTRL_STICK_RIGHT);
break;
case VIRTKEY_AXIS_RIGHT_X_MAX:
SetPSPAxis('X', value, CTRL_STICK_RIGHT);
SetPSPAxis(axis.deviceId, 'X', value, CTRL_STICK_RIGHT);
break;
case VIRTKEY_AXIS_RIGHT_Y_MIN:
SetPSPAxis('Y', -value, CTRL_STICK_RIGHT);
SetPSPAxis(axis.deviceId, 'Y', -value, CTRL_STICK_RIGHT);
break;
case VIRTKEY_AXIS_RIGHT_Y_MAX:
SetPSPAxis('Y', value, CTRL_STICK_RIGHT);
SetPSPAxis(axis.deviceId, 'Y', value, CTRL_STICK_RIGHT);
break;

case VIRTKEY_SPEED_ANALOG:
Expand Down Expand Up @@ -366,22 +391,22 @@ void ControlMapper::processAxis(const AxisInput &axis, int direction) {
if (axisState != 0) {
for (size_t i = 0; i < results.size(); i++) {
if (!IsAnalogStickKey(results[i]))
pspKey(results[i], KEY_DOWN);
pspKey(axis.deviceId, results[i], KEY_DOWN);
}
// Also unpress the other direction (unless both directions press the same key.)
for (size_t i = 0; i < resultsOpposite.size(); i++) {
if (!IsAnalogStickKey(resultsOpposite[i]) && std::find(results.begin(), results.end(), resultsOpposite[i]) == results.end())
pspKey(resultsOpposite[i], KEY_UP);
pspKey(axis.deviceId, resultsOpposite[i], KEY_UP);
}
} else if (axisState == 0) {
// Release both directions, trying to deal with some erratic controllers that can cause it to stick.
for (size_t i = 0; i < results.size(); i++) {
if (!IsAnalogStickKey(results[i]))
pspKey(results[i], KEY_UP);
pspKey(axis.deviceId, results[i], KEY_UP);
}
for (size_t i = 0; i < resultsOpposite.size(); i++) {
if (!IsAnalogStickKey(resultsOpposite[i]))
pspKey(resultsOpposite[i], KEY_UP);
pspKey(axis.deviceId, resultsOpposite[i], KEY_UP);
}
}
}
Expand Down
14 changes: 9 additions & 5 deletions Core/ControlMapper.h
Expand Up @@ -16,7 +16,7 @@ class ControlMapper {
void Update();

bool Key(const KeyInput &key, bool *pauseTrigger);
void pspKey(int pspKeyCode, int flags);
void pspKey(int deviceId, int pspKeyCode, int flags);
bool Axis(const AxisInput &axis);

// Required callbacks
Expand All @@ -30,20 +30,24 @@ class ControlMapper {

private:
void processAxis(const AxisInput &axis, int direction);
void setVKeyAnalog(char axis, int stick, int virtualKeyMin, int virtualKeyMax, bool setZero = true);
void setVKeyAnalog(int deviceId, char axis, int stick, int virtualKeyMin, int virtualKeyMax, bool setZero = true);

void SetPSPAxis(char axis, float value, int stick);
void SetPSPAxis(int deviceId, char axis, float value, int stick);
void ProcessAnalogSpeed(const AxisInput &axis, bool opposite);

void onVKeyDown(int vkey);
void onVKeyUp(int vkey);
void onVKeyDown(int deviceId, int vkey);
void onVKeyUp(int deviceId, int vkey);

// To track mappable virtual keys. We can have as many as we want.
bool virtKeys[VIRTKEY_COUNT]{};

// De-noise mapped axis updates
int axisState_[JOYSTICK_AXIS_MAX]{};

int lastNonDeadzoneDeviceID_[2]{};

float history[2][2] = {};

// Mappable auto-rotation. Useful for keyboard/dpad->analog in a few games.
bool autoRotatingAnalogCW_ = false;
bool autoRotatingAnalogCCW_ = false;
Expand Down
1 change: 1 addition & 0 deletions UI/ControlMappingScreen.cpp
Expand Up @@ -583,6 +583,7 @@ void JoystickHistoryView::Update() {

AnalogSetupScreen::AnalogSetupScreen() {
mapper_.SetCallbacks([](int vkey) {}, [](int vkey) {}, [&](int stick, float x, float y) {
NOTICE_LOG(COMMON, "analog value from mapper: %f %f", x, y);
analogX_[stick] = x;
analogY_[stick] = y;
});
Expand Down
3 changes: 0 additions & 3 deletions UI/EmuScreen.cpp
Expand Up @@ -136,8 +136,6 @@ static void __EmuScreenVblank()
}

// Handles control rotation due to internal screen rotation.
// TODO: This should be a callback too, so we don't actually call the __Ctrl functions
// from settings screens, etc.
static void SetPSPAnalog(int stick, float x, float y) {
switch (g_Config.iInternalScreenRotation) {
case ROTATION_LOCKED_HORIZONTAL:
Expand All @@ -164,7 +162,6 @@ static void SetPSPAnalog(int stick, float x, float y) {
default:
break;
}

__CtrlSetAnalogXY(stick, x, y);
}

Expand Down

0 comments on commit 5230fc7

Please sign in to comment.