[PATCH 08/11] dinput: Partially implement HID joystick IDirectInputEffect_GetParameters.

Rémi Bernon rbernon at codeweavers.com
Thu Oct 7 03:40:05 CDT 2021


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

diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c
index e0fd2842feb..3014e76603b 100644
--- a/dlls/dinput/joystick_hid.c
+++ b/dlls/dinput/joystick_hid.c
@@ -150,6 +150,12 @@ struct hid_joystick_effect
     struct list entry;
     struct hid_joystick *joystick;
 
+    DWORD axes[6];
+    LONG directions[6];
+    DIENVELOPE envelope;
+    DIPERIODIC periodic;
+    DIEFFECT params;
+
     char *effect_control_buf;
     char *effect_update_buf;
 };
@@ -2120,10 +2126,155 @@ static HRESULT WINAPI hid_joystick_effect_GetEffectGuid( IDirectInputEffect *ifa
     return DI_OK;
 }
 
+static BOOL get_parameters_object_id( struct hid_joystick *impl, struct hid_value_caps *caps,
+                                      DIDEVICEOBJECTINSTANCEW *instance, void *data )
+{
+    *(DWORD *)data = instance->dwType;
+    return DIENUM_STOP;
+}
+
+static BOOL get_parameters_object_ofs( struct hid_joystick *impl, struct hid_value_caps *caps,
+                                       DIDEVICEOBJECTINSTANCEW *instance, void *data )
+{
+    DIDATAFORMAT *format = impl->base.data_format.wine_df;
+    int *offsets = impl->base.data_format.offsets;
+    ULONG i;
+
+    if (!offsets) return DIENUM_CONTINUE;
+    for (i = 0; i < format->dwNumObjs; ++i)
+        if (format->rgodf[i].dwOfs == instance->dwOfs) break;
+    if (i == format->dwNumObjs) return DIENUM_CONTINUE;
+    *(DWORD *)data = offsets[i];
+
+    return DIENUM_STOP;
+}
+
 static HRESULT WINAPI hid_joystick_effect_GetParameters( IDirectInputEffect *iface, DIEFFECT *params, DWORD flags )
 {
-    FIXME( "iface %p, params %p, flags %#x stub!\n", iface, params, flags );
-    return DIERR_UNSUPPORTED;
+    DIPROPHEADER filter =
+    {
+        .dwSize = sizeof(DIPROPHEADER),
+        .dwHeaderSize = sizeof(DIPROPHEADER),
+        .dwHow = DIPH_BYUSAGE,
+    };
+    struct hid_joystick_effect *impl = impl_from_IDirectInputEffect( iface );
+    ULONG i, j, count, capacity, object_flags, direction_flags;
+    LONG tmp, directions[6] = {0};
+    BOOL ret;
+
+    TRACE( "iface %p, params %p, flags %#x.\n", iface, params, flags );
+
+    if (!params) return DI_OK;
+    if (params->dwSize != sizeof(DIEFFECT)) return DIERR_INVALIDPARAM;
+    capacity = params->cAxes;
+    object_flags = params->dwFlags & (DIEFF_OBJECTIDS | DIEFF_OBJECTOFFSETS);
+    direction_flags = params->dwFlags & (DIEFF_CARTESIAN | DIEFF_POLAR | DIEFF_SPHERICAL);
+
+    if (flags & DIEP_AXES)
+    {
+        if (!object_flags) return DIERR_INVALIDPARAM;
+        params->cAxes = impl->params.cAxes;
+        if (capacity < impl->params.cAxes) return DIERR_MOREDATA;
+
+        for (i = 0; i < impl->params.cAxes; ++i)
+        {
+            if (!params->rgdwAxes) return DIERR_INVALIDPARAM;
+            filter.dwObj = impl->params.rgdwAxes[i];
+            if (object_flags & DIEFF_OBJECTIDS)
+                ret = enum_objects( impl->joystick, &filter, DIDFT_AXIS, get_parameters_object_id,
+                                    &params->rgdwAxes[i] );
+            else
+                ret = enum_objects( impl->joystick, &filter, DIDFT_AXIS, get_parameters_object_ofs,
+                                    &params->rgdwAxes[i] );
+            if (ret != DIENUM_STOP) params->rgdwAxes[i] = 0;
+        }
+    }
+
+    if (flags & DIEP_DIRECTION)
+    {
+        if (!direction_flags) return DIERR_INVALIDPARAM;
+        params->dwFlags &= ~(DIEFF_CARTESIAN | DIEFF_POLAR | DIEFF_SPHERICAL);
+
+        count = params->cAxes = impl->params.cAxes;
+        if (capacity < params->cAxes) return DIERR_MOREDATA;
+        if (!count) params->dwFlags &= ~(DIEFF_CARTESIAN | DIEFF_POLAR | DIEFF_SPHERICAL);
+
+        if (direction_flags & DIEFF_SPHERICAL)
+            memcpy( directions, impl->params.rglDirection, count * sizeof(LONG) );
+        else if (direction_flags & DIEFF_POLAR)
+        {
+            if (count != 2) return DIERR_INVALIDPARAM;
+            directions[0] = (impl->params.rglDirection[0] + 9000) % 36000;
+            if (directions[0] < 0) directions[0] += 36000;
+        }
+        else if (direction_flags & DIEFF_CARTESIAN)
+        {
+            directions[0] = 10000;
+            for (i = 1; i <= count; ++i)
+            {
+                tmp = cos( impl->params.rglDirection[i - 1] * M_PI / 18000 ) * 10000;
+                for (j = 0; j < i; ++j) directions[j] = round( directions[j] * tmp / 10000.0 );
+                directions[i] = sin( impl->params.rglDirection[i - 1] * M_PI / 18000 ) * 10000;
+            }
+        }
+
+        if (!params->rglDirection) return DIERR_INVALIDPARAM;
+        else memcpy( params->rglDirection, directions, count * sizeof(LONG) );
+    }
+
+    if (flags & DIEP_TYPESPECIFICPARAMS)
+    {
+        switch (impl->type)
+        {
+        case PID_USAGE_ET_SQUARE:
+        case PID_USAGE_ET_SINE:
+        case PID_USAGE_ET_TRIANGLE:
+        case PID_USAGE_ET_SAWTOOTH_UP:
+        case PID_USAGE_ET_SAWTOOTH_DOWN:
+            if (!params->lpvTypeSpecificParams) return E_POINTER;
+            if (params->cbTypeSpecificParams != sizeof(DIPERIODIC)) return DIERR_INVALIDPARAM;
+            memcpy( params->lpvTypeSpecificParams, &impl->periodic, sizeof(DIPERIODIC) );
+            break;
+        case PID_USAGE_ET_SPRING:
+        case PID_USAGE_ET_DAMPER:
+        case PID_USAGE_ET_INERTIA:
+        case PID_USAGE_ET_FRICTION:
+        case PID_USAGE_ET_CONSTANT_FORCE:
+        case PID_USAGE_ET_RAMP:
+        case PID_USAGE_ET_CUSTOM_FORCE_DATA:
+            FIXME( "DIEP_TYPESPECIFICPARAMS not implemented!\n" );
+            return DIERR_UNSUPPORTED;
+        }
+    }
+
+    if (flags & DIEP_ENVELOPE)
+    {
+        if (!params->lpEnvelope) return E_POINTER;
+        if (params->lpEnvelope->dwSize != sizeof(DIENVELOPE)) return DIERR_INVALIDPARAM;
+        memcpy( params->lpEnvelope, &impl->envelope, sizeof(DIENVELOPE) );
+    }
+
+    if (flags & DIEP_DURATION) params->dwDuration = impl->params.dwDuration;
+    if (flags & DIEP_GAIN) params->dwGain = impl->params.dwGain;
+    if (flags & DIEP_SAMPLEPERIOD) params->dwSamplePeriod = impl->params.dwSamplePeriod;
+    if (flags & DIEP_STARTDELAY) params->dwStartDelay = impl->params.dwStartDelay;
+    if (flags & DIEP_TRIGGERREPEATINTERVAL) params->dwTriggerRepeatInterval = impl->params.dwTriggerRepeatInterval;
+
+    if (flags & DIEP_TRIGGERBUTTON)
+    {
+        if (!object_flags) return DIERR_INVALIDPARAM;
+
+        filter.dwObj = impl->params.dwTriggerButton;
+        if (object_flags & DIEFF_OBJECTIDS)
+            ret = enum_objects( impl->joystick, &filter, DIDFT_BUTTON, get_parameters_object_id,
+                                &params->dwTriggerButton );
+        else
+            ret = enum_objects( impl->joystick, &filter, DIDFT_BUTTON, get_parameters_object_ofs,
+                                &params->dwTriggerButton );
+        if (ret != DIENUM_STOP) params->dwTriggerButton = -1;
+    }
+
+    return DI_OK;
 }
 
 static HRESULT WINAPI hid_joystick_effect_SetParameters( IDirectInputEffect *iface,
@@ -2296,6 +2447,13 @@ static HRESULT hid_joystick_effect_create( struct hid_joystick *joystick, IDirec
     if (!(impl->effect_control_buf = HeapAlloc( GetProcessHeap(), 0, report_len ))) goto failed;
     if (!(impl->effect_update_buf = HeapAlloc( GetProcessHeap(), 0, report_len ))) goto failed;
 
+    impl->envelope.dwSize = sizeof(DIENVELOPE);
+    impl->params.dwSize = sizeof(DIEFFECT);
+    impl->params.lpEnvelope = &impl->envelope;
+    impl->params.rgdwAxes = impl->axes;
+    impl->params.rglDirection = impl->directions;
+    impl->params.dwTriggerButton = -1;
+
     *out = &impl->IDirectInputEffect_iface;
     return DI_OK;
 
diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c
index a53502ca8d4..fc6a235617c 100644
--- a/dlls/dinput8/tests/hid.c
+++ b/dlls/dinput8/tests/hid.c
@@ -5289,17 +5289,13 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file )
         debugstr_guid( &GUID_Square ) );
 
     hr = IDirectInputEffect_GetParameters( effect, NULL, 0 );
