1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
#pragma once
#pragma comment(lib, "cfgmgr32.lib")
#include <string>
#include <system_error>
#include <vector>
#include <Windows.h>
#include <cfgmgr32.h>
#include <initguid.h> // needed for devpkey.h to parse properly
#include <devpkey.h>
// Returns an empty string on failure
//
// interface names from GetRawInputDeviceInfo are not guaranteed to be valid;
// CM_Get_Device_Interface_PropertyW can return CR_NO_SUCH_DEVICE_INTERFACE
std::wstring dev_id_from_interface(const WCHAR* interface_name) {
ULONG size = 0;
DEVPROPTYPE type;
CONFIGRET cm_res;
cm_res = CM_Get_Device_Interface_PropertyW(interface_name, &DEVPKEY_Device_InstanceId,
&type, NULL, &size, 0);
if (cm_res != CR_BUFFER_SMALL && cm_res != CR_SUCCESS) return {};
std::wstring id((size + 1) / 2, L'\0');
cm_res = CM_Get_Device_Interface_PropertyW(interface_name, &DEVPKEY_Device_InstanceId,
&type, reinterpret_cast<PBYTE>(&id[0]), &size, 0);
if (cm_res != CR_SUCCESS) return {};
auto instance_delim_pos = id.find_last_of('\\');
if (instance_delim_pos != std::string::npos) {
id.resize(instance_delim_pos);
}
return id;
}
template <typename Func>
void rawinput_foreach_with_interface(Func fn, DWORD input_type = RIM_TYPEMOUSE) {
const UINT RI_ERROR = -1;
UINT num_devs = 0;
if (GetRawInputDeviceList(NULL, &num_devs, sizeof(RAWINPUTDEVICELIST)) == RI_ERROR) {
throw std::system_error(GetLastError(), std::system_category(), "GetRawInputDeviceList failed");
}
auto devs = std::vector<RAWINPUTDEVICELIST>(num_devs);
if (GetRawInputDeviceList(&devs[0], &num_devs, sizeof(RAWINPUTDEVICELIST)) == RI_ERROR) {
throw std::system_error(GetLastError(), std::system_category(), "GetRawInputDeviceList failed");
}
std::wstring name;
UINT len;
for (auto&& dev : devs) {
if (dev.dwType != input_type) continue;
// get required length
if (GetRawInputDeviceInfoW(dev.hDevice, RIDI_DEVICENAME, NULL, &len) == RI_ERROR) {
continue;
}
name.resize(len);
if (GetRawInputDeviceInfoW(dev.hDevice, RIDI_DEVICENAME, &name[0], &len) == RI_ERROR) {
continue;
}
fn(dev, &name[0]);
}
}
// returns device handles corresponding to a "device id"
// https://docs.microsoft.com/en-us/windows-hardware/drivers/install/device-ids
std::vector<HANDLE> rawinput_handles_from_dev_id(const std::wstring& device_id, DWORD input_type = RIM_TYPEMOUSE) {
std::vector<HANDLE> handles;
rawinput_foreach_with_interface([&](const auto& dev, const WCHAR* name) {
auto id = dev_id_from_interface(name);
if (!id.empty() && id == device_id) {
handles.push_back(dev.hDevice);
}
}, input_type);
return handles;
}
|