13

I'm switching an application from DirectInput to RawInput for gamepad handling, and I'd like to present a human readable description for each gamepad. The ideal would be the device text that appears in device manager, but the USB product description would also do. Any method should work without administrator permission.

So far I've found one set of clues: there seems to be a text field in the registry under HKLM\SYSTEM\CurrentControlSet\Control\MediaProperties\PrivateProperties\Joystick\OEM which is the same as the name provided by DirectInput. This isn't perfect - I have a gamepad that appears in English in device manager, but lists as 氀 in the registry.

Is there a way to get from the HANDLE provided by WM_INPUT to the device manager description? HidD_GetProductString looks promising, but I don't know how to get the Hid top level collection handle from the RawInput handle.

Edit: I have got a device instance path (eg. \\?\HID#VID_1267&PID_A001#8&1d630df6&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}, which may be enough to extract the information I need from SetupAPI. Does anybody know how to reach this given an instance path?

3 Answers 3

4

I've been having a similar problem and believe I found a potential solution.

It seems you must call CreateFile with the name that RawInput provides from calling GetRawInputDeviceInfo with RIDI_DEVICENAME as the uiCommand parameter's argument. This will give you a handle to the device with which you may call HidD_GetProductString.

wchar_t DeviceName[126];
HANDLE HIDHandle = CreateFile(RawInputDeviceName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
if(HIDHandle)
{
    BOOLEAN Result = HidD_GetProductString(HIDHandle, DeviceName, sizeof(wchar_t) * 126);
    CloseHandle(HIDHandle);
}

However, it seems that HidD_GetProductString fails on a majority of the devices attached on my system and only seems to succeed for my USB keyboard and a web camera. It does not succeed for my USB mouse. I have not yet discovered why this is, but perhaps my progress will aid you.

Sign up to request clarification or add additional context in comments.

1 Comment

Its worth mentioning that some devices will throw ERROR_ACCESS_DENIED when trying to open a handle to the device. In that case you can replace GENERIC_READ | GENERIC_WRITE with NULL and it will work.
0

You get a handle to the top level collection as explained here: https://msdn.microsoft.com/en-us/library/windows/hardware/ff538731%28v=vs.85%29.aspx

Comments

0

For HID devices you can use HidD_GetProductString but keyboard and mouse are not avalible via HID API on Windows and exposed as separate device types: GUID_DEVINTERFACE_KEYBOARD/GUID_DEVINTERFACE_MOUSE (they cannot be directly read by user-mode app by security reasons).

You can get their device info from device interface symbolic link like this:

  • use CM_Get_Device_Interface_Property or SetupDiGetDeviceInterfaceProperty with DEVPKEY_Device_InstanceId to get device instance id (one device can have multiple interfaces).

  • after you have device instance id you can use CM_Get_DevNode_Property or SetupDiGetDeviceProperty with DEVPKEY_NAME to get localized friendly name of a device (which is shown in Device Manager).

Here is example code via CM_* API from my test repo:

bool FillDeviceInfo(const std::wstring& deviceInterfaceName)
{
    // you need to provide deviceInterfaceName
    // example from my system: `\\?\HID#VID_203A&PID_FFFC&MI_01#7&2de99099&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}`

    DEVPROPTYPE propertyType;
    ULONG propertySize = 0;
    CONFIGRET cr = ::CM_Get_Device_Interface_PropertyW(deviceInterfaceName.c_str(), &DEVPKEY_Device_InstanceId, &propertyType, nullptr, &propertySize, 0);

    if (cr != CR_BUFFER_SMALL)
        return false;

    std::wstring deviceId;
    deviceId.resize(propertySize);
    cr = ::CM_Get_Device_Interface_PropertyW(deviceInterfaceName.c_str(), &DEVPKEY_Device_InstanceId, &propertyType, (PBYTE)deviceId.data(), &propertySize, 0);

    if (cr != CR_SUCCESS)
        return false;

    // here is deviceId will contain device instance id
    // example from my system: `HID\VID_203A&PID_FFFC&MI_01\7&2de99099&0&0000`

    DEVINST devInst;
    cr = ::CM_Locate_DevNodeW(&devInst, (DEVINSTID_W)deviceId.c_str(), CM_LOCATE_DEVNODE_NORMAL);

    if (cr != CR_SUCCESS)
        return false;

    propertySize = 0;
    cr = ::CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_NAME, &propertyType, nullptr, &propertySize, 0);

    if (cr != CR_BUFFER_SMALL)
        return false;

    std::wstring friendlyString;
    friendlyString.resize(propertySize);
    cr = ::CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_NAME, &propertyType, (PBYTE)friendlyString.data(), &propertySize, 0);

    // here is friendlyString will contain localized device friendly name

    propertySize = 0;
    cr = ::CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_Device_Manufacturer, &propertyType, nullptr, &propertySize, 0);

    if (cr != CR_BUFFER_SMALL)
        return false;

    std::wstring manufacturer;
    manufacturer.resize(propertySize);
    cr = ::CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_Device_Manufacturer, &propertyType, (PBYTE)manufacturer.data(), &propertySize, 0);

    // here is manufacturer will contain localized device "manufacturer-identifier"

    return true;
}

Update: it turned out that HidD_GetProductString and family is working for HID keyboard and mouse. You just need to open its device interface (path) as read-only. See https://github.com/DJm00n/RawInputDemo/blob/master/RawInputLib/RawInputDevice.cpp#L77-L86 for example.

5 Comments

There are still significant advantages to going the Configuration Manager API route... lots more information available, including the parent and bus relationships.
@BenVoigt I recommend using HidD_GetProductString first and DEVPKEY_NAME as a fallback for non-HID devices. This will give you more accurate HID device name, not just generic HID Keyboard Device.
"Bus Reported Description" tends to be really good, although you do often have to search upward to ancestors to find one.
DEVPKEY_Device_BusReportedDeviceDesc this one? I'll try to play with it and see how it goes.
Yes that's the one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.