123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990 |
- /*******************************************************
- 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;
- rpt_desc.buf = buf;
- rpt_desc.buf_size = buf_size;
- rpt_desc.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];
- struct rd_main_item_node **last_report_item_lookup[NUM_OF_HIDP_REPORT_TYPES];
- for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
- last_bit_position[rt_idx] = malloc(256 * sizeof(*last_bit_position[rt_idx]));
- last_report_item_lookup[rt_idx] = malloc(256 * sizeof(*last_report_item_lookup[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]);
- }
- }
- }
- free(last_bit_position[rt_idx]);
- free(last_report_item_lookup[rt_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;
- }
|