From 536c050943e9103d63769c5b46b69e2711d06a50 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 4 Jul 2022 12:49:38 -0700 Subject: [PATCH 1/7] Core: Track names of connected pad devices. Rather than just that it's a pad. This tries to get the identifier if possible. --- Core/KeyMap.cpp | 4 ++- Core/KeyMap.h | 2 +- SDL/SDLJoystick.cpp | 15 ++++++++-- UI/NativeApp.cpp | 7 +++-- Windows/DinputDevice.cpp | 8 +++-- Windows/XinputDevice.cpp | 30 +++++++++++++++---- .../org/ppsspp/ppsspp/InputDeviceState.java | 1 + ios/ViewController.mm | 7 +++++ 8 files changed, 60 insertions(+), 14 deletions(-) diff --git a/Core/KeyMap.cpp b/Core/KeyMap.cpp index 2e63fd70d44d..1456426ae28a 100644 --- a/Core/KeyMap.cpp +++ b/Core/KeyMap.cpp @@ -40,6 +40,7 @@ KeyMapping g_controllerMap; // Incremented on modification, so we know when to update menus. int g_controllerMapGeneration = 0; std::set g_seenPads; +std::map g_padNames; std::set g_seenDeviceIds; bool g_swapped_keys = false; @@ -762,8 +763,9 @@ bool HasBuiltinController(const std::string &name) { return IsOuya(name) || IsXperiaPlay(name) || IsNvidiaShield(name) || IsMOQII7S(name) || IsRetroid(name); } -void NotifyPadConnected(const std::string &name) { +void NotifyPadConnected(int deviceId, const std::string &name) { g_seenPads.insert(name); + g_padNames[deviceId] = name; } void AutoConfForPad(const std::string &name) { diff --git a/Core/KeyMap.h b/Core/KeyMap.h index 4c0930f5bd7e..78f2b95987a8 100644 --- a/Core/KeyMap.h +++ b/Core/KeyMap.h @@ -153,7 +153,7 @@ namespace KeyMap { void SwapAxis(); void UpdateNativeMenuKeys(); - void NotifyPadConnected(const std::string &name); + void NotifyPadConnected(int deviceId, const std::string &name); bool IsNvidiaShield(const std::string &name); bool IsNvidiaShieldTV(const std::string &name); bool IsXperiaPlay(const std::string &name); diff --git a/SDL/SDLJoystick.cpp b/SDL/SDLJoystick.cpp index c129ac821a74..0a53ef80b7d7 100644 --- a/SDL/SDLJoystick.cpp +++ b/SDL/SDLJoystick.cpp @@ -8,6 +8,7 @@ #include "Common/System/System.h" #include "Core/Config.h" +#include "Core/KeyMap.h" #include "SDL/SDLJoystick.h" using namespace std; @@ -54,11 +55,12 @@ void SDLJoystick::setUpControllers() { } void SDLJoystick::setUpController(int deviceIndex) { + static constexpr int cbGUID = 33; + char pszGUID[cbGUID]; + if (!SDL_IsGameController(deviceIndex)) { cout << "Control pad device " << deviceIndex << " not supported by SDL game controller database, attempting to create default mapping..." << endl; - int cbGUID = 33; - char pszGUID[cbGUID]; - SDL_Joystick* joystick = SDL_JoystickOpen(deviceIndex); + SDL_Joystick *joystick = SDL_JoystickOpen(deviceIndex); if (joystick) { SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick), pszGUID, cbGUID); // create default mapping - this is the PS3 dual shock mapping @@ -73,6 +75,12 @@ void SDLJoystick::setUpController(int deviceIndex) { } else { cout << "Failed to get joystick identifier. Read-only device? Control pad device " + std::to_string(deviceIndex) << endl; } + } else { + SDL_Joystick *joystick = SDL_JoystickOpen(deviceIndex); + if (joystick) { + SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick), pszGUID, cbGUID); + SDL_JoystickClose(joystick); + } } SDL_GameController *controller = SDL_GameControllerOpen(deviceIndex); if (controller) { @@ -80,6 +88,7 @@ void SDLJoystick::setUpController(int deviceIndex) { controllers.push_back(controller); controllerDeviceMap[SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller))] = deviceIndex; cout << "found control pad: " << SDL_GameControllerName(controller) << ", loading mapping: "; + KeyMap::NotifyPadConnected(deviceIndex, std::string(pszGUID) + ": " + SDL_GameControllerName(controller)); auto mapping = SDL_GameControllerMapping(controller); if (mapping == NULL) { //cout << "FAILED" << endl; diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index f6fe5d729803..cc1e08ff4d0a 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -1176,8 +1176,12 @@ void NativeRender(GraphicsContext *graphicsContext) { } void HandleGlobalMessage(const std::string &msg, const std::string &value) { + int nextInputDeviceID = -1; + if (msg == "inputDeviceConnectedID") { + nextInputDeviceID = parseLong(value); + } if (msg == "inputDeviceConnected") { - KeyMap::NotifyPadConnected(value); + KeyMap::NotifyPadConnected(nextInputDeviceID, value); } if (msg == "bgImage_updated") { if (!value.empty()) { @@ -1419,7 +1423,6 @@ bool NativeAxis(const AxisInput &axis) { } void NativeMessageReceived(const char *message, const char *value) { - // We can only have one message queued. std::lock_guard lock(pendingMutex); PendingMessage pendingMessage; pendingMessage.msg = message; diff --git a/Windows/DinputDevice.cpp b/Windows/DinputDevice.cpp index bba15bec56e9..75cb9893340d 100644 --- a/Windows/DinputDevice.cpp +++ b/Windows/DinputDevice.cpp @@ -23,6 +23,7 @@ #include "Common/Input/InputState.h" #include "Common/Input/KeyCodes.h" +#include "Common/StringUtils.h" #include "Common/System/NativeApp.h" #include "Core/Config.h" #include "Core/HLE/sceCtrl.h" @@ -57,8 +58,6 @@ static const int dinput_buttons[] = { NKCODE_BUTTON_16, }; -static float NormalizedDeadzoneFilter(short value); - #define DIFF (JOY_POVRIGHT - JOY_POVFORWARD) / 2 #define JOY_POVFORWARD_RIGHT JOY_POVFORWARD + DIFF #define JOY_POVRIGHT_BACKWARD JOY_POVRIGHT + DIFF @@ -152,6 +151,11 @@ DinputDevice::DinputDevice(int devnum) { return; } + wchar_t guid[64]; + if (StringFromGUID2(devices.at(devnum).guidProduct, guid, ARRAY_SIZE(guid)) != 0) { + KeyMap::NotifyPadConnected(DEVICE_ID_PAD_0 + pDevNum, StringFromFormat("%S: %S", devices.at(devnum).tszProductName, guid)); + } + if (FAILED(pJoystick->SetDataFormat(&c_dfDIJoystick2))) { pJoystick->Release(); pJoystick = NULL; diff --git a/Windows/XinputDevice.cpp b/Windows/XinputDevice.cpp index 6d708167484a..5dd00c165c74 100644 --- a/Windows/XinputDevice.cpp +++ b/Windows/XinputDevice.cpp @@ -4,13 +4,14 @@ #include #include "Common/System/NativeApp.h" -#include "Core/Config.h" #include "Common/CommonWindows.h" #include "Common/Log.h" +#include "Common/StringUtils.h" #include "Common/TimeUtil.h" #include "Common/Input/InputState.h" #include "Common/Input/KeyCodes.h" #include "XinputDevice.h" +#include "Core/Config.h" #include "Core/Core.h" #include "Core/KeyMap.h" #include "Core/HLE/sceCtrl.h" @@ -21,11 +22,21 @@ static double newVibrationTime = 0.0; #if !PPSSPP_PLATFORM(UWP) +struct XINPUT_CAPABILITIES_EX { + XINPUT_CAPABILITIES Capabilities; + WORD vendorId; + WORD productId; + WORD revisionId; + DWORD a4; //unknown +}; + typedef DWORD (WINAPI *XInputGetState_t) (DWORD dwUserIndex, XINPUT_STATE* pState); typedef DWORD (WINAPI *XInputSetState_t) (DWORD dwUserIndex, XINPUT_VIBRATION* pVibration); +typedef DWORD (WINAPI *XInputGetCapabilitiesEx_t) (DWORD unknown, DWORD dwUserIndex, DWORD flags, XINPUT_CAPABILITIES_EX *pCapabilities); static XInputGetState_t PPSSPP_XInputGetState = nullptr; static XInputSetState_t PPSSPP_XInputSetState = nullptr; +static XInputGetCapabilitiesEx_t PPSSPP_XInputGetCapabilitiesEx = nullptr; static DWORD PPSSPP_XInputVersion = 0; static HMODULE s_pXInputDLL = 0; static int s_XInputDLLRefCount = 0; @@ -83,6 +94,10 @@ static int LoadXInputDLL() { return -1; } + if (PPSSPP_XInputVersion >= ((1 << 16) | 4)) { + PPSSPP_XInputGetCapabilitiesEx = (XInputGetCapabilitiesEx_t)GetProcAddress((HMODULE)s_pXInputDLL, (LPCSTR)108); + } + return 0; } @@ -187,10 +202,15 @@ int XinputDevice::UpdateState() { } void XinputDevice::UpdatePad(int pad, const XINPUT_STATE &state, XINPUT_VIBRATION &vibration) { - static bool notified = false; - if (!notified) { - notified = true; - KeyMap::NotifyPadConnected("Xbox 360 Pad"); + static bool notified[XUSER_MAX_COUNT]{}; + if (!notified[pad]) { + notified[pad] = true; + XINPUT_CAPABILITIES_EX caps; + if (PPSSPP_XInputGetCapabilitiesEx != nullptr && PPSSPP_XInputGetCapabilitiesEx(1, pad, 0, &caps) == ERROR_SUCCESS) { + KeyMap::NotifyPadConnected(DEVICE_ID_XINPUT_0 + pad, StringFromFormat("Xbox 360 Pad: %d/%d", caps.vendorId, caps.productId)); + } else { + KeyMap::NotifyPadConnected(DEVICE_ID_XINPUT_0 + pad, "Xbox 360 Pad"); + } } ApplyButtons(pad, state); ApplyVibration(pad, vibration); diff --git a/android/src/org/ppsspp/ppsspp/InputDeviceState.java b/android/src/org/ppsspp/ppsspp/InputDeviceState.java index d117b5316778..9c7317fa6c2a 100644 --- a/android/src/org/ppsspp/ppsspp/InputDeviceState.java +++ b/android/src/org/ppsspp/ppsspp/InputDeviceState.java @@ -128,6 +128,7 @@ public InputDeviceState(InputDevice device) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { logAdvanced(device); } + NativeApp.sendMessage("inputDeviceConnectedID", String.valueOf(this.deviceId)); NativeApp.sendMessage("inputDeviceConnected", device.getName()); } diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 235a13373308..c90c30a22a7a 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -31,6 +31,7 @@ #include "Core/Config.h" #include "Core/ConfigValues.h" +#include "Core/KeyMap.h" #include "Core/System.h" #include "Core/HLE/sceUsbCam.h" #include "Core/HLE/sceUsbGps.h" @@ -94,6 +95,7 @@ void StopThread() override { static double lastSelectPress = 0.0f; static double lastStartPress = 0.0f; static bool simulateAnalog = false; +static bool iCadeConnectNotified = false; static bool threadEnabled = true; static bool threadStopped = false; static UITouch *g_touches[10]; @@ -507,6 +509,11 @@ - (void)buttonDown:(iCadeState)button - (void)buttonUp:(iCadeState)button { + if (!iCadeConnectNotified) { + iCadeConnectNotified = true; + KeyMap::NotifyPadConnected(DEVICE_ID_PAD_0, "iCade"); + } + if (button == iCadeButtonA) { // Pressing Select twice within 1 second toggles the DPad between // normal operation and simulating the Analog stick. From c15c4a6967ffbf150df5511f1b6cf90e8107f4f2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 4 Jul 2022 13:10:42 -0700 Subject: [PATCH 2/7] UI: Add analog speed limit mapping. Only shows up as a setting if mapped, to avoid cluttering settings. --- Core/Config.cpp | 2 ++ Core/Config.h | 2 ++ Core/ConfigValues.h | 6 ++++ Core/ControlMapper.cpp | 63 +++++++++++++++++++++++++++++++++++++ Core/ControlMapper.h | 1 + Core/CoreParameter.h | 2 ++ Core/HLE/sceDisplay.cpp | 2 ++ Core/KeyMap.cpp | 14 +++++++-- Core/KeyMap.h | 2 ++ GPU/GPUCommon.cpp | 9 +++++- UI/ControlMappingScreen.cpp | 3 ++ UI/EmuScreen.cpp | 4 +-- UI/GameSettingsScreen.cpp | 7 +++++ UI/GameSettingsScreen.h | 1 + 14 files changed, 113 insertions(+), 5 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 888c3c4aea68..fe03875ba8ab 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -867,6 +867,8 @@ static ConfigSetting graphicsSettings[] = { ReportedConfigSetting("AutoFrameSkip", &g_Config.bAutoFrameSkip, false, true, true), ConfigSetting("FrameRate", &g_Config.iFpsLimit1, 0, true, true), ConfigSetting("FrameRate2", &g_Config.iFpsLimit2, -1, true, true), + ConfigSetting("AnalogFrameRate", &g_Config.iAnalogFpsLimit, 240, true, true), + ConfigSetting("AnalogFrameRateMode", &g_Config.iAnalogFpsMode, 0, true, true), ConfigSetting("UnthrottlingMode", &g_Config.iFastForwardMode, &DefaultFastForwardMode, &FastForwardModeToString, &FastForwardModeFromString, true, true), #if defined(USING_WIN_UI) ConfigSetting("RestartRequired", &g_Config.bRestartRequired, false, false), diff --git a/Core/Config.h b/Core/Config.h index 8c989ce319e5..88aefb94e628 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -214,6 +214,8 @@ struct Config { bool bTexHardwareScaling; int iFpsLimit1; int iFpsLimit2; + int iAnalogFpsLimit; + int iAnalogFpsMode; // 0 = auto, 1 = single direction, 2 = mapped to opposite int iMaxRecent; int iCurrentStateSlot; int iRewindFlipFrequency; diff --git a/Core/ConfigValues.h b/Core/ConfigValues.h index 44653a28fca4..5499a6640528 100644 --- a/Core/ConfigValues.h +++ b/Core/ConfigValues.h @@ -130,3 +130,9 @@ enum class BackgroundAnimation { WAVE = 3, MOVING_BACKGROUND = 4, }; + +enum class AnalogFpsMode { + AUTO = 0, + MAPPED_DIRECTION = 1, + MAPPED_TO_OPPOSITE = 2, +}; diff --git a/Core/ControlMapper.cpp b/Core/ControlMapper.cpp index 44d034a2cb82..25a20470c7cc 100644 --- a/Core/ControlMapper.cpp +++ b/Core/ControlMapper.cpp @@ -7,6 +7,8 @@ #include "Core/KeyMap.h" #include "Core/ControlMapper.h" #include "Core/Config.h" +#include "Core/CoreParameter.h" +#include "Core/System.h" static float MapAxisValue(float v) { const float deadzone = g_Config.fAnalogDeadzone; @@ -334,12 +336,21 @@ void ControlMapper::processAxis(const AxisInput &axis, int direction) { case VIRTKEY_AXIS_RIGHT_Y_MAX: SetPSPAxis('Y', value, CTRL_STICK_RIGHT); break; + + case VIRTKEY_SPEED_ANALOG: + ProcessAnalogSpeed(axis, false); + break; } } std::vector resultsOpposite; KeyMap::AxisToPspButton(axis.deviceId, axis.axisId, -direction, &resultsOpposite); + for (int result : resultsOpposite) { + if (result == VIRTKEY_SPEED_ANALOG) + ProcessAnalogSpeed(axis, true); + } + int axisState = 0; float threshold = axis.deviceId == DEVICE_ID_MOUSE ? AXIS_BIND_THRESHOLD_MOUSE : AXIS_BIND_THRESHOLD; if (direction == 1 && axis.value >= threshold) { @@ -375,3 +386,55 @@ void ControlMapper::processAxis(const AxisInput &axis, int direction) { } } } + +void ControlMapper::ProcessAnalogSpeed(const AxisInput &axis, bool opposite) { + 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. + mode = AnalogFpsMode::MAPPED_TO_OPPOSITE; + 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); + if (opposite) + return; + } else if (mode == AnalogFpsMode::MAPPED_TO_OPPOSITE) { + value = fabsf(value); + if (opposite) + value = -value; + value = 0.5f - value * 0.5f; + } + + // 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; +} diff --git a/Core/ControlMapper.h b/Core/ControlMapper.h index cb363c7ebcc5..d930c56f8be2 100644 --- a/Core/ControlMapper.h +++ b/Core/ControlMapper.h @@ -33,6 +33,7 @@ class ControlMapper { void setVKeyAnalog(char axis, int stick, int virtualKeyMin, int virtualKeyMax, bool setZero = true); void SetPSPAxis(char axis, float value, int stick); + void ProcessAnalogSpeed(const AxisInput &axis, bool opposite); void onVKeyDown(int vkey); void onVKeyUp(int vkey); diff --git a/Core/CoreParameter.h b/Core/CoreParameter.h index 1e5ef6793533..7e9ea60b2e46 100644 --- a/Core/CoreParameter.h +++ b/Core/CoreParameter.h @@ -33,6 +33,7 @@ enum class FPSLimit { NORMAL = 0, CUSTOM1 = 1, CUSTOM2 = 2, + ANALOG = 3, }; class FileLoader; @@ -76,6 +77,7 @@ struct CoreParameter { // Can be modified at runtime. bool fastForward = false; FPSLimit fpsLimit = FPSLimit::NORMAL; + int analogFpsLimit = 0; bool updateRecent = true; diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 3ebd21046969..bd1de18342d1 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -354,6 +354,8 @@ static int FrameTimingLimit() { return g_Config.iFpsLimit1; if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM2) return g_Config.iFpsLimit2; + if (PSP_CoreParameter().fpsLimit == FPSLimit::ANALOG) + return PSP_CoreParameter().analogFpsLimit; if (PSP_CoreParameter().fastForward) return 0; return 60; diff --git a/Core/KeyMap.cpp b/Core/KeyMap.cpp index 1456426ae28a..eb9cb515b7ab 100644 --- a/Core/KeyMap.cpp +++ b/Core/KeyMap.cpp @@ -369,6 +369,7 @@ const KeyMap_IntStrPair psp_button_names[] = { {VIRTKEY_SPEED_TOGGLE, "SpeedToggle"}, {VIRTKEY_SPEED_CUSTOM1, "Alt speed 1"}, {VIRTKEY_SPEED_CUSTOM2, "Alt speed 2"}, + {VIRTKEY_SPEED_ANALOG, "Analog speed"}, {VIRTKEY_PAUSE, "Pause"}, #ifndef MOBILE_DEVICE {VIRTKEY_FRAME_ADVANCE, "Frame Advance"}, @@ -543,8 +544,10 @@ bool AxisFromPspButton(int btn, int *deviceId, int *axisId, int *direction) { for (auto iter = g_controllerMap.begin(); iter != g_controllerMap.end(); ++iter) { for (auto iter2 = iter->second.begin(); iter2 != iter->second.end(); ++iter2) { if (iter->first == btn && iter2->keyCode >= AXIS_BIND_NKCODE_START) { - *deviceId = iter2->deviceId; - *axisId = TranslateKeyCodeToAxis(iter2->keyCode, *direction); + if (deviceId) + *deviceId = iter2->deviceId; + if (axisId) + *axisId = TranslateKeyCodeToAxis(iter2->keyCode, *direction); return true; } } @@ -798,6 +801,13 @@ const std::set &GetSeenPads() { return g_seenPads; } +std::string PadName(int deviceId) { + auto it = g_padNames.find(deviceId); + if (it != g_padNames.end()) + return it->second; + return ""; +} + // Swap direction buttons and left analog axis void SwapAxis() { g_swapped_keys = !g_swapped_keys; diff --git a/Core/KeyMap.h b/Core/KeyMap.h index 78f2b95987a8..a8ae9f672a58 100644 --- a/Core/KeyMap.h +++ b/Core/KeyMap.h @@ -67,6 +67,7 @@ enum { VIRTKEY_SCREEN_ROTATION_VERTICAL180 = 0x40000021, VIRTKEY_SCREEN_ROTATION_HORIZONTAL = 0x40000022, VIRTKEY_SCREEN_ROTATION_HORIZONTAL180 = 0x40000023, + VIRTKEY_SPEED_ANALOG = 0x40000024, VIRTKEY_LAST, VIRTKEY_COUNT = VIRTKEY_LAST - VIRTKEY_FIRST }; @@ -163,6 +164,7 @@ namespace KeyMap { bool HasBuiltinController(const std::string &name); const std::set &GetSeenPads(); + std::string PadName(int deviceId); void AutoConfForPad(const std::string &name); bool IsKeyMapped(int device, int key); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index df978cfb9be6..0d24e004c499 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -505,7 +505,14 @@ void GPUCommon::UpdateVsyncInterval(bool force) { desiredVSyncInterval = 0; } if (PSP_CoreParameter().fpsLimit != FPSLimit::NORMAL) { - int limit = PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1 ? g_Config.iFpsLimit1 : g_Config.iFpsLimit2; + int limit; + if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1) + limit = g_Config.iFpsLimit1; + else if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM2) + limit = g_Config.iFpsLimit2; + else + limit = PSP_CoreParameter().analogFpsLimit; + // For an alternative speed that is a clean factor of 60, the user probably still wants vsync. if (limit == 0 || (limit >= 0 && limit != 15 && limit != 30 && limit != 60)) { desiredVSyncInterval = 0; diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 126f2629f3cd..32ada96a0d40 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -337,6 +337,9 @@ bool KeyMappingNewKeyDialog::key(const KeyInput &key) { if (key.keyCode == NKCODE_EXT_MOUSEBUTTON_1) { return true; } + // Only map analog values to this mapping. + if (pspBtn_ == VIRTKEY_SPEED_ANALOG) + return true; mapped_ = true; KeyDef kdf(key.deviceId, key.keyCode); diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 385be9944458..aa0857646704 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -585,10 +585,10 @@ void EmuScreen::onVKeyDown(int virtualKeyCode) { if (PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL && g_Config.iFpsLimit1 >= 0) { PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM1; osm.Show(sc->T("fixed", "Speed: alternate"), 1.0); - } else if (PSP_CoreParameter().fpsLimit != FPSLimit::CUSTOM2 && g_Config.iFpsLimit2 >= 0) { + } else if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1 && g_Config.iFpsLimit2 >= 0) { PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM2; osm.Show(sc->T("SpeedCustom2", "Speed: alternate 2"), 1.0); - } else if (PSP_CoreParameter().fpsLimit != FPSLimit::NORMAL) { + } else if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1 || PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM2) { PSP_CoreParameter().fpsLimit = FPSLimit::NORMAL; osm.Show(sc->T("standard", "Speed: standard"), 1.0); } diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 96fb695f042a..d732d1ebc8fb 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -201,6 +201,7 @@ void GameSettingsScreen::CreateViews() { iAlternateSpeedPercent1_ = g_Config.iFpsLimit1 < 0 ? -1 : (g_Config.iFpsLimit1 * 100) / 60; iAlternateSpeedPercent2_ = g_Config.iFpsLimit2 < 0 ? -1 : (g_Config.iFpsLimit2 * 100) / 60; + iAlternateSpeedPercentAnalog_ = (g_Config.iAnalogFpsLimit * 100) / 60; bool vertical = UseVerticalLayout(); @@ -335,6 +336,11 @@ void GameSettingsScreen::CreateViews() { altSpeed2->SetZeroLabel(gr->T("Unlimited")); altSpeed2->SetNegativeDisable(gr->T("Disabled")); + if (KeyMap::AxisFromPspButton(VIRTKEY_SPEED_ANALOG, nullptr, nullptr, nullptr)) { + PopupSliderChoice *analogSpeed = graphicsSettings->Add(new PopupSliderChoice(&iAlternateSpeedPercentAnalog_, 1, 1000, gr->T("Analog Alternative Speed", "Analog alternative speed (in %)"), 5, screenManager(), gr->T("%"))); + altSpeed2->SetFormat("%i%%"); + } + graphicsSettings->Add(new ItemHeader(gr->T("Postprocessing effect"))); std::set alreadyAddedShader; @@ -1402,6 +1408,7 @@ void GameSettingsScreen::dialogFinished(const Screen *dialog, DialogResult resul if (result == DialogResult::DR_OK) { g_Config.iFpsLimit1 = iAlternateSpeedPercent1_ < 0 ? -1 : (iAlternateSpeedPercent1_ * 60) / 100; g_Config.iFpsLimit2 = iAlternateSpeedPercent2_ < 0 ? -1 : (iAlternateSpeedPercent2_ * 60) / 100; + g_Config.iAnalogFpsLimit = (iAlternateSpeedPercentAnalog_ * 60) / 100; RecreateViews(); } diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 5e3f280f3bc3..2db41e2d9c30 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -137,6 +137,7 @@ class GameSettingsScreen : public UIDialogScreenWithGameBackground { // Temporaries to convert setting types, cache enabled, etc. int iAlternateSpeedPercent1_; int iAlternateSpeedPercent2_; + int iAlternateSpeedPercentAnalog_; int prevInflightFrames_; bool enableReports_ = false; bool enableReportsSet_ = false; From 6e1457e3bf146a1b8a8e8695607b063c8298b932 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 4 Jul 2022 14:37:22 -0700 Subject: [PATCH 3/7] UWP: Skip pad name lookup. --- Windows/XinputDevice.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Windows/XinputDevice.cpp b/Windows/XinputDevice.cpp index 5dd00c165c74..b9d73c8ecd22 100644 --- a/Windows/XinputDevice.cpp +++ b/Windows/XinputDevice.cpp @@ -205,10 +205,14 @@ void XinputDevice::UpdatePad(int pad, const XINPUT_STATE &state, XINPUT_VIBRATIO static bool notified[XUSER_MAX_COUNT]{}; if (!notified[pad]) { notified[pad] = true; +#if !PPSSPP_PLATFORM(UWP) XINPUT_CAPABILITIES_EX caps; if (PPSSPP_XInputGetCapabilitiesEx != nullptr && PPSSPP_XInputGetCapabilitiesEx(1, pad, 0, &caps) == ERROR_SUCCESS) { KeyMap::NotifyPadConnected(DEVICE_ID_XINPUT_0 + pad, StringFromFormat("Xbox 360 Pad: %d/%d", caps.vendorId, caps.productId)); } else { +#else + { +#endif KeyMap::NotifyPadConnected(DEVICE_ID_XINPUT_0 + pad, "Xbox 360 Pad"); } } From 3cb420736913b9243ded73ebcf08b6d2c3970c08 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 4 Jul 2022 20:20:13 -0700 Subject: [PATCH 4/7] UI: Allow cancel from analog speed mapping. --- UI/ControlMappingScreen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 32ada96a0d40..7acdd36f0542 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -338,13 +338,13 @@ bool KeyMappingNewKeyDialog::key(const KeyInput &key) { return true; } // Only map analog values to this mapping. - if (pspBtn_ == VIRTKEY_SPEED_ANALOG) + if (pspBtn_ == VIRTKEY_SPEED_ANALOG && !UI::IsEscapeKey(key)) return true; mapped_ = true; KeyDef kdf(key.deviceId, key.keyCode); TriggerFinish(DR_YES); - if (callback_) + if (callback_ && pspBtn_ != VIRTKEY_SPEED_ANALOG) callback_(kdf); } return true; From f18c1a6e8faed35581ce389765d81b9f952af9fa Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 4 Jul 2022 20:20:31 -0700 Subject: [PATCH 5/7] UI: Reset views when analog speed mapped. --- UI/GameSettingsScreen.cpp | 9 ++++++++- UI/GameSettingsScreen.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index d732d1ebc8fb..3a923214f0a7 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -93,6 +93,7 @@ GameSettingsScreen::GameSettingsScreen(const Path &gamePath, std::string gameID, : UIDialogScreenWithGameBackground(gamePath), gameID_(gameID), editThenRestore_(editThenRestore) { lastVertical_ = UseVerticalLayout(); prevInflightFrames_ = g_Config.iInflightFrames; + analogSpeedMapped_ = KeyMap::AxisFromPspButton(VIRTKEY_SPEED_ANALOG, nullptr, nullptr, nullptr); } bool GameSettingsScreen::UseVerticalLayout() const { @@ -336,7 +337,7 @@ void GameSettingsScreen::CreateViews() { altSpeed2->SetZeroLabel(gr->T("Unlimited")); altSpeed2->SetNegativeDisable(gr->T("Disabled")); - if (KeyMap::AxisFromPspButton(VIRTKEY_SPEED_ANALOG, nullptr, nullptr, nullptr)) { + if (analogSpeedMapped_) { PopupSliderChoice *analogSpeed = graphicsSettings->Add(new PopupSliderChoice(&iAlternateSpeedPercentAnalog_, 1, 1000, gr->T("Analog Alternative Speed", "Analog alternative speed (in %)"), 5, screenManager(), gr->T("%"))); altSpeed2->SetFormat("%i%%"); } @@ -1412,6 +1413,12 @@ void GameSettingsScreen::dialogFinished(const Screen *dialog, DialogResult resul RecreateViews(); } + + bool mapped = KeyMap::AxisFromPspButton(VIRTKEY_SPEED_ANALOG, nullptr, nullptr, nullptr); + if (mapped != analogSpeedMapped_) { + analogSpeedMapped_ = mapped; + RecreateViews(); + } } void GameSettingsScreen::RecreateViews() { diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 2db41e2d9c30..3e00c26bdac6 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -141,6 +141,7 @@ class GameSettingsScreen : public UIDialogScreenWithGameBackground { int prevInflightFrames_; bool enableReports_ = false; bool enableReportsSet_ = false; + bool analogSpeedMapped_ = false; std::string shaderNames_[256]; std::string searchFilter_; From e159cb2b91248be3d1d7a4249b5e154b861a17e2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 5 Jul 2022 16:07:09 -0700 Subject: [PATCH 6/7] UI: Clamp analog speed to 0 on opposite value. --- Core/ConfigValues.h | 2 +- Core/ControlMapper.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Core/ConfigValues.h b/Core/ConfigValues.h index 5499a6640528..9018653aab22 100644 --- a/Core/ConfigValues.h +++ b/Core/ConfigValues.h @@ -134,5 +134,5 @@ enum class BackgroundAnimation { enum class AnalogFpsMode { AUTO = 0, MAPPED_DIRECTION = 1, - MAPPED_TO_OPPOSITE = 2, + MAPPED_DIR_TO_OPPOSITE_DIR = 2, }; diff --git a/Core/ControlMapper.cpp b/Core/ControlMapper.cpp index 25a20470c7cc..b93653b7ebf9 100644 --- a/Core/ControlMapper.cpp +++ b/Core/ControlMapper.cpp @@ -408,7 +408,7 @@ void ControlMapper::ProcessAnalogSpeed(const AxisInput &axis, bool opposite) { case JOYSTICK_AXIS_RY: case JOYSTICK_AXIS_RZ: // These, at least on directinput, can be used for triggers that go from mapped to opposite. - mode = AnalogFpsMode::MAPPED_TO_OPPOSITE; + mode = AnalogFpsMode::MAPPED_DIR_TO_OPPOSITE_DIR; break; default: @@ -421,9 +421,10 @@ void ControlMapper::ProcessAnalogSpeed(const AxisInput &axis, bool opposite) { // Okay, now let's map it as appropriate. if (mode == AnalogFpsMode::MAPPED_DIRECTION) { value = fabsf(value); + // Clamp to 0 in this case if we're processing the opposite direction. if (opposite) - return; - } else if (mode == AnalogFpsMode::MAPPED_TO_OPPOSITE) { + value = 0.0f; + } else if (mode == AnalogFpsMode::MAPPED_DIR_TO_OPPOSITE_DIR) { value = fabsf(value); if (opposite) value = -value; From 0179da6f3611ee026f8cca5043d3d25b58b270fd Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 5 Jul 2022 19:37:56 -0700 Subject: [PATCH 7/7] UI: Add small deadzone for analog speed. --- Core/ControlMapper.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Core/ControlMapper.cpp b/Core/ControlMapper.cpp index b93653b7ebf9..b19c29dbda9d 100644 --- a/Core/ControlMapper.cpp +++ b/Core/ControlMapper.cpp @@ -388,6 +388,9 @@ void ControlMapper::processAxis(const AxisInput &axis, int direction) { } void ControlMapper::ProcessAnalogSpeed(const AxisInput &axis, bool opposite) { + static constexpr float DEADZONE_THRESHOLD = 0.15f; + static constexpr float DEADZONE_SCALE = 1.0f / (1.0f - DEADZONE_THRESHOLD); + FPSLimit &limitMode = PSP_CoreParameter().fpsLimit; // If we're using an alternate speed already, let that win. if (limitMode != FPSLimit::NORMAL && limitMode != FPSLimit::ANALOG) @@ -431,6 +434,9 @@ void ControlMapper::ProcessAnalogSpeed(const AxisInput &axis, bool opposite) { value = 0.5f - value * 0.5f; } + // Apply a small deadzone (against the resting position.) + value = std::max(0.0f, (value - DEADZONE_THRESHOLD) * DEADZONE_SCALE); + // 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;