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
;
40 WCHAR device_name
[128];
42 rc
= HidD_GetPreparsedData(device
, &ppd
);
43 ok(rc
, "Failed to get preparsed data(0x%x)\n", GetLastError());
44 status
= HidP_GetCaps(ppd
, &Caps
);
45 ok(status
== HIDP_STATUS_SUCCESS
, "Failed to get Caps(0x%x)\n", status
);
46 rc
= HidD_GetProductString(device
, device_name
, sizeof(device_name
));
47 ok(rc
, "Failed to get product string(0x%x)\n", GetLastError());
48 trace("Found device %s (%02x, %02x)\n", wine_dbgstr_w(device_name
), Caps
.UsagePage
, Caps
.Usage
);
49 rc
= HidD_FreePreparsedData(ppd
);
50 ok(rc
, "Failed to free preparsed data(0x%x)\n", GetLastError());
51 rc
= HidD_GetAttributes(device
, &attributes
);
52 ok(rc
, "Failed to get device attributes (0x%x)\n", GetLastError());
53 ok(attributes
.Size
== sizeof(attributes
), "Unexpected HIDD_ATTRIBUTES size: %d\n", attributes
.Size
);
54 trace("Device attributes: vid:%04x pid:%04x ver:%04x\n", attributes
.VendorID
, attributes
.ProductID
, attributes
.VersionNumber
);
57 static void run_for_each_device(device_test
*test
)
62 SP_DEVICE_INTERFACE_DATA interface_data
;
63 DWORD detail_size
= MAX_PATH
* sizeof(WCHAR
);
64 SP_DEVICE_INTERFACE_DETAIL_DATA_W
*data
;
66 HidD_GetHidGuid(&hid_guid
);
68 ZeroMemory(&interface_data
, sizeof(interface_data
));
69 interface_data
.cbSize
= sizeof(interface_data
);
71 data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*data
) + detail_size
);
72 data
->cbSize
= sizeof(*data
);
74 info_set
= SetupDiGetClassDevsW(&hid_guid
, NULL
, NULL
, DIGCF_DEVICEINTERFACE
| DIGCF_PRESENT
);
75 while (SetupDiEnumDeviceInterfaces(info_set
, NULL
, &hid_guid
, index
, &interface_data
))
79 if (SetupDiGetDeviceInterfaceDetailW(info_set
, &interface_data
, data
, sizeof(*data
) + detail_size
, NULL
, NULL
))
81 HANDLE file
= CreateFileW(data
->DevicePath
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0);
82 if (file
== INVALID_HANDLE_VALUE
&& GetLastError() == ERROR_ACCESS_DENIED
)
84 trace("Not enough permissions to read device %s.\n", wine_dbgstr_w(data
->DevicePath
));
87 if (file
== INVALID_HANDLE_VALUE
&& GetLastError() == ERROR_SHARING_VIOLATION
)
89 trace("Device is busy: %s.\n", wine_dbgstr_w(data
->DevicePath
));
93 ok(file
!= INVALID_HANDLE_VALUE
, "Failed to open %s, error %u.\n",
94 wine_dbgstr_w(data
->DevicePath
), GetLastError());
96 if (file
!= INVALID_HANDLE_VALUE
)
102 HeapFree(GetProcessHeap(), 0, data
);
103 SetupDiDestroyDeviceInfoList(info_set
);
106 static HANDLE
get_device(USHORT page
, USHORT usages
[], UINT usage_count
, DWORD access
)
111 SP_DEVICE_INTERFACE_DATA interface_data
;
112 DWORD detail_size
= MAX_PATH
* sizeof(WCHAR
);
113 SP_DEVICE_INTERFACE_DETAIL_DATA_W
*data
;
117 HidD_GetHidGuid(&hid_guid
);
119 ZeroMemory(&interface_data
, sizeof(interface_data
));
120 interface_data
.cbSize
= sizeof(interface_data
);
122 data
= HeapAlloc(GetProcessHeap(), 0 , sizeof(*data
) + detail_size
);
123 data
->cbSize
= sizeof(*data
);
125 info_set
= SetupDiGetClassDevsW(&hid_guid
, NULL
, NULL
, DIGCF_DEVICEINTERFACE
| DIGCF_PRESENT
);
126 while (SetupDiEnumDeviceInterfaces(info_set
, NULL
, &hid_guid
, index
, &interface_data
))
130 if (SetupDiGetDeviceInterfaceDetailW(info_set
, &interface_data
, data
, sizeof(*data
) + detail_size
, NULL
, NULL
))
132 PHIDP_PREPARSED_DATA ppd
;
134 HANDLE file
= CreateFileW(data
->DevicePath
, access
, FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
135 if (file
== INVALID_HANDLE_VALUE
&& GetLastError() == ERROR_ACCESS_DENIED
)
137 trace("Not enough permissions to read device %s.\n", wine_dbgstr_w(data
->DevicePath
));
140 ok(file
!= INVALID_HANDLE_VALUE
, "got error %u\n", GetLastError());
142 rc
= HidD_GetPreparsedData(file
, &ppd
);
143 ok(rc
, "Failed to get preparsed data(0x%x)\n", GetLastError());
144 status
= HidP_GetCaps(ppd
, &Caps
);
145 ok(status
== HIDP_STATUS_SUCCESS
, "Failed to get Caps(0x%x)\n", status
);
146 rc
= HidD_FreePreparsedData(ppd
);
147 ok(rc
, "Failed to free preparsed data(0x%x)\n", GetLastError());
148 if (!page
|| page
== Caps
.UsagePage
)
153 HeapFree(GetProcessHeap(), 0, data
);
154 SetupDiDestroyDeviceInfoList(info_set
);
157 for (j
= 0; j
< usage_count
; j
++)
158 if (!usages
[j
] || usages
[j
] == Caps
.Usage
)
160 HeapFree(GetProcessHeap(), 0, data
);
161 SetupDiDestroyDeviceInfoList(info_set
);
168 HeapFree(GetProcessHeap(), 0, data
);
169 SetupDiDestroyDeviceInfoList(info_set
);
173 static void process_data(HIDP_CAPS Caps
, PHIDP_PREPARSED_DATA ppd
, CHAR
*data
, DWORD data_length
)
178 if (Caps
.NumberInputButtonCaps
)
180 USAGE button_pages
[100];
182 for (i
= 1; i
< 0xff; i
++)
184 ULONG usage_length
= 100;
185 status
= HidP_GetUsages(HidP_Input
, i
, 0, button_pages
, &usage_length
, ppd
, data
, data_length
);
186 ok (status
== HIDP_STATUS_SUCCESS
|| usage_length
== 0,
187 "HidP_GetUsages failed (%x) but usage length still %i\n", status
, usage_length
);
194 count
= usage_length
;
197 trace("\tButtons [0x%x: %i buttons]:\n", i
, usage_length
);
198 for (count
= 0; count
< usage_length
; count
+= 15)
200 for (j
=count
; j
< count
+15 && j
< usage_length
; j
++)
203 sprintf(btn
, "%i ", button_pages
[j
]);
206 trace("\t\t%s\n", report
);
212 if (Caps
.NumberInputValueCaps
)
216 HIDP_VALUE_CAPS
*values
= NULL
;
218 values
= HeapAlloc(GetProcessHeap(), 0, sizeof(HIDP_VALUE_CAPS
) * Caps
.NumberInputValueCaps
);
219 length
= Caps
.NumberInputValueCaps
;
220 status
= HidP_GetValueCaps(HidP_Input
, values
, &length
, ppd
);
221 ok(status
== HIDP_STATUS_SUCCESS
, "Failed to get value caps (%x)\n",status
);
223 trace("\tValues:\n");
224 for (i
= 0; i
< length
; i
++)
226 status
= HidP_GetUsageValue(HidP_Input
, values
[i
].UsagePage
, 0,
227 values
[i
].Range
.UsageMin
, &value
, ppd
, data
, data_length
);
228 ok(status
== HIDP_STATUS_SUCCESS
, "Failed to get value [%i,%i] (%x)\n",
229 values
[i
].UsagePage
, values
[i
].Range
.UsageMin
, status
);
230 trace("[%02x, %02x]: %u\n",values
[i
].UsagePage
, values
[i
].Range
.UsageMin
, value
);
233 HeapFree(GetProcessHeap(), 0, values
);
237 static void test_read_device(void)
239 PHIDP_PREPARSED_DATA ppd
;
241 OVERLAPPED overlapped
;
242 WCHAR device_name
[128];
247 DWORD timeout
, tick
, spent
, max_time
;
250 USAGE device_usages
[] = {HID_USAGE_GENERIC_JOYSTICK
, HID_USAGE_GENERIC_GAMEPAD
};
251 HANDLE device
= get_device(HID_USAGE_PAGE_GENERIC
, device_usages
, 2, GENERIC_READ
);
254 device
= get_device(0x0, NULL
, 0x0, GENERIC_READ
);
258 trace("No device found for reading\n");
261 rc
= HidD_GetProductString(device
, device_name
, sizeof(device_name
));
262 ok(rc
, "Failed to get product string(0x%x)\n", GetLastError());
263 trace("Read tests on device :%s\n",wine_dbgstr_w(device_name
));
265 rc
= HidD_GetPreparsedData(device
, &ppd
);
266 ok(rc
, "Failed to get preparsed data(0x%x)\n", GetLastError());
267 status
= HidP_GetCaps(ppd
, &Caps
);
268 ok(status
== HIDP_STATUS_SUCCESS
, "Failed to get Caps(0x%x)\n", status
);
269 data
= HeapAlloc(GetProcessHeap(), 0, Caps
.InputReportByteLength
);
271 memset(&overlapped
, 0, sizeof(overlapped
));
272 overlapped
.hEvent
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
273 if (winetest_interactive
)
275 max_time
= READ_MAX_TIME
;
279 max_time
= timeout
= 100;
280 if (winetest_interactive
)
281 trace("Test your device for the next %i seconds\n", max_time
/1000);
282 report
= HeapAlloc(GetProcessHeap(), 0, 3 * Caps
.InputReportByteLength
);
283 tick
= GetTickCount();
287 ReadFile(device
, data
, Caps
.InputReportByteLength
, NULL
, &overlapped
);
288 if (WaitForSingleObject(overlapped
.hEvent
, timeout
) != WAIT_OBJECT_0
)
290 ResetEvent(overlapped
.hEvent
);
291 spent
= GetTickCount() - tick
;
292 trace("REMAINING: %d ms\n", max_time
- spent
);
295 ResetEvent(overlapped
.hEvent
);
296 spent
= GetTickCount() - tick
;
297 GetOverlappedResult(device
, &overlapped
, &read
, FALSE
);
303 for (i
= 0; i
< read
&& i
< Caps
.InputReportByteLength
; i
++)
306 sprintf(bytestr
, "%x ", (BYTE
)data
[i
]);
307 strcat(report
, bytestr
);
309 trace("Input report (%i): %s\n", read
, report
);
311 process_data(Caps
, ppd
, data
, read
);
313 trace("REMAINING: %d ms\n", max_time
- spent
);
314 } while(spent
< max_time
);
316 CloseHandle(overlapped
.hEvent
);
317 rc
= HidD_FreePreparsedData(ppd
);
318 ok(rc
, "Failed to free preparsed data(0x%x)\n", GetLastError());
320 HeapFree(GetProcessHeap(), 0, data
);
321 HeapFree(GetProcessHeap(), 0, report
);
324 static void test_get_input_report(void)
326 PHIDP_PREPARSED_DATA ppd
;
328 WCHAR device_name
[128];
330 DWORD tick
, spent
, max_time
;
335 USAGE device_usages
[] = {HID_USAGE_GENERIC_JOYSTICK
, HID_USAGE_GENERIC_GAMEPAD
};
336 HANDLE device
= get_device(HID_USAGE_PAGE_GENERIC
, device_usages
, 2, GENERIC_READ
);
339 device
= get_device(0x0, NULL
, 0x0, GENERIC_READ
);
343 trace("No device found for testing\n");
346 rc
= HidD_GetProductString(device
, device_name
, sizeof(device_name
));
347 ok(rc
, "Failed to get product string(0x%x)\n", GetLastError());
348 trace("HidD_GetInputRpeort tests on device :%s\n",wine_dbgstr_w(device_name
));
350 rc
= HidD_GetPreparsedData(device
, &ppd
);
351 ok(rc
, "Failed to get preparsed data(0x%x)\n", GetLastError());
352 status
= HidP_GetCaps(ppd
, &Caps
);
353 ok(status
== HIDP_STATUS_SUCCESS
, "Failed to get Caps(0x%x)\n", status
);
354 data
= HeapAlloc(GetProcessHeap(), 0, Caps
.InputReportByteLength
);
356 if (winetest_interactive
)
357 max_time
= READ_MAX_TIME
;
360 if (winetest_interactive
)
361 trace("Test your device for the next %i seconds\n", max_time
/1000);
362 report
= HeapAlloc(GetProcessHeap(), 0, 3 * Caps
.InputReportByteLength
);
363 tick
= GetTickCount();
369 data
[0] = 0; /* Just testing report ID 0 for now, That will catch most devices */
370 rc
= HidD_GetInputReport(device
, data
, Caps
.InputReportByteLength
);
371 spent
= GetTickCount() - tick
;
375 ok(data
[0] == 0, "Report ID (0) is not the first byte of the data\n");
377 for (i
= 0; i
< Caps
.InputReportByteLength
; i
++)
380 sprintf(bytestr
, "%x ", (BYTE
)data
[i
]);
381 strcat(report
, bytestr
);
383 trace("Input report (%i): %s\n", Caps
.InputReportByteLength
, report
);
385 process_data(Caps
, ppd
, data
, Caps
.InputReportByteLength
);
388 trace("Failed to get Input Report, (%x)\n", rc
);
389 trace("REMAINING: %d ms\n", max_time
- spent
);
391 } while(spent
< max_time
);
393 rc
= HidD_FreePreparsedData(ppd
);
394 ok(rc
, "Failed to free preparsed data(0x%x)\n", GetLastError());
396 HeapFree(GetProcessHeap(), 0, data
);
397 HeapFree(GetProcessHeap(), 0, report
);
402 run_for_each_device(test_device_info
);
404 test_get_input_report();