-    todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
     hr = IDirectInputEffect_GetParameters( effect, NULL, DIEP_DURATION );
-    todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
     hr = IDirectInputEffect_GetParameters( effect, &desc, 0 );
-    todo_wine
     ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr );
     desc.dwSize = sizeof(DIEFFECT);
     hr = IDirectInputEffect_GetParameters( effect, &desc, 0 );
-    todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
 
     set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) );
@@ -5307,7 +5303,6 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file )
     ok( hr == DI_OK, "Unacquire returned: %#x\n", hr );
     set_hid_expect( file, NULL, 0 );
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DURATION );
-    todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
     set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) );
     hr = IDirectInputDevice8_Acquire( device );
@@ -5316,24 +5311,17 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file )
 
     desc.dwDuration = 0xdeadbeef;
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DURATION );
-    todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
-    todo_wine
     check_member( desc, expect_desc_init, "%u", dwDuration );
     memset( &desc, 0xcd, sizeof(desc) );
     desc.dwSize = sizeof(DIEFFECT);
     desc.dwFlags = 0;
     flags = DIEP_GAIN | DIEP_SAMPLEPERIOD | DIEP_STARTDELAY | DIEP_TRIGGERREPEATINTERVAL;
     hr = IDirectInputEffect_GetParameters( effect, &desc, flags );
