Skip to content

Commit

Permalink
fix device id not working with g305
Browse files Browse the repository at this point in the history
this uses w32 apis for enumerating dev info instead of ManagementObjectSearcher, which upper-cases dev ids, differing from kernel/cfgmgr32

this also breaks showing dev name alongside id, as the name seems inaccessible from cfgmgr32 given an interface supplied by rawinput

not a big deal considering the names are too generic to be useful anyway
  • Loading branch information
a1xd committed Jan 30, 2021
1 parent e887f8d commit f64c403
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 54 deletions.
78 changes: 46 additions & 32 deletions common/utility-rawinput.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

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

#include <iostream>
#include <string>
#include <system_error>
#include <vector>
Expand All @@ -12,9 +11,40 @@
#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) {
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) {
const UINT RI_ERROR = -1;

UINT num_devs = 0;
Expand All @@ -28,8 +58,6 @@ std::vector<HANDLE> rawinput_handles_from_dev_id(const std::wstring& dev_id, DWO
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;
Expand All @@ -41,34 +69,20 @@ std::vector<HANDLE> rawinput_handles_from_dev_id(const std::wstring& dev_id, DWO
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) + ')');
}
fn(dev, name);
}
}

// remove instance id
id.resize(id.find_last_of('\\'));
// 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;

if (id == dev_id) handles.push_back(dev.hDevice);
}
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);

return handles;
}

2 changes: 1 addition & 1 deletion grapher/Models/Devices/DeviceIDItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public void SetDeactivated()
DeviceIDMenuItem.Checked = false;
}

private string MenuItemText() => string.IsNullOrEmpty(ID) ? $"{Name}" : $"{Name}: {ID}";
private string MenuItemText() => string.IsNullOrEmpty(ID) ? $"{Name}" : ID.Replace("&", "&&");

private string DisconnectedText() => $"Disconnected: {ID}";

Expand Down
22 changes: 2 additions & 20 deletions grapher/Models/Devices/DeviceIDManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,6 @@ public DeviceIDManager(ToolStripMenuItem deviceIDs)

public Dictionary<string, DeviceIDItem> DeviceIDs { get; private set; }

public static IEnumerable<(string, string)> GetDeviceIDs(string PNPClass = "Mouse")
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher(new SelectQuery("Win32_PnPEntity"));

foreach (ManagementObject obj in searcher.Get())
{
if (obj["PNPClass"] != null && obj["PNPClass"].ToString().Equals(PNPClass) && obj["DeviceID"] != null)
{
string name = obj["Name"].ToString();

string devInstanceID = obj["DeviceID"].ToString();
string devID = devInstanceID.Remove(devInstanceID.LastIndexOf('\\'));

yield return (name, devID);
}
}
}

public void SetActive(DeviceIDItem deviceIDItem)
{
if (SelectedDeviceID != null)
Expand All @@ -64,9 +46,9 @@ public void Update(string devID)

if (found) SetActive(anyDevice);

foreach (var device in GetDeviceIDs().Distinct())
foreach (var (name, id) in RawInputInterop.GetDeviceIDs())
{
var deviceItem = new DeviceIDItem(device.Item1, device.Item2, this);
var deviceItem = new DeviceIDItem(name, id, this);
if (!found && deviceItem.ID.Equals(devID))
{
SetActive(deviceItem);
Expand Down
1 change: 0 additions & 1 deletion grapher/grapher.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Management" />
<Reference Include="System.Windows.Forms.DataVisualization" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
Expand Down
48 changes: 48 additions & 0 deletions wrapper/wrapper.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

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

Expand Down Expand Up @@ -276,6 +277,30 @@ 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 @@ -292,6 +317,29 @@ public ref struct RawInputInterop
throw gcnew System::Exception(gcnew String(e.what()));
}
}

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

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

return managed;
}
catch (const std::exception& e)
{
throw gcnew System::Exception(gcnew String(e.what()));
}
}

};

public ref struct DriverInterop
Expand Down

0 comments on commit f64c403

Please sign in to comment.