src/haptic/windows/SDL_dinputhaptic.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 28 May 2015 01:27:24 -0400
changeset 9663 647180a6caad
parent 9662 932e57cf5648
child 9998 f67cf37e9cd4
permissions -rw-r--r--
I think this will be the time...
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2015 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #include "SDL_error.h"
    24 #include "SDL_haptic.h"
    25 #include "../SDL_syshaptic.h"
    26 
    27 #if SDL_HAPTIC_DINPUT
    28 
    29 #include "SDL_stdinc.h"
    30 #include "SDL_timer.h"
    31 #include "SDL_windowshaptic_c.h"
    32 #include "SDL_dinputhaptic_c.h"
    33 #include "../../joystick/windows/SDL_windowsjoystick_c.h"
    34 
    35 /*
    36  * External stuff.
    37  */
    38 extern HWND SDL_HelperWindow;
    39 
    40 
    41 /*
    42  * Internal stuff.
    43  */
    44 static SDL_bool coinitialized = SDL_FALSE;
    45 static LPDIRECTINPUT8 dinput = NULL;
    46 
    47 
    48 /*
    49  * Like SDL_SetError but for DX error codes.
    50  */
    51 static int
    52 DI_SetError(const char *str, HRESULT err)
    53 {
    54     /*
    55        SDL_SetError("Haptic: %s - %s: %s", str,
    56        DXGetErrorString8A(err), DXGetErrorDescription8A(err));
    57      */
    58     return SDL_SetError("Haptic error %s", str);
    59 }
    60 
    61 /*
    62  * Checks to see if two GUID are the same.
    63  */
    64 static int
    65 DI_GUIDIsSame(const GUID * a, const GUID * b)
    66 {
    67     return (SDL_memcmp(a, b, sizeof (GUID)) == 0);
    68 }
    69 
    70 /*
    71  * Callback to find the haptic devices.
    72  */
    73 static BOOL CALLBACK
    74 EnumHapticsCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
    75 {
    76     (void) pContext;
    77     SDL_DINPUT_MaybeAddDevice(pdidInstance);
    78     return DIENUM_CONTINUE;  /* continue enumerating */
    79 }
    80 
    81 int
    82 SDL_DINPUT_HapticInit(void)
    83 {
    84     HRESULT ret;
    85     HINSTANCE instance;
    86 
    87     if (dinput != NULL) {       /* Already open. */
    88         return SDL_SetError("Haptic: SubSystem already open.");
    89     }
    90 
    91     ret = WIN_CoInitialize();
    92     if (FAILED(ret)) {
    93         return DI_SetError("Coinitialize", ret);
    94     }
    95 
    96     coinitialized = SDL_TRUE;
    97 
    98     ret = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER,
    99         &IID_IDirectInput8, (LPVOID)& dinput);
   100     if (FAILED(ret)) {
   101         SDL_SYS_HapticQuit();
   102         return DI_SetError("CoCreateInstance", ret);
   103     }
   104 
   105     /* Because we used CoCreateInstance, we need to Initialize it, first. */
   106     instance = GetModuleHandle(NULL);
   107     if (instance == NULL) {
   108         SDL_SYS_HapticQuit();
   109         return SDL_SetError("GetModuleHandle() failed with error code %lu.",
   110             GetLastError());
   111     }
   112     ret = IDirectInput8_Initialize(dinput, instance, DIRECTINPUT_VERSION);
   113     if (FAILED(ret)) {
   114         SDL_SYS_HapticQuit();
   115         return DI_SetError("Initializing DirectInput device", ret);
   116     }
   117 
   118     /* Look for haptic devices. */
   119     ret = IDirectInput8_EnumDevices(dinput,
   120         0,
   121         EnumHapticsCallback,
   122         NULL,
   123         DIEDFL_FORCEFEEDBACK |
   124         DIEDFL_ATTACHEDONLY);
   125     if (FAILED(ret)) {
   126         SDL_SYS_HapticQuit();
   127         return DI_SetError("Enumerating DirectInput devices", ret);
   128     }
   129     return 0;
   130 }
   131 
   132 int
   133 SDL_DINPUT_MaybeAddDevice(const DIDEVICEINSTANCE * pdidInstance)
   134 {
   135     HRESULT ret;
   136     LPDIRECTINPUTDEVICE8 device;
   137     const DWORD needflags = DIDC_ATTACHED | DIDC_FORCEFEEDBACK;
   138     DIDEVCAPS capabilities;
   139     SDL_hapticlist_item *item = NULL;
   140 
   141     if (dinput == NULL) {
   142         return -1;  /* not initialized. We'll pick these up on enumeration if we init later. */
   143     }
   144 
   145     /* Make sure we don't already have it */
   146     for (item = SDL_hapticlist; item; item = item->next) {
   147         if ((!item->bXInputHaptic) && (SDL_memcmp(&item->instance, pdidInstance, sizeof(*pdidInstance)) == 0)) {
   148             return -1;  /* Already added */
   149         }
   150     }
   151 
   152     /* Open the device */
   153     ret = IDirectInput8_CreateDevice(dinput, &pdidInstance->guidInstance, &device, NULL);
   154     if (FAILED(ret)) {
   155         /* DI_SetError("Creating DirectInput device",ret); */
   156         return -1;
   157     }
   158 
   159     /* Get capabilities. */
   160     SDL_zero(capabilities);
   161     capabilities.dwSize = sizeof(DIDEVCAPS);
   162     ret = IDirectInputDevice8_GetCapabilities(device, &capabilities);
   163     IDirectInputDevice8_Release(device);
   164     if (FAILED(ret)) {
   165         /* DI_SetError("Getting device capabilities",ret); */
   166         return -1;
   167     }
   168 
   169     if ((capabilities.dwFlags & needflags) != needflags) {
   170         return -1;  /* not a device we can use. */
   171     }
   172 
   173     item = (SDL_hapticlist_item *)SDL_calloc(1, sizeof(SDL_hapticlist_item));
   174     if (item == NULL) {
   175         return SDL_OutOfMemory();
   176     }
   177 
   178     item->name = WIN_StringToUTF8(pdidInstance->tszProductName);
   179     if (!item->name) {
   180         SDL_free(item);
   181         return -1;
   182     }
   183 
   184     /* Copy the instance over, useful for creating devices. */
   185     SDL_memcpy(&item->instance, pdidInstance, sizeof(DIDEVICEINSTANCE));
   186     SDL_memcpy(&item->capabilities, &capabilities, sizeof(capabilities));
   187 
   188     return SDL_SYS_AddHapticDevice(item);
   189 }
   190 
   191 int
   192 SDL_DINPUT_MaybeRemoveDevice(const DIDEVICEINSTANCE * pdidInstance)
   193 {
   194     SDL_hapticlist_item *item;
   195     SDL_hapticlist_item *prev = NULL;
   196 
   197     if (dinput == NULL) {
   198         return -1;  /* not initialized, ignore this. */
   199     }
   200 
   201     for (item = SDL_hapticlist; item != NULL; item = item->next) {
   202         if (!item->bXInputHaptic && SDL_memcmp(&item->instance, pdidInstance, sizeof(*pdidInstance)) == 0) {
   203             /* found it, remove it. */
   204             return SDL_SYS_RemoveHapticDevice(prev, item);
   205         }
   206         prev = item;
   207     }
   208     return -1;
   209 }
   210 
   211 /*
   212  * Callback to get supported axes.
   213  */
   214 static BOOL CALLBACK
   215 DI_DeviceObjectCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
   216 {
   217     SDL_Haptic *haptic = (SDL_Haptic *) pvRef;
   218 
   219     if ((dev->dwType & DIDFT_AXIS) && (dev->dwFlags & DIDOI_FFACTUATOR)) {
   220         const GUID *guid = &dev->guidType;
   221         DWORD offset = 0;
   222         if (DI_GUIDIsSame(guid, &GUID_XAxis)) {
   223             offset = DIJOFS_X;
   224         } else if (DI_GUIDIsSame(guid, &GUID_YAxis)) {
   225             offset = DIJOFS_Y;
   226         } else if (DI_GUIDIsSame(guid, &GUID_ZAxis)) {
   227             offset = DIJOFS_Z;
   228         } else if (DI_GUIDIsSame(guid, &GUID_RxAxis)) {
   229             offset = DIJOFS_RX;
   230         } else if (DI_GUIDIsSame(guid, &GUID_RyAxis)) {
   231             offset = DIJOFS_RY;
   232         } else if (DI_GUIDIsSame(guid, &GUID_RzAxis)) {
   233             offset = DIJOFS_RZ;
   234         } else {
   235             return DIENUM_CONTINUE;   /* can't use this, go on. */
   236         }
   237 
   238         haptic->hwdata->axes[haptic->naxes] = offset;
   239         haptic->naxes++;
   240 
   241         /* Currently using the artificial limit of 3 axes. */
   242         if (haptic->naxes >= 3) {
   243             return DIENUM_STOP;
   244         }
   245     }
   246 
   247     return DIENUM_CONTINUE;
   248 }
   249 
   250 /*
   251  * Callback to get all supported effects.
   252  */
   253 #define EFFECT_TEST(e,s)               \
   254 if (DI_GUIDIsSame(&pei->guid, &(e)))   \
   255    haptic->supported |= (s)
   256 static BOOL CALLBACK
   257 DI_EffectCallback(LPCDIEFFECTINFO pei, LPVOID pv)
   258 {
   259     /* Prepare the haptic device. */
   260     SDL_Haptic *haptic = (SDL_Haptic *) pv;
   261 
   262     /* Get supported. */
   263     EFFECT_TEST(GUID_Spring, SDL_HAPTIC_SPRING);
   264     EFFECT_TEST(GUID_Damper, SDL_HAPTIC_DAMPER);
   265     EFFECT_TEST(GUID_Inertia, SDL_HAPTIC_INERTIA);
   266     EFFECT_TEST(GUID_Friction, SDL_HAPTIC_FRICTION);
   267     EFFECT_TEST(GUID_ConstantForce, SDL_HAPTIC_CONSTANT);
   268     EFFECT_TEST(GUID_CustomForce, SDL_HAPTIC_CUSTOM);
   269     EFFECT_TEST(GUID_Sine, SDL_HAPTIC_SINE);
   270     /* !!! FIXME: put this back when we have more bits in 2.1 */
   271     /* EFFECT_TEST(GUID_Square, SDL_HAPTIC_SQUARE); */
   272     EFFECT_TEST(GUID_Triangle, SDL_HAPTIC_TRIANGLE);
   273     EFFECT_TEST(GUID_SawtoothUp, SDL_HAPTIC_SAWTOOTHUP);
   274     EFFECT_TEST(GUID_SawtoothDown, SDL_HAPTIC_SAWTOOTHDOWN);
   275     EFFECT_TEST(GUID_RampForce, SDL_HAPTIC_RAMP);
   276 
   277     /* Check for more. */
   278     return DIENUM_CONTINUE;
   279 }
   280 
   281 /*
   282  * Opens the haptic device.
   283  *
   284  *    Steps:
   285  *       - Set cooperative level.
   286  *       - Set data format.
   287  *       - Acquire exclusiveness.
   288  *       - Reset actuators.
   289  *       - Get supported features.
   290  */
   291 static int
   292 SDL_DINPUT_HapticOpenFromDevice(SDL_Haptic * haptic, LPDIRECTINPUTDEVICE8 device8, SDL_bool is_joystick)
   293 {
   294     HRESULT ret;
   295     DIPROPDWORD dipdw;
   296 
   297     /* Allocate the hwdata */
   298     haptic->hwdata = (struct haptic_hwdata *)SDL_malloc(sizeof(*haptic->hwdata));
   299     if (haptic->hwdata == NULL) {
   300         return SDL_OutOfMemory();
   301     }
   302     SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
   303 
   304     /* We'll use the device8 from now on. */
   305     haptic->hwdata->device = device8;
   306     haptic->hwdata->is_joystick = is_joystick;
   307 
   308     /* !!! FIXME: opening a haptic device here first will make an attempt to
   309        !!! FIXME:  SDL_JoystickOpen() that same device fail later, since we
   310        !!! FIXME:  have it open in exclusive mode. But this will allow
   311        !!! FIXME:  SDL_JoystickOpen() followed by SDL_HapticOpenFromJoystick()
   312        !!! FIXME:  to work, and that's probably the common case. Still,
   313        !!! FIXME:  ideally, We need to unify the opening code. */
   314 
   315     if (!is_joystick) {  /* if is_joystick, we already set this up elsewhere. */
   316         /* Grab it exclusively to use force feedback stuff. */
   317         ret = IDirectInputDevice8_SetCooperativeLevel(haptic->hwdata->device,
   318                                                       SDL_HelperWindow,
   319                                                       DISCL_EXCLUSIVE |
   320                                                       DISCL_BACKGROUND);
   321         if (FAILED(ret)) {
   322             DI_SetError("Setting cooperative level to exclusive", ret);
   323             goto acquire_err;
   324         }
   325 
   326         /* Set data format. */
   327         ret = IDirectInputDevice8_SetDataFormat(haptic->hwdata->device,
   328                                                 &c_dfDIJoystick2);
   329         if (FAILED(ret)) {
   330             DI_SetError("Setting data format", ret);
   331             goto acquire_err;
   332         }
   333 
   334         /* Get number of axes. */
   335         ret = IDirectInputDevice8_EnumObjects(haptic->hwdata->device,
   336                                               DI_DeviceObjectCallback,
   337                                               haptic, DIDFT_AXIS);
   338         if (FAILED(ret)) {
   339             DI_SetError("Getting device axes", ret);
   340             goto acquire_err;
   341         }
   342 
   343         /* Acquire the device. */
   344         ret = IDirectInputDevice8_Acquire(haptic->hwdata->device);
   345         if (FAILED(ret)) {
   346             DI_SetError("Acquiring DirectInput device", ret);
   347             goto acquire_err;
   348         }
   349     }
   350 
   351     /* Reset all actuators - just in case. */
   352     ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
   353                                                        DISFFC_RESET);
   354     if (FAILED(ret)) {
   355         DI_SetError("Resetting device", ret);
   356         goto acquire_err;
   357     }
   358 
   359     /* Enabling actuators. */
   360     ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
   361                                                        DISFFC_SETACTUATORSON);
   362     if (FAILED(ret)) {
   363         DI_SetError("Enabling actuators", ret);
   364         goto acquire_err;
   365     }
   366 
   367     /* Get supported effects. */
   368     ret = IDirectInputDevice8_EnumEffects(haptic->hwdata->device,
   369                                           DI_EffectCallback, haptic,
   370                                           DIEFT_ALL);
   371     if (FAILED(ret)) {
   372         DI_SetError("Enumerating supported effects", ret);
   373         goto acquire_err;
   374     }
   375     if (haptic->supported == 0) {       /* Error since device supports nothing. */
   376         SDL_SetError("Haptic: Internal error on finding supported effects.");
   377         goto acquire_err;
   378     }
   379 
   380     /* Check autogain and autocenter. */
   381     dipdw.diph.dwSize = sizeof(DIPROPDWORD);
   382     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
   383     dipdw.diph.dwObj = 0;
   384     dipdw.diph.dwHow = DIPH_DEVICE;
   385     dipdw.dwData = 10000;
   386     ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device,
   387                                           DIPROP_FFGAIN, &dipdw.diph);
   388     if (!FAILED(ret)) {         /* Gain is supported. */
   389         haptic->supported |= SDL_HAPTIC_GAIN;
   390     }
   391     dipdw.diph.dwObj = 0;
   392     dipdw.diph.dwHow = DIPH_DEVICE;
   393     dipdw.dwData = DIPROPAUTOCENTER_OFF;
   394     ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device,
   395                                           DIPROP_AUTOCENTER, &dipdw.diph);
   396     if (!FAILED(ret)) {         /* Autocenter is supported. */
   397         haptic->supported |= SDL_HAPTIC_AUTOCENTER;
   398     }
   399 
   400     /* Status is always supported. */
   401     haptic->supported |= SDL_HAPTIC_STATUS | SDL_HAPTIC_PAUSE;
   402 
   403     /* Check maximum effects. */
   404     haptic->neffects = 128;     /* This is not actually supported as thus under windows,
   405                                    there is no way to tell the number of EFFECTS that a
   406                                    device can hold, so we'll just use a "random" number
   407                                    instead and put warnings in SDL_haptic.h */
   408     haptic->nplaying = 128;     /* Even more impossible to get this then neffects. */
   409 
   410     /* Prepare effects memory. */
   411     haptic->effects = (struct haptic_effect *)
   412         SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
   413     if (haptic->effects == NULL) {
   414         SDL_OutOfMemory();
   415         goto acquire_err;
   416     }
   417     /* Clear the memory */
   418     SDL_memset(haptic->effects, 0,
   419                sizeof(struct haptic_effect) * haptic->neffects);
   420 
   421     return 0;
   422 
   423     /* Error handling */
   424   acquire_err:
   425     IDirectInputDevice8_Unacquire(haptic->hwdata->device);
   426     return -1;
   427 }
   428 
   429 int
   430 SDL_DINPUT_HapticOpen(SDL_Haptic * haptic, SDL_hapticlist_item *item)
   431 {
   432     HRESULT ret;
   433     LPDIRECTINPUTDEVICE8 device;
   434     LPDIRECTINPUTDEVICE8 device8;
   435 
   436     /* Open the device */
   437     ret = IDirectInput8_CreateDevice(dinput, &item->instance.guidInstance,
   438         &device, NULL);
   439     if (FAILED(ret)) {
   440         DI_SetError("Creating DirectInput device", ret);
   441         return -1;
   442     }
   443 
   444     /* Now get the IDirectInputDevice8 interface, instead. */
   445     ret = IDirectInputDevice8_QueryInterface(device,
   446         &IID_IDirectInputDevice8,
   447         (LPVOID *)&device8);
   448     /* Done with the temporary one now. */
   449     IDirectInputDevice8_Release(device);
   450     if (FAILED(ret)) {
   451         DI_SetError("Querying DirectInput interface", ret);
   452         return -1;
   453     }
   454 
   455     if (SDL_DINPUT_HapticOpenFromDevice(haptic, device8, SDL_FALSE) < 0) {
   456         IDirectInputDevice8_Release(device8);
   457         return -1;
   458     }
   459     return 0;
   460 }
   461 
   462 int
   463 SDL_DINPUT_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
   464 {
   465     HRESULT ret;
   466     DIDEVICEINSTANCE hap_instance, joy_instance;
   467 
   468     hap_instance.dwSize = sizeof(DIDEVICEINSTANCE);
   469     joy_instance.dwSize = sizeof(DIDEVICEINSTANCE);
   470 
   471     /* Get the device instances. */
   472     ret = IDirectInputDevice8_GetDeviceInfo(haptic->hwdata->device,
   473         &hap_instance);
   474     if (FAILED(ret)) {
   475         return 0;
   476     }
   477     ret = IDirectInputDevice8_GetDeviceInfo(joystick->hwdata->InputDevice,
   478         &joy_instance);
   479     if (FAILED(ret)) {
   480         return 0;
   481     }
   482 
   483     return DI_GUIDIsSame(&hap_instance.guidInstance, &joy_instance.guidInstance);
   484 }
   485 
   486 int
   487 SDL_DINPUT_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
   488 {
   489     SDL_hapticlist_item *item;
   490     int index = 0;
   491     HRESULT ret;
   492     DIDEVICEINSTANCE joy_instance;
   493 
   494     joy_instance.dwSize = sizeof(DIDEVICEINSTANCE);
   495     ret = IDirectInputDevice8_GetDeviceInfo(joystick->hwdata->InputDevice, &joy_instance);
   496     if (FAILED(ret)) {
   497         return -1;
   498     }
   499 
   500     /* Since it comes from a joystick we have to try to match it with a haptic device on our haptic list. */
   501     for (item = SDL_hapticlist; item != NULL; item = item->next) {
   502         if (!item->bXInputHaptic && DI_GUIDIsSame(&item->instance.guidInstance, &joy_instance.guidInstance)) {
   503             haptic->index = index;
   504             return SDL_DINPUT_HapticOpenFromDevice(haptic, joystick->hwdata->InputDevice, SDL_TRUE);
   505         }
   506         ++index;
   507     }
   508 
   509     SDL_SetError("Couldn't find joystick in haptic device list");
   510     return -1;
   511 }
   512 
   513 void
   514 SDL_DINPUT_HapticClose(SDL_Haptic * haptic)
   515 {
   516     IDirectInputDevice8_Unacquire(haptic->hwdata->device);
   517 
   518     /* Only release if isn't grabbed by a joystick. */
   519     if (haptic->hwdata->is_joystick == 0) {
   520         IDirectInputDevice8_Release(haptic->hwdata->device);
   521     }
   522 }
   523 
   524 void
   525 SDL_DINPUT_HapticQuit(void)
   526 {
   527     if (dinput != NULL) {
   528         IDirectInput8_Release(dinput);
   529         dinput = NULL;
   530     }
   531 
   532     if (coinitialized) {
   533         WIN_CoUninitialize();
   534         coinitialized = SDL_FALSE;
   535     }
   536 }
   537 
   538 /*
   539  * Converts an SDL trigger button to an DIEFFECT trigger button.
   540  */
   541 static DWORD
   542 DIGetTriggerButton(Uint16 button)
   543 {
   544     DWORD dwTriggerButton;
   545 
   546     dwTriggerButton = DIEB_NOTRIGGER;
   547 
   548     if (button != 0) {
   549         dwTriggerButton = DIJOFS_BUTTON(button - 1);
   550     }
   551 
   552     return dwTriggerButton;
   553 }
   554 
   555 
   556 /*
   557  * Sets the direction.
   558  */
   559 static int
   560 SDL_SYS_SetDirection(DIEFFECT * effect, SDL_HapticDirection * dir, int naxes)
   561 {
   562     LONG *rglDir;
   563 
   564     /* Handle no axes a part. */
   565     if (naxes == 0) {
   566         effect->dwFlags |= DIEFF_SPHERICAL;     /* Set as default. */
   567         effect->rglDirection = NULL;
   568         return 0;
   569     }
   570 
   571     /* Has axes. */
   572     rglDir = SDL_malloc(sizeof(LONG) * naxes);
   573     if (rglDir == NULL) {
   574         return SDL_OutOfMemory();
   575     }
   576     SDL_memset(rglDir, 0, sizeof(LONG) * naxes);
   577     effect->rglDirection = rglDir;
   578 
   579     switch (dir->type) {
   580     case SDL_HAPTIC_POLAR:
   581         effect->dwFlags |= DIEFF_POLAR;
   582         rglDir[0] = dir->dir[0];
   583         return 0;
   584     case SDL_HAPTIC_CARTESIAN:
   585         effect->dwFlags |= DIEFF_CARTESIAN;
   586         rglDir[0] = dir->dir[0];
   587         if (naxes > 1)
   588             rglDir[1] = dir->dir[1];
   589         if (naxes > 2)
   590             rglDir[2] = dir->dir[2];
   591         return 0;
   592     case SDL_HAPTIC_SPHERICAL:
   593         effect->dwFlags |= DIEFF_SPHERICAL;
   594         rglDir[0] = dir->dir[0];
   595         if (naxes > 1)
   596             rglDir[1] = dir->dir[1];
   597         if (naxes > 2)
   598             rglDir[2] = dir->dir[2];
   599         return 0;
   600 
   601     default:
   602         return SDL_SetError("Haptic: Unknown direction type.");
   603     }
   604 }
   605 
   606 /* Clamps and converts. */
   607 #define CCONVERT(x)   (((x) > 0x7FFF) ? 10000 : ((x)*10000) / 0x7FFF)
   608 /* Just converts. */
   609 #define CONVERT(x)    (((x)*10000) / 0x7FFF)
   610 /*
   611  * Creates the DIEFFECT from a SDL_HapticEffect.
   612  */
   613 static int
   614 SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic, DIEFFECT * dest,
   615                    SDL_HapticEffect * src)
   616 {
   617     int i;
   618     DICONSTANTFORCE *constant;
   619     DIPERIODIC *periodic;
   620     DICONDITION *condition;     /* Actually an array of conditions - one per axis. */
   621     DIRAMPFORCE *ramp;
   622     DICUSTOMFORCE *custom;
   623     DIENVELOPE *envelope;
   624     SDL_HapticConstant *hap_constant;
   625     SDL_HapticPeriodic *hap_periodic;
   626     SDL_HapticCondition *hap_condition;
   627     SDL_HapticRamp *hap_ramp;
   628     SDL_HapticCustom *hap_custom;
   629     DWORD *axes;
   630 
   631     /* Set global stuff. */
   632     SDL_memset(dest, 0, sizeof(DIEFFECT));
   633     dest->dwSize = sizeof(DIEFFECT);    /* Set the structure size. */
   634     dest->dwSamplePeriod = 0;   /* Not used by us. */
   635     dest->dwGain = 10000;       /* Gain is set globally, not locally. */
   636     dest->dwFlags = DIEFF_OBJECTOFFSETS;        /* Seems obligatory. */
   637 
   638     /* Envelope. */
   639     envelope = SDL_malloc(sizeof(DIENVELOPE));
   640     if (envelope == NULL) {
   641         return SDL_OutOfMemory();
   642     }
   643     SDL_memset(envelope, 0, sizeof(DIENVELOPE));
   644     dest->lpEnvelope = envelope;
   645     envelope->dwSize = sizeof(DIENVELOPE);      /* Always should be this. */
   646 
   647     /* Axes. */
   648     dest->cAxes = haptic->naxes;
   649     if (dest->cAxes > 0) {
   650         axes = SDL_malloc(sizeof(DWORD) * dest->cAxes);
   651         if (axes == NULL) {
   652             return SDL_OutOfMemory();
   653         }
   654         axes[0] = haptic->hwdata->axes[0];      /* Always at least one axis. */
   655         if (dest->cAxes > 1) {
   656             axes[1] = haptic->hwdata->axes[1];
   657         }
   658         if (dest->cAxes > 2) {
   659             axes[2] = haptic->hwdata->axes[2];
   660         }
   661         dest->rgdwAxes = axes;
   662     }
   663 
   664     /* The big type handling switch, even bigger than Linux's version. */
   665     switch (src->type) {
   666     case SDL_HAPTIC_CONSTANT:
   667         hap_constant = &src->constant;
   668         constant = SDL_malloc(sizeof(DICONSTANTFORCE));
   669         if (constant == NULL) {
   670             return SDL_OutOfMemory();
   671         }
   672         SDL_memset(constant, 0, sizeof(DICONSTANTFORCE));
   673 
   674         /* Specifics */
   675         constant->lMagnitude = CONVERT(hap_constant->level);
   676         dest->cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
   677         dest->lpvTypeSpecificParams = constant;
   678 
   679         /* Generics */
   680         dest->dwDuration = hap_constant->length * 1000; /* In microseconds. */
   681         dest->dwTriggerButton = DIGetTriggerButton(hap_constant->button);
   682         dest->dwTriggerRepeatInterval = hap_constant->interval;
   683         dest->dwStartDelay = hap_constant->delay * 1000;        /* In microseconds. */
   684 
   685         /* Direction. */
   686         if (SDL_SYS_SetDirection(dest, &hap_constant->direction, dest->cAxes) < 0) {
   687             return -1;
   688         }
   689 
   690         /* Envelope */
   691         if ((hap_constant->attack_length == 0)
   692             && (hap_constant->fade_length == 0)) {
   693             SDL_free(dest->lpEnvelope);
   694             dest->lpEnvelope = NULL;
   695         } else {
   696             envelope->dwAttackLevel = CCONVERT(hap_constant->attack_level);
   697             envelope->dwAttackTime = hap_constant->attack_length * 1000;
   698             envelope->dwFadeLevel = CCONVERT(hap_constant->fade_level);
   699             envelope->dwFadeTime = hap_constant->fade_length * 1000;
   700         }
   701 
   702         break;
   703 
   704     case SDL_HAPTIC_SINE:
   705     /* !!! FIXME: put this back when we have more bits in 2.1 */
   706     /* case SDL_HAPTIC_SQUARE: */
   707     case SDL_HAPTIC_TRIANGLE:
   708     case SDL_HAPTIC_SAWTOOTHUP:
   709     case SDL_HAPTIC_SAWTOOTHDOWN:
   710         hap_periodic = &src->periodic;
   711         periodic = SDL_malloc(sizeof(DIPERIODIC));
   712         if (periodic == NULL) {
   713             return SDL_OutOfMemory();
   714         }
   715         SDL_memset(periodic, 0, sizeof(DIPERIODIC));
   716 
   717         /* Specifics */
   718         periodic->dwMagnitude = CONVERT(SDL_abs(hap_periodic->magnitude));
   719         periodic->lOffset = CONVERT(hap_periodic->offset);
   720         periodic->dwPhase = 
   721                 (hap_periodic->phase + (hap_periodic->magnitude < 0 ? 18000 : 0)) % 36000;
   722         periodic->dwPeriod = hap_periodic->period * 1000;
   723         dest->cbTypeSpecificParams = sizeof(DIPERIODIC);
   724         dest->lpvTypeSpecificParams = periodic;
   725 
   726         /* Generics */
   727         dest->dwDuration = hap_periodic->length * 1000; /* In microseconds. */
   728         dest->dwTriggerButton = DIGetTriggerButton(hap_periodic->button);
   729         dest->dwTriggerRepeatInterval = hap_periodic->interval;
   730         dest->dwStartDelay = hap_periodic->delay * 1000;        /* In microseconds. */
   731 
   732         /* Direction. */
   733         if (SDL_SYS_SetDirection(dest, &hap_periodic->direction, dest->cAxes)
   734             < 0) {
   735             return -1;
   736         }
   737 
   738         /* Envelope */
   739         if ((hap_periodic->attack_length == 0)
   740             && (hap_periodic->fade_length == 0)) {
   741             SDL_free(dest->lpEnvelope);
   742             dest->lpEnvelope = NULL;
   743         } else {
   744             envelope->dwAttackLevel = CCONVERT(hap_periodic->attack_level);
   745             envelope->dwAttackTime = hap_periodic->attack_length * 1000;
   746             envelope->dwFadeLevel = CCONVERT(hap_periodic->fade_level);
   747             envelope->dwFadeTime = hap_periodic->fade_length * 1000;
   748         }
   749 
   750         break;
   751 
   752     case SDL_HAPTIC_SPRING:
   753     case SDL_HAPTIC_DAMPER:
   754     case SDL_HAPTIC_INERTIA:
   755     case SDL_HAPTIC_FRICTION:
   756         hap_condition = &src->condition;
   757         condition = SDL_malloc(sizeof(DICONDITION) * dest->cAxes);
   758         if (condition == NULL) {
   759             return SDL_OutOfMemory();
   760         }
   761         SDL_memset(condition, 0, sizeof(DICONDITION));
   762 
   763         /* Specifics */
   764         for (i = 0; i < (int) dest->cAxes; i++) {
   765             condition[i].lOffset = CONVERT(hap_condition->center[i]);
   766             condition[i].lPositiveCoefficient =
   767                 CONVERT(hap_condition->right_coeff[i]);
   768             condition[i].lNegativeCoefficient =
   769                 CONVERT(hap_condition->left_coeff[i]);
   770             condition[i].dwPositiveSaturation =
   771                 CCONVERT(hap_condition->right_sat[i] / 2);
   772             condition[i].dwNegativeSaturation =
   773                 CCONVERT(hap_condition->left_sat[i] / 2);
   774             condition[i].lDeadBand = CCONVERT(hap_condition->deadband[i] / 2);
   775         }
   776         dest->cbTypeSpecificParams = sizeof(DICONDITION) * dest->cAxes;
   777         dest->lpvTypeSpecificParams = condition;
   778 
   779         /* Generics */
   780         dest->dwDuration = hap_condition->length * 1000;        /* In microseconds. */
   781         dest->dwTriggerButton = DIGetTriggerButton(hap_condition->button);
   782         dest->dwTriggerRepeatInterval = hap_condition->interval;
   783         dest->dwStartDelay = hap_condition->delay * 1000;       /* In microseconds. */
   784 
   785         /* Direction. */
   786         if (SDL_SYS_SetDirection(dest, &hap_condition->direction, dest->cAxes)
   787             < 0) {
   788             return -1;
   789         }
   790 
   791         /* Envelope - Not actually supported by most CONDITION implementations. */
   792         SDL_free(dest->lpEnvelope);
   793         dest->lpEnvelope = NULL;
   794 
   795         break;
   796 
   797     case SDL_HAPTIC_RAMP:
   798         hap_ramp = &src->ramp;
   799         ramp = SDL_malloc(sizeof(DIRAMPFORCE));
   800         if (ramp == NULL) {
   801             return SDL_OutOfMemory();
   802         }
   803         SDL_memset(ramp, 0, sizeof(DIRAMPFORCE));
   804 
   805         /* Specifics */
   806         ramp->lStart = CONVERT(hap_ramp->start);
   807         ramp->lEnd = CONVERT(hap_ramp->end);
   808         dest->cbTypeSpecificParams = sizeof(DIRAMPFORCE);
   809         dest->lpvTypeSpecificParams = ramp;
   810 
   811         /* Generics */
   812         dest->dwDuration = hap_ramp->length * 1000;     /* In microseconds. */
   813         dest->dwTriggerButton = DIGetTriggerButton(hap_ramp->button);
   814         dest->dwTriggerRepeatInterval = hap_ramp->interval;
   815         dest->dwStartDelay = hap_ramp->delay * 1000;    /* In microseconds. */
   816 
   817         /* Direction. */
   818         if (SDL_SYS_SetDirection(dest, &hap_ramp->direction, dest->cAxes) < 0) {
   819             return -1;
   820         }
   821 
   822         /* Envelope */
   823         if ((hap_ramp->attack_length == 0) && (hap_ramp->fade_length == 0)) {
   824             SDL_free(dest->lpEnvelope);
   825             dest->lpEnvelope = NULL;
   826         } else {
   827             envelope->dwAttackLevel = CCONVERT(hap_ramp->attack_level);
   828             envelope->dwAttackTime = hap_ramp->attack_length * 1000;
   829             envelope->dwFadeLevel = CCONVERT(hap_ramp->fade_level);
   830             envelope->dwFadeTime = hap_ramp->fade_length * 1000;
   831         }
   832 
   833         break;
   834 
   835     case SDL_HAPTIC_CUSTOM:
   836         hap_custom = &src->custom;
   837         custom = SDL_malloc(sizeof(DICUSTOMFORCE));
   838         if (custom == NULL) {
   839             return SDL_OutOfMemory();
   840         }
   841         SDL_memset(custom, 0, sizeof(DICUSTOMFORCE));
   842 
   843         /* Specifics */
   844         custom->cChannels = hap_custom->channels;
   845         custom->dwSamplePeriod = hap_custom->period * 1000;
   846         custom->cSamples = hap_custom->samples;
   847         custom->rglForceData =
   848             SDL_malloc(sizeof(LONG) * custom->cSamples * custom->cChannels);
   849         for (i = 0; i < hap_custom->samples * hap_custom->channels; i++) {      /* Copy data. */
   850             custom->rglForceData[i] = CCONVERT(hap_custom->data[i]);
   851         }
   852         dest->cbTypeSpecificParams = sizeof(DICUSTOMFORCE);
   853         dest->lpvTypeSpecificParams = custom;
   854 
   855         /* Generics */
   856         dest->dwDuration = hap_custom->length * 1000;   /* In microseconds. */
   857         dest->dwTriggerButton = DIGetTriggerButton(hap_custom->button);
   858         dest->dwTriggerRepeatInterval = hap_custom->interval;
   859         dest->dwStartDelay = hap_custom->delay * 1000;  /* In microseconds. */
   860 
   861         /* Direction. */
   862         if (SDL_SYS_SetDirection(dest, &hap_custom->direction, dest->cAxes) < 0) {
   863             return -1;
   864         }
   865 
   866         /* Envelope */
   867         if ((hap_custom->attack_length == 0)
   868             && (hap_custom->fade_length == 0)) {
   869             SDL_free(dest->lpEnvelope);
   870             dest->lpEnvelope = NULL;
   871         } else {
   872             envelope->dwAttackLevel = CCONVERT(hap_custom->attack_level);
   873             envelope->dwAttackTime = hap_custom->attack_length * 1000;
   874             envelope->dwFadeLevel = CCONVERT(hap_custom->fade_level);
   875             envelope->dwFadeTime = hap_custom->fade_length * 1000;
   876         }
   877 
   878         break;
   879 
   880     default:
   881         return SDL_SetError("Haptic: Unknown effect type.");
   882     }
   883 
   884     return 0;
   885 }
   886 
   887 
   888 /*
   889  * Frees an DIEFFECT allocated by SDL_SYS_ToDIEFFECT.
   890  */
   891 static void
   892 SDL_SYS_HapticFreeDIEFFECT(DIEFFECT * effect, int type)
   893 {
   894     DICUSTOMFORCE *custom;
   895 
   896     SDL_free(effect->lpEnvelope);
   897     effect->lpEnvelope = NULL;
   898     SDL_free(effect->rgdwAxes);
   899     effect->rgdwAxes = NULL;
   900     if (effect->lpvTypeSpecificParams != NULL) {
   901         if (type == SDL_HAPTIC_CUSTOM) {        /* Must free the custom data. */
   902             custom = (DICUSTOMFORCE *) effect->lpvTypeSpecificParams;
   903             SDL_free(custom->rglForceData);
   904             custom->rglForceData = NULL;
   905         }
   906         SDL_free(effect->lpvTypeSpecificParams);
   907         effect->lpvTypeSpecificParams = NULL;
   908     }
   909     SDL_free(effect->rglDirection);
   910     effect->rglDirection = NULL;
   911 }
   912 
   913 /*
   914  * Gets the effect type from the generic SDL haptic effect wrapper.
   915  */
   916 static REFGUID
   917 SDL_SYS_HapticEffectType(SDL_HapticEffect * effect)
   918 {
   919     switch (effect->type) {
   920     case SDL_HAPTIC_CONSTANT:
   921         return &GUID_ConstantForce;
   922 
   923     case SDL_HAPTIC_RAMP:
   924         return &GUID_RampForce;
   925 
   926     /* !!! FIXME: put this back when we have more bits in 2.1 */
   927     /* case SDL_HAPTIC_SQUARE:
   928         return &GUID_Square; */
   929 
   930     case SDL_HAPTIC_SINE:
   931         return &GUID_Sine;
   932 
   933     case SDL_HAPTIC_TRIANGLE:
   934         return &GUID_Triangle;
   935 
   936     case SDL_HAPTIC_SAWTOOTHUP:
   937         return &GUID_SawtoothUp;
   938 
   939     case SDL_HAPTIC_SAWTOOTHDOWN:
   940         return &GUID_SawtoothDown;
   941 
   942     case SDL_HAPTIC_SPRING:
   943         return &GUID_Spring;
   944 
   945     case SDL_HAPTIC_DAMPER:
   946         return &GUID_Damper;
   947 
   948     case SDL_HAPTIC_INERTIA:
   949         return &GUID_Inertia;
   950 
   951     case SDL_HAPTIC_FRICTION:
   952         return &GUID_Friction;
   953 
   954     case SDL_HAPTIC_CUSTOM:
   955         return &GUID_CustomForce;
   956 
   957     default:
   958         return NULL;
   959     }
   960 }
   961 int
   962 SDL_DINPUT_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * base)
   963 {
   964     HRESULT ret;
   965     REFGUID type = SDL_SYS_HapticEffectType(base);
   966 
   967     if (type == NULL) {
   968         SDL_SetError("Haptic: Unknown effect type.");
   969         return -1;
   970     }
   971 
   972     /* Get the effect. */
   973     if (SDL_SYS_ToDIEFFECT(haptic, &effect->hweffect->effect, base) < 0) {
   974         goto err_effectdone;
   975     }
   976 
   977     /* Create the actual effect. */
   978     ret = IDirectInputDevice8_CreateEffect(haptic->hwdata->device, type,
   979         &effect->hweffect->effect,
   980         &effect->hweffect->ref, NULL);
   981     if (FAILED(ret)) {
   982         DI_SetError("Unable to create effect", ret);
   983         goto err_effectdone;
   984     }
   985 
   986     return 0;
   987 
   988 err_effectdone:
   989     SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, base->type);
   990     return -1;
   991 }
   992 
   993 int
   994 SDL_DINPUT_HapticUpdateEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * data)
   995 {
   996     HRESULT ret;
   997     DWORD flags;
   998     DIEFFECT temp;
   999 
  1000     /* Get the effect. */
  1001     SDL_memset(&temp, 0, sizeof(DIEFFECT));
  1002     if (SDL_SYS_ToDIEFFECT(haptic, &temp, data) < 0) {
  1003         goto err_update;
  1004     }
  1005 
  1006     /* Set the flags.  Might be worthwhile to diff temp with loaded effect and
  1007     *  only change those parameters. */
  1008     flags = DIEP_DIRECTION |
  1009         DIEP_DURATION |
  1010         DIEP_ENVELOPE |
  1011         DIEP_STARTDELAY |
  1012         DIEP_TRIGGERBUTTON |
  1013         DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS;
  1014 
  1015     /* Create the actual effect. */
  1016     ret =
  1017         IDirectInputEffect_SetParameters(effect->hweffect->ref, &temp, flags);
  1018     if (FAILED(ret)) {
  1019         DI_SetError("Unable to update effect", ret);
  1020         goto err_update;
  1021     }
  1022 
  1023     /* Copy it over. */
  1024     SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, data->type);
  1025     SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(DIEFFECT));
  1026 
  1027     return 0;
  1028 
  1029 err_update:
  1030     SDL_SYS_HapticFreeDIEFFECT(&temp, data->type);
  1031     return -1;
  1032 }
  1033 
  1034 int
  1035 SDL_DINPUT_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect, Uint32 iterations)
  1036 {
  1037     HRESULT ret;
  1038     DWORD iter;
  1039 
  1040     /* Check if it's infinite. */
  1041     if (iterations == SDL_HAPTIC_INFINITY) {
  1042         iter = INFINITE;
  1043     } else {
  1044         iter = iterations;
  1045     }
  1046 
  1047     /* Run the effect. */
  1048     ret = IDirectInputEffect_Start(effect->hweffect->ref, iter, 0);
  1049     if (FAILED(ret)) {
  1050         return DI_SetError("Running the effect", ret);
  1051     }
  1052     return 0;
  1053 }
  1054 
  1055 int
  1056 SDL_DINPUT_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
  1057 {
  1058     HRESULT ret;
  1059 
  1060     ret = IDirectInputEffect_Stop(effect->hweffect->ref);
  1061     if (FAILED(ret)) {
  1062         return DI_SetError("Unable to stop effect", ret);
  1063     }
  1064     return 0;
  1065 }
  1066 
  1067 void
  1068 SDL_DINPUT_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
  1069 {
  1070     HRESULT ret;
  1071 
  1072     ret = IDirectInputEffect_Unload(effect->hweffect->ref);
  1073     if (FAILED(ret)) {
  1074         DI_SetError("Removing effect from the device", ret);
  1075     }
  1076     SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, effect->effect.type);
  1077 }
  1078 
  1079 int
  1080 SDL_DINPUT_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect *effect)
  1081 {
  1082     HRESULT ret;
  1083     DWORD status;
  1084 
  1085     ret = IDirectInputEffect_GetEffectStatus(effect->hweffect->ref, &status);
  1086     if (FAILED(ret)) {
  1087         return DI_SetError("Getting effect status", ret);
  1088     }
  1089 
  1090     if (status == 0)
  1091         return SDL_FALSE;
  1092     return SDL_TRUE;
  1093 }
  1094 
  1095 int
  1096 SDL_DINPUT_HapticSetGain(SDL_Haptic * haptic, int gain)
  1097 {
  1098     HRESULT ret;
  1099     DIPROPDWORD dipdw;
  1100 
  1101     /* Create the weird structure thingy. */
  1102     dipdw.diph.dwSize = sizeof(DIPROPDWORD);
  1103     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  1104     dipdw.diph.dwObj = 0;
  1105     dipdw.diph.dwHow = DIPH_DEVICE;
  1106     dipdw.dwData = gain * 100;  /* 0 to 10,000 */
  1107 
  1108     /* Try to set the autocenter. */
  1109     ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device,
  1110         DIPROP_FFGAIN, &dipdw.diph);
  1111     if (FAILED(ret)) {
  1112         return DI_SetError("Setting gain", ret);
  1113     }
  1114     return 0;
  1115 }
  1116 
  1117 int
  1118 SDL_DINPUT_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
  1119 {
  1120     HRESULT ret;
  1121     DIPROPDWORD dipdw;
  1122 
  1123     /* Create the weird structure thingy. */
  1124     dipdw.diph.dwSize = sizeof(DIPROPDWORD);
  1125     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  1126     dipdw.diph.dwObj = 0;
  1127     dipdw.diph.dwHow = DIPH_DEVICE;
  1128     dipdw.dwData = (autocenter == 0) ? DIPROPAUTOCENTER_OFF :
  1129         DIPROPAUTOCENTER_ON;
  1130 
  1131     /* Try to set the autocenter. */
  1132     ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device,
  1133         DIPROP_AUTOCENTER, &dipdw.diph);
  1134     if (FAILED(ret)) {
  1135         return DI_SetError("Setting autocenter", ret);
  1136     }
  1137     return 0;
  1138 }
  1139 
  1140 int
  1141 SDL_DINPUT_HapticPause(SDL_Haptic * haptic)
  1142 {
  1143     HRESULT ret;
  1144 
  1145     /* Pause the device. */
  1146     ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
  1147         DISFFC_PAUSE);
  1148     if (FAILED(ret)) {
  1149         return DI_SetError("Pausing the device", ret);
  1150     }
  1151     return 0;
  1152 }
  1153 
  1154 int
  1155 SDL_DINPUT_HapticUnpause(SDL_Haptic * haptic)
  1156 {
  1157     HRESULT ret;
  1158 
  1159     /* Unpause the device. */
  1160     ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
  1161         DISFFC_CONTINUE);
  1162     if (FAILED(ret)) {
  1163         return DI_SetError("Pausing the device", ret);
  1164     }
  1165     return 0;
  1166 }
  1167 
  1168 int
  1169 SDL_DINPUT_HapticStopAll(SDL_Haptic * haptic)
  1170 {
  1171     HRESULT ret;
  1172 
  1173     /* Try to stop the effects. */
  1174     ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
  1175         DISFFC_STOPALL);
  1176     if (FAILED(ret)) {
  1177         return DI_SetError("Stopping the device", ret);
  1178     }
  1179     return 0;
  1180 }
  1181 
  1182 #else /* !SDL_HAPTIC_DINPUT */
  1183 
  1184 typedef struct DIDEVICEINSTANCE DIDEVICEINSTANCE;
  1185 typedef struct SDL_hapticlist_item SDL_hapticlist_item;
  1186 
  1187 int
  1188 SDL_DINPUT_HapticInit(void)
  1189 {
  1190     return 0;
  1191 }
  1192 
  1193 int
  1194 SDL_DINPUT_MaybeAddDevice(const DIDEVICEINSTANCE * pdidInstance)
  1195 {
  1196     return SDL_Unsupported();
  1197 }
  1198 
  1199 int
  1200 SDL_DINPUT_MaybeRemoveDevice(const DIDEVICEINSTANCE * pdidInstance)
  1201 {
  1202     return SDL_Unsupported();
  1203 }
  1204 
  1205 int
  1206 SDL_DINPUT_HapticOpen(SDL_Haptic * haptic, SDL_hapticlist_item *item)
  1207 {
  1208     return SDL_Unsupported();
  1209 }
  1210 
  1211 int
  1212 SDL_DINPUT_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
  1213 {
  1214     return SDL_Unsupported();
  1215 }
  1216 
  1217 int
  1218 SDL_DINPUT_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
  1219 {
  1220     return SDL_Unsupported();
  1221 }
  1222 
  1223 void
  1224 SDL_DINPUT_HapticClose(SDL_Haptic * haptic)
  1225 {
  1226 }
  1227 
  1228 void
  1229 SDL_DINPUT_HapticQuit(void)
  1230 {
  1231 }
  1232 
  1233 int
  1234 SDL_DINPUT_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * base)
  1235 {
  1236     return SDL_Unsupported();
  1237 }
  1238 
  1239 int
  1240 SDL_DINPUT_HapticUpdateEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * data)
  1241 {
  1242     return SDL_Unsupported();
  1243 }
  1244 
  1245 int
  1246 SDL_DINPUT_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect, Uint32 iterations)
  1247 {
  1248     return SDL_Unsupported();
  1249 }
  1250 
  1251 int
  1252 SDL_DINPUT_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
  1253 {
  1254     return SDL_Unsupported();
  1255 }
  1256 
  1257 void
  1258 SDL_DINPUT_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
  1259 {
  1260 }
  1261 
  1262 int
  1263 SDL_DINPUT_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect *effect)
  1264 {
  1265     return SDL_Unsupported();
  1266 }
  1267 
  1268 int
  1269 SDL_DINPUT_HapticSetGain(SDL_Haptic * haptic, int gain)
  1270 {
  1271     return SDL_Unsupported();
  1272 }
  1273 
  1274 int
  1275 SDL_DINPUT_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
  1276 {
  1277     return SDL_Unsupported();
  1278 }
  1279 
  1280 int
  1281 SDL_DINPUT_HapticPause(SDL_Haptic * haptic)
  1282 {
  1283     return SDL_Unsupported();
  1284 }
  1285 
  1286 int
  1287 SDL_DINPUT_HapticUnpause(SDL_Haptic * haptic)
  1288 {
  1289     return SDL_Unsupported();
  1290 }
  1291 
  1292 int
  1293 SDL_DINPUT_HapticStopAll(SDL_Haptic * haptic)
  1294 {
  1295     return SDL_Unsupported();
  1296 }
  1297 
  1298 #endif /* SDL_HAPTIC_DINPUT */
  1299 
  1300 /* vi: set ts=4 sw=4 expandtab: */