2 * Copyright (c) 2017 Aric Stewart
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define WIN32_NO_STATUS
25 #include "ddk/hidsdi.h"
27 #include "wine/test.h"
29 #define READ_MAX_TIME 5000
31 typedef void (device_test
)(HANDLE device
);
33 static void test_device_info(HANDLE device
)
35 PHIDP_PREPARSED_DATA ppd
;
37 HIDD_ATTRIBUTES attributes
;
38 HIDP_LINK_COLLECTION_NODE nodes
[16];
42 WCHAR device_name
[128];
45 rc
= HidD_GetPreparsedData(device
, &ppd
);
46 ok(rc
, "Failed to get preparsed data(0x%x)\n", GetLastError());
47 status
= HidP_GetCaps(ppd
, &Caps
);
48 ok(status
== HIDP_STATUS_SUCCESS
, "Failed to get Caps(0x%x)\n", status
);
49 rc
= HidD_GetProductString(device
, device_name
, sizeof(device_name
));
50 ok(rc
, "Failed to get product string(0x%x)\n", GetLastError());
51 trace("Found device %s (%02x, %02x)\n", wine_dbgstr_w(device_name
), Caps
.UsagePage
, Caps
.Usage
);
53 trace("LinkCollectionNodes: (%d)\n", Caps
.NumberLinkCollectionNodes
);
54 ok(Caps
.NumberLinkCollectionNodes
> 0, "Expected at least one link collection\n");
57 status
= HidP_GetLinkCollectionNodes(nodes
, &nodes_count
, ppd
);
58 ok(status
== HIDP_STATUS_BUFFER_TOO_SMALL
, "HidP_GetLinkCollectionNodes succeeded:%x\n", status
);
60 nodes_count
= ARRAY_SIZE(nodes
);
61 status
= HidP_GetLinkCollectionNodes(nodes
, &nodes_count
, ppd
);
62 ok(status
== HIDP_STATUS_SUCCESS
, "HidP_GetLinkCollectionNodes failed:%x\n", status
);
64 for (i
= 0; i
< nodes_count
; ++i
)
66 trace(" [%d] LinkUsage: %x LinkUsagePage: %x Parent: %x "
67 "NumberOfChildren: %x NextSibling: %x FirstChild: %x "
68 "CollectionType: %x IsAlias: %x UserContext: %p\n",
69 i
, nodes
[i
].LinkUsage
, nodes
[i
].LinkUsagePage
, nodes
[i
].Parent
,
70 nodes
[i
].NumberOfChildren
, nodes
[i
].NextSibling
, nodes
[i
].FirstChild
,
71 nodes
[i
].CollectionType
, nodes
[i
].IsAlias
, nodes
[i
].UserContext
);
74 ok(nodes_count
> 0, "Unexpected number of link collection nodes:%u.\n", nodes_count
);
75 ok(nodes
[0].LinkUsagePage
== Caps
.UsagePage
, "Unexpected top collection usage page:%x\n", nodes
[0].LinkUsagePage
);
76 ok(nodes
[0].LinkUsage
== Caps
.Usage
, "Unexpected top collection usage:%x\n", nodes
[0].LinkUsage
);
77 ok(nodes
[0].CollectionType
== 1, "Unexpected top collection type:%x\n", nodes
[0].CollectionType
);
79 rc
= HidD_FreePreparsedData(ppd
);
80 ok(rc
, "Failed to free preparsed data(0x%x)\n", GetLastError());
81 rc
= HidD_GetAttributes(device
, &attributes
);
82 ok(rc
, "Failed to get device attributes (0x%x)\n", GetLastError());
83 ok(attributes
.Size
== sizeof(attributes
), "Unexpected HIDD_ATTRIBUTES size: %d\n", attributes
.Size
);
84 trace("Device attributes: vid:%04x pid:%04x ver:%04x\n", attributes
.VendorID
, attributes
.ProductID
, attributes
.VersionNumber
);
87 static void run_for_each_device(device_test
*test
)
92 SP_DEVICE_INTERFACE_DATA interface_data
;
93 DWORD detail_size
= MAX_PATH
* sizeof(WCHAR
);
94 SP_DEVICE_INTERFACE_DETAIL_DATA_W
*data
;
96 HidD_GetHidGuid(&hid_guid
);
98 ZeroMemory(&interface_data
, sizeof(interface_data
));
99 interface_data
.cbSize
= sizeof(interface_data
);
101 data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*data
) + detail_size
);
102 data
->cbSize
= sizeof(*data
);
104 info_set
= SetupDiGetClassDevsW(&hid_guid
, NULL
, NULL
, DIGCF_DEVICEINTERFACE
| DIGCF_PRESENT
);
105 while (SetupDiEnumDeviceInterfaces(info_set
, NULL
, &hid_guid
, index
, &interface_data
))
109 if (SetupDiGetDeviceInterfaceDetailW(info_set
, &interface_data
, data
, sizeof(*data
) + detail_size
, NULL
, NULL
))
111 HANDLE file
= CreateFileW(data
->DevicePath
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0);
112 if (file
== INVALID_HANDLE_VALUE
&& GetLastError() == ERROR_ACCESS_DENIED
)
114 trace("Not enough permissions to read device %s.\n", wine_dbgstr_w(data
->DevicePath
));
117 if (file
== INVALID_HANDLE_VALUE
&& GetLastError() == ERROR_SHARING_VIOLATION
)
119 trace("Device is busy: %s.\n", wine_dbgstr_w(data
->DevicePath
));
123 ok(file
!= INVALID_HANDLE_VALUE
, "Failed to open %s, error %u.\n",
124 wine_dbgstr_w(data
->DevicePath
), GetLastError());
126 if (file
!= INVALID_HANDLE_VALUE
)
132 HeapFree(GetProcessHeap(), 0, data
);
133 SetupDiDestroyDeviceInfoList(info_set
);
136 static HANDLE
get_device(USHORT page
, USHORT usages
[], UINT usage_count
, DWORD access
)
141 SP_DEVICE_INTERFACE_DATA interface_data
;
142 DWORD detail_size
= MAX_PATH
* sizeof(WCHAR
);
143 SP_DEVICE_INTERFACE_DETAIL_DATA_W
*data
;
147 HidD_GetHidGuid(&hid_guid
);
149 ZeroMemory(&interface_data
, sizeof(interface_data
));
150 interface_data
.cbSize
= sizeof(interface_data
);
152 data
= HeapAlloc(GetProcessHeap(), 0 , sizeof(*data
) + detail_size
);
153 data
->cbSize
= sizeof(*data
);
155 info_set
= SetupDiGetClassDevsW(&hid_guid
, NULL
, NULL
, DIGCF_DEVICEINTERFACE
| DIGCF_PRESENT
);
156 while (SetupDiEnumDeviceInterfaces(info_set
, NULL
, &hid_guid
, index
, &interface_data
))
160 if (SetupDiGetDeviceInterfaceDetailW(info_set
, &interface_data
, data
, sizeof(*data
) + detail_size
, NULL
, NULL
))
162 PHIDP_PREPARSED_DATA ppd
;
164 HANDLE file
= CreateFileW(data
->DevicePath
, access
, FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
165 if (file
== INVALID_HANDLE_VALUE
&& GetLastError() == ERROR_ACCESS_DENIED
)
167 trace("Not enough permissions to read device %s.\n", wine_dbgstr_w(data
->DevicePath
));
170 ok(file
!= INVALID_HANDLE_VALUE
, "got error %u\n", GetLastError());
172 rc
= HidD_GetPreparsedData(file
, &ppd
);
173 ok(rc
, "Failed to get preparsed data(0x%x)\n", GetLastError());
174 status
= HidP_GetCaps(ppd
, &Caps
);
175 ok(status
== HIDP_STATUS_SUCCESS
, "Failed to get Caps(0x%x)\n", status
);
176 rc
= HidD_FreePreparsedData(ppd
);
177 ok(rc
, "Failed to free preparsed data(0x%x)\n", GetLastError());
178 if (!page
|| page
== Caps
.UsagePage
)
183 HeapFree(GetProcessHeap(), 0, data
);
184 SetupDiDestroyDeviceInfoList(info_set
);
187 for (j
= 0; j
< usage_count
; j
++)
188 if (!usages
[j
] || usages
[j
] == Caps
.Usage
)
190 HeapFree(GetProcessHeap(), 0, data
);
191 SetupDiDestroyDeviceInfoList(info_set
);
198 HeapFree(GetProcessHeap(), 0, data
);
199 SetupDiDestroyDeviceInfoList(info_set
);
203 static void process_data(HIDP_CAPS Caps
, PHIDP_PREPARSED_DATA ppd
, CHAR
*data
, DWORD data_length
)
208 if (Caps
.NumberInputButtonCaps
)
210 USAGE button_pages
[100];
212 for (i
= 1; i
< 0xff; i
++)
214 ULONG usage_length
= 100;
215 status
= HidP_GetUsages(HidP_Input
, i
, 0, button_pages
, &usage_length
, ppd
, data
, data_length
);
216 ok (status
== HIDP_STATUS_SUCCESS
|| usage_length
== 0,
217 "HidP_GetUsages failed (%x) but usage length still %i\n", status
, usage_length
);
224 count
= usage_length
;
227 trace("\tButtons [0x%x: %i buttons]:\n", i
, usage_length
);
228 for (count
= 0; count
< usage_length
; count
+= 15)
230 for (j
=count
; j
< count
+15 && j
< usage_length
; j
++)
233 sprintf(btn
, "%i ", button_pages
[j
]);
236 trace("\t\t%s\n", report
);
242 if (Caps
.NumberInputValueCaps
)
246 HIDP_VALUE_CAPS
*values
= NULL
;
248 values
= HeapAlloc(GetProcessHeap(), 0, sizeof(HIDP_VALUE_CAPS
) * Caps
.NumberInputValueCaps
);
249 length
= Caps
.NumberInputValueCaps
;
250 status
= HidP_GetValueCaps(HidP_Input
, values
, &length
, ppd
);
251 ok(status
== HIDP_STATUS_SUCCESS
, "Failed to get value caps (%x)\n",status
);
253 trace("\tValues:\n");
254 for (i
= 0; i
< length
; i
++)
256 ok(values
[i
].ReportCount
, "Zero ReportCount for [%i,%i]\n", values
[i
].UsagePage
, values
[i
].NotRange
.Usage
);
257 if (values
[i
].IsRange
|| values
[i
].ReportCount
<= 1)
259 status
= HidP_GetUsageValue(HidP_Input
, values
[i
].UsagePage
, 0,
260 values
[i
].Range
.UsageMin
, &value
, ppd
, data
, data_length
);
261 ok(status
== HIDP_STATUS_SUCCESS
, "Failed to get value [%i,%i] (%x)\n",
262 values
[i
].UsagePage
, values
[i
].Range
.UsageMin
, status
);
263 trace("[%02x, %02x]: %u\n", values
[i
].UsagePage
, values
[i
].Range
.UsageMin
, value
);
267 USHORT k
, array_size
= (values
[i
].BitSize
* values
[i
].ReportCount
+ 7) / 8;
268 PCHAR array
= HeapAlloc(GetProcessHeap(), 0, array_size
);
269 char *dump
= HeapAlloc(GetProcessHeap(), 0, array_size
* 3 + 1);
271 status
= HidP_GetUsageValueArray(HidP_Input
, values
[i
].UsagePage
, 0,
272 values
[i
].NotRange
.Usage
, array
, array_size
, ppd
, data
, data_length
);
273 ok(status
== HIDP_STATUS_SUCCESS
, "Failed to get value array [%i,%i] (%x)\n",
274 values
[i
].UsagePage
, values
[i
].NotRange
.Usage
, status
);
276 for (k
= 0; k
< array_size
; k
++)
279 sprintf(bytestr
, " %02x", (BYTE
)array
[k
]);
280 strcat(dump
, bytestr
);
282 trace("[%02x, %02x] element bit size %u num elements %u:%s\n", values
[i
].UsagePage
,
283 values
[i
].NotRange
.Usage
, values
[i
].BitSize
, values
[i
].ReportCount
, dump
);
285 HeapFree(GetProcessHeap(), 0, dump
);
286 HeapFree(GetProcessHeap(), 0, array
);
290 HeapFree(GetProcessHeap(), 0, values
);
294 static void test_read_device(void)
296 PHIDP_PREPARSED_DATA ppd
;
298 OVERLAPPED overlapped
;
299 WCHAR device_name
[128];
304 DWORD timeout
, tick
, spent
, max_time
;
307 USAGE device_usages
[] = {HID_USAGE_GENERIC_JOYSTICK
, HID_USAGE_GENERIC_GAMEPAD
};
308 HANDLE device
= get_device(HID_USAGE_PAGE_GENERIC
, device_usages
, 2, GENERIC_READ
);
311 device
= get_device(0x0, NULL
, 0x0, GENERIC_READ
);
315 trace("No device found for reading\n");
318 rc
= HidD_GetProductString(device
, device_name
, sizeof(device_name
));
319 ok(rc
, "Failed to get product string(0x%x)\n", GetLastError());
320 trace("Read tests on device :%s\n",wine_dbgstr_w(device_name
));
322 rc
= HidD_GetPreparsedData(device
, &ppd
);
323 ok(rc
, "Failed to get preparsed data(0x%x)\n", GetLastError());
324 status
= HidP_GetCaps(ppd
, &Caps
);
325 ok(status
== HIDP_STATUS_SUCCESS
, "Failed to get Caps(0x%x)\n", status
);
326 data
= HeapAlloc(GetProcessHeap(), 0, Caps
.InputReportByteLength
);
328 memset(&overlapped
, 0, sizeof(overlapped
));
329 overlapped
.hEvent
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
330 if (winetest_interactive
)
332 max_time
= READ_MAX_TIME
;
336 max_time
= timeout
= 100;
337 if (winetest_interactive
)
338 trace("Test your device for the next %i seconds\n", max_time
/1000);
339 report
= HeapAlloc(GetProcessHeap(), 0, 3 * Caps
.InputReportByteLength
);
340 tick
= GetTickCount();
344 ReadFile(device
, data
, Caps
.InputReportByteLength
, NULL
, &overlapped
);
345 if (WaitForSingleObject(overlapped
.hEvent
, timeout
) != WAIT_OBJECT_0
)
347 ResetEvent(overlapped
.hEvent
);
348 spent
= GetTickCount() - tick
;
349 trace("REMAINING: %d ms\n", max_time
- spent
);
352 ResetEvent(overlapped
.hEvent
);
353 spent
= GetTickCount() - tick
;
354 GetOverlappedResult(device
, &overlapped
, &read
, FALSE
);
360 for (i
= 0; i
< read
&& i
< Caps
.InputReportByteLength
; i
++)
363 sprintf(bytestr
, "%x ", (BYTE
)data
[i
]);
364 strcat(report
, bytestr
);
366 trace("Input report (%i): %s\n", read
, report
);
368 process_data(Caps
, ppd
, data
, read
);
370 trace("REMAINING: %d ms\n", max_time
- spent
);
371 } while(spent
< max_time
);
373 CloseHandle(overlapped
.hEvent
);
374 rc
= HidD_FreePreparsedData(ppd
);
375 ok(rc
, "Failed to free preparsed data(0x%x)\n", GetLastError());
378 HeapFree(GetProcessHeap(), 0, data
);
379 HeapFree(GetProcessHeap(), 0, report
);
382 static void test_get_input_report(void)
384 PHIDP_PREPARSED_DATA ppd
;
386 WCHAR device_name
[128];
388 DWORD tick
, spent
, max_time
;
393 USAGE device_usages
[] = {HID_USAGE_GENERIC_JOYSTICK
, HID_USAGE_GENERIC_GAMEPAD
};
394 HANDLE device
= get_device(HID_USAGE_PAGE_GENERIC
, device_usages
, 2, GENERIC_READ
);
397 device
= get_device(0x0, NULL
, 0x0, GENERIC_READ
);
401 trace("No device found for testing\n");
404 rc
= HidD_GetProductString(device
, device_name
, sizeof(device_name
));
405 ok(rc
, "Failed to get product string(0x%x)\n", GetLastError());
406 trace("HidD_GetInputRpeort tests on device :%s\n",wine_dbgstr_w(device_name
));
408 rc
= HidD_GetPreparsedData(device
, &ppd
);
409 ok(rc
, "Failed to get preparsed data(0x%x)\n", GetLastError());
410 status
= HidP_GetCaps(ppd
, &Caps
);
411 ok(status
== HIDP_STATUS_SUCCESS
, "Failed to get Caps(0x%x)\n", status
);
412 data
= HeapAlloc(GetProcessHeap(), 0, Caps
.InputReportByteLength
);
414 if (winetest_interactive
)
415 max_time
= READ_MAX_TIME
;
418 if (winetest_interactive
)
419 trace("Test your device for the next %i seconds\n", max_time
/1000);
420 report
= HeapAlloc(GetProcessHeap(), 0, 3 * Caps
.InputReportByteLength
);
421 tick
= GetTickCount();
427 data
[0] = 0; /* Just testing report ID 0 for now, That will catch most devices */
428 rc
= HidD_GetInputReport(device
, data
, Caps
.InputReportByteLength
);
429 spent
= GetTickCount() - tick
;
433 ok(data
[0] == 0, "Report ID (0) is not the first byte of the data\n");
435 for (i
= 0; i
< Caps
.InputReportByteLength
; i
++)
438 sprintf(bytestr
, "%x ", (BYTE
)data
[i
]);
439 strcat(report
, bytestr
);
441 trace("Input report (%i): %s\n", Caps
.InputReportByteLength
, report
);
443 process_data(Caps
, ppd
, data
, Caps
.InputReportByteLength
);
446 trace("Failed to get Input Report, (%x)\n", rc
);
447 trace("REMAINING: %d ms\n", max_time
- spent
);
449 } while(spent
< max_time
);
451 rc
= HidD_FreePreparsedData(ppd
);
452 ok(rc
, "Failed to free preparsed data(0x%x)\n", GetLastError());
454 HeapFree(GetProcessHeap(), 0, data
);
455 HeapFree(GetProcessHeap(), 0, report
);
460 run_for_each_device(test_device_info
);
462 test_get_input_report();