dinput: Move gain support from effect to device

Vincent Pelletier plr.vincent at gmail.com
Thu Jan 29 14:27:29 CST 2009


Hi.

Windows supports setting force feedback effect gain at 2 levels:
- device
- effect
There is support for the former on Linux, but not for the latter.

-- 
Vincent Pelletier
-------------- next part --------------
From 1d123aa2a627723dd40821ebe6e59fdda3840015 Mon Sep 17 00:00:00 2001
From: Vincent Pelletier <plr.vincent at gmail.com>
Date: Thu, 29 Jan 2009 21:26:30 +0100
Subject: Add support for device gain.
 Remove support for effect gain, since it incorrectly used device gain,
 and there is no effect gain available on Linux.
 Add test for device gain.

---
 dlls/dinput/effect_linuxinput.c   |   10 ++----
 dlls/dinput/joystick_linuxinput.c |   37 +++++++++++++++++++++--
 dlls/dinput/tests/joystick.c      |   60 +++++++++++++++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 10 deletions(-)

diff --git a/dlls/dinput/effect_linuxinput.c b/dlls/dinput/effect_linuxinput.c
index 155d800..b309af9 100644
--- a/dlls/dinput/effect_linuxinput.c
+++ b/dlls/dinput/effect_linuxinput.c
@@ -512,12 +512,6 @@ static HRESULT WINAPI LinuxInputEffectImpl_Start(
     }
 
     event.type = EV_FF;
-
-    event.code = FF_GAIN;
-    event.value = This->gain;
-    if (write(*(This->fd), &event, sizeof(event)) == -1)
-	FIXME("Failed setting gain. Error: %d \"%s\".\n", errno, strerror(errno));
-
     event.code = This->effect.id;
     event.value = dwIterations;
     if (write(*(This->fd), &event, sizeof(event)) == -1) {
@@ -627,8 +621,10 @@ static HRESULT WINAPI LinuxInputEffectImpl_SetParameters(
 
     /* Gain and Sample Period settings are not supported by the linux
      * event system */
-    if (dwFlags & DIEP_GAIN)
+    if (dwFlags & DIEP_GAIN) {
 	This->gain = 0xFFFF * peff->dwGain / 10000;
+	TRACE("Effect gain requested but no effect gain functionality present.\n");
+    }
 
     if (dwFlags & DIEP_SAMPLEPERIOD)
 	TRACE("Sample period requested but no sample period functionality present.\n");
diff --git a/dlls/dinput/joystick_linuxinput.c b/dlls/dinput/joystick_linuxinput.c
index e1b92f7..52c031c 100644
--- a/dlls/dinput/joystick_linuxinput.c
+++ b/dlls/dinput/joystick_linuxinput.c
@@ -194,6 +194,7 @@ struct JoystickImpl
         struct list                     ff_effects;
 	int				ff_state;
 	int				ff_autocenter;
+	DWORD				ff_gain;
 };
 
 static void fake_current_js_state(JoystickImpl *ji);
@@ -461,6 +462,7 @@ static JoystickImpl *alloc_device(REFGUID rguid, const void *jvt, IDirectInputIm
        Instead, track it with ff_autocenter, and assume it's initialy
        enabled. */
     newDevice->ff_autocenter = 1;
+    newDevice->ff_gain = 10000;
     InitializeCriticalSection(&newDevice->base.crit);
     newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->base.crit");
 
@@ -670,12 +672,16 @@ static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
     }
     else
     {
+        struct input_event event;
+
+        event.type = EV_FF;
+        event.code = FF_GAIN;
+        event.value = This->ff_gain * 0xFFFF / 10000;
+        if (write(This->joyfd, &event, sizeof(event)) == -1)
+            ERR("Failed to set gain (%i): %d %s\n", This->ff_gain, errno, strerror(errno));
         if (!This->ff_autocenter)
         {
-            struct input_event event;
-
             /* Disable autocenter. */
-            event.type = EV_FF;
             event.code = FF_AUTOCENTER;
             event.value = 0;
             if (write(This->joyfd, &event, sizeof(event)) == -1)
@@ -974,6 +980,23 @@ static HRESULT WINAPI JoystickAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface,
       fake_current_js_state(This);
       break;
     }
+    case (DWORD_PTR)DIPROP_FFGAIN: {
+      LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
+
+      TRACE("DIPROP_FFGAIN(%d)\n", pd->dwData);
+      This->ff_gain = max(0, (int) pd->dwData);
+      if (This->joyfd != -1) {
+        /* Update immediately. */
+        struct input_event event;
+
+        event.type = EV_FF;
+        event.code = FF_GAIN;
+        event.value = This->ff_gain * 0xFFFF / 10000;
+        if (write(This->joyfd, &event, sizeof(event)) == -1)
+          ERR("Failed to set gain (%i): %d %s\n", This->ff_gain * 0xFFFF / 10000, errno, strerror(errno));
+      }
+      break;
+    }
     default:
       return IDirectInputDevice2AImpl_SetProperty(iface, rguid, ph);
     }
@@ -1085,6 +1108,14 @@ static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface,
         TRACE("autocenter(%d)\n", pd->dwData);
         break;
     }
+    case (DWORD_PTR) DIPROP_FFGAIN:
+    {
+        LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
+
+        pd->dwData = This->ff_gain;
+        TRACE("DIPROP_FFGAIN(%d)\n", pd->dwData);
+        break;
+    }
 
     default:
         return IDirectInputDevice2AImpl_GetProperty(iface, rguid, pdiph);
