13
0

Update hidapi

This commit is contained in:
Robin Gareus 2024-09-03 19:34:44 +02:00
parent e4d9344d2a
commit 8fea1ea42e
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
14 changed files with 4812 additions and 1272 deletions

View File

@ -1,2 +1 @@
http://www.signal11.us/oss/hidapi/
hidapi-0.8.0-rc1-21-ga6a622f (2016-01-08) from https://github.com/signal11/hidapi
hidapi-0.14.0-35-gc3c79a7 (2024-08-21) from https://github.com/libusb/hidapi

View File

@ -5,9 +5,9 @@
Alan Ott
Signal 11 Software
8/22/2009
libusb/hidapi Team
Copyright 2009, All Rights Reserved.
Copyright 2023, All Rights Reserved.
At the discretion of the user of this library,
this software may be licensed under the terms of the
@ -17,7 +17,7 @@
files located at the root of the source distribution.
These files may also be found in the public source
code repository located at:
http://github.com/signal11/hidapi .
https://github.com/libusb/hidapi .
********************************************************/
/** @file
@ -29,22 +29,123 @@
#include <wchar.h>
#if 0 // XXX we compile hidapi as static library
/* #480: this is to be refactored properly for v1.0 */
#ifdef _WIN32
#ifndef HID_API_NO_EXPORT_DEFINE
#define HID_API_EXPORT __declspec(dllexport)
#define HID_API_CALL
#else
#define HID_API_EXPORT /**< API export macro */
#define HID_API_CALL /**< API call macro */
#endif
#endif
#ifndef HID_API_EXPORT
#define HID_API_EXPORT /**< API export macro */
#endif
/* To be removed in v1.0 */
#define HID_API_CALL /**< API call macro */
#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/
/** @brief Static/compile-time major version of the library.
@ingroup API
*/
#define HID_API_VERSION_MAJOR 0
/** @brief Static/compile-time minor version of the library.
@ingroup API
*/
#define HID_API_VERSION_MINOR 15
/** @brief Static/compile-time patch version of the library.
@ingroup API
*/
#define HID_API_VERSION_PATCH 0
/* Helper macros */
#define HID_API_AS_STR_IMPL(x) #x
#define HID_API_AS_STR(x) HID_API_AS_STR_IMPL(x)
#define HID_API_TO_VERSION_STR(v1, v2, v3) HID_API_AS_STR(v1.v2.v3)
/** @brief Coverts a version as Major/Minor/Patch into a number:
<8 bit major><16 bit minor><8 bit patch>.
This macro was added in version 0.12.0.
Convenient function to be used for compile-time checks, like:
@code{.c}
#if HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
@endcode
@ingroup API
*/
#define HID_API_MAKE_VERSION(mj, mn, p) (((mj) << 24) | ((mn) << 8) | (p))
/** @brief Static/compile-time version of the library.
This macro was added in version 0.12.0.
@see @ref HID_API_MAKE_VERSION.
@ingroup API
*/
#define HID_API_VERSION HID_API_MAKE_VERSION(HID_API_VERSION_MAJOR, HID_API_VERSION_MINOR, HID_API_VERSION_PATCH)
/** @brief Static/compile-time string version of the library.
@ingroup API
*/
#define HID_API_VERSION_STR HID_API_TO_VERSION_STR(HID_API_VERSION_MAJOR, HID_API_VERSION_MINOR, HID_API_VERSION_PATCH)
/** @brief Maximum expected HID Report descriptor size in bytes.
Since version 0.13.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 13, 0)
@ingroup API
*/
#define HID_API_MAX_REPORT_DESCRIPTOR_SIZE 4096
#ifdef __cplusplus
extern "C" {
#endif
/** A structure to hold the version numbers. */
struct hid_api_version {
int major; /**< major version number */
int minor; /**< minor version number */
int patch; /**< patch version number */
};
struct hid_device_;
typedef struct hid_device_ hid_device; /**< opaque hidapi structure */
/** @brief HID underlying bus types.
@ingroup API
*/
typedef enum {
/** Unknown bus type */
HID_API_BUS_UNKNOWN = 0x00,
/** USB bus
Specifications:
https://usb.org/hid */
HID_API_BUS_USB = 0x01,
/** Bluetooth or Bluetooth LE bus
Specifications:
https://www.bluetooth.com/specifications/specs/human-interface-device-profile-1-1-1/
https://www.bluetooth.com/specifications/specs/hid-service-1-0/
https://www.bluetooth.com/specifications/specs/hid-over-gatt-profile-1-0/ */
HID_API_BUS_BLUETOOTH = 0x02,
/** I2C bus
Specifications:
https://docs.microsoft.com/previous-versions/windows/hardware/design/dn642101(v=vs.85) */
HID_API_BUS_I2C = 0x03,
/** SPI bus
Specifications:
https://www.microsoft.com/download/details.aspx?id=103325 */
HID_API_BUS_SPI = 0x04,
} hid_bus_type;
/** hidapi info structure */
struct hid_device_info {
/** Platform-specific device path */
@ -63,19 +164,26 @@ extern "C" {
/** Product string */
wchar_t *product_string;
/** Usage Page for this Device/Interface
(Windows/Mac only). */
(Windows/Mac/hidraw only) */
unsigned short usage_page;
/** Usage for this Device/Interface
(Windows/Mac only).*/
(Windows/Mac/hidraw only) */
unsigned short usage;
/** The USB interface which this logical device
represents. Valid on both Linux implementations
in all cases, and valid on the Windows implementation
only if the device contains more than one interface. */
represents.
Valid only if the device is a USB HID device.
Set to -1 in all other cases.
*/
int interface_number;
/** Pointer to the next device */
struct hid_device_info *next;
/** Underlying bus type
Since version 0.13.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 13, 0)
*/
hid_bus_type bus_type;
};
@ -87,11 +195,12 @@ extern "C" {
needed. This function should be called at the beginning of
execution however, if there is a chance of HIDAPI handles
being opened by different threads simultaneously.
@ingroup API
@returns
This function returns 0 on success and -1 on error.
Call hid_error(NULL) to get the failure reason.
*/
int HID_API_EXPORT HID_API_CALL hid_init(void);
@ -103,7 +212,7 @@ extern "C" {
@ingroup API
@returns
@returns
This function returns 0 on success and -1 on error.
*/
int HID_API_EXPORT HID_API_CALL hid_exit(void);
@ -123,21 +232,25 @@ extern "C" {
@param product_id The Product ID (PID) of the types of
device to open.
@returns
This function returns a pointer to a linked list of type
struct #hid_device, containing information about the HID devices
attached to the system, or NULL in the case of failure. Free
this linked list by calling hid_free_enumeration().
@returns
This function returns a pointer to a linked list of type
struct #hid_device_info, containing information about the HID devices
attached to the system,
or NULL in the case of failure or if no HID devices present in the system.
Call hid_error(NULL) to get the failure reason.
@note The returned value by this function must to be freed by calling hid_free_enumeration(),
when not needed anymore.
*/
struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id);
/** @brief Free an enumeration Linked List
This function frees a linked list created by hid_enumerate().
This function frees a linked list created by hid_enumerate().
@ingroup API
@param devs Pointer to a list of struct_device returned from
hid_enumerate().
@param devs Pointer to a list of struct_device returned from
hid_enumerate().
*/
void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs);
@ -151,11 +264,15 @@ extern "C" {
@param vendor_id The Vendor ID (VID) of the device to open.
@param product_id The Product ID (PID) of the device to open.
@param serial_number The Serial Number of the device to open
(Optionally NULL).
(Optionally NULL).
@returns
This function returns a pointer to a #hid_device object on
success or NULL on failure.
Call hid_error(NULL) to get the failure reason.
@note The returned object must be freed by calling hid_close(),
when not needed anymore.
*/
HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number);
@ -166,11 +283,15 @@ extern "C" {
Linux).
@ingroup API
@param path The path name of the device to open
@param path The path name of the device to open
@returns
This function returns a pointer to a #hid_device object on
success or NULL on failure.
Call hid_error(NULL) to get the failure reason.
@note The returned object must be freed by calling hid_close(),
when not needed anymore.
*/
HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path);
@ -186,12 +307,12 @@ extern "C" {
single report), followed by the report data (16 bytes). In
this example, the length passed in would be 17.
hid_write() will send the data on the first OUT endpoint, if
one exists. If it does not, it will send the data through
the Control Endpoint (Endpoint 0).
hid_write() will send the data on the first interrupt OUT
endpoint, if one exists. If it does not the behaviour is as
@ref hid_send_output_report
@ingroup API
@param device A device handle returned from hid_open().
@param dev A device handle returned from hid_open().
@param data The data to send, including the report number as
the first byte.
@param length The length in bytes of the data to send.
@ -199,8 +320,9 @@ extern "C" {
@returns
This function returns the actual number of bytes written and
-1 on error.
Call hid_error(dev) to get the failure reason.
*/
int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length);
int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length);
/** @brief Read an Input report from a HID device with timeout.
@ -209,7 +331,7 @@ extern "C" {
contain the Report number if the device uses numbered reports.
@ingroup API
@param device A device handle returned from hid_open().
@param dev A device handle returned from hid_open().
@param data A buffer to put the read data into.
@param length The number of bytes to read. For devices with
multiple reports, make sure to read an extra byte for
@ -218,7 +340,9 @@ extern "C" {
@returns
This function returns the actual number of bytes read and
-1 on error. If no packet was available to be read within
-1 on error.
Call hid_error(dev) to get the failure reason.
If no packet was available to be read within
the timeout period, this function returns 0.
*/
int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds);
@ -226,11 +350,11 @@ extern "C" {
/** @brief Read an Input report from a HID device.
Input reports are returned
to the host through the INTERRUPT IN endpoint. The first byte will
to the host through the INTERRUPT IN endpoint. The first byte will
contain the Report number if the device uses numbered reports.
@ingroup API
@param device A device handle returned from hid_open().
@param dev A device handle returned from hid_open().
@param data A buffer to put the read data into.
@param length The number of bytes to read. For devices with
multiple reports, make sure to read an extra byte for
@ -238,10 +362,12 @@ extern "C" {
@returns
This function returns the actual number of bytes read and
-1 on error. If no packet was available to be read and
-1 on error.
Call hid_error(dev) to get the failure reason.
If no packet was available to be read and
the handle is in non-blocking mode, this function returns 0.
*/
int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length);
int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length);
/** @brief Set the device handle to be non-blocking.
@ -253,15 +379,16 @@ extern "C" {
Nonblocking can be turned on and off at any time.
@ingroup API
@param device A device handle returned from hid_open().
@param dev A device handle returned from hid_open().
@param nonblock enable or not the nonblocking reads
- 1 to enable nonblocking
- 0 to disable nonblocking.
@returns
This function returns 0 on success and -1 on error.
Call hid_error(dev) to get the failure reason.
*/
int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock);
int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock);
/** @brief Send a Feature report to the device.
@ -279,7 +406,7 @@ extern "C" {
in would be 17.
@ingroup API
@param device A device handle returned from hid_open().
@param dev A device handle returned from hid_open().
@param data The data to send, including the report number as
the first byte.
@param length The length in bytes of the data to send, including
@ -288,8 +415,9 @@ extern "C" {
@returns
This function returns the actual number of bytes written and
-1 on error.
Call hid_error(dev) to get the failure reason.
*/
int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length);
int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length);
/** @brief Get a feature report from a HID device.
@ -300,7 +428,7 @@ extern "C" {
start in data[1].
@ingroup API
@param device A device handle returned from hid_open().
@param dev 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
@ -313,79 +441,218 @@ extern "C" {
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.
Call hid_error(dev) to get the failure reason.
*/
int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length);
int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length);
/** @brief Send a Output report to the device.
Since version 0.15.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 15, 0)
Output reports are sent over the Control endpoint as a
Set_Report transfer. The first byte of @p data[] must
contain the Report ID. For devices which only support a
single report, this must be set to 0x0. The remaining bytes
contain the report data. Since the Report ID is mandatory,
calls to hid_send_output_report() will always contain one
more byte than the report contains. For example, if a hid
report is 16 bytes long, 17 bytes must be passed to
hid_send_output_report(): the Report ID (or 0x0, for
devices which do not use numbered reports), followed by the
report data (16 bytes). In this example, the length passed
in would be 17.
This function sets the return value of hid_error().
@ingroup API
@param dev A device handle returned from hid_open().
@param data The data to send, including the report number as
the first byte.
@param length The length in bytes of the data to send, including
the report number.
@returns
This function returns the actual number of bytes written and
-1 on error.
@see @ref hid_write
*/
int HID_API_EXPORT HID_API_CALL hid_send_output_report(hid_device* dev, const unsigned char* data, size_t length);
/** @brief Get a input report from a HID device.
Since version 0.10.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 10, 0)
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 dev 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.
Call hid_error(dev) to get the failure reason.
*/
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.
@ingroup API
@param device A device handle returned from hid_open().
@param dev A device handle returned from hid_open().
*/
void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device);
void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev);
/** @brief Get The Manufacturer String from a HID device.
@ingroup API
@param device A device handle returned from hid_open().
@param dev A device handle returned from hid_open().
@param string A wide string buffer to put the data into.
@param maxlen The length of the buffer in multiples of wchar_t.
@returns
This function returns 0 on success and -1 on error.
Call hid_error(dev) to get the failure reason.
*/
int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen);
int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen);
/** @brief Get The Product String from a HID device.
@ingroup API
@param device A device handle returned from hid_open().
@param dev A device handle returned from hid_open().
@param string A wide string buffer to put the data into.
@param maxlen The length of the buffer in multiples of wchar_t.
@returns
This function returns 0 on success and -1 on error.
Call hid_error(dev) to get the failure reason.
*/
int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen);
int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen);
/** @brief Get The Serial Number String from a HID device.
@ingroup API
@param device A device handle returned from hid_open().
@param dev A device handle returned from hid_open().
@param string A wide string buffer to put the data into.
@param maxlen The length of the buffer in multiples of wchar_t.
@returns
This function returns 0 on success and -1 on error.
Call hid_error(dev) to get the failure reason.
*/
int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen);
int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen);
/** @brief Get The struct #hid_device_info from a HID device.
Since version 0.13.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 13, 0)
@ingroup API
@param dev A device handle returned from hid_open().
@returns
This function returns a pointer to the struct #hid_device_info
for this hid_device, or NULL in the case of failure.
Call hid_error(dev) to get the failure reason.
This struct is valid until the device is closed with hid_close().
@note The returned object is owned by the @p dev, and SHOULD NOT be freed by the user.
*/
struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_get_device_info(hid_device *dev);
/** @brief Get a string from a HID device, based on its string index.
@ingroup API
@param device A device handle returned from hid_open().
@param dev A device handle returned from hid_open().
@param string_index The index of the string to get.
@param string A wide string buffer to put the data into.
@param maxlen The length of the buffer in multiples of wchar_t.
@returns
This function returns 0 on success and -1 on error.
Call hid_error(dev) to get the failure reason.
*/
int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen);
int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen);
/** @brief Get a report descriptor from a HID device.
Since version 0.14.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 14, 0)
User has to provide a preallocated buffer where descriptor will be copied to.
The recommended size for preallocated buffer is @ref HID_API_MAX_REPORT_DESCRIPTOR_SIZE bytes.
@ingroup API
@param dev A device handle returned from hid_open().
@param buf The buffer to copy descriptor into.
@param buf_size The size of the buffer in bytes.
@returns
This function returns non-negative number of bytes actually copied, or -1 on error.
*/
int HID_API_EXPORT_CALL hid_get_report_descriptor(hid_device *dev, unsigned char *buf, size_t buf_size);
/** @brief Get a string describing the last error which occurred.
This function is intended for logging/debugging purposes.
This function guarantees to never return NULL.
If there was no error in the last function call -
the returned string clearly indicates that.
Any HIDAPI function that can explicitly indicate an execution failure
(e.g. by an error code, or by returning NULL) - may set the error string,
to be returned by this function.
Strings returned from hid_error() must not be freed by the user,
i.e. owned by HIDAPI library.
Device-specific error string may remain allocated at most until hid_close() is called.
Global error string may remain allocated at most until hid_exit() is called.
@ingroup API
@param device A device handle returned from hid_open().
@param dev A device handle returned from hid_open(),
or NULL to get the last non-device-specific error
(e.g. for errors in hid_open() or hid_enumerate()).
@returns
This function returns a string containing the last error
which occurred or NULL if none has occurred.
A string describing the last error (if any).
*/
HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device);
HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *dev);
/** @brief Get a runtime version of the library.
This function is thread-safe.
@ingroup API
@returns
Pointer to statically allocated struct, that contains version.
*/
HID_API_EXPORT const struct hid_api_version* HID_API_CALL hid_version(void);
/** @brief Get a runtime version string of the library.
This function is thread-safe.
@ingroup API
@returns
Pointer to statically allocated string, that contains version string.
*/
HID_API_EXPORT const char* HID_API_CALL hid_version_str(void);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,98 @@
/*******************************************************
HIDAPI - Multi-Platform library for
communication with HID devices.
libusb/hidapi Team
Copyright 2022, All Rights Reserved.
At the discretion of the user of this library,
this software may be licensed under the terms of the
GNU General Public License v3, a BSD-Style license, or the
original HIDAPI license as outlined in the LICENSE.txt,
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
files located at the root of the source distribution.
These files may also be found in the public source
code repository located at:
https://github.com/libusb/hidapi .
********************************************************/
/** @file
* @defgroup API hidapi API
* Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
*/
#ifndef HIDAPI_DARWIN_H__
#define HIDAPI_DARWIN_H__
#include <stdint.h>
#include "hidapi.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Get the location ID for a HID device.
Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
@ingroup API
@param dev A device handle returned from hid_open().
@param location_id The device's location ID on return.
@returns
This function returns 0 on success and -1 on error.
*/
int HID_API_EXPORT_CALL hid_darwin_get_location_id(hid_device *dev, uint32_t *location_id);
/** @brief Changes the behavior of all further calls to @ref hid_open or @ref hid_open_path.
By default on Darwin platform all devices opened by HIDAPI with @ref hid_open or @ref hid_open_path
are opened in exclusive mode (see kIOHIDOptionsTypeSeizeDevice).
Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
@ingroup API
@param open_exclusive When set to 0 - all further devices will be opened
in non-exclusive mode. Otherwise - all further devices will be opened
in exclusive mode.
@note During the initialisation by @ref hid_init - this property is set to 1 (TRUE).
This is done to preserve full backward compatibility with previous behavior.
@note Calling this function before @ref hid_init or after @ref hid_exit has no effect.
*/
void HID_API_EXPORT_CALL hid_darwin_set_open_exclusive(int open_exclusive);
/** @brief Getter for option set by @ref hid_darwin_set_open_exclusive.
Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
@ingroup API
@return 1 if all further devices will be opened in exclusive mode.
@note Value returned by this function before calling to @ref hid_init or after @ref hid_exit
is not reliable.
*/
int HID_API_EXPORT_CALL hid_darwin_get_open_exclusive(void);
/** @brief Check how the device was opened.
Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
@ingroup API
@param dev A device to get property from.
@return 1 if the device is opened in exclusive mode, 0 - opened in non-exclusive,
-1 - if dev is invalid.
*/
int HID_API_EXPORT_CALL hid_darwin_is_device_open_exclusive(hid_device *dev);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,75 @@
/*******************************************************
HIDAPI - Multi-Platform library for
communication with HID devices.
libusb/hidapi Team
Copyright 2022, All Rights Reserved.
At the discretion of the user of this library,
this software may be licensed under the terms of the
GNU General Public License v3, a BSD-Style license, or the
original HIDAPI license as outlined in the LICENSE.txt,
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
files located at the root of the source distribution.
These files may also be found in the public source
code repository located at:
https://github.com/libusb/hidapi .
********************************************************/
#ifndef HIDAPI_CFGMGR32_H
#define HIDAPI_CFGMGR32_H
#ifdef HIDAPI_USE_DDK
#include <cfgmgr32.h>
#include <initguid.h>
#include <devpkey.h>
#include <propkey.h>
#else
/* This part of the header mimics cfgmgr32.h,
but only what is used by HIDAPI */
#include <initguid.h>
#include <devpropdef.h>
#include <propkeydef.h>
typedef DWORD RETURN_TYPE;
typedef RETURN_TYPE CONFIGRET;
typedef DWORD DEVNODE, DEVINST;
typedef DEVNODE* PDEVNODE, * PDEVINST;
typedef WCHAR* DEVNODEID_W, * DEVINSTID_W;
#define CR_SUCCESS (0x00000000)
#define CR_BUFFER_SMALL (0x0000001A)
#define CR_FAILURE (0x00000013)
#define CM_LOCATE_DEVNODE_NORMAL 0x00000000
#define CM_GET_DEVICE_INTERFACE_LIST_PRESENT (0x00000000)
typedef CONFIGRET(__stdcall* CM_Locate_DevNodeW_)(PDEVINST pdnDevInst, DEVINSTID_W pDeviceID, ULONG ulFlags);
typedef CONFIGRET(__stdcall* CM_Get_Parent_)(PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags);
typedef CONFIGRET(__stdcall* CM_Get_DevNode_PropertyW_)(DEVINST dnDevInst, CONST DEVPROPKEY* PropertyKey, DEVPROPTYPE* PropertyType, PBYTE PropertyBuffer, PULONG PropertyBufferSize, ULONG ulFlags);
typedef CONFIGRET(__stdcall* CM_Get_Device_Interface_PropertyW_)(LPCWSTR pszDeviceInterface, CONST DEVPROPKEY* PropertyKey, DEVPROPTYPE* PropertyType, PBYTE PropertyBuffer, PULONG PropertyBufferSize, ULONG ulFlags);
typedef CONFIGRET(__stdcall* CM_Get_Device_Interface_List_SizeW_)(PULONG pulLen, LPGUID InterfaceClassGuid, DEVINSTID_W pDeviceID, ULONG ulFlags);
typedef CONFIGRET(__stdcall* CM_Get_Device_Interface_ListW_)(LPGUID InterfaceClassGuid, DEVINSTID_W pDeviceID, PZZWSTR Buffer, ULONG BufferLen, ULONG ulFlags);
// from devpkey.h
DEFINE_DEVPROPKEY(DEVPKEY_NAME, 0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac, 10); // DEVPROP_TYPE_STRING
DEFINE_DEVPROPKEY(DEVPKEY_Device_Manufacturer, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 13); // DEVPROP_TYPE_STRING
DEFINE_DEVPROPKEY(DEVPKEY_Device_InstanceId, 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 256); // DEVPROP_TYPE_STRING
DEFINE_DEVPROPKEY(DEVPKEY_Device_HardwareIds, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 3); // DEVPROP_TYPE_STRING_LIST
DEFINE_DEVPROPKEY(DEVPKEY_Device_CompatibleIds, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 4); // DEVPROP_TYPE_STRING_LIST
DEFINE_DEVPROPKEY(DEVPKEY_Device_ContainerId, 0x8c7ed206, 0x3f8a, 0x4827, 0xb3, 0xab, 0xae, 0x9e, 0x1f, 0xae, 0xfc, 0x6c, 2); // DEVPROP_TYPE_GUID
// from propkey.h
DEFINE_PROPERTYKEY(PKEY_DeviceInterface_Bluetooth_DeviceAddress, 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A, 1); // DEVPROP_TYPE_STRING
DEFINE_PROPERTYKEY(PKEY_DeviceInterface_Bluetooth_Manufacturer, 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A, 4); // DEVPROP_TYPE_STRING
DEFINE_PROPERTYKEY(PKEY_DeviceInterface_Bluetooth_ModelNumber, 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A, 5); // DEVPROP_TYPE_STRING
#endif
#endif /* HIDAPI_CFGMGR32_H */

