[PATCH 1/2] dinput/tests: Use EnumEffects and test a supported effect

Bruno Jesus 00cpxxx at gmail.com
Tue Aug 23 17:24:10 CDT 2016


Current test is fixed to CONSTANT effect, now we enum all effects and use a valid one.

Manually tested in XP.

Signed-off-by: Bruno Jesus <00cpxxx at gmail.com>
---
 dlls/dinput/tests/joystick.c | 163 +++++++++++++++++++++++++++++++++++++------
 1 file changed, 142 insertions(+), 21 deletions(-)

diff --git a/dlls/dinput/tests/joystick.c b/dlls/dinput/tests/joystick.c
index ed74bb9..696ad69 100644
--- a/dlls/dinput/tests/joystick.c
+++ b/dlls/dinput/tests/joystick.c
@@ -155,6 +155,111 @@ static BOOL CALLBACK EnumAxes(const DIDEVICEOBJECTINSTANCEA *pdidoi, void *pCont
     return DIENUM_CONTINUE;
 }
 
+static const struct effect_id
+{
+    const GUID *guid;
+    int dieft;
+    const char *name;
+} effect_conversion[] = {
+    {&GUID_ConstantForce, DIEFT_CONSTANTFORCE, "Constant"},
+    {&GUID_RampForce,     DIEFT_RAMPFORCE,     "Ramp"},
+    {&GUID_Square,        DIEFT_PERIODIC,      "Square"},
+    {&GUID_Sine,          DIEFT_PERIODIC,      "Sine"},
+    {&GUID_Triangle,      DIEFT_PERIODIC,      "Triangle"},
+    {&GUID_SawtoothUp,    DIEFT_PERIODIC,      "Saw Tooth Up"},
+    {&GUID_SawtoothDown,  DIEFT_PERIODIC,      "Saw Tooth Down"},
+    {&GUID_Spring,        DIEFT_CONDITION,     "Spring"},
+    {&GUID_Damper,        DIEFT_CONDITION,     "Damper"},
+    {&GUID_Inertia,       DIEFT_CONDITION,     "Inertia"},
+    {&GUID_Friction,      DIEFT_CONDITION,     "Friction"},
+    {&GUID_CustomForce,   DIEFT_CUSTOMFORCE,   "Custom"}
+};
+
+static const struct effect_id* effect_from_guid(const GUID *guid)
+{
+    unsigned int i;
+    for (i = 0; i < sizeof(effect_conversion) / sizeof(effect_conversion[0]); i++)
+        if (IsEqualGUID(guid, effect_conversion[i].guid))
+            return &effect_conversion[i];
+    return NULL;
+}
+
+struct effect_enum
+{
+    DIEFFECT eff;
+    GUID guid;
+    int effect_count;
+    const char *effect_name;
+};
+
+/* The last enumerated effect will be used for force feedback testing */
+static BOOL CALLBACK EnumEffects(const DIEFFECTINFOA *lpef, void *ref)
+{
+    const struct effect_id *id = effect_from_guid(&lpef->guid);
+    static union
+    {
+        DICONSTANTFORCE constant;
+        DIPERIODIC periodic;
+        DIRAMPFORCE ramp;
+        DICONDITION condition[2];
+    } specific;
+    struct effect_enum *data = ref;
+    int type = DIDFT_GETTYPE(lpef->dwEffType);
+
+    /* Insanity check */
+    if (!id)
+    {
+        ok(0, "unsupported effect enumerated, GUID %s!\n", wine_dbgstr_guid(&lpef->guid));
+        return DIENUM_CONTINUE;
+    }
+    trace("controller supports '%s' effect\n", id->name);
+    ok(type == id->dieft, "Invalid effect type, expected 0x%x, got 0x%x\n",
+       id->dieft, lpef->dwEffType);
+
+    /* Can't use custom for test as we don't know the data format */
+    if (type == DIEFT_CUSTOMFORCE)
+        return DIENUM_CONTINUE;
+
+    data->effect_count++;
+    data->effect_name = id->name;
+    data->guid = *id->guid;
+
+    ZeroMemory(&specific, sizeof(specific));
+    switch (type)
+    {
+        case DIEFT_PERIODIC:
+            data->eff.cbTypeSpecificParams  = sizeof(specific.periodic);
+            data->eff.lpvTypeSpecificParams = &specific.periodic;
+            specific.periodic.dwMagnitude = DI_FFNOMINALMAX / 2;
+            specific.periodic.dwPeriod = DI_SECONDS; /* 1 second */
+            break;
+        case DIEFT_CONSTANTFORCE:
+            data->eff.cbTypeSpecificParams  = sizeof(specific.constant);
+            data->eff.lpvTypeSpecificParams = &specific.constant;
+            specific.constant.lMagnitude = DI_FFNOMINALMAX / 2;
+            break;
+        case DIEFT_RAMPFORCE:
+            data->eff.cbTypeSpecificParams  = sizeof(specific.ramp);
+            data->eff.lpvTypeSpecificParams = &specific.ramp;
+            specific.ramp.lStart = -DI_FFNOMINALMAX / 2;
+            specific.ramp.lEnd = +DI_FFNOMINALMAX / 2;
+            break;
+        case DIEFT_CONDITION:
+        {
+            int i;
+            data->eff.cbTypeSpecificParams  = sizeof(specific.condition);
+            data->eff.lpvTypeSpecificParams = specific.condition;
+            for (i = 0; i < 2; i++)
+            {
+                specific.condition[i].lNegativeCoefficient = -DI_FFNOMINALMAX / 2;
+                specific.condition[i].lPositiveCoefficient = +DI_FFNOMINALMAX / 2;
+            }
+            break;
+        }
+    }
+    return DIENUM_CONTINUE;
+}
+
 static const HRESULT SetCoop_null_window[16] =  {
     E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG,
     E_INVALIDARG, E_HANDLE,     E_HANDLE,     E_INVALIDARG,
@@ -188,13 +293,12 @@ static BOOL CALLBACK EnumJoysticks(const DIDEVICEINSTANCEA *lpddi, void *pvRef)
     char oldstate[248], curstate[248];
     DWORD axes[2] = {DIJOFS_X, DIJOFS_Y};
     LONG  direction[2] = {0, 0};
-    DICONSTANTFORCE force = {0};
-    DIEFFECT eff;
     LPDIRECTINPUTEFFECT effect = NULL;
     LONG cnt1, cnt2;
     HWND real_hWnd;
     HINSTANCE hInstance = GetModuleHandleW(NULL);
     DIPROPDWORD dip_gain_set, dip_gain_get;
+    struct effect_enum effect_data;
 
     ok(data->version > 0x0300, "Joysticks not supported in version 0x%04x\n", data->version);
  
@@ -394,17 +498,15 @@ static BOOL CALLBACK EnumJoysticks(const DIDEVICEINSTANCEA *lpddi, void *pvRef)
     }
 
     trace("Testing force feedback\n");
