Windows HID APIHidD_GetPreparsedData() 由于句柄不正确而在 WM_INPUT 消息处理程序中失败?

问题描述

我正在尝试将 Apple Magic Trackpad 2(最终是任何 Windows Precision Touchpad)的自定义处理写入 Windows 桌面应用程序。我使用 this project 作为指导,因为它实现了类似的目标。我现在已经注册了 HID 触摸板,并且能够接收 WM_INPUT 消息,我正在下面的代码中处理这些消息。请注意,我确实必须下载 open-source drivers 才能使触摸板正常工作并触发 WM_INPUT 消息。

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,raw_data_buffer,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 @R_795_4045@ion 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://docs.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() */

现在,我正处于尝试使用 hidpi.h API 调用获取原始 x、y、联系人等数据的阶段。为了访问其中的任何一个,我需要由 HidD_GetPreparsedData() 输出的预解析数据。不幸的是,该函数失败了,并返回了一个错误代码,指出所提供的句柄(来自原始数据)是错误的。

我错过了什么吗?正如我所评论的,我传递的句柄看起来是正确的,与我注册的设备的句柄相匹配。

解决方法

我修好了!我不确定为什么我不能使用 HidD_GetPreparsedData(),但是使用 GetRawInputDeviceInfo() 获取数据,使用 RIDI_PREPARSEDDATA 参数,工作得很好。

,

RAWINPUTHEADER.hDevice 句柄不适用于 HidD_GetPreparsedData() API。此句柄只能与 GetRawInputDeviceInfo() 一起使用(如您所见)。

要使用 HidD_GetPreparsedData() 和其他 HIDClass support routines,您需要:

  • 通过 ::GetRawInputDeviceInfo(raw_data_buffer->header.hDevice,RIDI_DEVICENAME,..) 调用获取 HID 设备文件名。
  • 通过 ::CreateFile(device_name,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,nullptr,OPEN_EXISTING,nullptr) 调用打开设备文件以获得真实的 HID device_handle
  • 现在您可以使用 HidD_GetPreparsedData()
  • 您还可以在该句柄上使用 WriteFile API 将输出报告发送到 HID 集合。 Details are herehere