mirror of
https://github.com/reactos/reactos.git
synced 2024-12-22 10:33:30 +08:00
[HID_WINETEST] Import from Wine Staging 3.3. CORE-14434
This commit is contained in:
parent
4049e52e79
commit
845faec403
@ -1,11 +1,11 @@
|
||||
|
||||
spec2def(hid.dll hid.spec ADD_IMPORTLIB)
|
||||
|
||||
list(APPEND SOURCE
|
||||
hid.c
|
||||
stubs.c
|
||||
precomp.h)
|
||||
|
||||
spec2def(hid.dll hid.spec)
|
||||
|
||||
add_library(hid SHARED
|
||||
${SOURCE}
|
||||
hid.rc
|
||||
|
@ -30,6 +30,7 @@ add_subdirectory(faultrep)
|
||||
add_subdirectory(fusion)
|
||||
add_subdirectory(gdi32)
|
||||
add_subdirectory(gdiplus)
|
||||
add_subdirectory(hid)
|
||||
add_subdirectory(hlink)
|
||||
add_subdirectory(hnetcfg)
|
||||
add_subdirectory(imagehlp)
|
||||
|
5
modules/rostests/winetests/hid/CMakeLists.txt
Normal file
5
modules/rostests/winetests/hid/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
add_executable(hid_winetest device.c testlist.c)
|
||||
set_module_type(hid_winetest win32cui)
|
||||
add_importlibs(hid_winetest hid setupapi msvcrt kernel32)
|
||||
add_rostests_file(TARGET hid_winetest)
|
389
modules/rostests/winetests/hid/device.c
Normal file
389
modules/rostests/winetests/hid/device.c
Normal file
@ -0,0 +1,389 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Aric Stewart
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "windows.h"
|
||||
#include "setupapi.h"
|
||||
#include "hidusage.h"
|
||||
#include "ddk/hidsdi.h"
|
||||
|
||||
#include "wine/test.h"
|
||||
|
||||
#define READ_MAX_TIME 5000
|
||||
|
||||
typedef void (device_test)(HANDLE device);
|
||||
|
||||
static void test_device_info(HANDLE device)
|
||||
{
|
||||
PHIDP_PREPARSED_DATA ppd;
|
||||
HIDP_CAPS Caps;
|
||||
NTSTATUS status;
|
||||
BOOL rc;
|
||||
WCHAR device_name[128];
|
||||
|
||||
rc = HidD_GetPreparsedData(device, &ppd);
|
||||
ok(rc, "Failed to get preparsed data(0x%x)\n", GetLastError());
|
||||
status = HidP_GetCaps(ppd, &Caps);
|
||||
ok(status == HIDP_STATUS_SUCCESS, "Failed to get Caps(0x%x)\n", status);
|
||||
rc = HidD_GetProductString(device, device_name, sizeof(device_name));
|
||||
ok(rc, "Failed to get product string(0x%x)\n", GetLastError());
|
||||
trace("Found device %s (%02x, %02x)\n", wine_dbgstr_w(device_name), Caps.UsagePage, Caps.Usage);
|
||||
rc = HidD_FreePreparsedData(ppd);
|
||||
ok(rc, "Failed to free preparsed data(0x%x)\n", GetLastError());
|
||||
}
|
||||
|
||||
static void run_for_each_device(device_test *test)
|
||||
{
|
||||
GUID hid_guid;
|
||||
HDEVINFO info_set;
|
||||
DWORD index = 0;
|
||||
SP_DEVICE_INTERFACE_DATA interface_data;
|
||||
DWORD detail_size = MAX_PATH * sizeof(WCHAR);
|
||||
SP_DEVICE_INTERFACE_DETAIL_DATA_W *data;
|
||||
|
||||
HidD_GetHidGuid(&hid_guid);
|
||||
|
||||
ZeroMemory(&interface_data, sizeof(interface_data));
|
||||
interface_data.cbSize = sizeof(interface_data);
|
||||
|
||||
data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data) + detail_size);
|
||||
data->cbSize = sizeof(*data);
|
||||
|
||||
info_set = SetupDiGetClassDevsW(&hid_guid, NULL, NULL, DIGCF_DEVICEINTERFACE);
|
||||
while (SetupDiEnumDeviceInterfaces(info_set, NULL, &hid_guid, index, &interface_data))
|
||||
{
|
||||
index ++;
|
||||
|
||||
if (SetupDiGetDeviceInterfaceDetailW(info_set, &interface_data, data, sizeof(*data) + detail_size, NULL, NULL))
|
||||
{
|
||||
HANDLE file = CreateFileW(data->DevicePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
|
||||
if (file == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
trace("Failed to access device %s, likely not plugged in or access is denied.\n", wine_dbgstr_w(data->DevicePath));
|
||||
continue;
|
||||
}
|
||||
|
||||
test(file);
|
||||
|
||||
CloseHandle(file);
|
||||
}
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, data);
|
||||
SetupDiDestroyDeviceInfoList(info_set);
|
||||
}
|
||||
|
||||
static HANDLE get_device(USHORT page, USHORT usages[], UINT usage_count, DWORD access)
|
||||
{
|
||||
GUID hid_guid;
|
||||
HDEVINFO info_set;
|
||||
DWORD index = 0;
|
||||
SP_DEVICE_INTERFACE_DATA interface_data;
|
||||
DWORD detail_size = MAX_PATH * sizeof(WCHAR);
|
||||
SP_DEVICE_INTERFACE_DETAIL_DATA_W *data;
|
||||
NTSTATUS status;
|
||||
BOOL rc;
|
||||
|
||||
HidD_GetHidGuid(&hid_guid);
|
||||
|
||||
ZeroMemory(&interface_data, sizeof(interface_data));
|
||||
interface_data.cbSize = sizeof(interface_data);
|
||||
|
||||
data = HeapAlloc(GetProcessHeap(), 0 , sizeof(*data) + detail_size);
|
||||
data->cbSize = sizeof(*data);
|
||||
|
||||
info_set = SetupDiGetClassDevsW(&hid_guid, NULL, NULL, DIGCF_DEVICEINTERFACE);
|
||||
while (SetupDiEnumDeviceInterfaces(info_set, NULL, &hid_guid, index, &interface_data))
|
||||
{
|
||||
index ++;
|
||||
|
||||
if (SetupDiGetDeviceInterfaceDetailW(info_set, &interface_data, data, sizeof(*data) + detail_size, NULL, NULL))
|
||||
{
|
||||
PHIDP_PREPARSED_DATA ppd;
|
||||
HIDP_CAPS Caps;
|
||||
HANDLE file = CreateFileW(data->DevicePath, access, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
|
||||
if (file == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
trace("Failed to access device %s, likely not plugged in or access is denied.\n", wine_dbgstr_w(data->DevicePath));
|
||||
continue;
|
||||
}
|
||||
rc = HidD_GetPreparsedData(file, &ppd);
|
||||
ok(rc, "Failed to get preparsed data(0x%x)\n", GetLastError());
|
||||
status = HidP_GetCaps(ppd, &Caps);
|
||||
ok(status == HIDP_STATUS_SUCCESS, "Failed to get Caps(0x%x)\n", status);
|
||||
rc = HidD_FreePreparsedData(ppd);
|
||||
ok(rc, "Failed to free preparsed data(0x%x)\n", GetLastError());
|
||||
if (!page || page == Caps.UsagePage)
|
||||
{
|
||||
int j;
|
||||
if (!usage_count)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, data);
|
||||
SetupDiDestroyDeviceInfoList(info_set);
|
||||
return file;
|
||||
}
|
||||
for (j = 0; j < usage_count; j++)
|
||||
if (!usages[j] || usages[j] == Caps.Usage)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, data);
|
||||
SetupDiDestroyDeviceInfoList(info_set);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
CloseHandle(file);
|
||||
}
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, data);
|
||||
SetupDiDestroyDeviceInfoList(info_set);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void process_data(HIDP_CAPS Caps, PHIDP_PREPARSED_DATA ppd, CHAR *data, DWORD data_length)
|
||||
{
|
||||
INT i;
|
||||
NTSTATUS status;
|
||||
|
||||
if (Caps.NumberInputButtonCaps)
|
||||
{
|
||||
USAGE button_pages[100];
|
||||
|
||||
for (i = 1; i < 0xff; i++)
|
||||
{
|
||||
ULONG usage_length = 100;
|
||||
status = HidP_GetUsages(HidP_Input, i, 0, button_pages, &usage_length, ppd, data, data_length);
|
||||
ok (status == HIDP_STATUS_SUCCESS || usage_length == 0,
|
||||
"HidP_GetUsages failed (%x) but usage length still %i\n", status, usage_length);
|
||||
if (usage_length)
|
||||
{
|
||||
CHAR report[50];
|
||||
int count;
|
||||
int j;
|
||||
|
||||
count = usage_length;
|
||||
j = 0;
|
||||
report[0] = 0;
|
||||
trace("\tButtons [0x%x: %i buttons]:\n", i, usage_length);
|
||||
for (count = 0; count < usage_length; count += 15)
|
||||
{
|
||||
for (j=count; j < count+15 && j < usage_length; j++)
|
||||
{
|
||||
CHAR btn[7];
|
||||
sprintf(btn, "%i ", button_pages[j]);
|
||||
strcat(report, btn);
|
||||
}
|
||||
trace("\t\t%s\n", report);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Caps.NumberInputValueCaps)
|
||||
{
|
||||
ULONG value;
|
||||
USHORT length;
|
||||
HIDP_VALUE_CAPS *values = NULL;
|
||||
|
||||
values = HeapAlloc(GetProcessHeap(), 0, sizeof(HIDP_VALUE_CAPS) * Caps.NumberInputValueCaps);
|
||||
length = Caps.NumberInputValueCaps;
|
||||
status = HidP_GetValueCaps(HidP_Input, values, &length, ppd);
|
||||
ok(status == HIDP_STATUS_SUCCESS, "Failed to get value caps (%x)\n",status);
|
||||
|
||||
trace("\tValues:\n");
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
status = HidP_GetUsageValue(HidP_Input, values[i].UsagePage, 0,
|
||||
values[i].Range.UsageMin, &value, ppd, data, data_length);
|
||||
ok(status == HIDP_STATUS_SUCCESS, "Failed to get value [%i,%i] (%x)\n",
|
||||
values[i].UsagePage, values[i].Range.UsageMin, status);
|
||||
trace("[%02x, %02x]: %u\n",values[i].UsagePage, values[i].Range.UsageMin, value);
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, values);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_read_device(void)
|
||||
{
|
||||
PHIDP_PREPARSED_DATA ppd;
|
||||
HIDP_CAPS Caps;
|
||||
OVERLAPPED overlapped;
|
||||
WCHAR device_name[128];
|
||||
CHAR *data = NULL;
|
||||
DWORD read;
|
||||
BOOL rc;
|
||||
NTSTATUS status;
|
||||
DWORD timeout, tick, spent, max_time;
|
||||
char *report;
|
||||
|
||||
USAGE device_usages[] = {HID_USAGE_GENERIC_JOYSTICK, HID_USAGE_GENERIC_GAMEPAD};
|
||||
HANDLE device = get_device(HID_USAGE_PAGE_GENERIC, device_usages, 2, GENERIC_READ);
|
||||
|
||||
if (!device)
|
||||
device = get_device(0x0, NULL, 0x0, GENERIC_READ);
|
||||
|
||||
if (!device)
|
||||
{
|
||||
trace("No device found for reading\n");
|
||||
return;
|
||||
}
|
||||
rc = HidD_GetProductString(device, device_name, sizeof(device_name));
|
||||
ok(rc, "Failed to get product string(0x%x)\n", GetLastError());
|
||||
trace("Read tests on device :%s\n",wine_dbgstr_w(device_name));
|
||||
|
||||
rc = HidD_GetPreparsedData(device, &ppd);
|
||||
ok(rc, "Failed to get preparsed data(0x%x)\n", GetLastError());
|
||||
status = HidP_GetCaps(ppd, &Caps);
|
||||
ok(status == HIDP_STATUS_SUCCESS, "Failed to get Caps(0x%x)\n", status);
|
||||
data = HeapAlloc(GetProcessHeap(), 0, Caps.InputReportByteLength);
|
||||
|
||||
memset(&overlapped, 0, sizeof(overlapped));
|
||||
overlapped.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||
if (winetest_interactive)
|
||||
{
|
||||
max_time = READ_MAX_TIME;
|
||||
timeout = 1000;
|
||||
}
|
||||
else
|
||||
max_time = timeout = 100;
|
||||
if (winetest_interactive)
|
||||
trace("Test your device for the next %i seconds\n", max_time/1000);
|
||||
report = HeapAlloc(GetProcessHeap(), 0, 3 * Caps.InputReportByteLength);
|
||||
tick = GetTickCount();
|
||||
spent = 0;
|
||||
do
|
||||
{
|
||||
ReadFile(device, data, Caps.InputReportByteLength, NULL, &overlapped);
|
||||
if (WaitForSingleObject(overlapped.hEvent, timeout) != WAIT_OBJECT_0)
|
||||
{
|
||||
ResetEvent(overlapped.hEvent);
|
||||
spent = GetTickCount() - tick;
|
||||
trace("REMAINING: %d ms\n", max_time - spent);
|
||||
continue;
|
||||
}
|
||||
ResetEvent(overlapped.hEvent);
|
||||
spent = GetTickCount() - tick;
|
||||
GetOverlappedResult(device, &overlapped, &read, FALSE);
|
||||
if (read)
|
||||
{
|
||||
int i;
|
||||
|
||||
report[0] = 0;
|
||||
for (i = 0; i < read && i < Caps.InputReportByteLength; i++)
|
||||
{
|
||||
char bytestr[5];
|
||||
sprintf(bytestr, "%x ", (BYTE)data[i]);
|
||||
strcat(report, bytestr);
|
||||
}
|
||||
trace("Input report (%i): %s\n", read, report);
|
||||
|
||||
process_data(Caps, ppd, data, read);
|
||||
}
|
||||
trace("REMAINING: %d ms\n", max_time - spent);
|
||||
} while(spent < max_time);
|
||||
|
||||
CloseHandle(overlapped.hEvent);
|
||||
rc = HidD_FreePreparsedData(ppd);
|
||||
ok(rc, "Failed to free preparsed data(0x%x)\n", GetLastError());
|
||||
CloseHandle(device);
|
||||
HeapFree(GetProcessHeap(), 0, data);
|
||||
HeapFree(GetProcessHeap(), 0, report);
|
||||
}
|
||||
|
||||
static void test_get_input_report(void)
|
||||
{
|
||||
PHIDP_PREPARSED_DATA ppd;
|
||||
HIDP_CAPS Caps;
|
||||
WCHAR device_name[128];
|
||||
CHAR *data = NULL;
|
||||
DWORD tick, spent, max_time;
|
||||
char *report;
|
||||
BOOL rc;
|
||||
NTSTATUS status;
|
||||
|
||||
USAGE device_usages[] = {HID_USAGE_GENERIC_JOYSTICK, HID_USAGE_GENERIC_GAMEPAD};
|
||||
HANDLE device = get_device(HID_USAGE_PAGE_GENERIC, device_usages, 2, GENERIC_READ);
|
||||
|
||||
if (!device)
|
||||
device = get_device(0x0, NULL, 0x0, GENERIC_READ);
|
||||
|
||||
if (!device)
|
||||
{
|
||||
trace("No device found for testing\n");
|
||||
return;
|
||||
}
|
||||
rc = HidD_GetProductString(device, device_name, sizeof(device_name));
|
||||
ok(rc, "Failed to get product string(0x%x)\n", GetLastError());
|
||||
trace("HidD_GetInputRpeort tests on device :%s\n",wine_dbgstr_w(device_name));
|
||||
|
||||
rc = HidD_GetPreparsedData(device, &ppd);
|
||||
ok(rc, "Failed to get preparsed data(0x%x)\n", GetLastError());
|
||||
status = HidP_GetCaps(ppd, &Caps);
|
||||
ok(status == HIDP_STATUS_SUCCESS, "Failed to get Caps(0x%x)\n", status);
|
||||
data = HeapAlloc(GetProcessHeap(), 0, Caps.InputReportByteLength);
|
||||
|
||||
if (winetest_interactive)
|
||||
max_time = READ_MAX_TIME;
|
||||
else
|
||||
max_time = 100;
|
||||
if (winetest_interactive)
|
||||
trace("Test your device for the next %i seconds\n", max_time/1000);
|
||||
report = HeapAlloc(GetProcessHeap(), 0, 3 * Caps.InputReportByteLength);
|
||||
tick = GetTickCount();
|
||||
spent = 0;
|
||||
do
|
||||
{
|
||||
int i;
|
||||
|
||||
data[0] = 0; /* Just testing report ID 0 for now, That will catch most devices */
|
||||
rc = HidD_GetInputReport(device, data, Caps.InputReportByteLength);
|
||||
spent = GetTickCount() - tick;
|
||||
|
||||
if (rc)
|
||||
{
|
||||
ok(data[0] == 0, "Report ID (0) is not the first byte of the data\n");
|
||||
report[0] = 0;
|
||||
for (i = 0; i < Caps.InputReportByteLength; i++)
|
||||
{
|
||||
char bytestr[5];
|
||||
sprintf(bytestr, "%x ", (BYTE)data[i]);
|
||||
strcat(report, bytestr);
|
||||
}
|
||||
trace("Input report (%i): %s\n", Caps.InputReportByteLength, report);
|
||||
|
||||
process_data(Caps, ppd, data, Caps.InputReportByteLength);
|
||||
}
|
||||
else
|
||||
trace("Failed to get Input Report, (%x)\n", rc);
|
||||
trace("REMAINING: %d ms\n", max_time - spent);
|
||||
Sleep(500);
|
||||
} while(spent < max_time);
|
||||
|
||||
rc = HidD_FreePreparsedData(ppd);
|
||||
ok(rc, "Failed to free preparsed data(0x%x)\n", GetLastError());
|
||||
CloseHandle(device);
|
||||
HeapFree(GetProcessHeap(), 0, data);
|
||||
HeapFree(GetProcessHeap(), 0, report);
|
||||
}
|
||||
|
||||
START_TEST(device)
|
||||
{
|
||||
run_for_each_device(test_device_info);
|
||||
test_read_device();
|
||||
test_get_input_report();
|
||||
}
|
12
modules/rostests/winetests/hid/testlist.c
Normal file
12
modules/rostests/winetests/hid/testlist.c
Normal file
@ -0,0 +1,12 @@
|
||||
/* Automatically generated file; DO NOT EDIT!! */
|
||||
|
||||
#define STANDALONE
|
||||
#include <wine/test.h>
|
||||
|
||||
extern void func_device(void);
|
||||
|
||||
const struct test winetest_testlist[] =
|
||||
{
|
||||
{ "device", func_device },
|
||||
{ 0, 0 }
|
||||
};
|
Loading…
Reference in New Issue
Block a user