-    memset(&eff, 0, sizeof(eff));
-    eff.dwSize                = sizeof(eff);
-    eff.dwFlags               = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
-    eff.dwDuration            = INFINITE;
-    eff.dwGain                = DI_FFNOMINALMAX;
-    eff.dwTriggerButton       = DIEB_NOTRIGGER;
-    eff.cAxes                 = sizeof(axes) / sizeof(axes[0]);
-    eff.rgdwAxes              = axes;
-    eff.rglDirection          = direction;
-    eff.cbTypeSpecificParams  = sizeof(force);
-    eff.lpvTypeSpecificParams = &force;
+    ZeroMemory(&effect_data, sizeof(effect_data));
+    effect_data.eff.dwSize          = sizeof(effect_data.eff);
+    effect_data.eff.dwFlags         = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
+    effect_data.eff.dwDuration      = INFINITE;
+    effect_data.eff.dwGain          = DI_FFNOMINALMAX;
+    effect_data.eff.dwTriggerButton = DIEB_NOTRIGGER;
+    effect_data.eff.cAxes           = sizeof(axes) / sizeof(axes[0]);
+    effect_data.eff.rgdwAxes        = axes;
+    effect_data.eff.rglDirection    = direction;
 
     /* Sending effects to joystick requires
      * calling IDirectInputEffect_Initialize, which requires
@@ -427,12 +529,30 @@ static BOOL CALLBACK EnumJoysticks(const DIDEVICEINSTANCEA *lpddi, void *pvRef)
 
     cnt1 = get_refcount((IUnknown*)pJoystick);
 
+    hr = IDirectInputDevice2_EnumEffects((IDirectInputDevice2A*)pJoystick, EnumEffects, &effect_data, DIEFT_ALL);
+    ok(hr==DI_OK,"IDirectInputDevice2_EnumEffects() failed: %08x\n", hr);
+
+    /* If the controller does not support ANY effect use the constant effect to make
+     * CreateEffect fail but with the unsupported reason instead of invalid parameters. */
+    if (!effect_data.effect_count)
+    {
+        static DICONSTANTFORCE constant;
+        effect_data.guid = GUID_ConstantForce;
+        effect_data.eff.cbTypeSpecificParams  = sizeof(constant);
+        effect_data.eff.lpvTypeSpecificParams = &constant;
+        effect_data.effect_name = "Constant";
+        constant.lMagnitude = DI_FFNOMINALMAX / 2;
+
+        ok(!(caps.dwFlags & DIDC_FORCEFEEDBACK), "effect count is zero but controller supports force feedback?\n");
+    }
+
     effect = (void *)0xdeadbeef;
