[DINPUT] Sync with Wine Staging 1.9.23. CORE-12409
authorAmine Khaldi <amine.khaldi@reactos.org>
Thu, 17 Nov 2016 21:57:53 +0000 (21:57 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Thu, 17 Nov 2016 21:57:53 +0000 (21:57 +0000)
svn path=/trunk/; revision=73252

reactos/dll/directx/wine/dinput/device.c
reactos/dll/directx/wine/dinput/dinput_main.c
reactos/dll/directx/wine/dinput/effect_linuxinput.c
reactos/dll/directx/wine/dinput/joystick.c
reactos/dll/directx/wine/dinput/joystick_linux.c
reactos/dll/directx/wine/dinput/joystick_linuxinput.c
reactos/dll/directx/wine/dinput/joystick_osx.c
reactos/media/doc/README.WINE

index 5602923..d183066 100644 (file)
@@ -71,6 +71,42 @@ static void _dump_cooperativelevel_DI(DWORD dwFlags) {
     }
 }
 
+static void _dump_ObjectDataFormat_flags(DWORD dwFlags) {
+    unsigned int   i;
+    static const struct {
+        DWORD       mask;
+        const char  *name;
+    } flags[] = {
+#define FE(x) { x, #x}
+        FE(DIDOI_FFACTUATOR),
+        FE(DIDOI_FFEFFECTTRIGGER),
+        FE(DIDOI_POLLED),
+        FE(DIDOI_GUIDISUSAGE)
+#undef FE
+    };
+
+    if (!dwFlags) return;
+
+    TRACE("Flags:");
+
+    /* First the flags */
+    for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) {
+        if (flags[i].mask & dwFlags)
+        TRACE(" %s",flags[i].name);
+    }
+
+    /* Now specific values */
+#define FE(x) case x: TRACE(" "#x); break
+    switch (dwFlags & DIDOI_ASPECTMASK) {
+        FE(DIDOI_ASPECTACCEL);
+        FE(DIDOI_ASPECTFORCE);
+        FE(DIDOI_ASPECTPOSITION);
+        FE(DIDOI_ASPECTVELOCITY);
+    }
+#undef FE
+
+}
+
 static void _dump_EnumObjects_flags(DWORD dwFlags) {
     if (TRACE_ON(dinput)) {
        unsigned int   i;
@@ -215,6 +251,7 @@ void _dump_DIDATAFORMAT(const DIDATAFORMAT *df) {
         TRACE("      * dwType: 0x%08x\n", df->rgodf[i].dwType);
        TRACE("        "); _dump_EnumObjects_flags(df->rgodf[i].dwType); TRACE("\n");
         TRACE("      * dwFlags: 0x%08x\n", df->rgodf[i].dwFlags);
+       TRACE("        "); _dump_ObjectDataFormat_flags(df->rgodf[i].dwFlags); TRACE("\n");
     }
 }
 
@@ -431,16 +468,20 @@ static HRESULT create_DataFormat(LPCDIDATAFORMAT asked_format, DataFormat *forma
                      debugstr_guid(asked_format->rgodf[j].pguid),
                      _dump_dinput_GUID(asked_format->rgodf[j].pguid));
                 TRACE("       * Offset: %3d\n", asked_format->rgodf[j].dwOfs);
-                TRACE("       * dwType: %08x\n", asked_format->rgodf[j].dwType);
+                TRACE("       * dwType: 0x%08x\n", asked_format->rgodf[j].dwType);
                TRACE("         "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n");
+                TRACE("       * dwFlags: 0x%08x\n", asked_format->rgodf[j].dwFlags);
+               TRACE("         "); _dump_ObjectDataFormat_flags(asked_format->rgodf[j].dwFlags); TRACE("\n");
                
                TRACE("   - Wine  (%d) :\n", i);
                TRACE("       * GUID: %s ('%s')\n",
                       debugstr_guid(format->wine_df->rgodf[i].pguid),
                       _dump_dinput_GUID(format->wine_df->rgodf[i].pguid));
                 TRACE("       * Offset: %3d\n", format->wine_df->rgodf[i].dwOfs);
-                TRACE("       * dwType: %08x\n", format->wine_df->rgodf[i].dwType);
+                TRACE("       * dwType: 0x%08x\n", format->wine_df->rgodf[i].dwType);
                 TRACE("         "); _dump_EnumObjects_flags(format->wine_df->rgodf[i].dwType); TRACE("\n");
+                TRACE("       * dwFlags: 0x%08x\n", format->wine_df->rgodf[i].dwFlags);
+                TRACE("         "); _dump_ObjectDataFormat_flags(format->wine_df->rgodf[i].dwFlags); TRACE("\n");
                
                 if (format->wine_df->rgodf[i].dwType & DIDFT_BUTTON)
                    dt[index].size = sizeof(BYTE);
@@ -469,8 +510,10 @@ static HRESULT create_DataFormat(LPCDIDATAFORMAT asked_format, DataFormat *forma
                  debugstr_guid(asked_format->rgodf[j].pguid),
                  _dump_dinput_GUID(asked_format->rgodf[j].pguid));
             TRACE("       * Offset: %3d\n", asked_format->rgodf[j].dwOfs);
-            TRACE("       * dwType: %08x\n", asked_format->rgodf[j].dwType);
+            TRACE("       * dwType: 0x%08x\n", asked_format->rgodf[j].dwType);
            TRACE("         "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n");
+            TRACE("       * dwFlags: 0x%08x\n", asked_format->rgodf[j].dwFlags);
+           TRACE("         "); _dump_ObjectDataFormat_flags(asked_format->rgodf[j].dwFlags); TRACE("\n");
            
            if (asked_format->rgodf[j].dwType & DIDFT_BUTTON)
                dt[index].size = sizeof(BYTE);
@@ -1537,7 +1580,10 @@ HRESULT WINAPI IDirectInputDevice2WImpl_CreateEffect(LPDIRECTINPUTDEVICE8W iface
                                                      LPDIRECTINPUTEFFECT *ppdef, LPUNKNOWN pUnkOuter)
 {
     FIXME("(this=%p,%s,%p,%p,%p): stub!\n", iface, debugstr_guid(rguid), lpeff, ppdef, pUnkOuter);
-    return DI_OK;
+
+    FIXME("not available in the generic implementation\n");
+    *ppdef = NULL;
+    return DIERR_UNSUPPORTED;
 }
 
 HRESULT WINAPI IDirectInputDevice2AImpl_CreateEffect(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPCDIEFFECT lpeff,
index c63ab38..c725d63 100644 (file)
@@ -162,15 +162,26 @@ HRESULT WINAPI DECLSPEC_HOTPATCH DirectInputCreateW(HINSTANCE hinst, DWORD dwVer
     return DirectInputCreateEx(hinst, dwVersion, &IID_IDirectInput7W, (LPVOID *)ppDI, punkOuter);
 }
 
-static const char *_dump_DIDEVTYPE_value(DWORD dwDevType)
-{
-    switch (dwDevType) {
-        case 0: return "All devices";
-       case DIDEVTYPE_MOUSE: return "DIDEVTYPE_MOUSE";
-       case DIDEVTYPE_KEYBOARD: return "DIDEVTYPE_KEYBOARD";
-       case DIDEVTYPE_JOYSTICK: return "DIDEVTYPE_JOYSTICK";
-       case DIDEVTYPE_DEVICE: return "DIDEVTYPE_DEVICE";
-       default: return "Unknown";
+static const char *_dump_DIDEVTYPE_value(DWORD dwDevType, DWORD dwVersion)
+{
+    if (dwVersion < 0x0800) {
+        switch (dwDevType) {
+            case 0: return "All devices";
+            case DIDEVTYPE_MOUSE: return "DIDEVTYPE_MOUSE";
+            case DIDEVTYPE_KEYBOARD: return "DIDEVTYPE_KEYBOARD";
+            case DIDEVTYPE_JOYSTICK: return "DIDEVTYPE_JOYSTICK";
+            case DIDEVTYPE_DEVICE: return "DIDEVTYPE_DEVICE";
+            default: return "Unknown";
+        }
+    } else {
+        switch (dwDevType) {
+            case DI8DEVCLASS_ALL: return "All devices";
+            case DI8DEVCLASS_POINTER: return "DI8DEVCLASS_POINTER";
+            case DI8DEVCLASS_KEYBOARD: return "DI8DEVCLASS_KEYBOARD";
+            case DI8DEVCLASS_DEVICE: return "DI8DEVCLASS_DEVICE";
+            case DI8DEVCLASS_GAMECTRL: return "DI8DEVCLASS_GAMECTRL";
+            default: return "Unknown";
+        }
     }
 }
 
@@ -363,10 +374,11 @@ static HRESULT WINAPI IDirectInputAImpl_EnumDevices(
     IDirectInputImpl *This = impl_from_IDirectInput7A(iface);
     DIDEVICEINSTANCEA 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),
+    TRACE("(this=%p,0x%04x '%s',%p,%p,0x%04x)\n",
+         This, dwDevType, _dump_DIDEVTYPE_value(dwDevType, This->dwVersion),
          lpCallback, pvRef, dwFlags);
     _dump_EnumDevices_dwFlags(dwFlags);
 
@@ -405,8 +417,8 @@ static HRESULT WINAPI IDirectInputWImpl_EnumDevices(
     int j;
     HRESULT r;
 
-    TRACE("(this=%p,0x%04x '%s',%p,%p,%04x)\n",
-         This, dwDevType, _dump_DIDEVTYPE_value(dwDevType),
+    TRACE("(this=%p,0x%04x '%s',%p,%p,0x%04x)\n",
+         This, dwDevType, _dump_DIDEVTYPE_value(dwDevType, This->dwVersion),
          lpCallback, pvRef, dwFlags);
     _dump_EnumDevices_dwFlags(dwFlags);
 
index ad7d3ad..d3fede5 100644 (file)
@@ -72,6 +72,93 @@ static double ff_effect_direction_to_rad(unsigned int dir)
     return (dir & 0xffff) * M_PI / 0x8000;
 }
 
+static void ff_dump_effect(struct ff_effect *effect)
+{
+    const char *type = "(Unknown)", *length = "INFINITE";
+    struct ff_envelope *env = NULL;
+    double angle;
+#define FE(x) case x: type = #x; break
+    switch (effect->type)
+    {
+        FE(FF_RUMBLE);
+        FE(FF_PERIODIC);
+        FE(FF_CONSTANT);
+        FE(FF_SPRING);
+        FE(FF_FRICTION);
+        FE(FF_DAMPER);
+        FE(FF_INERTIA);
+        FE(FF_RAMP);
+    }
+#undef FE
+
+    /* rotate so 0 points right */
+    angle = 360 - ff_effect_direction_to_rad(effect->direction + 0xc000) * 180 / M_PI;
+
+    if (effect->replay.length)
+      length = wine_dbg_sprintf("%u ms", effect->replay.length);
+
+    TRACE("type 0x%x %s, id %d, direction 0x%x (source angle %.2f), time length %s, start delay %u ms\n",
+          effect->type, type, effect->id, effect->direction, angle, length, effect->replay.delay);
+    if (effect->trigger.button || effect->trigger.interval)
+        TRACE(" -> trigger button %u, re-trigger interval %u ms\n",
+              effect->trigger.button, effect->trigger.interval);
+
+    if (effect->type == FF_PERIODIC)
+    {
+        struct ff_periodic_effect *per = &effect->u.periodic;
+        const char *wave = "(Unknown)";
+#define FE(x) case x: wave = #x; break
+        switch (per->waveform)
+        {
+            FE(FF_SQUARE);
+            FE(FF_TRIANGLE);
+            FE(FF_SINE);
+            FE(FF_SAW_UP);
+            FE(FF_SAW_DOWN);
+            FE(FF_CUSTOM);
+        }
+#undef FE
+        angle = ff_effect_direction_to_rad(per->phase) * 180 / M_PI;
+        TRACE(" -> waveform 0x%x %s, period %u ms, magnitude %d, offset %d, phase 0x%x (angle %.2f), custom len %d\n",
+              per->waveform, wave, per->period, per->magnitude, per->offset, per->phase, angle, per->custom_len);
+        env = &per->envelope;
+    }
+    else if (effect->type == FF_CONSTANT)
+    {
+        struct ff_constant_effect *cons = &effect->u.constant;
+        TRACE(" -> level %d\n", cons->level);
+        env = &cons->envelope;
+    }
+    else if (effect->type == FF_RAMP)
+    {
+        struct ff_ramp_effect *ramp = &effect->u.ramp;
+        TRACE(" -> start/end level %d/%d\n", ramp->start_level, ramp->end_level);
+        env = &ramp->envelope;
+    }
+    else if (effect->type == FF_RUMBLE)
+    {
+        struct ff_rumble_effect *rumble = &effect->u.rumble;
+        TRACE(" -> strong/weak magnitude %u/%u\n", rumble->strong_magnitude, rumble->weak_magnitude);
+    }
+    else if (effect->type == FF_SPRING || effect->type == FF_FRICTION ||
+             effect->type == FF_DAMPER || effect->type == FF_INERTIA)
+    {
+        struct ff_condition_effect *cond = effect->u.condition;
+        int i;
+        for (i = 0; i < 2; i++)
+        {
+            /* format numbers here to make them align correctly */
+            TRACE(" -> [%d] right/left saturation %5u/%5u, right/left coefficient %5d/%5d,"
+                  " deadband %5u, center %5d\n", i, cond[i].right_saturation, cond[i].left_saturation,
+                  cond[i].right_coeff, cond[i].left_coeff, cond[i].deadband, cond[i].center);
+        }
+    }
+
+    if (env)
+        TRACE(" -> envelope attack length(ms)/level %u/%u, fade length(ms)/level %u/%u\n",
+              env->attack_length, env->attack_level, env->fade_length, env->fade_level);
+}
+
 /******************************************************************************
  *      LinuxInputEffectImpl 
  */
@@ -87,19 +174,37 @@ static HRESULT WINAPI LinuxInputEffectImpl_Download(
        LPDIRECTINPUTEFFECT iface)
 {
     LinuxInputEffectImpl *This = impl_from_IDirectInputEffect(iface);
+    int ret, old_effect_id;
 
     TRACE("(this=%p)\n", This);
+    ff_dump_effect(&This->effect);
 
-    if (ioctl(*(This->fd), EVIOCSFF, &This->effect) == -1) {
-       if (errno == ENOMEM) {
-           return DIERR_DEVICEFULL;
-       } else {
-            FIXME("Could not upload effect. Assuming a disconnected device %d \"%s\".\n", *This->fd, strerror(errno));
-           return DIERR_INPUTLOST;
-       }
-    }
+    old_effect_id = This->effect.id;
+    if (ioctl(*(This->fd), EVIOCSFF, &This->effect) != -1)
+        return DI_OK;
 
-    return DI_OK;
+    /* Linux kernel < 3.14 has a bug that incorrectly assigns an effect ID even
+     * on error, restore it here if that is the case. */
+    This->effect.id = old_effect_id;
+
+    switch (errno)
+    {
+        case EINVAL:
+            ret = DIERR_INVALIDPARAM;
+            break;
+        case ENOSPC:
+            ret = DIERR_DEVICEFULL;
+            break;
+        case ENOMEM:
+            ret = DIERR_OUTOFMEMORY;
+            break;
+        default:
+            ret = DIERR_INPUTLOST;
+            break;
+    }
+    TRACE("Could not upload effect to fd %d, errno %d \"%s\", returning 0x%x.\n",
+          *This->fd, errno, strerror(errno), ret);
+    return ret;
 }
 
 static HRESULT WINAPI LinuxInputEffectImpl_Escape(
@@ -131,6 +236,9 @@ static HRESULT WINAPI LinuxInputEffectImpl_GetEffectStatus(
 {
     TRACE("(this=%p,%p)\n", iface, pdwFlags);
 
+    if (!pdwFlags)
+        return E_POINTER;
+
     /* linux sends the effect status through an event.
      * that event is trapped by our parent joystick driver
      * and there is no clean way to pass it back to us. */
@@ -195,8 +303,12 @@ static HRESULT WINAPI LinuxInputEffectImpl_GetParameters(
        }
     }
 
-    if (dwFlags & DIEP_DURATION) {
-       peff->dwDuration = (DWORD)This->effect.replay.length * 1000;
+    if (dwFlags & DIEP_DURATION)
+    {
+        if (!This->effect.replay.length) /* infinite for the linux driver */
+            peff->dwDuration = INFINITE;
+        else
+            peff->dwDuration = (DWORD)This->effect.replay.length * 1000;
     }
 
     if (dwFlags & DIEP_ENVELOPE) {
@@ -227,9 +339,8 @@ static HRESULT WINAPI LinuxInputEffectImpl_GetParameters(
        peff->dwSamplePeriod = 0;
     }
 
-    if (dwFlags & DIEP_STARTDELAY) {
-       peff->dwStartDelay = This->effect.replay.delay * 1000;
-    }
+    if ((dwFlags & DIEP_STARTDELAY) && peff->dwSize > sizeof(DIEFFECT_DX5))
+        peff->dwStartDelay = This->effect.replay.delay * 1000;
 
     if (dwFlags & DIEP_TRIGGERBUTTON) {
        FIXME("LinuxInput button mapping needs redoing; for now, assuming we're using an actual joystick.\n");
@@ -409,52 +520,78 @@ static HRESULT WINAPI LinuxInputEffectImpl_SetParameters(
                /* one-axis effects must use cartesian coords */
                return DIERR_INVALIDPARAM;
            }
-       } else { /* two axes */
-           if (peff->dwFlags & DIEFF_CARTESIAN) {
-               LONG x, y;
-               if (This->first_axis_is_x) {
-                   x = peff->rglDirection[0];
-                   y = peff->rglDirection[1];
-               } else {
-                   x = peff->rglDirection[1];
-                   y = peff->rglDirection[0];
-               }
-               This->effect.direction = (int)((3 * M_PI / 2 - atan2(y, x)) * -0x7FFF / M_PI);
-           } else {
-               /* Polar and spherical are the same for 2 axes */
-               /* Precision is important here, so we do double math with exact constants */
-               This->effect.direction = (int)(((double)peff->rglDirection[0] - 90) / 35999) * 0x7FFF;
-           }
-       }
+        }
+        /* two axes */
+        else
+        {
+            if (peff->dwFlags & DIEFF_CARTESIAN)
+            {
+                LONG x, y;
+                if (This->first_axis_is_x)
+                {
+                    x = peff->rglDirection[0];
+                    y = peff->rglDirection[1];
+                }
+                else
+                {
+                    x = peff->rglDirection[1];
+                    y = peff->rglDirection[0];
+                }
+                This->effect.direction = (unsigned int)((M_PI / 2 + atan2(y, x)) * 0x8000 / M_PI);
+            }
+            else
+            {
+                /* Polar and spherical are the same for 2 axes */
+                /* Precision is important here, so we do double math with exact constants */
+                This->effect.direction = (unsigned int)(((double)peff->rglDirection[0] / 18000) * 0x8000);
+            }
+        }
     }
 
     if (dwFlags & DIEP_DURATION)
-       This->effect.replay.length = peff->dwDuration / 1000;
+    {
+        if (peff->dwDuration == INFINITE)
+            This->effect.replay.length = 0; /* infinite for the linux driver */
+        else if(peff->dwDuration > 1000)
+            This->effect.replay.length = peff->dwDuration / 1000;
+        else
+            This->effect.replay.length = 1;
+    }
 
-    if (dwFlags & DIEP_ENVELOPE) {
+    if (dwFlags & DIEP_ENVELOPE)
+    {
         struct ff_envelope* env;
-        if (This->effect.type == FF_CONSTANT) env = &This->effect.u.constant.envelope;
-        else if (This->effect.type == FF_PERIODIC) env = &This->effect.u.periodic.envelope;
-        else if (This->effect.type == FF_RAMP) env = &This->effect.u.ramp.envelope;
-        else env = NULL; 
-
-       if (peff->lpEnvelope == NULL) {
-           /* if this type had an envelope, reset it */
-           if (env) {
-               env->attack_length = 0;
-               env->attack_level = 0;
-               env->fade_length = 0;
-               env->fade_level = 0;
-           }
-       } else {
-           /* did we get passed an envelope for a type that doesn't even have one? */
-           if (!env) return DIERR_INVALIDPARAM;
-           /* copy the envelope */
-           env->attack_length = peff->lpEnvelope->dwAttackTime / 1000;
-           env->attack_level = (peff->lpEnvelope->dwAttackLevel / 10) * 32;
-           env->fade_length = peff->lpEnvelope->dwFadeTime / 1000;
-           env->fade_level = (peff->lpEnvelope->dwFadeLevel / 10) * 32;
-       }
+        if (This->effect.type == FF_CONSTANT)
+            env = &This->effect.u.constant.envelope;
+        else if (This->effect.type == FF_PERIODIC)
+            env = &This->effect.u.periodic.envelope;
+        else if (This->effect.type == FF_RAMP)
+            env = &This->effect.u.ramp.envelope;
+        else
+            env = NULL;
+
+        /* copy the envelope if it is present and the linux effect supports it */
+        if (peff->lpEnvelope && env)
+        {
+            env->attack_length = peff->lpEnvelope->dwAttackTime / 1000;
+            env->attack_level = (peff->lpEnvelope->dwAttackLevel / 10) * 32;
+            env->fade_length = peff->lpEnvelope->dwFadeTime / 1000;
+            env->fade_level = (peff->lpEnvelope->dwFadeLevel / 10) * 32;
+        }
+        /* if the dinput envelope is NULL we will clear the linux envelope */
+        else if (env)
+        {
+            env->attack_length = 0;
+            env->attack_level = 0;
+            env->fade_length = 0;
+            env->fade_level = 0;
+        }
+        else if(peff->lpEnvelope)
+        {
+            if(peff->lpEnvelope->dwAttackTime || peff->lpEnvelope->dwAttackLevel ||
+               peff->lpEnvelope->dwFadeTime || peff->lpEnvelope->dwFadeLevel)
+                WARN("Ignoring dinput envelope not supported in the linux effect\n");
+        }
     }
 
     /* Gain and Sample Period settings are not supported by the linux
@@ -468,7 +605,8 @@ static HRESULT WINAPI LinuxInputEffectImpl_SetParameters(
        TRACE("Sample period requested but no sample period functionality present.\n");
 
     if (dwFlags & DIEP_STARTDELAY)
-       This->effect.replay.delay = peff->dwStartDelay / 1000;
+    if ((dwFlags & DIEP_STARTDELAY) && peff->dwSize > sizeof(DIEFFECT_DX5))
+        This->effect.replay.delay = peff->dwStartDelay / 1000;
 
     if (dwFlags & DIEP_TRIGGERBUTTON) {
        if (peff->dwTriggerButton != -1) {
@@ -481,19 +619,30 @@ static HRESULT WINAPI LinuxInputEffectImpl_SetParameters(
     if (dwFlags & DIEP_TRIGGERREPEATINTERVAL)
        This->effect.trigger.interval = peff->dwTriggerRepeatInterval / 1000;
 
-    if (dwFlags & DIEP_TYPESPECIFICPARAMS) {
-       if (!(peff->lpvTypeSpecificParams))
-           return DIERR_INCOMPLETEEFFECT;
-       if (type == DIEFT_PERIODIC) {
-            LPCDIPERIODIC tsp;
+    if (dwFlags & DIEP_TYPESPECIFICPARAMS)
+    {
+        if (!(peff->lpvTypeSpecificParams))
+            return DIERR_INCOMPLETEEFFECT;
+
+        if (type == DIEFT_PERIODIC)
+        {
+            DIPERIODIC *tsp;
             if (peff->cbTypeSpecificParams != sizeof(DIPERIODIC))
                 return DIERR_INVALIDPARAM;
             tsp = peff->lpvTypeSpecificParams;
-           This->effect.u.periodic.magnitude = (tsp->dwMagnitude / 10) * 32;
-           This->effect.u.periodic.offset = (tsp->lOffset / 10) * 32;
-           This->effect.u.periodic.phase = (tsp->dwPhase / 9) * 8; /* == (/ 36 * 32) */
-           This->effect.u.periodic.period = tsp->dwPeriod / 1000;
-       } else if (type == DIEFT_CONSTANTFORCE) {
+
+            This->effect.u.periodic.magnitude = (tsp->dwMagnitude / 10) * 32;
+            This->effect.u.periodic.offset = (tsp->lOffset / 10) * 32;
+            /* phase ranges from 0 - 35999 in dinput and 0 - 65535 on linux */
+            This->effect.u.periodic.phase = (tsp->dwPhase / 36) * 65;
+            /* dinput uses microseconds, linux uses miliseconds */
+            if (tsp->dwPeriod <= 1000)
+                This->effect.u.periodic.period = 1;
+            else
+                This->effect.u.periodic.period = tsp->dwPeriod / 1000;
+        }
+        else if (type == DIEFT_CONSTANTFORCE)
+        {
             LPCDICONSTANTFORCE tsp;
             if (peff->cbTypeSpecificParams != sizeof(DICONSTANTFORCE))
                 return DIERR_INVALIDPARAM;
@@ -506,43 +655,49 @@ static HRESULT WINAPI LinuxInputEffectImpl_SetParameters(
             tsp = peff->lpvTypeSpecificParams;
            This->effect.u.ramp.start_level = (tsp->lStart / 10) * 32;
            This->effect.u.ramp.end_level = (tsp->lEnd / 10) * 32;
-       } else if (type == DIEFT_CONDITION) {
-            LPCDICONDITION tsp = peff->lpvTypeSpecificParams;
-            if (peff->cbTypeSpecificParams == sizeof(DICONDITION)) {
-               /* One condition block.  This needs to be rotated to direction,
-                * and expanded to separate x and y conditions. */
-               int i;
-               double factor[2], angle;
-               /* rotate so 0 points right */
-               angle = ff_effect_direction_to_rad(This->effect.direction + 0xc000);
-               factor[0] = sin(angle);
-               factor[1] = -cos(angle);
-                for (i = 0; i < 2; ++i) {
-                    This->effect.u.condition[i].center = (int)(factor[i] * (tsp->lOffset / 10) * 32);
-                    This->effect.u.condition[i].right_coeff = (int)(factor[i] * (tsp->lPositiveCoefficient / 10) * 32);
-                    This->effect.u.condition[i].left_coeff = (int)(factor[i] * (tsp->lNegativeCoefficient / 10) * 32); 
-                    This->effect.u.condition[i].right_saturation = (int)(factor[i] * (tsp->dwPositiveSaturation / 10) * 32);
-                    This->effect.u.condition[i].left_saturation = (int)(factor[i] * (tsp->dwNegativeSaturation / 10) * 32);
-                    This->effect.u.condition[i].deadband = (int)(factor[i] * (tsp->lDeadBand / 10) * 32);
-                }
-           } else if (peff->cbTypeSpecificParams == 2 * sizeof(DICONDITION)) {
-               /* Two condition blocks.  Direct parameter copy. */
-               int i;
-                for (i = 0; i < 2; ++i) {
-                   This->effect.u.condition[i].center = (tsp[i].lOffset / 10) * 32;
-                   This->effect.u.condition[i].right_coeff = (tsp[i].lPositiveCoefficient / 10) * 32;
-                   This->effect.u.condition[i].left_coeff = (tsp[i].lNegativeCoefficient / 10) * 32;
-                   This->effect.u.condition[i].right_saturation = (tsp[i].dwPositiveSaturation / 10) * 32;
-                   This->effect.u.condition[i].left_saturation = (tsp[i].dwNegativeSaturation / 10) * 32;
-                   This->effect.u.condition[i].deadband = (tsp[i].lDeadBand / 10) * 32;
-               }
-           } else {
+        }
+        else if (type == DIEFT_CONDITION)
+        {
+            DICONDITION *tsp = peff->lpvTypeSpecificParams;
+            struct ff_condition_effect *cond = This->effect.u.condition;
+            int i, j, sources;
+            double factor[2];
+
+            if (peff->cbTypeSpecificParams == sizeof(DICONDITION))
+            {
+                /* One condition block.  This needs to be rotated to direction,
+                 * and expanded to separate x and y conditions. Ensures 0 points right */
+                double angle = ff_effect_direction_to_rad(This->effect.direction + 0xc000);
+                factor[0] = sin(angle);
+                factor[1] = -cos(angle);
+                sources = 1;
+            }
+            else if (peff->cbTypeSpecificParams == 2 * sizeof(DICONDITION))
+            {
+                /* Direct parameter copy without changes */
+                factor[0] = factor[1] = 1;
+                sources = 2;
+            }
+            else
                 return DIERR_INVALIDPARAM;
-           }
-       } else {
-           FIXME("Custom force types are not supported\n");    
-           return DIERR_INVALIDPARAM;
-       }
+
+            for (i = j = 0; i < 2; ++i)
+            {
+                cond[i].center = (int)(factor[i] * (tsp[j].lOffset / 10) * 32);
+                cond[i].right_coeff = (int)(factor[i] * (tsp[j].lPositiveCoefficient / 10) * 32);
+                cond[i].left_coeff = (int)(factor[i] * (tsp[j].lNegativeCoefficient / 10) * 32);
+                cond[i].right_saturation = (int)(factor[i] * (tsp[j].dwPositiveSaturation / 10) * 65);
+                cond[i].left_saturation = (int)(factor[i] * (tsp[j].dwNegativeSaturation / 10) * 65);
+                cond[i].deadband = (int)(factor[i] * (tsp[j].lDeadBand / 10) * 32);
+                if (sources == 2)
+                    j++;
+            }
+        }
+        else
+        {
+            FIXME("Custom force types are not supported\n");
+            return DIERR_INVALIDPARAM;
+        }
     }
 
     if (!(dwFlags & DIEP_NODOWNLOAD))
index c435b1c..ef21faf 100644 (file)
@@ -213,10 +213,14 @@ void dump_DIEFFECT(LPCDIEFFECT eff, REFGUID guid, DWORD dwFlags)
             _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 {
+        if (eff->cbTypeSpecificParams == sizeof(DICONDITION)) {
             _dump_DICONDITION(eff->lpvTypeSpecificParams);
+        } else if (eff->cbTypeSpecificParams == 2 * sizeof(DICONDITION)) {
+            DICONDITION *condition = eff->lpvTypeSpecificParams;
+            _dump_DICONDITION(&condition[0]);
+            _dump_DICONDITION(&condition[1]);
+        } else {
+            WARN("Effect claims to be a condition but the type-specific params are the wrong size!\n");
         }
     } else if (type == DIEFT_CUSTOMFORCE) {
         if (eff->cbTypeSpecificParams != sizeof(DICUSTOMFORCE)) {
@@ -289,6 +293,11 @@ HRESULT WINAPI JoystickWGenericImpl_SetProperty(LPDIRECTINPUTDEVICE8W iface, REF
         case (DWORD_PTR)DIPROP_RANGE: {
             LPCDIPROPRANGE pr = (LPCDIPROPRANGE)ph;
             if (ph->dwHow == DIPH_DEVICE) {
+
+                /* Many games poll 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 */
+
                 TRACE("proprange(%d,%d) all\n", pr->lMin, pr->lMax);
                 for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++) {
 
@@ -322,8 +331,6 @@ 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;
 
@@ -333,7 +340,7 @@ HRESULT WINAPI JoystickWGenericImpl_SetProperty(LPDIRECTINPUTDEVICE8W iface, REF
                     remap_props.lMin = pr->lMin;
                     remap_props.lMax = pr->lMax;
 
-                    switch (ph->dwObj) {
+                    switch (This->base.data_format.wine_df->rgodf[obj].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;
@@ -404,7 +411,7 @@ HRESULT WINAPI JoystickAGenericImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface, REF
 void _dump_DIDEVCAPS(const DIDEVCAPS *lpDIDevCaps)
 {
     int type = GET_DIDEVICE_TYPE(lpDIDevCaps->dwDevType);
-    const char *str;
+    const char *str, *hid = "";
     TRACE("dwSize: %d\n", lpDIDevCaps->dwSize);
     TRACE("dwFlags: %08x\n", lpDIDevCaps->dwFlags);
     switch(type)
@@ -414,7 +421,6 @@ void _dump_DIDEVCAPS(const DIDEVCAPS *lpDIDevCaps)
         DEBUG_TYPE(DIDEVTYPE_MOUSE);
         DEBUG_TYPE(DIDEVTYPE_KEYBOARD);
         DEBUG_TYPE(DIDEVTYPE_JOYSTICK);
-        DEBUG_TYPE(DIDEVTYPE_HID);
         /* Direct X >= 8 definitions */
         DEBUG_TYPE(DI8DEVTYPE_DEVICE);
         DEBUG_TYPE(DI8DEVTYPE_MOUSE);
@@ -431,7 +437,10 @@ void _dump_DIDEVCAPS(const DIDEVCAPS *lpDIDevCaps)
         default: str = "UNKNOWN";
     }
 
-    TRACE("dwDevType: %08x %s\n", lpDIDevCaps->dwDevType, str);
+    if (lpDIDevCaps->dwDevType & DIDEVTYPE_HID)
+        hid = " (HID)";
+
+    TRACE("dwDevType: %08x %s%s\n", lpDIDevCaps->dwDevType, str, hid);
     TRACE("dwAxes: %d\n", lpDIDevCaps->dwAxes);
     TRACE("dwButtons: %d\n", lpDIDevCaps->dwButtons);
     TRACE("dwPOVs: %d\n", lpDIDevCaps->dwPOVs);
@@ -493,9 +502,10 @@ HRESULT WINAPI JoystickWGenericImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface,
     res = IDirectInputDevice2WImpl_GetObjectInfo(iface, pdidoi, dwObj, dwHow);
     if (res != DI_OK) return res;
 
-    if      (pdidoi->dwType & DIDFT_AXIS)
+    if (pdidoi->dwType & DIDFT_AXIS) {
         sprintfW(pdidoi->tszName, axisW, DIDFT_GETINSTANCE(pdidoi->dwType));
-    else if (pdidoi->dwType & DIDFT_POV)
+        pdidoi->dwFlags |= DIDOI_ASPECTPOSITION;
+    } else if (pdidoi->dwType & DIDFT_POV)
         sprintfW(pdidoi->tszName, povW, DIDFT_GETINSTANCE(pdidoi->dwType));
     else if (pdidoi->dwType & DIDFT_BUTTON)
         sprintfW(pdidoi->tszName, buttonW, DIDFT_GETINSTANCE(pdidoi->dwType));
@@ -575,6 +585,7 @@ HRESULT WINAPI JoystickWGenericImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REF
             }
             break;
         }
+        case (DWORD_PTR) DIPROP_PRODUCTNAME:
         case (DWORD_PTR) DIPROP_INSTANCENAME: {
             DIPROPSTRING *ps = (DIPROPSTRING*) pdiph;
             DIDEVICEINSTANCEW didev;
@@ -582,7 +593,10 @@ HRESULT WINAPI JoystickWGenericImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REF
             didev.dwSize = sizeof(didev);
 
             IDirectInputDevice_GetDeviceInfo(iface, &didev);
-            lstrcpynW(ps->wsz, didev.tszInstanceName, MAX_PATH);
+            if (LOWORD(rguid) == (DWORD_PTR) DIPROP_PRODUCTNAME)
+                lstrcpynW(ps->wsz, didev.tszProductName, MAX_PATH);
+            else
+                lstrcpynW(ps->wsz, didev.tszInstanceName, MAX_PATH);
 
             return DI_OK;
         }
index b40e11a..aba499d 100644 (file)
@@ -63,7 +63,7 @@ struct JoyDev
     BYTE button_count;
     int  *dev_axes_map;
 
-    WORD vendor_id, product_id;
+    WORD vendor_id, product_id, bus_type;
 };
 
 typedef struct JoystickImpl JoystickImpl;
@@ -122,6 +122,29 @@ static struct JoyDev *joystick_devices;
 
 static void joy_polldev(LPDIRECTINPUTDEVICE8A iface);
 
+#define SYS_PATH_FORMAT "/sys/class/input/js%d/device/id/%s"
+static BOOL read_sys_id_variable(int index, const char *property, WORD *value)
+{
+    char sys_path[sizeof(SYS_PATH_FORMAT) + 16], id_str[5];
+    int sys_fd;
+    BOOL ret = FALSE;
+
+    sprintf(sys_path, SYS_PATH_FORMAT, index, property);
+    if ((sys_fd = open(sys_path, O_RDONLY)) != -1)
+    {
+        if (read(sys_fd, id_str, 4) == 4)
+        {
+            id_str[4] = '\0';
+            *value = strtol(id_str, NULL, 16);
+            ret = TRUE;
+        }
+
+        close(sys_fd);
+    }
+    return ret;
+}
+#undef SYS_PATH_FORMAT
+
 static INT find_joystick_devices(void)
 {
     INT i;
@@ -131,16 +154,15 @@ static INT find_joystick_devices(void)
     joystick_devices_count = 0;
     for (i = 0; i < MAX_JOYSTICKS; i++)
     {
-        int fd, sys_fd;
+        int fd;
         struct JoyDev joydev, *new_joydevs;
         BYTE axes_map[ABS_MAX + 1];
-        char sys_path[sizeof("/sys/class/input/js/device/id/product") + 10], id_str[5];
 
         snprintf(joydev.device, sizeof(joydev.device), "%s%d", JOYDEV_NEW, i);
-        if ((fd = open(joydev.device, O_RDONLY)) < 0)
+        if ((fd = open(joydev.device, O_RDONLY)) == -1)
         {
             snprintf(joydev.device, sizeof(joydev.device), "%s%d", JOYDEV_OLD, i);
-            if ((fd = open(joydev.device, O_RDONLY)) < 0) continue;
+            if ((fd = open(joydev.device, O_RDONLY)) == -1) continue;
         }
 
         strcpy(joydev.name, "Wine Joystick");
@@ -205,31 +227,9 @@ static INT find_joystick_devices(void)
         joydev.vendor_id  = 0;
         joydev.product_id = 0;
 
-        sprintf(sys_path, "/sys/class/input/js%d/device/id/vendor", i);
-        sys_fd = open(sys_path, O_RDONLY);
-        if (sys_fd > 0)
-        {
-            if (read(sys_fd, id_str, 4) == 4)
-            {
-                id_str[4] = '\0';
-                joydev.vendor_id = strtol(id_str, NULL, 16);
-            }
-
-            close(sys_fd);
-        }
-
-        sprintf(sys_path, "/sys/class/input/js%d/device/id/product", i);
-        sys_fd = open(sys_path, O_RDONLY);
-        if (sys_fd > 0)
-        {
-            if (read(sys_fd, id_str, 4) == 4)
-            {
-                id_str[4] = '\0';
-                joydev.product_id = strtol(id_str, NULL, 16);
-            }
-
-            close(sys_fd);
-        }
+        read_sys_id_variable(i, "vendor", &joydev.vendor_id);
+        read_sys_id_variable(i, "product", &joydev.product_id);
+        read_sys_id_variable(i, "bustype", &joydev.bus_type);
 
         if (joydev.vendor_id == 0 || joydev.product_id == 0)
         {
@@ -261,7 +261,7 @@ static INT find_joystick_devices(void)
     return joystick_devices_count;
 }
 
-static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
+static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
 {
     DWORD dwSize = lpddi->dwSize;
 
@@ -278,33 +278,45 @@ static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD ver
         lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
     else
         lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
-    strcpy(lpddi->tszInstanceName, joystick_devices[id].name);
-    strcpy(lpddi->tszProductName,  joystick_devices[id].name);
 
+    /* Assume the joystick as HID if it is attached to USB bus and has a valid VID/PID */
+    if (joystick_devices[id].bus_type == BUS_USB &&
+        joystick_devices[id].vendor_id && joystick_devices[id].product_id)
+    {
+        lpddi->dwDevType |= DIDEVTYPE_HID;
+        lpddi->wUsagePage = 0x01; /* Desktop */
+        if (lpddi->dwDevType == DI8DEVTYPE_JOYSTICK || lpddi->dwDevType == DIDEVTYPE_JOYSTICK)
+            lpddi->wUsage = 0x04; /* Joystick */
+        else
+            lpddi->wUsage = 0x05; /* Game Pad */
+    }
+
+    MultiByteToWideChar(CP_ACP, 0, joystick_devices[id].name, -1, lpddi->tszInstanceName, MAX_PATH);
+    MultiByteToWideChar(CP_ACP, 0, joystick_devices[id].name, -1, lpddi->tszProductName, MAX_PATH);
     lpddi->guidFFDriver = GUID_NULL;
 }
 
-static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
+static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
 {
+    DIDEVICEINSTANCEW lpddiW;
     DWORD dwSize = lpddi->dwSize;
 
+    lpddiW.dwSize = sizeof(lpddiW);
+    fill_joystick_dideviceinstanceW(&lpddiW, version, id);
+
     TRACE("%d %p\n", dwSize, lpddi);
     memset(lpddi, 0, dwSize);
 
-    /* Return joystick */
+    /* Convert W->A */
     lpddi->dwSize = dwSize;
-    lpddi->guidInstance = DInput_Wine_Joystick_GUID;
-    lpddi->guidInstance.Data3 = id;
-    lpddi->guidProduct = joystick_devices[id].guid_product;
-    /* we only support traditional joysticks for now */
-    if (version >= 0x0800)
-        lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
-    else
-        lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
-
-    MultiByteToWideChar(CP_ACP, 0, joystick_devices[id].name, -1, lpddi->tszInstanceName, MAX_PATH);
-    MultiByteToWideChar(CP_ACP, 0, joystick_devices[id].name, -1, lpddi->tszProductName, MAX_PATH);
-    lpddi->guidFFDriver = GUID_NULL;
+    lpddi->guidInstance = lpddiW.guidInstance;
+    lpddi->guidProduct = lpddiW.guidProduct;
+    lpddi->dwDevType = lpddiW.dwDevType;
+    strcpy(lpddi->tszInstanceName, joystick_devices[id].name);
+    strcpy(lpddi->tszProductName,  joystick_devices[id].name);
+    lpddi->guidFFDriver = lpddiW.guidFFDriver;
+    lpddi->wUsagePage = lpddiW.wUsagePage;
+    lpddi->wUsage = lpddiW.wUsage;
 }
 
 static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
@@ -322,14 +334,14 @@ static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINS
        ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
        (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
         /* check whether we have a joystick */
-        if ((fd = open(joystick_devices[id].device, O_RDONLY)) < 0)
+        if ((fd = open(joystick_devices[id].device, O_RDONLY)) == -1)
         {
-            WARN("open(%s, O_RDONLY) failed: %s\n", joystick_devices[id].name, strerror(errno));
+            WARN("open(%s, O_RDONLY) failed: %s\n", joystick_devices[id].device, strerror(errno));
             return S_FALSE;
         }
         fill_joystick_dideviceinstanceA( lpddi, version, id );
         close(fd);
-        TRACE("Enumerating the linux Joystick device: %s (%s)\n", joystick_devices[id].device, lpddi->tszProductName);
+        TRACE("Enumerating the linux Joystick device: %s (%s)\n", joystick_devices[id].device, joystick_devices[id].name);
         return S_OK;
     }
 
@@ -351,9 +363,9 @@ static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINS
        ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
        (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
         /* check whether we have a joystick */
-        if ((fd = open(joystick_devices[id].device, O_RDONLY)) < 0)
+        if ((fd = open(joystick_devices[id].device, O_RDONLY)) == -1)
         {
-            WARN("open(%s,O_RDONLY) failed: %s\n", joystick_devices[id].device, strerror(errno));
+            WARN("open(%s, O_RDONLY) failed: %s\n", joystick_devices[id].device, strerror(errno));
             return S_FALSE;
         }
         fill_joystick_dideviceinstanceW( lpddi, version, id );
@@ -373,6 +385,7 @@ static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput,
     HRESULT hr;
     LPDIDATAFORMAT df = NULL;
     int idx = 0;
+    DIDEVICEINSTANCEW ddi;
 
     TRACE("%s %p %p %hu\n", debugstr_guid(rguid), dinput, pdev, index);
 
@@ -463,10 +476,11 @@ static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput,
 
     newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps);
     newDevice->generic.devcaps.dwFlags = DIDC_ATTACHED;
-    if (newDevice->generic.base.dinput->dwVersion >= 0x0800)
-        newDevice->generic.devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
-    else
-        newDevice->generic.devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
+
+    ddi.dwSize = sizeof(ddi);
+    fill_joystick_dideviceinstanceW(&ddi, newDevice->generic.base.dinput->dwVersion, index);
+    newDevice->generic.devcaps.dwDevType = ddi.dwDevType;
+
     newDevice->generic.devcaps.dwFFSamplePeriod = 0;
     newDevice->generic.devcaps.dwFFMinTimeResolution = 0;
     newDevice->generic.devcaps.dwFirmwareRevision = 0;
@@ -625,6 +639,16 @@ static HRESULT WINAPI JoystickLinuxWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface
 
     switch (LOWORD(rguid)) {
 
+        case (DWORD_PTR) DIPROP_VIDPID:
+        {
+            LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
+
+            if (!This->joydev->product_id || !This->joydev->vendor_id)
+                return DIERR_UNSUPPORTED;
+            pd->dwData = MAKELONG(This->joydev->vendor_id, This->joydev->product_id);
+            TRACE("DIPROP_VIDPID(%08x)\n", pd->dwData);
+            break;
+        }
         case (DWORD_PTR) DIPROP_JOYSTICKID:
         {
             LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
index 290a374..a962b56 100644 (file)
@@ -91,7 +91,7 @@ struct JoyDev {
        /* data returned by the EVIOCGABS() ioctl */
         struct wine_input_absinfo       axes[ABS_MAX];
 
-        WORD vendor_id, product_id;
+        WORD vendor_id, product_id, bus_type;
 };
 
 struct JoystickImpl
@@ -296,6 +296,7 @@ static void find_joydevs(void)
         {
             joydev.vendor_id = device_id.vendor;
             joydev.product_id = device_id.product;
+            joydev.bus_type = device_id.bustype;
 
             /* Concatenate product_id with vendor_id to mimic Windows behaviour */
             joydev.guid_product       = DInput_Wine_Joystick_Constant_Part_GUID;
@@ -320,7 +321,7 @@ static void find_joydevs(void)
     }
 }
 
-static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
+static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
 {
     DWORD dwSize = lpddi->dwSize;
 
@@ -337,29 +338,43 @@ static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD ver
     else
         lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
 
-    strcpy(lpddi->tszInstanceName, joydevs[id].name);
-    strcpy(lpddi->tszProductName, joydevs[id].name);
+    /* Assume the joystick as HID if it is attached to USB bus and has a valid VID/PID */
+    if (joydevs[id].bus_type == BUS_USB &&
+        joydevs[id].vendor_id && joydevs[id].product_id)
+    {
+        lpddi->dwDevType |= DIDEVTYPE_HID;
+        lpddi->wUsagePage = 0x01; /* Desktop */
+        if (lpddi->dwDevType == DI8DEVTYPE_JOYSTICK || lpddi->dwDevType == DIDEVTYPE_JOYSTICK)
+            lpddi->wUsage = 0x04; /* Joystick */
+        else
+            lpddi->wUsage = 0x05; /* Game Pad */
+    }
+
+    MultiByteToWideChar(CP_ACP, 0, joydevs[id].name, -1, lpddi->tszInstanceName, MAX_PATH);
+    MultiByteToWideChar(CP_ACP, 0, joydevs[id].name, -1, lpddi->tszProductName, MAX_PATH);
 }
 
-static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
+static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
 {
+    DIDEVICEINSTANCEW lpddiW;
     DWORD dwSize = lpddi->dwSize;
 
+    lpddiW.dwSize = sizeof(lpddiW);
+    fill_joystick_dideviceinstanceW(&lpddiW, version, id);
+
     TRACE("%d %p\n", dwSize, lpddi);
     memset(lpddi, 0, dwSize);
 
-    lpddi->dwSize       = dwSize;
-    lpddi->guidInstance = joydevs[id].guid;
-    lpddi->guidProduct  = joydevs[id].guid_product;
-    lpddi->guidFFDriver = GUID_NULL;
-
-    if (version >= 0x0800)
-        lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
-    else
-        lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
-
-    MultiByteToWideChar(CP_ACP, 0, joydevs[id].name, -1, lpddi->tszInstanceName, MAX_PATH);
-    MultiByteToWideChar(CP_ACP, 0, joydevs[id].name, -1, lpddi->tszProductName, MAX_PATH);
+    /* Convert W->A */
+    lpddi->dwSize = dwSize;
+    lpddi->guidInstance = lpddiW.guidInstance;
+    lpddi->guidProduct = lpddiW.guidProduct;
+    lpddi->dwDevType = lpddiW.dwDevType;
+    strcpy(lpddi->tszInstanceName, joydevs[id].name);
+    strcpy(lpddi->tszProductName,  joydevs[id].name);
+    lpddi->guidFFDriver = lpddiW.guidFFDriver;
+    lpddi->wUsagePage = lpddiW.wUsagePage;
+    lpddi->wUsage = lpddiW.wUsage;
 }
 
 static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
@@ -418,6 +433,7 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig
     LPDIDATAFORMAT df = NULL;
     int i, idx = 0;
     int default_axis_map[WINE_JOYSTICK_MAX_AXES + WINE_JOYSTICK_MAX_POVS*2];
+    DIDEVICEINSTANCEW ddi;
 
     newDevice = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(JoystickImpl));
     if (!newDevice) return NULL;
@@ -537,10 +553,10 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig
     /* Fill the caps */
     newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps);
     newDevice->generic.devcaps.dwFlags = DIDC_ATTACHED;
-    if (newDevice->generic.base.dinput->dwVersion >= 0x0800)
-        newDevice->generic.devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
-    else
-        newDevice->generic.devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
+
+    ddi.dwSize = sizeof(ddi);
+    fill_joystick_dideviceinstanceW(&ddi, newDevice->generic.base.dinput->dwVersion, index);
+    newDevice->generic.devcaps.dwDevType = ddi.dwDevType;
 
     if (newDevice->joydev->has_ff)
         newDevice->generic.devcaps.dwFlags |= DIDC_FORCEFEEDBACK;
@@ -1015,10 +1031,16 @@ static HRESULT WINAPI JoystickWImpl_CreateEffect(LPDIRECTINPUTDEVICE8W iface, RE
     JoystickImpl* This = impl_from_IDirectInputDevice8W(iface);
     TRACE("(this=%p,%p,%p,%p,%p)\n", This, rguid, lpeff, ppdef, pUnkOuter);
 
-#ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
-    TRACE("not available (compiled w/o ff support)\n");
     *ppdef = NULL;
-    return DI_OK;
+    if (!This->joydev->has_ff)
+    {
+        TRACE("No force feedback support\n");
+        return DIERR_UNSUPPORTED;
+    }
+
+#ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
+    TRACE("not available (compiled w/o force feedback support)\n");
+    return DIERR_UNSUPPORTED;
 #else
 
     if (!(new_effect = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_effect))))
index 8c6e784..e135849 100644 (file)
@@ -1398,7 +1398,7 @@ static HRESULT WINAPI JoystickWImpl_CreateEffect(IDirectInputDevice8W *iface,
     if(!This->ff){
         TRACE("No force feedback support\n");
         *out = NULL;
-        return S_OK;
+        return DIERR_UNSUPPORTED;
     }
 
     if(outer)
index 5343709..c1bf329 100644 (file)
@@ -30,7 +30,7 @@ reactos/dll/directx/wine/d3dx9_24 => 43 # Synced to WineStaging-1.9.4
 reactos/dll/directx/wine/d3dxof         # Synced to WineStaging-1.9.16
 reactos/dll/directx/wine/ddraw          # Synced to WineStaging-1.9.4
 reactos/dll/directx/wine/devenum        # Synced to WineStaging-1.9.16
-reactos/dll/directx/wine/dinput         # Synced to WineStaging-1.9.16
+reactos/dll/directx/wine/dinput         # Synced to WineStaging-1.9.23
 reactos/dll/directx/wine/dinput8        # Synced to WineStaging-1.9.11
 reactos/dll/directx/wine/dmusic         # Synced to WineStaging-1.9.16
 reactos/dll/directx/wine/dplay          # Synced to WineStaging-1.9.11