I am having issues getting usage data from a Windows Precision Touchpad in my C++ desktop application. I have gotten the following working:
- Registered for raw input
- I am receiving WM_INPUT messages containing raw data
- I can call
GetRawInputData()to return aRAWINPUTstructure
My next step has been trying to use the Hidpi.h utilities to determine which usages my touchpad support (HidP_GetCaps(), HidP_GetValueCaps(), etc...), and then get their values. To get things going, I am simply trying to print X, Y, tip switch, contact id, and max contact count).
In order to use the aforementioned utilities, I noticed from documentation that I generally need 2 things: Preparsed data (PHIDP_PREPARSED_DATA) and the actual Input or Feature Report.
This is where things started going wrong. Everything I have read said I should have been able to use HidD_GetPreparsedData() to get the first item. The HID device handle I'm passing is raw_data_buffer->header.hDevice, where raw_data_buffer is the PRAWINPUT type I populated from GetRawInputData(). Unfortunately, this fails. Calling GetLastError() returns ERROR_INVALID_HANDLE. I was unable to find any explanation...the handle wasn't NULL and matched the HID device I was trying to read from.
I found a different method to get the preparsed data:
...
preparsed_data_buffer = (PHIDP_PREPARSED_DATA)malloc( pp_data_buf_sz );
GetRawInputDeviceInfo( raw_data_buffer->header.hDevice, RIDI_PREPARSEDDATA, preparsed_data_buffer, &pp_data_buf_sz );
...
As far as I can tell, the data is correct. I was able to then able to use *_GetCaps() and _*GetValueCaps() to see supported usages.
11 Input Button Capabilites Found
Index: 0, IsRange: 0, UsagePage: 0X000D, Usage: 0X0042
Index: 1, IsRange: 0, UsagePage: 0X000D, Usage: 0X0047
Index: 2, IsRange: 0, UsagePage: 0X000D, Usage: 0X0042
Index: 3, IsRange: 0, UsagePage: 0X000D, Usage: 0X0047
Index: 4, IsRange: 0, UsagePage: 0X000D, Usage: 0X0042
Index: 5, IsRange: 0, UsagePage: 0X000D, Usage: 0X0047
Index: 6, IsRange: 0, UsagePage: 0X000D, Usage: 0X0042
Index: 7, IsRange: 0, UsagePage: 0X000D, Usage: 0X0047
Index: 8, IsRange: 0, UsagePage: 0X000D, Usage: 0X0042
Index: 9, IsRange: 0, UsagePage: 0X000D, Usage: 0X0047
Index: 10, IsRange: 0, UsagePage: 0X0009, Usage: 0X0001
17 Input Value Capabilites Found
Index: 0, IsRange: 0, UsagePage: 0X000D, Usage: 0X0051
Index: 1, IsRange: 0, UsagePage: 0X0001, Usage: 0X0030
Index: 2, IsRange: 0, UsagePage: 0X0001, Usage: 0X0031
Index: 3, IsRange: 0, UsagePage: 0X000D, Usage: 0X0051
Index: 4, IsRange: 0, UsagePage: 0X0001, Usage: 0X0030
Index: 5, IsRange: 0, UsagePage: 0X0001, Usage: 0X0031
Index: 6, IsRange: 0, UsagePage: 0X000D, Usage: 0X0051
Index: 7, IsRange: 0, UsagePage: 0X0001, Usage: 0X0030
Index: 8, IsRange: 0, UsagePage: 0X0001, Usage: 0X0031
Index: 9, IsRange: 0, UsagePage: 0X000D, Usage: 0X0051
Index: 10, IsRange: 0, UsagePage: 0X0001, Usage: 0X0030
Index: 11, IsRange: 0, UsagePage: 0X0001, Usage: 0X0031
Index: 12, IsRange: 0, UsagePage: 0X000D, Usage: 0X0051
Index: 13, IsRange: 0, UsagePage: 0X0001, Usage: 0X0030
Index: 14, IsRange: 0, UsagePage: 0X0001, Usage: 0X0031
Index: 15, IsRange: 0, UsagePage: 0X000D, Usage: 0X0056
Index: 16, IsRange: 0, UsagePage: 0X000D, Usage: 0X0054
3 Feature Value Capabilites Found
Index: 0, IsRange: 0, UsagePage: 0X000D, Usage: 0X0059
Index: 1, IsRange: 0, UsagePage: 0X000D, Usage: 0X0055
Index: 2, IsRange: 0, UsagePage: 0XFF00, Usage: 0X00C5
I found everything I expected. X (x1/x30), Y (x1/x31), and Contact ID (xD/x51) should be in my Input Report, the Tip Switch would be a button, and Max Contact Count (xD/x55) would be in my Feature Value Report.
Focusing on the Input/Feature reports next, I am running into my original problem. The 7th parameter to HidP_GetUsageValue() is a PCHAR to either the input or feature reports, but I don't know how to get them. HidD_GetInputReport() and HidD_GetFeature() both fail with the same invalid handle error I was seeing trying to get the preparsed data through that API.
After going through probably 10 threads or examples, I noticed somebody using their raw (unparsed) data to get input values as such:
HidP_GetUsageValue( HidP_Input, usages[ usage_idx ].page, 0, usages[ usage_idx ].usage, &val,
preparsed_data, (PCHAR)raw_data_buffer->data.hid.bRawData, hid_capabilities.InputReportByteLength );
This worked. I can get x, y, and contact ids from the input report...I guess because the raw input report must be the first block of raw data. However, I still can't get the feature report using HidP_GetUsageValue( HidP_Feature... because I don't know where that report is in the raw input.
I have spent over 10 hours researching for possible causes and workarounds, and have come up with nothing. For the purposes of my application I might be able to get away with just the Input Report values, but there has to be something I'm missing.
6/14 UPDATE:
@RbMm @psmears Thank you for your comments. I didn't realize that the return from GetRawInputDeviceInfo(), using RIDI_DEVICENAME, was the symbolic path needed to create a file for my device. I didn't need to use SetupApi or cfgmgr32 to go through all the device interfaces. I'm still unable to create a file for my device though. Since I can see the path I'm looking for while enumerating all of the device interfaces, I decided to test by creating a new file for each one to rule out path format/encoding issues. Here was my output:
CM_Get_Device_Interface_List() found device #1.
Path: \\?\HID#VID_1FD2&PID_6103&MI_00&Col02#9&885ad2f&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030}
CrateFile() worked.
CM_Get_Device_Interface_List() found device #2.
Path: \\?\HID#VID_046D&PID_C077#6&b39df8e&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
CreateFile() failed with error: 0x5
CM_Get_Device_Interface_List() found device #3.
Path: \\?\HID#VID_B404&PID_0101&MI_01&Col01#7&22822429&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
CreateFile() failed with error: 0x20
CM_Get_Device_Interface_List() found device #4.
Path: \\?\HID#VID_B404&PID_0101&MI_01&Col02#7&22822429&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030}
CreateFile() failed with error: 0x20
CM_Get_Device_Interface_List() found device #5.
Path: \\?\HID#VID_1FD2&PID_6103&MI_01#9&20493974&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
CrateFile() worked.
CM_Get_Device_Interface_List() found device #6.
Path: \\?\HID#VID_0424&PID_274C&MI_01#8&2d3dcce0&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
CrateFile() worked.
CM_Get_Device_Interface_List() found device #7.
Path: \\?\HID#VID_B404&PID_0101&MI_01&Col03#7&22822429&0&0002#{4d1e55b2-f16f-11cf-88cb-001111000030}\KBD
CreateFile() failed with error: 0x5
CM_Get_Device_Interface_List() found device #8.
Path: \\?\HID#VID_B404&PID_0101&MI_00#7&3a45b06e&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}\KBD
CreateFile() failed with error: 0x5
CM_Get_Device_Interface_List() found device #9.
Path: \\?\HID#VID_1FD2&PID_6103&MI_00&Col01#9&885ad2f&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
CreateFile() failed with error: 0x20
CM_Get_Device_Interface_List() found device #10.
Path: \\?\HID#VID_05AC&PID_0265&MI_00&Col01#8&7741f1a&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
CrateFile() worked.
CM_Get_Device_Interface_List() found device #11.
Path: \\?\HID#VID_05AC&PID_0265&MI_00&Col02#8&7741f1a&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030}
CrateFile() worked.
CM_Get_Device_Interface_List() found device #12.
Path: \\?\HID#VID_05AC&PID_0265&MI_01&Col02#8&1f37ab5f&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030}
CrateFile() worked.
CM_Get_Device_Interface_List() found device #13.
Path: \\?\HID#VID_05AC&PID_0265&MI_01&Col03#8&1f37ab5f&0&0002#{4d1e55b2-f16f-11cf-88cb-001111000030}
CrateFile() worked.
CM_Get_Device_Interface_List() found device #14.
Path: \\?\HID#VID_05AC&PID_0265&MI_02#8&36fb37a4&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
CrateFile() worked.
CM_Get_Device_Interface_List() found device #15.
Path: \\?\HID#VID_05AC&PID_0265&MI_03#8&1323f9e2&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
CrateFile() worked.
CM_Get_Device_Interface_List() found device #16.
Path: \\?\HID#VID_05AC&PID_0265&MI_01&Col01#8&1f37ab5f&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
THIS is the device we want a file handle for. Path matches what we expect.
CreateFile() failed with error: 0x20
The device I'm wanting to connect to (#16 here) is the touchpad. The last several interfaces are associated with the same Apple Trackpad device, and creating a file for them works. The error "ERROR_FILE_NOT_FOUND (0x2)" doesn't make any sense to me.
Here is how I'm creating the file:
file_handle = CreateFile( comp_hid_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
According to the MS documentation for OPEN_ALWAYS: "If the specified file does not exist and is a valid path to a writable location, the function creates a file and the last-error code is set to zero." That implies that this isn't a valid, writable location, but it definitely shows up when enumerating my interfaces.
Am I unable to open a file to the device since it was just sent raw input using WM_INPUT message?