[PATCH 6/8] dinput: Implement HID joystick DIPROP_(DEADZONE|SATURATION|GRANULARITY).

Rémi Bernon rbernon at codeweavers.com
Tue Sep 28 02:30:13 CDT 2021


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/dinput/joystick_hid.c | 119 +++++++++++++++++++++++++++++++++++--
 dlls/dinput8/tests/hid.c   |  30 ----------
 2 files changed, 113 insertions(+), 36 deletions(-)

diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c
index 3dc0776a1ec..4ce60e67faf 100644
--- a/dlls/dinput/joystick_hid.c
+++ b/dlls/dinput/joystick_hid.c
@@ -137,6 +137,12 @@ static inline const char *debugstr_hid_caps( struct hid_caps *caps )
     return "(unknown type)";
 }
 
+struct extra_caps
+{
+    LONG deadzone;
+    LONG saturation;
+};
+
 #define DEVICE_STATE_MAX_SIZE 1024
 
 struct hid_joystick
@@ -156,6 +162,7 @@ struct hid_joystick
     HIDP_LINK_COLLECTION_NODE *collection_nodes;
     HIDP_BUTTON_CAPS *input_button_caps;
     HIDP_VALUE_CAPS *input_value_caps;
+    struct extra_caps *input_extra_caps;
 
     char *input_report_buf;
     USAGE_AND_PAGE *usages_buf;