View File

@ -0,0 +1,987 @@
/*******************************************************
HIDAPI - Multi-Platform library for
communication with HID devices.
libusb/hidapi Team
Copyright 2022, All Rights Reserved.
At the discretion of the user of this library,
this software may be licensed under the terms of the
GNU General Public License v3, a BSD-Style license, or the
original HIDAPI license as outlined in the LICENSE.txt,
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
files located at the root of the source distribution.
These files may also be found in the public source
code repository located at:
https://github.com/libusb/hidapi .
********************************************************/
#include "hidapi_descriptor_reconstruct.h"
/**
* @brief References to report descriptor buffer.
*
*/
struct rd_buffer {
unsigned char* buf; /* Pointer to the array which stores the reconstructed descriptor */
size_t buf_size; /* Size of the buffer in bytes */
size_t byte_idx; /* Index of the next report byte to write to buf array */
};
/**
* @brief Function that appends a byte to encoded report descriptor buffer.
*
* @param[in] byte Single byte to append.
* @param rpt_desc Pointer to report descriptor buffer struct.
*/
static void rd_append_byte(unsigned char byte, struct rd_buffer* rpt_desc) {
if (rpt_desc->byte_idx < rpt_desc->buf_size) {
rpt_desc->buf[rpt_desc->byte_idx] = byte;
rpt_desc->byte_idx++;
}
}
/**
* @brief Writes a short report descriptor item according USB HID spec 1.11 chapter 6.2.2.2.
*
* @param[in] rd_item Enumeration identifying type (Main, Global, Local) and function (e.g Usage or Report Count) of the item.
* @param[in] data Data (Size depends on rd_item 0,1,2 or 4bytes).
* @param rpt_desc Pointer to report descriptor buffer struct.
*
* @return Returns 0 if successful, -1 for error.
*/
static int rd_write_short_item(rd_items rd_item, LONG64 data, struct rd_buffer* rpt_desc) {
if (rd_item & 0x03) {
// Invalid input data, last to bits are reserved for data size
return -1;
}
if (rd_item == rd_main_collection_end) {
// Item without data (1Byte prefix only)
unsigned char oneBytePrefix = (unsigned char) rd_item + 0x00;
rd_append_byte(oneBytePrefix, rpt_desc);
}
else if ((rd_item == rd_global_logical_minimum) ||
(rd_item == rd_global_logical_maximum) ||
(rd_item == rd_global_physical_minimum) ||
(rd_item == rd_global_physical_maximum)) {
// Item with signed integer data
if ((data >= -128) && (data <= 127)) {
// 1Byte prefix + 1Byte data
unsigned char oneBytePrefix = (unsigned char) rd_item + 0x01;
char localData = (char)data;
rd_append_byte(oneBytePrefix, rpt_desc);
rd_append_byte(localData & 0xFF, rpt_desc);
}
else if ((data >= -32768) && (data <= 32767)) {
// 1Byte prefix + 2Byte data
unsigned char oneBytePrefix = (unsigned char) rd_item + 0x02;
INT16 localData = (INT16)data;
rd_append_byte(oneBytePrefix, rpt_desc);
rd_append_byte(localData & 0xFF, rpt_desc);
rd_append_byte(localData >> 8 & 0xFF, rpt_desc);
}
else if ((data >= -2147483648LL) && (data <= 2147483647)) {
// 1Byte prefix + 4Byte data
unsigned char oneBytePrefix = (unsigned char) rd_item + 0x03;
INT32 localData = (INT32)data;
rd_append_byte(oneBytePrefix, rpt_desc);
rd_append_byte(localData & 0xFF, rpt_desc);
rd_append_byte(localData >> 8 & 0xFF, rpt_desc);
rd_append_byte(localData >> 16 & 0xFF, rpt_desc);
rd_append_byte(localData >> 24 & 0xFF, rpt_desc);
}
else {
// Data out of 32 bit signed integer range
return -1;
}
}
else {
// Item with unsigned integer data
if ((data >= 0) && (data <= 0xFF)) {
// 1Byte prefix + 1Byte data
unsigned char oneBytePrefix = (unsigned char) rd_item + 0x01;
unsigned char localData = (unsigned char)data;
rd_append_byte(oneBytePrefix, rpt_desc);
rd_append_byte(localData & 0xFF, rpt_desc);
}
else if ((data >= 0) && (data <= 0xFFFF)) {
// 1Byte prefix + 2Byte data
unsigned char oneBytePrefix = (unsigned char) rd_item + 0x02;
UINT16 localData = (UINT16)data;
rd_append_byte(oneBytePrefix, rpt_desc);
rd_append_byte(localData & 0xFF, rpt_desc);
rd_append_byte(localData >> 8 & 0xFF, rpt_desc);
}
else if ((data >= 0) && (data <= 0xFFFFFFFF)) {
// 1Byte prefix + 4Byte data
unsigned char oneBytePrefix = (unsigned char) rd_item + 0x03;
UINT32 localData = (UINT32)data;
rd_append_byte(oneBytePrefix, rpt_desc);
rd_append_byte(localData & 0xFF, rpt_desc);
rd_append_byte(localData >> 8 & 0xFF, rpt_desc);
rd_append_byte(localData >> 16 & 0xFF, rpt_desc);
rd_append_byte(localData >> 24 & 0xFF, rpt_desc);
}
else {
// Data out of 32 bit unsigned integer range
return -1;
}
}
return 0;
}
static struct rd_main_item_node * rd_append_main_item_node(int first_bit, int last_bit, rd_node_type type_of_node, int caps_index, int collection_index, rd_main_items main_item_type, unsigned char report_id, struct rd_main_item_node **list) {
struct rd_main_item_node *new_list_node;
// Determine last node in the list
while (*list != NULL)
{
list = &(*list)->next;
}
new_list_node = malloc(sizeof(*new_list_node)); // Create new list entry
new_list_node->FirstBit = first_bit;
new_list_node->LastBit = last_bit;
new_list_node->TypeOfNode = type_of_node;
new_list_node->CapsIndex = caps_index;
new_list_node->CollectionIndex = collection_index;
new_list_node->MainItemType = main_item_type;
new_list_node->ReportID = report_id;
new_list_node->next = NULL; // NULL marks last node in the list
*list = new_list_node;
return new_list_node;
}
static struct rd_main_item_node * rd_insert_main_item_node(int first_bit, int last_bit, rd_node_type type_of_node, int caps_index, int collection_index, rd_main_items main_item_type, unsigned char report_id, struct rd_main_item_node **list) {
// Insert item after the main item node referenced by list
struct rd_main_item_node *next_item = (*list)->next;
(*list)->next = NULL;
rd_append_main_item_node(first_bit, last_bit, type_of_node, caps_index, collection_index, main_item_type, report_id, list);
(*list)->next->next = next_item;
return (*list)->next;
}
static struct rd_main_item_node * rd_search_main_item_list_for_bit_position(int search_bit, rd_main_items main_item_type, unsigned char report_id, struct rd_main_item_node **list) {
// Determine first INPUT/OUTPUT/FEATURE main item, where the last bit position is equal or greater than the search bit position
while (((*list)->next->MainItemType != rd_collection) &&
((*list)->next->MainItemType != rd_collection_end) &&
!(((*list)->next->LastBit >= search_bit) &&
((*list)->next->ReportID == report_id) &&
((*list)->next->MainItemType == main_item_type))
)
{
list = &(*list)->next;
}
return *list;
}
int hid_winapi_descriptor_reconstruct_pp_data(void *preparsed_data, unsigned char *buf, size_t buf_size)
{
hidp_preparsed_data *pp_data = (hidp_preparsed_data *) preparsed_data;
// Check if MagicKey is correct, to ensure that pp_data points to an valid preparse data structure
if (memcmp(pp_data->MagicKey, "HidP KDR", 8) != 0) {
return -1;
}
struct rd_buffer rpt_desc = {
.buf = buf,
.buf_size = buf_size,
.byte_idx = 0
};
// Set pointer to the first node of link_collection_nodes
phid_pp_link_collection_node link_collection_nodes = (phid_pp_link_collection_node)(((unsigned char*)&pp_data->caps[0]) + pp_data->FirstByteOfLinkCollectionArray);
// ****************************************************************************************************************************
// Create lookup tables for the bit range of each report per collection (position of first bit and last bit in each collection)
// coll_bit_range[COLLECTION_INDEX][REPORT_ID][INPUT/OUTPUT/FEATURE]
// ****************************************************************************************************************************
// Allocate memory and initialize lookup table
rd_bit_range ****coll_bit_range;
coll_bit_range = malloc(pp_data->NumberLinkCollectionNodes * sizeof(*coll_bit_range));
for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
coll_bit_range[collection_node_idx] = malloc(256 * sizeof(*coll_bit_range[0])); // 256 possible report IDs (incl. 0x00)
for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
coll_bit_range[collection_node_idx][reportid_idx] = malloc(NUM_OF_HIDP_REPORT_TYPES * sizeof(*coll_bit_range[0][0]));
for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
coll_bit_range[collection_node_idx][reportid_idx][rt_idx] = malloc(sizeof(rd_bit_range));
coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->FirstBit = -1;
coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->LastBit = -1;
}
}
}
// Fill the lookup table where caps exist
for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
for (USHORT caps_idx = pp_data->caps_info[rt_idx].FirstCap; caps_idx < pp_data->caps_info[rt_idx].LastCap; caps_idx++) {
int first_bit, last_bit;
first_bit = (pp_data->caps[caps_idx].BytePosition - 1) * 8
+ pp_data->caps[caps_idx].BitPosition;
last_bit = first_bit + pp_data->caps[caps_idx].ReportSize
* pp_data->caps[caps_idx].ReportCount - 1;
if (coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->FirstBit == -1 ||
coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->FirstBit > first_bit) {
coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->FirstBit = first_bit;
}
if (coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->LastBit < last_bit) {
coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->LastBit = last_bit;
}
}
}
// *************************************************************************
// -Determine hierarchy levels of each collections and store it in:
// coll_levels[COLLECTION_INDEX]
// -Determine number of direct childs of each collections and store it in:
// coll_number_of_direct_childs[COLLECTION_INDEX]
// *************************************************************************
int max_coll_level = 0;
int *coll_levels = malloc(pp_data->NumberLinkCollectionNodes * sizeof(coll_levels[0]));
int *coll_number_of_direct_childs = malloc(pp_data->NumberLinkCollectionNodes * sizeof(coll_number_of_direct_childs[0]));
for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
coll_levels[collection_node_idx] = -1;
coll_number_of_direct_childs[collection_node_idx] = 0;
}
{
int actual_coll_level = 0;
USHORT collection_node_idx = 0;
while (actual_coll_level >= 0) {
coll_levels[collection_node_idx] = actual_coll_level;
if ((link_collection_nodes[collection_node_idx].NumberOfChildren > 0) &&
(coll_levels[link_collection_nodes[collection_node_idx].FirstChild] == -1)) {
actual_coll_level++;
coll_levels[collection_node_idx] = actual_coll_level;
if (max_coll_level < actual_coll_level) {
max_coll_level = actual_coll_level;
}
coll_number_of_direct_childs[collection_node_idx]++;
collection_node_idx = link_collection_nodes[collection_node_idx].FirstChild;
}
else if (link_collection_nodes[collection_node_idx].NextSibling != 0) {
coll_number_of_direct_childs[link_collection_nodes[collection_node_idx].Parent]++;
collection_node_idx = link_collection_nodes[collection_node_idx].NextSibling;
}
else {
actual_coll_level--;
if (actual_coll_level >= 0) {
collection_node_idx = link_collection_nodes[collection_node_idx].Parent;
}
}
}
}
// *********************************************************************************
// Propagate the bit range of each report from the child collections to their parent
// and store the merged result for the parent
// *********************************************************************************
for (int actual_coll_level = max_coll_level - 1; actual_coll_level >= 0; actual_coll_level--) {
for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
if (coll_levels[collection_node_idx] == actual_coll_level) {
USHORT child_idx = link_collection_nodes[collection_node_idx].FirstChild;
while (child_idx) {
for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
// Merge bit range from childs
if ((coll_bit_range[child_idx][reportid_idx][rt_idx]->FirstBit != -1) &&
(coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->FirstBit > coll_bit_range[child_idx][reportid_idx][rt_idx]->FirstBit)) {
coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->FirstBit = coll_bit_range[child_idx][reportid_idx][rt_idx]->FirstBit;
}
if (coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->LastBit < coll_bit_range[child_idx][reportid_idx][rt_idx]->LastBit) {
coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->LastBit = coll_bit_range[child_idx][reportid_idx][rt_idx]->LastBit;
}
child_idx = link_collection_nodes[child_idx].NextSibling;
}
}
}
}
}
}
// **************************************************************************************************
// Determine child collection order of the whole hierarchy, based on previously determined bit ranges
// and store it this index coll_child_order[COLLECTION_INDEX][DIRECT_CHILD_INDEX]
// **************************************************************************************************
USHORT **coll_child_order;
coll_child_order = malloc(pp_data->NumberLinkCollectionNodes * sizeof(*coll_child_order));
{
BOOLEAN *coll_parsed_flag;
coll_parsed_flag = malloc(pp_data->NumberLinkCollectionNodes * sizeof(coll_parsed_flag[0]));
for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
coll_parsed_flag[collection_node_idx] = FALSE;
}
int actual_coll_level = 0;
USHORT collection_node_idx = 0;
while (actual_coll_level >= 0) {
if ((coll_number_of_direct_childs[collection_node_idx] != 0) &&
(coll_parsed_flag[link_collection_nodes[collection_node_idx].FirstChild] == FALSE)) {
coll_parsed_flag[link_collection_nodes[collection_node_idx].FirstChild] = TRUE;
coll_child_order[collection_node_idx] = malloc((coll_number_of_direct_childs[collection_node_idx]) * sizeof(*coll_child_order[0]));
{
// Create list of child collection indices
// sorted reverse to the order returned to HidP_GetLinkCollectionNodeschild
// which seems to match the original order, as long as no bit position needs to be considered
USHORT child_idx = link_collection_nodes[collection_node_idx].FirstChild;
int child_count = coll_number_of_direct_childs[collection_node_idx] - 1;
coll_child_order[collection_node_idx][child_count] = child_idx;
while (link_collection_nodes[child_idx].NextSibling) {
child_count--;
child_idx = link_collection_nodes[child_idx].NextSibling;
coll_child_order[collection_node_idx][child_count] = child_idx;
}
}
if (coll_number_of_direct_childs[collection_node_idx] > 1) {
// Sort child collections indices by bit positions
for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
for (int child_idx = 1; child_idx < coll_number_of_direct_childs[collection_node_idx]; child_idx++) {
// since the coll_bit_range array is not sorted, we need to reference the collection index in
// our sorted coll_child_order array, and look up the corresponding bit ranges for comparing values to sort
int prev_coll_idx = coll_child_order[collection_node_idx][child_idx - 1];
int cur_coll_idx = coll_child_order[collection_node_idx][child_idx];
if ((coll_bit_range[prev_coll_idx][reportid_idx][rt_idx]->FirstBit != -1) &&
(coll_bit_range[cur_coll_idx][reportid_idx][rt_idx]->FirstBit != -1) &&
(coll_bit_range[prev_coll_idx][reportid_idx][rt_idx]->FirstBit > coll_bit_range[cur_coll_idx][reportid_idx][rt_idx]->FirstBit)) {
// Swap position indices of the two compared child collections
USHORT idx_latch = coll_child_order[collection_node_idx][child_idx - 1];
coll_child_order[collection_node_idx][child_idx - 1] = coll_child_order[collection_node_idx][child_idx];
coll_child_order[collection_node_idx][child_idx] = idx_latch;
}
}
}
}
}
actual_coll_level++;
collection_node_idx = link_collection_nodes[collection_node_idx].FirstChild;
}
else if (link_collection_nodes[collection_node_idx].NextSibling != 0) {
collection_node_idx = link_collection_nodes[collection_node_idx].NextSibling;
}
else {
actual_coll_level--;
if (actual_coll_level >= 0) {
collection_node_idx = link_collection_nodes[collection_node_idx].Parent;
}
}
}
free(coll_parsed_flag);
}
// ***************************************************************************************
// Create sorted main_item_list containing all the Collection and CollectionEnd main items
// ***************************************************************************************
struct rd_main_item_node *main_item_list = NULL; // List root
// Lookup table to find the Collection items in the list by index
struct rd_main_item_node **coll_begin_lookup = malloc(pp_data->NumberLinkCollectionNodes * sizeof(*coll_begin_lookup));
struct rd_main_item_node **coll_end_lookup = malloc(pp_data->NumberLinkCollectionNodes * sizeof(*coll_end_lookup));
{
int *coll_last_written_child = malloc(pp_data->NumberLinkCollectionNodes * sizeof(coll_last_written_child[0]));
for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
coll_last_written_child[collection_node_idx] = -1;
}
int actual_coll_level = 0;
USHORT collection_node_idx = 0;
struct rd_main_item_node *firstDelimiterNode = NULL;
struct rd_main_item_node *delimiterCloseNode = NULL;
coll_begin_lookup[0] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_collection, 0, &main_item_list);
while (actual_coll_level >= 0) {
if ((coll_number_of_direct_childs[collection_node_idx] != 0) &&
(coll_last_written_child[collection_node_idx] == -1)) {
// Collection has child collections, but none is written to the list yet
coll_last_written_child[collection_node_idx] = coll_child_order[collection_node_idx][0];
collection_node_idx = coll_child_order[collection_node_idx][0];
// In a HID Report Descriptor, the first usage declared is the most preferred usage for the control.
// While the order in the WIN32 capabiliy strutures is the opposite:
// Here the preferred usage is the last aliased usage in the sequence.
if (link_collection_nodes[collection_node_idx].IsAlias && (firstDelimiterNode == NULL)) {
// Alliased Collection (First node in link_collection_nodes -> Last entry in report descriptor output)
firstDelimiterNode = main_item_list;
coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_usage, 0, &main_item_list);
coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_close, 0, &main_item_list);
delimiterCloseNode = main_item_list;
}
else {
// Normal not aliased collection
coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_collection, 0, &main_item_list);
actual_coll_level++;
}
}
else if ((coll_number_of_direct_childs[collection_node_idx] > 1) &&
(coll_last_written_child[collection_node_idx] != coll_child_order[collection_node_idx][coll_number_of_direct_childs[collection_node_idx] - 1])) {
// Collection has child collections, and this is not the first child
int nextChild = 1;
while (coll_last_written_child[collection_node_idx] != coll_child_order[collection_node_idx][nextChild - 1]) {
nextChild++;
}
coll_last_written_child[collection_node_idx] = coll_child_order[collection_node_idx][nextChild];
collection_node_idx = coll_child_order[collection_node_idx][nextChild];
if (link_collection_nodes[collection_node_idx].IsAlias && (firstDelimiterNode == NULL)) {
// Alliased Collection (First node in link_collection_nodes -> Last entry in report descriptor output)
firstDelimiterNode = main_item_list;
coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_usage, 0, &main_item_list);
coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_close, 0, &main_item_list);
delimiterCloseNode = main_item_list;
}
else if (link_collection_nodes[collection_node_idx].IsAlias && (firstDelimiterNode != NULL)) {
coll_begin_lookup[collection_node_idx] = rd_insert_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_usage, 0, &firstDelimiterNode);
}
else if (!link_collection_nodes[collection_node_idx].IsAlias && (firstDelimiterNode != NULL)) {
coll_begin_lookup[collection_node_idx] = rd_insert_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_usage, 0, &firstDelimiterNode);
coll_begin_lookup[collection_node_idx] = rd_insert_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_open, 0, &firstDelimiterNode);
firstDelimiterNode = NULL;
main_item_list = delimiterCloseNode;
delimiterCloseNode = NULL; // Last entry of alias has .IsAlias == FALSE
}
if (!link_collection_nodes[collection_node_idx].IsAlias) {
coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_collection, 0, &main_item_list);
actual_coll_level++;
}
}
else {
actual_coll_level--;
coll_end_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_collection_end, 0, &main_item_list);
collection_node_idx = link_collection_nodes[collection_node_idx].Parent;
}
}
free(coll_last_written_child);
}
// ****************************************************************
// Inserted Input/Output/Feature main items into the main_item_list
// in order of reconstructed bit positions
// ****************************************************************
for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
// Add all value caps to node list
struct rd_main_item_node *firstDelimiterNode = NULL;
struct rd_main_item_node *delimiterCloseNode = NULL;
for (USHORT caps_idx = pp_data->caps_info[rt_idx].FirstCap; caps_idx < pp_data->caps_info[rt_idx].LastCap; caps_idx++) {
struct rd_main_item_node *coll_begin = coll_begin_lookup[pp_data->caps[caps_idx].LinkCollection];
int first_bit, last_bit;
first_bit = (pp_data->caps[caps_idx].BytePosition - 1) * 8 +
pp_data->caps[caps_idx].BitPosition;
last_bit = first_bit + pp_data->caps[caps_idx].ReportSize *
pp_data->caps[caps_idx].ReportCount - 1;
for (int child_idx = 0; child_idx < coll_number_of_direct_childs[pp_data->caps[caps_idx].LinkCollection]; child_idx++) {
// Determine in which section before/between/after child collection the item should be inserted
if (first_bit < coll_bit_range[coll_child_order[pp_data->caps[caps_idx].LinkCollection][child_idx]][pp_data->caps[caps_idx].ReportID][rt_idx]->FirstBit)
{
// Note, that the default value for undefined coll_bit_range is -1, which can't be greater than the bit position
break;
}
coll_begin = coll_end_lookup[coll_child_order[pp_data->caps[caps_idx].LinkCollection][child_idx]];
}
struct rd_main_item_node *list_node;
list_node = rd_search_main_item_list_for_bit_position(first_bit, (rd_main_items) rt_idx, pp_data->caps[caps_idx].ReportID, &coll_begin);
// In a HID Report Descriptor, the first usage declared is the most preferred usage for the control.
// While the order in the WIN32 capabiliy strutures is the opposite:
// Here the preferred usage is the last aliased usage in the sequence.
if (pp_data->caps[caps_idx].IsAlias && (firstDelimiterNode == NULL)) {
// Alliased Usage (First node in pp_data->caps -> Last entry in report descriptor output)
firstDelimiterNode = list_node;
rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_usage, pp_data->caps[caps_idx].ReportID, &list_node);
rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_close, pp_data->caps[caps_idx].ReportID, &list_node);
delimiterCloseNode = list_node;
} else if (pp_data->caps[caps_idx].IsAlias && (firstDelimiterNode != NULL)) {
rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_usage, pp_data->caps[caps_idx].ReportID, &list_node);
}
else if (!pp_data->caps[caps_idx].IsAlias && (firstDelimiterNode != NULL)) {
// Alliased Collection (Last node in pp_data->caps -> First entry in report descriptor output)
rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_usage, pp_data->caps[caps_idx].ReportID, &list_node);
rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_open, pp_data->caps[caps_idx].ReportID, &list_node);
firstDelimiterNode = NULL;
list_node = delimiterCloseNode;
delimiterCloseNode = NULL; // Last entry of alias has .IsAlias == FALSE
}
if (!pp_data->caps[caps_idx].IsAlias) {
rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, (rd_main_items) rt_idx, pp_data->caps[caps_idx].ReportID, &list_node);
}
}
}
// ***********************************************************
// Add const main items for padding to main_item_list
// -To fill all bit gaps
// -At each report end for 8bit padding
// Note that information about the padding at the report end,
// is not stored in the preparsed data, but in practice all
// report descriptors seem to have it, as assumed here.
// ***********************************************************
{
int last_bit_position[NUM_OF_HIDP_REPORT_TYPES][256];
struct rd_main_item_node *last_report_item_lookup[NUM_OF_HIDP_REPORT_TYPES][256];
for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
last_bit_position[rt_idx][reportid_idx] = -1;
last_report_item_lookup[rt_idx][reportid_idx] = NULL;
}
}
struct rd_main_item_node *list = main_item_list; // List root;
while (list->next != NULL)
{
if ((list->MainItemType >= rd_input) &&
(list->MainItemType <= rd_feature)) {
// INPUT, OUTPUT or FEATURE
if (list->FirstBit != -1) {
if ((last_bit_position[list->MainItemType][list->ReportID] + 1 != list->FirstBit) &&
(last_report_item_lookup[list->MainItemType][list->ReportID] != NULL) &&
(last_report_item_lookup[list->MainItemType][list->ReportID]->FirstBit != list->FirstBit) // Happens in case of IsMultipleItemsForArray for multiple dedicated usages for a multi-button array
) {
struct rd_main_item_node *list_node = rd_search_main_item_list_for_bit_position(last_bit_position[list->MainItemType][list->ReportID], list->MainItemType, list->ReportID, &last_report_item_lookup[list->MainItemType][list->ReportID]);
rd_insert_main_item_node(last_bit_position[list->MainItemType][list->ReportID] + 1, list->FirstBit - 1, rd_item_node_padding, -1, 0, list->MainItemType, list->ReportID, &list_node);
}
last_bit_position[list->MainItemType][list->ReportID] = list->LastBit;
last_report_item_lookup[list->MainItemType][list->ReportID] = list;
}
}
list = list->next;
}
// Add 8 bit padding at each report end
for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
if (last_bit_position[rt_idx][reportid_idx] != -1) {
int padding = 8 - ((last_bit_position[rt_idx][reportid_idx] + 1) % 8);
if (padding < 8) {
// Insert padding item after item referenced in last_report_item_lookup
rd_insert_main_item_node(last_bit_position[rt_idx][reportid_idx] + 1, last_bit_position[rt_idx][reportid_idx] + padding, rd_item_node_padding, -1, 0, (rd_main_items) rt_idx, (unsigned char) reportid_idx, &last_report_item_lookup[rt_idx][reportid_idx]);
}
}
}
}
}
// ***********************************
// Encode the report descriptor output
// ***********************************
UCHAR last_report_id = 0;
USAGE last_usage_page = 0;
LONG last_physical_min = 0;// If both, Physical Minimum and Physical Maximum are 0, the logical limits should be taken as physical limits according USB HID spec 1.11 chapter 6.2.2.7
LONG last_physical_max = 0;
ULONG last_unit_exponent = 0; // If Unit Exponent is Undefined it should be considered as 0 according USB HID spec 1.11 chapter 6.2.2.7
ULONG last_unit = 0; // If the first nibble is 7, or second nibble of Unit is 0, the unit is None according USB HID spec 1.11 chapter 6.2.2.7
BOOLEAN inhibit_write_of_usage = FALSE; // Needed in case of delimited usage print, before the normal collection or cap
int report_count = 0;
while (main_item_list != NULL)
{
int rt_idx = main_item_list->MainItemType;
int caps_idx = main_item_list->CapsIndex;
if (main_item_list->MainItemType == rd_collection) {
if (last_usage_page != link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage) {
// Write "Usage Page" at the begin of a collection - except it refers the same table as wrote last
rd_write_short_item(rd_global_usage_page, link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage, &rpt_desc);
last_usage_page = link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage;
}
if (inhibit_write_of_usage) {
// Inhibit only once after DELIMITER statement
inhibit_write_of_usage = FALSE;
}
else {
// Write "Usage" of collection
rd_write_short_item(rd_local_usage, link_collection_nodes[main_item_list->CollectionIndex].LinkUsage, &rpt_desc);
}
// Write begin of "Collection"
rd_write_short_item(rd_main_collection, link_collection_nodes[main_item_list->CollectionIndex].CollectionType, &rpt_desc);
}
else if (main_item_list->MainItemType == rd_collection_end) {
// Write "End Collection"
rd_write_short_item(rd_main_collection_end, 0, &rpt_desc);
}
else if (main_item_list->MainItemType == rd_delimiter_open) {
if (main_item_list->CollectionIndex != -1) {
// Write "Usage Page" inside of a collection delmiter section
if (last_usage_page != link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage) {
rd_write_short_item(rd_global_usage_page, link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage, &rpt_desc);
last_usage_page = link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage;
}
}
else if (main_item_list->CapsIndex != 0) {
// Write "Usage Page" inside of a main item delmiter section
if (pp_data->caps[caps_idx].UsagePage != last_usage_page) {
rd_write_short_item(rd_global_usage_page, pp_data->caps[caps_idx].UsagePage, &rpt_desc);
last_usage_page = pp_data->caps[caps_idx].UsagePage;
}
}
// Write "Delimiter Open"
rd_write_short_item(rd_local_delimiter, 1, &rpt_desc); // 1 = open set of aliased usages
}
else if (main_item_list->MainItemType == rd_delimiter_usage) {
if (main_item_list->CollectionIndex != -1) {
// Write aliased collection "Usage"
rd_write_short_item(rd_local_usage, link_collection_nodes[main_item_list->CollectionIndex].LinkUsage, &rpt_desc);
} if (main_item_list->CapsIndex != 0) {
// Write aliased main item range from "Usage Minimum" to "Usage Maximum"
if (pp_data->caps[caps_idx].IsRange) {
rd_write_short_item(rd_local_usage_minimum, pp_data->caps[caps_idx].Range.UsageMin, &rpt_desc);
rd_write_short_item(rd_local_usage_maximum, pp_data->caps[caps_idx].Range.UsageMax, &rpt_desc);
}
else {
// Write single aliased main item "Usage"
rd_write_short_item(rd_local_usage, pp_data->caps[caps_idx].NotRange.Usage, &rpt_desc);
}
}
}
else if (main_item_list->MainItemType == rd_delimiter_close) {
// Write "Delimiter Close"
rd_write_short_item(rd_local_delimiter, 0, &rpt_desc); // 0 = close set of aliased usages
// Inhibit next usage write
inhibit_write_of_usage = TRUE;
}
else if (main_item_list->TypeOfNode == rd_item_node_padding) {
// Padding
// The preparsed data doesn't contain any information about padding. Therefore all undefined gaps
// in the reports are filled with the same style of constant padding.
// Write "Report Size" with number of padding bits
rd_write_short_item(rd_global_report_size, (main_item_list->LastBit - main_item_list->FirstBit + 1), &rpt_desc);
// Write "Report Count" for padding always as 1
rd_write_short_item(rd_global_report_count, 1, &rpt_desc);
if (rt_idx == HidP_Input) {
// Write "Input" main item - We know it's Constant - We can only guess the other bits, but they don't matter in case of const
rd_write_short_item(rd_main_input, 0x03, &rpt_desc); // Const / Abs
}
else if (rt_idx == HidP_Output) {
// Write "Output" main item - We know it's Constant - We can only guess the other bits, but they don't matter in case of const
rd_write_short_item(rd_main_output, 0x03, &rpt_desc); // Const / Abs
}
else if (rt_idx == HidP_Feature) {
// Write "Feature" main item - We know it's Constant - We can only guess the other bits, but they don't matter in case of const
rd_write_short_item(rd_main_feature, 0x03, &rpt_desc); // Const / Abs
}
report_count = 0;
}
else if (pp_data->caps[caps_idx].IsButtonCap) {
// Button
// (The preparsed data contain different data for 1 bit Button caps, than for parametric Value caps)
if (last_report_id != pp_data->caps[caps_idx].ReportID) {
// Write "Report ID" if changed
rd_write_short_item(rd_global_report_id, pp_data->caps[caps_idx].ReportID, &rpt_desc);
last_report_id = pp_data->caps[caps_idx].ReportID;
}
// Write "Usage Page" when changed
if (pp_data->caps[caps_idx].UsagePage != last_usage_page) {
rd_write_short_item(rd_global_usage_page, pp_data->caps[caps_idx].UsagePage, &rpt_desc);
last_usage_page = pp_data->caps[caps_idx].UsagePage;
}
// Write only local report items for each cap, if ReportCount > 1
if (pp_data->caps[caps_idx].IsRange) {
report_count += (pp_data->caps[caps_idx].Range.DataIndexMax - pp_data->caps[caps_idx].Range.DataIndexMin);
}
if (inhibit_write_of_usage) {
// Inhibit only once after Delimiter - Reset flag
inhibit_write_of_usage = FALSE;
}
else {
if (pp_data->caps[caps_idx].IsRange) {
// Write range from "Usage Minimum" to "Usage Maximum"
rd_write_short_item(rd_local_usage_minimum, pp_data->caps[caps_idx].Range.UsageMin, &rpt_desc);
rd_write_short_item(rd_local_usage_maximum, pp_data->caps[caps_idx].Range.UsageMax, &rpt_desc);
}
else {
// Write single "Usage"
rd_write_short_item(rd_local_usage, pp_data->caps[caps_idx].NotRange.Usage, &rpt_desc);
}
}
if (pp_data->caps[caps_idx].IsDesignatorRange) {
// Write physical descriptor indices range from "Designator Minimum" to "Designator Maximum"
rd_write_short_item(rd_local_designator_minimum, pp_data->caps[caps_idx].Range.DesignatorMin, &rpt_desc);
rd_write_short_item(rd_local_designator_maximum, pp_data->caps[caps_idx].Range.DesignatorMax, &rpt_desc);
}
else if (pp_data->caps[caps_idx].NotRange.DesignatorIndex != 0) {
// Designator set 0 is a special descriptor set (of the HID Physical Descriptor),
// that specifies the number of additional descriptor sets.
// Therefore Designator Index 0 can never be a useful reference for a control and we can inhibit it.
// Write single "Designator Index"
rd_write_short_item(rd_local_designator_index, pp_data->caps[caps_idx].NotRange.DesignatorIndex, &rpt_desc);
}
if (pp_data->caps[caps_idx].IsStringRange) {
// Write range of indices of the USB string descriptor, from "String Minimum" to "String Maximum"
rd_write_short_item(rd_local_string_minimum, pp_data->caps[caps_idx].Range.StringMin, &rpt_desc);
rd_write_short_item(rd_local_string_maximum, pp_data->caps[caps_idx].Range.StringMax, &rpt_desc);
}
else if (pp_data->caps[caps_idx].NotRange.StringIndex != 0) {
// String Index 0 is a special entry of the USB string descriptor, that contains a list of supported languages,
// therefore Designator Index 0 can never be a useful reference for a control and we can inhibit it.
// Write single "String Index"
rd_write_short_item(rd_local_string, pp_data->caps[caps_idx].NotRange.StringIndex, &rpt_desc);
}
if ((main_item_list->next != NULL) &&
((int)main_item_list->next->MainItemType == rt_idx) &&
(main_item_list->next->TypeOfNode == rd_item_node_cap) &&
(pp_data->caps[main_item_list->next->CapsIndex].IsButtonCap) &&
(!pp_data->caps[caps_idx].IsRange) && // This node in list is no array
(!pp_data->caps[main_item_list->next->CapsIndex].IsRange) && // Next node in list is no array
(pp_data->caps[main_item_list->next->CapsIndex].UsagePage == pp_data->caps[caps_idx].UsagePage) &&
(pp_data->caps[main_item_list->next->CapsIndex].ReportID == pp_data->caps[caps_idx].ReportID) &&
(pp_data->caps[main_item_list->next->CapsIndex].BitField == pp_data->caps[caps_idx].BitField)
) {
if (main_item_list->next->FirstBit != main_item_list->FirstBit) {
// In case of IsMultipleItemsForArray for multiple dedicated usages for a multi-button array, the report count should be incremented
// Skip global items until any of them changes, than use ReportCount item to write the count of identical report fields
report_count++;
}
}
else {
if ((pp_data->caps[caps_idx].Button.LogicalMin == 0) &&
(pp_data->caps[caps_idx].Button.LogicalMax == 0)) {
// While a HID report descriptor must always contain LogicalMinimum and LogicalMaximum,
// the preparsed data contain both fields set to zero, for the case of simple buttons
// Write "Logical Minimum" set to 0 and "Logical Maximum" set to 1
rd_write_short_item(rd_global_logical_minimum, 0, &rpt_desc);
rd_write_short_item(rd_global_logical_maximum, 1, &rpt_desc);
}
else {
// Write logical range from "Logical Minimum" to "Logical Maximum"
rd_write_short_item(rd_global_logical_minimum, pp_data->caps[caps_idx].Button.LogicalMin, &rpt_desc);
rd_write_short_item(rd_global_logical_maximum, pp_data->caps[caps_idx].Button.LogicalMax, &rpt_desc);
}
// Write "Report Size"
rd_write_short_item(rd_global_report_size, pp_data->caps[caps_idx].ReportSize, &rpt_desc);
// Write "Report Count"
if (!pp_data->caps[caps_idx].IsRange) {
// Variable bit field with one bit per button
// In case of multiple usages with the same items, only "Usage" is written per cap, and "Report Count" is incremented
rd_write_short_item(rd_global_report_count, pp_data->caps[caps_idx].ReportCount + report_count, &rpt_desc);
}
else {
// Button array of "Report Size" x "Report Count
rd_write_short_item(rd_global_report_count, pp_data->caps[caps_idx].ReportCount, &rpt_desc);
}
// Buttons have only 1 bit and therefore no physical limits/units -> Set to undefined state
if (last_physical_min != 0) {
// Write "Physical Minimum", but only if changed
last_physical_min = 0;
rd_write_short_item(rd_global_physical_minimum, last_physical_min, &rpt_desc);
}
if (last_physical_max != 0) {
// Write "Physical Maximum", but only if changed
last_physical_max = 0;
rd_write_short_item(rd_global_physical_maximum, last_physical_max, &rpt_desc);
}
if (last_unit_exponent != 0) {
// Write "Unit Exponent", but only if changed
last_unit_exponent = 0;
rd_write_short_item(rd_global_unit_exponent, last_unit_exponent, &rpt_desc);
}
if (last_unit != 0) {
// Write "Unit",but only if changed
last_unit = 0;
rd_write_short_item(rd_global_unit, last_unit, &rpt_desc);
}
// Write "Input" main item
if (rt_idx == HidP_Input) {
rd_write_short_item(rd_main_input, pp_data->caps[caps_idx].BitField, &rpt_desc);
}
// Write "Output" main item
else if (rt_idx == HidP_Output) {
rd_write_short_item(rd_main_output, pp_data->caps[caps_idx].BitField, &rpt_desc);
}
// Write "Feature" main item
else if (rt_idx == HidP_Feature) {
rd_write_short_item(rd_main_feature, pp_data->caps[caps_idx].BitField, &rpt_desc);
}
report_count = 0;
}
}
else {
if (last_report_id != pp_data->caps[caps_idx].ReportID) {
// Write "Report ID" if changed
rd_write_short_item(rd_global_report_id, pp_data->caps[caps_idx].ReportID, &rpt_desc);
last_report_id = pp_data->caps[caps_idx].ReportID;
}
// Write "Usage Page" if changed
if (pp_data->caps[caps_idx].UsagePage != last_usage_page) {
rd_write_short_item(rd_global_usage_page, pp_data->caps[caps_idx].UsagePage, &rpt_desc);
last_usage_page = pp_data->caps[caps_idx].UsagePage;
}
if (inhibit_write_of_usage) {
// Inhibit only once after Delimiter - Reset flag
inhibit_write_of_usage = FALSE;
}
else {
if (pp_data->caps[caps_idx].IsRange) {
// Write usage range from "Usage Minimum" to "Usage Maximum"
rd_write_short_item(rd_local_usage_minimum, pp_data->caps[caps_idx].Range.UsageMin, &rpt_desc);
rd_write_short_item(rd_local_usage_maximum, pp_data->caps[caps_idx].Range.UsageMax, &rpt_desc);
}
else {
// Write single "Usage"
rd_write_short_item(rd_local_usage, pp_data->caps[caps_idx].NotRange.Usage, &rpt_desc);
}
}
if (pp_data->caps[caps_idx].IsDesignatorRange) {
// Write physical descriptor indices range from "Designator Minimum" to "Designator Maximum"
rd_write_short_item(rd_local_designator_minimum, pp_data->caps[caps_idx].Range.DesignatorMin, &rpt_desc);
rd_write_short_item(rd_local_designator_maximum, pp_data->caps[caps_idx].Range.DesignatorMax, &rpt_desc);
}
else if (pp_data->caps[caps_idx].NotRange.DesignatorIndex != 0) {
// Designator set 0 is a special descriptor set (of the HID Physical Descriptor),
// that specifies the number of additional descriptor sets.
// Therefore Designator Index 0 can never be a useful reference for a control and we can inhibit it.
// Write single "Designator Index"
rd_write_short_item(rd_local_designator_index, pp_data->caps[caps_idx].NotRange.DesignatorIndex, &rpt_desc);
}
if (pp_data->caps[caps_idx].IsStringRange) {
// Write range of indices of the USB string descriptor, from "String Minimum" to "String Maximum"
rd_write_short_item(rd_local_string_minimum, pp_data->caps[caps_idx].Range.StringMin, &rpt_desc);
rd_write_short_item(rd_local_string_maximum, pp_data->caps[caps_idx].Range.StringMax, &rpt_desc);
}
else if (pp_data->caps[caps_idx].NotRange.StringIndex != 0) {
// String Index 0 is a special entry of the USB string descriptor, that contains a list of supported languages,
// therefore Designator Index 0 can never be a useful reference for a control and we can inhibit it.
// Write single "String Index"
rd_write_short_item(rd_local_string, pp_data->caps[caps_idx].NotRange.StringIndex, &rpt_desc);
}
if ((pp_data->caps[caps_idx].BitField & 0x02) != 0x02) {
// In case of an value array overwrite "Report Count"
pp_data->caps[caps_idx].ReportCount = pp_data->caps[caps_idx].Range.DataIndexMax - pp_data->caps[caps_idx].Range.DataIndexMin + 1;
}
// Print only local report items for each cap, if ReportCount > 1
if ((main_item_list->next != NULL) &&
((int) main_item_list->next->MainItemType == rt_idx) &&
(main_item_list->next->TypeOfNode == rd_item_node_cap) &&
(!pp_data->caps[main_item_list->next->CapsIndex].IsButtonCap) &&
(!pp_data->caps[caps_idx].IsRange) && // This node in list is no array
(!pp_data->caps[main_item_list->next->CapsIndex].IsRange) && // Next node in list is no array
(pp_data->caps[main_item_list->next->CapsIndex].UsagePage == pp_data->caps[caps_idx].UsagePage) &&
(pp_data->caps[main_item_list->next->CapsIndex].NotButton.LogicalMin == pp_data->caps[caps_idx].NotButton.LogicalMin) &&
(pp_data->caps[main_item_list->next->CapsIndex].NotButton.LogicalMax == pp_data->caps[caps_idx].NotButton.LogicalMax) &&
(pp_data->caps[main_item_list->next->CapsIndex].NotButton.PhysicalMin == pp_data->caps[caps_idx].NotButton.PhysicalMin) &&
(pp_data->caps[main_item_list->next->CapsIndex].NotButton.PhysicalMax == pp_data->caps[caps_idx].NotButton.PhysicalMax) &&
(pp_data->caps[main_item_list->next->CapsIndex].UnitsExp == pp_data->caps[caps_idx].UnitsExp) &&
(pp_data->caps[main_item_list->next->CapsIndex].Units == pp_data->caps[caps_idx].Units) &&
(pp_data->caps[main_item_list->next->CapsIndex].ReportSize == pp_data->caps[caps_idx].ReportSize) &&
(pp_data->caps[main_item_list->next->CapsIndex].ReportID == pp_data->caps[caps_idx].ReportID) &&
(pp_data->caps[main_item_list->next->CapsIndex].BitField == pp_data->caps[caps_idx].BitField) &&
(pp_data->caps[main_item_list->next->CapsIndex].ReportCount == 1) &&
(pp_data->caps[caps_idx].ReportCount == 1)
) {
// Skip global items until any of them changes, than use ReportCount item to write the count of identical report fields
report_count++;
}
else {
// Value
// Write logical range from "Logical Minimum" to "Logical Maximum"
rd_write_short_item(rd_global_logical_minimum, pp_data->caps[caps_idx].NotButton.LogicalMin, &rpt_desc);
rd_write_short_item(rd_global_logical_maximum, pp_data->caps[caps_idx].NotButton.LogicalMax, &rpt_desc);
if ((last_physical_min != pp_data->caps[caps_idx].NotButton.PhysicalMin) ||
(last_physical_max != pp_data->caps[caps_idx].NotButton.PhysicalMax)) {
// Write range from "Physical Minimum" to " Physical Maximum", but only if one of them changed
rd_write_short_item(rd_global_physical_minimum, pp_data->caps[caps_idx].NotButton.PhysicalMin, &rpt_desc);
last_physical_min = pp_data->caps[caps_idx].NotButton.PhysicalMin;
rd_write_short_item(rd_global_physical_maximum, pp_data->caps[caps_idx].NotButton.PhysicalMax, &rpt_desc);
last_physical_max = pp_data->caps[caps_idx].NotButton.PhysicalMax;
}
if (last_unit_exponent != pp_data->caps[caps_idx].UnitsExp) {
// Write "Unit Exponent", but only if changed
rd_write_short_item(rd_global_unit_exponent, pp_data->caps[caps_idx].UnitsExp, &rpt_desc);
last_unit_exponent = pp_data->caps[caps_idx].UnitsExp;
}
if (last_unit != pp_data->caps[caps_idx].Units) {
// Write physical "Unit", but only if changed
rd_write_short_item(rd_global_unit, pp_data->caps[caps_idx].Units, &rpt_desc);
last_unit = pp_data->caps[caps_idx].Units;
}
// Write "Report Size"
rd_write_short_item(rd_global_report_size, pp_data->caps[caps_idx].ReportSize, &rpt_desc);
// Write "Report Count"
rd_write_short_item(rd_global_report_count, pp_data->caps[caps_idx].ReportCount + report_count, &rpt_desc);
if (rt_idx == HidP_Input) {
// Write "Input" main item
rd_write_short_item(rd_main_input, pp_data->caps[caps_idx].BitField, &rpt_desc);
}
else if (rt_idx == HidP_Output) {
// Write "Output" main item
rd_write_short_item(rd_main_output, pp_data->caps[caps_idx].BitField, &rpt_desc);
}
else if (rt_idx == HidP_Feature) {
// Write "Feature" main item
rd_write_short_item(rd_main_feature, pp_data->caps[caps_idx].BitField, &rpt_desc);
}
report_count = 0;
}
}
// Go to next item in main_item_list and free the memory of the actual item
struct rd_main_item_node *main_item_list_prev = main_item_list;
main_item_list = main_item_list->next;
free(main_item_list_prev);
}
// Free multidimensionable array: coll_bit_range[COLLECTION_INDEX][REPORT_ID][INPUT/OUTPUT/FEATURE]
// Free multidimensionable array: coll_child_order[COLLECTION_INDEX][DIRECT_CHILD_INDEX]
for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
free(coll_bit_range[collection_node_idx][reportid_idx][rt_idx]);
}
free(coll_bit_range[collection_node_idx][reportid_idx]);
}
free(coll_bit_range[collection_node_idx]);
if (coll_number_of_direct_childs[collection_node_idx] != 0) free(coll_child_order[collection_node_idx]);
}
free(coll_bit_range);
free(coll_child_order);
// Free one dimensional arrays
free(coll_begin_lookup);
free(coll_end_lookup);
free(coll_levels);
free(coll_number_of_direct_childs);
return (int) rpt_desc.byte_idx;
}

