Skip to content

Commit

Permalink
Merge pull request #15645 from unknownbrackets/analog-speed
Browse files Browse the repository at this point in the history
UI: Add analog speed limit mapping
  • Loading branch information
hrydgard authored Jul 6, 2022
2 parents 76da8a7 + 0179da6 commit e1ce0e2
Show file tree
Hide file tree
Showing 20 changed files with 193 additions and 20 deletions.
2 changes: 2 additions & 0 deletions Core/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
2 changes: 2 additions & 0 deletions Core/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions Core/ConfigValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,9 @@ enum class BackgroundAnimation {
WAVE = 3,
MOVING_BACKGROUND = 4,
};

enum class AnalogFpsMode {
AUTO = 0,
MAPPED_DIRECTION = 1,
MAPPED_DIR_TO_OPPOSITE_DIR = 2,
};
70 changes: 70 additions & 0 deletions Core/ControlMapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<int> 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) {
Expand Down Expand Up @@ -375,3 +386,62 @@ 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)
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_DIR_TO_OPPOSITE_DIR;
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);
// Clamp to 0 in this case if we're processing the opposite direction.
if (opposite)
value = 0.0f;
} else if (mode == AnalogFpsMode::MAPPED_DIR_TO_OPPOSITE_DIR) {
value = fabsf(value);
if (opposite)
value = -value;
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;
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;
}
1 change: 1 addition & 0 deletions Core/ControlMapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions Core/CoreParameter.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ enum class FPSLimit {
NORMAL = 0,
CUSTOM1 = 1,
CUSTOM2 = 2,
ANALOG = 3,
};

class FileLoader;
Expand Down Expand Up @@ -76,6 +77,7 @@ struct CoreParameter {
// Can be modified at runtime.
bool fastForward = false;
FPSLimit fpsLimit = FPSLimit::NORMAL;
int analogFpsLimit = 0;

bool updateRecent = true;

Expand Down
2 changes: 2 additions & 0 deletions Core/HLE/sceDisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
18 changes: 15 additions & 3 deletions Core/KeyMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ KeyMapping g_controllerMap;
// Incremented on modification, so we know when to update menus.
int g_controllerMapGeneration = 0;
std::set<std::string> g_seenPads;
std::map<int, std::string> g_padNames;
std::set<int> g_seenDeviceIds;

bool g_swapped_keys = false;
Expand Down Expand Up @@ -368,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"},
Expand Down Expand Up @@ -542,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;
}
}
Expand Down Expand Up @@ -762,8 +766,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) {
Expand Down Expand Up @@ -796,6 +801,13 @@ const std::set<std::string> &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;
Expand Down
4 changes: 3 additions & 1 deletion Core/KeyMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
Expand Down Expand Up @@ -153,7 +154,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);
Expand All @@ -163,6 +164,7 @@ namespace KeyMap {
bool HasBuiltinController(const std::string &name);

const std::set<std::string> &GetSeenPads();
std::string PadName(int deviceId);
void AutoConfForPad(const std::string &name);

bool IsKeyMapped(int device, int key);
Expand Down
9 changes: 8 additions & 1 deletion GPU/GPUCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
15 changes: 12 additions & 3 deletions SDL/SDLJoystick.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "Common/System/System.h"

#include "Core/Config.h"
#include "Core/KeyMap.h"
#include "SDL/SDLJoystick.h"

using namespace std;
Expand Down Expand Up @@ -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
Expand All @@ -73,13 +75,20 @@ 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) {
if (SDL_GameControllerGetAttached(controller)) {
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;
Expand Down
5 changes: 4 additions & 1 deletion UI/ControlMappingScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,11 +337,14 @@ 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 && !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;
Expand Down
4 changes: 2 additions & 2 deletions UI/EmuScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
14 changes: 14 additions & 0 deletions UI/GameSettingsScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -201,6 +202,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();

Expand Down Expand Up @@ -335,6 +337,11 @@ void GameSettingsScreen::CreateViews() {
altSpeed2->SetZeroLabel(gr->T("Unlimited"));
altSpeed2->SetNegativeDisable(gr->T("Disabled"));

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%%");
}

graphicsSettings->Add(new ItemHeader(gr->T("Postprocessing effect")));

std::set<std::string> alreadyAddedShader;
Expand Down Expand Up @@ -1402,7 +1409,14 @@ 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();
}

bool mapped = KeyMap::AxisFromPspButton(VIRTKEY_SPEED_ANALOG, nullptr, nullptr, nullptr);
if (mapped != analogSpeedMapped_) {
analogSpeedMapped_ = mapped;
RecreateViews();
}
}
Expand Down
2 changes: 2 additions & 0 deletions UI/GameSettingsScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,11 @@ 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;
bool analogSpeedMapped_ = false;
std::string shaderNames_[256];
std::string searchFilter_;

Expand Down
Loading

0 comments on commit e1ce0e2

Please sign in to comment.