@@ -424,6 +431,7 @@ static ULONG WINAPI hid_joystick_Release( IDirectInputDevice8W *iface )
     {
         HeapFree( GetProcessHeap(), 0, tmp.usages_buf );
         HeapFree( GetProcessHeap(), 0, tmp.input_report_buf );
+        HeapFree( GetProcessHeap(), 0, tmp.input_extra_caps );
         HeapFree( GetProcessHeap(), 0, tmp.input_value_caps );
         HeapFree( GetProcessHeap(), 0, tmp.input_button_caps );
         HeapFree( GetProcessHeap(), 0, tmp.collection_nodes );
@@ -519,6 +527,34 @@ static BOOL get_property_prop_range( struct hid_joystick *impl, struct hid_caps
     return DIENUM_STOP;
 }
 
+static BOOL get_property_prop_deadzone( struct hid_joystick *impl, struct hid_caps *caps,
+                                        DIDEVICEOBJECTINSTANCEW *instance, void *data )
+{
+    struct extra_caps *extra;
+    DIPROPDWORD *deadzone = data;
+    extra = impl->input_extra_caps + (caps->value - impl->input_value_caps);
+    deadzone->dwData = extra->deadzone;
+    return DIENUM_STOP;
+}
+
+static BOOL get_property_prop_saturation( struct hid_joystick *impl, struct hid_caps *caps,
+                                          DIDEVICEOBJECTINSTANCEW *instance, void *data )
+{
+    struct extra_caps *extra;
+    DIPROPDWORD *saturation = data;
+    extra = impl->input_extra_caps + (caps->value - impl->input_value_caps);
+    saturation->dwData = extra->saturation;
+    return DIENUM_STOP;
+}
+
+static BOOL get_property_prop_granularity( struct hid_joystick *impl, struct hid_caps *caps,
+                                           DIDEVICEOBJECTINSTANCEW *instance, void *data )
+{
+    DIPROPDWORD *granularity = data;
+    granularity->dwData = 1;
+    return DIENUM_STOP;
+}
+
 static HRESULT WINAPI hid_joystick_GetProperty( IDirectInputDevice8W *iface, const GUID *guid,
                                                 DIPROPHEADER *header )
 {
@@ -538,6 +574,24 @@ static HRESULT WINAPI hid_joystick_GetProperty( IDirectInputDevice8W *iface, con
         if (enum_objects( impl, header, DIDFT_AXIS, get_property_prop_range, header ) == DIENUM_STOP)
             return DI_OK;
         return DIERR_NOTFOUND;
+    case (DWORD_PTR)DIPROP_DEADZONE:
+        if (header->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
+        if (header->dwHow == DIPH_DEVICE) return DIERR_UNSUPPORTED;
+        if (enum_objects( impl, header, DIDFT_AXIS, get_property_prop_deadzone, header ) == DIENUM_STOP)
+            return DI_OK;
+        return DIERR_NOTFOUND;
+    case (DWORD_PTR)DIPROP_SATURATION:
+        if (header->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
+        if (header->dwHow == DIPH_DEVICE) return DIERR_UNSUPPORTED;
+        if (enum_objects( impl, header, DIDFT_AXIS, get_property_prop_saturation, header ) == DIENUM_STOP)
+            return DI_OK;
+        return DIERR_NOTFOUND;
+    case (DWORD_PTR)DIPROP_GRANULARITY:
+        if (header->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
+        if (header->dwHow == DIPH_DEVICE) return DIERR_UNSUPPORTED;
+        if (enum_objects( impl, header, DIDFT_AXIS, get_property_prop_granularity, header ) == DIENUM_STOP)
+            return DI_OK;
+        return DIERR_NOTFOUND;
     case (DWORD_PTR)DIPROP_PRODUCTNAME:
     {
         DIPROPSTRING *value = (DIPROPSTRING *)header;
@@ -606,6 +660,26 @@ static BOOL set_property_prop_range( struct hid_joystick *impl, struct hid_caps
     return DIENUM_CONTINUE;
 }
 
+static BOOL set_property_prop_deadzone( struct hid_joystick *impl, struct hid_caps *caps,
+                                        DIDEVICEOBJECTINSTANCEW *instance, void *data )
+{
+    struct extra_caps *extra;
+    DIPROPDWORD *deadzone = data;
+    extra = impl->input_extra_caps + (caps->value - impl->input_value_caps);
+    extra->deadzone = deadzone->dwData;
+    return DIENUM_CONTINUE;
+}
+
+static BOOL set_property_prop_saturation( struct hid_joystick *impl, struct hid_caps *caps,
+                                          DIDEVICEOBJECTINSTANCEW *instance, void *data )
+{
+    struct extra_caps *extra;
+    DIPROPDWORD *saturation = data;
+    extra = impl->input_extra_caps + (caps->value - impl->input_value_caps);
+    extra->saturation = saturation->dwData;
+    return DIENUM_CONTINUE;
+}
+
 static HRESULT WINAPI hid_joystick_SetProperty( IDirectInputDevice8W *iface, const GUID *guid,
                                                 const DIPROPHEADER *header )
 {
@@ -627,6 +701,22 @@ static HRESULT WINAPI hid_joystick_SetProperty( IDirectInputDevice8W *iface, con
         enum_objects( impl, header, DIDFT_AXIS, set_property_prop_range, (void *)header );
         return DI_OK;
     }
+    case (DWORD_PTR)DIPROP_DEADZONE:
+    {
+        DIPROPDWORD *value = (DIPROPDWORD *)header;
+        if (header->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
+        if (value->dwData > 10000) return DIERR_INVALIDPARAM;
+        enum_objects( impl, header, DIDFT_AXIS, set_property_prop_deadzone, (void *)header );
+        return DI_OK;
+    }
+    case (DWORD_PTR)DIPROP_SATURATION:
+    {
+        DIPROPDWORD *value = (DIPROPDWORD *)header;
+        if (header->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
+        if (value->dwData > 10000) return DIERR_INVALIDPARAM;
+        enum_objects( impl, header, DIDFT_AXIS, set_property_prop_saturation, (void *)header );
+        return DI_OK;
+    }
     case (DWORD_PTR)DIPROP_FFLOAD:
     case (DWORD_PTR)DIPROP_GRANULARITY:
     case (DWORD_PTR)DIPROP_VIDPID:
@@ -859,7 +949,7 @@ static LONG scale_value( ULONG value, const HIDP_VALUE_CAPS *caps, LONG min, LON
     return min + MulDiv( tmp - caps->LogicalMin, max - min, caps->LogicalMax - caps->LogicalMin );
 }
 
-static LONG scale_axis_value( ULONG value, const HIDP_VALUE_CAPS *caps )
+static LONG scale_axis_value( ULONG value, const HIDP_VALUE_CAPS *caps, struct extra_caps *extra )
 {
     LONG tmp = sign_extend( value, caps ), log_ctr, log_min, log_max, phy_ctr, phy_min, phy_max;
     ULONG bit_max = (1 << caps->BitSize) - 1;
@@ -879,14 +969,14 @@ static LONG scale_axis_value( ULONG value, const HIDP_VALUE_CAPS *caps )
     tmp -= log_ctr;
     if (tmp <= 0)
     {
-        log_max = 0;
-        log_min -= log_ctr;
+        log_max = MulDiv( log_min - log_ctr, extra->deadzone, 10000 );
+        log_min = MulDiv( log_min - log_ctr, extra->saturation, 10000 );
         phy_max = phy_ctr;
     }
     else
     {
-        log_min = 0;
-        log_max -= log_ctr;
+        log_min = MulDiv( log_max - log_ctr, extra->deadzone, 10000 );
+        log_max = MulDiv( log_max - log_ctr, extra->saturation, 10000 );
         phy_min = phy_ctr;
     }
 
@@ -903,14 +993,16 @@ static BOOL read_device_state_value( struct hid_joystick *impl, struct hid_caps
     struct parse_device_state_params *params = data;
     char *report_buf = impl->input_report_buf;
     HIDP_VALUE_CAPS *value_caps = caps->value;
+    struct extra_caps *extra;
     LONG old_value, value;
     NTSTATUS status;
 
+    extra = impl->input_extra_caps + (value_caps - impl->input_value_caps);
     status = HidP_GetUsageValue( HidP_Input, instance->wUsagePage, 0, instance->wUsage,
                                  &logical_value, impl->preparsed, report_buf, report_len );
     if (status != HIDP_STATUS_SUCCESS) WARN( "HidP_GetUsageValue %04x:%04x returned %#x\n",
                                              instance->wUsagePage, instance->wUsage, status );
-    if (instance->dwType & DIDFT_AXIS) value = scale_axis_value( logical_value, value_caps );
+    if (instance->dwType & DIDFT_AXIS) value = scale_axis_value( logical_value, value_caps, extra );
     else value = scale_value( logical_value, value_caps, value_caps->PhysicalMin, value_caps->PhysicalMax );
 
     old_value = *(LONG *)(params->old_state + instance->dwOfs);
@@ -1305,9 +1397,19 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID
             .dwHow = DIPH_DEVICE,
         },
     };
+    DIPROPDWORD saturation =
+    {
+        .diph =
+        {
+            .dwSize = sizeof(DIPROPDWORD),
+            .dwHeaderSize = sizeof(DIPROPHEADER),
+            .dwHow = DIPH_DEVICE,
+        },
+    };
     HIDD_ATTRIBUTES attrs = {.Size = sizeof(attrs)};
     HIDP_LINK_COLLECTION_NODE *nodes;
     struct hid_joystick *impl = NULL;
+    struct extra_caps *extra;
     DIDATAFORMAT *format = NULL;
     HIDP_BUTTON_CAPS *buttons;
     HIDP_VALUE_CAPS *values;
@@ -1356,6 +1458,9 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID
     size = impl->caps.NumberInputValueCaps * sizeof(HIDP_VALUE_CAPS);
     if (!(values = HeapAlloc( GetProcessHeap(), 0, size ))) goto failed;
     impl->input_value_caps = values;
+    size = impl->caps.NumberInputValueCaps * sizeof(struct extra_caps);
+    if (!(extra = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ))) goto failed;
+    impl->input_extra_caps = extra;
 
     size = impl->caps.InputReportByteLength;
     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size ))) goto failed;
@@ -1400,6 +1505,8 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID
     enum_objects( impl, &range.diph, DIDFT_AXIS, set_property_prop_range, &range );
     range.lMax = 36000;
     enum_objects( impl, &range.diph, DIDFT_POV, set_property_prop_range, &range );
+    saturation.dwData = 10000;
+    enum_objects( impl, &range.diph, DIDFT_AXIS, set_property_prop_saturation, &saturation );
 
     *out = &impl->base.IDirectInputDevice8W_iface;
     return DI_OK;
diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c
index ec5dffe70f5..07505797eb1 100644
--- a/dlls/dinput8/tests/hid.c
+++ b/dlls/dinput8/tests/hid.c
@@ -3867,16 +3867,13 @@ static void test_simple_joystick(void)
     todo_wine
     ok( hr == DIERR_UNSUPPORTED, "IDirectInputDevice8_GetProperty DIPROP_AUTOCENTER returned %#x\n", hr );
     hr = IDirectInputDevice8_GetProperty( device, DIPROP_DEADZONE, &prop_dword.diph );
-    todo_wine
     ok( hr == DIERR_UNSUPPORTED, "IDirectInputDevice8_GetProperty DIPROP_DEADZONE returned %#x\n", hr );
     hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph );
     todo_wine
     ok( hr == DIERR_UNSUPPORTED, "IDirectInputDevice8_GetProperty DIPROP_FFLOAD returned %#x\n", hr );
     hr = IDirectInputDevice8_GetProperty( device, DIPROP_GRANULARITY, &prop_dword.diph );
-    todo_wine
     ok( hr == DIERR_UNSUPPORTED, "IDirectInputDevice8_GetProperty DIPROP_GRANULARITY returned %#x\n", hr );
     hr = IDirectInputDevice8_GetProperty( device, DIPROP_SATURATION, &prop_dword.diph );
-    todo_wine
     ok( hr == DIERR_UNSUPPORTED, "IDirectInputDevice8_GetProperty DIPROP_SATURATION returned %#x\n", hr );
     hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph );
     ok( hr == DIERR_UNSUPPORTED, "IDirectInputDevice8_GetProperty DIPROP_RANGE returned %#x\n", hr );
@@ -3885,21 +3882,15 @@ static void test_simple_joystick(void)
     prop_dword.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC );
     prop_dword.dwData = 0xdeadbeef;
     hr = IDirectInputDevice8_GetProperty( device, DIPROP_DEADZONE, &prop_dword.diph );
-    todo_wine
     ok( hr == DI_OK, "IDirectInputDevice8_GetProperty DIPROP_DEADZONE returned %#x\n", hr );
-    todo_wine
     ok( prop_dword.dwData == 0, "got %u expected %u\n", prop_dword.dwData, 0 );
     prop_dword.dwData = 0xdeadbeef;
     hr = IDirectInputDevice8_GetProperty( device, DIPROP_GRANULARITY, &prop_dword.diph );
-    todo_wine
     ok( hr == DI_OK, "IDirectInputDevice8_GetProperty DIPROP_GRANULARITY returned %#x\n", hr );
-    todo_wine
     ok( prop_dword.dwData == 1, "got %u expected %u\n", prop_dword.dwData, 1 );
     prop_dword.dwData = 0xdeadbeef;
     hr = IDirectInputDevice8_GetProperty( device, DIPROP_SATURATION, &prop_dword.diph );
-    todo_wine
     ok( hr == DI_OK, "IDirectInputDevice8_GetProperty DIPROP_SATURATION returned %#x\n", hr );
-    todo_wine
     ok( prop_dword.dwData == 10000, "got %u expected %u\n", prop_dword.dwData, 10000 );
 
     prop_range.diph.dwHow = DIPH_BYUSAGE;
@@ -4368,67 +4359,51 @@ static void test_simple_joystick(void)
     prop_dword.diph.dwObj = 0;
     prop_dword.dwData = 10001;
     hr = IDirectInputDevice8_SetProperty( device, DIPROP_DEADZONE, &prop_dword.diph );
-    todo_wine
     ok( hr == DIERR_INVALIDPARAM, "IDirectInputDevice8_SetProperty DIPROP_DEADZONE returned %#x\n", hr );
     hr = IDirectInputDevice8_SetProperty( device, DIPROP_SATURATION, &prop_dword.diph );
-    todo_wine
     ok( hr == DIERR_INVALIDPARAM, "IDirectInputDevice8_SetProperty DIPROP_SATURATION returned %#x\n", hr );
     prop_dword.dwData = 1000;
     hr = IDirectInputDevice8_SetProperty( device, DIPROP_DEADZONE, &prop_dword.diph );
-    todo_wine
     ok( hr == DI_OK, "IDirectInputDevice8_SetProperty DIPROP_DEADZONE returned %#x\n", hr );
     prop_dword.dwData = 6000;
     hr = IDirectInputDevice8_SetProperty( device, DIPROP_SATURATION, &prop_dword.diph );
-    todo_wine
     ok( hr == DI_OK, "IDirectInputDevice8_SetProperty DIPROP_SATURATION returned %#x\n", hr );
 
     hr = IDirectInputDevice8_GetProperty( device, DIPROP_DEADZONE, &prop_dword.diph );
-    todo_wine
     ok( hr == DIERR_UNSUPPORTED, "IDirectInputDevice8_GetProperty DIPROP_DEADZONE returned %#x\n", hr );
     hr = IDirectInputDevice8_GetProperty( device, DIPROP_SATURATION, &prop_dword.diph );
-    todo_wine
     ok( hr == DIERR_UNSUPPORTED, "IDirectInputDevice8_GetProperty DIPROP_SATURATION returned %#x\n", hr );
 
     prop_dword.diph.dwHow = DIPH_BYUSAGE;
     prop_dword.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC );
     prop_dword.dwData = 2000;
     hr = IDirectInputDevice8_SetProperty( device, DIPROP_DEADZONE, &prop_dword.diph );
-    todo_wine
     ok( hr == DI_OK, "IDirectInputDevice8_SetProperty DIPROP_DEADZONE returned %#x\n", hr );
     ok( prop_dword.dwData == 2000, "got %u expected %u\n", prop_dword.dwData, 2000 );
     prop_dword.dwData = 7000;
     hr = IDirectInputDevice8_SetProperty( device, DIPROP_SATURATION, &prop_dword.diph );
-    todo_wine
     ok( hr == DI_OK, "IDirectInputDevice8_SetProperty DIPROP_SATURATION returned %#x\n", hr );
 
     prop_dword.diph.dwHow = DIPH_BYUSAGE;
     prop_dword.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC );
     prop_dword.dwData = 0xdeadbeef;
     hr = IDirectInputDevice8_GetProperty( device, DIPROP_DEADZONE, &prop_dword.diph );
-    todo_wine
     ok( hr == DI_OK, "IDirectInputDevice8_GetProperty DIPROP_DEADZONE returned %#x\n", hr );
-    todo_wine
     ok( prop_dword.dwData == 2000, "got %u expected %u\n", prop_dword.dwData, 2000 );
     prop_dword.dwData = 0xdeadbeef;
     hr = IDirectInputDevice8_GetProperty( device, DIPROP_SATURATION, &prop_dword.diph );
-    todo_wine
     ok( hr == DI_OK, "IDirectInputDevice8_GetProperty DIPROP_SATURATION returned %#x\n", hr );
-    todo_wine
     ok( prop_dword.dwData == 7000, "got %u expected %u\n", prop_dword.dwData, 7000 );
 
     prop_dword.diph.dwHow = DIPH_BYUSAGE;
     prop_dword.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_Y, HID_USAGE_PAGE_GENERIC );
     prop_dword.dwData = 0xdeadbeef;
     hr = IDirectInputDevice8_GetProperty( device, DIPROP_DEADZONE, &prop_dword.diph );
