VMManager: Rewrite input profile hotkey priority logic

This commit is contained in:
Stenzek 2024-05-15 23:29:01 +10:00 committed by Connor McLaughlin
parent 967a41c035
commit 55ee8242cc
8 changed files with 96 additions and 73 deletions

View File

@ -528,7 +528,7 @@ void MainWindow::recreate()
new_main_window->activateWindow(); new_main_window->activateWindow();
// Reload the sources we just closed. // Reload the sources we just closed.
g_emu_thread->reloadInputSources(); g_emu_thread->applySettings();
if (was_display_created) if (was_display_created)
{ {

View File

@ -679,14 +679,7 @@ void EmuThread::reloadInputSources()
return; return;
} }
std::unique_lock<std::mutex> lock = Host::GetSettingsLock(); VMManager::ReloadInputSources();
SettingsInterface* si = Host::GetSettingsInterface();
SettingsInterface* bindings_si = Host::GetSettingsInterfaceForBindings();
InputManager::ReloadSources(*si, lock);
// skip loading bindings if we're not running, since it'll get done on startup anyway
if (VMManager::HasValidVM())
InputManager::ReloadBindings(*si, *bindings_si);
} }
void EmuThread::reloadInputBindings() void EmuThread::reloadInputBindings()
@ -697,14 +690,7 @@ void EmuThread::reloadInputBindings()
return; return;
} }
// skip loading bindings if we're not running, since it'll get done on startup anyway VMManager::ReloadInputBindings();
if (!VMManager::HasValidVM())
return;
auto lock = Host::GetSettingsLock();
SettingsInterface* si = Host::GetSettingsInterface();
SettingsInterface* bindings_si = Host::GetSettingsInterfaceForBindings();
InputManager::ReloadBindings(*si, *bindings_si);
} }
void EmuThread::reloadInputDevices() void EmuThread::reloadInputDevices()

View File

@ -172,12 +172,6 @@ SettingsInterface* Host::GetSettingsInterface()
return &s_layered_settings_interface; return &s_layered_settings_interface;
} }
SettingsInterface* Host::GetSettingsInterfaceForBindings()
{
SettingsInterface* input_layer = s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_INPUT);
return input_layer ? input_layer : &s_layered_settings_interface;
}
std::string Host::GetBaseStringSettingValue(const char* section, const char* key, const char* default_value /*= ""*/) std::string Host::GetBaseStringSettingValue(const char* section, const char* key, const char* default_value /*= ""*/)
{ {
std::unique_lock lock(s_settings_mutex); std::unique_lock lock(s_settings_mutex);
@ -378,14 +372,12 @@ void Host::Internal::SetBaseSettingsLayer(SettingsInterface* sif)
s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_BASE, sif); s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_BASE, sif);
} }
void Host::Internal::SetGameSettingsLayer(SettingsInterface* sif) void Host::Internal::SetGameSettingsLayer(SettingsInterface* sif, std::unique_lock<std::mutex>& settings_lock)
{ {
std::unique_lock lock(s_settings_mutex);
s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_GAME, sif); s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_GAME, sif);
} }
void Host::Internal::SetInputSettingsLayer(SettingsInterface* sif) void Host::Internal::SetInputSettingsLayer(SettingsInterface* sif, std::unique_lock<std::mutex>& settings_lock)
{ {
std::unique_lock lock(s_settings_mutex);
s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_INPUT, sif); s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_INPUT, sif);
} }

View File

