diff --git a/src/core/host.cpp b/src/core/host.cpp index 89c866a32..cf676c856 100644 --- a/src/core/host.cpp +++ b/src/core/host.cpp @@ -40,12 +40,6 @@ SettingsInterface* Host::GetSettingsInterface() 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::unique_lock lock(s_settings_mutex); @@ -241,15 +235,13 @@ void Host::Internal::SetBaseSettingsLayer(SettingsInterface* 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& lock) { - std::unique_lock lock(s_settings_mutex); s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_GAME, sif); } -void Host::Internal::SetInputSettingsLayer(SettingsInterface* sif) +void Host::Internal::SetInputSettingsLayer(SettingsInterface* sif, std::unique_lock& lock) { - std::unique_lock lock(s_settings_mutex); s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_INPUT, sif); } diff --git a/src/core/host.h b/src/core/host.h index 86576f045..b502e5ac7 100644 --- a/src/core/host.h +++ b/src/core/host.h @@ -70,10 +70,6 @@ std::vector GetStringListSetting(const char* section, const char* k std::unique_lock GetSettingsLock(); 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(); - /// Debugger feedback. void ReportDebuggerMessage(std::string_view message); void ReportFormattedDebuggerMessage(const char* format, ...); @@ -120,9 +116,9 @@ SettingsInterface* GetInputSettingsLayer(); void SetBaseSettingsLayer(SettingsInterface* sif); /// Sets the game settings layer. Called by VMManager when the game changes. -void SetGameSettingsLayer(SettingsInterface* sif); +void SetGameSettingsLayer(SettingsInterface* sif, std::unique_lock& lock); /// Sets the input profile settings layer. Called by VMManager when the game changes. -void SetInputSettingsLayer(SettingsInterface* sif); +void SetInputSettingsLayer(SettingsInterface* sif, std::unique_lock& lock); } // namespace Internal } // namespace Host diff --git a/src/core/system.cpp b/src/core/system.cpp index bbdfa9ea2..b5962ba31 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -96,6 +96,8 @@ SystemBootParameters::~SystemBootParameters() = default; namespace System { static std::optional InternalGetExtendedSaveStateInfo(ByteStream* stream); +static void LoadInputBindings(SettingsInterface& si, std::unique_lock& lock); + static bool LoadEXE(const char* filename); static std::string GetExecutableNameForImage(IsoReader& iso, bool strip_subdirectories); @@ -970,7 +972,7 @@ void System::LoadSettings(bool display_osd_messages) Host::LoadSettings(si, lock); InputManager::ReloadSources(si, lock); - InputManager::ReloadBindings(si, *Host::GetSettingsInterfaceForBindings()); + LoadInputBindings(si, lock); // apply compatibility settings if (g_settings.apply_compatibility_settings) @@ -993,6 +995,57 @@ void System::LoadSettings(bool display_osd_messages) g_settings.FixIncompatibleSettings(display_osd_messages); } +void System::ReloadInputSources() +{ + std::unique_lock 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 (IsValid()) + LoadInputBindings(*si, lock); +} + +void System::ReloadInputBindings() +{ + // skip loading bindings if we're not running, since it'll get done on startup anyway + if (!IsValid()) + return; + + std::unique_lock lock = Host::GetSettingsLock(); + SettingsInterface* si = Host::GetSettingsInterface(); + LoadInputBindings(*si, lock); +} + +void System::LoadInputBindings(SettingsInterface& si, std::unique_lock& 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("ControllerPorts", "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("ControllerPorts", "UseGameSettingsForController", false)) + { + InputManager::ReloadBindings(si, *gsi, si); + } + else + { + InputManager::ReloadBindings(si, si, si); + } +} + void System::SetDefaultSettings(SettingsInterface& si) { Settings temp; @@ -1072,53 +1125,42 @@ bool System::UpdateGameSettingsLayer() } std::string input_profile_name; - bool use_game_settings_for_controller = false; if (new_interface) { - new_interface->GetBoolValue("ControllerPorts", "UseGameSettingsForController", &use_game_settings_for_controller); - if (!use_game_settings_for_controller) + if (!new_interface->GetBoolValue("ControllerPorts", "UseGameSettingsForController", false)) new_interface->GetStringValue("ControllerPorts", "InputProfileName", &input_profile_name); } if (!s_game_settings_interface && !new_interface && s_input_profile_name == input_profile_name) 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); std::unique_ptr 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)); - if (FileSystem::FileExists(filename.c_str())) + Log_InfoFmt("Loading input profile from '{}'...", Path::GetFileName(filename)); + input_interface = std::make_unique(std::move(filename)); + if (!input_interface->Load()) { - Log_InfoPrintf("Loading input profile from '%s'...", filename.c_str()); - input_interface = std::make_unique(std::move(filename)); - if (!input_interface->Load()) - { - Log_ErrorPrintf("Failed to parse input profile ini '%s'", input_interface->GetFileName().c_str()); - input_interface.reset(); - input_profile_name = {}; - } - } - else - { - Log_InfoPrintf("No input profile found (tried '%s')", filename.c_str()); + Log_ErrorFmt("Failed to parse input profile ini '{}'", Path::GetFileName(input_interface->GetFileName())); + input_interface.reset(); input_profile_name = {}; } } - - Host::Internal::SetInputSettingsLayer(input_interface ? input_interface.get() : - Host::Internal::GetBaseSettingsLayer()); - } - else - { - // using game settings for bindings too - Host::Internal::SetInputSettingsLayer(s_game_settings_interface.get()); + else + { + Log_WarningFmt("No input profile found (tried '{}')", Path::GetFileName(filename)); + input_profile_name = {}; + } } + Host::Internal::SetInputSettingsLayer(input_interface.get(), lock); s_input_settings_interface = std::move(input_interface); s_input_profile_name = std::move(input_profile_name); return true; @@ -3084,7 +3126,7 @@ void System::UpdateControllers() std::unique_ptr controller = Controller::Create(type, i); if (controller) { - controller->LoadSettings(*Host::GetSettingsInterfaceForBindings(), Controller::GetSettingsSection(i).c_str()); + controller->LoadSettings(*Host::GetSettingsInterface(), Controller::GetSettingsSection(i).c_str()); Pad::SetController(i, std::move(controller)); } } @@ -3099,7 +3141,7 @@ void System::UpdateControllerSettings() { Controller* controller = Pad::GetController(i); if (controller) - controller->LoadSettings(*Host::GetSettingsInterfaceForBindings(), Controller::GetSettingsSection(i).c_str()); + controller->LoadSettings(*Host::GetSettingsInterface(), Controller::GetSettingsSection(i).c_str()); } } diff --git a/src/core/system.h b/src/core/system.h index b6f4fcbf8..860bffd77 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -245,6 +245,12 @@ void ApplySettings(bool display_osd_messages); /// Reloads game specific settings, and applys any changes present. bool ReloadGameSettings(bool display_osd_messages); +/// Reloads input sources. +void ReloadInputSources(); + +/// Reloads input bindings. +void ReloadInputBindings(); + bool BootSystem(SystemBootParameters parameters, Error* error); void PauseSystem(bool paused); void ResetSystem(); diff --git a/src/duckstation-qt/qthost.cpp b/src/duckstation-qt/qthost.cpp index 34ad8d1d5..a678fbf91 100644 --- a/src/duckstation-qt/qthost.cpp +++ b/src/duckstation-qt/qthost.cpp @@ -1030,11 +1030,7 @@ void EmuThread::reloadInputSources() return; } - std::unique_lock lock = Host::GetSettingsLock(); - SettingsInterface* si = Host::GetSettingsInterface(); - SettingsInterface* bindings_si = Host::GetSettingsInterfaceForBindings(); - InputManager::ReloadSources(*si, lock); - InputManager::ReloadBindings(*si, *bindings_si); + System::ReloadInputSources(); } void EmuThread::reloadInputBindings() @@ -1045,10 +1041,7 @@ void EmuThread::reloadInputBindings() return; } - auto lock = Host::GetSettingsLock(); - SettingsInterface* si = Host::GetSettingsInterface(); - SettingsInterface* bindings_si = Host::GetSettingsInterfaceForBindings(); - InputManager::ReloadBindings(*si, *bindings_si); + System::ReloadInputBindings(); } void EmuThread::reloadInputDevices() diff --git a/src/util/input_manager.cpp b/src/util/input_manager.cpp index df99c1825..49dd3de33 100644 --- a/src/util/input_manager.cpp +++ b/src/util/input_manager.cpp @@ -1320,9 +1320,10 @@ void InputManager::CopyConfiguration(SettingsInterface* dest_si, const SettingsI for (u32 i = 0; i < NUM_MACRO_BUTTONS_PER_CONTROLLER; i++) { - dest_si->CopyStringListValue(src_si, section.c_str(), fmt::format("Macro{}", i + 1).c_str()); - dest_si->CopyStringValue(src_si, section.c_str(), fmt::format("Macro{}Binds", i + 1).c_str()); - dest_si->CopyUIntValue(src_si, section.c_str(), fmt::format("Macro{}Frequency", i + 1).c_str()); + dest_si->CopyStringListValue(src_si, section.c_str(), TinyString::from_format("Macro{}", i + 1)); + dest_si->CopyStringValue(src_si, section.c_str(), TinyString::from_format("Macro{}Binds", i + 1)); + dest_si->CopyUIntValue(src_si, section.c_str(), TinyString::from_format("Macro{}Frequency", i + 1)); + dest_si->CopyBoolValue(src_si, section.c_str(), TinyString::from_format("Macro{}Toggle", i + 1)); } } @@ -1717,7 +1718,8 @@ bool InputManager::DoEventHook(InputBindingKey key, float value) // Binding Updater // ------------------------------------------------------------------------ -void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& binding_si) +void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& binding_si, + SettingsInterface& hotkey_binding_si) { PauseVibration(); @@ -1730,8 +1732,7 @@ void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& bind Host::AddFixedInputBindings(binding_si); // Hotkeys use the base configuration, except if the custom hotkeys option is enabled. - const bool use_profile_hotkeys = si.GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false); - AddHotkeyBindings(use_profile_hotkeys ? binding_si : si); + AddHotkeyBindings(hotkey_binding_si); // If there's an input profile, we load pad bindings from it alone, rather than // falling back to the base configuration. diff --git a/src/util/input_manager.h b/src/util/input_manager.h index 24bac4c64..e04b8d951 100644 --- a/src/util/input_manager.h +++ b/src/util/input_manager.h @@ -253,7 +253,7 @@ GenericInputBindingMapping GetGenericBindingMapping(std::string_view device); bool IsInputSourceEnabled(SettingsInterface& si, InputSourceType type); /// 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. void ReloadSources(SettingsInterface& si, std::unique_lock& settings_lock);