FrontendCommon: Add input profile support
This commit is contained in:
parent
193763b4aa
commit
f75ea052a6
|
@ -694,6 +694,7 @@ void HostInterface::InitializeUserDirectory()
|
||||||
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("cache").c_str(), false);
|
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("cache").c_str(), false);
|
||||||
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("dump").c_str(), false);
|
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("dump").c_str(), false);
|
||||||
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("dump/audio").c_str(), false);
|
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("dump/audio").c_str(), false);
|
||||||
|
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("inputprofiles").c_str(), false);
|
||||||
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("savestates").c_str(), false);
|
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("savestates").c_str(), false);
|
||||||
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("screenshots").c_str(), false);
|
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("screenshots").c_str(), false);
|
||||||
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("memcards").c_str(), false);
|
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("memcards").c_str(), false);
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "sdl_audio_stream.h"
|
#include "sdl_audio_stream.h"
|
||||||
#include "sdl_controller_interface.h"
|
#include "sdl_controller_interface.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "ini_settings_interface.h"
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
Log_SetChannel(CommonHostInterface);
|
Log_SetChannel(CommonHostInterface);
|
||||||
|
@ -794,3 +795,153 @@ void CommonHostInterface::RegisterSaveStateHotkeys()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, std::string>> CommonHostInterface::GetInputProfileList() const
|
||||||
|
{
|
||||||
|
FileSystem::FindResultsArray results;
|
||||||
|
FileSystem::FindFiles(GetUserDirectoryRelativePath("inputprofiles").c_str(), "*.ini",
|
||||||
|
FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_RELATIVE_PATHS, &results);
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, std::string>> profile_names;
|
||||||
|
profile_names.reserve(results.size());
|
||||||
|
for (auto& it : results)
|
||||||
|
{
|
||||||
|
if (it.FileName.size() < 4)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::string profile_name = it.FileName.substr(0, it.FileName.length() - 4);
|
||||||
|
std::string full_filename = GetUserDirectoryRelativePath("inputprofiles/%s", it.FileName.c_str());
|
||||||
|
profile_names.emplace_back(std::move(profile_name), std::move(full_filename));
|
||||||
|
}
|
||||||
|
|
||||||
|
return profile_names;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommonHostInterface::ClearAllControllerBindings(SettingsInterface& si)
|
||||||
|
{
|
||||||
|
for (u32 controller_index = 1; controller_index <= NUM_CONTROLLER_AND_CARD_PORTS; controller_index++)
|
||||||
|
{
|
||||||
|
const ControllerType ctype = m_settings.controller_types[controller_index - 1];
|
||||||
|
if (ctype == ControllerType::None)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto section_name = TinyString::FromFormat("Controller%u", controller_index);
|
||||||
|
|
||||||
|
si.DeleteValue(section_name, "Type");
|
||||||
|
|
||||||
|
for (const auto& button : Controller::GetButtonNames(ctype))
|
||||||
|
si.DeleteValue(section_name, button.first.c_str());
|
||||||
|
|
||||||
|
for (const auto& axis : Controller::GetAxisNames(ctype))
|
||||||
|
si.DeleteValue(section_name, axis.first.c_str());
|
||||||
|
|
||||||
|
if (Controller::GetVibrationMotorCount(ctype) > 0)
|
||||||
|
si.DeleteValue(section_name, "Rumble");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommonHostInterface::ApplyInputProfile(const char* profile_path, SettingsInterface& si)
|
||||||
|
{
|
||||||
|
// clear bindings for all controllers
|
||||||
|
ClearAllControllerBindings(si);
|
||||||
|
|
||||||
|
INISettingsInterface profile(profile_path);
|
||||||
|
|
||||||
|
for (u32 controller_index = 1; controller_index <= NUM_CONTROLLER_AND_CARD_PORTS; controller_index++)
|
||||||
|
{
|
||||||
|
const auto section_name = TinyString::FromFormat("Controller%u", controller_index);
|
||||||
|
const std::string ctype_str = profile.GetStringValue(section_name, "Type");
|
||||||
|
if (ctype_str.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::optional<ControllerType> ctype = Settings::ParseControllerTypeName(ctype_str.c_str());
|
||||||
|
if (!ctype)
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Invalid controller type in profile: '%s'", ctype_str.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_settings.controller_types[controller_index - 1] = *ctype;
|
||||||
|
HostInterface::OnControllerTypeChanged(controller_index - 1);
|
||||||
|
|
||||||
|
si.SetStringValue(section_name, "Type", Settings::GetControllerTypeName(*ctype));
|
||||||
|
|
||||||
|
for (const auto& button : Controller::GetButtonNames(*ctype))
|
||||||
|
{
|
||||||
|
const auto key_name = TinyString::FromFormat("Button%s", button.first.c_str());
|
||||||
|
si.DeleteValue(section_name, key_name);
|
||||||
|
const std::vector<std::string> bindings = profile.GetStringList(section_name, key_name);
|
||||||
|
for (const std::string& binding : bindings)
|
||||||
|
si.AddToStringList(section_name, key_name, binding.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& axis : Controller::GetAxisNames(*ctype))
|
||||||
|
{
|
||||||
|
const auto key_name = TinyString::FromFormat("Axis%s", axis.first.c_str());
|
||||||
|
si.DeleteValue(section_name, axis.first.c_str());
|
||||||
|
const std::vector<std::string> bindings = profile.GetStringList(section_name, key_name);
|
||||||
|
for (const std::string& binding : bindings)
|
||||||
|
si.AddToStringList(section_name, key_name, binding.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
si.DeleteValue(section_name, "Rumble");
|
||||||
|
const std::string rumble_value = profile.GetStringValue(section_name, "Rumble");
|
||||||
|
if (!rumble_value.empty())
|
||||||
|
si.SetStringValue(section_name, "Rumble", rumble_value.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateInputMap(si);
|
||||||
|
|
||||||
|
if (m_system)
|
||||||
|
m_system->UpdateControllers();
|
||||||
|
|
||||||
|
ReportFormattedMessage("Loaded input profile from '%s'", profile_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CommonHostInterface::SaveInputProfile(const char* profile_path, SettingsInterface& si)
|
||||||
|
{
|
||||||
|
if (FileSystem::FileExists(profile_path))
|
||||||
|
{
|
||||||
|
if (!FileSystem::DeleteFile(profile_path))
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Failed to delete existing input profile '%s' when saving", profile_path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INISettingsInterface profile(profile_path);
|
||||||
|
|
||||||
|
for (u32 controller_index = 1; controller_index <= NUM_CONTROLLER_AND_CARD_PORTS; controller_index++)
|
||||||
|
{
|
||||||
|
const ControllerType ctype = m_settings.controller_types[controller_index - 1];
|
||||||
|
if (ctype == ControllerType::None)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto section_name = TinyString::FromFormat("Controller%u", controller_index);
|
||||||
|
|
||||||
|
profile.SetStringValue(section_name, "Type", Settings::GetControllerTypeName(ctype));
|
||||||
|
|
||||||
|
for (const auto& button : Controller::GetButtonNames(ctype))
|
||||||
|
{
|
||||||
|
const auto key_name = TinyString::FromFormat("Button%s", button.first.c_str());
|
||||||
|
const std::vector<std::string> bindings = si.GetStringList(section_name, key_name);
|
||||||
|
for (const std::string& binding : bindings)
|
||||||
|
profile.AddToStringList(section_name, key_name, binding.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& axis : Controller::GetAxisNames(ctype))
|
||||||
|
{
|
||||||
|
const auto key_name = TinyString::FromFormat("Axis%s", axis.first.c_str());
|
||||||
|
const std::vector<std::string> bindings = si.GetStringList(section_name, key_name);
|
||||||
|
for (const std::string& binding : bindings)
|
||||||
|
profile.AddToStringList(section_name, key_name, binding.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string rumble_value = si.GetStringValue(section_name, "Rumble");
|
||||||
|
if (!rumble_value.empty())
|
||||||
|
profile.SetStringValue(section_name, "Rumble", rumble_value.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
profile.Save();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -86,6 +86,15 @@ protected:
|
||||||
/// Reloads the input map from config. Callable from controller interface.
|
/// Reloads the input map from config. Callable from controller interface.
|
||||||
virtual void UpdateInputMap() = 0;
|
virtual void UpdateInputMap() = 0;
|
||||||
|
|
||||||
|
/// Returns a list of all input profiles. first - name, second - path
|
||||||
|
std::vector<std::pair<std::string, std::string>> GetInputProfileList() const;
|
||||||
|
|
||||||
|
/// Applies the specified input profile.
|
||||||
|
void ApplyInputProfile(const char* profile_path, SettingsInterface& si);
|
||||||
|
|
||||||
|
/// Saves the current input configuration to the specified profile name.
|
||||||
|
bool SaveInputProfile(const char* profile_path, SettingsInterface& si);
|
||||||
|
|
||||||
void RegisterHotkey(String category, String name, String display_name, InputButtonHandler handler);
|
void RegisterHotkey(String category, String name, String display_name, InputButtonHandler handler);
|
||||||
bool HandleHostKeyEvent(HostKeyCode code, bool pressed);
|
bool HandleHostKeyEvent(HostKeyCode code, bool pressed);
|
||||||
void UpdateInputMap(SettingsInterface& si);
|
void UpdateInputMap(SettingsInterface& si);
|
||||||
|
@ -102,6 +111,7 @@ private:
|
||||||
void RegisterSaveStateHotkeys();
|
void RegisterSaveStateHotkeys();
|
||||||
void UpdateControllerInputMap(SettingsInterface& si);
|
void UpdateControllerInputMap(SettingsInterface& si);
|
||||||
void UpdateHotkeyInputMap(SettingsInterface& si);
|
void UpdateHotkeyInputMap(SettingsInterface& si);
|
||||||
|
void ClearAllControllerBindings(SettingsInterface& si);
|
||||||
|
|
||||||
HotkeyInfoList m_hotkeys;
|
HotkeyInfoList m_hotkeys;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue