Skip to content

Commit b8fb16b

Browse files
committed
Control profiles
1 parent 81608b0 commit b8fb16b

File tree

10 files changed

+231
-22
lines changed

10 files changed

+231
-22
lines changed

Common/Data/Format/IniFile.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,18 @@ bool IniFile::Get(const char* sectionName, const char* key, bool* value, bool de
717717
}
718718
}
719719

720+
bool IniFile::Get(const char* sectionName, const char* key, float* value, float defaultValue)
721+
{
722+
Section *section = GetSection(sectionName);
723+
if (!section) {
724+
*value = defaultValue;
725+
return false;
726+
} else {
727+
return section->Get(key, value, defaultValue);
728+
}
729+
}
730+
731+
720732

721733
// Unit test. TODO: Move to the real unit test framework.
722734
/*

Common/Data/Format/IniFile.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ class IniFile {
125125
bool Get(const char* sectionName, const char* key, uint32_t* value, uint32_t defaultValue = 0);
126126
bool Get(const char* sectionName, const char* key, uint64_t* value, uint64_t defaultValue = 0);
127127
bool Get(const char* sectionName, const char* key, bool* value, bool defaultValue = false);
128+
bool Get(const char* sectionName, const char* key, float* value, float defaultValue = 0.0f);
128129
bool Get(const char* sectionName, const char* key, std::vector<std::string>& values);
129130

130131
template<typename T> bool GetIfExists(const char* sectionName, const char* key, T value)

Core/Config.cpp

Lines changed: 100 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -547,21 +547,6 @@ static const ConfigSetting generalSettings[] = {
547547
ConfigSetting("GridView1", &g_Config.bGridView1, true),
548548
ConfigSetting("GridView2", &g_Config.bGridView2, true),
549549
ConfigSetting("GridView3", &g_Config.bGridView3, false),
550-
ConfigSetting("RightAnalogUp", &g_Config.iRightAnalogUp, 0, true, true),
551-
ConfigSetting("RightAnalogDown", &g_Config.iRightAnalogDown, 0, true, true),
552-
ConfigSetting("RightAnalogLeft", &g_Config.iRightAnalogLeft, 0, true, true),
553-
ConfigSetting("RightAnalogRight", &g_Config.iRightAnalogRight, 0, true, true),
554-
ConfigSetting("RightAnalogPress", &g_Config.iRightAnalogPress, 0, true, true),
555-
ConfigSetting("RightAnalogCustom", &g_Config.bRightAnalogCustom, false, true, true),
556-
ConfigSetting("RightAnalogDisableDiagonal", &g_Config.bRightAnalogDisableDiagonal, false, true, true),
557-
ConfigSetting("SwipeUp", &g_Config.iSwipeUp, 0, true, true),
558-
ConfigSetting("SwipeDown", &g_Config.iSwipeDown, 0, true, true),
559-
ConfigSetting("SwipeLeft", &g_Config.iSwipeLeft, 0, true, true),
560-
ConfigSetting("SwipeRight", &g_Config.iSwipeRight, 0, true, true),
561-
ConfigSetting("SwipeSensitivity", &g_Config.fSwipeSensitivity, 1.0f, true, true),
562-
ConfigSetting("SwipeSmoothing", &g_Config.fSwipeSmoothing, 0.3f, true, true),
563-
ConfigSetting("DoubleTapGesture", &g_Config.iDoubleTapGesture, 0, true, true),
564-
ConfigSetting("GestureControlEnabled", &g_Config.bGestureControlEnabled, false, true, true),
565550

566551
// "default" means let emulator decide, "" means disable.
567552
ConfigSetting("ReportingHost", &g_Config.sReportHost, "default"),
@@ -606,6 +591,7 @@ static const ConfigSetting generalSettings[] = {
606591
ConfigSetting("EnablePlugins", &g_Config.bLoadPlugins, true, true, true),
607592

608593
ReportedConfigSetting("IgnoreCompatSettings", &g_Config.sIgnoreCompatSettings, "", true, true),
594+
ConfigSetting("SettingsVersion", &g_Config.uSettingsVersion, 0u, true, true), // Per game for game configs
609595
};
610596

611597
static bool DefaultSasThread() {
@@ -1039,6 +1025,23 @@ static const ConfigSetting controlSettings[] = {
10391025
ConfigSetting("MouseSensitivity", &g_Config.fMouseSensitivity, 0.1f, true, true),
10401026
ConfigSetting("MouseSmoothing", &g_Config.fMouseSmoothing, 0.9f, true, true),
10411027

1028+
ConfigSetting("RightAnalogUp", &g_Config.iRightAnalogUp, 0, true, true),
1029+
ConfigSetting("RightAnalogDown", &g_Config.iRightAnalogDown, 0, true, true),
1030+
ConfigSetting("RightAnalogLeft", &g_Config.iRightAnalogLeft, 0, true, true),
1031+
ConfigSetting("RightAnalogRight", &g_Config.iRightAnalogRight, 0, true, true),
1032+
ConfigSetting("RightAnalogPress", &g_Config.iRightAnalogPress, 0, true, true),
1033+
ConfigSetting("RightAnalogCustom", &g_Config.bRightAnalogCustom, false, true, true),
1034+
ConfigSetting("RightAnalogDisableDiagonal", &g_Config.bRightAnalogDisableDiagonal, false, true, true),
1035+
1036+
ConfigSetting("SwipeUp", &g_Config.iSwipeUp, 0, true, true),
1037+
ConfigSetting("SwipeDown", &g_Config.iSwipeDown, 0, true, true),
1038+
ConfigSetting("SwipeLeft", &g_Config.iSwipeLeft, 0, true, true),
1039+
ConfigSetting("SwipeRight", &g_Config.iSwipeRight, 0, true, true),
1040+
ConfigSetting("SwipeSensitivity", &g_Config.fSwipeSensitivity, 1.0f, true, true),
1041+
ConfigSetting("SwipeSmoothing", &g_Config.fSwipeSmoothing, 0.3f, true, true),
1042+
ConfigSetting("DoubleTapGesture", &g_Config.iDoubleTapGesture, 0, true, true),
1043+
ConfigSetting("GestureControlEnabled", &g_Config.bGestureControlEnabled, false, true, true),
1044+
10421045
ConfigSetting("SystemControls", &g_Config.bSystemControls, true, true, false),
10431046
};
10441047

@@ -1315,6 +1318,24 @@ void Config::UpdateAfterSettingAutoFrameSkip() {
13151318
}
13161319
}
13171320

1321+
static void loadOldControlSettings(IniFile &iniFile) {
1322+
iniFile.GetIfExists("General", "RightAnalogUp", &g_Config.iRightAnalogUp);
1323+
iniFile.GetIfExists("General", "RightAnalogDown", &g_Config.iRightAnalogDown);
1324+
iniFile.GetIfExists("General", "RightAnalogLeft", &g_Config.iRightAnalogLeft);
1325+
iniFile.GetIfExists("General", "RightAnalogRight", &g_Config.iRightAnalogRight);
1326+
iniFile.GetIfExists("General", "RightAnalogPress", &g_Config.iRightAnalogPress);
1327+
iniFile.GetIfExists("General", "SwipeUp", &g_Config.iSwipeUp);
1328+
iniFile.GetIfExists("General", "SwipeDown", &g_Config.iSwipeDown);
1329+
iniFile.GetIfExists("General", "SwipeLeft", &g_Config.iSwipeLeft);
1330+
iniFile.GetIfExists("General", "SwipeRight", &g_Config.iSwipeRight);
1331+
iniFile.GetIfExists("General", "DoubleTapGesture", &g_Config.iDoubleTapGesture);
1332+
iniFile.GetIfExists("General", "SwipeSensitivity", &g_Config.fSwipeSensitivity);
1333+
iniFile.GetIfExists("General", "SwipeSmoothing", &g_Config.fSwipeSmoothing);
1334+
iniFile.GetIfExists("General", "RightAnalogCustom", &g_Config.bRightAnalogCustom);
1335+
iniFile.GetIfExists("General", "RightAnalogDisableDiagonal", &g_Config.bRightAnalogDisableDiagonal);
1336+
iniFile.GetIfExists("General", "GestureControlEnabled", &g_Config.bGestureControlEnabled);
1337+
}
1338+
13181339
void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
13191340
if (!bUpdatedInstanceCounter) {
13201341
InitInstanceCounter();
@@ -1419,6 +1440,12 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
14191440
ResetControlLayout();
14201441
}
14211442

1443+
if (g_Config.uSettingsVersion == 0) {
1444+
g_Config.uSettingsVersion = 1;
1445+
1446+
loadOldControlSettings(iniFile);
1447+
}
1448+
14221449
const char *gitVer = PPSSPP_GIT_VERSION;
14231450
Version installed(gitVer);
14241451
Version upgrade(upgradeVersion);
@@ -1466,6 +1493,58 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
14661493
INFO_LOG(LOADER, "Config loaded: '%s'", iniFilename_.c_str());
14671494
}
14681495

1496+
bool Config::SaveControllerProfile(uint32_t id) {
1497+
IniFile iniFile;
1498+
if (!iniFile.Load(controllerIniFilename_)) {
1499+
ERROR_LOG(LOADER, "Error saving controller profile - can't read ini '%s'", controllerIniFilename_.c_str());
1500+
return false;
1501+
}
1502+
1503+
Section *section = iniFile.GetOrCreateSection(StringFromFormat("ControlProfile%uSettings", id).c_str());
1504+
for (auto &setting : controlSettings) {
1505+
setting.Set(section);
1506+
}
1507+
1508+
KeyMap::SaveToIni(iniFile, StringFromFormat("ControlProfile%uMapping", id).c_str());
1509+
1510+
if (!iniFile.Save(controllerIniFilename_)) {
1511+
ERROR_LOG(LOADER, "Error saving controller profile - can't write ini '%s'", controllerIniFilename_.c_str());
1512+
return false;
1513+
}
1514+
1515+
return true;
1516+
}
1517+
1518+
bool Config::ControllerProfileExist(uint32_t id) {
1519+
IniFile iniFile;
1520+
if (!iniFile.Load(controllerIniFilename_)) {
1521+
ERROR_LOG(LOADER, "Error checking controller profile - can't read ini '%s'", controllerIniFilename_.c_str());
1522+
return false;
1523+
}
1524+
1525+
return iniFile.HasSection(StringFromFormat("ControlProfile%uSettings", id).c_str());
1526+
}
1527+
1528+
bool Config::LoadControllerProfile(uint32_t id) {
1529+
IniFile iniFile;
1530+
if (!iniFile.Load(controllerIniFilename_)) {
1531+
ERROR_LOG(LOADER, "Error loading controller profile - can't read ini '%s'", controllerIniFilename_.c_str());
1532+
return false;
1533+
}
1534+
1535+
if (!iniFile.HasSection(StringFromFormat("ControlProfile%uSettings", id).c_str()))
1536+
return false;
1537+
1538+
Section *section = iniFile.GetOrCreateSection(StringFromFormat("ControlProfile%uSettings", id).c_str());
1539+
for (auto &setting : controlSettings) {
1540+
setting.Get(section);
1541+
}
1542+
1543+
KeyMap::LoadFromIni(iniFile, StringFromFormat("ControlProfile%uMapping", id).c_str());
1544+
1545+
return true;
1546+
}
1547+
14691548
bool Config::Save(const char *saveReason) {
14701549
if (!IsFirstInstance()) {
14711550
// TODO: Should we allow saving config if started from a different directory?
@@ -1944,6 +2023,12 @@ bool Config::loadGameConfig(const std::string &pGameId, const std::string &title
19442023
}
19452024
});
19462025

2026+
if (g_Config.uSettingsVersion == 0) {
2027+
g_Config.uSettingsVersion = 1;
2028+
2029+
loadOldControlSettings(iniFile);
2030+
}
2031+
19472032
KeyMap::LoadFromIni(iniFile);
19482033

19492034
if (!appendedConfigFileName_.ToString().empty() &&

Core/Config.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ struct Config {
9090
bool bEnableLogging;
9191
bool bDumpDecryptedEboot;
9292
bool bFullscreenOnDoubleclick;
93+
uint32_t uSettingsVersion;
9394

9495
// These four are Win UI only
9596
bool bPauseOnLostFocus;
@@ -521,6 +522,9 @@ struct Config {
521522

522523
void Load(const char *iniFileName = nullptr, const char *controllerIniFilename = nullptr);
523524
bool Save(const char *saveReason);
525+
bool SaveControllerProfile(uint32_t id);
526+
bool LoadControllerProfile(uint32_t id);
527+
bool ControllerProfileExist(uint32_t id);
524528
void Reload();
525529
void RestoreDefaults(RestoreSettingsBits whatToRestore);
526530

Core/KeyMap.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,12 @@ const KeyMap_IntStrPair psp_button_names[] = {
421421
{CTRL_VOL_DOWN, "Vol -"},
422422
{CTRL_SCREEN, "Screen"},
423423
{CTRL_NOTE, "Note"},
424+
425+
{VIRTKEY_CONTROLLER_PROFILE_1, "Load control profile 1"},
426+
{VIRTKEY_CONTROLLER_PROFILE_2, "Load control profile 2"},
427+
{VIRTKEY_CONTROLLER_PROFILE_3, "Load control profile 3"},
428+
{VIRTKEY_CONTROLLER_PROFILE_4, "Load control profile 4"},
429+
{VIRTKEY_CONTROLLER_PROFILE_5, "Load control profile 5"},
424430
};
425431

426432
static std::string FindName(int key, const KeyMap_IntStrPair list[], size_t size) {
@@ -647,13 +653,13 @@ void RestoreDefault() {
647653
}
648654

649655
// TODO: Make the ini format nicer.
650-
void LoadFromIni(IniFile &file) {
656+
void LoadFromIni(IniFile &file, const char *section) {
651657
RestoreDefault();
652-
if (!file.HasSection("ControlMapping")) {
658+
if (!file.HasSection("ControlMapping")) { // Only on default section
653659
return;
654660
}
655661

656-
Section *controls = file.GetOrCreateSection("ControlMapping");
662+
Section *controls = file.GetOrCreateSection(section);
657663
for (size_t i = 0; i < ARRAY_SIZE(psp_button_names); i++) {
658664
std::string value;
659665
controls->Get(psp_button_names[i].name, &value, "");
@@ -680,8 +686,8 @@ void LoadFromIni(IniFile &file) {
680686
UpdateNativeMenuKeys();
681687
}
682688

683-
void SaveToIni(IniFile &file) {
684-
Section *controls = file.GetOrCreateSection("ControlMapping");
689+
void SaveToIni(IniFile &file, const char *section) {
690+
Section *controls = file.GetOrCreateSection(section);
685691

686692
for (size_t i = 0; i < ARRAY_SIZE(psp_button_names); i++) {
687693
std::vector<InputMapping> keys;

Core/KeyMap.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ enum {
7070
VIRTKEY_SPEED_ANALOG = 0x40000024,
7171
VIRTKEY_VR_CAMERA_ADJUST = 0x40000025,
7272
VIRTKEY_VR_CAMERA_RESET = 0x40000026,
73+
VIRTKEY_CONTROLLER_PROFILE_1 = 0x40000027,
74+
VIRTKEY_CONTROLLER_PROFILE_2 = 0x40000028,
75+
VIRTKEY_CONTROLLER_PROFILE_3 = 0x40000029,
76+
VIRTKEY_CONTROLLER_PROFILE_4 = 0x4000002A,
77+
VIRTKEY_CONTROLLER_PROFILE_5 = 0x4000002B,
7378
VIRTKEY_LAST,
7479
VIRTKEY_COUNT = VIRTKEY_LAST - VIRTKEY_FIRST
7580
};
@@ -137,8 +142,8 @@ namespace KeyMap {
137142

138143
MappedAnalogAxes MappedAxesForDevice(int deviceId);
139144

140-
void LoadFromIni(IniFile &iniFile);
141-
void SaveToIni(IniFile &iniFile);
145+
void LoadFromIni(IniFile &iniFile, const char *section = "ControlMapping");
146+
void SaveToIni(IniFile &iniFile, const char *section = "ControlMapping");
142147

143148
void SetDefaultKeyMap(DefaultMaps dmap, bool replace);
144149

UI/EmuScreen.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,26 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) {
754754
if (down)
755755
g_Config.iInternalScreenRotation = ROTATION_LOCKED_HORIZONTAL180;
756756
break;
757+
case VIRTKEY_CONTROLLER_PROFILE_1:
758+
g_Config.LoadControllerProfile(1);
759+
RecreateViews();
760+
break;
761+
case VIRTKEY_CONTROLLER_PROFILE_2:
762+
g_Config.LoadControllerProfile(2);
763+
RecreateViews();
764+
break;
765+
case VIRTKEY_CONTROLLER_PROFILE_3:
766+
g_Config.LoadControllerProfile(3);
767+
RecreateViews();
768+
break;
769+
case VIRTKEY_CONTROLLER_PROFILE_4:
770+
g_Config.LoadControllerProfile(4);
771+
RecreateViews();
772+
break;
773+
case VIRTKEY_CONTROLLER_PROFILE_5:
774+
g_Config.LoadControllerProfile(5);
775+
RecreateViews();
776+
break;
757777
}
758778
}
759779

UI/GameSettingsScreen.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,11 @@ void GameSettingsScreen::CreateControlsSettings(UI::ViewGroup *controlsSettings)
686686
controlsSettings->Add(new Choice(co->T("Control Mapping")))->OnClick.Handle(this, &GameSettingsScreen::OnControlMapping);
687687
controlsSettings->Add(new Choice(co->T("Calibrate Analog Stick")))->OnClick.Handle(this, &GameSettingsScreen::OnCalibrateAnalogs);
688688

689+
controlsSettings->Add(new Choice(co->T("Control Profiles")))->OnClick.Add([=](EventParams &e) {
690+
screenManager()->push(new ControllerProfileScreen());
691+
return UI::EVENT_DONE;
692+
});
693+
689694
#if defined(USING_WIN_UI)
690695
controlsSettings->Add(new CheckBox(&g_Config.bSystemControls, co->T("Enable standard shortcut keys")));
691696
controlsSettings->Add(new CheckBox(&g_Config.bGamepadOnlyFocused, co->T("Ignore gamepads when not focused")));
@@ -2241,3 +2246,55 @@ void RestoreSettingsScreen::OnCompleted(DialogResult result) {
22412246
g_Config.RestoreDefaults((RestoreSettingsBits)restoreFlags_);
22422247
}
22432248
}
2249+
void ControllerProfileScreen::CreateViews() {
2250+
using namespace UI;
2251+
2252+
auto co = GetI18NCategory("Controls");
2253+
2254+
root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
2255+
AddStandardBack(root_);
2256+
TabHolder *tabHolder = new TabHolder(ORIENT_VERTICAL, 200, new AnchorLayoutParams(10, 0, 10, 0, false));
2257+
root_->Add(tabHolder);
2258+
ScrollView *rightPanel = new ScrollView(ORIENT_VERTICAL);
2259+
tabHolder->AddTab(co->T("Profiles"), rightPanel);
2260+
LinearLayout *vert = rightPanel->Add(new LinearLayout(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, FILL_PARENT)));
2261+
vert->SetSpacing(0);
2262+
2263+
float leftSide = 40.0f;
2264+
if (g_display.dp_yres <= g_display.dp_xres * 1.1f) {
2265+
leftSide += 200.0f;
2266+
}
2267+
settingInfo_ = new SettingInfoMessage(ALIGN_CENTER | FLAG_WRAP_TEXT, new AnchorLayoutParams(g_display.dp_xres - leftSide - 40.0f, WRAP_CONTENT, leftSide, g_display.dp_yres - 80.0f - 40.0f, NONE, NONE));
2268+
settingInfo_->SetBottomCutoff(g_display.dp_yres - 200.0f);
2269+
root_->Add(settingInfo_);
2270+
2271+
static constexpr int MAX_PROFILE = 5; // Should we have 5 with binding for fast selection and unlimited just to have them?
2272+
for (int i = 1; i <= MAX_PROFILE; ++i) {
2273+
vert->Add(new ItemHeader(ReplaceAll(co->T("Profile %1"), "%1", std::to_string(i))));
2274+
2275+
Choice *save = new Choice(co->T("Save current control settings"));
2276+
Choice *load = new Choice(co->T("Load control profile"));
2277+
2278+
load->OnClick.Add([=](EventParams &e) {
2279+
if (g_Config.LoadControllerProfile(i))
2280+
settingInfo_->Show(co->T("Control profile loaded"), e.v);
2281+
2282+
return UI::EVENT_CONTINUE;
2283+
});
2284+
2285+
save->OnClick.Add([=](EventParams &e) {
2286+
if (g_Config.SaveControllerProfile(i)) {
2287+
settingInfo_->Show(co->T("Control profile saved"), e.v);
2288+
load->SetEnabled(true);
2289+
}
2290+
2291+
return UI::EVENT_CONTINUE;
2292+
});
2293+
2294+
// Not a func to avoid Android slow IO problems
2295+
load->SetEnabled(g_Config.ControllerProfileExist(i));
2296+
vert->Add(save);
2297+
vert->Add(load);
2298+
}
2299+
}
2300+

UI/GameSettingsScreen.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,12 @@ class RestoreSettingsScreen : public PopupScreen {
265265
void OnCompleted(DialogResult result) override;
266266
int restoreFlags_ = (int)(RestoreSettingsBits::SETTINGS); // RestoreSettingsBits enum
267267
};
268+
269+
class ControllerProfileScreen : public UIDialogScreenWithBackground {
270+
public:
271+
void CreateViews() override;
272+
273+
const char *tag() const override { return "ControllerProfile"; }
274+
private:
275+
SettingInfoMessage *settingInfo_;
276+
};

0 commit comments

Comments
 (0)