Skip to content

Commit e7cd5f6

Browse files
CarterLiCopilot
andcommitted
Bluetooth (Windows): uses CM API to detect BTH battery detection
Co-authored-by: Copilot <copilot@github.com>
1 parent 55e4896 commit e7cd5f6

3 files changed

Lines changed: 93 additions & 111 deletions

File tree

CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1038,7 +1038,6 @@ elseif(WIN32)
10381038
src/detection/battery/battery_windows.c
10391039
src/detection/bios/bios_windows.c
10401040
src/detection/bluetooth/bluetooth_windows.c
1041-
src/detection/bluetooth/bluetooth_windows.cpp
10421041
src/detection/bluetoothradio/bluetoothradio_windows.c
10431042
src/detection/board/board_windows.c
10441043
src/detection/bootmgr/bootmgr_windows.c

src/detection/bluetooth/bluetooth_windows.c

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,102 @@
11
#include "bluetooth.h"
22
#include "common/library.h"
3+
#include "common/mallocHelper.h"
34
#include "common/windows/unicode.h"
45

6+
#define INITGUID
57
#include <windows.h>
68
#include <bluetoothapis.h>
9+
#include <cfgmgr32.h>
10+
#include <devpkey.h>
711

812
#pragma GCC diagnostic ignored "-Wpointer-sign"
913

