Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput8/tests/hid.c | 227 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+)
diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c index cb1f4d61b7a..1dc42909c7f 100644 --- a/dlls/dinput8/tests/hid.c +++ b/dlls/dinput8/tests/hid.c @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#define DIRECTINPUT_VERSION 0x0800 + #include <stdarg.h> #include <stddef.h>
@@ -40,18 +42,29 @@
#include "objbase.h"
+#define COBJMACROS +#include "wingdi.h" +#include "dinput.h" + #include "initguid.h" #include "ddk/wdm.h" #include "ddk/hidclass.h" #include "ddk/hidsdi.h" #include "ddk/hidpi.h" #include "ddk/hidport.h" +#include "devguid.h"
#include "wine/test.h" #include "wine/mssign.h"
#include "driver_hid.h"
+static HINSTANCE instance; + +#define EXPECT_VIDPID MAKELONG( 0x1209, 0x0001 ) +static const WCHAR expect_vidpid_str[] = L"VID_1209&PID_0001"; +static const GUID expect_guid_product = {EXPECT_VIDPID,0x0000,0x0000,{0x00,0x00,'P','I','D','V','I','D'}}; + static struct winetest_shared_data *test_data; static HANDLE okfile;
@@ -574,6 +587,18 @@ static BOOL pnp_driver_start( const WCHAR *resource ) #define check_member( val, exp, fmt, member ) \ check_member_( __FILE__, __LINE__, val, exp, fmt, member )
+#define check_member_guid_( file, line, val, exp, member ) \ + ok_( file, line )(IsEqualGUID( &(val).member, &(exp).member ), "got " #member " %s, expected %s\n", \ + debugstr_guid( &(val).member ), debugstr_guid( &(exp).member )) +#define check_member_guid( val, exp, member ) \ + check_member_guid_( __FILE__, __LINE__, val, exp, member ) + +#define check_member_wstr_( file, line, val, exp, member ) \ + ok_( file, line )(!wcscmp( (val).member, (exp).member ), "got " #member " %s, expected %s\n", \ + debugstr_w((val).member), debugstr_w((exp).member)) +#define check_member_wstr( val, exp, member ) \ + check_member_wstr_( __FILE__, __LINE__, val, exp, member ) + #define check_hidp_caps( a, b ) check_hidp_caps_( __LINE__, a, b ) static inline void check_hidp_caps_( int line, HIDP_CAPS *caps, const HIDP_CAPS *exp ) { @@ -3179,11 +3204,209 @@ done: SetCurrentDirectoryW( cwd ); }
+static void cleanup_registry_keys(void) +{ + static const WCHAR joystick_oem_path[] = L"System\CurrentControlSet\Control\MediaProperties\" + "PrivateProperties\Joystick\OEM"; + static const WCHAR dinput_path[] = L"System\CurrentControlSet\Control\MediaProperties\" + "PrivateProperties\DirectInput"; + HKEY root_key; + + /* These keys are automatically created by DInput and they store the + list of supported force-feedback effects. OEM drivers are supposed + to provide a list in HKLM for the vendor-specific force-feedback + support. + + We need to clean them up, or DInput will not refresh the list of + effects from the PID report changes. + */ + RegCreateKeyExW( HKEY_CURRENT_USER, joystick_oem_path, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &root_key, NULL ); + RegDeleteTreeW( root_key, expect_vidpid_str ); + RegCloseKey( root_key ); + + RegCreateKeyExW( HKEY_CURRENT_USER, dinput_path, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &root_key, NULL ); + RegDeleteTreeW( root_key, expect_vidpid_str ); + RegCloseKey( root_key ); + + RegCreateKeyExW( HKEY_LOCAL_MACHINE, joystick_oem_path, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &root_key, NULL ); + RegDeleteTreeW( root_key, expect_vidpid_str ); + RegCloseKey( root_key ); + + RegCreateKeyExW( HKEY_LOCAL_MACHINE, dinput_path, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &root_key, NULL ); + RegDeleteTreeW( root_key, expect_vidpid_str ); + RegCloseKey( root_key ); +} + +static BOOL dinput_driver_start( const BYTE *desc_buf, ULONG desc_len, const HIDP_CAPS *caps ) +{ + static const HID_DEVICE_ATTRIBUTES attributes = + { + .Size = sizeof(HID_DEVICE_ATTRIBUTES), + .VendorID = LOWORD( EXPECT_VIDPID ), + .ProductID = HIWORD( EXPECT_VIDPID ), + .VersionNumber = 0x0100, + }; + DWORD report_id = 1; + DWORD polled = 0; + LSTATUS status; + HKEY hkey; + + status = RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"System\CurrentControlSet\Services\winetest", + 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ); + ok( !status, "RegCreateKeyExW returned %#x\n", status ); + status = RegSetValueExW( hkey, L"ReportID", 0, REG_DWORD, (void *)&report_id, sizeof(report_id) ); + ok( !status, "RegSetValueExW returned %#x\n", status ); + status = RegSetValueExW( hkey, L"PolledMode", 0, REG_DWORD, (void *)&polled, sizeof(polled) ); + ok( !status, "RegSetValueExW returned %#x\n", status ); + status = RegSetValueExW( hkey, L"Descriptor", 0, REG_BINARY, (void *)desc_buf, desc_len ); + ok( !status, "RegSetValueExW returned %#x\n", status ); + status = RegSetValueExW( hkey, L"Attributes", 0, REG_BINARY, (void *)&attributes, sizeof(attributes) ); + ok( !status, "RegSetValueExW returned %#x\n", status ); + status = RegSetValueExW( hkey, L"Caps", 0, REG_BINARY, (void *)caps, sizeof(*caps) ); + ok( !status, "RegSetValueExW returned %#x\n", status ); + status = RegSetValueExW( hkey, L"Expect", 0, REG_BINARY, NULL, 0 ); + ok( !status, "RegSetValueExW returned %#x\n", status ); + status = RegSetValueExW( hkey, L"Input", 0, REG_BINARY, NULL, 0 ); + ok( !status, "RegSetValueExW returned %#x\n", status ); + + return pnp_driver_start( L"driver_hid.dll" ); +} + +static BOOL CALLBACK find_test_device( const DIDEVICEINSTANCEW *devinst, void *context ) +{ + if (IsEqualGUID( &devinst->guidProduct, &expect_guid_product )) + *(DIDEVICEINSTANCEW *)context = *devinst; + return DIENUM_CONTINUE; +} + +static void test_simple_joystick(void) +{ +#include "psh_hid_macros.h" + static const unsigned char report_desc[] = + { + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Application), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Report), + REPORT_ID(1, 1), + + USAGE(1, HID_USAGE_GENERIC_X), + USAGE(1, HID_USAGE_GENERIC_Y), + LOGICAL_MINIMUM(1, 0xe7), + LOGICAL_MAXIMUM(1, 0x38), + PHYSICAL_MINIMUM(1, 0xe7), + PHYSICAL_MAXIMUM(1, 0x38), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 2), + INPUT(1, Data|Var|Abs), + + USAGE(1, HID_USAGE_GENERIC_HATSWITCH), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 8), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 8), + REPORT_SIZE(1, 4), + REPORT_COUNT(1, 1), + INPUT(1, Data|Var|Abs|Null), + + USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), + USAGE_MINIMUM(1, 1), + USAGE_MAXIMUM(1, 2), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 4), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + END_COLLECTION, + }; +#undef REPORT_ID_OR_USAGE_PAGE +#include "pop_hid_macros.h" + + static const HIDP_CAPS hid_caps = + { + .InputReportByteLength = 4, + }; + + const DIDEVICEINSTANCEW expect_devinst = + { + .dwSize = sizeof(DIDEVICEINSTANCEW), + .guidInstance = expect_guid_product, + .guidProduct = expect_guid_product, + .dwDevType = DIDEVTYPE_HID | (DI8DEVTYPEJOYSTICK_LIMITED << 8) | DI8DEVTYPE_JOYSTICK, + .tszInstanceName = L"Wine test root driver", + .tszProductName = L"Wine test root driver", + .guidFFDriver = GUID_NULL, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_JOYSTICK, + }; + + WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; + DIDEVICEINSTANCEW devinst = {0}; + IDirectInputDevice8W *device; + IDirectInput8W *di; + HRESULT hr; + ULONG ref; + + GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); + GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); + SetCurrentDirectoryW( tempdir ); + + cleanup_registry_keys(); + if (!dinput_driver_start( report_desc, sizeof(report_desc), &hid_caps )) goto done; + + hr = DirectInput8Create( instance, DIRECTINPUT_VERSION, &IID_IDirectInput8W, (void **)&di, NULL ); + if (FAILED(hr)) + { + win_skip( "DirectInput8Create returned %#x\n", hr ); + goto done; + } + + hr = IDirectInput8_EnumDevices( di, DI8DEVCLASS_ALL, find_test_device, &devinst, DIEDFL_ALLDEVICES ); + ok( hr == DI_OK, "IDirectInput8_EnumDevices returned: %#x\n", hr ); + if (!IsEqualGUID( &devinst.guidProduct, &expect_guid_product )) + { + win_skip( "device not found, skipping tests\n" ); + IDirectInput8_Release( di ); + goto done; + } + + check_member( devinst, expect_devinst, "%d", dwSize ); + check_member_guid( devinst, expect_devinst, guidProduct ); + todo_wine + check_member( devinst, expect_devinst, "%#x", dwDevType ); + todo_wine + check_member_wstr( devinst, expect_devinst, tszInstanceName ); + todo_wine + check_member_wstr( devinst, expect_devinst, tszProductName ); + check_member_guid( devinst, expect_devinst, guidFFDriver ); + check_member( devinst, expect_devinst, "%04x", wUsagePage ); + check_member( devinst, expect_devinst, "%04x", wUsage ); + + hr = IDirectInput8_CreateDevice( di, &expect_guid_product, &device, NULL ); + ok( hr == DI_OK, "IDirectInput8_CreateDevice returned %#x\n", hr ); + + ref = IDirectInputDevice8_Release( device ); + ok( ref == 0, "IDirectInputDeviceW_Release returned %d\n", ref ); + + ref = IDirectInput8_Release( di ); + ok( ref == 0, "IDirectInput8_Release returned %d\n", ref ); + +done: + pnp_driver_stop(); + cleanup_registry_keys(); + SetCurrentDirectoryW( cwd ); +} + START_TEST( hid ) { HANDLE mapping; BOOL is_wow64;
+ instance = GetModuleHandleW( NULL ); pSignerSign = (void *)GetProcAddress( LoadLibraryW( L"mssign32" ), "SignerSign" );
if (IsWow64Process( GetCurrentProcess(), &is_wow64 ) && is_wow64) @@ -3216,6 +3439,10 @@ START_TEST( hid ) test_hid_driver( 0, TRUE ); test_hid_driver( 1, TRUE );
+ CoInitialize( NULL ); + test_simple_joystick(); + CoUninitialize(); + UnmapViewOfFile( test_data ); CloseHandle( mapping ); CloseHandle( okfile );