src/haptic/windows/SDL_dinputhaptic.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 07 Jul 2014 10:26:28 -0700
changeset 8976 1a5d959d7b32
parent 8972 dfc759d7486f
child 9070 8973a237f360
permissions -rw-r--r--
Fixed mingw64 build and warnings
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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_timer.h"
    26 #include "SDL_windowshaptic_c.h"
    27 #include "SDL_dinputhaptic_c.h"
    28 #include "../SDL_syshaptic.h"
    29 #include "../../joystick/windows/SDL_windowsjoystick_c.h"
    30 
    31 
    32 #if SDL_HAPTIC_DINPUT
    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 #define CONVERT(x)   (((x) > 0x7FFF) ? 10000 : ((x)*10000) / 0x7FFF)
   606 /*
   607  * Creates the DIEFFECT from a SDL_HapticEffect.
   608  */
   609 static int
   610 SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic, DIEFFECT * dest,
   611                    SDL_HapticEffect * src)
   612 {
   613     int i;
   614     DICONSTANTFORCE *constant;
   615     DIPERIODIC *periodic;
   616     DICONDITION *condition;     /* Actually an array of conditions - one per axis. */
   617     DIRAMPFORCE *ramp;
   618     DICUSTOMFORCE *custom;
   619     DIENVELOPE *envelope;
   620     SDL_HapticConstant *hap_constant;
   621     SDL_HapticPeriodic *hap_periodic;
   622     SDL_HapticCondition *hap_condition;
   623     SDL_HapticRamp *hap_ramp;
   624     SDL_HapticCustom *hap_custom;
   625     DWORD *axes;
   626 
   627     /* Set global stuff. */
   628     SDL_memset(dest, 0, sizeof(DIEFFECT));
   629     dest->dwSize = sizeof(DIEFFECT);    /* Set the structure size. */
   630     dest->dwSamplePeriod = 0;   /* Not used by us. */
   631     dest->dwGain = 10000;       /* Gain is set globally, not locally. */
   632     dest->dwFlags = DIEFF_OBJECTOFFSETS;        /* Seems obligatory. */
   633 
   634     /* Envelope. */
   635     envelope = SDL_malloc(sizeof(DIENVELOPE));
   636     if (envelope == NULL) {
   637         return SDL_OutOfMemory();
   638     }
   639     SDL_memset(envelope, 0, sizeof(DIENVELOPE));
   640     dest->lpEnvelope = envelope;
   641     envelope->dwSize = sizeof(DIENVELOPE);      /* Always should be this. */
   642 
   643     /* Axes. */
   644     dest->cAxes = haptic->naxes;
   645     if (dest->cAxes > 0) {
   646         axes = SDL_malloc(sizeof(DWORD) * dest->cAxes);
   647         if (axes == NULL) {
   648             return SDL_OutOfMemory();
   649         }
   650         axes[0] = haptic->hwdata->axes[0];      /* Always at least one axis. */
   651         if (dest->cAxes > 1) {
   652             axes[1] = haptic->hwdata->axes[1];
   653         }
   654         if (dest->cAxes > 2) {
   655             axes[2] = haptic->hwdata->axes[2];
   656         }
   657         dest->rgdwAxes = axes;
   658     }
   659 
   660     /* The big type handling switch, even bigger than Linux's version. */
   661     switch (src->type) {
   662     case SDL_HAPTIC_CONSTANT:
   663         hap_constant = &src->constant;
   664         constant = SDL_malloc(sizeof(DICONSTANTFORCE));
   665         if (constant == NULL) {
   666             return SDL_OutOfMemory();
   667         }
   668         SDL_memset(constant, 0, sizeof(DICONSTANTFORCE));
   669 
   670         /* Specifics */
   671         constant->lMagnitude = CONVERT(hap_constant->level);
   672         dest->cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
   673         dest->lpvTypeSpecificParams = constant;
   674 
   675         /* Generics */
   676         dest->dwDuration = hap_constant->length * 1000; /* In microseconds. */
   677         dest->dwTriggerButton = DIGetTriggerButton(hap_constant->button);
   678         dest->dwTriggerRepeatInterval = hap_constant->interval;
   679         dest->dwStartDelay = hap_constant->delay * 1000;        /* In microseconds. */
   680 
   681         /* Direction. */
   682         if (SDL_SYS_SetDirection(dest, &hap_constant->direction, dest->cAxes) < 0) {
   683             return -1;
   684         }
   685 
   686         /* Envelope */
   687         if ((hap_constant->attack_length == 0)
   688             && (hap_constant->fade_length == 0)) {
   689             SDL_free(dest->lpEnvelope);
   690             dest->lpEnvelope = NULL;
   691         } else {
   692             envelope->dwAttackLevel = CONVERT(hap_constant->attack_level);
   693             envelope->dwAttackTime = hap_constant->attack_length * 1000;
   694             envelope->dwFadeLevel = CONVERT(hap_constant->fade_level);
   695             envelope->dwFadeTime = hap_constant->fade_length * 1000;
   696         }
   697 
   698         break;
   699 
   700     case SDL_HAPTIC_SINE:
   701     /* !!! FIXME: put this back when we have more bits in 2.1 */
   702     /* case SDL_HAPTIC_SQUARE: */
   703     case SDL_HAPTIC_TRIANGLE:
   704     case SDL_HAPTIC_SAWTOOTHUP:
   705     case SDL_HAPTIC_SAWTOOTHDOWN:
   706         hap_periodic = &src->periodic;
   707         periodic = SDL_malloc(sizeof(DIPERIODIC));
   708         if (periodic == NULL) {
   709             return SDL_OutOfMemory();
   710         }
   711         SDL_memset(periodic, 0, sizeof(DIPERIODIC));
   712 
   713         /* Specifics */
   714         periodic->dwMagnitude = CONVERT(hap_periodic->magnitude);
   715         periodic->lOffset = CONVERT(hap_periodic->offset);
   716         periodic->dwPhase = hap_periodic->phase;
   717         periodic->dwPeriod = hap_periodic->period * 1000;
   718         dest->cbTypeSpecificParams = sizeof(DIPERIODIC);
   719         dest->lpvTypeSpecificParams = periodic;
   720 
   721         /* Generics */
   722         dest->dwDuration = hap_periodic->length * 1000; /* In microseconds. */
   723         dest->dwTriggerButton = DIGetTriggerButton(hap_periodic->button);
   724         dest->dwTriggerRepeatInterval = hap_periodic->interval;
   725         dest->dwStartDelay = hap_periodic->delay * 1000;        /* In microseconds. */
   726 
   727         /* Direction. */
   728         if (SDL_SYS_SetDirection(dest, &hap_periodic->direction, dest->cAxes)
   729             < 0) {
   730             return -1;
   731         }
   732 
   733         /* Envelope */
   734         if ((hap_periodic->attack_length == 0)
   735             && (hap_periodic->fade_length == 0)) {
   736             SDL_free(dest->lpEnvelope);
   737             dest->lpEnvelope = NULL;
   738         } else {
   739             envelope->dwAttackLevel = CONVERT(hap_periodic->attack_level);
   740             envelope->dwAttackTime = hap_periodic->attack_length * 1000;
   741             envelope->dwFadeLevel = CONVERT(hap_periodic->fade_level);
   742             envelope->dwFadeTime = hap_periodic->fade_length * 1000;
   743         }
   744 
   745         break;
   746 
   747     case SDL_HAPTIC_SPRING:
   748     case SDL_HAPTIC_DAMPER:
   749     case SDL_HAPTIC_INERTIA:
   750     case SDL_HAPTIC_FRICTION:
   751         hap_condition = &src->condition;
   752         condition = SDL_malloc(sizeof(DICONDITION) * dest->cAxes);
   753         if (condition == NULL) {
   754             return SDL_OutOfMemory();
   755         }
   756         SDL_memset(condition, 0, sizeof(DICONDITION));
   757 
   758         /* Specifics */
   759         for (i = 0; i < (int) dest->cAxes; i++) {
   760             condition[i].lOffset = CONVERT(hap_condition->center[i]);
   761             condition[i].lPositiveCoefficient =
   762                 CONVERT(hap_condition->right_coeff[i]);
   763             condition[i].lNegativeCoefficient =
   764                 CONVERT(hap_condition->left_coeff[i]);
   765             condition[i].dwPositiveSaturation =
   766                 CONVERT(hap_condition->right_sat[i]);
   767             condition[i].dwNegativeSaturation =
   768                 CONVERT(hap_condition->left_sat[i]);
   769             condition[i].lDeadBand = CONVERT(hap_condition->deadband[i]);
   770         }
   771         dest->cbTypeSpecificParams = sizeof(DICONDITION) * dest->cAxes;
   772         dest->lpvTypeSpecificParams = condition;
   773 
   774         /* Generics */
   775         dest->dwDuration = hap_condition->length * 1000;        /* In microseconds. */
   776         dest->dwTriggerButton = DIGetTriggerButton(hap_condition->button);
   777         dest->dwTriggerRepeatInterval = hap_condition->interval;
   778         dest->dwStartDelay = hap_condition->delay * 1000;       /* In microseconds. */
   779 
   780         /* Direction. */
   781         if (SDL_SYS_SetDirection(dest, &hap_condition->direction, dest->cAxes)
   782             < 0) {
   783             return -1;
   784         }
   785 
   786         /* Envelope - Not actually supported by most CONDITION implementations. */
   787         SDL_free(dest->lpEnvelope);
   788         dest->lpEnvelope = NULL;
   789 
   790         break;
   791 
   792     case SDL_HAPTIC_RAMP:
   793         hap_ramp = &src->ramp;
   794         ramp = SDL_malloc(sizeof(DIRAMPFORCE));
   795         if (ramp == NULL) {
   796             return SDL_OutOfMemory();
   797         }
   798         SDL_memset(ramp, 0, sizeof(DIRAMPFORCE));
   799 
   800         /* Specifics */
   801         ramp->lStart = CONVERT(hap_ramp->start);
   802         ramp->lEnd = CONVERT(hap_ramp->end);
   803         dest->cbTypeSpecificParams = sizeof(DIRAMPFORCE);
   804         dest->lpvTypeSpecificParams = ramp;
   805 
   806         /* Generics */
   807         dest->dwDuration = hap_ramp->length * 1000;     /* In microseconds. */
   808         dest->dwTriggerButton = DIGetTriggerButton(hap_ramp->button);
   809         dest->dwTriggerRepeatInterval = hap_ramp->interval;
   810         dest->dwStartDelay = hap_ramp->delay * 1000;    /* In microseconds. */
   811 
   812         /* Direction. */
   813         if (SDL_SYS_SetDirection(dest, &hap_ramp->direction, dest->cAxes) < 0) {
   814             return -1;
   815         }
   816 
   817         /* Envelope */
   818         if ((hap_ramp->attack_length == 0) && (hap_ramp->fade_length == 0)) {
   819             SDL_free(dest->lpEnvelope);
   820             dest->lpEnvelope = NULL;
   821         } else {
   822             envelope->dwAttackLevel = CONVERT(hap_ramp->attack_level);
   823             envelope->dwAttackTime = hap_ramp->attack_length * 1000;
   824             envelope->dwFadeLevel = CONVERT(hap_ramp->fade_level);
   825             envelope->dwFadeTime = hap_ramp->fade_length * 1000;
   826         }
   827 
   828         break;
   829 
   830     case SDL_HAPTIC_CUSTOM:
   831         hap_custom = &src->custom;
   832         custom = SDL_malloc(sizeof(DICUSTOMFORCE));
   833         if (custom == NULL) {
   834             return SDL_OutOfMemory();
   835         }
   836         SDL_memset(custom, 0, sizeof(DICUSTOMFORCE));
   837 
   838         /* Specifics */
   839         custom->cChannels = hap_custom->channels;
   840         custom->dwSamplePeriod = hap_custom->period * 1000;
   841         custom->cSamples = hap_custom->samples;
   842         custom->rglForceData =
   843             SDL_malloc(sizeof(LONG) * custom->cSamples * custom->cChannels);
   844         for (i = 0; i < hap_custom->samples * hap_custom->channels; i++) {      /* Copy data. */
   845             custom->rglForceData[i] = CONVERT(hap_custom->data[i]);
   846         }
   847         dest->cbTypeSpecificParams = sizeof(DICUSTOMFORCE);
   848         dest->lpvTypeSpecificParams = custom;
   849 
   850         /* Generics */
   851         dest->dwDuration = hap_custom->length * 1000;   /* In microseconds. */
   852         dest->dwTriggerButton = DIGetTriggerButton(hap_custom->button);
   853         dest->dwTriggerRepeatInterval = hap_custom->interval;
   854         dest->dwStartDelay = hap_custom->delay * 1000;  /* In microseconds. */
   855 
   856         /* Direction. */
   857         if (SDL_SYS_SetDirection(dest, &hap_custom->direction, dest->cAxes) < 0) {
   858             return -1;
   859         }
   860 
   861         /* Envelope */
   862         if ((hap_custom->attack_length == 0)
   863             && (hap_custom->fade_length == 0)) {
   864             SDL_free(dest->lpEnvelope);
   865             dest->lpEnvelope = NULL;
   866         } else {
   867             envelope->dwAttackLevel = CONVERT(hap_custom->attack_level);
   868             envelope->dwAttackTime = hap_custom->attack_length * 1000;
   869             envelope->dwFadeLevel = CONVERT(hap_custom->fade_level);
   870             envelope->dwFadeTime = hap_custom->fade_length * 1000;
   871         }
   872 
   873         break;
   874 
   875     default:
   876         return SDL_SetError("Haptic: Unknown effect type.");
   877     }
   878 
   879     return 0;
   880 }
   881 
   882 
   883 /*
   884  * Frees an DIEFFECT allocated by SDL_SYS_ToDIEFFECT.
   885  */
   886 static void
   887 SDL_SYS_HapticFreeDIEFFECT(DIEFFECT * effect, int type)
   888 {
   889     DICUSTOMFORCE *custom;
   890 
   891     SDL_free(effect->lpEnvelope);
   892     effect->lpEnvelope = NULL;
   893     SDL_free(effect->rgdwAxes);
   894     effect->rgdwAxes = NULL;
   895     if (effect->lpvTypeSpecificParams != NULL) {
   896         if (type == SDL_HAPTIC_CUSTOM) {        /* Must free the custom data. */
   897             custom = (DICUSTOMFORCE *) effect->lpvTypeSpecificParams;
   898             SDL_free(custom->rglForceData);
   899             custom->rglForceData = NULL;
   900         }
   901         SDL_free(effect->lpvTypeSpecificParams);
   902         effect->lpvTypeSpecificParams = NULL;
   903     }
   904     SDL_free(effect->rglDirection);
   905     effect->rglDirection = NULL;
   906 }
   907 
   908 /*
   909  * Gets the effect type from the generic SDL haptic effect wrapper.
   910  */
   911 static REFGUID
   912 SDL_SYS_HapticEffectType(SDL_HapticEffect * effect)
   913 {
   914     switch (effect->type) {
   915     case SDL_HAPTIC_CONSTANT:
   916         return &GUID_ConstantForce;
   917 
   918     case SDL_HAPTIC_RAMP:
   919         return &GUID_RampForce;
   920 
   921     /* !!! FIXME: put this back when we have more bits in 2.1 */
   922     /* case SDL_HAPTIC_SQUARE:
   923         return &GUID_Square; */
   924 
   925     case SDL_HAPTIC_SINE:
   926         return &GUID_Sine;
   927 
   928     case SDL_HAPTIC_TRIANGLE:
   929         return &GUID_Triangle;
   930 
   931     case SDL_HAPTIC_SAWTOOTHUP:
   932         return &GUID_SawtoothUp;
   933 
   934     case SDL_HAPTIC_SAWTOOTHDOWN:
   935         return &GUID_SawtoothDown;
   936 
   937     case SDL_HAPTIC_SPRING:
   938         return &GUID_Spring;
   939 
   940     case SDL_HAPTIC_DAMPER:
   941         return &GUID_Damper;
   942 
   943     case SDL_HAPTIC_INERTIA:
   944         return &GUID_Inertia;
   945 
   946     case SDL_HAPTIC_FRICTION:
   947         return &GUID_Friction;
   948 
   949     case SDL_HAPTIC_CUSTOM:
   950         return &GUID_CustomForce;
   951 
   952     default:
   953         return NULL;
   954     }
   955 }
   956 int
   957 SDL_DINPUT_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * base)
   958 {
   959     HRESULT ret;
   960     REFGUID type = SDL_SYS_HapticEffectType(base);
   961 
   962     if (type == NULL) {
   963         SDL_SetError("Haptic: Unknown effect type.");
   964         return -1;
   965     }
   966 
   967     /* Get the effect. */
   968     if (SDL_SYS_ToDIEFFECT(haptic, &effect->hweffect->effect, base) < 0) {
   969         goto err_effectdone;
   970     }
   971 
   972     /* Create the actual effect. */
   973     ret = IDirectInputDevice8_CreateEffect(haptic->hwdata->device, type,
   974         &effect->hweffect->effect,
   975         &effect->hweffect->ref, NULL);
   976     if (FAILED(ret)) {
   977         DI_SetError("Unable to create effect", ret);
   978         goto err_effectdone;
   979     }
   980 
   981     return 0;
   982 
   983 err_effectdone:
   984     SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, base->type);
   985     return -1;
   986 }
   987 
   988 int
   989 SDL_DINPUT_HapticUpdateEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * data)
   990 {
   991     HRESULT ret;
   992     DWORD flags;
   993     DIEFFECT temp;
   994 
   995     /* Get the effect. */
   996     SDL_memset(&temp, 0, sizeof(DIEFFECT));
   997     if (SDL_SYS_ToDIEFFECT(haptic, &temp, data) < 0) {
   998         goto err_update;
   999     }
  1000 
  1001     /* Set the flags.  Might be worthwhile to diff temp with loaded effect and
  1002     *  only change those parameters. */
  1003     flags = DIEP_DIRECTION |
  1004         DIEP_DURATION |
  1005         DIEP_ENVELOPE |
  1006         DIEP_STARTDELAY |
  1007         DIEP_TRIGGERBUTTON |
  1008         DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS;
  1009 
  1010     /* Create the actual effect. */
  1011     ret =
  1012         IDirectInputEffect_SetParameters(effect->hweffect->ref, &temp, flags);
  1013     if (FAILED(ret)) {
  1014         DI_SetError("Unable to update effect", ret);
  1015         goto err_update;
  1016     }
  1017 
  1018     /* Copy it over. */
  1019     SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, data->type);
  1020     SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(DIEFFECT));
  1021 
  1022     return 0;
  1023 
  1024 err_update:
  1025     SDL_SYS_HapticFreeDIEFFECT(&temp, data->type);
  1026     return -1;
  1027 }
  1028 
  1029 int
  1030 SDL_DINPUT_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect, Uint32 iterations)
  1031 {
  1032     HRESULT ret;
  1033     DWORD iter;
  1034 
  1035     /* Check if it's infinite. */
  1036     if (iterations == SDL_HAPTIC_INFINITY) {
  1037         iter = INFINITE;
  1038     } else {
  1039         iter = iterations;
  1040     }
  1041 
  1042     /* Run the effect. */
  1043     ret = IDirectInputEffect_Start(effect->hweffect->ref, iter, 0);
  1044     if (FAILED(ret)) {
  1045         return DI_SetError("Running the effect", ret);
  1046     }
  1047     return 0;
  1048 }
  1049 
  1050 int
  1051 SDL_DINPUT_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
  1052 {
  1053     HRESULT ret;
  1054 
  1055     ret = IDirectInputEffect_Stop(effect->hweffect->ref);
  1056     if (FAILED(ret)) {
  1057         return DI_SetError("Unable to stop effect", ret);
  1058     }
  1059     return 0;
  1060 }
  1061 
  1062 void
  1063 SDL_DINPUT_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
  1064 {
  1065     HRESULT ret;
  1066 
  1067     ret = IDirectInputEffect_Unload(effect->hweffect->ref);
  1068     if (FAILED(ret)) {
  1069         DI_SetError("Removing effect from the device", ret);
  1070     }
  1071     SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, effect->effect.type);
  1072 }
  1073 
  1074 int
  1075 SDL_DINPUT_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect *effect)
  1076 {
  1077     HRESULT ret;
  1078     DWORD status;
  1079 
  1080     ret = IDirectInputEffect_GetEffectStatus(effect->hweffect->ref, &status);
  1081     if (FAILED(ret)) {
  1082         return DI_SetError("Getting effect status", ret);
  1083     }
  1084 
  1085     if (status == 0)
  1086         return SDL_FALSE;
  1087     return SDL_TRUE;
  1088 }
  1089 
  1090 int
  1091 SDL_DINPUT_HapticSetGain(SDL_Haptic * haptic, int gain)
  1092 {
  1093     HRESULT ret;
  1094     DIPROPDWORD dipdw;
  1095 
  1096     /* Create the weird structure thingy. */
  1097     dipdw.diph.dwSize = sizeof(DIPROPDWORD);
  1098     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  1099     dipdw.diph.dwObj = 0;
  1100     dipdw.diph.dwHow = DIPH_DEVICE;
  1101     dipdw.dwData = gain * 100;  /* 0 to 10,000 */
  1102 
  1103     /* Try to set the autocenter. */
  1104     ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device,
  1105         DIPROP_FFGAIN, &dipdw.diph);
  1106     if (FAILED(ret)) {
  1107         return DI_SetError("Setting gain", ret);
  1108     }
  1109     return 0;
  1110 }
  1111 
  1112 int
  1113 SDL_DINPUT_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
  1114 {
  1115     HRESULT ret;
  1116     DIPROPDWORD dipdw;
  1117 
  1118     /* Create the weird structure thingy. */
  1119     dipdw.diph.dwSize = sizeof(DIPROPDWORD);
  1120     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  1121     dipdw.diph.dwObj = 0;
  1122     dipdw.diph.dwHow = DIPH_DEVICE;
  1123     dipdw.dwData = (autocenter == 0) ? DIPROPAUTOCENTER_OFF :
  1124         DIPROPAUTOCENTER_ON;
  1125 
  1126     /* Try to set the autocenter. */
  1127     ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device,
  1128         DIPROP_AUTOCENTER, &dipdw.diph);
  1129     if (FAILED(ret)) {
  1130         return DI_SetError("Setting autocenter", ret);
  1131     }
  1132     return 0;
  1133 }
  1134 
  1135 int
  1136 SDL_DINPUT_HapticPause(SDL_Haptic * haptic)
  1137 {
  1138     HRESULT ret;
  1139 
  1140     /* Pause the device. */
  1141     ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
  1142         DISFFC_PAUSE);
  1143     if (FAILED(ret)) {
  1144         return DI_SetError("Pausing the device", ret);
  1145     }
  1146     return 0;
  1147 }
  1148 
  1149 int
  1150 SDL_DINPUT_HapticUnpause(SDL_Haptic * haptic)
  1151 {
  1152     HRESULT ret;
  1153 
  1154     /* Unpause the device. */
  1155     ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
  1156         DISFFC_CONTINUE);
  1157     if (FAILED(ret)) {
  1158         return DI_SetError("Pausing the device", ret);
  1159     }
  1160     return 0;
  1161 }
  1162 
  1163 int
  1164 SDL_DINPUT_HapticStopAll(SDL_Haptic * haptic)
  1165 {
  1166     HRESULT ret;
  1167 
  1168     /* Try to stop the effects. */
  1169     ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
  1170         DISFFC_STOPALL);
  1171     if (FAILED(ret)) {
  1172         return DI_SetError("Stopping the device", ret);
  1173     }
  1174     return 0;
  1175 }
  1176 
  1177 #else /* !SDL_HAPTIC_DINPUT */
  1178 
  1179 
  1180 int
  1181 SDL_DINPUT_HapticInit(void)
  1182 {
  1183     return 0;
  1184 }
  1185 
  1186 int
  1187 SDL_DINPUT_MaybeAddDevice(const DIDEVICEINSTANCE * pdidInstance)
  1188 {
  1189     return SDL_Unsupported();
  1190 }
  1191 
  1192 int
  1193 SDL_DINPUT_MaybeRemoveDevice(const DIDEVICEINSTANCE * pdidInstance)
  1194 {
  1195     return SDL_Unsupported();
  1196 }
  1197 
  1198 int
  1199 SDL_DINPUT_HapticOpen(SDL_Haptic * haptic, SDL_hapticlist_item *item)
  1200 {
  1201     return SDL_Unsupported();
  1202 }
  1203 
  1204 int
  1205 SDL_DINPUT_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
  1206 {
  1207     return SDL_Unsupported();
  1208 }
  1209 
  1210 int
  1211 SDL_DINPUT_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
  1212 {
  1213     return SDL_Unsupported();
  1214 }
  1215 
  1216 void
  1217 SDL_DINPUT_HapticClose(SDL_Haptic * haptic)
  1218 {
  1219 }
  1220 
  1221 void
  1222 SDL_DINPUT_HapticQuit(void)
  1223 {
  1224 }
  1225 
  1226 int
  1227 SDL_DINPUT_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * base)
  1228 {
  1229     return SDL_Unsupported();
  1230 }
  1231 
  1232 int
  1233 SDL_DINPUT_HapticUpdateEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * data)
  1234 {
  1235     return SDL_Unsupported();
  1236 }
  1237 
  1238 int
  1239 SDL_DINPUT_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect, Uint32 iterations)
  1240 {
  1241     return SDL_Unsupported();
  1242 }
  1243 
  1244 int
  1245 SDL_DINPUT_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
  1246 {
  1247     return SDL_Unsupported();
  1248 }
  1249 
  1250 void
  1251 SDL_DINPUT_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
  1252 {
  1253 }
  1254 
  1255 int
  1256 SDL_DINPUT_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect *effect)
  1257 {
  1258     return SDL_Unsupported();
  1259 }
  1260 
  1261 int
  1262 SDL_DINPUT_HapticSetGain(SDL_Haptic * haptic, int gain)
  1263 {
  1264     return SDL_Unsupported();
  1265 }
  1266 
  1267 int
  1268 SDL_DINPUT_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
  1269 {
  1270     return SDL_Unsupported();
  1271 }
  1272 
  1273 int
  1274 SDL_DINPUT_HapticPause(SDL_Haptic * haptic)
  1275 {
  1276     return SDL_Unsupported();
  1277 }
  1278 
  1279 int
  1280 SDL_DINPUT_HapticUnpause(SDL_Haptic * haptic)
  1281 {
  1282     return SDL_Unsupported();
  1283 }
  1284 
  1285 int
  1286 SDL_DINPUT_HapticStopAll(SDL_Haptic * haptic)
  1287 {
  1288     return SDL_Unsupported();
  1289 }
  1290 
  1291 #endif /* SDL_HAPTIC_DINPUT */
  1292 
  1293 /* vi: set ts=4 sw=4 expandtab: */