-    todo_wine
     ok( hr == DI_OK, "IDirectInputDevice8_GetProperty DIPROP_DEADZONE returned %#x\n", hr );
-    todo_wine
     ok( prop_dword.dwData == 1000, "got %u expected %u\n", prop_dword.dwData, 1000 );
     prop_dword.dwData = 0xdeadbeef;
     hr = IDirectInputDevice8_GetProperty( device, DIPROP_SATURATION, &prop_dword.diph );
-    todo_wine
     ok( hr == DI_OK, "IDirectInputDevice8_GetProperty DIPROP_SATURATION returned %#x\n", hr );
-    todo_wine
     ok( prop_dword.dwData == 6000, "got %u expected %u\n", prop_dword.dwData, 6000 );
 
     for (i = 0; i < ARRAY_SIZE(injected_input); ++i)
@@ -4439,9 +4414,7 @@ static void test_simple_joystick(void)
         if (broken( state.lX == -10750 )) win_skip( "Ignoring 32-bit rounding\n" );
         else
         {
-            todo_wine_if( i == 3 || i == 4 )
             check_member( state, expect_state_abs[i], "%d", lX );
-            todo_wine_if( i == 3 || i == 4 )
             check_member( state, expect_state_abs[i], "%d", lY );
         }
         check_member( state, expect_state_abs[i], "%d", lZ );
