diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp index b6468ed85c..988af2a885 100644 --- a/Source/Android/jni/MainAndroid.cpp +++ b/Source/Android/jni/MainAndroid.cpp @@ -193,6 +193,14 @@ void Host_YieldToUI() { } +void Host_UpdateWiimoteExtension(int, int) +{ +} + +void Host_UpdateWiimoteMotionPlus(int, bool) +{ +} + void Host_TitleChanged() { s_game_metadata_is_valid = true; diff --git a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp index 2c510fb394..67dee9216d 100644 --- a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp @@ -604,7 +604,7 @@ ExtensionNumber Wiimote::GetActiveExtensionNumber() const bool Wiimote::IsMotionPlusAttached() const { - return m_is_motion_plus_attached; + return m_motion_plus_setting.GetValue(); } } // namespace WiimoteEmu diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp index a93ad379e8..44205a04e1 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp @@ -22,6 +22,7 @@ #include "Core/Config/MainSettings.h" #include "Core/Core.h" #include "Core/HW/Wiimote.h" +#include "Core/Host.h" #include "Core/Movie.h" #include "Core/System.h" @@ -269,7 +270,7 @@ Wiimote::Wiimote(const unsigned int index) : m_index(index), m_bt_device_index(i m_hotkeys->AddInput(_trans("Upright Hold"), false); // Extension - groups.emplace_back(m_attachments = new ControllerEmu::Attachments(_trans("Extension"))); + groups.emplace_back(m_attachments = new ControllerEmu::Attachments(_trans("Extension"), index)); m_attachments->AddAttachment(std::make_unique()); m_attachments->AddAttachment(std::make_unique()); m_attachments->AddAttachment(std::make_unique()); @@ -282,6 +283,8 @@ Wiimote::Wiimote(const unsigned int index) : m_index(index), m_bt_device_index(i m_attachments->AddAttachment(std::make_unique()); m_attachments->AddSetting(&m_motion_plus_setting, {_trans("Attach MotionPlus")}, true); + m_motion_plus_setting.AddCallback( + [index](const bool attached) { Host_UpdateWiimoteMotionPlus(index, attached); }); // Rumble groups.emplace_back(m_rumble = new ControllerEmu::ControlGroup(_trans("Rumble"))); diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h index e364ccdb6c..883d733633 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h @@ -308,7 +308,7 @@ private: ControllerEmu::SettingValue m_sideways_setting; ControllerEmu::SettingValue m_upright_setting; ControllerEmu::SettingValue m_battery_setting; - ControllerEmu::SettingValue m_motion_plus_setting; + ControllerEmu::SubscribableSettingValue m_motion_plus_setting; ControllerEmu::SettingValue m_fov_x_setting; ControllerEmu::SettingValue m_fov_y_setting; diff --git a/Source/Core/Core/Host.h b/Source/Core/Core/Host.h index 5fc1fc1ee9..f4037f10bd 100644 --- a/Source/Core/Core/Host.h +++ b/Source/Core/Core/Host.h @@ -66,6 +66,8 @@ void Host_JitProfileDataWiped(); void Host_UpdateMainFrame(); void Host_UpdateTitle(const std::string& title); void Host_YieldToUI(); +void Host_UpdateWiimoteExtension(int controller, int extension); +void Host_UpdateWiimoteMotionPlus(int controller, bool attached); void Host_TitleChanged(); void Host_UpdateDiscordClientID(const std::string& client_id = {}); diff --git a/Source/Core/DolphinNoGUI/MainNoGUI.cpp b/Source/Core/DolphinNoGUI/MainNoGUI.cpp index 539bbe769f..ced8b25cb2 100644 --- a/Source/Core/DolphinNoGUI/MainNoGUI.cpp +++ b/Source/Core/DolphinNoGUI/MainNoGUI.cpp @@ -132,6 +132,14 @@ void Host_YieldToUI() { } +void Host_UpdateWiimoteExtension(int, int) +{ +} + +void Host_UpdateWiimoteMotionPlus(int, bool) +{ +} + void Host_TitleChanged() { #ifdef USE_DISCORD_PRESENCE diff --git a/Source/Core/DolphinQt/Host.cpp b/Source/Core/DolphinQt/Host.cpp index a81924cfd8..72a20273e6 100644 --- a/Source/Core/DolphinQt/Host.cpp +++ b/Source/Core/DolphinQt/Host.cpp @@ -298,6 +298,22 @@ void Host_RefreshDSPDebuggerWindow() { } +void Host_UpdateWiimoteExtension(const int controller, const int extension) +{ + Settings& settings = Settings::Instance(); + QueueOnObject(&settings, [&settings, controller, extension] { + settings.UpdateWiimoteExtension(controller, extension); + }); +} + +void Host_UpdateWiimoteMotionPlus(const int controller, const bool attached) +{ + Settings& settings = Settings::Instance(); + QueueOnObject(&settings, [&settings, controller, attached] { + settings.UpdateWiimoteMotionPlus(controller, attached); + }); +} + void Host_TitleChanged() { #ifdef USE_DISCORD_PRESENCE diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 93ad16a59e..606503e980 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -519,6 +519,15 @@ void MainWindow::CreateComponents() &MemoryWidget::SetAddress); connect(m_cheats_manager, &CheatsManager::ShowMemory, m_memory_widget, &MemoryWidget::SetAddress); connect(m_cheats_manager, &CheatsManager::RequestWatch, request_watch); + + connect(&Settings::Instance(), &Settings::UpdateWiimoteExtension, + [this](const int controller_number, const int extension_index) { + m_wii_tas_input_windows[controller_number]->UpdateExtension(extension_index); + }); + connect(&Settings::Instance(), &Settings::UpdateWiimoteMotionPlus, + [this](const int controller_number, const bool attached) { + m_wii_tas_input_windows[controller_number]->UpdateMotionPlus(attached); + }); } void MainWindow::ConnectMenuBar() diff --git a/Source/Core/DolphinQt/Settings.h b/Source/Core/DolphinQt/Settings.h index ad7be608c3..2b2fdde182 100644 --- a/Source/Core/DolphinQt/Settings.h +++ b/Source/Core/DolphinQt/Settings.h @@ -224,6 +224,8 @@ signals: void USBKeyboardConnectionChanged(bool connected); void EnableGfxModsChanged(bool enabled); void HardcoreStateChanged(); + void UpdateWiimoteExtension(int controller_number, int extension_index); + void UpdateWiimoteMotionPlus(int controller_number, bool attached); private: Settings(); diff --git a/Source/Core/DolphinQt/TAS/WiiTASInputWindow.cpp b/Source/Core/DolphinQt/TAS/WiiTASInputWindow.cpp index 08c3431fd8..478d85e54b 100644 --- a/Source/Core/DolphinQt/TAS/WiiTASInputWindow.cpp +++ b/Source/Core/DolphinQt/TAS/WiiTASInputWindow.cpp @@ -347,32 +347,6 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : TASInputWindow( layout->addWidget(m_settings_box); setLayout(layout); - - if (Core::IsRunning(Core::System::GetInstance())) - { - m_active_extension = GetWiimote()->GetActiveExtensionNumber(); - m_is_motion_plus_attached = GetWiimote()->IsMotionPlusAttached(); - } - else - { - Common::IniFile ini; - ini.Load(File::GetUserPath(D_CONFIG_IDX) + "WiimoteNew.ini"); - const std::string section_name = "Wiimote" + std::to_string(num + 1); - - std::string extension; - ini.GetIfExists(section_name, "Extension", &extension); - - if (extension == "Nunchuk") - m_active_extension = WiimoteEmu::ExtensionNumber::NUNCHUK; - else if (extension == "Classic") - m_active_extension = WiimoteEmu::ExtensionNumber::CLASSIC; - else - m_active_extension = WiimoteEmu::ExtensionNumber::NONE; - - m_is_motion_plus_attached = true; - ini.GetIfExists(section_name, "Extension/Attach MotionPlus", &m_is_motion_plus_attached); - } - UpdateExt(); } WiimoteEmu::Wiimote* WiiTASInputWindow::GetWiimote() @@ -392,7 +366,60 @@ WiimoteEmu::Extension* WiiTASInputWindow::GetExtension() GetAttachments()->GetAttachmentList()[m_active_extension].get()); } -void WiiTASInputWindow::UpdateExt() +void WiiTASInputWindow::UpdateExtension(const int extension) +{ + const auto new_extension = static_cast(extension); + if (new_extension == m_active_extension) + return; + + m_active_extension = new_extension; + + UpdateControlVisibility(); + UpdateInputOverrideFunction(); +} + +void WiiTASInputWindow::UpdateMotionPlus(const bool attached) +{ + if (attached == m_is_motion_plus_attached) + return; + + m_is_motion_plus_attached = attached; + + UpdateControlVisibility(); +} + +void WiiTASInputWindow::LoadExtensionAndMotionPlus() +{ + if (Core::IsRunning(Core::System::GetInstance())) + { + m_active_extension = GetWiimote()->GetActiveExtensionNumber(); + m_is_motion_plus_attached = GetWiimote()->IsMotionPlusAttached(); + } + else + { + Common::IniFile ini; + ini.Load(File::GetUserPath(D_CONFIG_IDX) + "WiimoteNew.ini"); + const std::string section_name = "Wiimote" + std::to_string(m_num + 1); + + std::string extension; + ini.GetIfExists(section_name, "Extension", &extension); + + if (extension == "Nunchuk") + m_active_extension = WiimoteEmu::ExtensionNumber::NUNCHUK; + else if (extension == "Classic") + m_active_extension = WiimoteEmu::ExtensionNumber::CLASSIC; + else + m_active_extension = WiimoteEmu::ExtensionNumber::NONE; + + m_is_motion_plus_attached = true; + ini.GetIfExists(section_name, "Extension/Attach MotionPlus", &m_is_motion_plus_attached); + } + + UpdateControlVisibility(); + UpdateInputOverrideFunction(); +} + +void WiiTASInputWindow::UpdateControlVisibility() { if (m_active_extension == WiimoteEmu::ExtensionNumber::NUNCHUK) { @@ -451,17 +478,31 @@ void WiiTASInputWindow::UpdateExt() m_nunchuk_buttons_box->hide(); m_classic_buttons_box->hide(); } + + // Without these calls, switching between attachments can result in the Stick/IRWidgets being + // surrounded by large amounts of empty space in one dimension. + adjustSize(); + resize(sizeHint()); } -void WiiTASInputWindow::hideEvent(QHideEvent* event) +void WiiTASInputWindow::hideEvent(QHideEvent* const event) { GetWiimote()->ClearInputOverrideFunction(); GetExtension()->ClearInputOverrideFunction(); + + TASInputWindow::hideEvent(event); } -void WiiTASInputWindow::showEvent(QShowEvent* event) +void WiiTASInputWindow::showEvent(QShowEvent* const event) { - WiimoteEmu::Wiimote* wiimote = GetWiimote(); + LoadExtensionAndMotionPlus(); + + TASInputWindow::showEvent(event); +} + +void WiiTASInputWindow::UpdateInputOverrideFunction() +{ + WiimoteEmu::Wiimote* const wiimote = GetWiimote(); if (m_active_extension != WiimoteEmu::ExtensionNumber::CLASSIC) wiimote->SetInputOverrideFunction(m_wiimote_overrider.GetInputOverrideFunction()); diff --git a/Source/Core/DolphinQt/TAS/WiiTASInputWindow.h b/Source/Core/DolphinQt/TAS/WiiTASInputWindow.h index a77c38bb4c..2380afe617 100644 --- a/Source/Core/DolphinQt/TAS/WiiTASInputWindow.h +++ b/Source/Core/DolphinQt/TAS/WiiTASInputWindow.h @@ -34,12 +34,17 @@ public: void hideEvent(QHideEvent* event) override; void showEvent(QShowEvent* event) override; + void UpdateExtension(int extension); + void UpdateMotionPlus(bool attached); + private: WiimoteEmu::Wiimote* GetWiimote(); ControllerEmu::Attachments* GetAttachments(); WiimoteEmu::Extension* GetExtension(); - void UpdateExt(); + void LoadExtensionAndMotionPlus(); + void UpdateControlVisibility(); + void UpdateInputOverrideFunction(); WiimoteEmu::ExtensionNumber m_active_extension; bool m_is_motion_plus_attached; diff --git a/Source/Core/DolphinTool/ToolHeadlessPlatform.cpp b/Source/Core/DolphinTool/ToolHeadlessPlatform.cpp index 59495a7d43..c874b1e6c6 100644 --- a/Source/Core/DolphinTool/ToolHeadlessPlatform.cpp +++ b/Source/Core/DolphinTool/ToolHeadlessPlatform.cpp @@ -105,6 +105,14 @@ void Host_YieldToUI() { } +void Host_UpdateWiimoteExtension(int, int) +{ +} + +void Host_UpdateWiimoteMotionPlus(int, bool) +{ +} + void Host_TitleChanged() { } diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Attachments.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Attachments.cpp index 42e1acff5b..991dd0f222 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Attachments.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Attachments.cpp @@ -3,10 +3,15 @@ #include "InputCommon/ControllerEmu/ControlGroup/Attachments.h" +#include "Core/Host.h" + namespace ControllerEmu { -Attachments::Attachments(const std::string& name_) : ControlGroup(name_, GroupType::Attachments) +Attachments::Attachments(const std::string& name_, const int index) + : ControlGroup(name_, GroupType::Attachments) { + m_selection_value.AddCallback( + [index](const int extension) { Host_UpdateWiimoteExtension(index, extension); }); } void Attachments::AddAttachment(std::unique_ptr att) diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Attachments.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Attachments.h index 7553639396..1d0cc95183 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Attachments.h +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Attachments.h @@ -21,7 +21,7 @@ namespace ControllerEmu class Attachments : public ControlGroup { public: - explicit Attachments(const std::string& name); + explicit Attachments(const std::string& name, int index); void AddAttachment(std::unique_ptr att); @@ -33,7 +33,7 @@ public: const std::vector>& GetAttachmentList() const; private: - SettingValue m_selection_value; + SubscribableSettingValue m_selection_value; // This is here and not added to the list of numeric_settings because it's serialized differently, // by string (to be independent from the enum), and visualized differently in the UI. // For the rest, it's treated similarly to other numeric_settings in the group. diff --git a/Source/Core/InputCommon/ControllerEmu/Setting/NumericSetting.h b/Source/Core/InputCommon/ControllerEmu/Setting/NumericSetting.h index 863e211cae..87b63f5c1a 100644 --- a/Source/Core/InputCommon/ControllerEmu/Setting/NumericSetting.h +++ b/Source/Core/InputCommon/ControllerEmu/Setting/NumericSetting.h @@ -3,7 +3,10 @@ #pragma once +#include #include +#include +#include #include #include "Common/CommonTypes.h" @@ -173,7 +176,8 @@ class SettingValue friend class NumericSetting; public: - ValueType GetValue() const + virtual ~SettingValue() = default; + virtual ValueType GetValue() const { // Only update dynamic values when the input gate is enabled. // Otherwise settings will all change to 0 when window focus is lost. @@ -184,9 +188,11 @@ public: return m_value; } + ValueType GetCachedValue() const { return m_value; } + bool IsSimpleValue() const { return m_input.GetExpression().empty(); } - void SetValue(ValueType value) + virtual void SetValue(const ValueType value) { m_value = value; @@ -202,4 +208,76 @@ private: mutable InputReference m_input; }; +template +class SubscribableSettingValue final : public SettingValue +{ +public: + using Base = SettingValue; + + ValueType GetValue() const override + { + const ValueType cached_value = this->GetCachedValue(); + if (this->IsSimpleValue()) + return cached_value; + + const ValueType updated_value = Base::GetValue(); + if (updated_value != cached_value) + TriggerCallbacks(); + + return updated_value; + } + + void SetValue(const ValueType value) override + { + if (!this->IsSimpleValue() || (value != this->GetCachedValue())) + { + Base::SetValue(value); + TriggerCallbacks(); + } + } + + struct CallbackID + { + size_t id; + + bool operator==(const CallbackID&) const = default; + }; + + using SettingChangedCallback = std::function; + + CallbackID AddCallback(const SettingChangedCallback& callback) + { + const CallbackID callback_id{.id = m_next_callback_id}; + ++m_next_callback_id; + + std::lock_guard lock(m_mutex); + m_callback_pairs.emplace_back(callback_id, callback); + + return callback_id; + } + + void RemoveCallback(const CallbackID& id) + { + std::lock_guard lock(m_mutex); + const auto iter = std::ranges::find(m_callback_pairs, id, &IDCallbackPair::first); + if (iter != m_callback_pairs.end()) + m_callback_pairs.erase(iter); + } + + void TriggerCallbacks() const + { + const ValueType value = Base::GetValue(); + std::lock_guard lock(m_mutex); + for (const auto& pair : m_callback_pairs) + pair.second(value); + } + +private: + using IDCallbackPair = std::pair; + std::vector m_callback_pairs; + size_t m_next_callback_id = 0; + + mutable std::mutex m_mutex; +}; + } // namespace ControllerEmu diff --git a/Source/DSPTool/StubHost.cpp b/Source/DSPTool/StubHost.cpp index eb263d904c..f741f5254a 100644 --- a/Source/DSPTool/StubHost.cpp +++ b/Source/DSPTool/StubHost.cpp @@ -75,6 +75,12 @@ bool Host_TASInputHasFocus() void Host_YieldToUI() { } +void Host_UpdateWiimoteExtension(int, int) +{ +} +void Host_UpdateWiimoteMotionPlus(int, bool) +{ +} void Host_TitleChanged() { } diff --git a/Source/UnitTests/StubHost.cpp b/Source/UnitTests/StubHost.cpp index ffbb0c41c2..33a70b08e4 100644 --- a/Source/UnitTests/StubHost.cpp +++ b/Source/UnitTests/StubHost.cpp @@ -79,6 +79,12 @@ bool Host_TASInputHasFocus() void Host_YieldToUI() { } +void Host_UpdateWiimoteExtension(int, int) +{ +} +void Host_UpdateWiimoteMotionPlus(int, bool) +{ +} void Host_TitleChanged() { }