src/haptic/windows/SDL_dinputhaptic.c
author Sam Lantinga
Fri, 27 Jan 2017 06:05:50 -0800
changeset 10856 486aa38c6a88
parent 10819 bab110e44dcb
child 10885 4528f2a99fb7
permissions -rw-r--r--
Added Thrustmaster Wheel FFB entry to the list of wheels
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 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                                                 &SDL_c_dfDIJoystick2);
   329         if (FAILED(ret)) {
   330             DI_SetError("Setting data format", ret);
   331             goto acquire_err;
   332         }
   333 
   334 
   335         /* Acquire the device. */
   336         ret = IDirectInputDevice8_Acquire(haptic->hwdata->device);
   337         if (FAILED(ret)) {
   338             DI_SetError("Acquiring DirectInput device", ret);
   339             goto acquire_err;
   340         }
   341     }
   342 
   343     /* Get number of axes. */
   344     ret = IDirectInputDevice8_EnumObjects(haptic->hwdata->device,
   345                                           DI_DeviceObjectCallback,
   346                                           haptic, DIDFT_AXIS);
   347     if (FAILED(ret)) {
   348         DI_SetError("Getting device axes", ret);
   349         goto acquire_err;
   350     }
   351 
   352     /* Reset all actuators - just in case. */
   353     ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
   354                                                        DISFFC_RESET);
   355     if (FAILED(ret)) {
   356         DI_SetError("Resetting device", ret);
   357         goto acquire_err;
   358     }
   359 
   360     /* Enabling actuators. */
   361     ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
   362                                                        DISFFC_SETACTUATORSON);
   363     if (FAILED(ret)) {
   364         DI_SetError("Enabling actuators", ret);
   365         goto acquire_err;
   366     }
   367 
   368     /* Get supported effects. */
   369     ret = IDirectInputDevice8_EnumEffects(haptic->hwdata->device,
   370                                           DI_EffectCallback, haptic,
   371                                           DIEFT_ALL);
   372     if (FAILED(ret)) {
   373         DI_SetError("Enumerating supported effects", ret);
   374         goto acquire_err;
   375     }
   376     if (haptic->supported == 0) {       /* Error since device supports nothing. */
   377         SDL_SetError("Haptic: Internal error on finding supported effects.");
   378         goto acquire_err;
   379     }
   380 
   381     /* Check autogain and autocenter. */
   382     dipdw.diph.dwSize = sizeof(DIPROPDWORD);
   383     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
   384     dipdw.diph.dwObj = 0;
   385     dipdw.diph.dwHow = DIPH_DEVICE;
   386     dipdw.dwData = 10000;
   387     ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device,
   388                                           DIPROP_FFGAIN, &dipdw.diph);
   389     if (!FAILED(ret)) {         /* Gain is supported. */
   390         haptic->supported |= SDL_HAPTIC_GAIN;
   391     }
   392     dipdw.diph.dwObj = 0;
   393     dipdw.diph.dwHow = DIPH_DEVICE;
   394     dipdw.dwData = DIPROPAUTOCENTER_OFF;
   395     ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device,
   396                                           DIPROP_AUTOCENTER, &dipdw.diph);
   397     if (!FAILED(ret)) {         /* Autocenter is supported. */
   398         haptic->supported |= SDL_HAPTIC_AUTOCENTER;
   399     }
   400 
   401     /* Status is always supported. */
   402     haptic->supported |= SDL_HAPTIC_STATUS | SDL_HAPTIC_PAUSE;
   403 
   404     /* Check maximum effects. */
   405     haptic->neffects = 128;     /* This is not actually supported as thus under windows,
   406                                    there is no way to tell the number of EFFECTS that a
   407                                    device can hold, so we'll just use a "random" number
   408                                    instead and put warnings in SDL_haptic.h */
   409     haptic->nplaying = 128;     /* Even more impossible to get this then neffects. */
   410 
   411     /* Prepare effects memory. */
   412     haptic->effects = (struct haptic_effect *)
   413         SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
   414     if (haptic->effects == NULL) {
   415         SDL_OutOfMemory();
   416         goto acquire_err;
   417     }
   418     /* Clear the memory */
   419     SDL_memset(haptic->effects, 0,
   420                sizeof(struct haptic_effect) * haptic->neffects);
   421 
   422     return 0;
   423 
   424     /* Error handling */
   425   acquire_err:
   426     IDirectInputDevice8_Unacquire(haptic->hwdata->device);
   427     return -1;
   428 }
   429 
   430 int
   431 SDL_DINPUT_HapticOpen(SDL_Haptic * haptic, SDL_hapticlist_item *item)
   432 {
   433     HRESULT ret;
   434     LPDIRECTINPUTDEVICE8 device;
   435     LPDIRECTINPUTDEVICE8 device8;
   436 
   437     /* Open the device */
   438     ret = IDirectInput8_CreateDevice(dinput, &item->instance.guidInstance,
   439         &device, NULL);
   440     if (FAILED(ret)) {
   441         DI_SetError("Creating DirectInput device", ret);
   442         return -1;
   443     }
   444 
   445     /* Now get the IDirectInputDevice8 interface, instead. */
   446     ret = IDirectInputDevice8_QueryInterface(device,
   447         &IID_IDirectInputDevice8,
   448         (LPVOID *)&device8);
   449     /* Done with the temporary one now. */
   450     IDirectInputDevice8_Release(device);
   451     if (FAILED(ret)) {
   452         DI_SetError("Querying DirectInput interface", ret);
   453         return -1;
   454     }
   455 
   456     if (SDL_DINPUT_HapticOpenFromDevice(haptic, device8, SDL_FALSE) < 0) {
   457         IDirectInputDevice8_Release(device8);
   458         return -1;
   459     }
   460     return 0;
   461 }
   462 
   463 int
   464 SDL_DINPUT_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
   465 {
   466     HRESULT ret;
   467     DIDEVICEINSTANCE hap_instance, joy_instance;
   468 
   469     hap_instance.dwSize = sizeof(DIDEVICEINSTANCE);
   470     joy_instance.dwSize = sizeof(DIDEVICEINSTANCE);
   471 
   472     /* Get the device instances. */
   473     ret = IDirectInputDevice8_GetDeviceInfo(haptic->hwdata->device,
   474         &hap_instance);
   475     if (FAILED(ret)) {
   476         return 0;
   477     }
   478     ret = IDirectInputDevice8_GetDeviceInfo(joystick->hwdata->InputDevice,
   479         &joy_instance);
   480     if (FAILED(ret)) {
   481         return 0;
   482     }
   483 
   484     return DI_GUIDIsSame(&hap_instance.guidInstance, &joy_instance.guidInstance);
   485 }
   486 
   487 int
   488 SDL_DINPUT_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
   489 {
   490     SDL_hapticlist_item *item;
   491     int index = 0;
   492     HRESULT ret;
   493     DIDEVICEINSTANCE joy_instance;
   494 
   495     joy_instance.dwSize = sizeof(DIDEVICEINSTANCE);
   496     ret = IDirectInputDevice8_GetDeviceInfo(joystick->hwdata->InputDevice, &joy_instance);
   497     if (FAILED(ret)) {
   498         return -1;
   499     }
   500 
   501     /* Since it comes from a joystick we have to try to match it with a haptic device on our haptic list. */
   502     for (item = SDL_hapticlist; item != NULL; item = item->next) {
   503         if (!item->bXInputHaptic && DI_GUIDIsSame(&item->instance.guidInstance, &joy_instance.guidInstance)) {
   504             haptic->index = index;
   505             return SDL_DINPUT_HapticOpenFromDevice(haptic, joystick->hwdata->InputDevice, SDL_TRUE);
   506         }
   507         ++index;
   508     }
   509 
   510     SDL_SetError("Couldn't find joystick in haptic device list");
   511     return -1;
   512 }
   513 
   514 void
   515 SDL_DINPUT_HapticClose(SDL_Haptic * haptic)
   516 {
   517     IDirectInputDevice8_Unacquire(haptic->hwdata->device);
   518 
   519     /* Only release if isn't grabbed by a joystick. */
   520     if (haptic->hwdata->is_joystick == 0) {
   521         IDirectInputDevice8_Release(haptic->hwdata->device);
   522     }
   523 }
   524 
   525 void
   526 SDL_DINPUT_HapticQuit(void)
   527 {
   528     if (dinput != NULL) {
   529         IDirectInput8_Release(dinput);
   530         dinput = NULL;
   531     }
   532 
   533     if (coinitialized) {
   534         WIN_CoUninitialize();
   535         coinitialized = SDL_FALSE;
   536     }
   537 }
   538 
   539 /*
   540  * Converts an SDL trigger button to an DIEFFECT trigger button.
   541  */
   542 static DWORD
   543 DIGetTriggerButton(Uint16 button)
   544 {
   545     DWORD dwTriggerButton;
   546 
   547     dwTriggerButton = DIEB_NOTRIGGER;
   548 
   549     if (button != 0) {
   550         dwTriggerButton = DIJOFS_BUTTON(button - 1);
   551     }
   552 
   553     return dwTriggerButton;
   554 }
   555 
   556 
   557 /*
   558  * Sets the direction.
   559  */
   560 static int
   561 SDL_SYS_SetDirection(DIEFFECT * effect, SDL_HapticDirection * dir, int naxes)
   562 {
   563     LONG *rglDir;
   564 
   565     /* Handle no axes a part. */
   566     if (naxes == 0) {
   567         effect->dwFlags |= DIEFF_SPHERICAL;     /* Set as default. */
   568         effect->rglDirection = NULL;
   569         return 0;
   570     }
   571 
   572     /* Has axes. */
   573     rglDir = SDL_malloc(sizeof(LONG) * naxes);
   574     if (rglDir == NULL) {
   575         return SDL_OutOfMemory();
   576     }
   577     SDL_memset(rglDir, 0, sizeof(LONG) * naxes);
   578     effect->rglDirection = rglDir;
   579 
   580     switch (dir->type) {
   581     case SDL_HAPTIC_POLAR:
   582         effect->dwFlags |= DIEFF_POLAR;
   583         rglDir[0] = dir->dir[0];
   584         return 0;
   585     case SDL_HAPTIC_CARTESIAN:
   586         effect->dwFlags |= DIEFF_CARTESIAN;
   587         rglDir[0] = dir->dir[0];
   588         if (naxes > 1)
   589             rglDir[1] = dir->dir[1];
   590         if (naxes > 2)
   591             rglDir[2] = dir->dir[2];
   592         return 0;
   593     case SDL_HAPTIC_SPHERICAL:
   594         effect->dwFlags |= DIEFF_SPHERICAL;
   595         rglDir[0] = dir->dir[0];
   596         if (naxes > 1)
   597             rglDir[1] = dir->dir[1];
   598         if (naxes > 2)
   599             rglDir[2] = dir->dir[2];
   600         return 0;
   601 
   602     default:
   603         return SDL_SetError("Haptic: Unknown direction type.");
   604     }
   605 }
   606 
   607 /* Clamps and converts. */
   608 #define CCONVERT(x)   (((x) > 0x7FFF) ? 10000 : ((x)*10000) / 0x7FFF)
   609 /* Just converts. */
   610 #define CONVERT(x)    (((x)*10000) / 0x7FFF)
   611 /*
   612  * Creates the DIEFFECT from a SDL_HapticEffect.
   613  */
   614 static int
   615 SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic, DIEFFECT * dest,
   616                    SDL_HapticEffect * src)
   617 {
   618     int i;
   619     DICONSTANTFORCE *constant;
   620     DIPERIODIC *periodic;
   621     DICONDITION *condition;     /* Actually an array of conditions - one per axis. */
   622     DIRAMPFORCE *ramp;
   623     DICUSTOMFORCE *custom;
   624     DIENVELOPE *envelope;
   625     SDL_HapticConstant *hap_constant;
   626     SDL_HapticPeriodic *hap_periodic;
   627     SDL_HapticCondition *hap_condition;
   628     SDL_HapticRamp *hap_ramp;
   629     SDL_HapticCustom *hap_custom;
   630     DWORD *axes;
   631 
   632     /* Set global stuff. */
   633     SDL_memset(dest, 0, sizeof(DIEFFECT));
   634     dest->dwSize = sizeof(DIEFFECT);    /* Set the structure size. */
   635     dest->dwSamplePeriod = 0;   /* Not used by us. */
   636     dest->dwGain = 10000;       /* Gain is set globally, not locally. */
   637     dest->dwFlags = DIEFF_OBJECTOFFSETS;        /* Seems obligatory. */
   638 
   639     /* Envelope. */
   640     envelope = SDL_malloc(sizeof(DIENVELOPE));
   641     if (envelope == NULL) {
   642         return SDL_OutOfMemory();
   643     }
   644     SDL_memset(envelope, 0, sizeof(DIENVELOPE));
   645     dest->lpEnvelope = envelope;
   646     envelope->dwSize = sizeof(DIENVELOPE);      /* Always should be this. */
   647 
   648     /* Axes. */
   649     dest->cAxes = haptic->naxes;
   650     if (dest->cAxes > 0) {
   651         axes = SDL_malloc(sizeof(DWORD) * dest->cAxes);
   652         if (axes == NULL) {
   653             return SDL_OutOfMemory();
   654         }
   655         axes[0] = haptic->hwdata->axes[0];      /* Always at least one axis. */
   656         if (dest->cAxes > 1) {
   657             axes[1] = haptic->hwdata->axes[1];
   658         }
   659         if (dest->cAxes > 2) {
   660             axes[2] = haptic->hwdata->axes[2];
   661         }
   662         dest->rgdwAxes = axes;
   663     }
   664 
   665     /* The big type handling switch, even bigger than Linux's version. */
   666     switch (src->type) {
   667     case SDL_HAPTIC_CONSTANT:
   668         hap_constant = &src->constant;
   669         constant = SDL_malloc(sizeof(DICONSTANTFORCE));
   670         if (constant == NULL) {
   671             return SDL_OutOfMemory();
   672         }
   673         SDL_memset(constant, 0, sizeof(DICONSTANTFORCE));
   674 
   675         /* Specifics */
   676         constant->lMagnitude = CONVERT(hap_constant->level);
   677         dest->cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
   678         dest->lpvTypeSpecificParams = constant;
   679 
   680         /* Generics */
   681         dest->dwDuration = hap_constant->length * 1000; /* In microseconds. */
   682         dest->dwTriggerButton = DIGetTriggerButton(hap_constant->button);
   683         dest->dwTriggerRepeatInterval = hap_constant->interval;
   684         dest->dwStartDelay = hap_constant->delay * 1000;        /* In microseconds. */
   685 
   686         /* Direction. */
   687         if (SDL_SYS_SetDirection(dest, &hap_constant->direction, dest->cAxes) < 0) {
   688             return -1;
   689         }
   690 
   691         /* Envelope */
   692         if ((hap_constant->attack_length == 0)
   693             && (hap_constant->fade_length == 0)) {
   694             SDL_free(dest->lpEnvelope);
   695             dest->lpEnvelope = NULL;
   696         } else {
   697             envelope->dwAttackLevel = CCONVERT(hap_constant->attack_level);
   698             envelope->dwAttackTime = hap_constant->attack_length * 1000;
   699             envelope->dwFadeLevel = CCONVERT(hap_constant->fade_level);
   700             envelope->dwFadeTime = hap_constant->fade_length * 1000;
   701         }
   702 
   703         break;
   704 
   705     case SDL_HAPTIC_SINE:
   706     /* !!! FIXME: put this back when we have more bits in 2.1 */
   707     /* case SDL_HAPTIC_SQUARE: */
   708     case SDL_HAPTIC_TRIANGLE:
   709     case SDL_HAPTIC_SAWTOOTHUP:
   710     case SDL_HAPTIC_SAWTOOTHDOWN:
   711         hap_periodic = &src->periodic;
   712         periodic = SDL_malloc(sizeof(DIPERIODIC));
   713         if (periodic == NULL) {
   714             return SDL_OutOfMemory();
   715         }
   716         SDL_memset(periodic, 0, sizeof(DIPERIODIC));
   717 
   718         /* Specifics */
   719         periodic->dwMagnitude = CONVERT(SDL_abs(hap_periodic->magnitude));
   720         periodic->lOffset = CONVERT(hap_periodic->offset);
   721         periodic->dwPhase = 
   722                 (hap_periodic->phase + (hap_periodic->magnitude < 0 ? 18000 : 0)) % 36000;
   723         periodic->dwPeriod = hap_periodic->period * 1000;
   724         dest->cbTypeSpecificParams = sizeof(DIPERIODIC);
   725         dest->lpvTypeSpecificParams = periodic;
   726 
   727         /* Generics */
   728         dest->dwDuration = hap_periodic->length * 1000; /* In microseconds. */
   729         dest->dwTriggerButton = DIGetTriggerButton(hap_periodic->button);
   730         dest->dwTriggerRepeatInterval = hap_periodic->interval;
   731         dest->dwStartDelay = hap_periodic->delay * 1000;        /* In microseconds. */
   732 
   733         /* Direction. */
   734         if (SDL_SYS_SetDirection(dest, &hap_periodic->direction, dest->cAxes)
   735             < 0) {
   736             return -1;
   737         }
   738 
   739         /* Envelope */
   740         if ((hap_periodic->attack_length == 0)
   741             && (hap_periodic->fade_length == 0)) {
   742             SDL_free(dest->lpEnvelope);
   743             dest->lpEnvelope = NULL;
   744         } else {
   745             envelope->dwAttackLevel = CCONVERT(hap_periodic->attack_level);
   746             envelope->dwAttackTime = hap_periodic->attack_length * 1000;
   747             envelope->dwFadeLevel = CCONVERT(hap_periodic->fade_level);
   748             envelope->dwFadeTime = hap_periodic->fade_length * 1000;
   749         }
   750 
   751         break;
   752 
   753     case SDL_HAPTIC_SPRING:
   754     case SDL_HAPTIC_DAMPER:
   755     case SDL_HAPTIC_INERTIA:
   756     case SDL_HAPTIC_FRICTION:
   757         hap_condition = &src->condition;
   758         condition = SDL_malloc(sizeof(DICONDITION) * dest->cAxes);
   759         if (condition == NULL) {
   760             return SDL_OutOfMemory();
   761         }
   762         SDL_memset(condition, 0, sizeof(DICONDITION));
   763 
   764         /* Specifics */
   765         for (i = 0; i < (int) dest->cAxes; i++) {
   766             condition[i].lOffset = CONVERT(hap_condition->center[i]);
   767             condition[i].lPositiveCoefficient =
   768                 CONVERT(hap_condition->right_coeff[i]);
   769             condition[i].lNegativeCoefficient =
   770                 CONVERT(hap_condition->left_coeff[i]);
   771             condition[i].dwPositiveSaturation =
   772                 CCONVERT(hap_condition->right_sat[i] / 2);
   773             condition[i].dwNegativeSaturation =
   774                 CCONVERT(hap_condition->left_sat[i] / 2);
   775             condition[i].lDeadBand = CCONVERT(hap_condition->deadband[i] / 2);
   776         }
   777         dest->cbTypeSpecificParams = sizeof(DICONDITION) * dest->cAxes;
   778         dest->lpvTypeSpecificParams = condition;
   779 
   780         /* Generics */
   781         dest->dwDuration = hap_condition->length * 1000;        /* In microseconds. */
   782         dest->dwTriggerButton = DIGetTriggerButton(hap_condition->button);
   783         dest->dwTriggerRepeatInterval = hap_condition->interval;
   784         dest->dwStartDelay = hap_condition->delay * 1000;       /* In microseconds. */
   785 
   786         /* Direction. */
   787         if (SDL_SYS_SetDirection(dest, &hap_condition->direction, dest->cAxes)
   788             < 0) {
   789             return -1;
   790         }
   791 
   792         /* Envelope - Not actually supported by most CONDITION implementations. */
   793         SDL_free(dest->lpEnvelope);
   794         dest->lpEnvelope = NULL;
   795 
   796         break;
   797 
   798     case SDL_HAPTIC_RAMP:
   799         hap_ramp = &src->ramp;
   800         ramp = SDL_malloc(sizeof(DIRAMPFORCE));
   801         if (ramp == NULL) {
   802             return SDL_OutOfMemory();
   803         }
   804         SDL_memset(ramp, 0, sizeof(DIRAMPFORCE));
   805 
   806         /* Specifics */
   807         ramp->lStart = CONVERT(hap_ramp->start);
   808         ramp->lEnd = CONVERT(hap_ramp->end);
   809         dest->cbTypeSpecificParams = sizeof(DIRAMPFORCE);
   810         dest->lpvTypeSpecificParams = ramp;
   811 
   812         /* Generics */
   813         dest->dwDuration = hap_ramp->length * 1000;     /* In microseconds. */
   814         dest->dwTriggerButton = DIGetTriggerButton(hap_ramp->button);
   815         dest->dwTriggerRepeatInterval = hap_ramp->interval;
   816         dest->dwStartDelay = hap_ramp->delay * 1000;    /* In microseconds. */
   817 
   818         /* Direction. */
   819         if (SDL_SYS_SetDirection(dest, &hap_ramp->direction, dest->cAxes) < 0) {
   820             return -1;
   821         }
   822 
   823         /* Envelope */
   824         if ((hap_ramp->attack_length == 0) && (hap_ramp->fade_length == 0)) {
   825             SDL_free(dest->lpEnvelope);
   826             dest->lpEnvelope = NULL;
   827         } else {
   828             envelope->dwAttackLevel = CCONVERT(hap_ramp->attack_level);
   829             envelope->dwAttackTime = hap_ramp->attack_length * 1000;
   830             envelope->dwFadeLevel = CCONVERT(hap_ramp->fade_level);
   831             envelope->dwFadeTime = hap_ramp->fade_length * 1000;
   832         }
   833 
   834         break;
   835 
   836     case SDL_HAPTIC_CUSTOM:
   837         hap_custom = &src->custom;
   838         custom = SDL_malloc(sizeof(DICUSTOMFORCE));
   839         if (custom == NULL) {
   840             return SDL_OutOfMemory();
   841         }
   842         SDL_memset(custom, 0, sizeof(DICUSTOMFORCE));
   843 
   844         /* Specifics */
   845         custom->cChannels = hap_custom->channels;
   846         custom->dwSamplePeriod = hap_custom->period * 1000;
   847         custom->cSamples = hap_custom->samples;
   848         custom->rglForceData =
   849             SDL_malloc(sizeof(LONG) * custom->cSamples * custom->cChannels);
   850         for (i = 0; i < hap_custom->samples * hap_custom->channels; i++) {      /* Copy data. */
   851             custom->rglForceData[i] = CCONVERT(hap_custom->data[i]);
   852         }
   853         dest->cbTypeSpecificParams = sizeof(DICUSTOMFORCE);
   854         dest->lpvTypeSpecificParams = custom;
   855 
   856         /* Generics */
   857         dest->dwDuration = hap_custom->length * 1000;   /* In microseconds. */
   858         dest->dwTriggerButton = DIGetTriggerButton(hap_custom->button);
   859         dest->dwTriggerRepeatInterval = hap_custom->interval;
   860         dest->dwStartDelay = hap_custom->delay * 1000;  /* In microseconds. */
   861 
   862         /* Direction. */
   863         if (SDL_SYS_SetDirection(dest, &hap_custom->direction, dest->cAxes) < 0) {
   864             return -1;
   865         }
   866 
   867         /* Envelope */
   868         if ((hap_custom->attack_length == 0)
   869             && (hap_custom->fade_length == 0)) {
   870             SDL_free(dest->lpEnvelope);
   871             dest->lpEnvelope = NULL;
   872         } else {
   873             envelope->dwAttackLevel = CCONVERT(hap_custom->attack_level);
   874             envelope->dwAttackTime = hap_custom->attack_length * 1000;
   875             envelope->dwFadeLevel = CCONVERT(hap_custom->fade_level);
   876             envelope->dwFadeTime = hap_custom->fade_length * 1000;
   877         }
   878 
   879         break;
   880 
   881     default:
   882         return SDL_SetError("Haptic: Unknown effect type.");
   883     }
   884 
   885     return 0;
   886 }
   887 
   888 
   889 /*
   890  * Frees an DIEFFECT allocated by SDL_SYS_ToDIEFFECT.
   891  */
   892 static void
   893 SDL_SYS_HapticFreeDIEFFECT(DIEFFECT * effect, int type)
   894 {
   895     DICUSTOMFORCE *custom;
   896 
   897     SDL_free(effect->lpEnvelope);
   898     effect->lpEnvelope = NULL;
   899     SDL_free(effect->rgdwAxes);
   900     effect->rgdwAxes = NULL;
   901     if (effect->lpvTypeSpecificParams != NULL) {
   902         if (type == SDL_HAPTIC_CUSTOM) {        /* Must free the custom data. */
   903             custom = (DICUSTOMFORCE *) effect->lpvTypeSpecificParams;
   904             SDL_free(custom->rglForceData);
   905             custom->rglForceData = NULL;
   906         }
   907         SDL_free(effect->lpvTypeSpecificParams);
   908         effect->lpvTypeSpecificParams = NULL;
   909     }
   910     SDL_free(effect->rglDirection);
   911     effect->rglDirection = NULL;
   912 }
   913 
   914 /*
   915  * Gets the effect type from the generic SDL haptic effect wrapper.
   916  */
   917 static REFGUID
   918 SDL_SYS_HapticEffectType(SDL_HapticEffect * effect)
   919 {
   920     switch (effect->type) {
   921     case SDL_HAPTIC_CONSTANT:
   922         return &GUID_ConstantForce;
   923 
   924     case SDL_HAPTIC_RAMP:
   925         return &GUID_RampForce;
   926 
   927     /* !!! FIXME: put this back when we have more bits in 2.1 */
   928     /* case SDL_HAPTIC_SQUARE:
   929         return &GUID_Square; */
   930 
   931     case SDL_HAPTIC_SINE:
   932         return &GUID_Sine;
   933 
   934     case SDL_HAPTIC_TRIANGLE:
   935         return &GUID_Triangle;
   936 
   937     case SDL_HAPTIC_SAWTOOTHUP:
   938         return &GUID_SawtoothUp;
   939 
   940     case SDL_HAPTIC_SAWTOOTHDOWN:
   941         return &GUID_SawtoothDown;
   942 
   943     case SDL_HAPTIC_SPRING:
   944         return &GUID_Spring;
   945 
   946     case SDL_HAPTIC_DAMPER:
   947         return &GUID_Damper;
   948 
   949     case SDL_HAPTIC_INERTIA:
   950         return &GUID_Inertia;
   951 
   952     case SDL_HAPTIC_FRICTION:
   953         return &GUID_Friction;
   954 
   955     case SDL_HAPTIC_CUSTOM:
   956         return &GUID_CustomForce;
   957 
   958     default:
   959         return NULL;
   960     }
   961 }
   962 int
   963 SDL_DINPUT_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * base)
   964 {
   965     HRESULT ret;
   966     REFGUID type = SDL_SYS_HapticEffectType(base);
   967 
   968     if (type == NULL) {
   969         SDL_SetError("Haptic: Unknown effect type.");
   970         return -1;
   971     }
   972 
   973     /* Get the effect. */
   974     if (SDL_SYS_ToDIEFFECT(haptic, &effect->hweffect->effect, base) < 0) {
   975         goto err_effectdone;
   976     }
   977 
   978     /* Create the actual effect. */
   979     ret = IDirectInputDevice8_CreateEffect(haptic->hwdata->device, type,
   980         &effect->hweffect->effect,
   981         &effect->hweffect->ref, NULL);
   982     if (FAILED(ret)) {
   983         DI_SetError("Unable to create effect", ret);
   984         goto err_effectdone;
   985     }
   986 
   987     return 0;
   988 
   989 err_effectdone:
   990     SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, base->type);
   991     return -1;
   992 }
   993 
   994 int
   995 SDL_DINPUT_HapticUpdateEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * data)
   996 {
   997     HRESULT ret;
   998     DWORD flags;
   999     DIEFFECT temp;
  1000 
  1001     /* Get the effect. */
  1002     SDL_memset(&temp, 0, sizeof(DIEFFECT));
  1003     if (SDL_SYS_ToDIEFFECT(haptic, &temp, data) < 0) {
  1004         goto err_update;
  1005     }
  1006 
  1007     /* Set the flags.  Might be worthwhile to diff temp with loaded effect and
  1008     *  only change those parameters. */
  1009     flags = DIEP_DIRECTION |
  1010         DIEP_DURATION |
  1011         DIEP_ENVELOPE |
  1012         DIEP_STARTDELAY |
  1013         DIEP_TRIGGERBUTTON |
  1014         DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS;
  1015 
  1016     /* Create the actual effect. */
  1017     ret =
  1018         IDirectInputEffect_SetParameters(effect->hweffect->ref, &temp, flags);
  1019     if (ret == DIERR_NOTEXCLUSIVEACQUIRED) {
  1020         IDirectInputDevice8_Unacquire(haptic->hwdata->device);
  1021         ret = IDirectInputDevice8_SetCooperativeLevel(haptic->hwdata->device, SDL_HelperWindow, DISCL_EXCLUSIVE | DISCL_BACKGROUND);
  1022         if (SUCCEEDED(ret)) {
  1023             ret = DIERR_NOTACQUIRED;
  1024         }
  1025     }
  1026     if (ret == DIERR_INPUTLOST || ret == DIERR_NOTACQUIRED) {
  1027         ret = IDirectInputDevice8_Acquire(haptic->hwdata->device);
  1028         if (SUCCEEDED(ret)) {
  1029             ret = IDirectInputEffect_SetParameters(effect->hweffect->ref, &temp, flags);
  1030         }
  1031     }
  1032     if (FAILED(ret)) {
  1033         DI_SetError("Unable to update effect", ret);
  1034         goto err_update;
  1035     }
  1036 
  1037     /* Copy it over. */
  1038     SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, data->type);
  1039     SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(DIEFFECT));
  1040 
  1041     return 0;
  1042 
  1043 err_update:
  1044     SDL_SYS_HapticFreeDIEFFECT(&temp, data->type);
  1045     return -1;
  1046 }
  1047 
  1048 int
  1049 SDL_DINPUT_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect, Uint32 iterations)
  1050 {
  1051     HRESULT ret;
  1052     DWORD iter;
  1053 
  1054     /* Check if it's infinite. */
  1055     if (iterations == SDL_HAPTIC_INFINITY) {
  1056         iter = INFINITE;
  1057     } else {
  1058         iter = iterations;
  1059     }
  1060 
  1061     /* Run the effect. */
  1062     ret = IDirectInputEffect_Start(effect->hweffect->ref, iter, 0);
  1063     if (FAILED(ret)) {
  1064         return DI_SetError("Running the effect", ret);
  1065     }
  1066     return 0;
  1067 }
  1068 
  1069 int
  1070 SDL_DINPUT_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
  1071 {
  1072     HRESULT ret;
  1073 
  1074     ret = IDirectInputEffect_Stop(effect->hweffect->ref);
  1075     if (FAILED(ret)) {
  1076         return DI_SetError("Unable to stop effect", ret);
  1077     }
  1078     return 0;
  1079 }
  1080 
  1081 void
  1082 SDL_DINPUT_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
  1083 {
  1084     HRESULT ret;
  1085 
  1086     ret = IDirectInputEffect_Unload(effect->hweffect->ref);
  1087     if (FAILED(ret)) {
  1088         DI_SetError("Removing effect from the device", ret);
  1089     }
  1090     SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, effect->effect.type);
  1091 }
  1092 
  1093 int
  1094 SDL_DINPUT_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect *effect)
  1095 {
  1096     HRESULT ret;
  1097     DWORD status;
  1098 
  1099     ret = IDirectInputEffect_GetEffectStatus(effect->hweffect->ref, &status);
  1100     if (FAILED(ret)) {
  1101         return DI_SetError("Getting effect status", ret);
  1102     }
  1103 
  1104     if (status == 0)
  1105         return SDL_FALSE;
  1106     return SDL_TRUE;
  1107 }
  1108 
  1109 int
  1110 SDL_DINPUT_HapticSetGain(SDL_Haptic * haptic, int gain)
  1111 {
  1112     HRESULT ret;
  1113     DIPROPDWORD dipdw;
  1114 
  1115     /* Create the weird structure thingy. */
  1116     dipdw.diph.dwSize = sizeof(DIPROPDWORD);
  1117     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  1118     dipdw.diph.dwObj = 0;
  1119     dipdw.diph.dwHow = DIPH_DEVICE;
  1120     dipdw.dwData = gain * 100;  /* 0 to 10,000 */
  1121 
  1122     /* Try to set the autocenter. */
  1123     ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device,
  1124         DIPROP_FFGAIN, &dipdw.diph);
  1125     if (FAILED(ret)) {
  1126         return DI_SetError("Setting gain", ret);
  1127     }
  1128     return 0;
  1129 }
  1130 
  1131 int
  1132 SDL_DINPUT_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
  1133 {
  1134     HRESULT ret;
  1135     DIPROPDWORD dipdw;
  1136 
  1137     /* Create the weird structure thingy. */
  1138     dipdw.diph.dwSize = sizeof(DIPROPDWORD);
  1139     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  1140     dipdw.diph.dwObj = 0;
  1141     dipdw.diph.dwHow = DIPH_DEVICE;
  1142     dipdw.dwData = (autocenter == 0) ? DIPROPAUTOCENTER_OFF :
  1143         DIPROPAUTOCENTER_ON;
  1144 
  1145     /* Try to set the autocenter. */
  1146     ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device,
  1147         DIPROP_AUTOCENTER, &dipdw.diph);
  1148     if (FAILED(ret)) {
  1149         return DI_SetError("Setting autocenter", ret);
  1150     }
  1151     return 0;
  1152 }
  1153 
  1154 int
  1155 SDL_DINPUT_HapticPause(SDL_Haptic * haptic)
  1156 {
  1157     HRESULT ret;
  1158 
  1159     /* Pause the device. */
  1160     ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
  1161         DISFFC_PAUSE);
  1162     if (FAILED(ret)) {
  1163         return DI_SetError("Pausing the device", ret);
  1164     }
  1165     return 0;
  1166 }
  1167 
  1168 int
  1169 SDL_DINPUT_HapticUnpause(SDL_Haptic * haptic)
  1170 {
  1171     HRESULT ret;
  1172 
  1173     /* Unpause the device. */
  1174     ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
  1175         DISFFC_CONTINUE);
  1176     if (FAILED(ret)) {
  1177         return DI_SetError("Pausing the device", ret);
  1178     }
  1179     return 0;
  1180 }
  1181 
  1182 int
  1183 SDL_DINPUT_HapticStopAll(SDL_Haptic * haptic)
  1184 {
  1185     HRESULT ret;
  1186 
  1187     /* Try to stop the effects. */
  1188     ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
  1189         DISFFC_STOPALL);
  1190     if (FAILED(ret)) {
  1191         return DI_SetError("Stopping the device", ret);
  1192     }
  1193     return 0;
  1194 }
  1195 
  1196 #else /* !SDL_HAPTIC_DINPUT */
  1197 
  1198 typedef struct DIDEVICEINSTANCE DIDEVICEINSTANCE;
  1199 typedef struct SDL_hapticlist_item SDL_hapticlist_item;
  1200 
  1201 int
  1202 SDL_DINPUT_HapticInit(void)
  1203 {
  1204     return 0;
  1205 }
  1206 
  1207 int
  1208 SDL_DINPUT_MaybeAddDevice(const DIDEVICEINSTANCE * pdidInstance)
  1209 {
  1210     return SDL_Unsupported();
  1211 }
  1212 
  1213 int
  1214 SDL_DINPUT_MaybeRemoveDevice(const DIDEVICEINSTANCE * pdidInstance)
  1215 {
  1216     return SDL_Unsupported();
  1217 }
  1218 
  1219 int
  1220 SDL_DINPUT_HapticOpen(SDL_Haptic * haptic, SDL_hapticlist_item *item)
  1221 {
  1222     return SDL_Unsupported();
  1223 }
  1224 
  1225 int
  1226 SDL_DINPUT_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
  1227 {
  1228     return SDL_Unsupported();
  1229 }
  1230 
  1231 int
  1232 SDL_DINPUT_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
  1233 {
  1234     return SDL_Unsupported();
  1235 }
  1236 
  1237 void
  1238 SDL_DINPUT_HapticClose(SDL_Haptic * haptic)
  1239 {
  1240 }
  1241 
  1242 void
  1243 SDL_DINPUT_HapticQuit(void)
  1244 {
  1245 }
  1246 
  1247 int
  1248 SDL_DINPUT_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * base)
  1249 {
  1250     return SDL_Unsupported();
  1251 }
  1252 
  1253 int
  1254 SDL_DINPUT_HapticUpdateEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * data)
  1255 {
  1256     return SDL_Unsupported();
  1257 }
  1258 
  1259 int
  1260 SDL_DINPUT_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect, Uint32 iterations)
  1261 {
  1262     return SDL_Unsupported();
  1263 }
  1264 
  1265 int
  1266 SDL_DINPUT_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
  1267 {
  1268     return SDL_Unsupported();
  1269 }
  1270 
  1271 void
  1272 SDL_DINPUT_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
  1273 {
  1274 }
  1275 
  1276 int
  1277 SDL_DINPUT_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect *effect)
  1278 {
  1279     return SDL_Unsupported();
  1280 }
  1281 
  1282 int
  1283 SDL_DINPUT_HapticSetGain(SDL_Haptic * haptic, int gain)
  1284 {
  1285     return SDL_Unsupported();
  1286 }
  1287 
  1288 int
  1289 SDL_DINPUT_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
  1290 {
  1291     return SDL_Unsupported();
  1292 }
  1293 
  1294 int
  1295 SDL_DINPUT_HapticPause(SDL_Haptic * haptic)
  1296 {
  1297     return SDL_Unsupported();
  1298 }
  1299 
  1300 int
  1301 SDL_DINPUT_HapticUnpause(SDL_Haptic * haptic)
  1302 {
  1303     return SDL_Unsupported();
  1304 }
  1305 
  1306 int
  1307 SDL_DINPUT_HapticStopAll(SDL_Haptic * haptic)
  1308 {
  1309     return SDL_Unsupported();
  1310 }
  1311 
  1312 #endif /* SDL_HAPTIC_DINPUT */
  1313 
  1314 /* vi: set ts=4 sw=4 expandtab: */