summaryrefslogtreecommitdiff
path: root/common/utility-rawinput.hpp
blob: 3c440687e6aa55d972f2f1aa9e2ab6c17ae4e3b7 (plain) (blame)
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
#pragma once

#pragma comment(lib, "cfgmgr32.lib")

#include <iostream>
#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 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& dev_id, 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::vector<HANDLE> handles;

    for (auto&& dev : devs) {
        if (dev.dwType != input_type) continue;

        WCHAR name[256] = {};
        UINT name_size = sizeof(name);

        if (GetRawInputDeviceInfoW(dev.hDevice, RIDI_DEVICENAME, name, &name_size) == RI_ERROR) {
            throw std::system_error(GetLastError(), std::system_category(), "GetRawInputDeviceInfoW failed");
        }

        ULONG id_size = 0;
        DEVPROPTYPE type;
        CONFIGRET cm_res;

        cm_res = CM_Get_Device_Interface_PropertyW(name, &DEVPKEY_Device_InstanceId,
            &type, NULL, &id_size, 0);

        if (cm_res != CR_BUFFER_SMALL && cm_res != CR_SUCCESS) {
            throw std::runtime_error("CM_Get_Device_Interface_PropertyW failed (" +
                std::to_string(cm_res) + ')');
        }

        std::wstring id((static_cast<size_t>(id_size) + 1) / 2, '\0');

        cm_res = CM_Get_Device_Interface_PropertyW(name, &DEVPKEY_Device_InstanceId,
            &type, reinterpret_cast<PBYTE>(&id[0]), &id_size, 0);

        if (cm_res != CR_SUCCESS) {
            throw std::runtime_error("CM_Get_Device_Interface_PropertyW failed (" +
                std::to_string(cm_res) + ')');
        }

        // remove instance id
        id.resize(id.find_last_of('\\'));

        if (id == dev_id) handles.push_back(dev.hDevice);
    }

    return handles;
}