po: Updated Polish translation.
[wine.git] / dlls / hid / tests / device.c
bloba4c12ce1febd92ad009cdbcb86c83573e640e90d
1 /*
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
19 #include <stdio.h>
20 #include "ntstatus.h"
21 #define WIN32_NO_STATUS
22 #include "windows.h"
23 #include "setupapi.h"
24 #include "hidusage.h"
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;
36 HIDP_CAPS Caps;
37 NTSTATUS status;
38 BOOL rc;
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)
54 GUID hid_guid;
55 HDEVINFO info_set;
56 DWORD index = 0;
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))
72 index ++;
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));
80 continue;
83 test(file);
85 CloseHandle(file);
88 HeapFree(GetProcessHeap(), 0, data);
89 SetupDiDestroyDeviceInfoList(info_set);
92 static HANDLE get_device(USHORT page, USHORT usages[], UINT usage_count, DWORD access)
94 GUID hid_guid;
95 HDEVINFO info_set;
96 DWORD index = 0;
97 SP_DEVICE_INTERFACE_DATA interface_data;
98 DWORD detail_size = MAX_PATH * sizeof(WCHAR);
99 SP_DEVICE_INTERFACE_DETAIL_DATA_W *data;
100 NTSTATUS status;
101 BOOL rc;
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))
114 index ++;
116 if (SetupDiGetDeviceInterfaceDetailW(info_set, &interface_data, data, sizeof(*data) + detail_size, NULL, NULL))
118 PHIDP_PREPARSED_DATA ppd;
119 HIDP_CAPS Caps;
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));
124 continue;
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)
134 int j;
135 if (!usage_count)
137 HeapFree(GetProcessHeap(), 0, data);
138 SetupDiDestroyDeviceInfoList(info_set);
139 return file;
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);
146 return file;
149 CloseHandle(file);
152 HeapFree(GetProcessHeap(), 0, data);
153 SetupDiDestroyDeviceInfoList(info_set);
154 return NULL;
157 static void process_data(HIDP_CAPS Caps, PHIDP_PREPARSED_DATA ppd, CHAR *data, DWORD data_length)
159 INT i;
160 NTSTATUS status;
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);
172 if (usage_length)
174 CHAR report[50];
175 int count;
176 int j;
178 count = usage_length;
179 j = 0;
180 report[0] = 0;
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++)
186 CHAR btn[5];
187 sprintf(btn, "%i ", button_pages[j]);
188 strcat(report, btn);
190 trace("\t\t%s\n", report);
196 if (Caps.NumberInputValueCaps)
198 ULONG value;
199 USHORT length;
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;
224 HIDP_CAPS Caps;
225 OVERLAPPED overlapped;
226 WCHAR device_name[128];
227 CHAR *data = NULL;
228 DWORD read;
229 BOOL rc;
230 NTSTATUS status;
231 DWORD timeout, tick, spent, max_time;
232 char *report;
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);
237 if (!device)
238 device = get_device(0x0, NULL, 0x0, GENERIC_READ);
240 if (!device)
242 trace("No device found for reading\n");
243 return;
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;
260 timeout = 1000;
262 else
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();
268 spent = 0;
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);
277 continue;
279 ResetEvent(overlapped.hEvent);
280 spent = GetTickCount() - tick;
281 GetOverlappedResult(device, &overlapped, &read, FALSE);
282 if (read)
284 int i;
286 report[0] = 0;
287 for (i = 0; i < read && i < Caps.InputReportByteLength; i++)
289 char bytestr[5];
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());
303 CloseHandle(device);
304 HeapFree(GetProcessHeap(), 0, data);
305 HeapFree(GetProcessHeap(), 0, report);
308 static void test_get_input_report(void)
310 PHIDP_PREPARSED_DATA ppd;
311 HIDP_CAPS Caps;
312 WCHAR device_name[128];
313 CHAR *data = NULL;
314 DWORD tick, spent, max_time;
315 char *report;
316 BOOL rc;
317 NTSTATUS status;
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);
322 if (!device)
323 device = get_device(0x0, NULL, 0x0, GENERIC_READ);
325 if (!device)
327 trace("No device found for testing\n");
328 return;
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;
342 else
343 max_time = 100;
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();
348 spent = 0;
351 int i;
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;
357 if (rc)
359 ok(data[0] == 0, "Report ID (0) is not the first byte of the data\n");
360 report[0] = 0;
361 for (i = 0; i < Caps.InputReportByteLength; i++)
363 char bytestr[5];
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);
371 else
372 trace("Failed to get Input Report, (%x)\n", rc);
373 trace("REMAINING: %d ms\n", max_time - spent);
374 Sleep(500);
375 } while(spent < max_time);
377 rc = HidD_FreePreparsedData(ppd);
378 ok(rc, "Failed to free preparsed data(0x%x)\n", GetLastError());
379 CloseHandle(device);
380 HeapFree(GetProcessHeap(), 0, data);
381 HeapFree(GetProcessHeap(), 0, report);
384 START_TEST(device)
386 run_for_each_device(test_device_info);
387 test_read_device();
388 test_get_input_report();