-    todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
-    todo_wine
     check_member( desc, expect_desc_init, "%u", dwSamplePeriod );
-    todo_wine
     check_member( desc, expect_desc_init, "%u", dwGain );
-    todo_wine
     check_member( desc, expect_desc_init, "%u", dwStartDelay );
-    todo_wine
     check_member( desc, expect_desc_init, "%u", dwTriggerRepeatInterval );
 
     memset( &desc, 0xcd, sizeof(desc) );
@@ -5341,15 +5329,12 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file )
     desc.dwFlags = 0;
     desc.lpEnvelope = NULL;
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_ENVELOPE );
-    todo_wine
     ok( hr == E_POINTER, "GetParameters returned %#x\n", hr );
     desc.lpEnvelope = &envelope;
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_ENVELOPE );
-    todo_wine
     ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr );
     envelope.dwSize = sizeof(DIENVELOPE);
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_ENVELOPE );
-    todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
 
     desc.dwFlags = 0;
@@ -5360,58 +5345,43 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file )
     desc.cbTypeSpecificParams = 0;
     desc.lpvTypeSpecificParams = NULL;
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_ALLPARAMS );
-    todo_wine
     ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr );
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_TRIGGERBUTTON );
-    todo_wine
     ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr );
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_AXES );
-    todo_wine
     ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr );
     desc.dwFlags = DIEFF_OBJECTOFFSETS;
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION );
-    todo_wine
     ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr );
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_TRIGGERBUTTON );
-    todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
-    todo_wine
     check_member( desc, expect_desc_init, "%#x", dwTriggerButton );
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_AXES );
-    todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
     check_member( desc, expect_desc_init, "%u", cAxes );
     desc.dwFlags = DIEFF_OBJECTIDS;
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION );
-    todo_wine
     ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr );
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_TRIGGERBUTTON );
-    todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
-    todo_wine
     check_member( desc, expect_desc_init, "%#x", dwTriggerButton );
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_AXES );
-    todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
     check_member( desc, expect_desc_init, "%u", cAxes );
     desc.dwFlags |= DIEFF_CARTESIAN;
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION );
     todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
-    todo_wine
     ok( desc.dwFlags == DIEFF_OBJECTIDS, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_OBJECTIDS );
     desc.dwFlags |= DIEFF_POLAR;
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION );
-    todo_wine
     ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr );
