summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorJMC47 <JMC4789@gmail.com>2025-12-23 17:01:44 -0500
committerGitHub <noreply@github.com>2025-12-23 17:01:44 -0500
commit4b086b1256855be85873b9cee5b2bdd4efb91caf (patch)
tree00157dd8667f75efccb627aa8f001998c508d70a /Source/Core
parent0a3aac6d85d1e276755e4f1a4215eef567c1c85c (diff)
parentfc4cbf9c6fa76862b153d72baddde11edb8a3958 (diff)
Merge pull request #14223 from jordan-woyak/wmreal-windows-device-enumeration
HW/WiimoteReal: Cache the enumerated Wii remote HID interface list between calls to FindWiimoteHIDDevices.
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Common/WindowsDevice.cpp59
-rw-r--r--Source/Core/Common/WindowsDevice.h29
-rw-r--r--Source/Core/Core/HW/WiimoteReal/IOWin.cpp41
-rw-r--r--Source/Core/Core/HW/WiimoteReal/IOWin.h17
4 files changed, 134 insertions, 12 deletions
diff --git a/Source/Core/Common/WindowsDevice.cpp b/Source/Core/Common/WindowsDevice.cpp
index 4bbd213774..34a540ed7b 100644
--- a/Source/Core/Common/WindowsDevice.cpp
+++ b/Source/Core/Common/WindowsDevice.cpp
@@ -90,6 +90,65 @@ NullTerminatedStringList<WCHAR> GetDeviceInterfaceList(LPGUID iface_class_guid,
}
}
+static __callback DWORD OnDevicesChanged(_In_ HCMNOTIFICATION notify_handle, _In_opt_ PVOID context,
+ _In_ CM_NOTIFY_ACTION action,
+ _In_reads_bytes_(event_data_size)
+ PCM_NOTIFY_EVENT_DATA event_data,
+ _In_ DWORD event_data_size)
+{
+ auto& callback = *static_cast<DeviceChangeNotification::CallbackType*>(context);
+ switch (action)
+ {
+ case CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL:
+ callback(DeviceChangeNotification::EventType::Arrival);
+ break;
+ case CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL:
+ callback(DeviceChangeNotification::EventType::Removal);
+ break;
+ default:
+ break;
+ }
+ return ERROR_SUCCESS;
+}
+
+DeviceChangeNotification::DeviceChangeNotification() = default;
+
+DeviceChangeNotification::~DeviceChangeNotification()
+{
+ Unregister();
+}
+
+void DeviceChangeNotification::Register(CallbackType callback)
+{
+ Unregister();
+ m_callback = std::move(callback);
+
+ CM_NOTIFY_FILTER notify_filter{
+ .cbSize = sizeof(notify_filter),
+ .FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE,
+ .u{.DeviceInterface{.ClassGuid = GUID_DEVINTERFACE_HID}},
+ };
+ const CONFIGRET cfg_rv =
+ CM_Register_Notification(&notify_filter, &m_callback, OnDevicesChanged, &m_notify_handle);
+ if (cfg_rv != CR_SUCCESS)
+ {
+ ERROR_LOG_FMT(COMMON, "CM_Register_Notification failed: {:x}", cfg_rv);
+ }
+}
+
+void DeviceChangeNotification::Unregister()
+{
+ if (m_notify_handle == nullptr)
+ return;
+
+ const CONFIGRET cfg_rv = CM_Unregister_Notification(m_notify_handle);
+ if (cfg_rv != CR_SUCCESS)
+ {
+ ERROR_LOG_FMT(COMMON, "CM_Unregister_Notification failed: {:x}", cfg_rv);
+ }
+ m_notify_handle = nullptr;
+}
+
} // namespace Common
#endif
diff --git a/Source/Core/Common/WindowsDevice.h b/Source/Core/Common/WindowsDevice.h
index 8c682ac850..78e8234c15 100644
--- a/Source/Core/Common/WindowsDevice.h
+++ b/Source/Core/Common/WindowsDevice.h
@@ -22,6 +22,8 @@
#include <cfgmgr32.h>
#include <devpropdef.h>
+#include "Common/Functional.h"
+
namespace Common
{
std::optional<std::wstring> GetDevNodeStringProperty(DEVINST device,
@@ -71,6 +73,33 @@ struct NullTerminatedStringList
NullTerminatedStringList<WCHAR> GetDeviceInterfaceList(LPGUID iface_class_guid, DEVINSTID device_id,
ULONG flags);
+class DeviceChangeNotification
+{
+public:
+ enum class EventType : bool
+ {
+ Arrival,
+ Removal,
+ };
+ using CallbackType = Common::MoveOnlyFunction<void(EventType)>;
+
+ DeviceChangeNotification();
+ ~DeviceChangeNotification();
+
+ // FYI: Currently hardcoded to a GUID_DEVINTERFACE_HID filter.
+ void Register(CallbackType callback);
+ void Unregister();
+
+ DeviceChangeNotification(const DeviceChangeNotification&) = delete;
+ DeviceChangeNotification(DeviceChangeNotification&&) = delete;
+ void operator=(const DeviceChangeNotification&) = delete;
+ void operator=(DeviceChangeNotification&&) = delete;
+
+private:
+ CallbackType m_callback{};
+ HCMNOTIFICATION m_notify_handle{nullptr};
+};
+
} // namespace Common
#endif
diff --git a/Source/Core/Core/HW/WiimoteReal/IOWin.cpp b/Source/Core/Core/HW/WiimoteReal/IOWin.cpp
index e1cf4971e9..29a7ef2d45 100644
--- a/Source/Core/Core/HW/WiimoteReal/IOWin.cpp
+++ b/Source/Core/Core/HW/WiimoteReal/IOWin.cpp
@@ -24,7 +24,6 @@
#include "Common/ScopeGuard.h"
#include "Common/StringUtil.h"
#include "Common/Thread.h"
-#include "Common/WindowsDevice.h"
#include "Core/HW/WiimoteCommon/DataReport.h"
#include "Core/HW/WiimoteCommon/WiimoteConstants.h"
@@ -328,7 +327,12 @@ void WiimoteScannerWindows::RemoveRememberedWiimotes()
NOTICE_LOG_FMT(WIIMOTE, "Removed remembered Wiimotes: {}", forget_count);
}
-WiimoteScannerWindows::WiimoteScannerWindows() = default;
+WiimoteScannerWindows::WiimoteScannerWindows()
+{
+ m_device_change_notification.Register([this](Common::DeviceChangeNotification::EventType) {
+ m_devices_changed.store(true, std::memory_order_release);
+ });
+}
void WiimoteScannerWindows::Update()
{
@@ -576,9 +580,9 @@ int WiimoteWindows::IOWrite(const u8* buf, size_t len)
return write_result;
}
-auto WiimoteScannerWindows::FindWiimoteHIDDevices() -> FindResults
+static std::vector<WiimoteScannerWindows::EnumeratedWiimoteInterface> GetAllWiimoteHIDInterfaces()
{
- FindResults results;
+ std::vector<WiimoteScannerWindows::EnumeratedWiimoteInterface> results;
// Enumerate connected HID interfaces IDs.
auto class_guid = GUID_DEVINTERFACE_HID;
@@ -586,14 +590,6 @@ auto WiimoteScannerWindows::FindWiimoteHIDDevices() -> FindResults
for (auto* hid_iface : Common::GetDeviceInterfaceList(&class_guid, nullptr, flags))
{
- // TODO: WiimoteWindows::GetId() does a redundant conversion.
- const auto hid_iface_utf8 = WStringToUTF8(hid_iface);
- DEBUG_LOG_FMT(WIIMOTE, "Found HID interface: {}", hid_iface_utf8);
-
- // Are we already using this device?
- if (!IsNewWiimote(hid_iface_utf8))
- continue;
-
// When connected via Bluetooth, this has a proper name like "Nintendo RVL-CNT-01".
const auto parent_description = GetParentDeviceDescription(hid_iface);
@@ -650,6 +646,27 @@ auto WiimoteScannerWindows::FindWiimoteHIDDevices() -> FindResults
}
// Once here, we are confident that this is a Wii device.
+ results.push_back({hid_iface, is_balance_board});
+ }
+
+ return results;
+}
+
+auto WiimoteScannerWindows::FindWiimoteHIDDevices() -> FindResults
+{
+ if (m_devices_changed.exchange(false, std::memory_order_acquire))
+ {
+ m_wiimote_hid_interfaces = GetAllWiimoteHIDInterfaces();
+ INFO_LOG_FMT(WIIMOTE, "Found {} HID interface(s).", m_wiimote_hid_interfaces.size());
+ }
+
+ FindResults results;
+
+ for (auto& [hid_iface, is_balance_board] : m_wiimote_hid_interfaces)
+ {
+ // Are we already using this device?
+ if (!IsNewWiimote(WStringToUTF8(hid_iface)))
+ continue;
DEBUG_LOG_FMT(WIIMOTE, "Creating WiimoteWindows");
diff --git a/Source/Core/Core/HW/WiimoteReal/IOWin.h b/Source/Core/Core/HW/WiimoteReal/IOWin.h
index b8bc29a86f..aa7b426288 100644
--- a/Source/Core/Core/HW/WiimoteReal/IOWin.h
+++ b/Source/Core/Core/HW/WiimoteReal/IOWin.h
@@ -6,7 +6,12 @@
#ifdef _WIN32
#include <windows.h>
+#include <atomic>
+#include <vector>
+
#include "Common/SocketContext.h"
+#include "Common/WindowsDevice.h"
+
#include "Core/HW/WiimoteReal/WiimoteReal.h"
#include "Core/USBUtils.h"
@@ -50,6 +55,12 @@ private:
class WiimoteScannerWindows final : public WiimoteScannerBackend
{
public:
+ struct EnumeratedWiimoteInterface
+ {
+ std::wstring hid_iface;
+ std::optional<bool> is_balance_board;
+ };
+
WiimoteScannerWindows();
bool IsReady() const override;
@@ -64,6 +75,12 @@ public:
private:
FindResults FindWiimoteHIDDevices();
+
+ // This vector is updated after we receive a device change notification.
+ std::vector<EnumeratedWiimoteInterface> m_wiimote_hid_interfaces;
+ std::atomic_bool m_devices_changed{true};
+
+ Common::DeviceChangeNotification m_device_change_notification;
};
} // namespace WiimoteReal