@ -128,10 +128,6 @@ namespace Host
std::unique_lock<std::mutex> GetSettingsLock(); std::unique_lock<std::mutex> GetSettingsLock();
SettingsInterface* GetSettingsInterface(); SettingsInterface* GetSettingsInterface();
/// Returns the settings interface that controller bindings should be loaded from.
/// If an input profile is being used, this will be the input layer, otherwise the layered interface.
SettingsInterface* GetSettingsInterfaceForBindings();
/// Sets host-specific default settings. /// Sets host-specific default settings.
void SetDefaultUISettings(SettingsInterface& si); void SetDefaultUISettings(SettingsInterface& si);
@ -150,10 +146,10 @@ namespace Host
void SetBaseSettingsLayer(SettingsInterface* sif); void SetBaseSettingsLayer(SettingsInterface* sif);
/// Sets the game settings layer. Called by VMManager when the game changes. /// Sets the game settings layer. Called by VMManager when the game changes.
void SetGameSettingsLayer(SettingsInterface* sif); void SetGameSettingsLayer(SettingsInterface* sif, std::unique_lock<std::mutex>& settings_lock);
/// Sets the input profile settings layer. Called by VMManager when the game changes. /// Sets the input profile settings layer. Called by VMManager when the game changes.
void SetInputSettingsLayer(SettingsInterface* sif); void SetInputSettingsLayer(SettingsInterface* sif, std::unique_lock<std::mutex>& settings_lock);
/// Implementation to retrieve a translated string. /// Implementation to retrieve a translated string.
s32 GetTranslatedStringImpl(const std::string_view context, const std::string_view msg, char* tbuf, size_t tbuf_space); s32 GetTranslatedStringImpl(const std::string_view context, const std::string_view msg, char* tbuf, size_t tbuf_space);

View File

