Reactos

[HID_WINETEST] Import from Wine Staging 3.3. CORE-14434

+409 -2
+2 -2
dll/win32/hid/CMakeLists.txt
··· 1 + 2 + spec2def(hid.dll hid.spec ADD_IMPORTLIB) 1 3 2 4 list(APPEND SOURCE 3 5 hid.c 4 6 stubs.c 5 7 precomp.h) 6 - 7 - spec2def(hid.dll hid.spec) 8 8 9 9 add_library(hid SHARED 10 10 ${SOURCE}
+1
modules/rostests/winetests/CMakeLists.txt
··· 30 30 add_subdirectory(fusion) 31 31 add_subdirectory(gdi32) 32 32 add_subdirectory(gdiplus) 33 + add_subdirectory(hid) 33 34 add_subdirectory(hlink) 34 35 add_subdirectory(hnetcfg) 35 36 add_subdirectory(imagehlp)
+5
modules/rostests/winetests/hid/CMakeLists.txt
··· 1 + 2 + add_executable(hid_winetest device.c testlist.c) 3 + set_module_type(hid_winetest win32cui) 4 + add_importlibs(hid_winetest hid setupapi msvcrt kernel32) 5 + add_rostests_file(TARGET hid_winetest)
+389
modules/rostests/winetests/hid/device.c
··· 1 + /* 2 + * Copyright (c) 2017 Aric Stewart 3 + * 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. 8 + * 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. 13 + * 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 17 + */ 18 + 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" 26 + 27 + #include "wine/test.h" 28 + 29 + #define READ_MAX_TIME 5000 30 + 31 + typedef void (device_test)(HANDLE device); 32 + 33 + static void test_device_info(HANDLE device) 34 + { 35 + PHIDP_PREPARSED_DATA ppd; 36 + HIDP_CAPS Caps; 37 + NTSTATUS status; 38 + BOOL rc; 39 + WCHAR device_name[128]; 40 + 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()); 50 + } 51 + 52 + static void run_for_each_device(device_test *test) 53 + { 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; 60 + 61 + HidD_GetHidGuid(&hid_guid); 62 + 63 + ZeroMemory(&interface_data, sizeof(interface_data)); 64 + interface_data.cbSize = sizeof(interface_data); 65 + 66 + data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data) + detail_size); 67 + data->cbSize = sizeof(*data); 68 + 69 + info_set = SetupDiGetClassDevsW(&hid_guid, NULL, NULL, DIGCF_DEVICEINTERFACE); 70 + while (SetupDiEnumDeviceInterfaces(info_set, NULL, &hid_guid, index, &interface_data)) 71 + { 72 + index ++; 73 + 74 + if (SetupDiGetDeviceInterfaceDetailW(info_set, &interface_data, data, sizeof(*data) + detail_size, NULL, NULL)) 75 + { 76 + HANDLE file = CreateFileW(data->DevicePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); 77 + if (file == INVALID_HANDLE_VALUE) 78 + { 79 + trace("Failed to access device %s, likely not plugged in or access is denied.\n", wine_dbgstr_w(data->DevicePath)); 80 + continue; 81 + } 82 + 83 + test(file); 84 + 85 + CloseHandle(file); 86 + } 87 + } 88 + HeapFree(GetProcessHeap(), 0, data); 89 + SetupDiDestroyDeviceInfoList(info_set); 90 + } 91 + 92 + static HANDLE get_device(USHORT page, USHORT usages[], UINT usage_count, DWORD access) 93 + { 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; 102 + 103 + HidD_GetHidGuid(&hid_guid); 104 + 105 + ZeroMemory(&interface_data, sizeof(interface_data)); 106 + interface_data.cbSize = sizeof(interface_data); 107 + 108 + data = HeapAlloc(GetProcessHeap(), 0 , sizeof(*data) + detail_size); 109 + data->cbSize = sizeof(*data); 110 + 111 + info_set = SetupDiGetClassDevsW(&hid_guid, NULL, NULL, DIGCF_DEVICEINTERFACE); 112 + while (SetupDiEnumDeviceInterfaces(info_set, NULL, &hid_guid, index, &interface_data)) 113 + { 114 + index ++; 115 + 116 + if (SetupDiGetDeviceInterfaceDetailW(info_set, &interface_data, data, sizeof(*data) + detail_size, NULL, NULL)) 117 + { 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) 122 + { 123 + trace("Failed to access device %s, likely not plugged in or access is denied.\n", wine_dbgstr_w(data->DevicePath)); 124 + continue; 125 + } 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) 133 + { 134 + int j; 135 + if (!usage_count) 136 + { 137 + HeapFree(GetProcessHeap(), 0, data); 138 + SetupDiDestroyDeviceInfoList(info_set); 139 + return file; 140 + } 141 + for (j = 0; j < usage_count; j++) 142 + if (!usages[j] || usages[j] == Caps.Usage) 143 + { 144 + HeapFree(GetProcessHeap(), 0, data); 145 + SetupDiDestroyDeviceInfoList(info_set); 146 + return file; 147 + } 148 + } 149 + CloseHandle(file); 150 + } 151 + } 152 + HeapFree(GetProcessHeap(), 0, data); 153 + SetupDiDestroyDeviceInfoList(info_set); 154 + return NULL; 155 + } 156 + 157 + static void process_data(HIDP_CAPS Caps, PHIDP_PREPARSED_DATA ppd, CHAR *data, DWORD data_length) 158 + { 159 + INT i; 160 + NTSTATUS status; 161 + 162 + if (Caps.NumberInputButtonCaps) 163 + { 164 + USAGE button_pages[100]; 165 + 166 + for (i = 1; i < 0xff; i++) 167 + { 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 || usage_length == 0, 171 + "HidP_GetUsages failed (%x) but usage length still %i\n", status, usage_length); 172 + if (usage_length) 173 + { 174 + CHAR report[50]; 175 + int count; 176 + int j; 177 + 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) 183 + { 184 + for (j=count; j < count+15 && j < usage_length; j++) 185 + { 186 + CHAR btn[7]; 187 + sprintf(btn, "%i ", button_pages[j]); 188 + strcat(report, btn); 189 + } 190 + trace("\t\t%s\n", report); 191 + } 192 + } 193 + } 194 + } 195 + 196 + if (Caps.NumberInputValueCaps) 197 + { 198 + ULONG value; 199 + USHORT length; 200 + HIDP_VALUE_CAPS *values = NULL; 201 + 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); 206 + 207 + trace("\tValues:\n"); 208 + for (i = 0; i < length; i++) 209 + { 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); 215 + } 216 + 217 + HeapFree(GetProcessHeap(), 0, values); 218 + } 219 + } 220 + 221 + static void test_read_device(void) 222 + { 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; 233 + 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); 236 + 237 + if (!device) 238 + device = get_device(0x0, NULL, 0x0, GENERIC_READ); 239 + 240 + if (!device) 241 + { 242 + trace("No device found for reading\n"); 243 + return; 244 + } 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)); 248 + 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); 254 + 255 + memset(&overlapped, 0, sizeof(overlapped)); 256 + overlapped.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL); 257 + if (winetest_interactive) 258 + { 259 + max_time = READ_MAX_TIME; 260 + timeout = 1000; 261 + } 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; 269 + do 270 + { 271 + ReadFile(device, data, Caps.InputReportByteLength, NULL, &overlapped); 272 + if (WaitForSingleObject(overlapped.hEvent, timeout) != WAIT_OBJECT_0) 273 + { 274 + ResetEvent(overlapped.hEvent); 275 + spent = GetTickCount() - tick; 276 + trace("REMAINING: %d ms\n", max_time - spent); 277 + continue; 278 + } 279 + ResetEvent(overlapped.hEvent); 280 + spent = GetTickCount() - tick; 281 + GetOverlappedResult(device, &overlapped, &read, FALSE); 282 + if (read) 283 + { 284 + int i; 285 + 286 + report[0] = 0; 287 + for (i = 0; i < read && i < Caps.InputReportByteLength; i++) 288 + { 289 + char bytestr[5]; 290 + sprintf(bytestr, "%x ", (BYTE)data[i]); 291 + strcat(report, bytestr); 292 + } 293 + trace("Input report (%i): %s\n", read, report); 294 + 295 + process_data(Caps, ppd, data, read); 296 + } 297 + trace("REMAINING: %d ms\n", max_time - spent); 298 + } while(spent < max_time); 299 + 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); 306 + } 307 + 308 + static void test_get_input_report(void) 309 + { 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; 318 + 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); 321 + 322 + if (!device) 323 + device = get_device(0x0, NULL, 0x0, GENERIC_READ); 324 + 325 + if (!device) 326 + { 327 + trace("No device found for testing\n"); 328 + return; 329 + } 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)); 333 + 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); 339 + 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; 349 + do 350 + { 351 + int i; 352 + 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; 356 + 357 + if (rc) 358 + { 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++) 362 + { 363 + char bytestr[5]; 364 + sprintf(bytestr, "%x ", (BYTE)data[i]); 365 + strcat(report, bytestr); 366 + } 367 + trace("Input report (%i): %s\n", Caps.InputReportByteLength, report); 368 + 369 + process_data(Caps, ppd, data, Caps.InputReportByteLength); 370 + } 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); 376 + 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); 382 + } 383 + 384 + START_TEST(device) 385 + { 386 + run_for_each_device(test_device_info); 387 + test_read_device(); 388 + test_get_input_report(); 389 + }
+12
modules/rostests/winetests/hid/testlist.c
··· 1 + /* Automatically generated file; DO NOT EDIT!! */ 2 + 3 + #define STANDALONE 4 + #include <wine/test.h> 5 + 6 + extern void func_device(void); 7 + 8 + const struct test winetest_testlist[] = 9 + { 10 + { "device", func_device }, 11 + { 0, 0 } 12 + };