3
votes

We have some HID devices (touch digitizers) that communicate with an internal R&D tool. This tool parses the raw feature reports from the devices to draw the touch reports along with some additional data that are present in the raw feature report but filtered out by the HID driver of Windows 7 (eg, pressure data is not present in WM_TOUCH messages).

However, we have started working with some devices that may have different firmware variants, and thus that do not share the same ordering or bytelength of the fields and I need to modify our R&D tool so that it will adapt transparently to all the devices.

The devices come from the same manufacturer (ourselves) and share the same device info, so using these fields to differentiate between the different firmwares is not an option. What I would like to do is to get the HID feature report descriptor sent by the device and update dynamically our feature report parsing method based on this information.

However, I didn't manage to find the correct method to call in order to get this descriptor when browsing the Windows API. What I have found so far is the Raw Input page on MSDN, but I'm not sure what to do next. Can I find the required information in the RID_DEVICE_HID structure ? Or do I need to call a completely different API ?

Thanks in advance for your help!

2

2 Answers

4
votes

Ok, finally I've got something (almost completely) functional. As inferred by mcoill, I used the HidP_xxx() family of functions, but it needs a little bit of data preparation first.

I based my solution on this example code that targets USB joysticks and adapted it to touch digitizer devices. If someone else also gets confused by the online doc, here are the required steps involved in the process:

  1. registering the application for a Raw Input device at launch. This is done by calling the function RegisterRawInputDevice(&Rid, 1, sizeof(Rid)), where Rid is a RAWINPUTDEVICE with the following properties set (in order to get a touch digitizer) :

    Rid.usUsage = 0x04;
    Rid.usUsagePage = 0x0d;
    Rid.dwFlags = RIDEV_INPUT_SINK;
    
  2. registering a callback OnInput(LPARAM lParam) for the events WM_INPUT since the Rid device will generate this type of events;

  3. the OnInput(LPARAM lParam) method will get the data from this event in two steps:

    // Parse the raw input header to read its size.
    UINT bufferSize;
    GetRawInputData(HRAWINPUT)lParam, RID_INPUT, NULL, &bufferSize, sizeof(RAWINPUTHEADER));
    
    // Allocate memory for the raw input data and retrieve it
    PRAWINPUT = (PRAWINPUT)HeapAlloc(GetProcessHeap(), 0, bufferSize);
    GetRawInputData(HRAWINPUT)lParam, RID_INPUT, rawInput /* NOT NULL */, &bufferSize, sizeof(RAWINPUTHEADER));
    
  4. it then calls a parsing method that creates the HIDP_PREPARSED_DATA structure required by the lookup functions:

    // Again, read the data size, allocate then retrieve
    GetRawInputDeviceInfo(rawInput->header.hDevice, RIDI_PREPARSEDDATA, NULL, &bufferSize);
    PHIDP_PREPARSED_DATA preparsedData = (PHIDP_PREPARSED_DATA)HeapAlloc(heap, 0, bufferSize);
    GetRawInputDeviceInfo(rawInput->header.hDevice, RIDI_PREPARSEDDATA, preparsedData, &bufferSize);
    

The preparsed data is split into capabilities:

    // Create a structure that will hold the values
    HidP_GetCaps(preparsedData, &caps);
    USHORT capsLength = caps.NumberInputValueCaps;
    PHIDP_VALUE_CAPS valueCaps = (PHIDP_VALUE_CAPS)HeapAlloc(heap, 0, capsLength*sizeof(HIDP_VALUE_CAPS));
    HidP_GetValueCaps(HidP_Input, valueCaps, &capsLength, preparsedData);

And capabilities can be asked for their value:

    // Read sample value
    HidP_GetUsageValue(HidP_Input, valueCaps[i].UsagePage, 0, valueCaps[i].Range.UsageMin, &value, preparsedData, (PCHAR)rawInput->data.hid.bRawData, rawInput->data.hid.dwSizeHid);
1
votes

Wouldn't HidP_GetPReparsedData(...), HidP_GetValueCaps(HidP_Feature, ...) and their ilk give you enough information without having to get the raw feature report?

HIDClass Support Routines on MSDN