Make reverse mapping lookup work for the simple PSP buttons.
This commit is contained in:
parent
2814668cf5
commit
38f4cc4cc9
12 changed files with 129 additions and 64 deletions
|
@ -183,7 +183,6 @@ struct AxisInput {
|
|||
int deviceId;
|
||||
int axisId; // Android axis Ids are the canonical ones.
|
||||
float value;
|
||||
int flags;
|
||||
};
|
||||
|
||||
// Is there a nicer place for this stuff? It's here to avoid dozens of linking errors in UnitTest..
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
#include "Common/VR/VRMath.h"
|
||||
#include "Common/VR/VRRenderer.h"
|
||||
|
||||
#include "Common/Input/InputState.h"
|
||||
#include "Common/Input/KeyCodes.h"
|
||||
|
||||
#include "Common/GPU/Vulkan/VulkanContext.h"
|
||||
|
||||
#include "Common/Math/lin/matrix4x4.h"
|
||||
|
|
|
@ -20,6 +20,11 @@ static float MapAxisValue(float v) {
|
|||
return sign * Clamp(invDeadzone + (abs(v) - deadzone) / (1.0f - deadzone) * (sensitivity - invDeadzone), 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
// TODO: Possibly make these configurable?
|
||||
float GetDeviceAxisThreshold(int device) {
|
||||
return device == DEVICE_ID_MOUSE ? AXIS_BIND_THRESHOLD_MOUSE : AXIS_BIND_THRESHOLD;
|
||||
}
|
||||
|
||||
void ConvertAnalogStick(float &x, float &y) {
|
||||
const bool isCircular = g_Config.bAnalogIsCircular;
|
||||
|
||||
|
@ -97,21 +102,89 @@ void ControlMapper::SetPSPAxis(int device, char axis, float value, int stick) {
|
|||
}
|
||||
}
|
||||
|
||||
bool ControlMapper::Key(const KeyInput &key, bool *pauseTrigger) {
|
||||
std::vector<int> pspKeys;
|
||||
KeyMap::InputMappingToPspButton(InputMapping(key.deviceId, key.keyCode), &pspKeys);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (pspKeys.size() && (key.flags & KEY_IS_REPEAT)) {
|
||||
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.
|
||||
|
||||
// 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) {
|
||||
// Claim that we handled this. Prevents volume key repeats from popping up the volume control on Android.
|
||||
return true;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < pspKeys.size(); i++) {
|
||||
SetPSPKey(key.deviceId, pspKeys[i], key.flags);
|
||||
InputMapping mapping(key.deviceId, key.keyCode);
|
||||
|
||||
if (key.flags & KEY_DOWN) {
|
||||
curInput_[mapping] = 1.0f;
|
||||
} else if (key.flags & KEY_UP) {
|
||||
curInput_.erase(mapping);
|
||||
}
|
||||
|
||||
std::vector<int> pspKeys;
|
||||
KeyMap::InputMappingToPspButton(InputMapping(key.deviceId, key.keyCode), &pspKeys);
|
||||
DEBUG_LOG(SYSTEM, "Key: %d DeviceId: %d", key.keyCode, key.deviceId);
|
||||
|
||||
if (!pspKeys.size() || key.deviceId == DEVICE_ID_DEFAULT) {
|
||||
if ((key.flags & KEY_DOWN) && key.keyCode == NKCODE_BACK) {
|
||||
*pauseTrigger = true;
|
||||
|
@ -119,18 +192,22 @@ bool ControlMapper::Key(const KeyInput &key, bool *pauseTrigger) {
|
|||
}
|
||||
}
|
||||
|
||||
return pspKeys.size() > 0;
|
||||
return UpdatePSPState();
|
||||
}
|
||||
|
||||
void ControlMapper::Axis(const AxisInput &axis) {
|
||||
if (axis.value > 0) {
|
||||
ProcessAxis(axis, 1);
|
||||
InputMapping mapping(axis.deviceId, axis.axisId, 1);
|
||||
curInput_[mapping] = axis.value;
|
||||
} else if (axis.value < 0) {
|
||||
ProcessAxis(axis, -1);
|
||||
} else if (axis.value == 0) {
|
||||
InputMapping mapping(axis.deviceId, axis.axisId, -1);
|
||||
curInput_[mapping] = axis.value;
|
||||
} else if (axis.value == 0.0f) { // Threshold?
|
||||
// Both directions! Prevents sticking for digital input devices that are axises (like HAT)
|
||||
ProcessAxis(axis, 1);
|
||||
ProcessAxis(axis, -1);
|
||||
InputMapping mappingPositive(axis.deviceId, axis.axisId, -1);
|
||||
InputMapping mappingNegative(axis.deviceId, axis.axisId, -1);
|
||||
curInput_[mappingPositive] = 0.0f;
|
||||
curInput_[mappingNegative] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,17 +244,6 @@ inline bool IsAnalogStickKey(int key) {
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
|
@ -199,6 +265,7 @@ void ControlMapper::PSPKey(int deviceId, int pspKeyCode, int flags) {
|
|||
}
|
||||
|
||||
void ControlMapper::SetPSPKey(int deviceId, int pspKeyCode, int flags) {
|
||||
/*
|
||||
if (pspKeyCode >= VIRTKEY_FIRST) {
|
||||
int vk = pspKeyCode - VIRTKEY_FIRST;
|
||||
if (flags & KEY_DOWN) {
|
||||
|
@ -210,29 +277,13 @@ void ControlMapper::SetPSPKey(int deviceId, int pspKeyCode, int flags) {
|
|||
onVKey(deviceId, pspKeyCode, false);
|
||||
}
|
||||
} else {
|
||||
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 < rotations; i++) {
|
||||
pspKeyCode = RotatePSPKeyCode(pspKeyCode);
|
||||
}
|
||||
|
||||
// INFO_LOG(SYSTEM, "pspKey %d %d", pspKeyCode, flags);
|
||||
if (flags & KEY_DOWN)
|
||||
setPSPButtonState_(pspKeyCode, true);
|
||||
if (flags & KEY_UP)
|
||||
setPSPButtonState_(pspKeyCode, false);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void ControlMapper::onVKey(int deviceId, int vkey, bool down) {
|
||||
|
@ -343,7 +394,7 @@ void ControlMapper::ProcessAxis(const AxisInput &axis, int direction) {
|
|||
}
|
||||
|
||||
int axisState = 0;
|
||||
float threshold = axis.deviceId == DEVICE_ID_MOUSE ? AXIS_BIND_THRESHOLD_MOUSE : AXIS_BIND_THRESHOLD;
|
||||
float threshold = GetDeviceAxisThreshold(axis.deviceId);
|
||||
if (direction == 1 && axis.value >= threshold) {
|
||||
axisState = 1;
|
||||
} else if (direction == -1 && axis.value <= -threshold) {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "Core/KeyMap.h"
|
||||
|
||||
#include <functional>
|
||||
#include <cstring>
|
||||
|
||||
// Utilities for mapping input events to PSP inputs and virtual keys.
|
||||
// Main use is of course from EmuScreen.cpp, but also useful from control settings etc.
|
||||
|
@ -11,6 +12,17 @@
|
|||
// At some point I want to refactor this from using callbacks to simply providing lists of events.
|
||||
// Still it won't be able to be completely stateless due to the 2-D processing of analog sticks.
|
||||
|
||||
// Unified representation. Might spread across the code base later.
|
||||
struct ControlInputKey {
|
||||
int direction; // 0 if key, 1 or -1 if axis.
|
||||
int deviceId;
|
||||
int controlId; // key or axis.
|
||||
|
||||
bool operator < (const ControlInputKey &other) const {
|
||||
return memcmp(this, &other, sizeof(*this)) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
class ControlMapper {
|
||||
public:
|
||||
void Update();
|
||||
|
@ -34,6 +46,8 @@ public:
|
|||
void SetRawCallback(std::function<void(int, float, float)> setRawAnalog);
|
||||
|
||||
private:
|
||||
bool UpdatePSPState();
|
||||
|
||||
void ProcessAxis(const AxisInput &axis, int direction);
|
||||
void SetVKeyAnalog(int deviceId, char axis, int stick, int virtualKeyMin, int virtualKeyMax, bool setZero = true);
|
||||
|
||||
|
@ -57,6 +71,8 @@ private:
|
|||
bool autoRotatingAnalogCW_ = false;
|
||||
bool autoRotatingAnalogCCW_ = false;
|
||||
|
||||
std::map<InputMapping, float> curInput_;
|
||||
|
||||
// Callbacks
|
||||
std::function<void(int, bool)> onVKey_;
|
||||
std::function<void(uint32_t, uint32_t)> setAllPSPButtonStates_;
|
||||
|
|
|
@ -192,6 +192,7 @@ void WebSocketInputState::ButtonsPress(DebuggerRequest &req) {
|
|||
}
|
||||
press.button = info->second;
|
||||
|
||||
// TODO: Route into the control mapper's PSPKey function instead.
|
||||
__CtrlButtonDown(press.button);
|
||||
pressTickets_.push_back(press);
|
||||
}
|
||||
|
@ -205,6 +206,7 @@ void WebSocketInputState::Broadcast(net::WebSocketServer *ws) {
|
|||
for (PressInfo &press : pressTickets_) {
|
||||
press.duration--;
|
||||
if (press.duration == -1) {
|
||||
// TODO: Route into the control mapper's PSPKey function instead.
|
||||
__CtrlButtonUp(press.button);
|
||||
ws->Send(press.Event());
|
||||
}
|
||||
|
@ -254,6 +256,7 @@ void WebSocketInputState::AnalogSend(DebuggerRequest &req) {
|
|||
if (!AnalogValue(req, &x, "x") || !AnalogValue(req, &y, "y"))
|
||||
return;
|
||||
|
||||
// TODO: Route into the control mapper's PSPKey function or similar instead.
|
||||
__CtrlSetAnalogXY(stick == "left" ? CTRL_STICK_LEFT : CTRL_STICK_RIGHT, x, y);
|
||||
|
||||
req.Respond();
|
||||
|
|
|
@ -70,7 +70,8 @@ void __CtrlShutdown();
|
|||
void __CtrlButtonDown(u32 buttonBit);
|
||||
// Call this whenever a button is released. Similar to __CtrlButtonDown().
|
||||
void __CtrlButtonUp(u32 buttonBit);
|
||||
// To be used by the new mapping code.
|
||||
// Sets the full state. Used by the new control mapper. The above two functions
|
||||
// should go away over time.
|
||||
void __CtrlSetAllButtons(u32 bitsToSet, u32 bitsToClear);
|
||||
|
||||
// Call this to set the position of an analog stick, ideally when it changes.
|
||||
|
|
|
@ -43,7 +43,7 @@ std::set<std::string> g_seenPads;
|
|||
std::map<int, std::string> g_padNames;
|
||||
std::set<int> g_seenDeviceIds;
|
||||
|
||||
bool g_swapped_keys = false;
|
||||
bool g_swapDpadWithLStick = false;
|
||||
|
||||
// TODO: This is such a mess...
|
||||
void UpdateNativeMenuKeys() {
|
||||
|
@ -472,8 +472,8 @@ std::vector<KeyMap_IntStrPair> GetMappableKeys() {
|
|||
return temp;
|
||||
}
|
||||
|
||||
int CheckAxisSwap(int btn) {
|
||||
if (g_swapped_keys) {
|
||||
inline int CheckAxisSwap(int btn) {
|
||||
if (g_swapDpadWithLStick) {
|
||||
switch (btn) {
|
||||
case CTRL_UP: btn = VIRTKEY_AXIS_Y_MAX; break;
|
||||
case VIRTKEY_AXIS_Y_MAX: btn = CTRL_UP; break;
|
||||
|
@ -488,19 +488,18 @@ int CheckAxisSwap(int btn) {
|
|||
return btn;
|
||||
}
|
||||
|
||||
static bool FindKeyMapping(const InputMapping &mapping, std::vector<int> *pspButtons) {
|
||||
bool InputMappingToPspButton(const InputMapping &mapping, std::vector<int> *pspButtons) {
|
||||
bool found = false;
|
||||
for (auto iter = g_controllerMap.begin(); iter != g_controllerMap.end(); ++iter) {
|
||||
for (auto iter2 = iter->second.begin(); iter2 != iter->second.end(); ++iter2) {
|
||||
if (*iter2 == mapping) {
|
||||
if (pspButtons)
|
||||
pspButtons->push_back(CheckAxisSwap(iter->first));
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pspButtons->size() > 0;
|
||||
}
|
||||
|
||||
bool InputMappingToPspButton(const InputMapping &mapping, std::vector<int> *pspButtons) {
|
||||
return FindKeyMapping(mapping, pspButtons);
|
||||
return found;
|
||||
}
|
||||
|
||||
bool InputMappingsFromPspButton(int btn, std::vector<InputMapping> *mappings, bool ignoreMouse) {
|
||||
|
@ -774,7 +773,7 @@ std::string PadName(int deviceId) {
|
|||
|
||||
// Swap direction buttons and left analog axis
|
||||
void SwapAxis() {
|
||||
g_swapped_keys = !g_swapped_keys;
|
||||
g_swapDpadWithLStick = !g_swapDpadWithLStick;
|
||||
}
|
||||
|
||||
bool HasChanged(int &prevGeneration) {
|
||||
|
|
|
@ -129,6 +129,8 @@ inline float clamp(float f) {
|
|||
return f;
|
||||
}
|
||||
|
||||
// TODO: Instead of __Ctrl, route data into the ControlMapper.
|
||||
|
||||
void GenerateAnalogStickEvent(float tiltX, float tiltY) {
|
||||
__CtrlSetAnalogXY(CTRL_STICK_LEFT, clamp(tiltX), clamp(tiltY));
|
||||
}
|
||||
|
|
|
@ -725,7 +725,6 @@ void MainUI::updateAccelerometer() {
|
|||
if (reading) {
|
||||
AxisInput axis;
|
||||
axis.deviceId = DEVICE_ID_ACCELEROMETER;
|
||||
axis.flags = 0;
|
||||
|
||||
axis.axisId = JOYSTICK_AXIS_ACCELEROMETER_X;
|
||||
axis.value = reading->x();
|
||||
|
|
|
@ -187,7 +187,6 @@ void SDLJoystick::ProcessInput(SDL_Event &event){
|
|||
if (axis.value > 1.0f) axis.value = 1.0f;
|
||||
if (axis.value < -1.0f) axis.value = -1.0f;
|
||||
axis.deviceId = DEVICE_ID_PAD_0 + getDeviceIndex(event.caxis.which);
|
||||
axis.flags = 0;
|
||||
NativeAxis(axis);
|
||||
break;
|
||||
case SDL_CONTROLLERDEVICEREMOVED:
|
||||
|
|
|
@ -1221,7 +1221,6 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_accelerometer(JNIEnv *,
|
|||
|
||||
AxisInput axis;
|
||||
axis.deviceId = DEVICE_ID_ACCELEROMETER;
|
||||
axis.flags = 0;
|
||||
|
||||
axis.axisId = JOYSTICK_AXIS_ACCELEROMETER_X;
|
||||
axis.value = x;
|
||||
|
|
|
@ -460,7 +460,6 @@ int ToTouchID(UITouch *uiTouch, bool allowAllocate) {
|
|||
break;
|
||||
}
|
||||
axis.deviceId = DEVICE_ID_PAD_0;
|
||||
axis.flags = 0;
|
||||
NativeAxis(axis);
|
||||
} else {
|
||||
KeyInput key;
|
||||
|
@ -530,7 +529,6 @@ int ToTouchID(UITouch *uiTouch, bool allowAllocate) {
|
|||
break;
|
||||
}
|
||||
axis.deviceId = DEVICE_ID_PAD_0;
|
||||
axis.flags = 0;
|
||||
NativeAxis(axis);
|
||||
} else {
|
||||
KeyInput key;
|
||||
|
@ -687,7 +685,6 @@ int ToTouchID(UITouch *uiTouch, bool allowAllocate) {
|
|||
extendedProfile.leftThumbstick.xAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) {
|
||||
AxisInput axisInput;
|
||||
axisInput.deviceId = DEVICE_ID_PAD_0;
|
||||
axisInput.flags = 0;
|
||||
axisInput.axisId = JOYSTICK_AXIS_X;
|
||||
axisInput.value = value;
|
||||
NativeAxis(axisInput);
|
||||
|
@ -696,7 +693,6 @@ int ToTouchID(UITouch *uiTouch, bool allowAllocate) {
|
|||
extendedProfile.leftThumbstick.yAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) {
|
||||
AxisInput axisInput;
|
||||
axisInput.deviceId = DEVICE_ID_PAD_0;
|
||||
axisInput.flags = 0;
|
||||
axisInput.axisId = JOYSTICK_AXIS_Y;
|
||||
axisInput.value = -value;
|
||||
NativeAxis(axisInput);
|
||||
|
@ -706,7 +702,6 @@ int ToTouchID(UITouch *uiTouch, bool allowAllocate) {
|
|||
extendedProfile.rightThumbstick.xAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) {
|
||||
AxisInput axisInput;
|
||||
axisInput.deviceId = DEVICE_ID_PAD_0;
|
||||
axisInput.flags = 0;
|
||||
axisInput.axisId = JOYSTICK_AXIS_Z;
|
||||
axisInput.value = value;
|
||||
NativeAxis(axisInput);
|
||||
|
@ -715,7 +710,6 @@ int ToTouchID(UITouch *uiTouch, bool allowAllocate) {
|
|||
extendedProfile.rightThumbstick.yAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) {
|
||||
AxisInput axisInput;
|
||||
axisInput.deviceId = DEVICE_ID_PAD_0;
|
||||
axisInput.flags = 0;
|
||||
axisInput.axisId = JOYSTICK_AXIS_RZ;
|
||||
axisInput.value = -value;
|
||||
NativeAxis(axisInput);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue