diff options
Diffstat (limited to 'contrib/SDL-3.2.8/src/hidapi/windows/pp_data_dump')
3 files changed, 375 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/hidapi/windows/pp_data_dump/CMakeLists.txt b/contrib/SDL-3.2.8/src/hidapi/windows/pp_data_dump/CMakeLists.txt new file mode 100644 index 0000000..f017de9 --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/windows/pp_data_dump/CMakeLists.txt | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | project(pp_data_dump C) | ||
| 2 | |||
| 3 | add_executable(pp_data_dump pp_data_dump.c) | ||
| 4 | set_target_properties(pp_data_dump | ||
| 5 | PROPERTIES | ||
| 6 | C_STANDARD 11 | ||
| 7 | C_STANDARD_REQUIRED TRUE | ||
| 8 | ) | ||
| 9 | target_link_libraries(pp_data_dump | ||
| 10 | PRIVATE hidapi_winapi | ||
| 11 | ) | ||
| 12 | |||
| 13 | install(TARGETS pp_data_dump | ||
| 14 | RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" | ||
| 15 | ) | ||
diff --git a/contrib/SDL-3.2.8/src/hidapi/windows/pp_data_dump/README.md b/contrib/SDL-3.2.8/src/hidapi/windows/pp_data_dump/README.md new file mode 100644 index 0000000..a0989cd --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/windows/pp_data_dump/README.md | |||
| @@ -0,0 +1,122 @@ | |||
| 1 | ## pp_data_dump.exe for Windows | ||
| 2 | |||
| 3 | |||
| 4 | pp_data_dump.exe is a small command line tool for Windows, which dumps the content of the [Preparsed Data](https://learn.microsoft.com/en-us/windows-hardware/drivers/hid/preparsed-data) structure, provided by the Windows HID subsystem, into a file. | ||
| 5 | |||
| 6 | The generated file is in a text format, which is readable for human, as by the hid_report_reconstructor_test.exe unit test executable of the HIDAPI project. This unit test allows it to test the HIDAPIs report descriptor reconstructor - offline, without the hardware device connected. | ||
| 7 | |||
| 8 | pp_data_dump.exe has no arguments, just connect you HID device and execute pp_data_dump.exe. It will generate one file with the name | ||
| 9 | ``` | ||
| 10 | <vendor_id>_<product_id>_<usage>_<usage_table>.pp_data | ||
| 11 | ``` | ||
| 12 | for each top-level collection, of each connected HID device. | ||
| 13 | |||
| 14 | |||
| 15 | ## File content | ||
| 16 | |||
| 17 | The content of such a .pp_data file looks like the struct, which HIDAPI uses internally to represent the Preparsed Data. | ||
| 18 | |||
| 19 | *NOTE: | ||
| 20 | Windows parses HID report descriptors into opaque `_HIDP_PREPARSED_DATA` objects. | ||
| 21 | The internal structure of `_HIDP_PREPARSED_DATA` is reserved for internal system use.\ | ||
| 22 | Microsoft doesn't document this structure. [hid_preparsed_data.cc](https://chromium.googlesource.com/chromium/src/+/73fdaaf605bb60caf34d5f30bb84a417688aa528/services/device/hid/hid_preparsed_data.cc) is taken as a reference for its parsing.* | ||
| 23 | |||
| 24 | ``` | ||
| 25 | # HIDAPI device info struct: | ||
| 26 | dev->vendor_id = 0x046D | ||
| 27 | dev->product_id = 0xB010 | ||
| 28 | dev->manufacturer_string = "Logitech" | ||
| 29 | dev->product_string = "Logitech Bluetooth Wireless Mouse" | ||
| 30 | dev->release_number = 0x0000 | ||
| 31 | dev->interface_number = -1 | ||
| 32 | dev->usage = 0x0001 | ||
| 33 | dev->usage_page = 0x000C | ||
| 34 | dev->path = "\\?\hid#{00001124-0000-1000-8000-00805f9b34fb}_vid&0002046d_pid&b010&col02#8&1cf1c1b9&3&0001#{4d1e55b2-f16f-11cf-88cb-001111000030}" | ||
| 35 | |||
| 36 | # Preparsed Data struct: | ||
| 37 | pp_data->MagicKey = 0x48696450204B4452 | ||
| 38 | pp_data->Usage = 0x0001 | ||
| 39 | pp_data->UsagePage = 0x000C | ||
| 40 | pp_data->Reserved = 0x00000000 | ||
| 41 | # Input caps_info struct: | ||
| 42 | pp_data->caps_info[0]->FirstCap = 0 | ||
| 43 | pp_data->caps_info[0]->LastCap = 1 | ||
| 44 | pp_data->caps_info[0]->NumberOfCaps = 1 | ||
| 45 | pp_data->caps_info[0]->ReportByteLength = 2 | ||
| 46 | # Output caps_info struct: | ||
| 47 | pp_data->caps_info[1]->FirstCap = 1 | ||
| 48 | pp_data->caps_info[1]->LastCap = 1 | ||
| 49 | pp_data->caps_info[1]->NumberOfCaps = 0 | ||
| 50 | pp_data->caps_info[1]->ReportByteLength = 0 | ||
| 51 | # Feature caps_info struct: | ||
| 52 | pp_data->caps_info[2]->FirstCap = 1 | ||
| 53 | pp_data->caps_info[2]->LastCap = 1 | ||
| 54 | pp_data->caps_info[2]->NumberOfCaps = 0 | ||
| 55 | pp_data->caps_info[2]->ReportByteLength = 0 | ||
| 56 | # LinkCollectionArray Offset & Size: | ||
| 57 | pp_data->FirstByteOfLinkCollectionArray = 0x0068 | ||
| 58 | pp_data->NumberLinkCollectionNodes = 1 | ||
| 59 | # Input hid_pp_cap struct: | ||
| 60 | pp_data->cap[0]->UsagePage = 0x0006 | ||
| 61 | pp_data->cap[0]->ReportID = 0x03 | ||
| 62 | pp_data->cap[0]->BitPosition = 0 | ||
| 63 | pp_data->cap[0]->BitSize = 8 | ||
| 64 | pp_data->cap[0]->ReportCount = 1 | ||
| 65 | pp_data->cap[0]->BytePosition = 0x0001 | ||
| 66 | pp_data->cap[0]->BitCount = 8 | ||
| 67 | pp_data->cap[0]->BitField = 0x02 | ||
| 68 | pp_data->cap[0]->NextBytePosition = 0x0002 | ||
| 69 | pp_data->cap[0]->LinkCollection = 0x0000 | ||
| 70 | pp_data->cap[0]->LinkUsagePage = 0x000C | ||
| 71 | pp_data->cap[0]->LinkUsage = 0x0001 | ||
| 72 | pp_data->cap[0]->IsMultipleItemsForArray = 0 | ||
| 73 | pp_data->cap[0]->IsButtonCap = 0 | ||
| 74 | pp_data->cap[0]->IsPadding = 0 | ||
| 75 | pp_data->cap[0]->IsAbsolute = 1 | ||
| 76 | pp_data->cap[0]->IsRange = 0 | ||
| 77 | pp_data->cap[0]->IsAlias = 0 | ||
| 78 | pp_data->cap[0]->IsStringRange = 0 | ||
| 79 | pp_data->cap[0]->IsDesignatorRange = 0 | ||
| 80 | pp_data->cap[0]->Reserved1 = 0x000000 | ||
| 81 | pp_data->cap[0]->pp_cap->UnknownTokens[0].Token = 0x00 | ||
| 82 | pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000 | ||
| 83 | pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000 | ||
| 84 | pp_data->cap[0]->pp_cap->UnknownTokens[1].Token = 0x00 | ||
| 85 | pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000 | ||
| 86 | pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000 | ||
| 87 | pp_data->cap[0]->pp_cap->UnknownTokens[2].Token = 0x00 | ||
| 88 | pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000 | ||
| 89 | pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000 | ||
| 90 | pp_data->cap[0]->pp_cap->UnknownTokens[3].Token = 0x00 | ||
| 91 | pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000 | ||
| 92 | pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000 | ||
| 93 | pp_data->cap[0]->NotRange.Usage = 0x0020 | ||
| 94 | pp_data->cap[0]->NotRange.Reserved1 = 0x0020 | ||
| 95 | pp_data->cap[0]->NotRange.StringIndex = 0 | ||
| 96 | pp_data->cap[0]->NotRange.Reserved2 = 0 | ||
| 97 | pp_data->cap[0]->NotRange.DesignatorIndex = 0 | ||
| 98 | pp_data->cap[0]->NotRange.Reserved3 = 0 | ||
| 99 | pp_data->cap[0]->NotRange.DataIndex = 0 | ||
| 100 | pp_data->cap[0]->NotRange.Reserved4 = 0 | ||
| 101 | pp_data->cap[0]->NotButton.HasNull = 0 | ||
| 102 | pp_data->cap[0]->NotButton.Reserved4 = 0x000000 | ||
| 103 | pp_data->cap[0]->NotButton.LogicalMin = 0 | ||
| 104 | pp_data->cap[0]->NotButton.LogicalMax = 100 | ||
| 105 | pp_data->cap[0]->NotButton.PhysicalMin = 0 | ||
| 106 | pp_data->cap[0]->NotButton.PhysicalMax = 0 | ||
| 107 | pp_data->cap[0]->Units = 0 | ||
| 108 | pp_data->cap[0]->UnitsExp = 0 | ||
| 109 | |||
| 110 | # Output hid_pp_cap struct: | ||
| 111 | # Feature hid_pp_cap struct: | ||
| 112 | # Link Collections: | ||
| 113 | pp_data->LinkCollectionArray[0]->LinkUsage = 0x0001 | ||
| 114 | pp_data->LinkCollectionArray[0]->LinkUsagePage = 0x000C | ||
| 115 | pp_data->LinkCollectionArray[0]->Parent = 0 | ||
| 116 | pp_data->LinkCollectionArray[0]->NumberOfChildren = 0 | ||
| 117 | pp_data->LinkCollectionArray[0]->NextSibling = 0 | ||
| 118 | pp_data->LinkCollectionArray[0]->FirstChild = 0 | ||
| 119 | pp_data->LinkCollectionArray[0]->CollectionType = 1 | ||
| 120 | pp_data->LinkCollectionArray[0]->IsAlias = 0 | ||
| 121 | pp_data->LinkCollectionArray[0]->Reserved = 0x00000000 | ||
| 122 | ``` \ No newline at end of file | ||
diff --git a/contrib/SDL-3.2.8/src/hidapi/windows/pp_data_dump/pp_data_dump.c b/contrib/SDL-3.2.8/src/hidapi/windows/pp_data_dump/pp_data_dump.c new file mode 100644 index 0000000..d5df68b --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/windows/pp_data_dump/pp_data_dump.c | |||
| @@ -0,0 +1,238 @@ | |||
| 1 | #if defined(__MINGW32__) | ||
| 2 | // Needed for %hh | ||
| 3 | #define __USE_MINGW_ANSI_STDIO 1 | ||
| 4 | #endif | ||
| 5 | |||
| 6 | #include <hid.c> | ||
| 7 | #include <../windows/hidapi_descriptor_reconstruct.h> | ||
| 8 | |||
| 9 | #include <hidapi.h> | ||
| 10 | |||
| 11 | void dump_hid_pp_cap(FILE* file, phid_pp_cap pp_cap, unsigned int cap_idx) { | ||
| 12 | fprintf(file, "pp_data->cap[%u]->UsagePage = 0x%04hX\n", cap_idx, pp_cap->UsagePage); | ||
| 13 | fprintf(file, "pp_data->cap[%u]->ReportID = 0x%02hhX\n", cap_idx, pp_cap->ReportID); | ||
| 14 | fprintf(file, "pp_data->cap[%u]->BitPosition = %hhu\n", cap_idx, pp_cap->BitPosition); | ||
| 15 | fprintf(file, "pp_data->cap[%u]->BitSize = %hu\n", cap_idx, pp_cap->ReportSize); | ||
| 16 | fprintf(file, "pp_data->cap[%u]->ReportCount = %hu\n", cap_idx, pp_cap->ReportCount); | ||
| 17 | fprintf(file, "pp_data->cap[%u]->BytePosition = 0x%04hX\n", cap_idx, pp_cap->BytePosition); | ||
| 18 | fprintf(file, "pp_data->cap[%u]->BitCount = %hu\n", cap_idx, pp_cap->BitCount); | ||
| 19 | fprintf(file, "pp_data->cap[%u]->BitField = 0x%02lX\n", cap_idx, pp_cap->BitField); | ||
| 20 | fprintf(file, "pp_data->cap[%u]->NextBytePosition = 0x%04hX\n", cap_idx, pp_cap->NextBytePosition); | ||
| 21 | fprintf(file, "pp_data->cap[%u]->LinkCollection = 0x%04hX\n", cap_idx, pp_cap->LinkCollection); | ||
| 22 | fprintf(file, "pp_data->cap[%u]->LinkUsagePage = 0x%04hX\n", cap_idx, pp_cap->LinkUsagePage); | ||
| 23 | fprintf(file, "pp_data->cap[%u]->LinkUsage = 0x%04hX\n", cap_idx, pp_cap->LinkUsage); | ||
| 24 | |||
| 25 | // 8 Flags in one byte | ||
| 26 | fprintf(file, "pp_data->cap[%u]->IsMultipleItemsForArray = %hhu\n", cap_idx, pp_cap->IsMultipleItemsForArray); | ||
| 27 | fprintf(file, "pp_data->cap[%u]->IsButtonCap = %hhu\n", cap_idx, pp_cap->IsButtonCap); | ||
| 28 | fprintf(file, "pp_data->cap[%u]->IsPadding = %hhu\n", cap_idx, pp_cap->IsPadding); | ||
| 29 | fprintf(file, "pp_data->cap[%u]->IsAbsolute = %hhu\n", cap_idx, pp_cap->IsAbsolute); | ||
| 30 | fprintf(file, "pp_data->cap[%u]->IsRange = %hhu\n", cap_idx, pp_cap->IsRange); | ||
| 31 | fprintf(file, "pp_data->cap[%u]->IsAlias = %hhu\n", cap_idx, pp_cap->IsAlias); | ||
| 32 | fprintf(file, "pp_data->cap[%u]->IsStringRange = %hhu\n", cap_idx, pp_cap->IsStringRange); | ||
| 33 | fprintf(file, "pp_data->cap[%u]->IsDesignatorRange = %hhu\n", cap_idx, pp_cap->IsDesignatorRange); | ||
| 34 | |||
| 35 | fprintf(file, "pp_data->cap[%u]->Reserved1 = 0x%02hhX%02hhX%02hhX\n", cap_idx, pp_cap->Reserved1[0], pp_cap->Reserved1[1], pp_cap->Reserved1[2]); | ||
| 36 | |||
| 37 | for (int token_idx = 0; token_idx < 4; token_idx++) { | ||
| 38 | fprintf(file, "pp_data->cap[%u]->pp_cap->UnknownTokens[%d].Token = 0x%02hhX\n", cap_idx, token_idx, pp_cap->UnknownTokens[token_idx].Token); | ||
| 39 | fprintf(file, "pp_data->cap[%u]->pp_cap->UnknownTokens[%d].Reserved = 0x%02hhX%02hhX%02hhX\n", cap_idx, token_idx, pp_cap->UnknownTokens[token_idx].Reserved[0], pp_cap->UnknownTokens[token_idx].Reserved[1], pp_cap->UnknownTokens[token_idx].Reserved[2]); | ||
| 40 | fprintf(file, "pp_data->cap[%u]->pp_cap->UnknownTokens[%d].BitField = 0x%08lX\n", cap_idx, token_idx, pp_cap->UnknownTokens[token_idx].BitField); | ||
| 41 | } | ||
| 42 | |||
| 43 | if (pp_cap->IsRange) { | ||
| 44 | fprintf(file, "pp_data->cap[%u]->Range.UsageMin = 0x%04hX\n", cap_idx, pp_cap->Range.UsageMin); | ||
| 45 | fprintf(file, "pp_data->cap[%u]->Range.UsageMax = 0x%04hX\n", cap_idx, pp_cap->Range.UsageMax); | ||
| 46 | fprintf(file, "pp_data->cap[%u]->Range.StringMin = %hu\n", cap_idx, pp_cap->Range.StringMin); | ||
| 47 | fprintf(file, "pp_data->cap[%u]->Range.StringMax = %hu\n", cap_idx, pp_cap->Range.StringMax); | ||
| 48 | fprintf(file, "pp_data->cap[%u]->Range.DesignatorMin = %hu\n", cap_idx, pp_cap->Range.DesignatorMin); | ||
| 49 | fprintf(file, "pp_data->cap[%u]->Range.DesignatorMax = %hu\n", cap_idx, pp_cap->Range.DesignatorMax); | ||
| 50 | fprintf(file, "pp_data->cap[%u]->Range.DataIndexMin = %hu\n", cap_idx, pp_cap->Range.DataIndexMin); | ||
| 51 | fprintf(file, "pp_data->cap[%u]->Range.DataIndexMax = %hu\n", cap_idx, pp_cap->Range.DataIndexMax); | ||
| 52 | } | ||
| 53 | else { | ||
| 54 | fprintf(file, "pp_data->cap[%u]->NotRange.Usage = 0x%04hX\n", cap_idx, pp_cap->NotRange.Usage); | ||
| 55 | fprintf(file, "pp_data->cap[%u]->NotRange.Reserved1 = 0x%04hX\n", cap_idx, pp_cap->NotRange.Reserved1); | ||
| 56 | fprintf(file, "pp_data->cap[%u]->NotRange.StringIndex = %hu\n", cap_idx, pp_cap->NotRange.StringIndex); | ||
| 57 | fprintf(file, "pp_data->cap[%u]->NotRange.Reserved2 = %hu\n", cap_idx, pp_cap->NotRange.Reserved2); | ||
| 58 | fprintf(file, "pp_data->cap[%u]->NotRange.DesignatorIndex = %hu\n", cap_idx, pp_cap->NotRange.DesignatorIndex); | ||
| 59 | fprintf(file, "pp_data->cap[%u]->NotRange.Reserved3 = %hu\n", cap_idx, pp_cap->NotRange.Reserved3); | ||
| 60 | fprintf(file, "pp_data->cap[%u]->NotRange.DataIndex = %hu\n", cap_idx, pp_cap->NotRange.DataIndex); | ||
| 61 | fprintf(file, "pp_data->cap[%u]->NotRange.Reserved4 = %hu\n", cap_idx, pp_cap->NotRange.Reserved4); | ||
| 62 | } | ||
| 63 | |||
| 64 | if (pp_cap->IsButtonCap) { | ||
| 65 | fprintf(file, "pp_data->cap[%u]->Button.LogicalMin = %ld\n", cap_idx, pp_cap->Button.LogicalMin); | ||
| 66 | fprintf(file, "pp_data->cap[%u]->Button.LogicalMax = %ld\n", cap_idx, pp_cap->Button.LogicalMax); | ||
| 67 | } | ||
| 68 | else | ||
| 69 | { | ||
| 70 | fprintf(file, "pp_data->cap[%u]->NotButton.HasNull = %hhu\n", cap_idx, pp_cap->NotButton.HasNull); | ||
| 71 | fprintf(file, "pp_data->cap[%u]->NotButton.Reserved4 = 0x%02hhX%02hhX%02hhX\n", cap_idx, pp_cap->NotButton.Reserved4[0], pp_cap->NotButton.Reserved4[1], pp_cap->NotButton.Reserved4[2]); | ||
| 72 | fprintf(file, "pp_data->cap[%u]->NotButton.LogicalMin = %ld\n", cap_idx, pp_cap->NotButton.LogicalMin); | ||
| 73 | fprintf(file, "pp_data->cap[%u]->NotButton.LogicalMax = %ld\n", cap_idx, pp_cap->NotButton.LogicalMax); | ||
| 74 | fprintf(file, "pp_data->cap[%u]->NotButton.PhysicalMin = %ld\n", cap_idx, pp_cap->NotButton.PhysicalMin); | ||
| 75 | fprintf(file, "pp_data->cap[%u]->NotButton.PhysicalMax = %ld\n", cap_idx, pp_cap->NotButton.PhysicalMax); | ||
| 76 | }; | ||
| 77 | fprintf(file, "pp_data->cap[%u]->Units = %lu\n", cap_idx, pp_cap->Units); | ||
| 78 | fprintf(file, "pp_data->cap[%u]->UnitsExp = %lu\n", cap_idx, pp_cap->UnitsExp); | ||
| 79 | } | ||
| 80 | |||
| 81 | void dump_hidp_link_collection_node(FILE* file, phid_pp_link_collection_node pcoll, unsigned int coll_idx) { | ||
| 82 | fprintf(file, "pp_data->LinkCollectionArray[%u]->LinkUsage = 0x%04hX\n", coll_idx, pcoll->LinkUsage); | ||
| 83 | fprintf(file, "pp_data->LinkCollectionArray[%u]->LinkUsagePage = 0x%04hX\n", coll_idx, pcoll->LinkUsagePage); | ||
| 84 | fprintf(file, "pp_data->LinkCollectionArray[%u]->Parent = %hu\n", coll_idx, pcoll->Parent); | ||
| 85 | fprintf(file, "pp_data->LinkCollectionArray[%u]->NumberOfChildren = %hu\n", coll_idx, pcoll->NumberOfChildren); | ||
| 86 | fprintf(file, "pp_data->LinkCollectionArray[%u]->NextSibling = %hu\n", coll_idx, pcoll->NextSibling); | ||
| 87 | fprintf(file, "pp_data->LinkCollectionArray[%u]->FirstChild = %hu\n", coll_idx, pcoll->FirstChild); | ||
| 88 | // The compilers are not consistent on ULONG-bit-fields: They lose the unsinged or define them as int. | ||
| 89 | // Thus just always cast them to unsinged int, which should be fine, as the biggest bit-field is 28 bit | ||
| 90 | fprintf(file, "pp_data->LinkCollectionArray[%u]->CollectionType = %u\n", coll_idx, (unsigned int)(pcoll->CollectionType)); | ||
| 91 | fprintf(file, "pp_data->LinkCollectionArray[%u]->IsAlias = %u\n", coll_idx, (unsigned int)(pcoll->IsAlias)); | ||
| 92 | fprintf(file, "pp_data->LinkCollectionArray[%u]->Reserved = 0x%08X\n", coll_idx, (unsigned int)(pcoll->Reserved)); | ||
| 93 | } | ||
| 94 | |||
| 95 | int dump_pp_data(FILE* file, hid_device* dev) | ||
| 96 | { | ||
| 97 | BOOL res; | ||
| 98 | hidp_preparsed_data* pp_data = NULL; | ||
| 99 | |||
| 100 | res = HidD_GetPreparsedData(dev->device_handle, (PHIDP_PREPARSED_DATA*) &pp_data); | ||
| 101 | if (!res) { | ||
| 102 | printf("ERROR: HidD_GetPreparsedData failed!"); | ||
| 103 | return -1; | ||
| 104 | } | ||
| 105 | else { | ||
| 106 | fprintf(file, "pp_data->MagicKey = 0x%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX\n", pp_data->MagicKey[0], pp_data->MagicKey[1], pp_data->MagicKey[2], pp_data->MagicKey[3], pp_data->MagicKey[4], pp_data->MagicKey[5], pp_data->MagicKey[6], pp_data->MagicKey[7]); | ||
| 107 | fprintf(file, "pp_data->Usage = 0x%04hX\n", pp_data->Usage); | ||
| 108 | fprintf(file, "pp_data->UsagePage = 0x%04hX\n", pp_data->UsagePage); | ||
| 109 | fprintf(file, "pp_data->Reserved = 0x%04hX%04hX\n", pp_data->Reserved[0], pp_data->Reserved[1]); | ||
| 110 | fprintf(file, "# Input caps_info struct:\n"); | ||
| 111 | fprintf(file, "pp_data->caps_info[0]->FirstCap = %hu\n", pp_data->caps_info[0].FirstCap); | ||
| 112 | fprintf(file, "pp_data->caps_info[0]->LastCap = %hu\n", pp_data->caps_info[0].LastCap); | ||
| 113 | fprintf(file, "pp_data->caps_info[0]->NumberOfCaps = %hu\n", pp_data->caps_info[0].NumberOfCaps); | ||
| 114 | fprintf(file, "pp_data->caps_info[0]->ReportByteLength = %hu\n", pp_data->caps_info[0].ReportByteLength); | ||
| 115 | fprintf(file, "# Output caps_info struct:\n"); | ||
| 116 | fprintf(file, "pp_data->caps_info[1]->FirstCap = %hu\n", pp_data->caps_info[1].FirstCap); | ||
| 117 | fprintf(file, "pp_data->caps_info[1]->LastCap = %hu\n", pp_data->caps_info[1].LastCap); | ||
| 118 | fprintf(file, "pp_data->caps_info[1]->NumberOfCaps = %hu\n", pp_data->caps_info[1].NumberOfCaps); | ||
| 119 | fprintf(file, "pp_data->caps_info[1]->ReportByteLength = %hu\n", pp_data->caps_info[1].ReportByteLength); | ||
| 120 | fprintf(file, "# Feature caps_info struct:\n"); | ||
| 121 | fprintf(file, "pp_data->caps_info[2]->FirstCap = %hu\n", pp_data->caps_info[2].FirstCap); | ||
| 122 | fprintf(file, "pp_data->caps_info[2]->LastCap = %hu\n", pp_data->caps_info[2].LastCap); | ||
| 123 | fprintf(file, "pp_data->caps_info[2]->NumberOfCaps = %hu\n", pp_data->caps_info[2].NumberOfCaps); | ||
| 124 | fprintf(file, "pp_data->caps_info[2]->ReportByteLength = %hu\n", pp_data->caps_info[2].ReportByteLength); | ||
| 125 | fprintf(file, "# LinkCollectionArray Offset & Size:\n"); | ||
| 126 | fprintf(file, "pp_data->FirstByteOfLinkCollectionArray = 0x%04hX\n", pp_data->FirstByteOfLinkCollectionArray); | ||
| 127 | fprintf(file, "pp_data->NumberLinkCollectionNodes = %hu\n", pp_data->NumberLinkCollectionNodes); | ||
| 128 | |||
| 129 | |||
| 130 | phid_pp_cap pcap = (phid_pp_cap)(((unsigned char*)pp_data) + offsetof(hidp_preparsed_data, caps)); | ||
| 131 | fprintf(file, "# Input hid_pp_cap struct:\n"); | ||
| 132 | for (int caps_idx = pp_data->caps_info[0].FirstCap; caps_idx < pp_data->caps_info[0].LastCap; caps_idx++) { | ||
| 133 | dump_hid_pp_cap(file, pcap + caps_idx, caps_idx); | ||
| 134 | fprintf(file, "\n"); | ||
| 135 | } | ||
| 136 | fprintf(file, "# Output hid_pp_cap struct:\n"); | ||
| 137 | for (int caps_idx = pp_data->caps_info[1].FirstCap; caps_idx < pp_data->caps_info[1].LastCap; caps_idx++) { | ||
| 138 | dump_hid_pp_cap(file, pcap + caps_idx, caps_idx); | ||
| 139 | fprintf(file, "\n"); | ||
| 140 | } | ||
| 141 | fprintf(file, "# Feature hid_pp_cap struct:\n"); | ||
| 142 | for (int caps_idx = pp_data->caps_info[2].FirstCap; caps_idx < pp_data->caps_info[2].LastCap; caps_idx++) { | ||
| 143 | dump_hid_pp_cap(file, pcap + caps_idx, caps_idx); | ||
| 144 | fprintf(file, "\n"); | ||
| 145 | } | ||
| 146 | |||
| 147 | phid_pp_link_collection_node pcoll = (phid_pp_link_collection_node)(((unsigned char*)pcap) + pp_data->FirstByteOfLinkCollectionArray); | ||
| 148 | fprintf(file, "# Link Collections:\n"); | ||
| 149 | for (int coll_idx = 0; coll_idx < pp_data->NumberLinkCollectionNodes; coll_idx++) { | ||
| 150 | dump_hidp_link_collection_node(file, pcoll + coll_idx, coll_idx); | ||
| 151 | } | ||
| 152 | |||
| 153 | HidD_FreePreparsedData((PHIDP_PREPARSED_DATA) pp_data); | ||
| 154 | return 0; | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | int main(int argc, char* argv[]) | ||
| 159 | { | ||
| 160 | (void)argc; | ||
| 161 | (void)argv; | ||
| 162 | |||
| 163 | #define MAX_STR 255 | ||
| 164 | |||
| 165 | struct hid_device_info *devs, *cur_dev; | ||
| 166 | |||
| 167 | printf("pp_data_dump tool. Compiled with hidapi version %s, runtime version %s.\n", HID_API_VERSION_STR, hid_version_str()); | ||
| 168 | if (hid_version()->major == HID_API_VERSION_MAJOR && hid_version()->minor == HID_API_VERSION_MINOR && hid_version()->patch == HID_API_VERSION_PATCH) { | ||
| 169 | printf("Compile-time version matches runtime version of hidapi.\n\n"); | ||
| 170 | } | ||
| 171 | else { | ||
| 172 | printf("Compile-time version is different than runtime version of hidapi.\n]n"); | ||
| 173 | } | ||
| 174 | |||
| 175 | if (hid_init()) | ||
| 176 | return -1; | ||
| 177 | |||
| 178 | devs = hid_enumerate(0x0, 0x0); | ||
| 179 | cur_dev = devs; | ||
| 180 | while (cur_dev) { | ||
| 181 | printf("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number); | ||
| 182 | printf("\n"); | ||
| 183 | printf(" Manufacturer: %ls\n", cur_dev->manufacturer_string); | ||
| 184 | printf(" Product: %ls\n", cur_dev->product_string); | ||
| 185 | printf(" Release: %hX\n", cur_dev->release_number); | ||
| 186 | printf(" Interface: %d\n", cur_dev->interface_number); | ||
| 187 | printf(" Usage (page): %02X (%02X)\n", cur_dev->usage, cur_dev->usage_page); | ||
| 188 | |||
| 189 | hid_device *device = hid_open_path(cur_dev->path); | ||
| 190 | if (device) { | ||
| 191 | char filename[MAX_STR]; | ||
| 192 | FILE* file; | ||
| 193 | |||
| 194 | sprintf_s(filename, MAX_STR, "%04X_%04X_%04X_%04X.pp_data", cur_dev->vendor_id, cur_dev->product_id, cur_dev->usage, cur_dev->usage_page); | ||
| 195 | errno_t err = fopen_s(&file, filename, "w"); | ||
| 196 | if (err == 0) { | ||
| 197 | fprintf(file, "# HIDAPI device info struct:\n"); | ||
| 198 | fprintf(file, "dev->vendor_id = 0x%04hX\n", cur_dev->vendor_id); | ||
| 199 | fprintf(file, "dev->product_id = 0x%04hX\n", cur_dev->product_id); | ||
| 200 | fprintf(file, "dev->manufacturer_string = \"%ls\"\n", cur_dev->manufacturer_string); | ||
| 201 | fprintf(file, "dev->product_string = \"%ls\"\n", cur_dev->product_string); | ||
| 202 | fprintf(file, "dev->release_number = 0x%04hX\n", cur_dev->release_number); | ||
| 203 | fprintf(file, "dev->interface_number = %d\n", cur_dev->interface_number); | ||
| 204 | fprintf(file, "dev->usage = 0x%04hX\n", cur_dev->usage); | ||
| 205 | fprintf(file, "dev->usage_page = 0x%04hX\n", cur_dev->usage_page); | ||
| 206 | fprintf(file, "dev->path = \"%s\"\n", cur_dev->path); | ||
| 207 | fprintf(file, "\n# Preparsed Data struct:\n"); | ||
| 208 | int res = dump_pp_data(file, device); | ||
| 209 | |||
| 210 | if (res == 0) { | ||
| 211 | printf("Dumped Preparsed Data to %s\n", filename); | ||
| 212 | } | ||
| 213 | else { | ||
| 214 | printf("ERROR: Dump Preparsed Data to %s failed!\n", filename); | ||
| 215 | } | ||
| 216 | |||
| 217 | fclose(file); | ||
| 218 | } | ||
| 219 | |||
| 220 | hid_close(device); | ||
| 221 | } | ||
| 222 | else { | ||
| 223 | printf(" Device: not available.\n"); | ||
| 224 | } | ||
| 225 | |||
| 226 | printf("\n"); | ||
| 227 | cur_dev = cur_dev->next; | ||
| 228 | } | ||
| 229 | hid_free_enumeration(devs); | ||
| 230 | |||
| 231 | |||
| 232 | /* Free static HIDAPI objects. */ | ||
| 233 | hid_exit(); | ||
| 234 | |||
| 235 | //system("pause"); | ||
| 236 | |||
| 237 | return 0; | ||
| 238 | } | ||
