summaryrefslogtreecommitdiff
path: root/wrapper/input.h
blob: c83dca835e9e28ece2cda6da202f9e7a115b308b (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
75
76
77
78
#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>

struct rawinput_device {
    HANDLE handle;
    std::wstring id;
};

template <typename Func>
void rawinput_foreach(Func fn, DWORD device_type = RIM_TYPEMOUSE)
{
    const UINT RI_ERROR = -1;

    // get number of devices
    UINT num_devs = 0;
    if (GetRawInputDeviceList(NULL, &num_devs, sizeof(RAWINPUTDEVICELIST)) != 0) {
        throw std::system_error(GetLastError(), std::system_category(), "GetRawInputDeviceList failed");
    }

    auto dev_list = std::vector<RAWINPUTDEVICELIST>(num_devs);

    if (GetRawInputDeviceList(&dev_list[0], &num_devs, sizeof(RAWINPUTDEVICELIST)) == RI_ERROR) {
        return;
    }

    std::wstring name;
    rawinput_device dev;
    DEVPROPTYPE prop_type;
    CONFIGRET cm_res;

    for (auto [handle, dev_type] : dev_list) {
        if (dev_type != device_type) continue;

        // get interface name length
        UINT name_len = 0;
        if (GetRawInputDeviceInfoW(handle, RIDI_DEVICENAME, NULL, &name_len) == RI_ERROR) {
            continue;
        }

        name.resize(name_len);

        if (GetRawInputDeviceInfoW(handle, RIDI_DEVICENAME, &name[0], &name_len) == RI_ERROR) {
            continue;
        }

        // get sizeof device instance id
        ULONG id_size = 0;
        cm_res = CM_Get_Device_Interface_PropertyW(&name[0], &DEVPKEY_Device_InstanceId,
            &prop_type, NULL, &id_size, 0);

        if (cm_res != CR_BUFFER_SMALL && cm_res != CR_SUCCESS) continue;

        dev.id.resize((id_size + 1) / 2);

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

        if (cm_res != CR_SUCCESS) continue;

        // pop instance id
        auto instance_delim_pos = dev.id.find_last_of('\\');
        if (instance_delim_pos != std::string::npos) dev.id.resize(instance_delim_pos);

        dev.handle = handle;

        fn(dev);
    }
}