View File

@ -0,0 +1,247 @@
/*******************************************************
HIDAPI - Multi-Platform library for
communication with HID devices.
libusb/hidapi Team
Copyright 2022, All Rights Reserved.
At the discretion of the user of this library,
this software may be licensed under the terms of the
GNU General Public License v3, a BSD-Style license, or the
original HIDAPI license as outlined in the LICENSE.txt,
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
files located at the root of the source distribution.
These files may also be found in the public source
code repository located at:
https://github.com/libusb/hidapi .
********************************************************/
#ifndef HIDAPI_DESCRIPTOR_RECONSTRUCT_H__
#define HIDAPI_DESCRIPTOR_RECONSTRUCT_H__
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
/* Do not warn about wcsncpy usage.
https://docs.microsoft.com/cpp/c-runtime-library/security-features-in-the-crt */
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "hidapi_winapi.h"
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4200)
#pragma warning(disable: 4201)
#pragma warning(disable: 4214)
#endif
#include <windows.h>
#include "hidapi_hidsdi.h"
#include <assert.h>
#define NUM_OF_HIDP_REPORT_TYPES 3
typedef enum rd_items_ {
rd_main_input = 0x80, /* 1000 00 nn */
rd_main_output = 0x90, /* 1001 00 nn */
rd_main_feature = 0xB0, /* 1011 00 nn */
rd_main_collection = 0xA0, /* 1010 00 nn */
rd_main_collection_end = 0xC0, /* 1100 00 nn */
rd_global_usage_page = 0x04, /* 0000 01 nn */
rd_global_logical_minimum = 0x14, /* 0001 01 nn */
rd_global_logical_maximum = 0x24, /* 0010 01 nn */
rd_global_physical_minimum = 0x34, /* 0011 01 nn */
rd_global_physical_maximum = 0x44, /* 0100 01 nn */
rd_global_unit_exponent = 0x54, /* 0101 01 nn */
rd_global_unit = 0x64, /* 0110 01 nn */
rd_global_report_size = 0x74, /* 0111 01 nn */
rd_global_report_id = 0x84, /* 1000 01 nn */
rd_global_report_count = 0x94, /* 1001 01 nn */
rd_global_push = 0xA4, /* 1010 01 nn */
rd_global_pop = 0xB4, /* 1011 01 nn */
rd_local_usage = 0x08, /* 0000 10 nn */
rd_local_usage_minimum = 0x18, /* 0001 10 nn */
rd_local_usage_maximum = 0x28, /* 0010 10 nn */
rd_local_designator_index = 0x38, /* 0011 10 nn */
rd_local_designator_minimum = 0x48, /* 0100 10 nn */
rd_local_designator_maximum = 0x58, /* 0101 10 nn */
rd_local_string = 0x78, /* 0111 10 nn */
rd_local_string_minimum = 0x88, /* 1000 10 nn */
rd_local_string_maximum = 0x98, /* 1001 10 nn */
rd_local_delimiter = 0xA8 /* 1010 10 nn */
} rd_items;
typedef enum rd_main_items_ {
rd_input = HidP_Input,
rd_output = HidP_Output,
rd_feature = HidP_Feature,
rd_collection,
rd_collection_end,
rd_delimiter_open,
rd_delimiter_usage,
rd_delimiter_close,
} rd_main_items;
typedef struct rd_bit_range_ {
int FirstBit;
int LastBit;
} rd_bit_range;
typedef enum rd_item_node_type_ {
rd_item_node_cap,
rd_item_node_padding,
rd_item_node_collection,
} rd_node_type;
struct rd_main_item_node {
int FirstBit; /* Position of first bit in report (counting from 0) */
int LastBit; /* Position of last bit in report (counting from 0) */
rd_node_type TypeOfNode; /* Information if caps index refers to the array of button caps, value caps,
or if the node is just a padding element to fill unused bit positions.
The node can also be a collection node without any bits in the report. */
int CapsIndex; /* Index in the array of caps */
int CollectionIndex; /* Index in the array of link collections */
rd_main_items MainItemType; /* Input, Output, Feature, Collection or Collection End */
unsigned char ReportID;
struct rd_main_item_node* next;
};
typedef struct hid_pp_caps_info_ {
USHORT FirstCap;
USHORT NumberOfCaps; // Includes empty caps after LastCap
USHORT LastCap;
USHORT ReportByteLength;
} hid_pp_caps_info, *phid_pp_caps_info;
typedef struct hid_pp_link_collection_node_ {
USAGE LinkUsage;
USAGE LinkUsagePage;
USHORT Parent;
USHORT NumberOfChildren;
USHORT NextSibling;
USHORT FirstChild;
ULONG CollectionType : 8;
ULONG IsAlias : 1;
ULONG Reserved : 23;
// Same as the public API structure HIDP_LINK_COLLECTION_NODE, but without PVOID UserContext at the end
} hid_pp_link_collection_node, *phid_pp_link_collection_node;
// Note: This is risk-reduction-measure for this specific struct, as it has ULONG bit-field.
// Although very unlikely, it might still be possible that the compiler creates a memory layout that is
// not binary compatile.
// Other structs are not checked at the time of writing.
static_assert(sizeof(struct hid_pp_link_collection_node_) == 16,
"Size of struct hid_pp_link_collection_node_ not as expected. This might break binary compatibility");
typedef struct hidp_unknown_token_ {
UCHAR Token; /* Specifies the one-byte prefix of a global item. */
UCHAR Reserved[3];
ULONG BitField; /* Specifies the data part of the global item. */
} hidp_unknown_token, * phidp_unknown_token;
typedef struct hid_pp_cap_ {
USAGE UsagePage;
UCHAR ReportID;
UCHAR BitPosition;
USHORT ReportSize; // WIN32 term for this is BitSize
USHORT ReportCount;
USHORT BytePosition;
USHORT BitCount;
ULONG BitField;
USHORT NextBytePosition;
USHORT LinkCollection;
USAGE LinkUsagePage;
USAGE LinkUsage;
// Start of 8 Flags in one byte
BOOLEAN IsMultipleItemsForArray:1;
BOOLEAN IsPadding:1;
BOOLEAN IsButtonCap:1;
BOOLEAN IsAbsolute:1;
BOOLEAN IsRange:1;
BOOLEAN IsAlias:1; // IsAlias is set to TRUE in the first n-1 capability structures added to the capability array. IsAlias set to FALSE in the nth capability structure.
BOOLEAN IsStringRange:1;
BOOLEAN IsDesignatorRange:1;
// End of 8 Flags in one byte
BOOLEAN Reserved1[3];
hidp_unknown_token UnknownTokens[4]; // 4 x 8 Byte
union {
struct {
USAGE UsageMin;
USAGE UsageMax;
USHORT StringMin;
USHORT StringMax;
USHORT DesignatorMin;
USHORT DesignatorMax;
USHORT DataIndexMin;
USHORT DataIndexMax;
} Range;
struct {
USAGE Usage;
USAGE Reserved1;
USHORT StringIndex;
USHORT Reserved2;
USHORT DesignatorIndex;
USHORT Reserved3;
USHORT DataIndex;
USHORT Reserved4;
} NotRange;
};
union {
struct {
LONG LogicalMin;
LONG LogicalMax;
} Button;
struct {
BOOLEAN HasNull;
UCHAR Reserved4[3];
LONG LogicalMin;
LONG LogicalMax;
LONG PhysicalMin;
LONG PhysicalMax;
} NotButton;
};
ULONG Units;
ULONG UnitsExp;
} hid_pp_cap, *phid_pp_cap;
typedef struct hidp_preparsed_data_ {
UCHAR MagicKey[8];
USAGE Usage;
USAGE UsagePage;
USHORT Reserved[2];
// CAPS structure for Input, Output and Feature
hid_pp_caps_info caps_info[3];
USHORT FirstByteOfLinkCollectionArray;
USHORT NumberLinkCollectionNodes;
#ifndef _MSC_VER
// MINGW fails with: Flexible array member in union not supported
// Solution: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
union {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
hid_pp_cap caps[0];
hid_pp_link_collection_node LinkCollectionArray[0];
#pragma GCC diagnostic pop
};
#else
union {
hid_pp_cap caps[];
hid_pp_link_collection_node LinkCollectionArray[];
};
#endif
} hidp_preparsed_data;
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif

View File

@ -0,0 +1,38 @@
/*******************************************************
HIDAPI - Multi-Platform library for
communication with HID devices.
libusb/hidapi Team
Copyright 2022, All Rights Reserved.
At the discretion of the user of this library,
this software may be licensed under the terms of the
GNU General Public License v3, a BSD-Style license, or the
original HIDAPI license as outlined in the LICENSE.txt,
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
files located at the root of the source distribution.
These files may also be found in the public source
code repository located at:
https://github.com/libusb/hidapi .
********************************************************/
#ifndef HIDAPI_HIDCLASS_H
#define HIDAPI_HIDCLASS_H
#ifdef HIDAPI_USE_DDK
#include <hidclass.h>
#else
/* This part of the header mimics hidclass.h,
but only what is used by HIDAPI */
#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)
#endif
#endif /* HIDAPI_HIDCLASS_H */

View File

@ -0,0 +1,72 @@
/*******************************************************
HIDAPI - Multi-Platform library for
communication with HID devices.
libusb/hidapi Team
Copyright 2022, All Rights Reserved.
At the discretion of the user of this library,
this software may be licensed under the terms of the
GNU General Public License v3, a BSD-Style license, or the
original HIDAPI license as outlined in the LICENSE.txt,
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
files located at the root of the source distribution.
These files may also be found in the public source
code repository located at:
https://github.com/libusb/hidapi .
********************************************************/
#ifndef HIDAPI_HIDPI_H
#define HIDAPI_HIDPI_H
#ifdef HIDAPI_USE_DDK
#include <hidpi.h>
#else
/* This part of the header mimics hidpi.h,
but only what is used by HIDAPI */
typedef enum _HIDP_REPORT_TYPE
{
HidP_Input,
HidP_Output,
HidP_Feature
} HIDP_REPORT_TYPE;
typedef struct _HIDP_PREPARSED_DATA * PHIDP_PREPARSED_DATA;
typedef struct _HIDP_CAPS
{
USAGE Usage;
USAGE UsagePage;
USHORT InputReportByteLength;
USHORT OutputReportByteLength;
USHORT FeatureReportByteLength;
USHORT Reserved[17];
USHORT NumberLinkCollectionNodes;
USHORT NumberInputButtonCaps;
USHORT NumberInputValueCaps;
USHORT NumberInputDataIndices;
USHORT NumberOutputButtonCaps;
USHORT NumberOutputValueCaps;
USHORT NumberOutputDataIndices;
USHORT NumberFeatureButtonCaps;
USHORT NumberFeatureValueCaps;
USHORT NumberFeatureDataIndices;
} HIDP_CAPS, *PHIDP_CAPS;
#define HIDP_STATUS_SUCCESS 0x00110000
#define HIDP_STATUS_INVALID_PREPARSED_DATA 0xc0110001
typedef NTSTATUS (__stdcall *HidP_GetCaps_)(PHIDP_PREPARSED_DATA preparsed_data, PHIDP_CAPS caps);
#endif
#endif /* HIDAPI_HIDPI_H */