diff --git a/dlls/dinput/tests/joystick.c b/dlls/dinput/tests/joystick.c
index 371f7ee..5845596 100644
--- a/dlls/dinput/tests/joystick.c
+++ b/dlls/dinput/tests/joystick.c
@@ -330,6 +330,7 @@ static BOOL CALLBACK EnumJoysticks(
         LONG cnt1, cnt2;
         HWND real_hWnd;
         HINSTANCE hInstance = GetModuleHandle(NULL);
+        DIPROPDWORD dip_gain_set, dip_gain_get;
 
         trace("Testing force-feedback\n");
         memset(&eff, 0, sizeof(eff));
@@ -486,6 +487,65 @@ static BOOL CALLBACK EnumJoysticks(
             ok(hr==DI_OK,"IDirectInputDevice_Acquire() failed: %08x\n", hr);
             hr = IDirectInputDevice2_GetProperty(pJoystick, DIPROP_AUTOCENTER, &diprop_word.diph);
 
+            /* Device gain (DIPROP_FFGAIN).
+             * From MSDN:
+             *  0..10000 range, otherwise DIERR_INVALIDPARAM.
+             *  Can be changed even if device is acquired.
+             * Difference found by tests:
+             *  <0 is refused, >10000 is accepted
+             */
+            dip_gain_set.diph.dwSize       = sizeof(DIPROPDWORD);
+            dip_gain_set.diph.dwHeaderSize = sizeof(DIPROPHEADER);
+            dip_gain_set.diph.dwObj        = 0;
+            dip_gain_set.diph.dwHow        = DIPH_DEVICE;
+            dip_gain_set.dwData            = 10000;
+            dip_gain_get.diph.dwSize       = sizeof(DIPROPDWORD);
+            dip_gain_get.diph.dwHeaderSize = sizeof(DIPROPHEADER);
+            dip_gain_get.diph.dwObj        = 0;
+            dip_gain_get.diph.dwHow        = DIPH_DEVICE;
+            dip_gain_get.dwData            = 0;
+
+            /* Test device is acquisition (non)impact. */
+            hr = IDirectInputDevice_Unacquire(pJoystick);
+            ok(hr == DI_OK, "IDirectInputDevice_Unacquire() should have returned S_FALSE, got: %08x\n", hr);
+            dip_gain_set.dwData = 1;
+            hr = IDirectInputDevice_SetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_set.diph);
+            ok(hr==DI_OK, "IDirectInputDevice_SetProperty() failed: %08x\n", hr);
+            hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_get.diph);
+            ok(hr==DI_OK, "IDirectInputDevice_GetProperty() failed: %08x\n", hr);
+            ok(dip_gain_get.dwData==dip_gain_set.dwData, "Gain not udated: %i\n", dip_gain_get.dwData);
+            hr = IDirectInputDevice_Acquire(pJoystick);
+            ok(hr==DI_OK,"IDirectInputDevice_Acquire() failed: %08x\n", hr);
+            dip_gain_set.dwData = 2;
+            hr = IDirectInputDevice_SetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_set.diph);
+            ok(hr==DI_OK, "IDirectInputDevice_SetProperty() failed: %08x\n", hr);
+            hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_get.diph);
+            ok(hr==DI_OK, "IDirectInputDevice_GetProperty() failed: %08x\n", hr);
+            ok(dip_gain_get.dwData==dip_gain_set.dwData, "Gain not udated: %i\n", dip_gain_get.dwData);
+            /* Test range and internal clamping. */
+            dip_gain_set.dwData = -1;
+            hr = IDirectInputDevice_SetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_set.diph);
+            todo_wine ok(hr==DIERR_INVALIDPARAM, "IDirectInputDevice_SetProperty() should have returned %08x: %08x\n", DIERR_INVALIDPARAM, hr);
+            dip_gain_set.dwData = 0;
+            hr = IDirectInputDevice_SetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_set.diph);
+            ok(hr==DI_OK, "IDirectInputDevice_SetProperty() failed: %08x\n", hr);
+            hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_get.diph);
+            ok(hr==DI_OK, "IDirectInputDevice_GetProperty() failed: %08x\n", hr);
+            ok(dip_gain_get.dwData==dip_gain_set.dwData, "Gain not updated: %i\n", dip_gain_get.dwData);
+            dip_gain_set.dwData = 10000;
+            hr = IDirectInputDevice_SetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_set.diph);
+            ok(hr==DI_OK, "IDirectInputDevice_SetProperty() failed: %08x\n", hr);
+            hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_get.diph);
+            ok(hr==DI_OK, "IDirectInputDevice_GetProperty() failed: %08x\n", hr);
+            ok(dip_gain_get.dwData==dip_gain_set.dwData, "Gain not updated: %i\n", dip_gain_get.dwData);
+            /* WARNING: This call succeeds, on the contrary of what is stated on MSDN. */
+            dip_gain_set.dwData = 10001;
+            hr = IDirectInputDevice_SetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_set.diph);
+            ok(hr==DI_OK, "IDirectInputDevice_SetProperty() should have returned %08x: %08x\n", DIERR_INVALIDPARAM, hr);
+            hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_get.diph);
+            ok(hr==DI_OK, "IDirectInputDevice_GetProperty() failed: %08x\n", hr);
+            ok(dip_gain_get.dwData==dip_gain_set.dwData, "Gain not Updated: %i\n", dip_gain_get.dwData);
+
             ref = IUnknown_Release(effect);
             ok(ref == 0, "IDirectInputDevice_Release() reference count = %d\n", ref);
         }
-- 
1.5.6.5



More information about the wine-patches mailing list