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.
This commit is contained in:
@@ -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(¬ify_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
|
} // namespace Common
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
#include <cfgmgr32.h>
|
#include <cfgmgr32.h>
|
||||||
#include <devpropdef.h>
|
#include <devpropdef.h>
|
||||||
|
|
||||||
|
#include "Common/Functional.h"
|
||||||
|
|
||||||
namespace Common
|
namespace Common
|
||||||
{
|
{
|
||||||
std::optional<std::wstring> GetDevNodeStringProperty(DEVINST device,
|
std::optional<std::wstring> GetDevNodeStringProperty(DEVINST device,
|
||||||
@@ -71,6 +73,33 @@ struct NullTerminatedStringList
|
|||||||
NullTerminatedStringList<WCHAR> GetDeviceInterfaceList(LPGUID iface_class_guid, DEVINSTID device_id,
|
NullTerminatedStringList<WCHAR> GetDeviceInterfaceList(LPGUID iface_class_guid, DEVINSTID device_id,
|
||||||
ULONG flags);
|
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
|
} // namespace Common
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
#include "Common/ScopeGuard.h"
|
#include "Common/ScopeGuard.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
#include "Common/Thread.h"
|
#include "Common/Thread.h"
|
||||||
#include "Common/WindowsDevice.h"
|
|
||||||
|
|
||||||
#include "Core/HW/WiimoteCommon/DataReport.h"
|
#include "Core/HW/WiimoteCommon/DataReport.h"
|
||||||
#include "Core/HW/WiimoteCommon/WiimoteConstants.h"
|
#include "Core/HW/WiimoteCommon/WiimoteConstants.h"
|
||||||
@@ -328,7 +327,12 @@ void WiimoteScannerWindows::RemoveRememberedWiimotes()
|
|||||||
NOTICE_LOG_FMT(WIIMOTE, "Removed remembered Wiimotes: {}", forget_count);
|
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()
|
void WiimoteScannerWindows::Update()
|
||||||
{
|
{
|
||||||
@@ -576,9 +580,9 @@ int WiimoteWindows::IOWrite(const u8* buf, size_t len)
|
|||||||
return write_result;
|
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.
|
// Enumerate connected HID interfaces IDs.
|
||||||
auto class_guid = GUID_DEVINTERFACE_HID;
|
auto class_guid = GUID_DEVINTERFACE_HID;
|
||||||
@@ -586,14 +590,6 @@ auto WiimoteScannerWindows::FindWiimoteHIDDevices() -> FindResults
|
|||||||
|
|
||||||
for (auto* hid_iface : Common::GetDeviceInterfaceList(&class_guid, nullptr, flags))
|
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".
|
// When connected via Bluetooth, this has a proper name like "Nintendo RVL-CNT-01".
|
||||||
const auto parent_description = GetParentDeviceDescription(hid_iface);
|
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.
|
// 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");
|
DEBUG_LOG_FMT(WIIMOTE, "Creating WiimoteWindows");
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,12 @@
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "Common/SocketContext.h"
|
#include "Common/SocketContext.h"
|
||||||
|
#include "Common/WindowsDevice.h"
|
||||||
|
|
||||||
#include "Core/HW/WiimoteReal/WiimoteReal.h"
|
#include "Core/HW/WiimoteReal/WiimoteReal.h"
|
||||||
#include "Core/USBUtils.h"
|
#include "Core/USBUtils.h"
|
||||||
|
|
||||||
@@ -50,6 +55,12 @@ private:
|
|||||||
class WiimoteScannerWindows final : public WiimoteScannerBackend
|
class WiimoteScannerWindows final : public WiimoteScannerBackend
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
struct EnumeratedWiimoteInterface
|
||||||
|
{
|
||||||
|
std::wstring hid_iface;
|
||||||
|
std::optional<bool> is_balance_board;
|
||||||
|
};
|
||||||
|
|
||||||
WiimoteScannerWindows();
|
WiimoteScannerWindows();
|
||||||
bool IsReady() const override;
|
bool IsReady() const override;
|
||||||
|
|
||||||
@@ -64,6 +75,12 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
FindResults FindWiimoteHIDDevices();
|
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
|
} // namespace WiimoteReal
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user