View File

@ -0,0 +1,59 @@
/*******************************************************
HIDAPI - Multi-Platform library for
communication with HID devices.
libusb/hidapi Team
Copyright 2022, All Rights Reserved.
At the discretion of the user of this library,
this software may be licensed under the terms of the
GNU General Public License v3, a BSD-Style license, or the
original HIDAPI license as outlined in the LICENSE.txt,
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
files located at the root of the source distribution.
These files may also be found in the public source
code repository located at:
https://github.com/libusb/hidapi .
********************************************************/
#ifndef HIDAPI_HIDSDI_H
#define HIDAPI_HIDSDI_H
#ifdef HIDAPI_USE_DDK
#include <hidsdi.h>
#else
/* This part of the header mimics hidsdi.h,
but only what is used by HIDAPI */
typedef USHORT USAGE;
#include "hidapi_hidpi.h"
typedef struct _HIDD_ATTRIBUTES{
ULONG Size;
USHORT VendorID;
USHORT ProductID;
USHORT VersionNumber;
} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
typedef void (__stdcall *HidD_GetHidGuid_)(LPGUID hid_guid);
typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib);
typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len);
typedef BOOLEAN (__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);
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_SetOutputReport_)(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);
typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers);
#endif
#endif /* HIDAPI_HIDSDI_H */

