The magic of HID is simple once you understood it.
UINT expectedNumberOfHIDs = 0;
if(0 != GetRawInputDeviceList(nullptr, &expectedNumberOfHIDs, sizeof(RAWINPUTDEVICELIST)))
{
return; //no devices found
}
std::vector<RAWINPUTDEVICELIST> hidDescriptors(expectedNumberOfHIDs);
if(expectedNumberOfHIDs != GetRawInputDeviceList(&*hidDescriptors.begin(), &expectedNumberOfHIDs, sizeof(RAWINPUTDEVICELIST)))
{
return; // Error
}
Devices are enumerated from the OS Driver Level into a struct which gives little to no information at all, except which kind of input type and data pages it has. This is because HID e.g. the USB (Universal Serial Bus) standard is made for any kind of device, so you have first to list the generic instances you are interested in and second “cast” them into the objects that “inherit” those generic properties.
for(auto const & hidDescriptor : hidDescriptors)
{
if(RIM_TYPEHID == hidDescriptor.dwType)
theHIDs.push_back(hidDescriptor.hDevice);
}
Like in Unix (which Windows took a deep look at even if they don't say it) every device can be accessed like a file and this is where we get the properties from. So you have to first get the “file path” from the Driver API to finally open a handle and then you are able to obtain all the info you want from device name up to vendor IDs.
wchar_t pathBuffer[260 + 4];
auto pathsLength = UINT(sizeof pathBuffer / sizeof pathBuffer[0]);
pathsLength = GetRawInputDeviceInfoW(itsRawInputHandle, RIDI_DEVICENAME, pathBuffer, &pathsLength);
if(sizeof pathBuffer / sizeof pathBuffer[0] < pathsLength)
{
//invalid HID: could not retrieve its path
return;
}
pathBuffer[1] = L'\\';
ntHandle = CreateFileW(pathBuffer, 0u, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0u, nullptr);
if(INVALID_HANDLE_VALUE == ntHandle)
{
//invalid HID: could not open its handle
return;
}
wchar_t nameBuffer[255];
if(TRUE == HidD_GetManufacturerString(ntHandle, nameBuffer, 127))
{
auto manufacturerLength = wcslen(nameBuffer);
nameBuffer[manufacturerLength++] = ' ';
HidD_GetProductString(ntHandle, nameBuffer + manufacturerLength, ULONG(255 - manufacturerLength));
}
//don't forget to close the handle if you're done
CloseHandle(ntHandle);
You should now be able to see something like
G502 LIGHTSPEED WIRELESS GAMING MOUSE
I found a neat and well explained tutorial some time ago but unfortunately it is in German. However, it explains in very detail how you “could” handle those things without any pain. As I don't have my source on hand at the moment, I took the source provided here