[PATCH 3/5] dinput8/tests: Add a new HID joystick test based on the HID driver.

Rémi Bernon rbernon at codeweavers.com
Wed Sep 15 02:29:51 CDT 2021


Signed-off-by: Rémi Bernon <rbernon at 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 );
-- 
2.33.0




More information about the wine-devel mailing list