diff --git a/hidapi/hidapi.h b/hidapi/hidapi.h index ca43bcd41..4102e6c17 100644 --- a/hidapi/hidapi.h +++ b/hidapi/hidapi.h @@ -334,6 +334,31 @@ extern "C" { */ int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length); + /** @brief Get a input report from a HID device. + + Set the first byte of @p data[] to the Report ID of the + report to be read. Make sure to allow space for this + extra byte in @p data[]. Upon return, the first byte will + still contain the Report ID, and the report data will + start in data[1]. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data A buffer to put the read data into, including + the Report ID. Set the first byte of @p data[] to the + Report ID of the report to be read, or set it to zero + if your device does not use numbered reports. + @param length The number of bytes to read, including an + extra byte for the report ID. The buffer can be longer + than the actual report. + + @returns + This function returns the number of bytes read plus + one for the report ID (which is still in the first + byte), or -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length); + /** @brief Close a HID device. This function sets the return value of hid_error(). diff --git a/libusb/hid.c b/libusb/hid.c index 298793961..6a0b17bfc 100644 --- a/libusb/hid.c +++ b/libusb/hid.c @@ -1227,6 +1227,35 @@ int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, return res; } +int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length) +{ + int res = -1; + int skipped_report_id = 0; + int report_number = data[0]; + + if (report_number == 0x0) { + /* Offset the return buffer by 1, so that the report ID + will remain in byte 0. */ + data++; + length--; + skipped_report_id = 1; + } + res = libusb_control_transfer(dev->device_handle, + LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_IN, + 0x01/*HID get_report*/, + (1/*HID Input*/ << 8) | report_number, + dev->interface, + (unsigned char *)data, length, + 1000/*timeout millis*/); + + if (res < 0) + return -1; + + if (skipped_report_id) + res++; + + return res; +} void HID_API_EXPORT hid_close(hid_device *dev) { diff --git a/linux/hid.c b/linux/hid.c index c8720dbf2..07ab3e17a 100644 --- a/linux/hid.c +++ b/linux/hid.c @@ -790,6 +790,11 @@ int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, return res; } +// Not supported by Linux HidRaw yet +int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length) +{ + return -1; +} void HID_API_EXPORT hid_close(hid_device *dev) { diff --git a/mac/hid.c b/mac/hid.c index 9d2479e10..6d7b372db 100644 --- a/mac/hid.c +++ b/mac/hid.c @@ -983,6 +983,11 @@ int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, return get_report(dev, kIOHIDReportTypeFeature, data, length); } +int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length) +{ + return get_report(dev, kIOHIDReportTypeInput, data, length); +} + void HID_API_EXPORT hid_close(hid_device *dev) { if (!dev) diff --git a/windows/ddk_build/hidapi.def b/windows/ddk_build/hidapi.def index 05e35afd6..01fe47d64 100644 --- a/windows/ddk_build/hidapi.def +++ b/windows/ddk_build/hidapi.def @@ -14,4 +14,5 @@ EXPORTS hid_open_path @12 hid_send_feature_report @13 hid_get_feature_report @14 + hid_get_input_report @15 \ No newline at end of file diff --git a/windows/hid.c b/windows/hid.c index c31af3087..a535d3312 100755 --- a/windows/hid.c +++ b/windows/hid.c @@ -55,6 +55,7 @@ extern "C" { #define HID_OUT_CTL_CODE(id) \ CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS) #define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100) + #define IOCTL_HID_GET_INPUT_REPORT HID_OUT_CTL_CODE(104) #ifdef __cplusplus } /* extern "C" */ @@ -109,6 +110,7 @@ extern "C" { typedef BOOLEAN (__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); typedef BOOLEAN (__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length); typedef BOOLEAN (__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length); + typedef BOOLEAN (__stdcall *HidD_GetInputReport_)(HANDLE handle, PVOID data, ULONG length); typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len); typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data); typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data); @@ -121,6 +123,7 @@ extern "C" { static HidD_GetProductString_ HidD_GetProductString; static HidD_SetFeature_ HidD_SetFeature; static HidD_GetFeature_ HidD_GetFeature; + static HidD_GetInputReport_ HidD_GetInputReport; static HidD_GetIndexedString_ HidD_GetIndexedString; static HidD_GetPreparsedData_ HidD_GetPreparsedData; static HidD_FreePreparsedData_ HidD_FreePreparsedData; @@ -211,6 +214,7 @@ static int lookup_functions() RESOLVE(HidD_GetProductString); RESOLVE(HidD_SetFeature); RESOLVE(HidD_GetFeature); + RESOLVE(HidD_GetInputReport); RESOLVE(HidD_GetIndexedString); RESOLVE(HidD_GetPreparsedData); RESOLVE(HidD_FreePreparsedData); @@ -818,6 +822,55 @@ int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned #endif } + +int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length) +{ +#if 0 + BOOL res; + res = HidD_GetInputReport(dev->device_handle, data, length); + if (!res) { + register_error(dev, "HidD_GetInputReport"); + return -1; + } + return length; +#else + DWORD bytes_returned; + + OVERLAPPED ol; + memset(&ol, 0, sizeof(ol)); + + BOOL res = DeviceIoControl(dev->device_handle, + IOCTL_HID_GET_INPUT_REPORT, + data, length, + data, length, + &bytes_returned, &ol); + + if (!res) { + if (GetLastError() != ERROR_IO_PENDING) { + /* DeviceIoControl() failed. Return error. */ + register_error(dev, "Send Input Report DeviceIoControl"); + return -1; + } + } + + /* Wait here until the write is done. This makes + hid_get_feature_report() synchronous. */ + res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/); + if (!res) { + /* The operation failed. */ + register_error(dev, "Send Input Report GetOverLappedResult"); + return -1; + } + + /* bytes_returned does not include the first byte which contains the + report ID. The data buffer actually contains one more byte than + bytes_returned. */ + bytes_returned++; + + return bytes_returned; +#endif +} + void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev) { if (!dev)