src/haptic/windows/SDL_dinputhaptic.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 28 May 2015 00:54:52 -0400
changeset 9658 9753468b5c0e
parent 9619 b94b6d0bff0f
child 9661 62a04df5afe1
permissions -rw-r--r--
Move tests from SDL_config higher up in Windows joystick/haptic code.

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