First version of the windows haptic port, won't compile yet. gsoc2008_force_feedback
authorEdgar Simo <bobbens@gmail.com>
Wed, 30 Jul 2008 11:54:08 +0000
branchgsoc2008_force_feedback
changeset 2551f010e1d4e431
parent 2550 b5b8a7f4a965
child 2552 ee048e7bc909
First version of the windows haptic port, won't compile yet.
src/haptic/win32/SDL_syshaptic.c
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/haptic/win32/SDL_syshaptic.c	Wed Jul 30 11:54:08 2008 +0000
     1.3 @@ -0,0 +1,1086 @@
     1.4 +/*
     1.5 +    SDL - Simple DirectMedia Layer
     1.6 +    Copyright (C) 2008 Edgar Simo
     1.7 +
     1.8 +    This library is free software; you can redistribute it and/or
     1.9 +    modify it under the terms of the GNU Lesser General Public
    1.10 +    License as published by the Free Software Foundation; either
    1.11 +    version 2.1 of the License, or (at your option) any later version.
    1.12 +
    1.13 +    This library is distributed in the hope that it will be useful,
    1.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    1.16 +    Lesser General Public License for more details.
    1.17 +
    1.18 +    You should have received a copy of the GNU Lesser General Public
    1.19 +    License along with this library; if not, write to the Free Software
    1.20 +    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    1.21 +
    1.22 +    Sam Lantinga
    1.23 +    slouken@libsdl.org
    1.24 +*/
    1.25 +#include "SDL_config.h"
    1.26 +
    1.27 +#ifdef SDL_HAPTIC_DINPUT
    1.28 +
    1.29 +#include "SDL_haptic.h"
    1.30 +#include "../SDL_syshaptic.h"
    1.31 +#include "SDL_joystick.h"
    1.32 +#include "../../joystick/SDL_sysjoystick.h" /* For the real SDL_Joystick */
    1.33 +/*#include "../../joystick/win32/SDL_sysjoystick_c.h"*/ /* For joystick hwdata */ 
    1.34 +
    1.35 +#define WIN32_LEAN_AND_MEAN
    1.36 +#include <windows.h>
    1.37 +
    1.38 +#define DIRECTINPUT_VERSION 0x0500
    1.39 +#include <dinput.h>
    1.40 +#include <dxerr9.h>          /* From DirectX SDK 9c */
    1.41 +#ifdef _MSC_VER
    1.42 +#   pragma comment (lib, "dxerr9.lib")
    1.43 +#endif /* _MSC_VER */
    1.44 +
    1.45 +    /* an ISO hack for VisualC++ */
    1.46 +#ifdef _MSC_VER
    1.47 +#define   snprintf   _snprintf
    1.48 +#endif /* _MSC_VER */
    1.49 +
    1.50 +
    1.51 +#define MAX_HAPTICS  32
    1.52 +
    1.53 +
    1.54 +/*
    1.55 + * List of available haptic devices.
    1.56 + */
    1.57 +static struct
    1.58 +{
    1.59 +   DIDEVICEINSTANCE instance;
    1.60 +   SDL_Haptic *haptic;
    1.61 +} SDL_hapticlist[MAX_HAPTICS];
    1.62 +
    1.63 +
    1.64 +/*
    1.65 + * Haptic system hardware data.
    1.66 + */
    1.67 +struct haptic_hwdata
    1.68 +{
    1.69 +   LPDIRECTINPUTDEVICE2 device;
    1.70 +   DIDEVCAPS capabilities;
    1.71 +};
    1.72 +
    1.73 +
    1.74 +/*
    1.75 + * Haptic system effect data.
    1.76 + */
    1.77 +struct haptic_hweffect
    1.78 +{
    1.79 +   DIEFFECT effect;
    1.80 +};
    1.81 +
    1.82 +
    1.83 +/*
    1.84 + * Internal stuff.
    1.85 + */
    1.86 +static LPDIRECTINPUT dinput = NULL;
    1.87 +
    1.88 +
    1.89 +/*
    1.90 + * Prototypes.
    1.91 + */
    1.92 +static BOOL CALLBACK EnumHapticsCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext);
    1.93 +
    1.94 +
    1.95 +/* 
    1.96 + * Like SDL_SetError but for DX error codes.
    1.97 + */
    1.98 +static void
    1.99 +DI_SetError(const char *str, HRESULT err)
   1.100 +{
   1.101 +   SDL_SetError( "Haptic: %s - %s: %s", str,
   1.102 +                 DXGetErrorString9(err),
   1.103 +                 DXGetErrorDescription9(err));
   1.104 +}
   1.105 +
   1.106 +
   1.107 +/*
   1.108 + * Initializes the haptic subsystem.
   1.109 + */
   1.110 +int
   1.111 +SDL_SYS_HapticInit(void)
   1.112 +{
   1.113 +   HRESULT ret;
   1.114 +
   1.115 +   if (dinput != NULL) { /* Already open. */
   1.116 +      SDL_SetError("Haptic: SubSystem already open.");
   1.117 +      return -1;
   1.118 +   }
   1.119 +
   1.120 +   /* Clear all the memory. */
   1.121 +   SDL_memset(SDL_hapticlist, 0, sizeof(SDL_hapticlist));
   1.122 +
   1.123 +   SDL_numhaptics = 0;
   1.124 +
   1.125 +   ret = CoInitialize(NULL);
   1.126 +   if (FAILED(ret)) {
   1.127 +      DI_SetError("Coinitialize",ret);
   1.128 +      return -1;
   1.129 +   }
   1.130 +
   1.131 +   ret = CoCreateInstance(&CLSID_DirectInput, NULL, CLSCTX_INPROC_SERVER,
   1.132 +                          &IID_IDirectInput, &dinput);
   1.133 +   if (FAILED(ret)) {
   1.134 +      DI_SetError("CoCreateInstance",ret);
   1.135 +      return -1;
   1.136 +   }
   1.137 +
   1.138 +   /* Because we used CoCreateInstance, we need to Initialize it, first. */
   1.139 +   ret = IDirectInput_Initialize(dinput, SDL_Instance, DIRECTINPUT_VERSION);
   1.140 +   if (FAILED(ret)) {
   1.141 +      DI_SetError("Initializing DirectInput device",ret);
   1.142 +      return -1;
   1.143 +   }
   1.144 +
   1.145 +   /* Look for haptic devices. */
   1.146 +   ret = IDirectInput_EnumDevices( dinput,
   1.147 +                                   DIDEVTYPE_ALL,
   1.148 +                                   EnumJoysticksCallback,
   1.149 +                                   NULL, DIEDFL_FORCEFEEDBACK | DIEDFL_ATTACHEDONLY);
   1.150 +   if (FAILED(ret)) {
   1.151 +      DI_SetError("Enumerating DirectInput devices",ret);
   1.152 +      return -1;
   1.153 +   }
   1.154 +
   1.155 +   return SDL_numhaptics;
   1.156 +}
   1.157 +
   1.158 +/*
   1.159 + * Callback to find the haptic devices.
   1.160 + */
   1.161 +static BOOL CALLBACK
   1.162 +EnumHapticsCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
   1.163 +{
   1.164 +   memcpy(&SDL_hapticlist[SDL_numhaptics].instance, pdidInstance,
   1.165 +         sizeof(DIDEVICEINSTANCE));
   1.166 +   SDL_numhaptics++;
   1.167 +
   1.168 +   if (SDL_numhaptics >= MAX_HAPTICS)
   1.169 +      return DIENUM_STOP;
   1.170 +
   1.171 +   return DIENUM_CONTINUE;
   1.172 +}
   1.173 +
   1.174 +
   1.175 +/*
   1.176 + * Return the name of a haptic device, does not need to be opened.
   1.177 + */
   1.178 +const char *
   1.179 +SDL_SYS_HapticName(int index)
   1.180 +{
   1.181 +   return SDL_hapticlist[index].instance.tszProductName;
   1.182 +}
   1.183 +
   1.184 +
   1.185 +/*
   1.186 + * Callback to get all supported effects.
   1.187 + */
   1.188 +#define EFFECT_TEST(e,s)   \
   1.189 +if (pei->guid == (e))   \
   1.190 +   haptic->supported |= (s)
   1.191 +static BOOL CALLBACK
   1.192 +DI_EffectCallback(LPCDIEffectInfo pei, LPVOID pv)
   1.193 +{
   1.194 +   /* Prepare the haptic device. */
   1.195 +   SDL_Haptic *haptic = (SDL_Haptic*) pv;
   1.196 +   haptic->supported = 0;
   1.197 +
   1.198 +   /* Get supported. */
   1.199 +   EFFECT_TEST(GUID_Spring,         SDL_HAPTIC_SPRING);
   1.200 +   EFFECT_TEST(GUID_Damper,         SDL_HAPTIC_DAMPER);
   1.201 +   EFFECT_TEST(GUID_Inertia,        SDL_HAPTIC_INERTIA);
   1.202 +   EFFECT_TEST(GUID_Friction,       SDL_HAPTIC_FRICTION);
   1.203 +   EFFECT_TEST(GUID_ConstantForce,  SDL_HAPTIC_CONSTANT);
   1.204 +   EFFECT_TEST(GUID_CustomForce,    SDL_HAPTIC_CUSTOM);
   1.205 +   EFFECT_TEST(GUID_Sine,           SDL_HAPTIC_SINE);
   1.206 +   EFFECT_TEST(GUID_Square,         SDL_HAPTIC_SQUARE);
   1.207 +   EFFECT_TEST(GUID_Triangle,       SDL_HAPTIC_TRIANGLE);
   1.208 +   EFFECT_TEST(GUID_SawtoothUp,     SDL_HAPTIC_SAWTOOTHUP);
   1.209 +   EFFECT_TEST(GUID_SawtoothDown,   SDL_HAPTIC_SAWTOOTHDOWN);
   1.210 +   EFFECT_TEST(GUID_RampForce,      SDL_HAPTIC_RAMP);
   1.211 +  
   1.212 +   /* Check for more. */
   1.213 +   return DIENUM_CONTINUE;
   1.214 +}
   1.215 +
   1.216 +
   1.217 +/*
   1.218 + * Opens the haptic device from the file descriptor.
   1.219 + *
   1.220 + *    Steps:
   1.221 + *       - Open temporary DirectInputDevice interface.
   1.222 + *       - Create DirectInputDevice2 interface.
   1.223 + *       - Release DirectInputDevice interface.
   1.224 + *       - Acquire exclusiveness.
   1.225 + *       - Reset actuators.
   1.226 + *       - Get supported featuers.
   1.227 + */
   1.228 +static int
   1.229 +SDL_SYS_HapticOpenFromInstance(SDL_Haptic * haptic, DIDEVICEINSTANCE instance)
   1.230 +{
   1.231 +   HRESULT ret;
   1.232 +   LPDIRECTINPUTDEVICE device;
   1.233 +   DIPROPDWORD dipdw;
   1.234 +
   1.235 +   /* Allocate the hwdata */
   1.236 +   haptic->hwdata = (struct haptic_hwdata *)
   1.237 +         SDL_malloc(sizeof(*haptic->hwdata));
   1.238 +   if (haptic->hwdata == NULL) {
   1.239 +      SDL_OutOfMemory();
   1.240 +      goto creat_err;
   1.241 +   }
   1.242 +   SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
   1.243 +  
   1.244 +   /* Open the device */
   1.245 +   ret = IDirectInput_CreateDevice( dinput, &instance,
   1.246 +                                    guidInstance, &device, NULL);
   1.247 +   if (FAILED(ret)) {
   1.248 +      DI_SetError("Creating DirectInput device",ret);
   1.249 +      goto creat_err;
   1.250 +   }
   1.251 +
   1.252 +   /* Now get the IDirectInputDevice2 interface, instead. */
   1.253 +   ret = IDirectInputDevice_QueryInterface( device,
   1.254 +                                            &IID_IDirectInputDevice2,
   1.255 +                                            haptic->hwdata->device );
   1.256 +   /* Done with the temporary one now. */
   1.257 +   IDirectInputDevice_Release(device);
   1.258 +   if (FAILED(ret)) {
   1.259 +      DI_SetError("Querying DirectInput interface",ret);
   1.260 +      goto creat_err;
   1.261 +   }
   1.262 +
   1.263 +   /* Acquire the device. */
   1.264 +   ret = IDirectInputDevice2_Acquire(haptic->hwdata->device);
   1.265 +   if (FAILED(ret)) {
   1.266 +      DI_SetError("Acquiring DirectInput device",ret);
   1.267 +      goto query_err;
   1.268 +   }
   1.269 +
   1.270 +   /* Grab it exclusively to use force feedback stuff. */
   1.271 +   ret =IDirectInputDevice2_SetCooperativeLevel( haptic->hwdata->device,
   1.272 +                                                 SDL_Window,
   1.273 +                                                 DISCL_EXCLUSIVE | DISCL_BACKGROUND );
   1.274 +   if (FAILED(ret)) {
   1.275 +      DI_SetError("Setting cooperative level to exclusive",ret);
   1.276 +      goto acquire_err;
   1.277 +   }
   1.278 +
   1.279 +   /* Reset all actuators - just in case. */
   1.280 +   ret = IDirectInputDevice2_SendForceFeedbackCommand( haptic->hwdata->device,
   1.281 +                                                       DISFFC_RESET );
   1.282 +   if (FAILED(ret)) {
   1.283 +      DI_SetError("Resetting device",ret);
   1.284 +      goto acquire_err;
   1.285 +   }
   1.286 +
   1.287 +
   1.288 +   /* Enabling actuators. */
   1.289 +   ret = IDirectInputDevice2_SendForceFeedbackCommand( haptic->hwdata->device,
   1.290 +                                                       DISFFC_SETACTUATORSON );
   1.291 +   if (FAILED(ret)) {
   1.292 +      DI_SetError("Enabling actuators",ret);
   1.293 +      goto acquire_err;
   1.294 +   }
   1.295 +
   1.296 +
   1.297 +   /* Get capabilities. */
   1.298 +   ret = IDirectInputDevice2_GetCapabilities( haptic->hwdata->device,
   1.299 +                                              haptic->hwdata->capabilities );
   1.300 +   if (FAILED(ret)) {
   1.301 +      DI_SetError("Getting device capabilities",ret);
   1.302 +      goto acquire_err;
   1.303 +   }
   1.304 +
   1.305 +
   1.306 +   /* Get supported effects. */
   1.307 +   ret = IDirectInput_EnumEffects( DI_EffectCallback, haptic, DIEFT_ALL);
   1.308 +   if (FAILED(ret)) {
   1.309 +      DI_SetError("Enumerating supported effects",ret);
   1.310 +      goto acquire_err;
   1.311 +   }
   1.312 +   if (haptic->supported == 0) { /* Error since device supports nothing. */
   1.313 +      SDL_SetError("Haptic: Internal error on finding supported effects.");
   1.314 +      goto acquire_err;
   1.315 +   }
   1.316 +
   1.317 +   /* Check autogain and autocenter. */
   1.318 +   dipdw.diph.dwSize       = sizeof(DIPROPDWORD); 
   1.319 +   dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); 
   1.320 +   dipdw.diph.dwObj        = 0;
   1.321 +   dipdw.diph.dwHow        = DIPH_DEVICE;
   1.322 +   dipdw.dwData            = 10000;
   1.323 +   ret = IDirectInputDevice2_SetProperty( haptic->hwdata->device,        
   1.324 +                                          DIPROP_FFGAIN, &dipdw.diph );
   1.325 +   if (FAILED(ret)) {
   1.326 +      if (ret != DIERR_UNSUPPORTED) {
   1.327 +         DI_SetError("Checking gain",ret);
   1.328 +         goto acquire_err;
   1.329 +      }
   1.330 +   }
   1.331 +   else { /* Gain is supported. */
   1.332 +      haptic->supported |= SDL_HAPTIC_GAIN;
   1.333 +   }
   1.334 +   dipdw.dwData            = DIPROPAUTOCENTER_OFF;
   1.335 +   ret = IDirectInputDevice2_SetProperty( haptic->hwdata->device,
   1.336 +                                          DIPROP_AUTOCENTER, &dipdw.diph );
   1.337 +   if (FAILED(ret)) {
   1.338 +      if (ret != DIERR_UNSUPPORTED) {
   1.339 +         DI_SetError("Checking autocenter",ret);
   1.340 +         goto acquire_err;
   1.341 +      }
   1.342 +   }
   1.343 +   else { /* Autocenter is supported. */
   1.344 +      haptic->supported |= SDL_HAPTIC_AUTOCENTER;
   1.345 +   }
   1.346 +
   1.347 +
   1.348 +   /* Check maximum effects. */
   1.349 +   haptic->neffects = 128; /* TODO actually figure this out. */
   1.350 +   haptic->nplaying = 128;
   1.351 +
   1.352 +
   1.353 +   /* Prepare effects memory. */
   1.354 +   haptic->effects = (struct haptic_effect *)
   1.355 +         SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
   1.356 +   if (haptic->effects == NULL) {
   1.357 +      SDL_OutOfMemory();
   1.358 +      goto acquire_err;
   1.359 +   }
   1.360 +   /* Clear the memory */
   1.361 +   SDL_memset(haptic->effects, 0,
   1.362 +         sizeof(struct haptic_effect) * haptic->neffects);
   1.363 +   
   1.364 +   return 0;
   1.365 +   
   1.366 +   /* Error handling */
   1.367 +open_err:
   1.368 +   IDirectInputDevice_Release(device);
   1.369 +   goto creat_err;
   1.370 +acquire_err:
   1.371 +   IDirectInputDevice2_Unacquire(haptic->hwdata->device);
   1.372 +query_err:
   1.373 +   IDirectInputDevice2_Release(haptic->hwdata->device);   
   1.374 +creat_err:
   1.375 +   if (haptic->hwdata != NULL) {
   1.376 +      free(haptic->hwdata);
   1.377 +      haptic->hwdata = NULL;                                              
   1.378 +   }
   1.379 +   return -1;
   1.380 +
   1.381 +}
   1.382 +
   1.383 +
   1.384 +/*
   1.385 + * Opens a haptic device for usage.
   1.386 + */
   1.387 +int
   1.388 +SDL_SYS_HapticOpen(SDL_Haptic * haptic)
   1.389 +{
   1.390 +   return SDL_SYS_HapticOpenFromInstance( haptic,
   1.391 +         SDL_hapticlist[haptic->index].instance );
   1.392 +}
   1.393 +
   1.394 +
   1.395 +/*
   1.396 + * Opens a haptic device from first mouse it finds for usage.
   1.397 + */
   1.398 +int
   1.399 +SDL_SYS_HapticMouse(void)
   1.400 +{
   1.401 +   return -1;
   1.402 +}
   1.403 +
   1.404 +
   1.405 +/*
   1.406 + * Checks to see if a joystick has haptic features.
   1.407 + */
   1.408 +int
   1.409 +SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
   1.410 +{
   1.411 +   return SDL_FALSE;
   1.412 +}
   1.413 +
   1.414 +
   1.415 +/*
   1.416 + * Checks to see if the haptic device and joystick and in reality the same.
   1.417 + */
   1.418 +int
   1.419 +SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
   1.420 +{
   1.421 +   return 0;
   1.422 +}
   1.423 +
   1.424 +
   1.425 +/*
   1.426 + * Opens a SDL_Haptic from a SDL_Joystick.
   1.427 + */
   1.428 +int
   1.429 +SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
   1.430 +{
   1.431 +   return -1;
   1.432 +}
   1.433 +
   1.434 +
   1.435 +/*
   1.436 + * Closes the haptic device.
   1.437 + */
   1.438 +void
   1.439 +SDL_SYS_HapticClose(SDL_Haptic * haptic)
   1.440 +{
   1.441 +   int i;
   1.442 +
   1.443 +   if (haptic->hwdata) {
   1.444 +
   1.445 +      /* Free the effects. */
   1.446 +      for (i=0; i<haptic->neffects; i++) {        
   1.447 +         if (haptic->effects[i].hweffect != NULL) {
   1.448 +            SDL_SYS_HapticFreeFFEFFECT( &haptic->effects[i].hweffect->effect,
   1.449 +                                        haptic->effects[i].effect.type );
   1.450 +            SDL_free(haptic->effects[i].hweffect);
   1.451 +         } 
   1.452 +      }    
   1.453 +      SDL_free(haptic->effects);
   1.454 +      haptic->neffects = 0;
   1.455 +
   1.456 +      /* Clean up */
   1.457 +      IDirectInputDevice2_Unacquire(haptic->hwdata->device);
   1.458 +      IDirectInputDevice2_Release(haptic->hwdata->device);   
   1.459 +
   1.460 +      /* Free */
   1.461 +      SDL_free(haptic->hwdata);
   1.462 +      haptic->hwdata = NULL;
   1.463 +   }
   1.464 +}
   1.465 +
   1.466 +
   1.467 +/* 
   1.468 + * Clean up after system specific haptic stuff
   1.469 + */
   1.470 +void
   1.471 +SDL_SYS_HapticQuit(void)
   1.472 +{
   1.473 +   IDirectInput_Release(dinput);
   1.474 +   dinput = NULL;
   1.475 +}
   1.476 +
   1.477 +
   1.478 +/*
   1.479 + * Sets the direction.
   1.480 + */
   1.481 +static int
   1.482 +SDL_SYS_SetDirection( FFEFFECT * effect, SDL_HapticDirection *dir, int naxes )
   1.483 +{
   1.484 +   LONG *rglDir;
   1.485 +
   1.486 +   /* Handle no axes a part. */
   1.487 +   if (naxes == 0) {
   1.488 +      effect->rglDirection = NULL;
   1.489 +      return 0;
   1.490 +   }
   1.491 +
   1.492 +   /* Has axes. */
   1.493 +   rglDir = SDL_malloc( sizeof(LONG) * naxes );
   1.494 +   if (rglDir == NULL) {
   1.495 +      SDL_OutOfMemory();
   1.496 +      return -1;
   1.497 +   }
   1.498 +   SDL_memset( rglDir, 0, sizeof(LONG) * naxes );
   1.499 +   effect->rglDirection = rglDir;
   1.500 +
   1.501 +   switch (dir->type) {
   1.502 +      case SDL_HAPTIC_POLAR:
   1.503 +         effect->dwFlags |= FFEFF_POLAR;
   1.504 +         rglDir[0] = dir->dir[0];
   1.505 +         return 0;
   1.506 +      case SDL_HAPTIC_CARTESIAN:
   1.507 +         effect->dwFlags |= FFEFF_CARTESIAN;
   1.508 +         rglDir[0] = dir->dir[0];
   1.509 +         rglDir[1] = dir->dir[1];
   1.510 +         rglDir[2] = dir->dir[2];
   1.511 +         return 0;
   1.512 +      case SDL_HAPTIC_SPHERICAL:
   1.513 +         effect->dwFlags |= FFEFF_SPHERICAL;
   1.514 +         rglDir[0] = dir->dir[0];
   1.515 +         rglDir[1] = dir->dir[1];
   1.516 +         rglDir[2] = dir->dir[2];
   1.517 +         return 0;
   1.518 +
   1.519 +      default:
   1.520 +         SDL_SetError("Haptic: Unknown direction type.");
   1.521 +         return -1;
   1.522 +   }
   1.523 +}
   1.524 +
   1.525 +#define CONVERT(x)   (((x)*10000) / 0xFFFF )
   1.526 +/*
   1.527 + * Creates the FFEFFECT from a SDL_HapticEffect.
   1.528 + */
   1.529 +static int
   1.530 +SDL_SYS_ToFFEFFECT( SDL_Haptic * haptic, FFEFFECT * dest, SDL_HapticEffect * src )
   1.531 +{
   1.532 +   int i;
   1.533 +   FFCONSTANTFORCE *constant;
   1.534 +   FFPERIODIC *periodic;
   1.535 +   FFCONDITION *condition; /* Actually an array of conditions - one per axis. */
   1.536 +   FFRAMPFORCE *ramp;
   1.537 +   FFCUSTOMFORCE *custom;
   1.538 +   FFENVELOPE *envelope;
   1.539 +   SDL_HapticConstant *hap_constant;
   1.540 +   SDL_HapticPeriodic *hap_periodic;
   1.541 +   SDL_HapticCondition *hap_condition;
   1.542 +   SDL_HapticRamp *hap_ramp;
   1.543 +   SDL_HapticCustom *hap_custom;
   1.544 +   DWORD *axes;
   1.545 +
   1.546 +   /* Set global stuff. */
   1.547 +   SDL_memset(dest, 0, sizeof(FFEFFECT));
   1.548 +   dest->dwSize = sizeof(FFEFFECT); /* Set the structure size. */
   1.549 +   dest->dwSamplePeriod = 0; /* Not used by us. */
   1.550 +   dest->dwGain = 10000; /* Gain is set globally, not locally. */
   1.551 +
   1.552 +   /* Envelope. */
   1.553 +   envelope = SDL_malloc( sizeof(FFENVELOPE) );
   1.554 +   if (envelope == NULL) {
   1.555 +      SDL_OutOfMemory();
   1.556 +      return -1;
   1.557 +   }
   1.558 +   SDL_memset(envelope, 0, sizeof(FFENVELOPE));
   1.559 +   dest->lpEnvelope = envelope;
   1.560 +   envelope->dwSize = sizeof(FFENVELOPE); /* Always should be this. */
   1.561 +
   1.562 +   /* Axes. */
   1.563 +   dest->cAxes = haptic->naxes;
   1.564 +   if (dest->cAxes > 0) {
   1.565 +      axes = SDL_malloc(sizeof(DWORD) * dest->cAxes);
   1.566 +      if (axes == NULL) {
   1.567 +         SDL_OutOfMemory();
   1.568 +         return -1;
   1.569 +      }
   1.570 +      axes[0] = FFJOFS_X; /* Always at least one axis. */
   1.571 +      if (dest->cAxes > 1) {
   1.572 +         axes[1] = FFJOFS_Y;
   1.573 +      }
   1.574 +      if (dest->cAxes > 2) {
   1.575 +         axes[2] = FFJOFS_Z;
   1.576 +      }
   1.577 +      dest->rgdwAxes = axes;
   1.578 +   }
   1.579 +
   1.580 +
   1.581 +   /* The big type handling switch, even bigger then linux's version. */
   1.582 +   switch (src->type) {
   1.583 +      case SDL_HAPTIC_CONSTANT:
   1.584 +         hap_constant = &src->constant;
   1.585 +         constant = SDL_malloc( sizeof(FFCONSTANTFORCE) );
   1.586 +         if (constant == NULL) {
   1.587 +            SDL_OutOfMemory();
   1.588 +            return -1;
   1.589 +         }
   1.590 +         SDL_memset(constant, 0, sizeof(FFCONSTANTFORCE));
   1.591 +
   1.592 +         /* Specifics */
   1.593 +         constant->lMagnitude = CONVERT(hap_constant->level);
   1.594 +         dest->cbTypeSpecificParams = sizeof(FFCONSTANTFORCE); 
   1.595 +         dest->lpvTypeSpecificParams = constant;
   1.596 +
   1.597 +         /* Generics */
   1.598 +         dest->dwDuration = hap_constant->length * 1000; /* In microseconds. */
   1.599 +         dest->dwTriggerButton = FFJOFS_BUTTON(hap_constant->button);
   1.600 +         dest->dwTriggerRepeatInterval = hap_constant->interval;
   1.601 +         dest->dwStartDelay = hap_constant->delay * 1000; /* In microseconds. */
   1.602 +
   1.603 +         /* Direction. */
   1.604 +         if (SDL_SYS_SetDirection(dest, &hap_constant->direction, dest->cAxes) < 0) {
   1.605 +            return -1;
   1.606 +         }
   1.607 +         
   1.608 +         /* Envelope */
   1.609 +         envelope->dwAttackLevel = CONVERT(hap_constant->attack_level);
   1.610 +         envelope->dwAttackTime = hap_constant->attack_length * 1000;
   1.611 +         envelope->dwFadeLevel = CONVERT(hap_constant->fade_level);
   1.612 +         envelope->dwFadeTime = hap_constant->fade_length * 1000;
   1.613 +
   1.614 +         break;
   1.615 +
   1.616 +      case SDL_HAPTIC_SINE:
   1.617 +      case SDL_HAPTIC_SQUARE:
   1.618 +      case SDL_HAPTIC_TRIANGLE:
   1.619 +      case SDL_HAPTIC_SAWTOOTHUP:
   1.620 +      case SDL_HAPTIC_SAWTOOTHDOWN:
   1.621 +         hap_periodic = &src->periodic;
   1.622 +         periodic = SDL_malloc(sizeof(FFPERIODIC));
   1.623 +         if (periodic == NULL) {
   1.624 +            SDL_OutOfMemory();
   1.625 +            return -1;
   1.626 +         }
   1.627 +         SDL_memset(periodic, 0, sizeof(FFPERIODIC));
   1.628 +
   1.629 +         /* Specifics */
   1.630 +         periodic->dwMagnitude = CONVERT(hap_periodic->magnitude);
   1.631 +         periodic->lOffset = CONVERT(hap_periodic->offset);
   1.632 +         periodic->dwPhase = hap_periodic->phase;
   1.633 +         periodic->dwPeriod = hap_periodic->period * 1000;
   1.634 +         dest->cbTypeSpecificParams = sizeof(FFPERIODIC);
   1.635 +         dest->lpvTypeSpecificParams = periodic;
   1.636 +
   1.637 +         /* Generics */
   1.638 +         dest->dwDuration = hap_periodic->length * 1000; /* In microseconds. */
   1.639 +         dest->dwTriggerButton = FFJOFS_BUTTON(hap_periodic->button);
   1.640 +         dest->dwTriggerRepeatInterval = hap_periodic->interval;
   1.641 +         dest->dwStartDelay = hap_periodic->delay * 1000; /* In microseconds. */
   1.642 +         
   1.643 +         /* Direction. */
   1.644 +         if (SDL_SYS_SetDirection(dest, &hap_periodic->direction, dest->cAxes) < 0) {
   1.645 +            return -1;
   1.646 +         }
   1.647 +         
   1.648 +         /* Envelope */
   1.649 +         envelope->dwAttackLevel = CONVERT(hap_periodic->attack_level);
   1.650 +         envelope->dwAttackTime = hap_periodic->attack_length * 1000;
   1.651 +         envelope->dwFadeLevel = CONVERT(hap_periodic->fade_level);
   1.652 +         envelope->dwFadeTime = hap_periodic->fade_length * 1000;
   1.653 +
   1.654 +         break;
   1.655 +
   1.656 +      case SDL_HAPTIC_SPRING:
   1.657 +      case SDL_HAPTIC_DAMPER:
   1.658 +      case SDL_HAPTIC_INERTIA:
   1.659 +      case SDL_HAPTIC_FRICTION:
   1.660 +         hap_condition = &src->condition;
   1.661 +         condition = SDL_malloc(sizeof(FFCONDITION) * dest->cAxes);
   1.662 +         if (condition == NULL) {
   1.663 +            SDL_OutOfMemory();
   1.664 +            return -1;
   1.665 +         }
   1.666 +         SDL_memset(condition, 0, sizeof(FFCONDITION));
   1.667 +
   1.668 +         /* Specifics */
   1.669 +         for (i=0; i<dest->cAxes; i++) {
   1.670 +            condition[i].lOffset = CONVERT(hap_condition->center[i]);
   1.671 +            condition[i].lPositiveCoefficient = CONVERT(hap_condition->right_coeff[i]);
   1.672 +            condition[i].lNegativeCoefficient = CONVERT(hap_condition->left_coeff[i]);
   1.673 +            condition[i].dwPositiveSaturation = CONVERT(hap_condition->right_sat[i]);
   1.674 +            condition[i].dwNegativeSaturation = CONVERT(hap_condition->left_sat[i]);
   1.675 +            condition[i].lDeadBand = CONVERT(hap_condition->deadband[i]);
   1.676 +         }
   1.677 +         dest->cbTypeSpecificParams = sizeof(FFCONDITION) * dest->cAxes;
   1.678 +         dest->lpvTypeSpecificParams = condition;
   1.679 +
   1.680 +         /* Generics */
   1.681 +         dest->dwDuration = hap_condition->length * 1000; /* In microseconds. */
   1.682 +         dest->dwTriggerButton = FFJOFS_BUTTON(hap_condition->button);
   1.683 +         dest->dwTriggerRepeatInterval = hap_condition->interval;
   1.684 +         dest->dwStartDelay = hap_condition->delay * 1000; /* In microseconds. */
   1.685 +
   1.686 +         /* Direction. */
   1.687 +         if (SDL_SYS_SetDirection(dest, &hap_condition->direction, dest->cAxes) < 0) {
   1.688 +            return -1;                
   1.689 +         }                            
   1.690 +                                      
   1.691 +         /* Envelope */
   1.692 +/* TODO Check is envelope actually used.
   1.693 +         envelope->dwAttackLevel = CONVERT(hap_condition->attack_level);
   1.694 +         envelope->dwAttackTime = hap_condition->attack_length * 1000;
   1.695 +         envelope->dwFadeLevel = CONVERT(hap_condition->fade_level);
   1.696 +         envelope->dwFadeTime = hap_condition->fade_length * 1000;
   1.697 +*/
   1.698 +
   1.699 +         break;
   1.700 +
   1.701 +      case SDL_HAPTIC_RAMP:
   1.702 +         hap_ramp = &src->ramp;
   1.703 +         ramp = SDL_malloc(sizeof(FFRAMPFORCE));
   1.704 +         if (ramp == NULL) {
   1.705 +            SDL_OutOfMemory();
   1.706 +            return -1;
   1.707 +         }
   1.708 +         SDL_memset(ramp, 0, sizeof(FFRAMPFORCE));
   1.709 +
   1.710 +         /* Specifics */
   1.711 +         ramp->lStart = CONVERT(hap_ramp->start);
   1.712 +         ramp->lEnd = CONVERT(hap_ramp->end);
   1.713 +         dest->cbTypeSpecificParams = sizeof(FFRAMPFORCE);
   1.714 +         dest->lpvTypeSpecificParams = ramp;
   1.715 +
   1.716 +         /* Generics */
   1.717 +         dest->dwDuration = hap_ramp->length * 1000; /* In microseconds. */
   1.718 +         dest->dwTriggerButton = FFJOFS_BUTTON(hap_ramp->button);
   1.719 +         dest->dwTriggerRepeatInterval = hap_ramp->interval;
   1.720 +         dest->dwStartDelay = hap_ramp->delay * 1000; /* In microseconds. */
   1.721 +
   1.722 +         /* Direction. */
   1.723 +         if (SDL_SYS_SetDirection(dest, &hap_ramp->direction, dest->cAxes) < 0) {
   1.724 +            return -1;
   1.725 +         }
   1.726 +
   1.727 +         /* Envelope */
   1.728 +         envelope->dwAttackLevel = CONVERT(hap_ramp->attack_level);
   1.729 +         envelope->dwAttackTime = hap_ramp->attack_length * 1000;
   1.730 +         envelope->dwFadeLevel = CONVERT(hap_ramp->fade_level);
   1.731 +         envelope->dwFadeTime = hap_ramp->fade_length * 1000;
   1.732 +
   1.733 +         break;
   1.734 +
   1.735 +      case SDL_HAPTIC_CUSTOM:
   1.736 +         hap_custom = &src->custom;
   1.737 +         custom = SDL_malloc(sizeof(FFCUSTOMFORCE));
   1.738 +         if (custom == NULL) {
   1.739 +            SDL_OutOfMemory();
   1.740 +            return -1;
   1.741 +         }
   1.742 +         SDL_memset(custom, 0, sizeof(FFCUSTOMFORCE));
   1.743 +
   1.744 +         /* Specifics */
   1.745 +         custom->cChannels = hap_custom->channels;
   1.746 +         custom->dwSamplePeriod = hap_custom->period * 1000;
   1.747 +         custom->cSamples = hap_custom->samples;
   1.748 +         custom->rglForceData = SDL_malloc(sizeof(LONG)*custom->cSamples*custom->cChannels);
   1.749 +         for (i=0; i<hap_custom->samples*hap_custom->channels; i++) { /* Copy data. */
   1.750 +            custom->rglForceData[i] = CONVERT(hap_custom->data[i]);
   1.751 +         }
   1.752 +         dest->cbTypeSpecificParams = sizeof(FFCUSTOMFORCE);
   1.753 +         dest->lpvTypeSpecificParams = custom;
   1.754 +
   1.755 +         /* Generics */
   1.756 +         dest->dwDuration = hap_custom->length * 1000; /* In microseconds. */
   1.757 +         dest->dwTriggerButton = FFJOFS_BUTTON(hap_custom->button);
   1.758 +         dest->dwTriggerRepeatInterval = hap_custom->interval;
   1.759 +         dest->dwStartDelay = hap_custom->delay * 1000; /* In microseconds. */
   1.760 +
   1.761 +         /* Direction. */
   1.762 +         if (SDL_SYS_SetDirection(dest, &hap_custom->direction, dest->cAxes) < 0) {
   1.763 +            return -1;
   1.764 +         }
   1.765 +         
   1.766 +         /* Envelope */
   1.767 +         envelope->dwAttackLevel = CONVERT(hap_custom->attack_level);
   1.768 +         envelope->dwAttackTime = hap_custom->attack_length * 1000;
   1.769 +         envelope->dwFadeLevel = CONVERT(hap_custom->fade_level);
   1.770 +         envelope->dwFadeTime = hap_custom->fade_length * 1000;
   1.771 +
   1.772 +         break;
   1.773 +
   1.774 +
   1.775 +      default:
   1.776 +         SDL_SetError("Haptic: Unknown effect type.");
   1.777 +         return -1;
   1.778 +   }
   1.779 +
   1.780 +   return 0;
   1.781 +}
   1.782 +
   1.783 +
   1.784 +/*
   1.785 + * Frees an FFEFFECT allocated by SDL_SYS_ToFFEFFECT.
   1.786 + */
   1.787 +static void
   1.788 +SDL_SYS_HapticFreeFFEFFECT( FFEFFECT * effect, int type )
   1.789 +{
   1.790 +   FFCUSTOMFORCE *custom;
   1.791 +
   1.792 +   if (effect->lpEnvelope != NULL) {
   1.793 +      SDL_free(effect->lpEnvelope);
   1.794 +      effect->lpEnvelope = NULL;
   1.795 +   }
   1.796 +   if (effect->rgdwAxes != NULL) {
   1.797 +      SDL_free(effect->rgdwAxes);
   1.798 +      effect->rgdwAxes = NULL;
   1.799 +   }
   1.800 +   if (effect->lpvTypeSpecificParams != NULL) {
   1.801 +      if (type == SDL_HAPTIC_CUSTOM) { /* Must free the custom data. */
   1.802 +         custom = (FFCUSTOMFORCE*) effect->lpvTypeSpecificParams;
   1.803 +         SDL_free(custom->rglForceData);
   1.804 +         custom->rglForceData = NULL;
   1.805 +      }
   1.806 +      SDL_free(effect->lpvTypeSpecificParams);
   1.807 +      effect->lpvTypeSpecificParams = NULL;
   1.808 +   }
   1.809 +   if (effect->rglDirection != NULL) {
   1.810 +      SDL_free(effect->rglDirection);
   1.811 +      effect->rglDirection = NULL;
   1.812 +   }
   1.813 +}
   1.814 +
   1.815 +
   1.816 +/*
   1.817 + * Gets the effect type from the generic SDL haptic effect wrapper.
   1.818 + */
   1.819 +REFGUID
   1.820 +SDL_SYS_HapticEffectType(struct haptic_effect * effect)
   1.821 +{
   1.822 +   switch (effect->effect.type) {
   1.823 +      case SDL_HAPTIC_CONSTANT:
   1.824 +         return GUID_ConstantForce;
   1.825 +
   1.826 +      case SDL_HAPTIC_RAMP:
   1.827 +         return GUID_RampForce;
   1.828 +
   1.829 +      case SDL_HAPTIC_SQUARE:
   1.830 +         return GUID_Square;
   1.831 +
   1.832 +      case SDL_HAPTIC_SINE:
   1.833 +         return GUID_Sine;
   1.834 +
   1.835 +      case SDL_HAPTIC_TRIANGLE:
   1.836 +         return GUID_Triangle;
   1.837 +
   1.838 +      case SDL_HAPTIC_SAWTOOTHUP:
   1.839 +         return GUID_SawtoothUp;
   1.840 +
   1.841 +      case SDL_HAPTIC_SAWTOOTHDOWN:
   1.842 +         return GUID_SawtoothDown;
   1.843 +
   1.844 +      case SDL_HAPTIC_SPRING:
   1.845 +         return GUID_Spring;
   1.846 +
   1.847 +      case SDL_HAPTIC_DAMPER:
   1.848 +         return GUID_Damper;
   1.849 +
   1.850 +      case SDL_HAPTIC_INERTIA:
   1.851 +         return GUID_Inertia;
   1.852 +
   1.853 +      case SDL_HAPTIC_FRICTION:
   1.854 +         return GUID_Friction;
   1.855 +
   1.856 +      case SDL_HAPTIC_CUSTOM:
   1.857 +         return GUID_CustomForce;
   1.858 +
   1.859 +      default:
   1.860 +         SDL_SetError("Haptic: Unknown effect type.");
   1.861 +         return NULL;
   1.862 +   }
   1.863 +}
   1.864 +
   1.865 +
   1.866 +/*
   1.867 + * Creates a new haptic effect.
   1.868 + */
   1.869 +int
   1.870 +SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect * effect,
   1.871 +      SDL_HapticEffect * base)
   1.872 +{
   1.873 +   HRESULT ret;
   1.874 +   REFGUID type;
   1.875 +
   1.876 +   /* Alloc the effect. */
   1.877 +   effect->hweffect = (struct haptic_hweffect *)
   1.878 +         SDL_malloc(sizeof(struct haptic_hweffect));
   1.879 +   if (effect->hweffect == NULL) {
   1.880 +      SDL_OutOfMemory();
   1.881 +      goto err_hweffect;
   1.882 +   }
   1.883 +
   1.884 +   /* Get the type. */
   1.885 +   type = SDL_SYS_HapticEffectType(effect);
   1.886 +   if (type == NULL) {
   1.887 +      goto err_hweffect;
   1.888 +   }
   1.889 +
   1.890 +   /* Get the effect. */
   1.891 +   if (SDL_SYS_ToFFEFFECT(haptic, &effect->hweffect->effect, base) < 0) {
   1.892 +      goto err_effectdone;
   1.893 +   }
   1.894 +
   1.895 +   /* Create the actual effect. */
   1.896 +   ret = FFDeviceCreateEffect(haptic->hwdata->device, type,
   1.897 +         &effect->hweffect->effect, &effect->hweffect->ref);
   1.898 +   if (ret != FF_OK) {
   1.899 +      SDL_SetError("Haptic: Unable to create effect: %s.", FFStrError(ret));
   1.900 +      goto err_effectdone;
   1.901 +   }
   1.902 +
   1.903 +   return 0;
   1.904 +
   1.905 +err_effectdone:
   1.906 +   SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect, base->type);
   1.907 +err_hweffect:
   1.908 +   if (effect->hweffect != NULL) {
   1.909 +      SDL_free(effect->hweffect);
   1.910 +      effect->hweffect = NULL;
   1.911 +   }
   1.912 +   return -1;
   1.913 +}
   1.914 +
   1.915 +
   1.916 +/*
   1.917 + * Updates an effect.
   1.918 + */
   1.919 +int
   1.920 +SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
   1.921 +      struct haptic_effect * effect, SDL_HapticEffect * data)
   1.922 +{
   1.923 +   HRESULT ret;
   1.924 +   FFEffectParameterFlag flags;
   1.925 +   FFEFFECT temp;
   1.926 +
   1.927 +   /* Get the effect. */
   1.928 +   SDL_memset(&temp, 0, sizeof(FFEFFECT));
   1.929 +   if (SDL_SYS_ToFFEFFECT(haptic, &temp, data) < 0) {
   1.930 +      goto err_update;
   1.931 +   }
   1.932 +
   1.933 +   /* Set the flags.  Might be worthwhile to diff temp with loaded effect and
   1.934 +    *  only change those parameters. */
   1.935 +   flags = FFEP_ALLPARAMS;
   1.936 +
   1.937 +   /* Create the actual effect. */
   1.938 +   ret = FFEffectSetParameters(effect->hweffect->ref, &temp, flags);
   1.939 +   if (ret != FF_OK) {
   1.940 +      SDL_SetError("Haptic: Unable to update effect: %s.", FFStrError(ret));
   1.941 +      goto err_update;
   1.942 +   }
   1.943 +
   1.944 +   /* Copy it over. */
   1.945 +   SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect, data->type);
   1.946 +   SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(FFEFFECT));
   1.947 +
   1.948 +   return 0;
   1.949 +
   1.950 +err_update:
   1.951 +   SDL_SYS_HapticFreeFFEFFECT(&temp, data->type);
   1.952 +   return -1;
   1.953 +}
   1.954 +
   1.955 +
   1.956 +/*
   1.957 + * Runs an effect.
   1.958 + */
   1.959 +int
   1.960 +SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect * effect,
   1.961 +                        Uint32 iterations)
   1.962 +{
   1.963 +   HRESULT ret;
   1.964 +   Uint32 iter;
   1.965 +
   1.966 +   /* Check if it's infinite. */
   1.967 +   if (iterations == SDL_HAPTIC_INFINITY) {
   1.968 +      iter = FF_INFINITE;
   1.969 +   }
   1.970 +   else
   1.971 +      iter = iterations;
   1.972 +
   1.973 +   /* Run the effect. */
   1.974 +   ret = FFEffectStart(effect->hweffect->ref, iter, 0);
   1.975 +   if (ret != FF_OK) {
   1.976 +      SDL_SetError("Haptic: Unable to run the effect: %s.", FFStrError(ret));
   1.977 +      return -1;
   1.978 +   }
   1.979 +
   1.980 +   return 0;
   1.981 +}
   1.982 +
   1.983 +
   1.984 +/*
   1.985 + * Stops an effect.
   1.986 + */
   1.987 +int
   1.988 +SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect * effect)
   1.989 +{
   1.990 +   HRESULT ret;
   1.991 +
   1.992 +   ret = FFEffectStop(effect->hweffect->ref);
   1.993 +   if (ret != FF_OK) {
   1.994 +      SDL_SetError("Haptic: Unable to stop the effect: %s.", FFStrError(ret));
   1.995 +      return -1;
   1.996 +   }
   1.997 +
   1.998 +   return 0;
   1.999 +}
  1.1000 +
  1.1001 +
  1.1002 +/*
  1.1003 + * Frees the effect.
  1.1004 + */
  1.1005 +void
  1.1006 +SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect * effect)
  1.1007 +{
  1.1008 +   HRESULT ret;
  1.1009 +
  1.1010 +   ret = FFDeviceReleaseEffect(haptic->hwdata->device, effect->hweffect->ref);
  1.1011 +   if (ret != FF_OK) {
  1.1012 +      SDL_SetError("Haptic: Error removing the effect from the device: %s.",
  1.1013 +                   FFStrError(ret));
  1.1014 +   }
  1.1015 +   SDL_free(effect->hweffect->effect.lpvTypeSpecificParams);
  1.1016 +   effect->hweffect->effect.lpvTypeSpecificParams = NULL;
  1.1017 +   SDL_free(effect->hweffect);
  1.1018 +   effect->hweffect = NULL;
  1.1019 +}
  1.1020 +
  1.1021 +
  1.1022 +/*
  1.1023 + * Gets the status of a haptic effect.
  1.1024 + */
  1.1025 +int
  1.1026 +SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect * effect)
  1.1027 +{
  1.1028 +}
  1.1029 +
  1.1030 +
  1.1031 +/*
  1.1032 + * Sets the gain.
  1.1033 + */
  1.1034 +int
  1.1035 +SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
  1.1036 +{
  1.1037 +   HRESULT ret;
  1.1038 +   DIPROPDWORD dipdw;
  1.1039 +
  1.1040 +   /* Create the weird structure thingy. */
  1.1041 +   dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
  1.1042 +   dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  1.1043 +   dipdw.diph.dwObj        = 0;
  1.1044 +   dipdw.diph.dwHow        = DIPH_DEVICE;
  1.1045 +   dipdw.dwData            = gain * 100; /* 0 to 10,000 */
  1.1046 +
  1.1047 +   /* Try to set the autocenter. */
  1.1048 +   ret = IDirectInputDevice2_SetProperty( haptic->hwdata->device,
  1.1049 +                                          DIPROP_FFGAIN, &dipdw.diph );
  1.1050 +   if (FAILED(ret)) {
  1.1051 +      DI_SetError("Setting gain",ret);
  1.1052 +      return -1;
  1.1053 +   }
  1.1054 +  
  1.1055 +   return 0;
  1.1056 +}
  1.1057 +
  1.1058 +
  1.1059 +/*
  1.1060 + * Sets the autocentering.
  1.1061 + */
  1.1062 +int
  1.1063 +SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
  1.1064 +{
  1.1065 +   HRESULT ret;
  1.1066 +   DIPROPDWORD dipdw;
  1.1067 +
  1.1068 +   /* Create the weird structure thingy. */
  1.1069 +   dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
  1.1070 +   dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  1.1071 +   dipdw.diph.dwObj        = 0;
  1.1072 +   dipdw.diph.dwHow        = DIPH_DEVICE;
  1.1073 +   dipdw.dwData            = (autocenter == 0) ? DIPROPAUTOCENTER_OFF : 
  1.1074 +                                                 DIPROPAUTOCENTER_ON;
  1.1075 +
  1.1076 +   /* Try to set the autocenter. */
  1.1077 +   ret = IDirectInputDevice2_SetProperty( haptic->hwdata->device,
  1.1078 +                                          DIPROP_AUTOCENTER, &dipdw.diph );
  1.1079 +   if (FAILED(ret)) {
  1.1080 +      DI_SetError("Setting autocenter",ret);
  1.1081 +      return -1;
  1.1082 +   }
  1.1083 +  
  1.1084 +   return 0;
  1.1085 +
  1.1086 +}
  1.1087 +
  1.1088 +
  1.1089 +#endif /* SDL_HAPTIC_DINPUT */