DJL
DJL

Reputation: 166

(Windows HID API) HidD_GetPreparsedData() failing in WM_INPUT message handler due to incorrect handle?

I am trying to write custom handling for an Apple Magic Trackpad 2 (ultimately any Windows Precision Touchpad) into a Windows Desktop application. I am using this project as a guide, as it accomplishes similar goals. I am at the point where I have registered the HID touchpad, and am able to receive WM_INPUT messages, which I am handling in the code below. Note, I did have to download open-source drivers in order for the touchpad to work correctly and trigger WM_INPUT messages.

afx_msg void CSimulatorWnd::OnRawInput( UINT nInputCode, HRAWINPUT hRawInput )
{
/*----------------------------------------------------------
Local variables
----------------------------------------------------------*/
HIDP_CAPS hid_capabilities;
UINT data_size = 0;
PHIDP_PREPARSED_DATA preparsed_data = NULL; // allocated by HidD_GetPreparsedData
PRAWINPUT raw_data_buffer = NULL;
RAWINPUTDEVICELIST * connected_devices = NULL;

// add vars that need to be de-allocated here
#define free_and_return() free( raw_data_buffer ); \
                          if( preparsed_data ){ HidD_FreePreparsedData( preparsed_data ); } \
                          return;

// get the required raw data size (returns 0 if successful)
if( GetRawInputData( hRawInput, RID_INPUT, NULL, &data_size, sizeof( RAWINPUTHEADER ) ) != 0
 || data_size == 0 )
    {
    free_and_return();
    }

// allocate space in the input data buffer
raw_data_buffer = (RAWINPUT *)malloc( data_size );

// get the raw data (returns the required buffer size from above if successful)
if( GetRawInputData( hRawInput, RID_INPUT, raw_data_buffer, &data_size, sizeof( RAWINPUTHEADER ) ) != data_size )
    {
    free_and_return();
    }

// only handle registered HIDs
if( raw_data_buffer->header.dwType != RIM_TYPEHID )
    {
    free_and_return();
    }

// get pre-parsed HID data. need this structure
if( !HidD_GetPreparsedData( raw_data_buffer->header.hDevice, &preparsed_data ) )
    {
    // NOTE: raw_data_buffer->header.hDevice = 0x000000004ddd0ce9,
    //       returning a ERROR_INVALID_HANDLE for some reason.
    //
    //    Below is the information for the HID I registered.
    //    The handle is correct. The printout below was from
    //    enumerating over available devices from GetRawInputDeviceList()
    //    and the output from GetRawInputDeviceInfo()
    //
    //    *********** HID INFO ***********
    //    HNDL:            000000004DDD0CE9
    //    Product ID:             613
    //    Vendor ID:            35088
    //    Version Number:           1
    //    Usage Page:      0X0000000D
    //    Usage:           0X00000005
    //    ********************************
    DWORD error = GetLastError();
    free_and_return();
    }

// get multi-touch HID capabilities and data
// https://learn.microsoft.com/en-us/windows-hardware/design/component-guidelines/supporting-usages-in-multitouch-digitizer-drivers
HidP_GetCaps( preparsed_data, &hid_capabilities );

// free dynamically allocated memory
free_and_return();

}   /* CSimulatorWnd::OnRawInput() */

Right now, I am at the stage of trying to use the hidpi.h API calls to get raw x, y, contact, etc. data. In order to access any of this, I need preparsed data output by HidD_GetPreparsedData(). Unfortunately, that function is failing, and returning an error code stating the provided handle (from the raw data) is wrong.

Am I missing something? As I commented, the handle I'm passing in looks correct, matching that of the device I registered.

Upvotes: 2

Views: 835

Answers (2)

DJm00n
DJm00n

Reputation: 1411

RAWINPUTHEADER.hDevice handle is not usable with HidD_GetPreparsedData() API. This handle could be used only with GetRawInputDeviceInfo() (as you already found).

To use HidD_GetPreparsedData() and other HIDClass support routines you need:

  • Get HID device file name via ::GetRawInputDeviceInfo(raw_data_buffer->header.hDevice, RIDI_DEVICENAME, ..) call.
  • Open device file via ::CreateFile(device_name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, nullptr, nullptr) call to get a real HIDs device_handle.
  • Now you can use HidD_GetPreparsedData().
  • Also you can use WriteFile API on that handle to send output reports to a HID collection. Details are here and here.

Upvotes: 2

DJL
DJL

Reputation: 166

I fixed it! I am not sure as to why I couldn't use HidD_GetPreparsedData(), but getting the data with GetRawInputDeviceInfo(), using the RIDI_PREPARSEDDATA param, worked just fine.

Upvotes: 1

Related Questions