|
2 | 2 |
|
3 | 3 | #pragma comment(lib, "cfgmgr32.lib")
|
4 | 4 |
|
| 5 | +#include <algorithm> |
5 | 6 | #include <string>
|
6 | 7 | #include <system_error>
|
7 | 8 | #include <vector>
|
|
11 | 12 | #include <initguid.h> // needed for devpkey.h to parse properly
|
12 | 13 | #include <devpkey.h>
|
13 | 14 |
|
14 |
| -std::wstring dev_prop_wstr_from_interface(const WCHAR* interface_name, const DEVPROPKEY* key) { |
15 |
| - ULONG size = 0; |
16 |
| - DEVPROPTYPE type; |
17 |
| - CONFIGRET cm_res; |
18 |
| - |
19 |
| - cm_res = CM_Get_Device_Interface_PropertyW(interface_name, key, |
20 |
| - &type, NULL, &size, 0); |
21 |
| - |
22 |
| - if (cm_res != CR_BUFFER_SMALL && cm_res != CR_SUCCESS) { |
23 |
| - throw std::runtime_error("CM_Get_Device_Interface_PropertyW failed (" + |
24 |
| - std::to_string(cm_res) + ')'); |
25 |
| - } |
26 |
| - |
27 |
| - std::wstring prop((size + 1) / 2, L'\0'); |
28 |
| - |
29 |
| - cm_res = CM_Get_Device_Interface_PropertyW(interface_name, key, |
30 |
| - &type, reinterpret_cast<PBYTE>(&prop[0]), &size, 0); |
31 |
| - |
32 |
| - if (cm_res != CR_SUCCESS) { |
33 |
| - throw std::runtime_error("CM_Get_Device_Interface_PropertyW failed (" + |
34 |
| - std::to_string(cm_res) + ')'); |
35 |
| - } |
36 |
| - |
37 |
| - return prop; |
38 |
| -} |
39 |
| - |
40 |
| -std::wstring dev_id_from_interface(const WCHAR* interface_name) { |
41 |
| - auto id = dev_prop_wstr_from_interface(interface_name, &DEVPKEY_Device_InstanceId); |
42 |
| - id.resize(id.find_last_of('\\')); |
43 |
| - return id; |
44 |
| -} |
45 |
| - |
46 | 15 | template <typename Func>
|
47 |
| -void rawinput_foreach_with_interface(Func fn, DWORD input_type = RIM_TYPEMOUSE) { |
| 16 | +void rawinput_foreach_dev_with_id(Func fn, bool with_instance_id = false, |
| 17 | + DWORD input_type = RIM_TYPEMOUSE) |
| 18 | +{ |
48 | 19 | const UINT RI_ERROR = -1;
|
49 |
| - |
| 20 | + |
| 21 | + // get number of devices |
50 | 22 | UINT num_devs = 0;
|
51 |
| - |
52 |
| - if (GetRawInputDeviceList(NULL, &num_devs, sizeof(RAWINPUTDEVICELIST)) == RI_ERROR) { |
| 23 | + if (GetRawInputDeviceList(NULL, &num_devs, sizeof(RAWINPUTDEVICELIST)) != 0) { |
53 | 24 | throw std::system_error(GetLastError(), std::system_category(), "GetRawInputDeviceList failed");
|
54 | 25 | }
|
55 | 26 |
|
56 | 27 | auto devs = std::vector<RAWINPUTDEVICELIST>(num_devs);
|
57 | 28 |
|
58 | 29 | if (GetRawInputDeviceList(&devs[0], &num_devs, sizeof(RAWINPUTDEVICELIST)) == RI_ERROR) {
|
59 |
| - throw std::system_error(GetLastError(), std::system_category(), "GetRawInputDeviceList failed"); |
| 30 | + return; |
60 | 31 | }
|
61 | 32 |
|
| 33 | + std::wstring name; |
| 34 | + std::wstring id; |
| 35 | + DEVPROPTYPE type; |
| 36 | + CONFIGRET cm_res; |
| 37 | + |
62 | 38 | for (auto&& dev : devs) {
|
63 | 39 | if (dev.dwType != input_type) continue;
|
64 | 40 |
|
65 |
| - WCHAR name[256] = {}; |
66 |
| - UINT name_size = sizeof(name); |
| 41 | + // get interface name length |
| 42 | + UINT name_len = 0; |
| 43 | + if (GetRawInputDeviceInfoW(dev.hDevice, RIDI_DEVICENAME, NULL, &name_len) == RI_ERROR) { |
| 44 | + continue; |
| 45 | + } |
| 46 | + |
| 47 | + name.resize(name_len); |
| 48 | + |
| 49 | + if (GetRawInputDeviceInfoW(dev.hDevice, RIDI_DEVICENAME, &name[0], &name_len) == RI_ERROR) { |
| 50 | + continue; |
| 51 | + } |
| 52 | + |
| 53 | + // get sizeof dev instance id |
| 54 | + ULONG id_size = 0; |
| 55 | + cm_res = CM_Get_Device_Interface_PropertyW(&name[0], &DEVPKEY_Device_InstanceId, |
| 56 | + &type, NULL, &id_size, 0); |
| 57 | + |
| 58 | + if (cm_res != CR_BUFFER_SMALL && cm_res != CR_SUCCESS) continue; |
| 59 | + |
| 60 | + id.resize((id_size + 1) / 2); |
| 61 | + |
| 62 | + cm_res = CM_Get_Device_Interface_PropertyW(&name[0], &DEVPKEY_Device_InstanceId, |
| 63 | + &type, reinterpret_cast<PBYTE>(&id[0]), &id_size, 0); |
67 | 64 |
|
68 |
| - if (GetRawInputDeviceInfoW(dev.hDevice, RIDI_DEVICENAME, name, &name_size) == RI_ERROR) { |
69 |
| - throw std::system_error(GetLastError(), std::system_category(), "GetRawInputDeviceInfoW failed"); |
| 65 | + if (cm_res != CR_SUCCESS) continue; |
| 66 | + |
| 67 | + if (!with_instance_id) { |
| 68 | + auto instance_delim_pos = id.find_last_of('\\'); |
| 69 | + if(instance_delim_pos != std::string::npos) id.resize(instance_delim_pos); |
70 | 70 | }
|
71 | 71 |
|
72 |
| - fn(dev, name); |
| 72 | + fn(dev, id); |
73 | 73 | }
|
74 | 74 | }
|
75 | 75 |
|
76 |
| -// returns device handles corresponding to a "device id" |
77 |
| -// https://docs.microsoft.com/en-us/windows-hardware/drivers/install/device-ids |
78 |
| -std::vector<HANDLE> rawinput_handles_from_dev_id(const std::wstring& device_id, DWORD input_type = RIM_TYPEMOUSE) { |
| 76 | +inline |
| 77 | +std::vector<HANDLE> rawinput_handles_from_dev_id(const std::wstring& device_id, |
| 78 | + bool with_instance_id = false, |
| 79 | + DWORD input_type = RIM_TYPEMOUSE) |
| 80 | +{ |
79 | 81 | std::vector<HANDLE> handles;
|
80 | 82 |
|
81 |
| - rawinput_foreach_with_interface([&](const auto& dev, const WCHAR* name) { |
82 |
| - if (device_id == dev_id_from_interface(name)) { |
83 |
| - handles.push_back(dev.hDevice); |
84 |
| - } |
85 |
| - }, input_type); |
| 83 | + rawinput_foreach_dev_with_id([&](const auto& dev, const std::wstring& id) { |
| 84 | + if (id == device_id) handles.push_back(dev.hDevice); |
| 85 | + }, with_instance_id, input_type); |
86 | 86 |
|
87 | 87 | return handles;
|
88 | 88 | }
|
| 89 | + |
| 90 | +inline |
| 91 | +std::vector<std::wstring> rawinput_dev_id_list(bool with_instance_id = false, |
| 92 | + DWORD input_type = RIM_TYPEMOUSE) |
| 93 | +{ |
| 94 | + std::vector<std::wstring> ids; |
| 95 | + |
| 96 | + rawinput_foreach_dev_with_id([&](const auto& dev, const std::wstring& id) { |
| 97 | + ids.push_back(id); |
| 98 | + }, with_instance_id, input_type); |
| 99 | + |
| 100 | + std::sort(ids.begin(), ids.end()); |
| 101 | + ids.erase(std::unique(ids.begin(), ids.end()), ids.end()); |
| 102 | + return ids; |
| 103 | +} |
0 commit comments