View File

@ -0,0 +1,74 @@
/*******************************************************
HIDAPI - Multi-Platform library for
communication with HID devices.
libusb/hidapi Team
Copyright 2022, All Rights Reserved.
At the discretion of the user of this library,
this software may be licensed under the terms of the
GNU General Public License v3, a BSD-Style license, or the
original HIDAPI license as outlined in the LICENSE.txt,
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
files located at the root of the source distribution.
These files may also be found in the public source
code repository located at:
https://github.com/libusb/hidapi .
********************************************************/
/** @file
* @defgroup API hidapi API
*
* Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
*/
#ifndef HIDAPI_WINAPI_H__
#define HIDAPI_WINAPI_H__
#include <stdint.h>
#include <guiddef.h>
#include "hidapi.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Get the container ID for a HID device.
Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
This function returns the `DEVPKEY_Device_ContainerId` property of
the given device. This can be used to correlate different
interfaces/ports on the same hardware device.
@ingroup API
@param dev A device handle returned from hid_open().
@param container_id The device's container ID on return.
@returns
This function returns 0 on success and -1 on error.
*/
int HID_API_EXPORT_CALL hid_winapi_get_container_id(hid_device *dev, GUID *container_id);
/**
* @brief Reconstructs a HID Report Descriptor from a Win32 HIDP_PREPARSED_DATA structure.
* This reconstructed report descriptor is logical identical to the real report descriptor,
* but not byte wise identical.
*
* @param[in] hidp_preparsed_data Pointer to the HIDP_PREPARSED_DATA to read, i.e.: the value of PHIDP_PREPARSED_DATA,
* as returned by HidD_GetPreparsedData WinAPI function.
* @param buf Pointer to the buffer where the report descriptor should be stored.
* @param[in] buf_size Size of the buffer. The recommended size for the buffer is @ref HID_API_MAX_REPORT_DESCRIPTOR_SIZE bytes.
*
* @return Returns size of reconstructed report descriptor if successful, -1 for error.
*/
int HID_API_EXPORT_CALL hid_winapi_descriptor_reconstruct_pp_data(void *hidp_preparsed_data, unsigned char *buf, size_t buf_size);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -50,6 +50,7 @@ def build(bld):
obj.source = 'mac/hid.c'
obj.framework = [ 'IOKit', 'CoreFoundation' ]
else:
# with '-strict' this needs "-std=gnu99" to compile w/o warnings
obj.source = 'linux/hid.c'
if re.search ("linux", sys.platform) != None:
obj.uselib = 'UDEV'