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