@@ -4465,7 +4438,6 @@ static void test_simple_joystick(void)
     ok( hr == DI_OK, "IDirectInputDevice8_GetDeviceState returned: %#x\n", hr );
     winetest_push_context( "state[%d]", i );
     check_member( state, expect_state_abs[i], "%d", lX );
-    todo_wine
     check_member( state, expect_state_abs[i], "%d", lY );
     check_member( state, expect_state_abs[i], "%d", lZ );
     check_member( state, expect_state_abs[i], "%d", lRx );
@@ -4547,11 +4519,9 @@ static void test_simple_joystick(void)
     ok( hr == DIERR_INVALIDPARAM, "IDirectInputDevice8_SetProperty DIPROP_CALIBRATION returned %#x\n", hr );
     prop_dword.dwData = 0xdeadbeef;
     hr = IDirectInputDevice8_SetProperty( device, DIPROP_DEADZONE, &prop_dword.diph );
-    todo_wine
     ok( hr == DIERR_INVALIDPARAM, "IDirectInputDevice8_SetProperty DIPROP_DEADZONE returned %#x\n", hr );
     prop_dword.dwData = 0xdeadbeef;
     hr = IDirectInputDevice8_SetProperty( device, DIPROP_SATURATION, &prop_dword.diph );
-    todo_wine
     ok( hr == DIERR_INVALIDPARAM, "IDirectInputDevice8_SetProperty DIPROP_SATURATION returned %#x\n", hr );
 
     for (i = 0; i < ARRAY_SIZE(injected_input); ++i)
-- 
2.33.0




More information about the wine-devel mailing list