Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Common/Data/Format/IniFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,18 @@ bool IniFile::Get(const char* sectionName, const char* key, bool* value, bool de
}
}

bool IniFile::Get(const char* sectionName, const char* key, float* value, float defaultValue)
{
Section *section = GetSection(sectionName);
if (!section) {
*value = defaultValue;
return false;
} else {
return section->Get(key, value, defaultValue);
}
}



// Unit test. TODO: Move to the real unit test framework.
/*
Expand Down
1 change: 1 addition & 0 deletions Common/Data/Format/IniFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ class IniFile {
bool Get(const char* sectionName, const char* key, uint32_t* value, uint32_t defaultValue = 0);
bool Get(const char* sectionName, const char* key, uint64_t* value, uint64_t defaultValue = 0);
bool Get(const char* sectionName, const char* key, bool* value, bool defaultValue = false);
bool Get(const char* sectionName, const char* key, float* value, float defaultValue = 0.0f);
bool Get(const char* sectionName, const char* key, std::vector<std::string>& values);

template<typename T> bool GetIfExists(const char* sectionName, const char* key, T value)
Expand Down
115 changes: 100 additions & 15 deletions Core/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -547,21 +547,6 @@ static const ConfigSetting generalSettings[] = {
ConfigSetting("GridView1", &g_Config.bGridView1, true),
ConfigSetting("GridView2", &g_Config.bGridView2, true),
ConfigSetting("GridView3", &g_Config.bGridView3, false),
ConfigSetting("RightAnalogUp", &g_Config.iRightAnalogUp, 0, true, true),
ConfigSetting("RightAnalogDown", &g_Config.iRightAnalogDown, 0, true, true),
ConfigSetting("RightAnalogLeft", &g_Config.iRightAnalogLeft, 0, true, true),
ConfigSetting("RightAnalogRight", &g_Config.iRightAnalogRight, 0, true, true),
ConfigSetting("RightAnalogPress", &g_Config.iRightAnalogPress, 0, true, true),
ConfigSetting("RightAnalogCustom", &g_Config.bRightAnalogCustom, false, true, true),
ConfigSetting("RightAnalogDisableDiagonal", &g_Config.bRightAnalogDisableDiagonal, false, true, true),
ConfigSetting("SwipeUp", &g_Config.iSwipeUp, 0, true, true),
ConfigSetting("SwipeDown", &g_Config.iSwipeDown, 0, true, true),
ConfigSetting("SwipeLeft", &g_Config.iSwipeLeft, 0, true, true),
ConfigSetting("SwipeRight", &g_Config.iSwipeRight, 0, true, true),
ConfigSetting("SwipeSensitivity", &g_Config.fSwipeSensitivity, 1.0f, true, true),
ConfigSetting("SwipeSmoothing", &g_Config.fSwipeSmoothing, 0.3f, true, true),
ConfigSetting("DoubleTapGesture", &g_Config.iDoubleTapGesture, 0, true, true),
ConfigSetting("GestureControlEnabled", &g_Config.bGestureControlEnabled, false, true, true),

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

ReportedConfigSetting("IgnoreCompatSettings", &g_Config.sIgnoreCompatSettings, "", true, true),
ConfigSetting("SettingsVersion", &g_Config.uSettingsVersion, 0u, true, true), // Per game for game configs

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We traditionally haven't had a version number for settings. I hope the addition of this will not lead to a proliferation of changes, because testing all kinds of settings upgrades will be very laborious...

@iota97 iota97 Jul 16, 2022

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could have a bool specific for this port like bRightAnalogSettingPorted that would reduce the temptations to add new settings version.

Anyway I see your concern with this PR, if/when you decide what's best for the project I'll change and rebase accordingly :)

Edit: another option would be to just leave the settings in the old section and have the profile code get them from there, a bit uglier code but the end user would not notice at least

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm taking back my comment here, SettingsVersion is the better option, otherwise if we make more corrections in the future, we'll just end up with more specific bools and the combinations get harder to understand.

};

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

ConfigSetting("RightAnalogUp", &g_Config.iRightAnalogUp, 0, true, true),
ConfigSetting("RightAnalogDown", &g_Config.iRightAnalogDown, 0, true, true),
ConfigSetting("RightAnalogLeft", &g_Config.iRightAnalogLeft, 0, true, true),
ConfigSetting("RightAnalogRight", &g_Config.iRightAnalogRight, 0, true, true),
ConfigSetting("RightAnalogPress", &g_Config.iRightAnalogPress, 0, true, true),
ConfigSetting("RightAnalogCustom", &g_Config.bRightAnalogCustom, false, true, true),
ConfigSetting("RightAnalogDisableDiagonal", &g_Config.bRightAnalogDisableDiagonal, false, true, true),

ConfigSetting("SwipeUp", &g_Config.iSwipeUp, 0, true, true),
ConfigSetting("SwipeDown", &g_Config.iSwipeDown, 0, true, true),
ConfigSetting("SwipeLeft", &g_Config.iSwipeLeft, 0, true, true),
ConfigSetting("SwipeRight", &g_Config.iSwipeRight, 0, true, true),
ConfigSetting("SwipeSensitivity", &g_Config.fSwipeSensitivity, 1.0f, true, true),
ConfigSetting("SwipeSmoothing", &g_Config.fSwipeSmoothing, 0.3f, true, true),
ConfigSetting("DoubleTapGesture", &g_Config.iDoubleTapGesture, 0, true, true),
ConfigSetting("GestureControlEnabled", &g_Config.bGestureControlEnabled, false, true, true),

ConfigSetting("SystemControls", &g_Config.bSystemControls, true, true, false),
};

Expand Down Expand Up @@ -1315,6 +1318,24 @@ void Config::UpdateAfterSettingAutoFrameSkip() {
}
}

static void loadOldControlSettings(IniFile &iniFile) {
iniFile.GetIfExists("General", "RightAnalogUp", &g_Config.iRightAnalogUp);
iniFile.GetIfExists("General", "RightAnalogDown", &g_Config.iRightAnalogDown);
iniFile.GetIfExists("General", "RightAnalogLeft", &g_Config.iRightAnalogLeft);
iniFile.GetIfExists("General", "RightAnalogRight", &g_Config.iRightAnalogRight);
iniFile.GetIfExists("General", "RightAnalogPress", &g_Config.iRightAnalogPress);
iniFile.GetIfExists("General", "SwipeUp", &g_Config.iSwipeUp);
iniFile.GetIfExists("General", "SwipeDown", &g_Config.iSwipeDown);
iniFile.GetIfExists("General", "SwipeLeft", &g_Config.iSwipeLeft);
iniFile.GetIfExists("General", "SwipeRight", &g_Config.iSwipeRight);
iniFile.GetIfExists("General", "DoubleTapGesture", &g_Config.iDoubleTapGesture);
iniFile.GetIfExists("General", "SwipeSensitivity", &g_Config.fSwipeSensitivity);
iniFile.GetIfExists("General", "SwipeSmoothing", &g_Config.fSwipeSmoothing);
iniFile.GetIfExists("General", "RightAnalogCustom", &g_Config.bRightAnalogCustom);
iniFile.GetIfExists("General", "RightAnalogDisableDiagonal", &g_Config.bRightAnalogDisableDiagonal);
iniFile.GetIfExists("General", "GestureControlEnabled", &g_Config.bGestureControlEnabled);
}

void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
if (!bUpdatedInstanceCounter) {
InitInstanceCounter();
Expand Down Expand Up @@ -1419,6 +1440,12 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
ResetControlLayout();
}

if (g_Config.uSettingsVersion == 0) {
g_Config.uSettingsVersion = 1;

loadOldControlSettings(iniFile);
}

const char *gitVer = PPSSPP_GIT_VERSION;
Version installed(gitVer);
Version upgrade(upgradeVersion);
Expand Down Expand Up @@ -1466,6 +1493,58 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
INFO_LOG(LOADER, "Config loaded: '%s'", iniFilename_.c_str());
}

bool Config::SaveControllerProfile(uint32_t id) {
IniFile iniFile;
if (!iniFile.Load(controllerIniFilename_)) {
ERROR_LOG(LOADER, "Error saving controller profile - can't read ini '%s'", controllerIniFilename_.c_str());
return false;
}

Section *section = iniFile.GetOrCreateSection(StringFromFormat("ControlProfile%uSettings", id).c_str());
for (auto &setting : controlSettings) {
setting.Set(section);
}

KeyMap::SaveToIni(iniFile, StringFromFormat("ControlProfile%uMapping", id).c_str());

if (!iniFile.Save(controllerIniFilename_)) {
ERROR_LOG(LOADER, "Error saving controller profile - can't write ini '%s'", controllerIniFilename_.c_str());
return false;
}

return true;
}

bool Config::ControllerProfileExist(uint32_t id) {
IniFile iniFile;
if (!iniFile.Load(controllerIniFilename_)) {
ERROR_LOG(LOADER, "Error checking controller profile - can't read ini '%s'", controllerIniFilename_.c_str());
return false;
}

return iniFile.HasSection(StringFromFormat("ControlProfile%uSettings", id).c_str());
}

bool Config::LoadControllerProfile(uint32_t id) {
IniFile iniFile;
if (!iniFile.Load(controllerIniFilename_)) {
ERROR_LOG(LOADER, "Error loading controller profile - can't read ini '%s'", controllerIniFilename_.c_str());
return false;
}

if (!iniFile.HasSection(StringFromFormat("ControlProfile%uSettings", id).c_str()))
return false;

Section *section = iniFile.GetOrCreateSection(StringFromFormat("ControlProfile%uSettings", id).c_str());
for (auto &setting : controlSettings) {
setting.Get(section);
}

KeyMap::LoadFromIni(iniFile, StringFromFormat("ControlProfile%uMapping", id).c_str());

return true;
}

bool Config::Save(const char *saveReason) {
if (!IsFirstInstance()) {
// TODO: Should we allow saving config if started from a different directory?
Expand Down Expand Up @@ -1944,6 +2023,12 @@ bool Config::loadGameConfig(const std::string &pGameId, const std::string &title
}
});

if (g_Config.uSettingsVersion == 0) {
g_Config.uSettingsVersion = 1;

loadOldControlSettings(iniFile);
}

KeyMap::LoadFromIni(iniFile);

if (!appendedConfigFileName_.ToString().empty() &&
Expand Down
4 changes: 4 additions & 0 deletions Core/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ struct Config {
bool bEnableLogging;
bool bDumpDecryptedEboot;
bool bFullscreenOnDoubleclick;
uint32_t uSettingsVersion;

// These four are Win UI only
bool bPauseOnLostFocus;
Expand Down Expand Up @@ -521,6 +522,9 @@ struct Config {

void Load(const char *iniFileName = nullptr, const char *controllerIniFilename = nullptr);
bool Save(const char *saveReason);
bool SaveControllerProfile(uint32_t id);
bool LoadControllerProfile(uint32_t id);
bool ControllerProfileExist(uint32_t id);
void Reload();
void RestoreDefaults(RestoreSettingsBits whatToRestore);

Expand Down
16 changes: 11 additions & 5 deletions Core/KeyMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,12 @@ const KeyMap_IntStrPair psp_button_names[] = {
{CTRL_VOL_DOWN, "Vol -"},
{CTRL_SCREEN, "Screen"},
{CTRL_NOTE, "Note"},

{VIRTKEY_CONTROLLER_PROFILE_1, "Load control profile 1"},
{VIRTKEY_CONTROLLER_PROFILE_2, "Load control profile 2"},
{VIRTKEY_CONTROLLER_PROFILE_3, "Load control profile 3"},
{VIRTKEY_CONTROLLER_PROFILE_4, "Load control profile 4"},
{VIRTKEY_CONTROLLER_PROFILE_5, "Load control profile 5"},
};

static std::string FindName(int key, const KeyMap_IntStrPair list[], size_t size) {
Expand Down Expand Up @@ -685,13 +691,13 @@ void RestoreDefault() {
}

// TODO: Make the ini format nicer.
void LoadFromIni(IniFile &file) {
void LoadFromIni(IniFile &file, const char *section) {
RestoreDefault();
if (!file.HasSection("ControlMapping")) {
if (!file.HasSection("ControlMapping")) { // Only on default section
return;
}

Section *controls = file.GetOrCreateSection("ControlMapping");
Section *controls = file.GetOrCreateSection(section);
for (size_t i = 0; i < ARRAY_SIZE(psp_button_names); i++) {
std::string value;
controls->Get(psp_button_names[i].name, &value, "");
Expand All @@ -717,8 +723,8 @@ void LoadFromIni(IniFile &file) {
UpdateNativeMenuKeys();
}

void SaveToIni(IniFile &file) {
Section *controls = file.GetOrCreateSection("ControlMapping");
void SaveToIni(IniFile &file, const char *section) {
Section *controls = file.GetOrCreateSection(section);

for (size_t i = 0; i < ARRAY_SIZE(psp_button_names); i++) {
std::vector<MultiInputMapping> keys;
Expand Down
9 changes: 7 additions & 2 deletions Core/KeyMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ enum {
VIRTKEY_SPEED_ANALOG = 0x40000024,
VIRTKEY_VR_CAMERA_ADJUST = 0x40000025,
VIRTKEY_VR_CAMERA_RESET = 0x40000026,
VIRTKEY_CONTROLLER_PROFILE_1 = 0x40000027,
VIRTKEY_CONTROLLER_PROFILE_2 = 0x40000028,
VIRTKEY_CONTROLLER_PROFILE_3 = 0x40000029,
VIRTKEY_CONTROLLER_PROFILE_4 = 0x4000002A,
VIRTKEY_CONTROLLER_PROFILE_5 = 0x4000002B,
VIRTKEY_LAST,
VIRTKEY_COUNT = VIRTKEY_LAST - VIRTKEY_FIRST
};
Expand Down Expand Up @@ -190,8 +195,8 @@ namespace KeyMap {

MappedAnalogAxes MappedAxesForDevice(int deviceId);

void LoadFromIni(IniFile &iniFile);
void SaveToIni(IniFile &iniFile);
void LoadFromIni(IniFile &iniFile, const char *section = "ControlMapping");
void SaveToIni(IniFile &iniFile, const char *section = "ControlMapping");
void ClearAllMappings();
void DeleteNthMapping(int key, int number);

Expand Down
20 changes: 20 additions & 0 deletions UI/EmuScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,26 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) {
if (down)
g_Config.iInternalScreenRotation = ROTATION_LOCKED_HORIZONTAL180;
break;
case VIRTKEY_CONTROLLER_PROFILE_1:
g_Config.LoadControllerProfile(1);
RecreateViews();
break;
case VIRTKEY_CONTROLLER_PROFILE_2:
g_Config.LoadControllerProfile(2);
RecreateViews();
break;
case VIRTKEY_CONTROLLER_PROFILE_3:
g_Config.LoadControllerProfile(3);
RecreateViews();
break;
case VIRTKEY_CONTROLLER_PROFILE_4:
g_Config.LoadControllerProfile(4);
RecreateViews();
break;
case VIRTKEY_CONTROLLER_PROFILE_5:
g_Config.LoadControllerProfile(5);
RecreateViews();
break;
}
}

Expand Down
57 changes: 57 additions & 0 deletions UI/GameSettingsScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,11 @@ void GameSettingsScreen::CreateControlsSettings(UI::ViewGroup *controlsSettings)
controlsSettings->Add(new Choice(co->T("Control Mapping")))->OnClick.Handle(this, &GameSettingsScreen::OnControlMapping);
controlsSettings->Add(new Choice(co->T("Calibrate Analog Stick")))->OnClick.Handle(this, &GameSettingsScreen::OnCalibrateAnalogs);

controlsSettings->Add(new Choice(co->T("Control Profiles")))->OnClick.Add([=](EventParams &e) {
screenManager()->push(new ControllerProfileScreen());
return UI::EVENT_DONE;
});

#if defined(USING_WIN_UI)
controlsSettings->Add(new CheckBox(&g_Config.bSystemControls, co->T("Enable standard shortcut keys")));
controlsSettings->Add(new CheckBox(&g_Config.bGamepadOnlyFocused, co->T("Ignore gamepads when not focused")));
Expand Down Expand Up @@ -2241,3 +2246,55 @@ void RestoreSettingsScreen::OnCompleted(DialogResult result) {
g_Config.RestoreDefaults((RestoreSettingsBits)restoreFlags_);
}
}
void ControllerProfileScreen::CreateViews() {
using namespace UI;

auto co = GetI18NCategory("Controls");

root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
AddStandardBack(root_);
TabHolder *tabHolder = new TabHolder(ORIENT_VERTICAL, 200, new AnchorLayoutParams(10, 0, 10, 0, false));
root_->Add(tabHolder);
ScrollView *rightPanel = new ScrollView(ORIENT_VERTICAL);
tabHolder->AddTab(co->T("Profiles"), rightPanel);
LinearLayout *vert = rightPanel->Add(new LinearLayout(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, FILL_PARENT)));
vert->SetSpacing(0);

float leftSide = 40.0f;
if (g_display.dp_yres <= g_display.dp_xres * 1.1f) {
leftSide += 200.0f;
}
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));
settingInfo_->SetBottomCutoff(g_display.dp_yres - 200.0f);
root_->Add(settingInfo_);

static constexpr int MAX_PROFILE = 5; // Should we have 5 with binding for fast selection and unlimited just to have them?
for (int i = 1; i <= MAX_PROFILE; ++i) {
vert->Add(new ItemHeader(ReplaceAll(co->T("Profile %1"), "%1", std::to_string(i))));

Choice *save = new Choice(co->T("Save current control settings"));
Choice *load = new Choice(co->T("Load control profile"));

load->OnClick.Add([=](EventParams &e) {
if (g_Config.LoadControllerProfile(i))
settingInfo_->Show(co->T("Control profile loaded"), e.v);

return UI::EVENT_CONTINUE;
});

save->OnClick.Add([=](EventParams &e) {
if (g_Config.SaveControllerProfile(i)) {
settingInfo_->Show(co->T("Control profile saved"), e.v);
load->SetEnabled(true);
}

return UI::EVENT_CONTINUE;
});

// Not a func to avoid Android slow IO problems
load->SetEnabled(g_Config.ControllerProfileExist(i));
vert->Add(save);
vert->Add(load);
}
}

9 changes: 9 additions & 0 deletions UI/GameSettingsScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,3 +265,12 @@ class RestoreSettingsScreen : public PopupScreen {
void OnCompleted(DialogResult result) override;
int restoreFlags_ = (int)(RestoreSettingsBits::SETTINGS); // RestoreSettingsBits enum
};

class ControllerProfileScreen : public UIDialogScreenWithBackground {
public:
void CreateViews() override;

const char *tag() const override { return "ControllerProfile"; }
private:
SettingInfoMessage *settingInfo_;
};
Loading