@ -1374,7 +1374,7 @@ bool InputManager::DoEventHook(InputBindingKey key, float value)
// Binding Updater // Binding Updater
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& binding_si) void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& binding_si, SettingsInterface& hotkey_binding_si)
{ {
PauseVibration(); PauseVibration();
@ -1386,8 +1386,7 @@ void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& bind
s_pointer_move_callbacks.clear(); s_pointer_move_callbacks.clear();
// Hotkeys use the base configuration, except if the custom hotkeys option is enabled. // Hotkeys use the base configuration, except if the custom hotkeys option is enabled.
const bool use_profile_hotkeys = si.GetBoolValue("Pad", "UseProfileHotkeyBindings", false); AddHotkeyBindings(hotkey_binding_si);
AddHotkeyBindings(use_profile_hotkeys ? binding_si : si);
// If there's an input profile, we load pad bindings from it alone, rather than // If there's an input profile, we load pad bindings from it alone, rather than
// falling back to the base configuration. // falling back to the base configuration.

View File

@ -228,7 +228,7 @@ namespace InputManager
bool IsInputSourceEnabled(SettingsInterface& si, InputSourceType type); bool IsInputSourceEnabled(SettingsInterface& si, InputSourceType type);
/// Re-parses the config and registers all hotkey and pad bindings. /// Re-parses the config and registers all hotkey and pad bindings.
void ReloadBindings(SettingsInterface& si, SettingsInterface& binding_si); void ReloadBindings(SettingsInterface& si, SettingsInterface& binding_si, SettingsInterface& hotkey_binding_si);
/// Re-parses the sources part of the config and initializes any backends. /// Re-parses the sources part of the config and initializes any backends.
void ReloadSources(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock); void ReloadSources(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock);

View File

@ -125,8 +125,9 @@ namespace VMManager
s32 slot_for_message); s32 slot_for_message);
static void LoadSettings(); static void LoadSettings();
static void LoadCoreSettings(SettingsInterface* si); static void LoadCoreSettings(SettingsInterface& si);
static void ApplyCoreSettings(); static void ApplyCoreSettings();
static void LoadInputBindings(SettingsInterface& si, std::unique_lock<std::mutex>& lock);
static void UpdateInhibitScreensaver(bool allow); static void UpdateInhibitScreensaver(bool allow);
static void AccumulateSessionPlaytime(); static void AccumulateSessionPlaytime();
static void ResetResumeTimestamp(); static void ResetResumeTimestamp();
@ -578,11 +579,11 @@ void VMManager::LoadSettings()
std::unique_lock<std::mutex> lock = Host::GetSettingsLock(); std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
SettingsInterface* si = Host::GetSettingsInterface(); SettingsInterface* si = Host::GetSettingsInterface();
LoadCoreSettings(si); LoadCoreSettings(*si);
Pad::LoadConfig(*si); Pad::LoadConfig(*si);
Host::LoadSettings(*si, lock); Host::LoadSettings(*si, lock);
InputManager::ReloadSources(*si, lock); InputManager::ReloadSources(*si, lock);
InputManager::ReloadBindings(*si, *Host::GetSettingsInterfaceForBindings()); LoadInputBindings(*si, lock);
UpdateLoggingSettings(*si); UpdateLoggingSettings(*si);
if (HasValidOrInitializingVM()) if (HasValidOrInitializingVM())
@ -592,9 +593,33 @@ void VMManager::LoadSettings()
} }
} }
void VMManager::LoadCoreSettings(SettingsInterface* si) void VMManager::ReloadInputSources()
{ {
SettingsLoadWrapper slw(*si); FPControlRegisterBackup fpcr_backup(FPControlRegister::GetDefault());
std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
SettingsInterface* si = Host::GetSettingsInterface();
InputManager::ReloadSources(*si, lock);
// skip loading bindings if we're not running, since it'll get done on startup anyway
if (HasValidVM())
LoadInputBindings(*si, lock);
}
void VMManager::ReloadInputBindings()
{
// skip loading bindings if we're not running, since it'll get done on startup anyway
if (!HasValidVM())
return;
FPControlRegisterBackup fpcr_backup(FPControlRegister::GetDefault());
std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
SettingsInterface* si = Host::GetSettingsInterface();
LoadInputBindings(*si, lock);
}
void VMManager::LoadCoreSettings(SettingsInterface& si)
{
SettingsLoadWrapper slw(si);
EmuConfig.LoadSave(slw); EmuConfig.LoadSave(slw);
Patch::ApplyPatchSettingOverrides(); Patch::ApplyPatchSettingOverrides();
@ -610,6 +635,35 @@ void VMManager::LoadCoreSettings(SettingsInterface* si)
EmuConfig.Speedhacks.vuThread = false; EmuConfig.Speedhacks.vuThread = false;
} }
void VMManager::LoadInputBindings(SettingsInterface& si, std::unique_lock<std::mutex>& lock)
{
// Hotkeys use the base configuration, except if the custom hotkeys option is enabled.
if (SettingsInterface* isi = Host::Internal::GetInputSettingsLayer())
{
const bool use_profile_hotkeys = isi->GetBoolValue("Pad", "UseProfileHotkeyBindings", false);
if (use_profile_hotkeys)
{
InputManager::ReloadBindings(si, *isi, *isi);
}
else
{
// Temporarily disable the input profile layer, so it doesn't take precedence.
Host::Internal::SetInputSettingsLayer(nullptr, lock);
InputManager::ReloadBindings(si, *isi, si);
Host::Internal::SetInputSettingsLayer(s_input_settings_interface.get(), lock);
}
}
else if (SettingsInterface* gsi = Host::Internal::GetGameSettingsLayer();
gsi && gsi->GetBoolValue("Pad", "UseGameSettingsForController", false))
{
InputManager::ReloadBindings(si, *gsi, si);
}
else
{
InputManager::ReloadBindings(si, si, si);
}
}
void VMManager::ApplyGameFixes() void VMManager::ApplyGameFixes()
{ {
if (!HasBootedELF() && !GSDumpReplayer::IsReplayingDump()) if (!HasBootedELF() && !GSDumpReplayer::IsReplayingDump())
@ -678,7 +732,7 @@ void VMManager::ApplyCoreSettings()
{ {
FPControlRegisterBackup fpcr_backup(FPControlRegister::GetDefault()); FPControlRegisterBackup fpcr_backup(FPControlRegister::GetDefault());
std::unique_lock<std::mutex> lock = Host::GetSettingsLock(); std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
LoadCoreSettings(Host::GetSettingsInterface()); LoadCoreSettings(*Host::GetSettingsInterface());
WarnAboutUnsafeSettings(); WarnAboutUnsafeSettings();
ApplyGameFixes(); ApplyGameFixes();
} }
@ -879,53 +933,42 @@ bool VMManager::UpdateGameSettingsLayer()
} }
std::string input_profile_name; std::string input_profile_name;
bool use_game_settings_for_controller = false;
if (new_interface) if (new_interface)
{ {
new_interface->GetBoolValue("Pad", "UseGameSettingsForController", &use_game_settings_for_controller); if (!new_interface->GetBoolValue("Pad", "UseGameSettingsForController", false))
if (!use_game_settings_for_controller)
new_interface->GetStringValue("EmuCore", "InputProfileName", &input_profile_name); new_interface->GetStringValue("EmuCore", "InputProfileName", &input_profile_name);
} }
if (!s_game_settings_interface && !new_interface && s_input_profile_name == input_profile_name) if (!s_game_settings_interface && !new_interface && s_input_profile_name == input_profile_name)
return false; return false;
Host::Internal::SetGameSettingsLayer(new_interface.get()); auto lock = Host::GetSettingsLock();
Host::Internal::SetGameSettingsLayer(new_interface.get(), lock);
s_game_settings_interface = std::move(new_interface); s_game_settings_interface = std::move(new_interface);
std::unique_ptr<INISettingsInterface> input_interface; std::unique_ptr<INISettingsInterface> input_interface;
if (!use_game_settings_for_controller) if (!input_profile_name.empty())
{ {
if (!input_profile_name.empty()) const std::string filename(GetInputProfilePath(input_profile_name));
if (FileSystem::FileExists(filename.c_str()))
{ {
const std::string filename(GetInputProfilePath(input_profile_name)); Console.WriteLn("Loading input profile from '%s'...", filename.c_str());
if (FileSystem::FileExists(filename.c_str())) input_interface = std::make_unique<INISettingsInterface>(std::move(filename));
if (!input_interface->Load())
{ {
Console.WriteLn("Loading input profile from '%s'...", filename.c_str()); Console.Error("Failed to parse input profile ini '%s'", input_interface->GetFileName().c_str());
input_interface = std::make_unique<INISettingsInterface>(std::move(filename)); input_interface.reset();
if (!input_interface->Load())
{
Console.Error("Failed to parse input profile ini '%s'", input_interface->GetFileName().c_str());
input_interface.reset();
input_profile_name = {};
}
}
else
{
DevCon.WriteLn("No game settings found (tried '%s')", filename.c_str());
input_profile_name = {}; input_profile_name = {};
} }
} }
else
Host::Internal::SetInputSettingsLayer( {
input_interface ? input_interface.get() : Host::Internal::GetBaseSettingsLayer()); DevCon.WriteLn("No game settings found (tried '%s')", filename.c_str());
} input_profile_name = {};
else }
{
// using game settings for bindings too
Host::Internal::SetInputSettingsLayer(s_game_settings_interface.get());
} }
Host::Internal::SetInputSettingsLayer(input_interface.get(), lock);
s_input_settings_interface = std::move(input_interface); s_input_settings_interface = std::move(input_interface);
s_input_profile_name = std::move(input_profile_name); s_input_profile_name = std::move(input_profile_name);
return true; return true;
@ -1725,7 +1768,7 @@ bool VMManager::DoLoadState(const char* filename)
Error error; Error error;
if (!SaveState_UnzipFromDisk(filename, &error)) if (!SaveState_UnzipFromDisk(filename, &error))
{ {
Host::ReportErrorAsync(TRANSLATE_SV("VMManager","Failed to load save state"), error.GetDescription()); Host::ReportErrorAsync(TRANSLATE_SV("VMManager", "Failed to load save state"), error.GetDescription());
return false; return false;
} }
@ -2285,7 +2328,8 @@ inline void LogUserPowerPlan()
" Power Profile = '{}'\n" " Power Profile = '{}'\n"
" Power States (min/max)\n" " Power States (min/max)\n"
" AC = {}% / {}%\n" " AC = {}% / {}%\n"
" Battery = {}% / {}%\n", friendlyName.c_str(), acMin, acMax, dcMin, dcMax); " Battery = {}% / {}%\n",
friendlyName.c_str(), acMin, acMax, dcMin, dcMax);
} }
#endif #endif

View File

@ -110,6 +110,12 @@ namespace VMManager
/// Reloads game patches. /// Reloads game patches.
void ReloadPatches(bool reload_files, bool reload_enabled_list, bool verbose, bool verbose_if_changed); void ReloadPatches(bool reload_files, bool reload_enabled_list, bool verbose, bool verbose_if_changed);
/// Reloads input sources.
void ReloadInputSources();
/// Reloads input bindings.
void ReloadInputBindings();
/// Returns the save state filename for the given game serial/crc. /// Returns the save state filename for the given game serial/crc.
std::string GetSaveStateFileName(const char* game_serial, u32 game_crc, s32 slot); std::string GetSaveStateFileName(const char* game_serial, u32 game_crc, s32 slot);