2021-07-08 20:39:17 +00:00
|
|
|
#include <algorithm>
|
|
|
|
|
2021-07-08 19:30:23 +00:00
|
|
|
#include "Common/Math/math_util.h"
|
2021-07-09 14:14:32 +00:00
|
|
|
#include "Common/TimeUtil.h"
|
2021-08-28 13:12:10 +00:00
|
|
|
#include "Common/Log.h"
|
2021-07-09 14:14:32 +00:00
|
|
|
|
2023-03-26 09:35:42 +00:00
|
|
|
#include "Core/HLE/sceCtrl.h"
|
2021-07-08 19:30:23 +00:00
|
|
|
#include "Core/KeyMap.h"
|
|
|
|
#include "Core/ControlMapper.h"
|
|
|
|
#include "Core/Config.h"
|
2022-07-04 20:10:42 +00:00
|
|
|
#include "Core/CoreParameter.h"
|
|
|
|
#include "Core/System.h"
|
2021-07-08 19:30:23 +00:00
|
|
|
|
|
|
|
static float MapAxisValue(float v) {
|
|
|
|
const float deadzone = g_Config.fAnalogDeadzone;
|
|
|
|
const float invDeadzone = g_Config.fAnalogInverseDeadzone;
|
|
|
|
const float sensitivity = g_Config.fAnalogSensitivity;
|
|
|
|
const float sign = v >= 0.0f ? 1.0f : -1.0f;
|
2022-11-23 11:22:59 +00:00
|
|
|
|
2021-07-08 19:30:23 +00:00
|
|
|
return sign * Clamp(invDeadzone + (abs(v) - deadzone) / (1.0f - deadzone) * (sensitivity - invDeadzone), 0.0f, 1.0f);
|
|
|
|
}
|
|
|
|
|
2023-03-29 08:21:49 +00:00
|
|
|
// TODO: Possibly make these configurable?
|
|
|
|
float GetDeviceAxisThreshold(int device) {
|
|
|
|
return device == DEVICE_ID_MOUSE ? AXIS_BIND_THRESHOLD_MOUSE : AXIS_BIND_THRESHOLD;
|
|
|
|
}
|
|
|
|
|
2021-07-09 11:10:16 +00:00
|
|
|
void ConvertAnalogStick(float &x, float &y) {
|
2021-07-08 19:30:23 +00:00
|
|
|
const bool isCircular = g_Config.bAnalogIsCircular;
|
|
|
|
|
|
|
|
float norm = std::max(fabsf(x), fabsf(y));
|
|
|
|
|
|
|
|
if (norm == 0.0f)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (isCircular) {
|
|
|
|
float newNorm = sqrtf(x * x + y * y);
|
|
|
|
float factor = newNorm / norm;
|
|
|
|
x *= factor;
|
|
|
|
y *= factor;
|
|
|
|
norm = newNorm;
|
|
|
|
}
|
|
|
|
|
|
|
|
float mappedNorm = MapAxisValue(norm);
|
|
|
|
x = Clamp(x / norm * mappedNorm, -1.0f, 1.0f);
|
|
|
|
y = Clamp(y / norm * mappedNorm, -1.0f, 1.0f);
|
|
|
|
}
|
|
|
|
|
2023-03-30 08:47:28 +00:00
|
|
|
void ControlMapper::SetCallbacks(
|
|
|
|
std::function<void(int, bool)> onVKey,
|
|
|
|
std::function<void(uint32_t, uint32_t)> setAllPSPButtonStates,
|
|
|
|
std::function<void(int, bool)> setPSPButtonState,
|
|
|
|
std::function<void(int, float, float)> setPSPAnalog) {
|
|
|
|
onVKey_ = onVKey;
|
|
|
|
setAllPSPButtonStates_ = setAllPSPButtonStates;
|
2023-03-26 09:35:42 +00:00
|
|
|
setPSPButtonState_ = setPSPButtonState;
|
2021-07-09 09:01:56 +00:00
|
|
|
setPSPAnalog_ = setPSPAnalog;
|
|
|
|
}
|
|
|
|
|
2021-07-09 11:10:16 +00:00
|
|
|
void ControlMapper::SetRawCallback(std::function<void(int, float, float)> setRawAnalog) {
|
|
|
|
setRawAnalog_ = setRawAnalog;
|
|
|
|
}
|
|
|
|
|
2022-11-23 11:22:59 +00:00
|
|
|
void ControlMapper::SetPSPAxis(int device, char axis, float value, int stick) {
|
2021-07-09 09:01:56 +00:00
|
|
|
int axisId = axis == 'X' ? 0 : 1;
|
|
|
|
|
2022-11-23 11:22:59 +00:00
|
|
|
float position[2];
|
2023-03-26 16:04:40 +00:00
|
|
|
position[0] = history_[stick][0];
|
|
|
|
position[1] = history_[stick][1];
|
2021-07-09 09:01:56 +00:00
|
|
|
|
2022-11-23 11:22:59 +00:00
|
|
|
position[axisId] = value;
|
|
|
|
|
|
|
|
float x = position[0];
|
|
|
|
float y = position[1];
|
2021-07-09 09:01:56 +00:00
|
|
|
|
2021-07-09 11:10:16 +00:00
|
|
|
if (setRawAnalog_) {
|
|
|
|
setRawAnalog_(stick, x, y);
|
|
|
|
}
|
|
|
|
|
2022-11-23 11:22:59 +00:00
|
|
|
// 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
|
|
|
|
ignore = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!inDeadZone) {
|
|
|
|
lastNonDeadzoneDeviceID_[stick] = device;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ignore) {
|
2023-03-26 16:04:40 +00:00
|
|
|
history_[stick][axisId] = value;
|
2022-11-23 11:22:59 +00:00
|
|
|
|
2023-03-26 16:04:40 +00:00
|
|
|
float x = history_[stick][0];
|
|
|
|
float y = history_[stick][1];
|
2021-07-09 09:01:56 +00:00
|
|
|
|
2022-11-23 11:22:59 +00:00
|
|
|
ConvertAnalogStick(x, y);
|
|
|
|
setPSPAnalog_(stick, x, y);
|
|
|
|
}
|
2021-07-08 19:30:23 +00:00
|
|
|
}
|
|
|
|
|
2023-03-29 08:21:49 +00:00
|
|
|
static int RotatePSPKeyCode(int x) {
|
|
|
|
switch (x) {
|
|
|
|
case CTRL_UP: return CTRL_RIGHT;
|
|
|
|
case CTRL_RIGHT: return CTRL_DOWN;
|
|
|
|
case CTRL_DOWN: return CTRL_LEFT;
|
|
|
|
case CTRL_LEFT: return CTRL_UP;
|
|
|
|
default:
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ControlMapper::UpdatePSPState() {
|
|
|
|
// Instead of taking an input key and finding what it outputs, we loop through the OUTPUTS and
|
|
|
|
// see if the input that corresponds to it has a value. That way we can easily implement all sorts
|
|
|
|
// of crazy input combos if needed.
|
|
|
|
|
|
|
|
// For the PSP's button inputs, we just go through and put the flags together.
|
|
|
|
uint32_t buttonMask = 0;
|
|
|
|
|
|
|
|
int rotations = 0;
|
|
|
|
switch (g_Config.iInternalScreenRotation) {
|
|
|
|
case ROTATION_LOCKED_HORIZONTAL180: rotations = 2; break;
|
|
|
|
case ROTATION_LOCKED_VERTICAL: rotations = 1; break;
|
|
|
|
case ROTATION_LOCKED_VERTICAL180: rotations = 3; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < 32; i++) {
|
|
|
|
uint32_t mask = 1 << i;
|
|
|
|
if (!(mask & CTRL_MASK_USER)) {
|
|
|
|
// Not a mappable button bit
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t mapping = mask;
|
|
|
|
for (int i = 0; i < rotations; i++) {
|
|
|
|
mapping = RotatePSPKeyCode(mapping);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<InputMapping> inputMappings;
|
|
|
|
// This is really "MappingsFromPspButtons".
|
|
|
|
if (!KeyMap::InputMappingsFromPspButton(mapping, &inputMappings, false))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (int j = 0; j < inputMappings.size(); j++) {
|
|
|
|
auto iter = curInput_.find(inputMappings[j]) ;
|
|
|
|
if (iter != curInput_.end() && iter->second > 0.0f) {
|
|
|
|
buttonMask |= mask;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setAllPSPButtonStates_(buttonMask);
|
|
|
|
|
|
|
|
// OK, handle all the virtual keys next. For these we need to do deltas here and send events.
|
2021-07-08 19:30:23 +00:00
|
|
|
|
2023-03-29 08:21:49 +00:00
|
|
|
// Now let's look at the four axes.
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Here we need to diff pspState with prevPspState_ to generate
|
|
|
|
// any new PSP key events. Though for the actual PSP buttons themselves (not the sticks),
|
|
|
|
// we could just or them together and set them all at once.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ControlMapper::Key(const KeyInput &key, bool *pauseTrigger) {
|
|
|
|
if (key.flags & KEY_IS_REPEAT) {
|
2021-07-08 19:30:23 +00:00
|
|
|
// Claim that we handled this. Prevents volume key repeats from popping up the volume control on Android.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-03-29 08:21:49 +00:00
|
|
|
InputMapping mapping(key.deviceId, key.keyCode);
|
|
|
|
|
|
|
|
if (key.flags & KEY_DOWN) {
|
|
|
|
curInput_[mapping] = 1.0f;
|
|
|
|
} else if (key.flags & KEY_UP) {
|
|
|
|
curInput_.erase(mapping);
|
2021-07-08 19:30:23 +00:00
|
|
|
}
|
|
|
|
|
2023-03-29 08:21:49 +00:00
|
|
|
std::vector<int> pspKeys;
|
|
|
|
KeyMap::InputMappingToPspButton(InputMapping(key.deviceId, key.keyCode), &pspKeys);
|
2021-08-28 16:14:53 +00:00
|
|
|
DEBUG_LOG(SYSTEM, "Key: %d DeviceId: %d", key.keyCode, key.deviceId);
|
2021-07-08 19:30:23 +00:00
|
|
|
if (!pspKeys.size() || key.deviceId == DEVICE_ID_DEFAULT) {
|
|
|
|
if ((key.flags & KEY_DOWN) && key.keyCode == NKCODE_BACK) {
|
|
|
|
*pauseTrigger = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-29 08:21:49 +00:00
|
|
|
return UpdatePSPState();
|
2021-07-08 19:30:23 +00:00
|
|
|
}
|
|
|
|
|
2022-12-31 20:44:52 +00:00
|
|
|
void ControlMapper::Axis(const AxisInput &axis) {
|
2021-07-08 19:30:23 +00:00
|
|
|
if (axis.value > 0) {
|
2023-03-29 08:21:49 +00:00
|
|
|
InputMapping mapping(axis.deviceId, axis.axisId, 1);
|
|
|
|
curInput_[mapping] = axis.value;
|
2021-07-08 19:30:23 +00:00
|
|
|
} else if (axis.value < 0) {
|
2023-03-29 08:21:49 +00:00
|
|
|
InputMapping mapping(axis.deviceId, axis.axisId, -1);
|
|
|
|
curInput_[mapping] = axis.value;
|
|
|
|
} else if (axis.value == 0.0f) { // Threshold?
|
2021-07-08 19:30:23 +00:00
|
|
|
// Both directions! Prevents sticking for digital input devices that are axises (like HAT)
|
2023-03-29 08:21:49 +00:00
|
|
|
InputMapping mappingPositive(axis.deviceId, axis.axisId, -1);
|
|
|
|
InputMapping mappingNegative(axis.deviceId, axis.axisId, -1);
|
|
|
|
curInput_[mappingPositive] = 0.0f;
|
|
|
|
curInput_[mappingNegative] = 0.0f;
|
2021-07-08 19:30:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-09 14:14:32 +00:00
|
|
|
void ControlMapper::Update() {
|
|
|
|
if (autoRotatingAnalogCW_) {
|
|
|
|
const double now = time_now_d();
|
|
|
|
// Clamp to a square
|
|
|
|
float x = std::min(1.0f, std::max(-1.0f, 1.42f * (float)cos(now * -g_Config.fAnalogAutoRotSpeed)));
|
|
|
|
float y = std::min(1.0f, std::max(-1.0f, 1.42f * (float)sin(now * -g_Config.fAnalogAutoRotSpeed)));
|
|
|
|
|
|
|
|
setPSPAnalog_(0, x, y);
|
|
|
|
} else if (autoRotatingAnalogCCW_) {
|
|
|
|
const double now = time_now_d();
|
|
|
|
float x = std::min(1.0f, std::max(-1.0f, 1.42f * (float)cos(now * g_Config.fAnalogAutoRotSpeed)));
|
|
|
|
float y = std::min(1.0f, std::max(-1.0f, 1.42f * (float)sin(now * g_Config.fAnalogAutoRotSpeed)));
|
|
|
|
|
|
|
|
setPSPAnalog_(0, x, y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-08 19:30:23 +00:00
|
|
|
inline bool IsAnalogStickKey(int key) {
|
|
|
|
switch (key) {
|
|
|
|
case VIRTKEY_AXIS_X_MIN:
|
|
|
|
case VIRTKEY_AXIS_X_MAX:
|
|
|
|
case VIRTKEY_AXIS_Y_MIN:
|
|
|
|
case VIRTKEY_AXIS_Y_MAX:
|
|
|
|
case VIRTKEY_AXIS_RIGHT_X_MIN:
|
|
|
|
case VIRTKEY_AXIS_RIGHT_X_MAX:
|
|
|
|
case VIRTKEY_AXIS_RIGHT_Y_MIN:
|
|
|
|
case VIRTKEY_AXIS_RIGHT_Y_MAX:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-26 16:04:40 +00:00
|
|
|
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];
|
2021-07-08 19:30:23 +00:00
|
|
|
|
2023-03-26 16:04:40 +00:00
|
|
|
const float scale = virtKeys_[VIRTKEY_ANALOG_LIGHTLY - VIRTKEY_FIRST] ? g_Config.fAnalogLimiterDeadzone : 1.0f;
|
2021-07-08 19:30:23 +00:00
|
|
|
float value = 0.0f;
|
|
|
|
if (minDown)
|
|
|
|
value -= scale;
|
|
|
|
if (maxDown)
|
|
|
|
value += scale;
|
|
|
|
if (setZero || minDown || maxDown) {
|
2022-11-23 11:22:59 +00:00
|
|
|
SetPSPAxis(deviceId, axis, value, stick);
|
2021-07-08 19:30:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-26 16:04:40 +00:00
|
|
|
void ControlMapper::PSPKey(int deviceId, int pspKeyCode, int flags) {
|
|
|
|
SetPSPKey(deviceId, pspKeyCode, flags);
|
|
|
|
}
|
2021-07-08 19:30:23 +00:00
|
|
|
|
2023-03-26 16:04:40 +00:00
|
|
|
void ControlMapper::SetPSPKey(int deviceId, int pspKeyCode, int flags) {
|
2023-03-29 08:21:49 +00:00
|
|
|
/*
|
2021-07-08 19:30:23 +00:00
|
|
|
if (pspKeyCode >= VIRTKEY_FIRST) {
|
|
|
|
int vk = pspKeyCode - VIRTKEY_FIRST;
|
|
|
|
if (flags & KEY_DOWN) {
|
2023-03-26 16:04:40 +00:00
|
|
|
virtKeys_[vk] = true;
|
2023-03-30 08:47:28 +00:00
|
|
|
onVKey(deviceId, pspKeyCode, true);
|
2021-07-08 19:30:23 +00:00
|
|
|
}
|
|
|
|
if (flags & KEY_UP) {
|
2023-03-26 16:04:40 +00:00
|
|
|
virtKeys_[vk] = false;
|
2023-03-30 08:47:28 +00:00
|
|
|
onVKey(deviceId, pspKeyCode, false);
|
2021-07-08 19:30:23 +00:00
|
|
|
}
|
|
|
|
} else {
|
2023-03-26 16:04:40 +00:00
|
|
|
// INFO_LOG(SYSTEM, "pspKey %d %d", pspKeyCode, flags);
|
2021-07-08 19:30:23 +00:00
|
|
|
if (flags & KEY_DOWN)
|
2023-03-26 09:35:42 +00:00
|
|
|
setPSPButtonState_(pspKeyCode, true);
|
2021-07-08 19:30:23 +00:00
|
|
|
if (flags & KEY_UP)
|
2023-03-26 09:35:42 +00:00
|
|
|
setPSPButtonState_(pspKeyCode, false);
|
2021-07-08 19:30:23 +00:00
|
|
|
}
|
2023-03-29 08:21:49 +00:00
|
|
|
*/
|
2021-07-08 19:30:23 +00:00
|
|
|
}
|
|
|
|
|
2023-03-30 08:47:28 +00:00
|
|
|
void ControlMapper::onVKey(int deviceId, int vkey, bool down) {
|
2021-07-08 19:30:23 +00:00
|
|
|
switch (vkey) {
|
|
|
|
case VIRTKEY_AXIS_X_MIN:
|
|
|
|
case VIRTKEY_AXIS_X_MAX:
|
2023-03-26 16:04:40 +00:00
|
|
|
SetVKeyAnalog(deviceId, 'X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX);
|
2021-07-08 19:30:23 +00:00
|
|
|
break;
|
|
|
|
case VIRTKEY_AXIS_Y_MIN:
|
|
|
|
case VIRTKEY_AXIS_Y_MAX:
|
2023-03-26 16:04:40 +00:00
|
|
|
SetVKeyAnalog(deviceId, 'Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX);
|
2021-07-08 19:30:23 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIRTKEY_AXIS_RIGHT_X_MIN:
|
|
|
|
case VIRTKEY_AXIS_RIGHT_X_MAX:
|
2023-03-26 16:04:40 +00:00
|
|
|
SetVKeyAnalog(deviceId, 'X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX);
|
2021-07-08 19:30:23 +00:00
|
|
|
break;
|
|
|
|
case VIRTKEY_AXIS_RIGHT_Y_MIN:
|
|
|
|
case VIRTKEY_AXIS_RIGHT_Y_MAX:
|
2023-03-26 16:04:40 +00:00
|
|
|
SetVKeyAnalog(deviceId, 'Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX);
|
2021-07-08 19:30:23 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIRTKEY_ANALOG_LIGHTLY:
|
2023-03-26 16:04:40 +00:00
|
|
|
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);
|
2021-07-08 19:30:23 +00:00
|
|
|
break;
|
|
|
|
|
2021-07-09 14:14:32 +00:00
|
|
|
case VIRTKEY_ANALOG_ROTATE_CW:
|
2023-03-30 08:47:28 +00:00
|
|
|
if (down) {
|
|
|
|
autoRotatingAnalogCW_ = true;
|
|
|
|
autoRotatingAnalogCCW_ = false;
|
|
|
|
} else {
|
|
|
|
autoRotatingAnalogCW_ = false;
|
|
|
|
setPSPAnalog_(0, 0.0f, 0.0f);
|
|
|
|
}
|
2021-07-09 14:14:32 +00:00
|
|
|
break;
|
|
|
|
case VIRTKEY_ANALOG_ROTATE_CCW:
|
2023-03-30 08:47:28 +00:00
|
|
|
if (down) {
|
|
|
|
autoRotatingAnalogCW_ = false;
|
|
|
|
autoRotatingAnalogCCW_ = true;
|
|
|
|
} else {
|
|
|
|
autoRotatingAnalogCCW_ = false;
|
|
|
|
setPSPAnalog_(0, 0.0f, 0.0f);
|
|
|
|
}
|
2021-07-09 14:14:32 +00:00
|
|
|
break;
|
|
|
|
|
2021-07-08 19:30:23 +00:00
|
|
|
default:
|
2023-03-30 08:47:28 +00:00
|
|
|
if (onVKey_)
|
|
|
|
onVKey_(vkey, down);
|
2021-07-08 19:30:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-26 16:04:40 +00:00
|
|
|
void ControlMapper::ProcessAxis(const AxisInput &axis, int direction) {
|
2021-07-08 19:30:23 +00:00
|
|
|
// Sanity check
|
|
|
|
if (axis.axisId < 0 || axis.axisId >= JOYSTICK_AXIS_MAX) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-03-26 16:04:40 +00:00
|
|
|
const float scale = virtKeys_[VIRTKEY_ANALOG_LIGHTLY - VIRTKEY_FIRST] ? g_Config.fAnalogLimiterDeadzone : 1.0f;
|
2021-07-08 19:30:23 +00:00
|
|
|
|
|
|
|
std::vector<int> results;
|
2023-03-29 09:59:31 +00:00
|
|
|
KeyMap::InputMappingToPspButton(InputMapping(axis.deviceId, axis.axisId, direction), &results);
|
2021-07-08 19:30:23 +00:00
|
|
|
|
|
|
|
for (int result : results) {
|
|
|
|
float value = fabs(axis.value) * scale;
|
|
|
|
switch (result) {
|
|
|
|
case VIRTKEY_AXIS_X_MIN:
|
2022-11-23 11:22:59 +00:00
|
|
|
SetPSPAxis(axis.deviceId, 'X', -value, CTRL_STICK_LEFT);
|
2021-07-08 19:30:23 +00:00
|
|
|
break;
|
|
|
|
case VIRTKEY_AXIS_X_MAX:
|
2022-11-23 11:22:59 +00:00
|
|
|
SetPSPAxis(axis.deviceId, 'X', value, CTRL_STICK_LEFT);
|
2021-07-08 19:30:23 +00:00
|
|
|
break;
|
|
|
|
case VIRTKEY_AXIS_Y_MIN:
|
2022-11-23 11:22:59 +00:00
|
|
|
SetPSPAxis(axis.deviceId, 'Y', -value, CTRL_STICK_LEFT);
|
2021-07-08 19:30:23 +00:00
|
|
|
break;
|
|
|
|
case VIRTKEY_AXIS_Y_MAX:
|
2022-11-23 11:22:59 +00:00
|
|
|
SetPSPAxis(axis.deviceId, 'Y', value, CTRL_STICK_LEFT);
|
2021-07-08 19:30:23 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIRTKEY_AXIS_RIGHT_X_MIN:
|
2022-11-23 11:22:59 +00:00
|
|
|
SetPSPAxis(axis.deviceId, 'X', -value, CTRL_STICK_RIGHT);
|
2021-07-08 19:30:23 +00:00
|
|
|
break;
|
|
|
|
case VIRTKEY_AXIS_RIGHT_X_MAX:
|
2022-11-23 11:22:59 +00:00
|
|
|
SetPSPAxis(axis.deviceId, 'X', value, CTRL_STICK_RIGHT);
|
2021-07-08 19:30:23 +00:00
|
|
|
break;
|
|
|
|
case VIRTKEY_AXIS_RIGHT_Y_MIN:
|
2022-11-23 11:22:59 +00:00
|
|
|
SetPSPAxis(axis.deviceId, 'Y', -value, CTRL_STICK_RIGHT);
|
2021-07-08 19:30:23 +00:00
|
|
|
break;
|
|
|
|
case VIRTKEY_AXIS_RIGHT_Y_MAX:
|
2022-11-23 11:22:59 +00:00
|
|
|
SetPSPAxis(axis.deviceId, 'Y', value, CTRL_STICK_RIGHT);
|
2021-07-08 19:30:23 +00:00
|
|
|
break;
|
2022-07-04 20:10:42 +00:00
|
|
|
|
|
|
|
case VIRTKEY_SPEED_ANALOG:
|
|
|
|
ProcessAnalogSpeed(axis, false);
|
|
|
|
break;
|
2021-07-08 19:30:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<int> resultsOpposite;
|
2023-03-29 09:59:31 +00:00
|
|
|
KeyMap::InputMappingToPspButton(InputMapping(axis.deviceId, axis.axisId, -direction), &resultsOpposite);
|
2021-07-08 19:30:23 +00:00
|
|
|
|
2022-07-04 20:10:42 +00:00
|
|
|
for (int result : resultsOpposite) {
|
|
|
|
if (result == VIRTKEY_SPEED_ANALOG)
|
|
|
|
ProcessAnalogSpeed(axis, true);
|
|
|
|
}
|
|
|
|
|
2021-07-08 19:30:23 +00:00
|
|
|
int axisState = 0;
|
2023-03-29 08:21:49 +00:00
|
|
|
float threshold = GetDeviceAxisThreshold(axis.deviceId);
|
2021-07-08 19:30:23 +00:00
|
|
|
if (direction == 1 && axis.value >= threshold) {
|
|
|
|
axisState = 1;
|
|
|
|
} else if (direction == -1 && axis.value <= -threshold) {
|
|
|
|
axisState = -1;
|
|
|
|
} else {
|
|
|
|
axisState = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (axisState != axisState_[axis.axisId]) {
|
|
|
|
axisState_[axis.axisId] = axisState;
|
|
|
|
if (axisState != 0) {
|
|
|
|
for (size_t i = 0; i < results.size(); i++) {
|
|
|
|
if (!IsAnalogStickKey(results[i]))
|
2023-03-26 16:04:40 +00:00
|
|
|
SetPSPKey(axis.deviceId, results[i], KEY_DOWN);
|
2021-07-08 19:30:23 +00:00
|
|
|
}
|
|
|
|
// 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())
|
2023-03-26 16:04:40 +00:00
|
|
|
SetPSPKey(axis.deviceId, resultsOpposite[i], KEY_UP);
|
2021-07-08 19:30:23 +00:00
|
|
|
}
|
|
|
|
} 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]))
|
2023-03-26 16:04:40 +00:00
|
|
|
SetPSPKey(axis.deviceId, results[i], KEY_UP);
|
2021-07-08 19:30:23 +00:00
|
|
|
}
|
|
|
|
for (size_t i = 0; i < resultsOpposite.size(); i++) {
|
|
|
|
if (!IsAnalogStickKey(resultsOpposite[i]))
|
2023-03-26 16:04:40 +00:00
|
|
|
SetPSPKey(axis.deviceId, resultsOpposite[i], KEY_UP);
|
2021-07-08 19:30:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-07-04 20:10:42 +00:00
|
|
|
|
|
|
|
void ControlMapper::ProcessAnalogSpeed(const AxisInput &axis, bool opposite) {
|
2022-07-06 02:37:56 +00:00
|
|
|
static constexpr float DEADZONE_THRESHOLD = 0.15f;
|
|
|
|
static constexpr float DEADZONE_SCALE = 1.0f / (1.0f - DEADZONE_THRESHOLD);
|
|
|
|
|
2022-07-04 20:10:42 +00:00
|
|
|
FPSLimit &limitMode = PSP_CoreParameter().fpsLimit;
|
|
|
|
// If we're using an alternate speed already, let that win.
|
|
|
|
if (limitMode != FPSLimit::NORMAL && limitMode != FPSLimit::ANALOG)
|
|
|
|
return;
|
|
|
|
// Don't even try if the limit is invalid.
|
|
|
|
if (g_Config.iAnalogFpsLimit <= 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
AnalogFpsMode mode = (AnalogFpsMode)g_Config.iAnalogFpsMode;
|
|
|
|
float value = axis.value;
|
|
|
|
if (mode == AnalogFpsMode::AUTO) {
|
|
|
|
// TODO: Consider the pad name for better auto? KeyMap::PadName(axis.deviceId);
|
|
|
|
switch (axis.axisId) {
|
|
|
|
case JOYSTICK_AXIS_X:
|
|
|
|
case JOYSTICK_AXIS_Y:
|
|
|
|
case JOYSTICK_AXIS_Z:
|
|
|
|
case JOYSTICK_AXIS_RX:
|
|
|
|
case JOYSTICK_AXIS_RY:
|
|
|
|
case JOYSTICK_AXIS_RZ:
|
|
|
|
// These, at least on directinput, can be used for triggers that go from mapped to opposite.
|
2022-07-05 23:07:09 +00:00
|
|
|
mode = AnalogFpsMode::MAPPED_DIR_TO_OPPOSITE_DIR;
|
2022-07-04 20:10:42 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
// Other axises probably don't go from negative to positive.
|
|
|
|
mode = AnalogFpsMode::MAPPED_DIRECTION;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Okay, now let's map it as appropriate.
|
|
|
|
if (mode == AnalogFpsMode::MAPPED_DIRECTION) {
|
|
|
|
value = fabsf(value);
|
2022-07-05 23:07:09 +00:00
|
|
|
// Clamp to 0 in this case if we're processing the opposite direction.
|
2022-07-04 20:10:42 +00:00
|
|
|
if (opposite)
|
2022-07-05 23:07:09 +00:00
|
|
|
value = 0.0f;
|
|
|
|
} else if (mode == AnalogFpsMode::MAPPED_DIR_TO_OPPOSITE_DIR) {
|
2022-07-04 20:10:42 +00:00
|
|
|
value = fabsf(value);
|
|
|
|
if (opposite)
|
|
|
|
value = -value;
|
|
|
|
value = 0.5f - value * 0.5f;
|
|
|
|
}
|
|
|
|
|
2022-07-06 02:37:56 +00:00
|
|
|
// Apply a small deadzone (against the resting position.)
|
|
|
|
value = std::max(0.0f, (value - DEADZONE_THRESHOLD) * DEADZONE_SCALE);
|
|
|
|
|
2022-07-04 20:10:42 +00:00
|
|
|
// If target is above 60, value is how much to speed up over 60. Otherwise, it's how much slower.
|
|
|
|
// So normalize the target.
|
|
|
|
int target = g_Config.iAnalogFpsLimit - 60;
|
|
|
|
PSP_CoreParameter().analogFpsLimit = 60 + (int)(target * value);
|
|
|
|
|
|
|
|
// If we've reset back to normal, turn it off.
|
|
|
|
limitMode = PSP_CoreParameter().analogFpsLimit == 60 ? FPSLimit::NORMAL : FPSLimit::ANALOG;
|
|
|
|
}
|