14+
// https://github.com/wine-mirror/wine/blob/ab6f4584b89f28504b0b277c0b4c723a86b4d6b7/include/ddk/bthguid.h#L4
15+
/* DEVPROP_TYPE_STRING */
16+
DEFINE_DEVPROPKEY(DEVPKEY_Bluetooth_DeviceAddress, 0x2bd67d8b, 0x8beb, 0x48d5, 0x87, 0xe0, 0x6c, 0xda, 0x34, 0x28, 0x04, 0x0a, 1);
17+
/* DEVPROP_TYPE_UINT32 */
18+
DEFINE_DEVPROPKEY(DEVPKEY_Bluetooth_ClassOfDevice, 0x2bd67d8b, 0x8beb, 0x48d5, 0x87, 0xe0, 0x6c, 0xda, 0x34, 0x28, 0x04, 0x0a, 10);
19+
/* DEVPROP_TYPE_FILETIME */
20+
DEFINE_DEVPROPKEY(DEVPKEY_Bluetooth_LastConnectedTime, 0x2bd67d8b, 0x8beb, 0x48d5, 0x87, 0xe0, 0x6c, 0xda, 0x34, 0x28, 0x04, 0x0a, 11);
21+
/* DEVPROP_TYPE_GUID */
22+
DEFINE_DEVPROPKEY(DEVPKEY_Bluetooth_ServiceGUID, 0x2bd67d8b, 0x8beb, 0x48d5, 0x87, 0xe0, 0x6c, 0xda, 0x34, 0x28, 0x04, 0x0a, 2);
23+
/* DEVPROP_TYPE_UINT8 */
24+
DEFINE_DEVPROPKEY(DEVPKEY_Bluetooth_BatteryLevel, 0x104ea319, 0x6ee2, 0x4701, 0xbd, 0x47, 0x8d, 0xdb, 0xf4, 0x25, 0xbb, 0xe5, 2);
25+
26+
// TODO: use CM API to fetch bluetooth devices instead of BluetoothFindFirstDevice, if we find DEVPKEY_Bluetooth_IsConnected or similar
27+
#define GUID_DEVCLASS_BLUETOOTH_STRING L"{e0cbf06c-cd8b-4647-bb8a-263b43f0f974}" // Found in <devguid.h>
28+
#define GUID_DEVCLASS_MEDIA_STRING L"{4d36e96c-e325-11ce-bfc1-08002be10318}" // Found in <devguid.h>
29+
30+
static const char* ffBluetoothDetectBattery(FFlist* devices) {
31+
ULONG idListLength = 0;
32+
CONFIGRET status = CM_Get_Device_ID_List_SizeW(&idListLength, GUID_DEVCLASS_MEDIA_STRING, CM_GETIDLIST_FILTER_PRESENT);
33+
if (status != CR_SUCCESS) {
34+
return "CM_Get_Device_ID_List_SizeW failed";
35+
}
36+
37+
if (idListLength == 0) {
38+
return NULL;
39+
}
40+
41+
wchar_t* FF_AUTO_FREE idList = (wchar_t*) malloc((size_t) idListLength * sizeof(wchar_t));
42+
if (!idList) {
43+
return "malloc() failed";
44+
}
45+
46+
status = CM_Get_Device_ID_ListW(GUID_DEVCLASS_MEDIA_STRING, idList, idListLength, CM_GETIDLIST_FILTER_PRESENT);
47+
if (status != CR_SUCCESS) {
48+
return "CM_Get_Device_ID_ListW failed";
49+
}
50+
51+
for (const wchar_t* deviceId = idList; *deviceId; deviceId += wcslen(deviceId) + 1) {
52+
DEVINST devInst = 0;
53+
54+
// Hands-Free profile service; headsets often expose battery level through this media device node rather than the Bluetooth device node
55+
// BthHFEnum
56+
if (CM_Locate_DevNodeW(&devInst, (DEVINSTID_W) deviceId, CM_LOCATE_DEVNODE_NORMAL) != CR_SUCCESS) {
57+
continue;
58+
}
59+
60+
uint8_t battery = 0;
61+
{
62+
DEVPROPTYPE devPropertyType = DEVPROP_TYPE_EMPTY;
63+
ULONG propertySize = sizeof(battery);
64+
if (CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_Bluetooth_BatteryLevel, &devPropertyType, (PBYTE) &battery, &propertySize, 0) != CR_SUCCESS || devPropertyType != DEVPROP_TYPE_BYTE || propertySize != sizeof(battery)) {
65+
continue;
66+
}
67+
}
68+
69+
WCHAR deviceAddress[13]; // 6 bytes in hex + null terminator
70+
{
71+
DEVPROPTYPE devPropertyType = DEVPROP_TYPE_EMPTY;
72+
ULONG propertySize = sizeof(deviceAddress);
73+
if (CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_Bluetooth_DeviceAddress, &devPropertyType, (PBYTE) deviceAddress, &propertySize, 0) != CR_SUCCESS || devPropertyType != DEVPROP_TYPE_STRING || propertySize != sizeof(deviceAddress)) {
74+
continue;
75+
}
76+
}
77+
78+
FF_LIST_FOR_EACH (FFBluetoothResult, bt, *devices) {
79+
if (deviceAddress[0] == bt->address.chars[0] &&
80+
deviceAddress[1] == bt->address.chars[1] &&
81+
deviceAddress[2] == bt->address.chars[3] &&
82+
deviceAddress[3] == bt->address.chars[4] &&
83+
deviceAddress[4] == bt->address.chars[6] &&
84+
deviceAddress[5] == bt->address.chars[7] &&
85+
deviceAddress[6] == bt->address.chars[9] &&
86+
deviceAddress[7] == bt->address.chars[10] &&
87+
deviceAddress[8] == bt->address.chars[12] &&
88+
deviceAddress[9] == bt->address.chars[13] &&
89+
deviceAddress[10] == bt->address.chars[15] &&
90+
deviceAddress[11] == bt->address.chars[16]) {
91+
bt->battery = battery;
92+
break;
93+
}
94+
}
95+
}
96+
97+
return NULL;
98+
}
99+
10100
const char* ffDetectBluetooth(FFBluetoothOptions* options, FFlist* devices /* FFBluetoothResult */) {
11101
FF_LIBRARY_LOAD_MESSAGE(bluetoothapis, "bluetoothapis.dll", 1)
12102
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindFirstDevice)
@@ -125,8 +215,9 @@ const char* ffDetectBluetooth(FFBluetoothOptions* options, FFlist* devices /* FF
125215

126216
ffBluetoothFindDeviceClose(hFind);
127217

128-
const char* ffBluetoothDetectBattery(FFlist * result);
129-
ffBluetoothDetectBattery(devices);
218+
if (devices->length > 0) {
219+
ffBluetoothDetectBattery(devices);
220+
}
130221

131222
return NULL;
132223
}

src/detection/bluetooth/bluetooth_windows.cpp

Lines changed: 0 additions & 108 deletions
This file was deleted.

0 commit comments

Comments
 (0)