Skip to content

Commit

Permalink
Merge pull request #86 from a1xd/fix-input
Browse files Browse the repository at this point in the history
Suppress id/rawinput related errors
  • Loading branch information
a1xd authored Apr 28, 2021
2 parents 11b62cf + f218e44 commit c13f066
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 85 deletions.
2 changes: 1 addition & 1 deletion common/rawaccel-version.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#define RA_VER_MAJOR 1
#define RA_VER_MINOR 4
#define RA_VER_PATCH 3
#define RA_VER_PATCH 4

#define RA_OS "Win7+"

Expand Down
115 changes: 65 additions & 50 deletions common/utility-rawinput.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

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

#include <algorithm>
#include <string>
#include <system_error>
#include <vector>
Expand All @@ -11,78 +12,92 @@
#include <initguid.h> // needed for devpkey.h to parse properly
#include <devpkey.h>

std::wstring dev_prop_wstr_from_interface(const WCHAR* interface_name, const DEVPROPKEY* key) {
ULONG size = 0;
DEVPROPTYPE type;
CONFIGRET cm_res;

cm_res = CM_Get_Device_Interface_PropertyW(interface_name, key,
&type, NULL, &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 prop((size + 1) / 2, L'\0');

cm_res = CM_Get_Device_Interface_PropertyW(interface_name, key,
&type, reinterpret_cast<PBYTE>(&prop[0]), &size, 0);

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

return prop;
}

std::wstring dev_id_from_interface(const WCHAR* interface_name) {
auto id = dev_prop_wstr_from_interface(interface_name, &DEVPKEY_Device_InstanceId);
id.resize(id.find_last_of('\\'));
return id;
}

template <typename Func>
void rawinput_foreach_with_interface(Func fn, DWORD input_type = RIM_TYPEMOUSE) {
void rawinput_foreach_dev_with_id(Func fn, bool with_instance_id = false,
DWORD input_type = RIM_TYPEMOUSE)
{
const UINT RI_ERROR = -1;


// get number of devices
UINT num_devs = 0;

if (GetRawInputDeviceList(NULL, &num_devs, sizeof(RAWINPUTDEVICELIST)) == RI_ERROR) {
if (GetRawInputDeviceList(NULL, &num_devs, sizeof(RAWINPUTDEVICELIST)) != 0) {
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");
return;
}

std::wstring name;
std::wstring id;
DEVPROPTYPE type;
CONFIGRET cm_res;

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

WCHAR name[256] = {};
UINT name_size = sizeof(name);
// get interface name length
UINT name_len = 0;
if (GetRawInputDeviceInfoW(dev.hDevice, RIDI_DEVICENAME, NULL, &name_len) == RI_ERROR) {
continue;
}

name.resize(name_len);

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

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

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

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

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

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

if (!with_instance_id) {
auto instance_delim_pos = id.find_last_of('\\');
if(instance_delim_pos != std::string::npos) id.resize(instance_delim_pos);
}

fn(dev, name);
fn(dev, id);
}
}

// 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) {
inline
std::vector<HANDLE> rawinput_handles_from_dev_id(const std::wstring& device_id,
bool with_instance_id = false,
DWORD input_type = RIM_TYPEMOUSE)
{
std::vector<HANDLE> handles;

rawinput_foreach_with_interface([&](const auto& dev, const WCHAR* name) {
if (device_id == dev_id_from_interface(name)) {
handles.push_back(dev.hDevice);
}
}, input_type);
rawinput_foreach_dev_with_id([&](const auto& dev, const std::wstring& id) {
if (id == device_id) handles.push_back(dev.hDevice);
}, with_instance_id, input_type);

return handles;
}

inline
std::vector<std::wstring> rawinput_dev_id_list(bool with_instance_id = false,
DWORD input_type = RIM_TYPEMOUSE)
{
std::vector<std::wstring> ids;

rawinput_foreach_dev_with_id([&](const auto& dev, const std::wstring& id) {
ids.push_back(id);
}, with_instance_id, input_type);

std::sort(ids.begin(), ids.end());
ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
return ids;
}
4 changes: 2 additions & 2 deletions grapher/Models/Devices/DeviceIDManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ public void Update(string devID)

if (found) SetActive(anyDevice);

foreach (var (name, id) in RawInputInterop.GetDeviceIDs())
foreach (string id in RawInputInterop.GetDeviceIDs())
{
var deviceItem = new DeviceIDItem(name, id, this);
var deviceItem = new DeviceIDItem(string.Empty, id, this);
if (!found && deviceItem.ID.Equals(devID))
{
SetActive(deviceItem);
Expand Down
36 changes: 4 additions & 32 deletions wrapper/wrapper.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#pragma once

#include <algorithm>
#include <type_traits>
#include <msclr\marshal_cppstd.h>

Expand Down Expand Up @@ -277,30 +276,6 @@ public ref class SettingsErrors
}
};

struct device_info {
std::wstring name;
std::wstring id;
};

std::vector<device_info> get_unique_device_info() {
std::vector<device_info> info;

rawinput_foreach_with_interface([&](const auto& dev, const WCHAR* name) {
info.push_back({
L"", // get_property_wstr(name, &DEVPKEY_Device_FriendlyName), /* doesn't work */
dev_id_from_interface(name)
});
});

std::sort(info.begin(), info.end(),
[](auto&& l, auto&& r) { return l.id < r.id; });
auto last = std::unique(info.begin(), info.end(),
[](auto&& l, auto&& r) { return l.id == r.id; });
info.erase(last, info.end());

return info;
}

public ref struct RawInputInterop
{
static void AddHandlesFromID(String^ deviceID, List<IntPtr>^ rawInputHandles)
Expand All @@ -318,18 +293,15 @@ public ref struct RawInputInterop
}
}

static List<ValueTuple<String^, String^>>^ GetDeviceIDs()
static List<String^>^ GetDeviceIDs()
{
try
{
auto managed = gcnew List<ValueTuple<String^, String^>>();
auto managed = gcnew List<String^>();

for (auto&& [name, id] : get_unique_device_info())
for (auto&& id : rawinput_dev_id_list())
{
managed->Add(
ValueTuple<String^, String^>(
msclr::interop::marshal_as<String^>(name),
msclr::interop::marshal_as<String^>(id)));
managed->Add(msclr::interop::marshal_as<String^>(id));
}

return managed;
Expand Down

0 comments on commit c13f066

Please sign in to comment.