[DINPUT]
authorAmine Khaldi <amine.khaldi@reactos.org>
Sun, 29 Sep 2013 12:16:54 +0000 (12:16 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Sun, 29 Sep 2013 12:16:54 +0000 (12:16 +0000)
* Sync with Wine 1.7.1.
CORE-7469

svn path=/trunk/; revision=60446

13 files changed:
reactos/dll/directx/dinput/CMakeLists.txt
reactos/dll/directx/dinput/device.c
reactos/dll/directx/dinput/dinput_main.c
reactos/dll/directx/dinput/dinput_private.h
reactos/dll/directx/dinput/effect_linuxinput.c
reactos/dll/directx/dinput/joystick.c
reactos/dll/directx/dinput/joystick_linux.c
reactos/dll/directx/dinput/joystick_linuxinput.c
reactos/dll/directx/dinput/joystick_osx.c
reactos/dll/directx/dinput/joystick_private.h
reactos/dll/directx/dinput/keyboard.c
reactos/dll/directx/dinput/mouse.c
reactos/media/doc/README.WINE

index 7a626fc..c7d9ed2 100644 (file)
@@ -1,13 +1,9 @@
 
-remove_definitions(-D_WIN32_WINNT=0x502)
-add_definitions(-D_WIN32_WINNT=0x600)
-
 add_definitions(-D__WINESRC__)
 include_directories(${REACTOS_SOURCE_DIR}/include/reactos/wine)
-
 spec2def(dinput.dll dinput.spec ADD_IMPORTLIB)
 
-add_library(dinput SHARED
+list(APPEND SOURCE
     config.c
     data_formats.c
     device.c
@@ -19,12 +15,12 @@ add_library(dinput SHARED
     joystick_osx.c
     keyboard.c
     mouse.c
-    dinput.rc
     ${CMAKE_CURRENT_BINARY_DIR}/dinput.def)
 
+add_library(dinput SHARED ${SOURCE} dinput.rc)
 add_library(dinput_data_formats data_formats.c)
 add_dependencies(dinput_data_formats psdk)
-set_module_type(dinput win32dll UNICODE)
+set_module_type(dinput win32dll)
 target_link_libraries(dinput dxguid uuid wine)
 add_importlibs(dinput comctl32 ole32 user32 advapi32 msvcrt kernel32 ntdll)
 add_cd_file(TARGET dinput DESTINATION reactos/system32 FOR all)
index d5f6a31..bb9eae8 100644 (file)
@@ -145,13 +145,13 @@ void _dump_DIPROPHEADER(LPCDIPROPHEADER diph) {
 }
 
 void _dump_OBJECTINSTANCEA(const DIDEVICEOBJECTINSTANCEA *ddoi) {
-    TRACE("    - enumerating : %s ('%s') - %2d - 0x%08x - %s\n",
-        debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, ddoi->tszName);
+    TRACE("    - enumerating : %s ('%s') - %2d - 0x%08x - %s - 0x%x\n",
+        debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, ddoi->tszName, ddoi->dwFlags);
 }
 
 void _dump_OBJECTINSTANCEW(const DIDEVICEOBJECTINSTANCEW *ddoi) {
-    TRACE("    - enumerating : %s ('%s'), - %2d - 0x%08x - %s\n",
-        debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, debugstr_w(ddoi->tszName));
+    TRACE("    - enumerating : %s ('%s'), - %2d - 0x%08x - %s - 0x%x\n",
+        debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, debugstr_w(ddoi->tszName), ddoi->dwFlags);
 }
 
 /* This function is a helper to convert a GUID into any possible DInput GUID out there */
index 4d6b56a..6beed0e 100644 (file)
@@ -375,17 +375,17 @@ static HRESULT WINAPI IDirectInputAImpl_EnumDevices(
 
     for (i = 0; i < NB_DINPUT_DEVICES; i++) {
         if (!dinput_devices[i]->enum_deviceA) continue;
-        for (j = 0, r = -1; r != 0; j++) {
-           devInstance.dwSize = sizeof(devInstance);
-           TRACE("  - checking device %u ('%s')\n", i, dinput_devices[i]->name);
-           if ((r = dinput_devices[i]->enum_deviceA(dwDevType, dwFlags, &devInstance, This->dwVersion, j))) {
-               if (lpCallback(&devInstance,pvRef) == DIENUM_STOP)
-                   return 0;
-           }
-       }
+        for (j = 0, r = S_OK; SUCCEEDED(r); j++) {
+            devInstance.dwSize = sizeof(devInstance);
+            TRACE("  - checking device %u ('%s')\n", i, dinput_devices[i]->name);
+            r = dinput_devices[i]->enum_deviceA(dwDevType, dwFlags, &devInstance, This->dwVersion, j);
+            if (r == S_OK)
+                if (lpCallback(&devInstance,pvRef) == DIENUM_STOP)
+                    return S_OK;
+        }
     }
-    
-    return 0;
+
+    return S_OK;
 }
 /******************************************************************************
  *     IDirectInputW_EnumDevices
@@ -397,7 +397,8 @@ static HRESULT WINAPI IDirectInputWImpl_EnumDevices(
     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
     DIDEVICEINSTANCEW devInstance;
     unsigned int i;
-    int j, r;
+    int j;
+    HRESULT r;
 
     TRACE("(this=%p,0x%04x '%s',%p,%p,%04x)\n",
          This, dwDevType, _dump_DIDEVTYPE_value(dwDevType),
@@ -414,17 +415,17 @@ static HRESULT WINAPI IDirectInputWImpl_EnumDevices(
 
     for (i = 0; i < NB_DINPUT_DEVICES; i++) {
         if (!dinput_devices[i]->enum_deviceW) continue;
-        for (j = 0, r = -1; r != 0; j++) {
-           devInstance.dwSize = sizeof(devInstance);
-           TRACE("  - checking device %u ('%s')\n", i, dinput_devices[i]->name);
-           if ((r = dinput_devices[i]->enum_deviceW(dwDevType, dwFlags, &devInstance, This->dwVersion, j))) {
-               if (lpCallback(&devInstance,pvRef) == DIENUM_STOP)
-                   return 0;
-           }
-       }
+        for (j = 0, r = S_OK; SUCCEEDED(r); j++) {
+            devInstance.dwSize = sizeof(devInstance);
+            TRACE("  - checking device %u ('%s')\n", i, dinput_devices[i]->name);
+            r = dinput_devices[i]->enum_deviceW(dwDevType, dwFlags, &devInstance, This->dwVersion, j);
+            if (r == S_OK)
+                if (lpCallback(&devInstance,pvRef) == DIENUM_STOP)
+                    return S_OK;
+        }
     }
-    
-    return 0;
+
+    return S_OK;
 }
 
 static ULONG WINAPI IDirectInputAImpl_AddRef(LPDIRECTINPUT7A iface)
@@ -913,18 +914,18 @@ static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics(
     /* Enumerate all the joysticks */
     for (i = 0; i < NB_DINPUT_DEVICES; i++)
     {
-        BOOL enumSuccess;
+        HRESULT enumSuccess;
 
         if (!dinput_devices[i]->enum_deviceA) continue;
 
-        for (j = 0, enumSuccess = -1; enumSuccess != 0; j++)
+        for (j = 0, enumSuccess = S_OK; SUCCEEDED(enumSuccess); j++)
         {
             TRACE(" - checking device %u ('%s')\n", i, dinput_devices[i]->name);
 
             callbackFlags = diactionformat_priorityA(lpdiActionFormat, lpdiActionFormat->dwGenre);
             /* Default behavior is to enumerate attached game controllers */
             enumSuccess = dinput_devices[i]->enum_deviceA(DI8DEVCLASS_GAMECTRL, DIEDFL_ATTACHEDONLY | dwFlags, &didevi, This->dwVersion, j);
-            if (enumSuccess)
+            if (enumSuccess == S_OK)
             {
                 IDirectInput_CreateDevice(iface, &didevi.guidInstance, &lpdid, NULL);
 
@@ -973,18 +974,18 @@ static HRESULT WINAPI IDirectInput8WImpl_EnumDevicesBySemantics(
     /* Enumerate all the joysticks */
     for (i = 0; i < NB_DINPUT_DEVICES; i++)
     {
-        BOOL enumSuccess;
+        HRESULT enumSuccess;
 
         if (!dinput_devices[i]->enum_deviceW) continue;
 
-        for (j = 0, enumSuccess = -1; enumSuccess != 0; j++)
+        for (j = 0, enumSuccess = S_OK; SUCCEEDED(enumSuccess); j++)
         {
             TRACE(" - checking device %u ('%s')\n", i, dinput_devices[i]->name);
 
             callbackFlags = diactionformat_priorityW(lpdiActionFormat, lpdiActionFormat->dwGenre);
             /* Default behavior is to enumerate attached game controllers */
             enumSuccess = dinput_devices[i]->enum_deviceW(DI8DEVCLASS_GAMECTRL, DIEDFL_ATTACHEDONLY | dwFlags, &didevi, This->dwVersion, j);
-            if (enumSuccess)
+            if (enumSuccess == S_OK)
             {
                 IDirectInput_CreateDevice(iface, &didevi.guidInstance, &lpdid, NULL);
 
@@ -1152,7 +1153,8 @@ static HRESULT WINAPI JoyConfig8Impl_GetConfig(IDirectInputJoyConfig8 *iface, UI
 {
     IDirectInputImpl *di = impl_from_IDirectInputJoyConfig8(iface);
     UINT found = 0;
-    int i, j, r;
+    int i, j;
+    HRESULT r;
 
     FIXME("(%p)->(%d, %p, 0x%08x): semi-stub!\n", iface, id, info, flags);
 
@@ -1168,11 +1170,11 @@ static HRESULT WINAPI JoyConfig8Impl_GetConfig(IDirectInputJoyConfig8 *iface, UI
     {
         if (!dinput_devices[i]->enum_deviceA) continue;
 
-        for (j = 0, r = -1; r != 0; j++)
+        for (j = 0, r = S_OK; SUCCEEDED(r); j++)
         {
             DIDEVICEINSTANCEA dev;
             dev.dwSize = sizeof(dev);
-            if ((r = dinput_devices[i]->enum_deviceA(DI8DEVCLASS_GAMECTRL, 0, &dev, di->dwVersion, j)))
+            if ((r = dinput_devices[i]->enum_deviceA(DI8DEVCLASS_GAMECTRL, 0, &dev, di->dwVersion, j)) == S_OK)
             {
                 /* Only take into account the chosen id */
                 if (found == id)
@@ -1639,7 +1641,7 @@ void check_dinput_hooks(LPDIRECTINPUTDEVICE8W iface)
     LeaveCriticalSection(&dinput_hook_crit);
 }
 
-BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserv)
+BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved)
 {
     switch(reason)
     {
@@ -1648,6 +1650,7 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserv)
         DINPUT_instance = inst;
         break;
       case DLL_PROCESS_DETACH:
+        if (reserved) break;
         DeleteCriticalSection(&dinput_hook_crit);
         break;
     }
index f270ce9..e7b2c07 100644 (file)
@@ -55,8 +55,8 @@ struct IDirectInputImpl
 /* Function called by all devices that Wine supports */
 struct dinput_device {
     const char *name;
-    BOOL (*enum_deviceA)(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id);
-    BOOL (*enum_deviceW)(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id);
+    HRESULT (*enum_deviceA)(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id);
+    HRESULT (*enum_deviceW)(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id);
     HRESULT (*create_device)(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPVOID *pdev, int unicode);
 };
 
index 0fb183f..da1fb85 100644 (file)
@@ -43,6 +43,7 @@
 #include "dinput.h"
 
 #include "device_private.h"
+#include "joystick_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
 
@@ -66,194 +67,6 @@ static inline LinuxInputEffectImpl *impl_from_IDirectInputEffect(IDirectInputEff
     return CONTAINING_RECORD(iface, LinuxInputEffectImpl, IDirectInputEffect_iface);
 }
 
-/******************************************************************************
- *      DirectInputEffect Functional Helper
- */
-
-static DWORD _typeFromGUID(REFGUID guid)
-{
-    if (IsEqualGUID(guid, &GUID_ConstantForce)) {
-       return DIEFT_CONSTANTFORCE;
-    } else if (IsEqualGUID(guid, &GUID_Square)
-            || IsEqualGUID(guid, &GUID_Sine)
-            || IsEqualGUID(guid, &GUID_Triangle)
-            || IsEqualGUID(guid, &GUID_SawtoothUp)
-            || IsEqualGUID(guid, &GUID_SawtoothDown)) {
-       return DIEFT_PERIODIC;
-    } else if (IsEqualGUID(guid, &GUID_RampForce)) {
-       return DIEFT_RAMPFORCE;
-    } else if (IsEqualGUID(guid, &GUID_Spring)
-            || IsEqualGUID(guid, &GUID_Damper)
-            || IsEqualGUID(guid, &GUID_Inertia)
-            || IsEqualGUID(guid, &GUID_Friction)) {
-       return DIEFT_CONDITION;
-    } else if (IsEqualGUID(guid, &GUID_CustomForce)) {
-       return DIEFT_CUSTOMFORCE;
-    } else {
-        WARN("GUID (%s) is not a known force type\n", _dump_dinput_GUID(guid));
-       return 0;
-    }
-}
-
-
-/******************************************************************************
- *      DirectInputEffect debug helpers 
- */
-
-static void _dump_DIEFFECT_flags(DWORD dwFlags)
-{
-    if (TRACE_ON(dinput)) {
-        unsigned int   i;
-        static const struct {
-            DWORD       mask;
-            const char  *name;
-        } flags[] = {
-#define FE(x) { x, #x}
-            FE(DIEFF_CARTESIAN),
-            FE(DIEFF_OBJECTIDS),
-            FE(DIEFF_OBJECTOFFSETS),
-            FE(DIEFF_POLAR),
-            FE(DIEFF_SPHERICAL)
-#undef FE
-        };
-        for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++)
-            if (flags[i].mask & dwFlags)
-                TRACE("%s ", flags[i].name);
-        TRACE("\n");
-    }       
-}
-
-static void _dump_DIENVELOPE(LPCDIENVELOPE env)
-{
-    if (env->dwSize != sizeof(DIENVELOPE)) {
-        WARN("Non-standard DIENVELOPE structure size %d.\n", env->dwSize);
-    }
-    TRACE("Envelope has attack (level: %d time: %d), fade (level: %d time: %d)\n",
-         env->dwAttackLevel, env->dwAttackTime, env->dwFadeLevel, env->dwFadeTime);
-} 
-
-static void _dump_DICONSTANTFORCE(LPCDICONSTANTFORCE frc)
-{
-    TRACE("Constant force has magnitude %d\n", frc->lMagnitude);
-}
-
-static void _dump_DIPERIODIC(LPCDIPERIODIC frc)
-{
-    TRACE("Periodic force has magnitude %d, offset %d, phase %d, period %d\n",
-         frc->dwMagnitude, frc->lOffset, frc->dwPhase, frc->dwPeriod);
-}
-
-static void _dump_DIRAMPFORCE(LPCDIRAMPFORCE frc)
-{
-    TRACE("Ramp force has start %d, end %d\n",
-         frc->lStart, frc->lEnd);
-}
-
-static void _dump_DICONDITION(LPCDICONDITION frc)
-{
-    TRACE("Condition has offset %d, pos/neg coefficients %d and %d, pos/neg saturations %d and %d, deadband %d\n",
-         frc->lOffset, frc->lPositiveCoefficient, frc->lNegativeCoefficient,
-         frc->dwPositiveSaturation, frc->dwNegativeSaturation, frc->lDeadBand);
-}
-
-static void _dump_DICUSTOMFORCE(LPCDICUSTOMFORCE frc)
-{
-    unsigned int i;
-    TRACE("Custom force uses %d channels, sample period %d.  Has %d samples at %p.\n",
-         frc->cChannels, frc->dwSamplePeriod, frc->cSamples, frc->rglForceData);
-    if (frc->cSamples % frc->cChannels != 0)
-       WARN("Custom force has a non-integral samples-per-channel count!\n");
-    if (TRACE_ON(dinput)) {
-       TRACE("Custom force data (time aligned, axes in order):\n");
-       for (i = 1; i <= frc->cSamples; ++i) {
-           TRACE("%d ", frc->rglForceData[i]);
-           if (i % frc->cChannels == 0)
-               TRACE("\n");
-       }       
-    }
-}
-
-static void _dump_DIEFFECT(LPCDIEFFECT eff, REFGUID guid, DWORD dwFlags)
-{
-    unsigned int i;
-    DWORD type = _typeFromGUID(guid);
-
-    TRACE("Dumping DIEFFECT structure:\n");
-    TRACE("  - dwSize: %d\n", eff->dwSize);
-    if ((eff->dwSize != sizeof(DIEFFECT)) && (eff->dwSize != sizeof(DIEFFECT_DX5))) {
-        WARN("Non-standard DIEFFECT structure size %d\n", eff->dwSize);
-    }
-    TRACE("  - dwFlags: %d\n", eff->dwFlags);
-    TRACE("    ");
-    _dump_DIEFFECT_flags(eff->dwFlags); 
-    TRACE("  - dwDuration: %d\n", eff->dwDuration);
-    TRACE("  - dwGain: %d\n", eff->dwGain);
-
-    if (eff->dwGain > 10000)
-        WARN("dwGain is out of range (>10,000)\n");
-
-    TRACE("  - dwTriggerButton: %d\n", eff->dwTriggerButton);
-    TRACE("  - dwTriggerRepeatInterval: %d\n", eff->dwTriggerRepeatInterval);
-    TRACE("  - rglDirection: %p\n", eff->rglDirection);
-    TRACE("  - cbTypeSpecificParams: %d\n", eff->cbTypeSpecificParams);
-    TRACE("  - lpvTypeSpecificParams: %p\n", eff->lpvTypeSpecificParams);
-
-    /* Only trace some members if dwFlags indicates they have data */
-    if (dwFlags & DIEP_AXES) {
-        TRACE("  - cAxes: %d\n", eff->cAxes);
-        TRACE("  - rgdwAxes: %p\n", eff->rgdwAxes);
-
-        if (TRACE_ON(dinput) && eff->rgdwAxes) {
-            TRACE("    ");
-            for (i = 0; i < eff->cAxes; ++i)
-                TRACE("%d ", eff->rgdwAxes[i]);
-            TRACE("\n");
-        }
-    }
-
-    if (dwFlags & DIEP_ENVELOPE) {
-        TRACE("  - lpEnvelope: %p\n", eff->lpEnvelope);
-        if (eff->lpEnvelope != NULL)
-            _dump_DIENVELOPE(eff->lpEnvelope);
-    }
-
-    if (eff->dwSize > sizeof(DIEFFECT_DX5))
-        TRACE("  - dwStartDelay: %d\n", eff->dwStartDelay);
-
-    if (type == DIEFT_CONSTANTFORCE) {
-       if (eff->cbTypeSpecificParams != sizeof(DICONSTANTFORCE)) {
-           WARN("Effect claims to be a constant force but the type-specific params are the wrong size!\n"); 
-       } else {
-           _dump_DICONSTANTFORCE(eff->lpvTypeSpecificParams);
-       }
-    } else if (type == DIEFT_PERIODIC) { 
-        if (eff->cbTypeSpecificParams != sizeof(DIPERIODIC)) {
-            WARN("Effect claims to be a periodic force but the type-specific params are the wrong size!\n");
-        } else {
-            _dump_DIPERIODIC(eff->lpvTypeSpecificParams);
-        }
-    } else if (type == DIEFT_RAMPFORCE) {
-        if (eff->cbTypeSpecificParams != sizeof(DIRAMPFORCE)) {
-            WARN("Effect claims to be a ramp force but the type-specific params are the wrong size!\n");
-        } else {
-            _dump_DIRAMPFORCE(eff->lpvTypeSpecificParams);
-        }
-    } else if (type == DIEFT_CONDITION) { 
-        if (eff->cbTypeSpecificParams != sizeof(DICONDITION)) {
-            WARN("Effect claims to be a condition but the type-specific params are the wrong size!\n");
-        } else {
-            _dump_DICONDITION(eff->lpvTypeSpecificParams);
-        }
-    } else if (type == DIEFT_CUSTOMFORCE) {
-        if (eff->cbTypeSpecificParams != sizeof(DICUSTOMFORCE)) {
-            WARN("Effect claims to be a custom force but the type-specific params are the wrong size!\n");
-        } else {
-            _dump_DICUSTOMFORCE(eff->lpvTypeSpecificParams);
-        }
-    }
-}
-
-
 /******************************************************************************
  *      LinuxInputEffectImpl 
  */
@@ -546,12 +359,12 @@ static HRESULT WINAPI LinuxInputEffectImpl_SetParameters(
         DWORD dwFlags)
 {
     LinuxInputEffectImpl *This = impl_from_IDirectInputEffect(iface);
-    DWORD type = _typeFromGUID(&This->guid);
+    DWORD type = typeFromGUID(&This->guid);
     HRESULT retval = DI_OK;
 
     TRACE("(this=%p,%p,%d)\n", This, peff, dwFlags);
 
-    _dump_DIEFFECT(peff, &This->guid, dwFlags);
+    dump_DIEFFECT(peff, &This->guid, dwFlags);
 
     if ((dwFlags & ~DIEP_NORESTART & ~DIEP_NODOWNLOAD & ~DIEP_START) == 0) {
        /* set everything */
@@ -800,7 +613,7 @@ DECLSPEC_HIDDEN HRESULT linuxinput_create_effect(
 {
     LinuxInputEffectImpl* newEffect = HeapAlloc(GetProcessHeap(), 
        HEAP_ZERO_MEMORY, sizeof(LinuxInputEffectImpl));
-    DWORD type = _typeFromGUID(rguid);
+    DWORD type = typeFromGUID(rguid);
 
     newEffect->IDirectInputEffect_iface.lpVtbl = &LinuxInputEffectVtbl;
     newEffect->ref = 1;
@@ -869,7 +682,7 @@ DECLSPEC_HIDDEN HRESULT linuxinput_get_info_A(
        REFGUID rguid,
        LPDIEFFECTINFOA info)
 {
-    DWORD type = _typeFromGUID(rguid);
+    DWORD type = typeFromGUID(rguid);
 
     TRACE("(%d, %s, %p) type=%d\n", fd, _dump_dinput_GUID(rguid), info, type);
 
@@ -903,7 +716,7 @@ DECLSPEC_HIDDEN HRESULT linuxinput_get_info_W(
        REFGUID rguid,
        LPDIEFFECTINFOW info)
 {
-    DWORD type = _typeFromGUID(rguid);
+    DWORD type = typeFromGUID(rguid);
 
     TRACE("(%d, %s, %p) type=%d\n", fd, _dump_dinput_GUID(rguid), info, type);
 
index 539334c..875d8ac 100644 (file)
@@ -49,6 +49,184 @@ static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(JoystickGener
     return &This->base.IDirectInputDevice8W_iface;
 }
 
+DWORD typeFromGUID(REFGUID guid)
+{
+    if (IsEqualGUID(guid, &GUID_ConstantForce)) {
+        return DIEFT_CONSTANTFORCE;
+    } else if (IsEqualGUID(guid, &GUID_Square)
+            || IsEqualGUID(guid, &GUID_Sine)
+            || IsEqualGUID(guid, &GUID_Triangle)
+            || IsEqualGUID(guid, &GUID_SawtoothUp)
+            || IsEqualGUID(guid, &GUID_SawtoothDown)) {
+        return DIEFT_PERIODIC;
+    } else if (IsEqualGUID(guid, &GUID_RampForce)) {
+        return DIEFT_RAMPFORCE;
+    } else if (IsEqualGUID(guid, &GUID_Spring)
+            || IsEqualGUID(guid, &GUID_Damper)
+            || IsEqualGUID(guid, &GUID_Inertia)
+            || IsEqualGUID(guid, &GUID_Friction)) {
+        return DIEFT_CONDITION;
+    } else if (IsEqualGUID(guid, &GUID_CustomForce)) {
+        return DIEFT_CUSTOMFORCE;
+    } else {
+        WARN("GUID (%s) is not a known force type\n", _dump_dinput_GUID(guid));
+        return 0;
+    }
+}
+
+static void _dump_DIEFFECT_flags(DWORD dwFlags)
+{
+    if (TRACE_ON(dinput)) {
+        unsigned int   i;
+        static const struct {
+            DWORD       mask;
+            const char  *name;
+        } flags[] = {
+#define FE(x) { x, #x}
+            FE(DIEFF_CARTESIAN),
+            FE(DIEFF_OBJECTIDS),
+            FE(DIEFF_OBJECTOFFSETS),
+            FE(DIEFF_POLAR),
+            FE(DIEFF_SPHERICAL)
+#undef FE
+        };
+        for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++)
+            if (flags[i].mask & dwFlags)
+                TRACE("%s ", flags[i].name);
+        TRACE("\n");
+    }
+}
+
+static void _dump_DIENVELOPE(LPCDIENVELOPE env)
+{
+    if (env->dwSize != sizeof(DIENVELOPE)) {
+        WARN("Non-standard DIENVELOPE structure size %d.\n", env->dwSize);
+    }
+    TRACE("Envelope has attack (level: %d time: %d), fade (level: %d time: %d)\n",
+          env->dwAttackLevel, env->dwAttackTime, env->dwFadeLevel, env->dwFadeTime);
+}
+
+static void _dump_DICONSTANTFORCE(LPCDICONSTANTFORCE frc)
+{
+    TRACE("Constant force has magnitude %d\n", frc->lMagnitude);
+}
+
+static void _dump_DIPERIODIC(LPCDIPERIODIC frc)
+{
+    TRACE("Periodic force has magnitude %d, offset %d, phase %d, period %d\n",
+          frc->dwMagnitude, frc->lOffset, frc->dwPhase, frc->dwPeriod);
+}
+
+static void _dump_DIRAMPFORCE(LPCDIRAMPFORCE frc)
+{
+    TRACE("Ramp force has start %d, end %d\n",
+          frc->lStart, frc->lEnd);
+}
+
+static void _dump_DICONDITION(LPCDICONDITION frc)
+{
+    TRACE("Condition has offset %d, pos/neg coefficients %d and %d, pos/neg saturations %d and %d, deadband %d\n",
+          frc->lOffset, frc->lPositiveCoefficient, frc->lNegativeCoefficient,
+          frc->dwPositiveSaturation, frc->dwNegativeSaturation, frc->lDeadBand);
+}
+
+static void _dump_DICUSTOMFORCE(LPCDICUSTOMFORCE frc)
+{
+    unsigned int i;
+    TRACE("Custom force uses %d channels, sample period %d.  Has %d samples at %p.\n",
+          frc->cChannels, frc->dwSamplePeriod, frc->cSamples, frc->rglForceData);
+    if (frc->cSamples % frc->cChannels != 0)
+        WARN("Custom force has a non-integral samples-per-channel count!\n");
+    if (TRACE_ON(dinput)) {
+        TRACE("Custom force data (time aligned, axes in order):\n");
+        for (i = 1; i <= frc->cSamples; ++i) {
+            TRACE("%d ", frc->rglForceData[i]);
+            if (i % frc->cChannels == 0)
+                TRACE("\n");
+        }
+    }
+}
+
+void dump_DIEFFECT(LPCDIEFFECT eff, REFGUID guid, DWORD dwFlags)
+{
+    DWORD type = typeFromGUID(guid);
+    unsigned int i;
+
+    TRACE("Dumping DIEFFECT structure:\n");
+    TRACE("  - dwSize: %d\n", eff->dwSize);
+    if ((eff->dwSize != sizeof(DIEFFECT)) && (eff->dwSize != sizeof(DIEFFECT_DX5))) {
+        WARN("Non-standard DIEFFECT structure size %d\n", eff->dwSize);
+    }
+    TRACE("  - dwFlags: %d\n", eff->dwFlags);
+    TRACE("    ");
+    _dump_DIEFFECT_flags(eff->dwFlags);
+    TRACE("  - dwDuration: %d\n", eff->dwDuration);
+    TRACE("  - dwGain: %d\n", eff->dwGain);
+
+    if (eff->dwGain > 10000)
+        WARN("dwGain is out of range (>10,000)\n");
+
+    TRACE("  - dwTriggerButton: %d\n", eff->dwTriggerButton);
+    TRACE("  - dwTriggerRepeatInterval: %d\n", eff->dwTriggerRepeatInterval);
+    TRACE("  - rglDirection: %p\n", eff->rglDirection);
+    TRACE("  - cbTypeSpecificParams: %d\n", eff->cbTypeSpecificParams);
+    TRACE("  - lpvTypeSpecificParams: %p\n", eff->lpvTypeSpecificParams);
+
+    /* Only trace some members if dwFlags indicates they have data */
+    if (dwFlags & DIEP_AXES) {
+        TRACE("  - cAxes: %d\n", eff->cAxes);
+        TRACE("  - rgdwAxes: %p\n", eff->rgdwAxes);
+
+        if (TRACE_ON(dinput) && eff->rgdwAxes) {
+            TRACE("    ");
+            for (i = 0; i < eff->cAxes; ++i)
+                TRACE("%d ", eff->rgdwAxes[i]);
+            TRACE("\n");
+        }
+    }
+
+    if (dwFlags & DIEP_ENVELOPE) {
+        TRACE("  - lpEnvelope: %p\n", eff->lpEnvelope);
+        if (eff->lpEnvelope != NULL)
+            _dump_DIENVELOPE(eff->lpEnvelope);
+    }
+
+    if (eff->dwSize > sizeof(DIEFFECT_DX5))
+        TRACE("  - dwStartDelay: %d\n", eff->dwStartDelay);
+
+    if (type == DIEFT_CONSTANTFORCE) {
+        if (eff->cbTypeSpecificParams != sizeof(DICONSTANTFORCE)) {
+            WARN("Effect claims to be a constant force but the type-specific params are the wrong size!\n");
+        } else {
+            _dump_DICONSTANTFORCE(eff->lpvTypeSpecificParams);
+        }
+    } else if (type == DIEFT_PERIODIC) {
+        if (eff->cbTypeSpecificParams != sizeof(DIPERIODIC)) {
+            WARN("Effect claims to be a periodic force but the type-specific params are the wrong size!\n");
+        } else {
+            _dump_DIPERIODIC(eff->lpvTypeSpecificParams);
+        }
+    } else if (type == DIEFT_RAMPFORCE) {
+        if (eff->cbTypeSpecificParams != sizeof(DIRAMPFORCE)) {
+            WARN("Effect claims to be a ramp force but the type-specific params are the wrong size!\n");
+        } else {
+            _dump_DIRAMPFORCE(eff->lpvTypeSpecificParams);
+        }
+    } else if (type == DIEFT_CONDITION) {
+        if (eff->cbTypeSpecificParams != sizeof(DICONDITION)) {
+            WARN("Effect claims to be a condition but the type-specific params are the wrong size!\n");
+        } else {
+            _dump_DICONDITION(eff->lpvTypeSpecificParams);
+        }
+    } else if (type == DIEFT_CUSTOMFORCE) {
+        if (eff->cbTypeSpecificParams != sizeof(DICUSTOMFORCE)) {
+            WARN("Effect claims to be a custom force but the type-specific params are the wrong size!\n");
+        } else {
+            _dump_DICUSTOMFORCE(eff->lpvTypeSpecificParams);
+        }
+    }
+}
+
 BOOL device_disabled_registry(const char* name)
 {
     static const char disabled_str[] = "disabled";
@@ -94,6 +272,7 @@ HRESULT WINAPI JoystickWGenericImpl_SetProperty(LPDIRECTINPUTDEVICE8W iface, REF
 {
     JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface);
     DWORD i;
+    ObjProps remap_props;
 
     TRACE("(%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
 
@@ -112,6 +291,28 @@ HRESULT WINAPI JoystickWGenericImpl_SetProperty(LPDIRECTINPUTDEVICE8W iface, REF
             if (ph->dwHow == DIPH_DEVICE) {
                 TRACE("proprange(%d,%d) all\n", pr->lMin, pr->lMax);
                 for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++) {
+
+                    remap_props.lDevMin = This->props[i].lMin;
+                    remap_props.lDevMax = This->props[i].lMax;
+
+                    remap_props.lDeadZone = This->props[i].lDeadZone;
+                    remap_props.lSaturation = This->props[i].lSaturation;
+
+                    remap_props.lMin = pr->lMin;
+                    remap_props.lMax = pr->lMax;
+
+                    switch (This->base.data_format.wine_df->rgodf[i].dwOfs) {
+                    case DIJOFS_X        : This->js.lX  = joystick_map_axis(&remap_props, This->js.lX); break;
+                    case DIJOFS_Y        : This->js.lY  = joystick_map_axis(&remap_props, This->js.lY); break;
+                    case DIJOFS_Z        : This->js.lZ  = joystick_map_axis(&remap_props, This->js.lZ); break;
+                    case DIJOFS_RX       : This->js.lRx = joystick_map_axis(&remap_props, This->js.lRx); break;
+                    case DIJOFS_RY       : This->js.lRy = joystick_map_axis(&remap_props, This->js.lRy); break;
+                    case DIJOFS_RZ       : This->js.lRz = joystick_map_axis(&remap_props, This->js.lRz); break;
+                    case DIJOFS_SLIDER(0): This->js.rglSlider[0] = joystick_map_axis(&remap_props, This->js.rglSlider[0]); break;
+                    case DIJOFS_SLIDER(1): This->js.rglSlider[1] = joystick_map_axis(&remap_props, This->js.rglSlider[1]); break;
+                   default: break;
+                    }
+
                     This->props[i].lMin = pr->lMin;
                     This->props[i].lMax = pr->lMax;
                 }
@@ -120,6 +321,30 @@ HRESULT WINAPI JoystickWGenericImpl_SetProperty(LPDIRECTINPUTDEVICE8W iface, REF
 
                 TRACE("proprange(%d,%d) obj=%d\n", pr->lMin, pr->lMax, obj);
                 if (obj >= 0) {
+
+                    /*ePSXe polls the joystick immediately after setting the range for calibration purposes, so the old values need to be remapped to the new range before it does so*/
+
+                    remap_props.lDevMin = This->props[obj].lMin;
+                    remap_props.lDevMax = This->props[obj].lMax;
+
+                    remap_props.lDeadZone = This->props[obj].lDeadZone;
+                    remap_props.lSaturation = This->props[obj].lSaturation;
+
+                    remap_props.lMin = pr->lMin;
+                    remap_props.lMax = pr->lMax;
+
+                    switch (ph->dwObj) {
+                    case DIJOFS_X        : This->js.lX  = joystick_map_axis(&remap_props, This->js.lX); break;
+                    case DIJOFS_Y        : This->js.lY  = joystick_map_axis(&remap_props, This->js.lY); break;
+                    case DIJOFS_Z        : This->js.lZ  = joystick_map_axis(&remap_props, This->js.lZ); break;
+                    case DIJOFS_RX       : This->js.lRx = joystick_map_axis(&remap_props, This->js.lRx); break;
+                    case DIJOFS_RY       : This->js.lRy = joystick_map_axis(&remap_props, This->js.lRy); break;
+                    case DIJOFS_RZ       : This->js.lRz = joystick_map_axis(&remap_props, This->js.lRz); break;
+                    case DIJOFS_SLIDER(0): This->js.rglSlider[0] = joystick_map_axis(&remap_props, This->js.rglSlider[0]); break;
+                    case DIJOFS_SLIDER(1): This->js.rglSlider[1] = joystick_map_axis(&remap_props, This->js.rglSlider[1]); break;
+                   default: break;
+                    }
+
                     This->props[obj].lMin = pr->lMin;
                     This->props[obj].lMax = pr->lMax;
                     return DI_OK;
index 6e444a8..f8c36d5 100644 (file)
@@ -220,15 +220,15 @@ static INT find_joystick_devices(void)
     return joystick_devices_count;
 }
 
-static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
+static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
 {
     int fd = -1;
 
-    if (id >= find_joystick_devices()) return FALSE;
+    if (id >= find_joystick_devices()) return E_FAIL;
 
     if (dwFlags & DIEDFL_FORCEFEEDBACK) {
         WARN("force feedback not supported\n");
-        return FALSE;
+        return S_FALSE;
     }
 
     if ((dwDevType == 0) ||
@@ -238,7 +238,7 @@ static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN
         if ((fd = open(joystick_devices[id].device, O_RDONLY)) < 0)
         {
             WARN("open(%s, O_RDONLY) failed: %s\n", joystick_devices[id].name, strerror(errno));
-            return FALSE;
+            return S_FALSE;
         }
 
         /* Return joystick */
@@ -257,21 +257,21 @@ static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN
         lpddi->guidFFDriver = GUID_NULL;
         close(fd);
         TRACE("Enumerating the linux Joystick device: %s (%s)\n", joystick_devices[id].device, lpddi->tszProductName);
-        return TRUE;
+        return S_OK;
     }
 
-    return FALSE;
+    return S_FALSE;
 }
 
-static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
+static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
 {
     int fd = -1;
 
-    if (id >= find_joystick_devices()) return FALSE;
+    if (id >= find_joystick_devices()) return E_FAIL;
 
     if (dwFlags & DIEDFL_FORCEFEEDBACK) {
         WARN("force feedback not supported\n");
-        return FALSE;
+        return S_FALSE;
     }
 
     if ((dwDevType == 0) ||
@@ -281,7 +281,7 @@ static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN
         if ((fd = open(joystick_devices[id].device, O_RDONLY)) < 0)
         {
             WARN("open(%s,O_RDONLY) failed: %s\n", joystick_devices[id].device, strerror(errno));
-            return FALSE;
+            return S_FALSE;
         }
 
         /* Return joystick */
@@ -299,10 +299,10 @@ static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN
         lpddi->guidFFDriver = GUID_NULL;
         close(fd);
         TRACE("Enumerating the linux Joystick device: %s (%s)\n", joystick_devices[id].device, joystick_devices[id].name);
-        return TRUE;
+        return S_OK;
     }
 
-    return FALSE;
+    return S_FALSE;
 }
 
 static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput,
index 441097d..c40f442 100644 (file)
@@ -43,7 +43,7 @@
 # include <linux/input.h>
 # undef SW_MAX
 # if defined(EVIOCGBIT) && defined(EV_ABS) && defined(BTN_PINKIE)
-#  define HAVE_CORRECT_LINUXINPUT_H
+#  define HAS_PROPER_HEADER
 # endif
 #endif
 #ifdef HAVE_SYS_POLL_H
@@ -65,7 +65,7 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
 
-#ifdef HAVE_CORRECT_LINUXINPUT_H
+#ifdef HAS_PROPER_HEADER
 
 #define EVDEVPREFIX "/dev/input/event"
 #define EVDEVDRIVER " (event)"
@@ -363,54 +363,54 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD ver
     MultiByteToWideChar(CP_ACP, 0, joydevs[id].name, -1, lpddi->tszProductName, MAX_PATH);
 }
 
-static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
+static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
 {
   find_joydevs();
 
   if (id >= have_joydevs) {
-    return FALSE;
+    return E_FAIL;
   }
 
   if (!((dwDevType == 0) ||
         ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
         (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))))
-    return FALSE;
+    return S_FALSE;
 
 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
   if (dwFlags & DIEDFL_FORCEFEEDBACK)
-    return FALSE;
+    return S_FALSE;
 #endif
 
   if (!(dwFlags & DIEDFL_FORCEFEEDBACK) || joydevs[id].has_ff) {
     fill_joystick_dideviceinstanceA(lpddi, version, id);
-    return TRUE;
+    return S_OK;
   }
-  return FALSE;
+  return S_FALSE;
 }
 
-static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
+static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
 {
   find_joydevs();
 
   if (id >= have_joydevs) {
-    return FALSE;
+    return E_FAIL;
   }
 
   if (!((dwDevType == 0) ||
         ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
         (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))))
-    return FALSE;
+    return S_FALSE;
 
 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
   if (dwFlags & DIEDFL_FORCEFEEDBACK)
-    return FALSE;
+    return S_FALSE;
 #endif
 
   if (!(dwFlags & DIEDFL_FORCEFEEDBACK) || joydevs[id].has_ff) {
     fill_joystick_dideviceinstanceW(lpddi, version, id);
-    return TRUE;
+    return S_OK;
   }
-  return FALSE;
+  return S_FALSE;
 }
 
 static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsigned short index)
@@ -445,9 +445,10 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig
     newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->base.crit");
 
     /* Count number of available axes - supported Axis & POVs */
-    for (i = 0; i < WINE_JOYSTICK_MAX_AXES; i++)
+    for (i = 0; i < ABS_MAX; i++)
     {
-        if (test_bit(newDevice->joydev->absbits, i))
+        if (i < WINE_JOYSTICK_MAX_AXES &&
+            test_bit(newDevice->joydev->absbits, i))
         {
             newDevice->generic.device_axis_count++;
             newDevice->dev_axes_to_di[i] = idx;
@@ -1477,7 +1478,7 @@ static const IDirectInputDevice8WVtbl JoystickWvt =
     IDirectInputDevice8WImpl_GetImageInfo
 };
 
-#else  /* HAVE_CORRECT_LINUXINPUT_H */
+#else  /* HAS_PROPER_HEADER */
 
 const struct dinput_device joystick_linuxinput_device = {
   "Wine Linux-input joystick driver",
@@ -1486,4 +1487,4 @@ const struct dinput_device joystick_linuxinput_device = {
   NULL
 };
 
-#endif  /* HAVE_CORRECT_LINUXINPUT_H */
+#endif  /* HAS_PROPER_HEADER */
index 8dad41b..6058cc0 100644 (file)
 //#include "wine/port.h"
 
 #if defined(HAVE_IOKIT_HID_IOHIDLIB_H)
+#define DWORD UInt32
+#define LPDWORD UInt32*
+#define LONG SInt32
+#define LPLONG SInt32*
+#define E_PENDING __carbon_E_PENDING
 #define ULONG __carbon_ULONG
 #define E_INVALIDARG __carbon_E_INVALIDARG
 #define E_OUTOFMEMORY __carbon_E_OUTOFMEMORY
@@ -44,7 +49,9 @@
 #define MAKE_HRESULT __carbon_MAKE_HRESULT
 #define HRESULT __carbon_HRESULT
 #define STDMETHODCALLTYPE __carbon_STDMETHODCALLTYPE
+#include <IOKit/IOKitLib.h>
 #include <IOKit/hid/IOHIDLib.h>
+#include <ForceFeedback/ForceFeedback.h>
 #undef ULONG
 #undef E_INVALIDARG
 #undef E_OUTOFMEMORY
 #undef MAKE_HRESULT
 #undef HRESULT
 #undef STDMETHODCALLTYPE
+#undef DWORD
+#undef LPDWORD
+#undef LONG
+#undef LPLONG
+#undef E_PENDING
 #endif /* HAVE_IOKIT_HID_IOHIDLIB_H */
 
 //#include "wine/debug.h"
@@ -98,6 +110,8 @@ struct JoystickImpl
     int                    id;
     CFMutableArrayRef      elementCFArrayRef;
     ObjProps               **propmap;
+    FFDeviceObjectReference ff;
+    struct list effects;
 };
 
 static inline JoystickImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface)
@@ -111,15 +125,116 @@ static inline JoystickImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W
            JoystickGenericImpl, base), JoystickImpl, generic);
 }
 
+typedef struct _EffectImpl {
+    IDirectInputEffect IDirectInputEffect_iface;
+    LONG ref;
+
+    JoystickImpl *device;
+    FFEffectObjectReference effect;
+    GUID guid;
+
+    struct list entry;
+} EffectImpl;
+
+static EffectImpl *impl_from_IDirectInputEffect(IDirectInputEffect *iface)
+{
+    return CONTAINING_RECORD(iface, EffectImpl, IDirectInputEffect_iface);
+}
+
+static const IDirectInputEffectVtbl EffectVtbl;
+
 static const GUID DInput_Wine_OsX_Joystick_GUID = { /* 59CAD8F6-E617-41E2-8EB7-47B23EEEDC5A */
   0x59CAD8F6, 0xE617, 0x41E2, {0x8E, 0xB7, 0x47, 0xB2, 0x3E, 0xEE, 0xDC, 0x5A}
 };
 
+static HRESULT osx_to_win32_hresult(HRESULT in)
+{
+    /* OSX returns 16-bit COM runtime errors, which we should
+     * convert to win32 */
+    switch(in){
+    case 0x80000001:
+        return E_NOTIMPL;
+    case 0x80000002:
+        return E_OUTOFMEMORY;
+    case 0x80000003:
+        return E_INVALIDARG;
+    case 0x80000004:
+        return E_NOINTERFACE;
+    case 0x80000005:
+        return E_POINTER;
+    case 0x80000006:
+        return E_HANDLE;
+    case 0x80000007:
+        return E_ABORT;
+    case 0x80000008:
+        return E_FAIL;
+    case 0x80000009:
+        return E_ACCESSDENIED;
+    case 0x8000FFFF:
+        return E_UNEXPECTED;
+    }
+    return in;
+}
+
 static void CFSetApplierFunctionCopyToCFArray(const void *value, void *context)
 {
     CFArrayAppendValue( ( CFMutableArrayRef ) context, value );
 }
 
+static IOHIDDeviceRef get_device_ref(int id)
+{
+    IOHIDElementRef tIOHIDElementRef;
+    IOHIDDeviceRef tIOHIDDeviceRef;
+
+    if (!gCollections)
+        return 0;
+
+    tIOHIDElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(gCollections, id);
+    if (!tIOHIDElementRef)
+    {
+        ERR("Invalid Element requested %i\n",id);
+        return 0;
+    }
+
+    tIOHIDDeviceRef = IOHIDElementGetDevice(tIOHIDElementRef);
+    if (!tIOHIDDeviceRef)
+    {
+        ERR("Invalid Device requested %i\n",id);
+        return 0;
+    }
+
+    return tIOHIDDeviceRef;
+}
+
+static HRESULT get_ff(IOHIDDeviceRef device, FFDeviceObjectReference *ret)
+{
+    io_service_t service;
+    CFMutableDictionaryRef matching;
+    CFTypeRef type;
+
+    matching = IOServiceMatching(kIOHIDDeviceKey);
+    if(!matching){
+        WARN("IOServiceMatching failed, force feedback disabled\n");
+        return DIERR_DEVICENOTREG;
+    }
+
+    type = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDLocationIDKey));
+    if(!matching){
+        CFRelease(matching);
+        WARN("IOHIDDeviceGetProperty failed, force feedback disabled\n");
+        return DIERR_DEVICENOTREG;
+    }
+
+    CFDictionaryAddValue(matching, CFSTR(kIOHIDLocationIDKey), type);
+
+    service = IOServiceGetMatchingService(kIOMasterPortDefault, matching);
+
+    if(!ret)
+        return FFIsForceFeedback(service) == FF_OK ? S_OK : S_FALSE;
+
+    return osx_to_win32_hresult(FFCreateDevice(service, ret));
+}
+
 static CFMutableDictionaryRef creates_osx_device_match(int usage)
 {
     CFMutableDictionaryRef result;
@@ -298,30 +413,15 @@ static int find_osx_devices(void)
 static int get_osx_device_name(int id, char *name, int length)
 {
     CFStringRef str;
-    IOHIDElementRef tIOHIDElementRef;
     IOHIDDeviceRef tIOHIDDeviceRef;
 
-    if (!gCollections)
-        return 0;
-
-    tIOHIDElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(gCollections, id);
-
-    if (!tIOHIDElementRef)
-    {
-        ERR("Invalid Element requested %i\n",id);
-        return 0;
-    }
-
-    tIOHIDDeviceRef = IOHIDElementGetDevice(tIOHIDElementRef);
+    tIOHIDDeviceRef = get_device_ref(id);
 
     if (name)
         name[0] = 0;
 
     if (!tIOHIDDeviceRef)
-    {
-        ERR("Invalid Device requested %i\n",id);
         return 0;
-    }
 
     str = IOHIDDeviceGetProperty(tIOHIDDeviceRef, CFSTR( kIOHIDProductKey ));
     if (str)
@@ -651,19 +751,21 @@ static INT find_joystick_devices(void)
     return  joystick_devices_count;
 }
 
-static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
+static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
 {
-    if (id >= find_joystick_devices()) return FALSE;
-
-    if (dwFlags & DIEDFL_FORCEFEEDBACK) {
-        WARN("force feedback not supported\n");
-        return FALSE;
-    }
+    if (id >= find_joystick_devices()) return E_FAIL;
 
     if ((dwDevType == 0) ||
     ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
     (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))
     {
+        if (dwFlags & DIEDFL_FORCEFEEDBACK) {
+            IOHIDDeviceRef device = get_device_ref(id);
+            if(!device)
+                return S_FALSE;
+            if(get_ff(device, NULL) != S_OK)
+                return S_FALSE;
+        }
         /* Return joystick */
         lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
         lpddi->guidInstance.Data3 = id;
@@ -679,27 +781,29 @@ static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN
         get_osx_device_name(id, lpddi->tszProductName, MAX_PATH);
 
         lpddi->guidFFDriver = GUID_NULL;
-        return TRUE;
+        return S_OK;
     }
 
-    return FALSE;
+    return S_FALSE;
 }
 
-static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
+static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
 {
     char name[MAX_PATH];
     char friendly[32];
 
-    if (id >= find_joystick_devices()) return FALSE;
-
-    if (dwFlags & DIEDFL_FORCEFEEDBACK) {
-        WARN("force feedback not supported\n");
-        return FALSE;
-    }
+    if (id >= find_joystick_devices()) return E_FAIL;
 
     if ((dwDevType == 0) ||
     ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
     (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
+        if (dwFlags & DIEDFL_FORCEFEEDBACK) {
+            IOHIDDeviceRef device = get_device_ref(id);
+            if(!device)
+                return S_FALSE;
+            if(get_ff(device, NULL) != S_OK)
+                return S_FALSE;
+        }
         /* Return joystick */
         lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
         lpddi->guidInstance.Data3 = id;
@@ -716,16 +820,41 @@ static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN
 
         MultiByteToWideChar(CP_ACP, 0, name, -1, lpddi->tszProductName, MAX_PATH);
         lpddi->guidFFDriver = GUID_NULL;
-        return TRUE;
+        return S_OK;
+    }
+
+    return S_FALSE;
+}
+
+static const char *osx_ff_axis_name(UInt8 axis)
+{
+    static char ret[6];
+    switch(axis){
+    case FFJOFS_X:
+        return "FFJOFS_X";
+    case FFJOFS_Y:
+        return "FFJOFS_Y";
+    case FFJOFS_Z:
+        return "FFJOFS_Z";
     }
+    sprintf(ret, "%u", (unsigned int)axis);
+    return ret;
+}
 
-    return FALSE;
+static int osx_axis_has_ff(FFCAPABILITIES *ffcaps, UInt8 axis)
+{
+    int i;
+    for(i = 0; i < ffcaps->numFfAxes; ++i)
+        if(ffcaps->ffAxes[i] == axis)
+            return 1;
+    return 0;
 }
 
 static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput,
                             JoystickImpl **pdev, unsigned short index)
 {
     DWORD i;
+    IOHIDDeviceRef device;
     JoystickImpl* newDevice;
     char name[MAX_PATH];
     HRESULT hr;
@@ -733,6 +862,7 @@ static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput,
     int idx = 0;
     int axis_map[8]; /* max axes */
     int slider_count = 0;
+    FFCAPABILITIES ffcaps;
 
     TRACE("%s %p %p %hu\n", debugstr_guid(rguid), dinput, pdev, index);
 
@@ -758,6 +888,38 @@ static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput,
     newDevice->generic.name = HeapAlloc(GetProcessHeap(),0,strlen(name) + 1);
     strcpy(newDevice->generic.name, name);
 
+    list_init(&newDevice->effects);
+    device = get_device_ref(index);
+    if(get_ff(device, &newDevice->ff) == S_OK){
+        newDevice->generic.devcaps.dwFlags |= DIDC_FORCEFEEDBACK;
+
+        hr = FFDeviceGetForceFeedbackCapabilities(newDevice->ff, &ffcaps);
+        if(SUCCEEDED(hr)){
+            TRACE("FF Capabilities:\n");
+            TRACE("\tsupportedEffects: 0x%x\n", (unsigned int)ffcaps.supportedEffects);
+            TRACE("\temulatedEffects: 0x%x\n", (unsigned int)ffcaps.emulatedEffects);
+            TRACE("\tsubType: 0x%x\n", (unsigned int)ffcaps.subType);
+            TRACE("\tnumFfAxes: %u\n", (unsigned int)ffcaps.numFfAxes);
+            TRACE("\tffAxes: [");
+            for(i = 0; i < ffcaps.numFfAxes; ++i){
+                TRACE("%s", osx_ff_axis_name(ffcaps.ffAxes[i]));
+                if(i < ffcaps.numFfAxes - 1)
+                    TRACE(", ");
+            }
+            TRACE("]\n");
+            TRACE("\tstorageCapacity: %u\n", (unsigned int)ffcaps.storageCapacity);
+            TRACE("\tplaybackCapacity: %u\n", (unsigned int)ffcaps.playbackCapacity);
+        }
+
+        hr = FFDeviceSendForceFeedbackCommand(newDevice->ff, FFSFFC_RESET);
+        if(FAILED(hr))
+            WARN("FFDeviceSendForceFeedbackCommand(FFSFFC_RESET) failed: %08x\n", hr);
+
+        hr = FFDeviceSendForceFeedbackCommand(newDevice->ff, FFSFFC_SETACTUATORSON);
+        if(FAILED(hr))
+            WARN("FFDeviceSendForceFeedbackCommand(FFSFFC_SETACTUATORSON) failed: %08x\n", hr);
+    }
+
     memset(axis_map, 0, sizeof(axis_map));
     get_osx_device_elements(newDevice, axis_map);
 
@@ -786,24 +948,46 @@ static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput,
 
     for (i = 0; i < newDevice->generic.devcaps.dwAxes; i++)
     {
-        int wine_obj = -1;
+        int wine_obj = -1, has_ff = 0;
         switch (axis_map[i])
         {
-            case kHIDUsage_GD_X: wine_obj = 0; break;
-            case kHIDUsage_GD_Y: wine_obj = 1; break;
-            case kHIDUsage_GD_Z: wine_obj = 2; break;
-            case kHIDUsage_GD_Rx: wine_obj = 3; break;
-            case kHIDUsage_GD_Ry: wine_obj = 4; break;
-            case kHIDUsage_GD_Rz: wine_obj = 5; break;
+            case kHIDUsage_GD_X:
+                wine_obj = 0;
+                has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_X);
+                break;
+            case kHIDUsage_GD_Y:
+                wine_obj = 1;
+                has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_Y);
+                break;
+            case kHIDUsage_GD_Z:
+                wine_obj = 2;
+                has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_Z);
+                break;
+            case kHIDUsage_GD_Rx:
+                wine_obj = 3;
+                has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_RX);
+                break;
+            case kHIDUsage_GD_Ry:
+                wine_obj = 4;
+                has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_RY);
+                break;
+            case kHIDUsage_GD_Rz:
+                wine_obj = 5;
+                has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_RZ);
+                break;
             case kHIDUsage_GD_Slider:
                 wine_obj = 6 + slider_count;
+                has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_SLIDER(slider_count));
                 slider_count++;
                 break;
         }
         if (wine_obj < 0 ) continue;
 
         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[wine_obj], df->dwObjSize);
-        df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS;
+        df->rgodf[idx].dwType = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS;
+        if(has_ff)
+            df->rgodf[idx].dwFlags |= DIDOI_FFACTUATOR;
+        ++idx;
     }
 
     for (i = 0; i < newDevice->generic.devcaps.dwPOVs; i++)
@@ -830,7 +1014,7 @@ static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput,
     LeaveCriticalSection(&dinput->crit);
 
     newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps);
-    newDevice->generic.devcaps.dwFlags = DIDC_ATTACHED;
+    newDevice->generic.devcaps.dwFlags |= DIDC_ATTACHED;
     if (newDevice->generic.base.dinput->dwVersion >= 0x0800)
         newDevice->generic.devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
     else
@@ -934,6 +1118,174 @@ static HRESULT joydev_create_device(IDirectInputImpl *dinput, REFGUID rguid, REF
     return DIERR_DEVICENOTREG;
 }
 
+static HRESULT osx_set_autocenter(JoystickImpl *This,
+        const DIPROPDWORD *header)
+{
+    UInt32 v;
+    HRESULT hr;
+    if(!This->ff)
+        return DIERR_UNSUPPORTED;
+    v = header->dwData;
+    hr = osx_to_win32_hresult(FFDeviceSetForceFeedbackProperty(This->ff, FFPROP_AUTOCENTER, &v));
+    TRACE("returning: %08x\n", hr);
+    return hr;
+}
+
+static HRESULT osx_set_ffgain(JoystickImpl *This, const DIPROPDWORD *header)
+{
+    UInt32 v;
+    HRESULT hr;
+    if(!This->ff)
+        return DIERR_UNSUPPORTED;
+    v = header->dwData;
+    hr = osx_to_win32_hresult(FFDeviceSetForceFeedbackProperty(This->ff, FFPROP_FFGAIN, &v));
+    TRACE("returning: %08x\n", hr);
+    return hr;
+}
+
+static HRESULT WINAPI JoystickWImpl_SetProperty(IDirectInputDevice8W *iface,
+        const GUID *prop, const DIPROPHEADER *header)
+{
+    JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
+
+    TRACE("%p %s %p\n", This, debugstr_guid(prop), header);
+
+    switch(LOWORD(prop))
+    {
+    case (DWORD_PTR)DIPROP_AUTOCENTER:
+        return osx_set_autocenter(This, (const DIPROPDWORD *)header);
+    case (DWORD_PTR)DIPROP_FFGAIN:
+        return osx_set_ffgain(This, (const DIPROPDWORD *)header);
+    }
+
+    return JoystickWGenericImpl_SetProperty(iface, prop, header);
+}
+
+static HRESULT WINAPI JoystickAImpl_SetProperty(IDirectInputDevice8A *iface,
+        const GUID *prop, const DIPROPHEADER *header)
+{
+    JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
+
+    TRACE("%p %s %p\n", This, debugstr_guid(prop), header);
+
+    switch(LOWORD(prop))
+    {
+    case (DWORD_PTR)DIPROP_AUTOCENTER:
+        return osx_set_autocenter(This, (const DIPROPDWORD *)header);
+    case (DWORD_PTR)DIPROP_FFGAIN:
+        return osx_set_ffgain(This, (const DIPROPDWORD *)header);
+    }
+
+    return JoystickAGenericImpl_SetProperty(iface, prop, header);
+}
+
+static CFUUIDRef effect_win_to_mac(const GUID *effect)
+{
+#define DO_MAP(X) \
+    if(IsEqualGUID(&GUID_##X, effect)) \
+        return kFFEffectType_##X##_ID;
+    DO_MAP(ConstantForce)
+    DO_MAP(RampForce)
+    DO_MAP(Square)
+    DO_MAP(Sine)
+    DO_MAP(Triangle)
+    DO_MAP(SawtoothUp)
+    DO_MAP(SawtoothDown)
+    DO_MAP(Spring)
+    DO_MAP(Damper)
+    DO_MAP(Inertia)
+    DO_MAP(Friction)
+    DO_MAP(CustomForce)
+#undef DO_MAP
+    WARN("Unknown effect GUID! %s\n", debugstr_guid(effect));
+    return 0;
+}
+
+static HRESULT WINAPI JoystickWImpl_CreateEffect(IDirectInputDevice8W *iface,
+        const GUID *type, const DIEFFECT *params, IDirectInputEffect **out,
+        IUnknown *outer)
+{
+    JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
+    EffectImpl *effect;
+    HRESULT hr;
+
+    TRACE("%p %s %p %p %p\n", iface, debugstr_guid(type), params, out, outer);
+    dump_DIEFFECT(params, type, 0);
+
+    if(!This->ff){
+        TRACE("No force feedback support\n");
+        *out = NULL;
+        return S_OK;
+    }
+
+    if(outer)
+        WARN("aggregation not implemented\n");
+
+    effect = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
+    effect->IDirectInputEffect_iface.lpVtbl = &EffectVtbl;
+    effect->ref = 1;
+    effect->guid = *type;
+    effect->device = This;
+
+    /* Mac's FFEFFECT and Win's DIEFFECT are binary identical. */
+    hr = osx_to_win32_hresult(FFDeviceCreateEffect(This->ff,
+                effect_win_to_mac(type), (FFEFFECT*)params, &effect->effect));
+    if(FAILED(hr)){
+        WARN("FFDeviceCreateEffect failed: %08x\n", hr);
+        HeapFree(GetProcessHeap(), 0, effect);
+        return hr;
+    }
+
+    list_add_tail(&This->effects, &effect->entry);
+    *out = &effect->IDirectInputEffect_iface;
+
+    TRACE("allocated effect: %p\n", effect);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI JoystickAImpl_CreateEffect(IDirectInputDevice8A *iface,
+        const GUID *type, const DIEFFECT *params, IDirectInputEffect **out,
+        IUnknown *outer)
+{
+    JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
+
+    TRACE("%p %s %p %p %p\n", iface, debugstr_guid(type), params, out, outer);
+
+    return JoystickWImpl_CreateEffect(&This->generic.base.IDirectInputDevice8W_iface,
+            type, params, out, outer);
+}
+
+static HRESULT WINAPI JoystickWImpl_SendForceFeedbackCommand(IDirectInputDevice8W *iface,
+        DWORD flags)
+{
+    JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
+    HRESULT hr;
+
+    TRACE("%p 0x%x\n", This, flags);
+
+    if(!This->ff)
+        return DI_NOEFFECT;
+
+    hr = osx_to_win32_hresult(FFDeviceSendForceFeedbackCommand(This->ff, flags));
+    if(FAILED(hr)){
+        WARN("FFDeviceSendForceFeedbackCommand failed: %08x\n", hr);
+        return hr;
+    }
+
+    return S_OK;
+}
+
+static HRESULT WINAPI JoystickAImpl_SendForceFeedbackCommand(IDirectInputDevice8A *iface,
+        DWORD flags)
+{
+    JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
+
+    TRACE("%p 0x%x\n", This, flags);
+
+    return JoystickWImpl_SendForceFeedbackCommand(&This->generic.base.IDirectInputDevice8W_iface, flags);
+}
+
 const struct dinput_device joystick_osx_device = {
   "Wine OS X joystick driver",
   joydev_enum_deviceA,
@@ -949,7 +1301,7 @@ static const IDirectInputDevice8AVtbl JoystickAvt =
     JoystickAGenericImpl_GetCapabilities,
     IDirectInputDevice2AImpl_EnumObjects,
     JoystickAGenericImpl_GetProperty,
-    JoystickAGenericImpl_SetProperty,
+    JoystickAImpl_SetProperty,
     IDirectInputDevice2AImpl_Acquire,
     IDirectInputDevice2AImpl_Unacquire,
     JoystickAGenericImpl_GetDeviceState,
@@ -961,11 +1313,11 @@ static const IDirectInputDevice8AVtbl JoystickAvt =
     JoystickAGenericImpl_GetDeviceInfo,
     IDirectInputDevice2AImpl_RunControlPanel,
     IDirectInputDevice2AImpl_Initialize,
-    IDirectInputDevice2AImpl_CreateEffect,
+    JoystickAImpl_CreateEffect,
     IDirectInputDevice2AImpl_EnumEffects,
     IDirectInputDevice2AImpl_GetEffectInfo,
     IDirectInputDevice2AImpl_GetForceFeedbackState,
-    IDirectInputDevice2AImpl_SendForceFeedbackCommand,
+    JoystickAImpl_SendForceFeedbackCommand,
     IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
     IDirectInputDevice2AImpl_Escape,
     JoystickAGenericImpl_Poll,
@@ -985,7 +1337,7 @@ static const IDirectInputDevice8WVtbl JoystickWvt =
     JoystickWGenericImpl_GetCapabilities,
     IDirectInputDevice2WImpl_EnumObjects,
     JoystickWGenericImpl_GetProperty,
-    JoystickWGenericImpl_SetProperty,
+    JoystickWImpl_SetProperty,
     IDirectInputDevice2WImpl_Acquire,
     IDirectInputDevice2WImpl_Unacquire,
     JoystickWGenericImpl_GetDeviceState,
@@ -997,11 +1349,11 @@ static const IDirectInputDevice8WVtbl JoystickWvt =
     JoystickWGenericImpl_GetDeviceInfo,
     IDirectInputDevice2WImpl_RunControlPanel,
     IDirectInputDevice2WImpl_Initialize,
-    IDirectInputDevice2WImpl_CreateEffect,
+    JoystickWImpl_CreateEffect,
     IDirectInputDevice2WImpl_EnumEffects,
     IDirectInputDevice2WImpl_GetEffectInfo,
     IDirectInputDevice2WImpl_GetForceFeedbackState,
-    IDirectInputDevice2WImpl_SendForceFeedbackCommand,
+    JoystickWImpl_SendForceFeedbackCommand,
     IDirectInputDevice2WImpl_EnumCreatedEffectObjects,
     IDirectInputDevice2WImpl_Escape,
     JoystickWGenericImpl_Poll,
@@ -1013,6 +1365,137 @@ static const IDirectInputDevice8WVtbl JoystickWvt =
     IDirectInputDevice8WImpl_GetImageInfo
 };
 
+static HRESULT WINAPI effect_QueryInterface(IDirectInputEffect *iface,
+        const GUID *guid, void **out)
+{
+    EffectImpl *This = impl_from_IDirectInputEffect(iface);
+
+    TRACE("%p %s %p\n", This, debugstr_guid(guid), out);
+
+    if(IsEqualIID(guid, &IID_IDirectInputEffect)){
+        *out = iface;
+        IDirectInputEffect_AddRef(iface);
+        return S_OK;
+    }
+
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI effect_AddRef(IDirectInputEffect *iface)
+{
+    EffectImpl *This = impl_from_IDirectInputEffect(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
+    TRACE("%p, ref is now: %u\n", This, ref);
+    return ref;
+}
+
+static ULONG WINAPI effect_Release(IDirectInputEffect *iface)
+{
+    EffectImpl *This = impl_from_IDirectInputEffect(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+    TRACE("%p, ref is now: %u\n", This, ref);
+
+    if(!ref){
+        list_remove(&This->entry);
+        FFDeviceReleaseEffect(This->device->ff, This->effect);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI effect_Initialize(IDirectInputEffect *iface, HINSTANCE hinst,
+        DWORD version, const GUID *guid)
+{
+    EffectImpl *This = impl_from_IDirectInputEffect(iface);
+    TRACE("%p %p 0x%x, %s\n", This, hinst, version, debugstr_guid(guid));
+    return S_OK;
+}
+
+static HRESULT WINAPI effect_GetEffectGuid(IDirectInputEffect *iface, GUID *out)
+{
+    EffectImpl *This = impl_from_IDirectInputEffect(iface);
+    TRACE("%p %p\n", This, out);
+    *out = This->guid;
+    return S_OK;
+}
+
+static HRESULT WINAPI effect_GetParameters(IDirectInputEffect *iface,
+        DIEFFECT *effect, DWORD flags)
+{
+    EffectImpl *This = impl_from_IDirectInputEffect(iface);
+    TRACE("%p %p 0x%x\n", This, effect, flags);
+    return osx_to_win32_hresult(FFEffectGetParameters(This->effect, (FFEFFECT*)effect, flags));
+}
+
+static HRESULT WINAPI effect_SetParameters(IDirectInputEffect *iface,
+        const DIEFFECT *effect, DWORD flags)
+{
+    EffectImpl *This = impl_from_IDirectInputEffect(iface);
+    TRACE("%p %p 0x%x\n", This, effect, flags);
+    dump_DIEFFECT(effect, &This->guid, flags);
+    return osx_to_win32_hresult(FFEffectSetParameters(This->effect, (FFEFFECT*)effect, flags));
+}
+
+static HRESULT WINAPI effect_Start(IDirectInputEffect *iface, DWORD iterations,
+        DWORD flags)
+{
+    EffectImpl *This = impl_from_IDirectInputEffect(iface);
+    TRACE("%p 0x%x 0x%x\n", This, iterations, flags);
+    return osx_to_win32_hresult(FFEffectStart(This->effect, iterations, flags));
+}
+
+static HRESULT WINAPI effect_Stop(IDirectInputEffect *iface)
+{
+    EffectImpl *This = impl_from_IDirectInputEffect(iface);
+    TRACE("%p\n", This);
+    return osx_to_win32_hresult(FFEffectStop(This->effect));
+}
+
+static HRESULT WINAPI effect_GetEffectStatus(IDirectInputEffect *iface, DWORD *flags)
+{
+    EffectImpl *This = impl_from_IDirectInputEffect(iface);
+    TRACE("%p %p\n", This, flags);
+    return osx_to_win32_hresult(FFEffectGetEffectStatus(This->effect, (UInt32*)flags));
+}
+
+static HRESULT WINAPI effect_Download(IDirectInputEffect *iface)
+{
+    EffectImpl *This = impl_from_IDirectInputEffect(iface);
+    TRACE("%p\n", This);
+    return osx_to_win32_hresult(FFEffectDownload(This->effect));
+}
+
+static HRESULT WINAPI effect_Unload(IDirectInputEffect *iface)
+{
+    EffectImpl *This = impl_from_IDirectInputEffect(iface);
+    TRACE("%p\n", This);
+    return osx_to_win32_hresult(FFEffectUnload(This->effect));
+}
+
+static HRESULT WINAPI effect_Escape(IDirectInputEffect *iface, DIEFFESCAPE *escape)
+{
+    EffectImpl *This = impl_from_IDirectInputEffect(iface);
+    TRACE("%p %p\n", This, escape);
+    return osx_to_win32_hresult(FFEffectEscape(This->effect, (FFEFFESCAPE*)escape));
+}
+
+static const IDirectInputEffectVtbl EffectVtbl = {
+    effect_QueryInterface,
+    effect_AddRef,
+    effect_Release,
+    effect_Initialize,
+    effect_GetEffectGuid,
+    effect_GetParameters,
+    effect_SetParameters,
+    effect_Start,
+    effect_Stop,
+    effect_GetEffectStatus,
+    effect_Download,
+    effect_Unload,
+    effect_Escape
+};
+
 #else /* HAVE_IOHIDMANAGERCREATE */
 
 const struct dinput_device joystick_osx_device = {
index 8388f4e..947e2df 100644 (file)
@@ -98,4 +98,7 @@ HRESULT WINAPI JoystickWGenericImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface,
 HRESULT WINAPI JoystickAGenericImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface, LPDIACTIONFORMATA lpdiaf, LPCSTR lpszUserName, DWORD dwFlags) DECLSPEC_HIDDEN;
 HRESULT WINAPI JoystickWGenericImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags) DECLSPEC_HIDDEN;
 
+DWORD typeFromGUID(REFGUID guid) DECLSPEC_HIDDEN;
+void dump_DIEFFECT(LPCDIEFFECT eff, REFGUID guid, DWORD dwFlags) DECLSPEC_HIDDEN;
+
 #endif /* __WINE_DLLS_DINPUT_JOYSTICK_PRIVATE_H */
index f7cef15..27e8769 100644 (file)
@@ -185,10 +185,10 @@ static void fill_keyboard_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD ver
     memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi)));
 }
  
-static BOOL keyboarddev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
+static HRESULT keyboarddev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
 {
   if (id != 0)
-    return FALSE;
+    return E_FAIL;
 
   if ((dwDevType == 0) ||
       ((dwDevType == DIDEVTYPE_KEYBOARD) && (version < 0x0800)) ||
@@ -197,16 +197,16 @@ static BOOL keyboarddev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEI
  
     fill_keyboard_dideviceinstanceA(lpddi, version);
     
-    return TRUE;
+    return S_OK;
   }
 
-  return FALSE;
+  return S_FALSE;
 }
 
-static BOOL keyboarddev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
+static HRESULT keyboarddev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
 {
   if (id != 0)
-    return FALSE;
+    return E_FAIL;
 
   if ((dwDevType == 0) ||
       ((dwDevType == DIDEVTYPE_KEYBOARD) && (version < 0x0800)) ||
@@ -215,10 +215,10 @@ static BOOL keyboarddev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEI
 
     fill_keyboard_dideviceinstanceW(lpddi, version);
     
-    return TRUE;
+    return S_OK;
   }
 
-  return FALSE;
+  return S_FALSE;
 }
 
 static SysKeyboardImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput)
@@ -440,7 +440,7 @@ static HRESULT WINAPI SysKeyboardWImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface
     scan = DIDFT_GETINSTANCE(pdidoi->dwType);
     if (scan == DIK_PAUSE || scan == DIK_NUMLOCK) scan ^= 0x80;
     if (!GetKeyNameTextW((scan & 0x80) << 17 | (scan & 0x7f) << 16,
-                         pdidoi->tszName, sizeof(pdidoi->tszName)))
+                         pdidoi->tszName, sizeof(pdidoi->tszName)/sizeof(pdidoi->tszName[0])))
         return DIERR_OBJECTNOTFOUND;
 
     _dump_OBJECTINSTANCEW(pdidoi);
index f5bfa52..6192556 100644 (file)
@@ -159,10 +159,10 @@ static void fill_mouse_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD versio
     memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi)));
 }
 
-static BOOL mousedev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
+static HRESULT mousedev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
 {
     if (id != 0)
-        return FALSE;
+        return E_FAIL;
 
     if ((dwDevType == 0) ||
        ((dwDevType == DIDEVTYPE_MOUSE) && (version < 0x0800)) ||
@@ -171,16 +171,16 @@ static BOOL mousedev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINST
        
        fill_mouse_dideviceinstanceA(lpddi, version);
        
-       return TRUE;
+       return S_OK;
     }
     
-    return FALSE;
+    return S_FALSE;
 }
 
-static BOOL mousedev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
+static HRESULT mousedev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
 {
     if (id != 0)
-        return FALSE;
+        return E_FAIL;
 
     if ((dwDevType == 0) ||
        ((dwDevType == DIDEVTYPE_MOUSE) && (version < 0x0800)) ||
@@ -189,10 +189,10 @@ static BOOL mousedev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINST
        
        fill_mouse_dideviceinstanceW(lpddi, version);
        
-       return TRUE;
+       return S_OK;
     }
     
-    return FALSE;
+    return S_FALSE;
 }
 
 static SysMouseImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput)
index e848d6f..f09f6db 100644 (file)
@@ -28,7 +28,7 @@ reactos/tools/wpp                 # Synced to Wine-1.7.1
 The following libraries are shared with Wine.
 
 reactos/dll/directx/amstream            # Synced to Wine-1.3.37
-reactos/dll/directx/dinput              # Synced to Wine-1.5.26
+reactos/dll/directx/dinput              # Synced to Wine-1.7.1
 reactos/dll/directx/dinput8             # Synced to Wine-1.5.26
 reactos/dll/directx/dmusic              # Synced to Wine-1.5.26
 reactos/dll/directx/dplay               # Synced to Wine-1.5.26