diff --git a/Common/Input/InputState.h b/Common/Input/InputState.h index 5de44996ed..1c7181572d 100644 --- a/Common/Input/InputState.h +++ b/Common/Input/InputState.h @@ -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.. diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 9e00e75aa4..30df54352c 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -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" diff --git a/Core/ControlMapper.cpp b/Core/ControlMapper.cpp index 3cef1079f1..d1cb5d223c 100644 --- a/Core/ControlMapper.cpp +++ b/Core/ControlMapper.cpp @@ -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 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 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 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) { diff --git a/Core/ControlMapper.h b/Core/ControlMapper.h index 74783f0a7e..27b6cd2265 100644 --- a/Core/ControlMapper.h +++ b/Core/ControlMapper.h @@ -4,6 +4,7 @@ #include "Core/KeyMap.h" #include +#include // 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 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 curInput_; + // Callbacks std::function onVKey_; std::function setAllPSPButtonStates_; diff --git a/Core/Debugger/WebSocket/InputSubscriber.cpp b/Core/Debugger/WebSocket/InputSubscriber.cpp index fd0f478e76..49db4758ca 100644 --- a/Core/Debugger/WebSocket/InputSubscriber.cpp +++ b/Core/Debugger/WebSocket/InputSubscriber.cpp @@ -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(); diff --git a/Core/HLE/sceCtrl.h b/Core/HLE/sceCtrl.h index 8307247e17..c163f21744 100644 --- a/Core/HLE/sceCtrl.h +++ b/Core/HLE/sceCtrl.h @@ -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. diff --git a/Core/KeyMap.cpp b/Core/KeyMap.cpp index 21cc22554e..f303ab3978 100644 --- a/Core/KeyMap.cpp +++ b/Core/KeyMap.cpp @@ -43,7 +43,7 @@ std::set g_seenPads; std::map g_padNames; std::set 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 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 *pspButtons) { +bool InputMappingToPspButton(const InputMapping &mapping, std::vector *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) { - pspButtons->push_back(CheckAxisSwap(iter->first)); + if (pspButtons) + pspButtons->push_back(CheckAxisSwap(iter->first)); + found = true; } } } - return pspButtons->size() > 0; -} - -bool InputMappingToPspButton(const InputMapping &mapping, std::vector *pspButtons) { - return FindKeyMapping(mapping, pspButtons); + return found; } bool InputMappingsFromPspButton(int btn, std::vector *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) { diff --git a/Core/TiltEventProcessor.cpp b/Core/TiltEventProcessor.cpp index 5d142955a8..716fee429e 100644 --- a/Core/TiltEventProcessor.cpp +++ b/Core/TiltEventProcessor.cpp @@ -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)); } diff --git a/Qt/QtMain.cpp b/Qt/QtMain.cpp index 411f26e1fd..17edeefb74 100644 --- a/Qt/QtMain.cpp +++ b/Qt/QtMain.cpp @@ -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(); diff --git a/SDL/SDLJoystick.cpp b/SDL/SDLJoystick.cpp index 59906f4a3e..2f6b47171d 100644 --- a/SDL/SDLJoystick.cpp +++ b/SDL/SDLJoystick.cpp @@ -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: diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 8dfdf662b9..78e7a100bc 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -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; diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 4535b39a80..359eda075b 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -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);