Rémi Bernon : dinput: Implement more accurate HID joystick device subtypes.

Alexandre Julliard julliard at winehq.org
Mon Sep 20 16:26:21 CDT 2021


Module: wine
Branch: master
Commit: 7c4941d0ec554e27208c370f624bfddb11febea1
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=7c4941d0ec554e27208c370f624bfddb11febea1

Author: Rémi Bernon <rbernon at codeweavers.com>
Date:   Mon Sep 20 10:57:25 2021 +0200

dinput: Implement more accurate HID joystick device subtypes.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/dinput/joystick_hid.c | 91 +++++++++++++++++++++++++++++++++++++++++++++-
 dlls/dinput8/tests/hid.c   |  6 ---
 2 files changed, 90 insertions(+), 7 deletions(-)

diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c
index 1614f5e8583..a9ca6fe6cc6 100644
--- a/dlls/dinput/joystick_hid.c
+++ b/dlls/dinput/joystick_hid.c
@@ -919,12 +919,52 @@ static HRESULT hid_joystick_read_state( IDirectInputDevice8W *iface )
     return DI_OK;
 }
 
+static DWORD device_type_for_version( DWORD type, DWORD version )
+{
+    if (version >= 0x0800) return type;
+
+    switch (GET_DIDEVICE_TYPE( type ))
+    {
+    case DI8DEVTYPE_JOYSTICK:
+        if (GET_DIDEVICE_SUBTYPE( type ) == DI8DEVTYPEJOYSTICK_LIMITED)
+            return DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_UNKNOWN << 8) | DIDEVTYPE_HID;
+        return DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8) | DIDEVTYPE_HID;
+
+    case DI8DEVTYPE_GAMEPAD:
+        return DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8) | DIDEVTYPE_HID;
+
+    case DI8DEVTYPE_DRIVING:
+        return DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_WHEEL << 8) | DIDEVTYPE_HID;
+
+    case DI8DEVTYPE_FLIGHT:
+        return DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_FLIGHTSTICK << 8) | DIDEVTYPE_HID;
+
+    case DI8DEVTYPE_SUPPLEMENTAL:
+        if (GET_DIDEVICE_SUBTYPE( type ) == DI8DEVTYPESUPPLEMENTAL_HEADTRACKER)
+            return DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_HEADTRACKER << 8) | DIDEVTYPE_HID;
+        if (GET_DIDEVICE_SUBTYPE( type ) == DI8DEVTYPESUPPLEMENTAL_RUDDERPEDALS)
+            return DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_RUDDER << 8) | DIDEVTYPE_HID;
+        return DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_UNKNOWN << 8) | DIDEVTYPE_HID;
+
+    case DI8DEVTYPE_1STPERSON:
+        return DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_UNKNOWN << 8) | DIDEVTYPE_HID;
+
+    default:
+        return DIDEVTYPE_DEVICE | DIDEVTYPE_HID;
+    }
+}
+
 static BOOL hid_joystick_device_try_open( UINT32 handle, const WCHAR *path, HANDLE *device,
                                           PHIDP_PREPARSED_DATA *preparsed, HIDD_ATTRIBUTES *attrs,
                                           HIDP_CAPS *caps, DIDEVICEINSTANCEW *instance, DWORD version )
 {
     PHIDP_PREPARSED_DATA preparsed_data = NULL;
+    DWORD type = 0, button_count = 0;
+    HIDP_BUTTON_CAPS buttons[10];
+    HIDP_VALUE_CAPS value;
     HANDLE device_file;
+    NTSTATUS status;
+    USHORT count;
 
     device_file = CreateFileW( path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
                                NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, 0 );
@@ -946,11 +986,60 @@ static BOOL hid_joystick_device_try_open( UINT32 handle, const WCHAR *path, HAND
     instance->guidInstance.Data1 ^= handle;
     instance->guidProduct = DInput_PIDVID_Product_GUID;
     instance->guidProduct.Data1 = MAKELONG( attrs->VendorID, attrs->ProductID );
-    instance->dwDevType = get_device_type( version, caps->Usage != HID_USAGE_GENERIC_GAMEPAD ) | DIDEVTYPE_HID;
     instance->guidFFDriver = GUID_NULL;
     instance->wUsagePage = caps->UsagePage;
     instance->wUsage = caps->Usage;
 
+    count = ARRAY_SIZE(buttons);
+    status = HidP_GetSpecificButtonCaps( HidP_Input, HID_USAGE_PAGE_BUTTON, 0, 0, buttons, &count, preparsed_data );
+    if (status != HIDP_STATUS_SUCCESS) count = button_count = 0;
+    while (count--)
+    {
+        if (!buttons[count].IsRange) button_count += 1;
+        else button_count += buttons[count].Range.UsageMax - buttons[count].Range.UsageMin + 1;
+    }
+
+    switch (caps->Usage)
+    {
+    case HID_USAGE_GENERIC_GAMEPAD:
+        type = DI8DEVTYPE_GAMEPAD | DIDEVTYPE_HID;
+        if (button_count < 6) type |= DI8DEVTYPEGAMEPAD_LIMITED << 8;
+        else type |= DI8DEVTYPEGAMEPAD_STANDARD << 8;
+        break;
+    case HID_USAGE_GENERIC_JOYSTICK:
+        type = DI8DEVTYPE_JOYSTICK | DIDEVTYPE_HID;
+        if (button_count < 5) type |= DI8DEVTYPEJOYSTICK_LIMITED << 8;
+        else type |= DI8DEVTYPEJOYSTICK_STANDARD << 8;
+
+        count = 1;
+        status = HidP_GetSpecificValueCaps( HidP_Input, HID_USAGE_PAGE_GENERIC, 0,
+                                            HID_USAGE_GENERIC_Z, &value, &count, preparsed_data );
+        if (status != HIDP_STATUS_SUCCESS || !count)
+            type = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_LIMITED << 8) | DIDEVTYPE_HID;
+
+        count = 1;
+        status = HidP_GetSpecificValueCaps( HidP_Input, HID_USAGE_PAGE_GENERIC, 0,
+                                            HID_USAGE_GENERIC_HATSWITCH, &value, &count, preparsed_data );
+        if (status != HIDP_STATUS_SUCCESS || !count)
+            type = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_LIMITED << 8) | DIDEVTYPE_HID;
+
+        break;
+    }
+
+    count = 1;
+    status = HidP_GetSpecificValueCaps( HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X,
+                                        &value, &count, preparsed_data );
+    if (status != HIDP_STATUS_SUCCESS || !count)
+        type = DI8DEVTYPE_SUPPLEMENTAL | (DI8DEVTYPESUPPLEMENTAL_UNKNOWN << 8) | DIDEVTYPE_HID;
+
+    count = 1;
+    status = HidP_GetSpecificValueCaps( HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Y,
+                                        &value, &count, preparsed_data );
+    if (status != HIDP_STATUS_SUCCESS || !count)
+        type = DI8DEVTYPE_SUPPLEMENTAL | (DI8DEVTYPESUPPLEMENTAL_UNKNOWN << 8) | DIDEVTYPE_HID;
+
+    instance->dwDevType = device_type_for_version( type, version );
+
     *device = device_file;
     *preparsed = preparsed_data;
     return TRUE;
diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c
index 63e909047aa..b02cdf1aa30 100644
--- a/dlls/dinput8/tests/hid.c
+++ b/dlls/dinput8/tests/hid.c
@@ -3666,7 +3666,6 @@ static void test_simple_joystick(void)
 
     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 );
@@ -3736,7 +3735,6 @@ static void test_simple_joystick(void)
     todo_wine
     check_member_guid( devinst, expect_devinst, guidInstance );
     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 );
@@ -3751,7 +3749,6 @@ static void test_simple_joystick(void)
     todo_wine
     check_member_guid( devinst, expect_devinst, guidInstance );
     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 );
@@ -3771,7 +3768,6 @@ static void test_simple_joystick(void)
     ok( hr == DI_OK, "IDirectInputDevice8_GetCapabilities returned %#x\n", hr );
     check_member( caps, expect_caps, "%d", dwSize );
     check_member( caps, expect_caps, "%#x", dwFlags );
-    todo_wine
     check_member( caps, expect_caps, "%#x", dwDevType );
     check_member( caps, expect_caps, "%d", dwAxes );
     check_member( caps, expect_caps, "%d", dwButtons );
@@ -4958,7 +4954,6 @@ static void test_device_types( void )
         todo_wine
         check_member_guid( devinst, expect_devinst[i], guidInstance );
         check_member_guid( devinst, expect_devinst[i], guidProduct );
-        todo_wine_if( i < 2 )
         check_member( devinst, expect_devinst[i], "%#x", dwDevType );
         todo_wine
         check_member_wstr( devinst, expect_devinst[i], tszInstanceName );
@@ -4972,7 +4967,6 @@ static void test_device_types( void )
         ok( hr == DI_OK, "IDirectInputDevice8_GetCapabilities returned %#x\n", hr );
         check_member( caps, expect_caps[i], "%d", dwSize );
         check_member( caps, expect_caps[i], "%#x", dwFlags );
-        todo_wine_if( i < 2 )
         check_member( caps, expect_caps[i], "%#x", dwDevType );
         check_member( caps, expect_caps[i], "%d", dwAxes );
         check_member( caps, expect_caps[i], "%d", dwButtons );




More information about the wine-cvs mailing list