summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/hidapi/windows/pp_data_dump
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
committer3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
commit5a079a2d114f96d4847d1ee305d5b7c16eeec50e (patch)
tree8926ab44f168acf787d8e19608857b3af0f82758 /contrib/SDL-3.2.8/src/hidapi/windows/pp_data_dump
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/src/hidapi/windows/pp_data_dump')
-rw-r--r--contrib/SDL-3.2.8/src/hidapi/windows/pp_data_dump/CMakeLists.txt15
-rw-r--r--contrib/SDL-3.2.8/src/hidapi/windows/pp_data_dump/README.md122
-rw-r--r--contrib/SDL-3.2.8/src/hidapi/windows/pp_data_dump/pp_data_dump.c238
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 @@
1project(pp_data_dump C)
2
3add_executable(pp_data_dump pp_data_dump.c)
4set_target_properties(pp_data_dump
5 PROPERTIES
6 C_STANDARD 11
7 C_STANDARD_REQUIRED TRUE
8)
9target_link_libraries(pp_data_dump
10 PRIVATE hidapi_winapi
11)
12
13install(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
4pp_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
6The 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
8pp_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```
12for each top-level collection, of each connected HID device.
13
14
15## File content
16
17The content of such a .pp_data file looks like the struct, which HIDAPI uses internally to represent the Preparsed Data.
18
19*NOTE:
20Windows parses HID report descriptors into opaque `_HIDP_PREPARSED_DATA` objects.
21The internal structure of `_HIDP_PREPARSED_DATA` is reserved for internal system use.\
22Microsoft 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:
26dev->vendor_id = 0x046D
27dev->product_id = 0xB010
28dev->manufacturer_string = "Logitech"
29dev->product_string = "Logitech Bluetooth Wireless Mouse"
30dev->release_number = 0x0000
31dev->interface_number = -1
32dev->usage = 0x0001
33dev->usage_page = 0x000C
34dev->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:
37pp_data->MagicKey = 0x48696450204B4452
38pp_data->Usage = 0x0001
39pp_data->UsagePage = 0x000C
40pp_data->Reserved = 0x00000000
41# Input caps_info struct:
42pp_data->caps_info[0]->FirstCap = 0
43pp_data->caps_info[0]->LastCap = 1
44pp_data->caps_info[0]->NumberOfCaps = 1
45pp_data->caps_info[0]->ReportByteLength = 2
46# Output caps_info struct:
47pp_data->caps_info[1]->FirstCap = 1
48pp_data->caps_info[1]->LastCap = 1
49pp_data->caps_info[1]->NumberOfCaps = 0
50pp_data->caps_info[1]->ReportByteLength = 0
51# Feature caps_info struct:
52pp_data->caps_info[2]->FirstCap = 1
53pp_data->caps_info[2]->LastCap = 1
54pp_data->caps_info[2]->NumberOfCaps = 0
55pp_data->caps_info[2]->ReportByteLength = 0
56# LinkCollectionArray Offset & Size:
57pp_data->FirstByteOfLinkCollectionArray = 0x0068
58pp_data->NumberLinkCollectionNodes = 1
59# Input hid_pp_cap struct:
60pp_data->cap[0]->UsagePage = 0x0006
61pp_data->cap[0]->ReportID = 0x03
62pp_data->cap[0]->BitPosition = 0
63pp_data->cap[0]->BitSize = 8
64pp_data->cap[0]->ReportCount = 1
65pp_data->cap[0]->BytePosition = 0x0001
66pp_data->cap[0]->BitCount = 8
67pp_data->cap[0]->BitField = 0x02
68pp_data->cap[0]->NextBytePosition = 0x0002
69pp_data->cap[0]->LinkCollection = 0x0000
70pp_data->cap[0]->LinkUsagePage = 0x000C
71pp_data->cap[0]->LinkUsage = 0x0001
72pp_data->cap[0]->IsMultipleItemsForArray = 0
73pp_data->cap[0]->IsButtonCap = 0
74pp_data->cap[0]->IsPadding = 0
75pp_data->cap[0]->IsAbsolute = 1
76pp_data->cap[0]->IsRange = 0
77pp_data->cap[0]->IsAlias = 0
78pp_data->cap[0]->IsStringRange = 0
79pp_data->cap[0]->IsDesignatorRange = 0
80pp_data->cap[0]->Reserved1 = 0x000000
81pp_data->cap[0]->pp_cap->UnknownTokens[0].Token = 0x00
82pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
83pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
84pp_data->cap[0]->pp_cap->UnknownTokens[1].Token = 0x00
85pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
86pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
87pp_data->cap[0]->pp_cap->UnknownTokens[2].Token = 0x00
88pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
89pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
90pp_data->cap[0]->pp_cap->UnknownTokens[3].Token = 0x00
91pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
92pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
93pp_data->cap[0]->NotRange.Usage = 0x0020
94pp_data->cap[0]->NotRange.Reserved1 = 0x0020
95pp_data->cap[0]->NotRange.StringIndex = 0
96pp_data->cap[0]->NotRange.Reserved2 = 0
97pp_data->cap[0]->NotRange.DesignatorIndex = 0
98pp_data->cap[0]->NotRange.Reserved3 = 0
99pp_data->cap[0]->NotRange.DataIndex = 0
100pp_data->cap[0]->NotRange.Reserved4 = 0
101pp_data->cap[0]->NotButton.HasNull = 0
102pp_data->cap[0]->NotButton.Reserved4 = 0x000000
103pp_data->cap[0]->NotButton.LogicalMin = 0
104pp_data->cap[0]->NotButton.LogicalMax = 100
105pp_data->cap[0]->NotButton.PhysicalMin = 0
106pp_data->cap[0]->NotButton.PhysicalMax = 0
107pp_data->cap[0]->Units = 0
108pp_data->cap[0]->UnitsExp = 0
109
110# Output hid_pp_cap struct:
111# Feature hid_pp_cap struct:
112# Link Collections:
113pp_data->LinkCollectionArray[0]->LinkUsage = 0x0001
114pp_data->LinkCollectionArray[0]->LinkUsagePage = 0x000C
115pp_data->LinkCollectionArray[0]->Parent = 0
116pp_data->LinkCollectionArray[0]->NumberOfChildren = 0
117pp_data->LinkCollectionArray[0]->NextSibling = 0
118pp_data->LinkCollectionArray[0]->FirstChild = 0
119pp_data->LinkCollectionArray[0]->CollectionType = 1
120pp_data->LinkCollectionArray[0]->IsAlias = 0
121pp_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
11void 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
81void 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
95int 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
158int 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}