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
;
39 WCHAR device_name
[128];
41 rc
= HidD_GetPreparsedData(device
, &ppd
);
42 ok(rc
, "Failed to get preparsed data(0x%x)\n", GetLastError());
43 status
= HidP_GetCaps(ppd
, &Caps
);
44 ok(status
== HIDP_STATUS_SUCCESS
, "Failed to get Caps(0x%x)\n", status
);
45 rc
= HidD_GetProductString(device
, device_name
, sizeof(device_name
));
46 ok(rc
, "Failed to get product string(0x%x)\n", GetLastError());
47 trace("Found device %s (%02x, %02x)\n", wine_dbgstr_w(device_name
), Caps
.UsagePage
, Caps
.Usage
);
48 rc
= HidD_FreePreparsedData(ppd
);
49 ok(rc
, "Failed to free preparsed data(0x%x)\n", GetLastError());
52 static void run_for_each_device(device_test
*test
)
57 SP_DEVICE_INTERFACE_DATA interface_data
;
58 DWORD detail_size
= MAX_PATH
* sizeof(WCHAR
);
59 SP_DEVICE_INTERFACE_DETAIL_DATA_W
*data
;
61 HidD_GetHidGuid(&hid_guid
);
63 ZeroMemory(&interface_data
, sizeof(interface_data
));
64 interface_data
.cbSize
= sizeof(interface_data
);
66 data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*data
) + detail_size
);
67 data
->cbSize
= sizeof(*data
);
69 info_set
= SetupDiGetClassDevsW(&hid_guid
, NULL
, NULL
, DIGCF_DEVICEINTERFACE
);
70 while (SetupDiEnumDeviceInterfaces(info_set
, NULL
, &hid_guid
, index
, &interface_data
))
74 if (SetupDiGetDeviceInterfaceDetailW(info_set
, &interface_data
, data
, sizeof(*data
) + detail_size
, NULL
, NULL
))
76 HANDLE file
= CreateFileW(data
->DevicePath
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0);
77 if (file
== INVALID_HANDLE_VALUE
)
79 trace("Failed to access device %s, likely not plugged in or access is denied.\n", wine_dbgstr_w(data
->DevicePath
));
88 HeapFree(GetProcessHeap(), 0, data
);
89 SetupDiDestroyDeviceInfoList(info_set
);
92 static HANDLE
get_device(USHORT page
, USHORT usages
[], UINT usage_count
, DWORD access
)
97 SP_DEVICE_INTERFACE_DATA interface_data
;
98 DWORD detail_size
= MAX_PATH
* sizeof(WCHAR
);
99 SP_DEVICE_INTERFACE_DETAIL_DATA_W
*data
;
103 HidD_GetHidGuid(&hid_guid
);
105 ZeroMemory(&interface_data
, sizeof(interface_data
));
106 interface_data
.cbSize
= sizeof(interface_data
);
108 data
= HeapAlloc(GetProcessHeap(), 0 , sizeof(*data
) + detail_size
);
109 data
->cbSize
= sizeof(*data
);
111 info_set
= SetupDiGetClassDevsW(&hid_guid
, NULL
, NULL
, DIGCF_DEVICEINTERFACE
);
112 while (SetupDiEnumDeviceInterfaces(info_set
, NULL
, &hid_guid
, index
, &interface_data
))
116 if (SetupDiGetDeviceInterfaceDetailW(info_set
, &interface_data
, data
, sizeof(*data
) + detail_size
, NULL
, NULL
))
118 PHIDP_PREPARSED_DATA ppd
;
120 HANDLE file
= CreateFileW(data
->DevicePath
, access
, FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
121 if (file
== INVALID_HANDLE_VALUE
)
123 trace("Failed to access device %s, likely not plugged in or access is denied.\n", wine_dbgstr_w(data
->DevicePath
));
126 rc
= HidD_GetPreparsedData(file
, &ppd
);
127 ok(rc
, "Failed to get preparsed data(0x%x)\n", GetLastError());
128 status
= HidP_GetCaps(ppd
, &Caps
);
129 ok(status
== HIDP_STATUS_SUCCESS
, "Failed to get Caps(0x%x)\n", status
);
130 rc
= HidD_FreePreparsedData(ppd
);
131 ok(rc
, "Failed to free preparsed data(0x%x)\n", GetLastError());
132 if (!page
|| page
== Caps
.UsagePage
)
137 HeapFree(GetProcessHeap(), 0, data
);
138 SetupDiDestroyDeviceInfoList(info_set
);
141 for (j
= 0; j
< usage_count
; j
++)
142 if (!usages
[j
] || usages
[j
] == Caps
.Usage
)
144 HeapFree(GetProcessHeap(), 0, data
);
145 SetupDiDestroyDeviceInfoList(info_set
);
152 HeapFree(GetProcessHeap(), 0, data
);
153 SetupDiDestroyDeviceInfoList(info_set
);
157 static void process_data(HIDP_CAPS Caps
, PHIDP_PREPARSED_DATA ppd
, CHAR
*data
, DWORD data_length
)
162 if (Caps
.NumberInputButtonCaps
)
164 USAGE button_pages
[100];
166 for (i
= 1; i
< 0xff; i
++)
168 ULONG usage_length
= 100;
169 status
= HidP_GetUsages(HidP_Input
, i
, 0, button_pages
, &usage_length
, ppd
, data
, data_length
);
170 ok (status
== HIDP_STATUS_SUCCESS
|| (status
!= HIDP_STATUS_SUCCESS
&& usage_length
== 0),
171 "HidP_GetUsages failed (%x) but usage length still %i\n", status
, usage_length
);
178 count
= usage_length
;
181 trace("\tButtons [0x%x: %i buttons]:\n", i
, usage_length
);
182 for (count
= 0; count
< usage_length
; count
+= 15)
184 for (j
=count
; j
< count
+15 && j
< usage_length
; j
++)
187 sprintf(btn
, "%i ", button_pages
[j
]);
190 trace("\t\t%s\n", report
);
196 if (Caps
.NumberInputValueCaps
)
200 HIDP_VALUE_CAPS
*values
= NULL
;
202 values
= HeapAlloc(GetProcessHeap(), 0, sizeof(HIDP_VALUE_CAPS
) * Caps
.NumberInputValueCaps
);
203 length
= Caps
.NumberInputValueCaps
;
204 status
= HidP_GetValueCaps(HidP_Input
, values
, &length
, ppd
);
205 ok(status
== HIDP_STATUS_SUCCESS
, "Failed to get value caps (%x)\n",status
);
207 trace("\tValues:\n");
208 for (i
= 0; i
< length
; i
++)
210 status
= HidP_GetUsageValue(HidP_Input
, values
[i
].UsagePage
, 0,
211 values
[i
].Range
.UsageMin
, &value
, ppd
, data
, data_length
);
212 ok(status
== HIDP_STATUS_SUCCESS
, "Failed to get value [%i,%i] (%x)\n",
213 values
[i
].UsagePage
, values
[i
].Range
.UsageMin
, status
);
214 trace("[%02x, %02x]: %u\n",values
[i
].UsagePage
, values
[i
].Range
.UsageMin
, value
);
217 HeapFree(GetProcessHeap(), 0, values
);
221 static void test_read_device(void)
223 PHIDP_PREPARSED_DATA ppd
;
225 OVERLAPPED overlapped
;
226 WCHAR device_name
[128];
231 DWORD timeout
, tick
, spent
, max_time
;
234 USAGE device_usages
[] = {HID_USAGE_GENERIC_JOYSTICK
, HID_USAGE_GENERIC_GAMEPAD
};
235 HANDLE device
= get_device(HID_USAGE_PAGE_GENERIC
, device_usages
, 2, GENERIC_READ
);
238 device
= get_device(0x0, NULL
, 0x0, GENERIC_READ
);
242 trace("No device found for reading\n");
245 rc
= HidD_GetProductString(device
, device_name
, sizeof(device_name
));
246 ok(rc
, "Failed to get product string(0x%x)\n", GetLastError());
247 trace("Read tests on device :%s\n",wine_dbgstr_w(device_name
));
249 rc
= HidD_GetPreparsedData(device
, &ppd
);
250 ok(rc
, "Failed to get preparsed data(0x%x)\n", GetLastError());
251 status
= HidP_GetCaps(ppd
, &Caps
);
252 ok(status
== HIDP_STATUS_SUCCESS
, "Failed to get Caps(0x%x)\n", status
);
253 data
= HeapAlloc(GetProcessHeap(), 0, Caps
.InputReportByteLength
);
255 memset(&overlapped
, 0, sizeof(overlapped
));
256 overlapped
.hEvent
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
257 if (winetest_interactive
)
259 max_time
= READ_MAX_TIME
;
263 max_time
= timeout
= 100;
264 if (winetest_interactive
)
265 trace("Test your device for the next %i seconds\n", max_time
/1000);
266 report
= HeapAlloc(GetProcessHeap(), 0, 3 * Caps
.InputReportByteLength
);
267 tick
= GetTickCount();
271 ReadFile(device
, data
, Caps
.InputReportByteLength
, NULL
, &overlapped
);
272 if (WaitForSingleObject(overlapped
.hEvent
, timeout
) != WAIT_OBJECT_0
)
274 ResetEvent(overlapped
.hEvent
);
275 spent
= GetTickCount() - tick
;
276 trace("REMAINING: %d ms\n", max_time
- spent
);
279 ResetEvent(overlapped
.hEvent
);
280 spent
= GetTickCount() - tick
;
281 GetOverlappedResult(device
, &overlapped
, &read
, FALSE
);
287 for (i
= 0; i
< read
&& i
< Caps
.InputReportByteLength
; i
++)
290 sprintf(bytestr
, "%x ", (BYTE
)data
[i
]);
291 strcat(report
, bytestr
);
293 trace("Input report (%i): %s\n", read
, report
);
295 process_data(Caps
, ppd
, data
, read
);
297 trace("REMAINING: %d ms\n", max_time
- spent
);
298 } while(spent
< max_time
);
300 CloseHandle(overlapped
.hEvent
);
301 rc
= HidD_FreePreparsedData(ppd
);
302 ok(rc
, "Failed to free preparsed data(0x%x)\n", GetLastError());
304 HeapFree(GetProcessHeap(), 0, data
);
305 HeapFree(GetProcessHeap(), 0, report
);
308 static void test_get_input_report(void)
310 PHIDP_PREPARSED_DATA ppd
;
312 WCHAR device_name
[128];
314 DWORD tick
, spent
, max_time
;
319 USAGE device_usages
[] = {HID_USAGE_GENERIC_JOYSTICK
, HID_USAGE_GENERIC_GAMEPAD
};
320 HANDLE device
= get_device(HID_USAGE_PAGE_GENERIC
, device_usages
, 2, GENERIC_READ
);
323 device
= get_device(0x0, NULL
, 0x0, GENERIC_READ
);
327 trace("No device found for testing\n");
330 rc
= HidD_GetProductString(device
, device_name
, sizeof(device_name
));
331 ok(rc
, "Failed to get product string(0x%x)\n", GetLastError());
332 trace("HidD_GetInputRpeort tests on device :%s\n",wine_dbgstr_w(device_name
));
334 rc
= HidD_GetPreparsedData(device
, &ppd
);
335 ok(rc
, "Failed to get preparsed data(0x%x)\n", GetLastError());
336 status
= HidP_GetCaps(ppd
, &Caps
);
337 ok(status
== HIDP_STATUS_SUCCESS
, "Failed to get Caps(0x%x)\n", status
);
338 data
= HeapAlloc(GetProcessHeap(), 0, Caps
.InputReportByteLength
);
340 if (winetest_interactive
)
341 max_time
= READ_MAX_TIME
;
344 if (winetest_interactive
)
345 trace("Test your device for the next %i seconds\n", max_time
/1000);
346 report
= HeapAlloc(GetProcessHeap(), 0, 3 * Caps
.InputReportByteLength
);
347 tick
= GetTickCount();
353 data
[0] = 0; /* Just testing report ID 0 for now, That will catch most devices */
354 rc
= HidD_GetInputReport(device
, data
, Caps
.InputReportByteLength
);
355 spent
= GetTickCount() - tick
;
359 ok(data
[0] == 0, "Report ID (0) is not the first byte of the data\n");
361 for (i
= 0; i
< Caps
.InputReportByteLength
; i
++)
364 sprintf(bytestr
, "%x ", (BYTE
)data
[i
]);
365 strcat(report
, bytestr
);
367 trace("Input report (%i): %s\n", Caps
.InputReportByteLength
, report
);
369 process_data(Caps
, ppd
, data
, Caps
.InputReportByteLength
);
372 trace("Failed to get Input Report, (%x)\n", rc
);
373 trace("REMAINING: %d ms\n", max_time
- spent
);
375 } while(spent
< max_time
);
377 rc
= HidD_FreePreparsedData(ppd
);
378 ok(rc
, "Failed to free preparsed data(0x%x)\n", GetLastError());
380 HeapFree(GetProcessHeap(), 0, data
);
381 HeapFree(GetProcessHeap(), 0, report
);
386 run_for_each_device(test_device_info
);
388 test_get_input_report();