diff options
| author | Dentomologist <dentomologist@gmail.com> | 2026-01-08 12:19:36 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-08 12:19:36 -0800 |
| commit | fa374187d4bf37ceee958f5fb70c09297054c0ed (patch) | |
| tree | 22199397a1408ddd7d8d615c542fe6e78c851c52 /Source/Core | |
| parent | fb2a46c4cfa2687cd0191c00efaa4ce9431ca639 (diff) | |
| parent | cb07f9608ce7ab92deb139ac765486d6046c4821 (diff) | |
Merge pull request #14249 from jordan-woyak/iowin-check-bt-name
WiimoteReal/IOWin: Determine the Bluetooth name of HID interfaces to identify Balance Boards
Diffstat (limited to 'Source/Core')
| -rw-r--r-- | Source/Core/Core/HW/WiimoteReal/IOWin.cpp | 94 |
1 files changed, 68 insertions, 26 deletions
diff --git a/Source/Core/Core/HW/WiimoteReal/IOWin.cpp b/Source/Core/Core/HW/WiimoteReal/IOWin.cpp index c422e4abb1..cb1824e9e3 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOWin.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IOWin.cpp @@ -5,6 +5,7 @@ #include <algorithm> #include <array> +#include <bit> #include <optional> #include <vector> @@ -14,8 +15,11 @@ #include <Hidclass.h> #include <Hidsdi.h> #include <initguid.h> -// initguid.h must be included before Devpkey.h -#include <Devpkey.h> +#include <wtypes.h> +// initguid.h must be included before devpkey.h +#include <devpkey.h> +// wtypes.h must be included before propkey.h +#include <propkey.h> #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" @@ -125,7 +129,7 @@ std::optional<USBUtils::DeviceInfo> GetDeviceInfo(const WCHAR* hid_iface) return USBUtils::DeviceInfo{attributes.VendorID, attributes.ProductID}; } -static std::optional<std::string> GetParentDeviceDescription(const WCHAR* hid_iface) +static std::optional<DEVINST> GetInst(const WCHAR* hid_iface) { auto dev_inst_id = Common::GetDeviceInterfaceStringProperty(hid_iface, &DEVPKEY_Device_InstanceId); @@ -141,6 +145,11 @@ static std::optional<std::string> GetParentDeviceDescription(const WCHAR* hid_if return std::nullopt; } + return dev_inst; +} + +static std::optional<DEVINST> GetParentInst(DEVINST dev_inst) +{ DEVINST parent_inst{}; if (CM_Get_Parent(&parent_inst, dev_inst, 0) != CR_SUCCESS) { @@ -148,13 +157,39 @@ static std::optional<std::string> GetParentDeviceDescription(const WCHAR* hid_if return std::nullopt; } - const auto description = - Common::GetDevNodeStringProperty(parent_inst, &DEVPKEY_Device_BusReportedDeviceDesc); + return parent_inst; +} + +static std::optional<std::string> GetBluetoothName(DEVINST dev_inst) +{ + // Association Endpoint ID. + const auto aep_id_key = std::bit_cast<DEVPROPKEY>(PKEY_Devices_Aep_AepId); + + // This provides a string like "Bluetooth#Bluetoothbc:fc:e7:2d:83:72-d8:6b:f7:32:db:46". + const auto aep_id = Common::GetDevNodeStringProperty(dev_inst, &aep_id_key); + if (!aep_id.has_value()) + return std::nullopt; + + // Traverse all siblings and find the "Bluetooth" class device with a matching AepID. + const auto parent_inst = GetParentInst(dev_inst); + if (!parent_inst.has_value()) + return std::nullopt; - if (description.has_value()) - return WStringToUTF8(*description); + DEVINST child; + if (CM_Get_Child(&child, *parent_inst, 0) != CR_SUCCESS) + return std::nullopt; - return std::nullopt; + while (true) + { + if (Common::GetDevNodeStringProperty(child, &DEVPKEY_Device_Class) == L"Bluetooth" && + *aep_id == Common::GetDevNodeStringProperty(child, &aep_id_key)) + { + return Common::GetDevNodeStringProperty(child, &DEVPKEY_NAME).transform(WStringToUTF8); + } + + if (CM_Get_Sibling(&child, child, 0) != CR_SUCCESS) + return std::nullopt; + } } void EnumerateRadios(std::invocable<HANDLE> auto&& enumeration_callback) @@ -590,11 +625,21 @@ static std::vector<WiimoteScannerWindows::EnumeratedWiimoteInterface> GetAllWiim for (auto* hid_iface : Common::GetDeviceInterfaceList(&class_guid, nullptr, flags)) { - // When connected via Bluetooth, this has a proper name like "Nintendo RVL-CNT-01". - const auto parent_description = GetParentDeviceDescription(hid_iface); + DEBUG_LOG_FMT(WIIMOTE, "Found HID interface."); + + const auto parent_inst = GetInst(hid_iface).and_then(GetParentInst); - if (parent_description.has_value()) - DEBUG_LOG_FMT(WIIMOTE, "HID description: {}", *parent_description); + // This provies a proper name like "Nintendo RVL-CNT-01" or "Nintendo RVL-WBC-01". + const auto bluetooth_name = parent_inst.and_then(GetBluetoothName); + DEBUG_LOG_FMT(WIIMOTE, " BluetoothName: {}", bluetooth_name.value_or("<error>")); + + // For some reason, a Balance Board `BusReportedDeviceDesc` is "Nintendo RVL-CNT-01". + const auto device_description = + parent_inst + .and_then(std::bind_back(Common::GetDevNodeStringProperty, + &DEVPKEY_Device_BusReportedDeviceDesc)) + .transform(WStringToUTF8); + DEBUG_LOG_FMT(WIIMOTE, " BusReportedDeviceDesc: {}", device_description.value_or("<error>")); // Mayflash has confirmed in email that every revision of the DolphinBar // advertises this descriptor and a VID:PID of 057e:0306. @@ -611,28 +656,25 @@ static std::vector<WiimoteScannerWindows::EnumeratedWiimoteInterface> GetAllWiim std::optional<bool> is_balance_board; bool is_relevant_description = false; - if (parent_description.has_value()) + if (bluetooth_name.has_value()) { - if (IsBalanceBoardName(*parent_description)) + if (IsWiimoteName(*bluetooth_name)) { is_relevant_description = true; - is_balance_board = true; + is_balance_board = false; } - else if (IsWiimoteName(*parent_description)) - { - is_relevant_description = true; - - // For some reason, a Balance Board `BusReportedDeviceDesc` is "Nintendo RVL-CNT-01". - // TODO: Additional device tree shenanigans will be needed to observe "Nintendo RVL-WBC-01". - // The easiest way might be to find a BT device instance with a matching BDADDR. - // For now, we'll just always force the `Wiimote::IsBalanceBoard` check. - // is_balance_board = false; - } - else if (*parent_description == dolphinbar_device_description) + else if (IsBalanceBoardName(*bluetooth_name)) { is_relevant_description = true; + is_balance_board = true; } } + else if (device_description.has_value() && + (*device_description == dolphinbar_device_description || + IsValidDeviceName(*device_description))) + { + is_relevant_description = true; + } // Whelp, if the description didn't match, let's check the VID/PID ? // This is potentially unnecessary. Checking the description should be enough. |
