Skip to content

Commit

Permalink
Added support for Get Input Report (#59)
Browse files Browse the repository at this point in the history
- Get Input Report supported on linux/libusb, mac and windows;
- linux/hidraw doesn't support it on kernel level;
  • Loading branch information
DanielVanNoord authored and Youw committed Nov 15, 2019
1 parent 7e91963 commit 083223e
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 0 deletions.
25 changes: 25 additions & 0 deletions hidapi/hidapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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().
Expand Down
29 changes: 29 additions & 0 deletions libusb/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -1237,6 +1237,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)
{
Expand Down
5 changes: 5 additions & 0 deletions linux/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
5 changes: 5 additions & 0 deletions mac/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions windows/ddk_build/hidapi.def
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ EXPORTS
hid_open_path @12
hid_send_feature_report @13
hid_get_feature_report @14
hid_get_input_report @15

53 changes: 53 additions & 0 deletions windows/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -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" */
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -821,6 +825,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)
Expand Down

0 comments on commit 083223e

Please sign in to comment.