-    hr = IDirectInputDevice2_CreateEffect((IDirectInputDevice2A*)pJoystick, &GUID_ConstantForce,
-                                          &eff, &effect, NULL);
+    hr = IDirectInputDevice2_CreateEffect((IDirectInputDevice2A*)pJoystick, &effect_data.guid,
+                                          &effect_data.eff, &effect, NULL);
     if (caps.dwFlags & DIDC_FORCEFEEDBACK)
     {
-        trace("force feedback supported\n");
+        trace("force feedback supported with %d effects, using '%s' for test\n",
+              effect_data.effect_count, effect_data.effect_name);
         ok(hr == DI_OK, "IDirectInputDevice_CreateEffect() failed: %08x\n", hr);
         cnt2 = get_refcount((IUnknown*)pJoystick);
         ok(cnt1 == cnt2, "Ref count is wrong %d != %d\n", cnt1, cnt2);
@@ -444,9 +564,9 @@ static BOOL CALLBACK EnumJoysticks(const DIDEVICEINSTANCEA *lpddi, void *pvRef)
             GUID guid = {0};
 
             hr = IDirectInputEffect_Initialize(effect, hInstance, data->version,
-                                               &GUID_ConstantForce);
+                                               &effect_data.guid);
             ok(hr==DI_OK,"IDirectInputEffect_Initialize failed: %08x\n", hr);
-            hr = IDirectInputEffect_SetParameters(effect, &eff, DIEP_AXES | DIEP_DIRECTION |
+            hr = IDirectInputEffect_SetParameters(effect, &effect_data.eff, DIEP_AXES | DIEP_DIRECTION |
                                                   DIEP_TYPESPECIFICPARAMS);
             ok(hr==DI_OK,"IDirectInputEffect_SetParameters failed: %08x\n", hr);
             if (hr==DI_OK) {
@@ -456,7 +576,7 @@ static BOOL CALLBACK EnumJoysticks(const DIDEVICEINSTANCEA *lpddi, void *pvRef)
                 ok(hr==DI_OK,"IDirectInputDevice_Unacquire() failed: %08x\n", hr);
                 hr = IDirectInputDevice_Acquire(pJoystick);
                 ok(hr==DI_OK,"IDirectInputDevice_Acquire() failed: %08x\n", hr);
-                hr = IDirectInputEffect_SetParameters(effect, &eff, DIEP_GAIN);
+                hr = IDirectInputEffect_SetParameters(effect, &effect_data.eff, DIEP_GAIN);
                 ok(hr==DI_OK,"IDirectInputEffect_SetParameters failed: %08x\n", hr);
             }
 
@@ -480,7 +600,7 @@ static BOOL CALLBACK EnumJoysticks(const DIDEVICEINSTANCEA *lpddi, void *pvRef)
             hr = IDirectInputEffect_GetEffectStatus(effect, &effect_status);
             ok(hr==DI_OK,"IDirectInputEffect_GetEffectStatus() failed: %08x\n", hr);
             ok(effect_status==0,"IDirectInputEffect_GetEffectStatus() reported effect as started\n");
-            hr = IDirectInputEffect_SetParameters(effect, &eff, DIEP_START);
+            hr = IDirectInputEffect_SetParameters(effect, &effect_data.eff, DIEP_START);
             ok(hr==DI_OK,"IDirectInputEffect_SetParameters failed: %08x\n", hr);
             hr = IDirectInputEffect_GetEffectStatus(effect, &effect_status);
             ok(hr==DI_OK,"IDirectInputEffect_GetEffectStatus() failed: %08x\n", hr);
@@ -498,10 +618,11 @@ static BOOL CALLBACK EnumJoysticks(const DIDEVICEINSTANCEA *lpddi, void *pvRef)
             ok(hr==DI_OK,"IDirectInputEffect_Start() failed: %08x\n", hr);
             hr = IDirectInputEffect_GetEffectStatus(effect, &effect_status);
             ok(hr==DI_OK,"IDirectInputEffect_GetEffectStatus() failed: %08x\n", hr);
+            Sleep(250); /* feel the magic */
             todo_wine ok(effect_status!=0,"IDirectInputEffect_GetEffectStatus() reported effect as stopped\n");
             hr = IDirectInputEffect_GetEffectGuid(effect, &guid);
             ok(hr==DI_OK,"IDirectInputEffect_GetEffectGuid() failed: %08x\n", hr);
-            ok(IsEqualGUID(&GUID_ConstantForce, &guid), "Wrong guid returned\n");
+            ok(IsEqualGUID(&effect_data.guid, &guid), "Wrong guid returned\n");
 
             /* Check autocenter status
              * State: initially stopped
-- 
2.9.3




More information about the wine-patches mailing list