-    todo_wine
     ok( desc.dwFlags == DIEFF_OBJECTIDS, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_OBJECTIDS );
     desc.dwFlags |= DIEFF_SPHERICAL;
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION );
     todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
     check_member( desc, expect_desc_init, "%u", cAxes );
-    todo_wine
     ok( desc.dwFlags == DIEFF_OBJECTIDS, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_OBJECTIDS );
 
     desc.dwFlags |= DIEFF_SPHERICAL;
@@ -5419,15 +5389,12 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file )
     desc.rgdwAxes = axes;
     desc.rglDirection = directions;
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_AXES | DIEP_DIRECTION );
-    todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
-    todo_wine
     check_member( desc, expect_desc_init, "%u", cAxes );
     check_member( desc, expect_desc_init, "%u", rgdwAxes[0] );
     check_member( desc, expect_desc_init, "%u", rgdwAxes[1] );
     todo_wine
     check_member( desc, expect_desc_init, "%p", rglDirection );
-    todo_wine
     ok( desc.dwFlags == DIEFF_OBJECTIDS, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_OBJECTIDS );
 
     desc.dwFlags |= DIEFF_SPHERICAL;
@@ -5435,19 +5402,12 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file )
     desc.cbTypeSpecificParams = sizeof(periodic);
     desc.lpvTypeSpecificParams = &periodic;
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_ALLPARAMS );
-    todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
-    todo_wine
     check_member( desc, expect_desc_init, "%u", dwDuration );
-    todo_wine
     check_member( desc, expect_desc_init, "%u", dwSamplePeriod );
-    todo_wine
     check_member( desc, expect_desc_init, "%u", dwGain );
-    todo_wine
     check_member( desc, expect_desc_init, "%#x", dwTriggerButton );
-    todo_wine
     check_member( desc, expect_desc_init, "%u", dwTriggerRepeatInterval );
-    todo_wine
     check_member( desc, expect_desc_init, "%u", cAxes );
     check_member( desc, expect_desc_init, "%u", rgdwAxes[0] );
     check_member( desc, expect_desc_init, "%u", rgdwAxes[1] );
@@ -5457,7 +5417,6 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file )
     check_member( desc, expect_desc_init, "%p", lpEnvelope );
     todo_wine
     check_member( desc, expect_desc_init, "%u", cbTypeSpecificParams );
-    todo_wine
     check_member( desc, expect_desc_init, "%u", dwStartDelay );
 
     set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) );
@@ -5509,7 +5468,6 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file )
 
     desc.dwTriggerButton = -1;
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DURATION );
-    todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
     todo_wine
     check_member( desc, expect_desc, "%u", dwDuration );
@@ -5538,7 +5496,6 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file )
     desc.dwDuration = 0;
     flags = DIEP_DURATION | DIEP_GAIN | DIEP_SAMPLEPERIOD | DIEP_STARTDELAY | DIEP_TRIGGERREPEATINTERVAL;
     hr = IDirectInputEffect_GetParameters( effect, &desc, flags );
-    todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
     todo_wine
     check_member( desc, expect_desc, "%u", dwDuration );
@@ -5580,7 +5537,6 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file )
     desc.lpEnvelope = &envelope;
     envelope.dwSize = sizeof(DIENVELOPE);
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_ENVELOPE );
-    todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
     todo_wine
     check_member( envelope, expect_envelope, "%u", dwAttackLevel );
@@ -5639,7 +5595,6 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file )
     todo_wine
     check_member( desc, expect_desc, "%u", cAxes );
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_AXES | DIEP_TRIGGERBUTTON );
-    todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
     todo_wine
     check_member( desc, expect_desc, "%#x", dwTriggerButton );
@@ -5654,7 +5609,6 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file )
 
     desc.dwFlags = DIEFF_OBJECTOFFSETS;
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_AXES | DIEP_TRIGGERBUTTON );
-    todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
     todo_wine
     ok( desc.dwTriggerButton == 0x30, "got %#x expected %#x\n", desc.dwTriggerButton, 0x30 );
@@ -5729,7 +5683,6 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file )
     desc.dwFlags = DIEFF_POLAR;
     desc.cAxes = 3;
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION );
-    todo_wine
     ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr );
 
     hr = IDirectInputEffect_Download( effect );
@@ -5753,7 +5706,6 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file )
     ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr );
 
     hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_TYPESPECIFICPARAMS );
-    todo_wine
     ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
     todo_wine
     check_member( periodic, expect_periodic, "%u", dwMagnitude );
-- 
2.33.0




More information about the wine-devel mailing list