Adding initial darwin port of haptic subsystem - broken atm. gsoc2008_force_feedback
authorEdgar Simo <bobbens@gmail.com>
Tue, 15 Jul 2008 16:35:14 +0000
branchgsoc2008_force_feedback
changeset 25206aee9eb4fc6d
parent 2519 af9df9662807
child 2521 7aa91c21ce5f
Adding initial darwin port of haptic subsystem - broken atm.
src/haptic/darwin/SDL_syshaptic.c
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/haptic/darwin/SDL_syshaptic.c	Tue Jul 15 16:35:14 2008 +0000
     1.3 @@ -0,0 +1,693 @@
     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_IOKIT
    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/dawrin/SDL_sysjoystick_c.h"*/ /* For joystick hwdata */ 
    1.34 +
    1.35 +#include <ForceFeedback/ForceFeedback.h>
    1.36 +#include <ForceFeedback/ForceFeedbackConstants.h>
    1.37 +
    1.38 +
    1.39 +#define MAX_HAPTICS  32
    1.40 +
    1.41 +
    1.42 +/*
    1.43 + * List of available haptic devices.
    1.44 + */
    1.45 +static struct
    1.46 +{
    1.47 +   io_service_t dev;
    1.48 +   SDL_Haptic *haptic;
    1.49 +} SDL_hapticlist[MAX_HAPTICS];
    1.50 +
    1.51 +
    1.52 +/*
    1.53 + * Haptic system hardware data.
    1.54 + */
    1.55 +struct haptic_hwdata
    1.56 +{
    1.57 +   FFDeviceObjectReference device; /* Hardware device. */
    1.58 +};
    1.59 +
    1.60 +
    1.61 +/*
    1.62 + * Haptic system effect data.
    1.63 + */
    1.64 +struct haptic_hweffect
    1.65 +{
    1.66 +   FFEffectObjectReference ref; /* Reference. */
    1.67 +   struct FFEFFECT effect; /* Hardware effect. */
    1.68 +};
    1.69 +
    1.70 +
    1.71 +/*
    1.72 + * Initializes the haptic subsystem.
    1.73 + */
    1.74 +int
    1.75 +SDL_SYS_HapticInit(void)
    1.76 +{
    1.77 +   int numhaptics;
    1.78 +   IOReturn result;
    1.79 +   io_iterator_t iter;
    1.80 +   CFDictionaryRef match;
    1.81 +   io_sercive_t device;
    1.82 +
    1.83 +   /* Get HID devices. */
    1.84 +   match = IOServiceMatching(kIOHIDDeviceKey);
    1.85 +   if (match == NULL) {
    1.86 +      SDL_SetError("Haptic: Failed to get IOServiceMatching.");
    1.87 +      return -1;
    1.88 +   }
    1.89 +
    1.90 +   /* Now search I/O Registry for matching devices. */
    1.91 +   result = IOServiceGetMatchingServices(kIOMasterPortDefault, match, &iter);
    1.92 +   if (result != kIOReturnSuccess) {
    1.93 +      SDL_SetError("Haptic: Couldn't create a HID object iterator.");
    1.94 +      return -1;
    1.95 +   }
    1.96 +   /* IOServiceGetMatchingServices consumes dictionary. */
    1.97 +
    1.98 +   numhaptics = 0;
    1.99 +   while ((device = IOIteratorNext(iter)) != IO_OBJECT_NULL) {
   1.100 +
   1.101 +      /* Check for force feedback. */
   1.102 +      if (FFIsForceFeedback(device) == FF_OK) {
   1.103 +         SDL_hapticlist[numhaptics].dev = device;
   1.104 +         SDL_hapticlist[numhaptics].haptic = NULL;
   1.105 +         numhaptics++;
   1.106 +      }
   1.107 +
   1.108 +      /* Reached haptic limit. */
   1.109 +      if (numhaptics >= MAX_HAPTICS)
   1.110 +         break;
   1.111 +   }
   1.112 +   IOObjectRelease(iter);
   1.113 +
   1.114 +   return numhaptics;
   1.115 +}
   1.116 +
   1.117 +
   1.118 +/*
   1.119 + * Return the name of a haptic device, does not need to be opened.
   1.120 + */
   1.121 +const char *
   1.122 +SDL_SYS_HapticName(int index)
   1.123 +{
   1.124 +   return NULL;
   1.125 +}
   1.126 +
   1.127 +
   1.128 +#define FF_TEST(ff, s) \
   1.129 +if (features.supportedEffects & ff) supported |= s
   1.130 +/*
   1.131 + * Gets supported features.
   1.132 + */
   1.133 +static unsigned int
   1.134 +GetSupportedFeatures(FFDeviceObjectReference device,
   1.135 +                     int *neffects, int *nplaying)
   1.136 +{
   1.137 +   HRESULT ret;
   1.138 +   FFCAPABILITIES features;
   1.139 +   unsigned int supported;
   1.140 +   Uint32 val;
   1.141 +
   1.142 +   ret = FFDeviceGetForceFeedbackCapabilities(device, &features);
   1.143 +   if (ret != FF_OK) {
   1.144 +      SDL_SetError("Haptic: Unable to get device's supported features.");
   1.145 +      return 0;
   1.146 +   }
   1.147 +
   1.148 +   supported = 0;
   1.149 +
   1.150 +   /* Get maximum effects. */
   1.151 +   *neffects = features.storageCapacity;
   1.152 +   *nplaying = features.playbackCapacity;
   1.153 +
   1.154 +   /* Test for effects. */
   1.155 +   FF_TEST(FFCAP_ET_CONSTANTFORCE, SDL_HAPTIC_CONSTANT);
   1.156 +   FF_TEST(FFCAP_ET_RAMPFORCE,     SDL_HAPTIC_RAMP);
   1.157 +   FF_TEST(FFCAP_ET_SQUARE,        SDL_HAPTIC_SQUARE);
   1.158 +   FF_TEST(FFCAP_ET_SINE,          SDL_HAPTIC_SINE);
   1.159 +   FF_TEST(FFCAP_ET_TRIANGLE,      SDL_HAPTIC_TRIANGLE);
   1.160 +   FF_TEST(FFCAP_ET_SAWTOOTHUP,    SDL_HAPTIC_SAWTOOTHUP);
   1.161 +   FF_TEST(FFCAP_ET_SAWTOOTHDOWN,  SDL_HAPTIC_SAWTOOTHDOWN);
   1.162 +   FF_TEST(FFCAP_ET_SPRING,        SDL_HAPTIC_SPRING);
   1.163 +   FF_TEST(FFCAP_ET_DAMPER,        SDL_HAPTIC_DAMPER);
   1.164 +   FF_TEST(FFCAP_ET_INERTIA,       SDL_HAPTIC_INERTIA);
   1.165 +   FF_TEST(FFCAP_ET_FRICTION,      SDL_HAPTIC_FRICTION);
   1.166 +   FF_TEST(FFCAP_ET_CUSTOMFORCE,   SDL_HAPTIC_CUSTOM);
   1.167 +
   1.168 +   /* Check if supports gain. */
   1.169 +   ret = FFDeviceGetForceFeedbackProperty(device, FFPROP_FFGAIN,
   1.170 +                                          val, sizeof(val));
   1.171 +   if (ret == FF_OK) supported |= SDL_HAPTIC_GAIN;
   1.172 +   else if (ret != FFERR_UNSUPPORTED) {
   1.173 +      SDL_SetError("Haptic: Unable to get if device supports gain.");
   1.174 +      return 0;
   1.175 +   }
   1.176 +
   1.177 +   /* Checks if supports autocenter. */
   1.178 +   ret = FFDeviceGetForceFeedbackProperty(device, FFPROP_FFAUTOCENTER,
   1.179 +                                          val, sizeof(val));
   1.180 +   if (ret == FF_OK) supported |= SDL_HAPTIC_AUTOCENTER;
   1.181 +   else if (ret != FFERR_UNSUPPORTED) {
   1.182 +      SDL_SetError("Haptic: Unable to get if device supports autocenter.");
   1.183 +      return 0;
   1.184 +   }
   1.185 +
   1.186 +   /* Always supported features. */
   1.187 +   supported |= SDL_HAPTIC_STATUS;
   1.188 +   return supported;
   1.189 +}
   1.190 +
   1.191 +
   1.192 +/*
   1.193 + * Opens the haptic device from the file descriptor.
   1.194 + */
   1.195 +static int
   1.196 +SDL_SYS_HapticOpenFromService(SDL_Haptic * haptic, io_service_t service)
   1.197 +{
   1.198 +   /* Allocate the hwdata */
   1.199 +   haptic->hwdata = (struct haptic_hwdata *)
   1.200 +         SDL_malloc(sizeof(*haptic->hwdata));
   1.201 +   if (haptic->hwdata == NULL) {
   1.202 +      SDL_OutOfMemory();
   1.203 +      goto creat_err;
   1.204 +   }
   1.205 +   SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
   1.206 +  
   1.207 +   /* Open the device */
   1.208 +   if (FFCreateDevice( &service, &haptic->hwdata->device ) != FF_OK) {
   1.209 +      SDL_SetError("Haptic: Unable to create device from service.");
   1.210 +      goto creat_err;
   1.211 +   }
   1.212 +
   1.213 +   /* Get supported features. */
   1.214 +   haptic->supported = GetSupportedFeatures(haptic->hwdata->device,
   1.215 +                                            &haptic->neffects, &haptic->nplaying);
   1.216 +   if (haptic->supported == 0) { /* Error since device supports nothing. */
   1.217 +      goto open_err;
   1.218 +   }
   1.219 +   haptic->effects = (struct haptic_effect *)
   1.220 +         SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
   1.221 +   if (haptic->effects == NULL) {
   1.222 +      SDL_OutOfMemory();
   1.223 +      goto open_err;
   1.224 +   }
   1.225 +   /* Clear the memory */
   1.226 +   SDL_memset(haptic->effects, 0,
   1.227 +         sizeof(struct haptic_effect) * haptic->neffects);
   1.228 +   
   1.229 +   return 0;
   1.230 +   
   1.231 +   /* Error handling */
   1.232 +open_err:
   1.233 +   FFReleaseDevice(haptic->hwdata->device);
   1.234 +creat_err:
   1.235 +   if (haptic->hwdata != NULL) {
   1.236 +      free(haptic->hwdata);
   1.237 +      haptic->hwdata = NULL;                                              
   1.238 +   }
   1.239 +   return -1;
   1.240 +
   1.241 +}
   1.242 +
   1.243 +
   1.244 +/*
   1.245 + * Opens a haptic device for usage.
   1.246 + */
   1.247 +int
   1.248 +SDL_SYS_HapticOpen(SDL_Haptic * haptic)
   1.249 +{
   1.250 +   return SDL_SYS_HapticOpenFromService(haptic,
   1.251 +                SDL_hapticlist[haptic->index].device);
   1.252 +}
   1.253 +
   1.254 +
   1.255 +/*
   1.256 + * Opens a haptic device from first mouse it finds for usage.
   1.257 + */
   1.258 +int
   1.259 +SDL_SYS_HapticMouse(void)
   1.260 +{
   1.261 +   return -1;
   1.262 +}
   1.263 +
   1.264 +
   1.265 +/*
   1.266 + * Checks to see if a joystick has haptic features.
   1.267 + */
   1.268 +int
   1.269 +SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
   1.270 +{
   1.271 +   return SDL_FALSE;
   1.272 +}
   1.273 +
   1.274 +
   1.275 +/*
   1.276 + * Checks to see if the haptic device and joystick and in reality the same.
   1.277 + */
   1.278 +int
   1.279 +SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
   1.280 +{
   1.281 +   if (SDL_strcmp(joystick->name,haptic->name)==0) {
   1.282 +      return 1;
   1.283 +   }
   1.284 +   return 0;
   1.285 +}
   1.286 +
   1.287 +
   1.288 +/*
   1.289 + * Opens a SDL_Haptic from a SDL_Joystick.
   1.290 + */
   1.291 +int
   1.292 +SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
   1.293 +{
   1.294 +   return -1;
   1.295 +}
   1.296 +
   1.297 +
   1.298 +/*
   1.299 + * Closes the haptic device.
   1.300 + */
   1.301 +void
   1.302 +SDL_SYS_HapticClose(SDL_Haptic * haptic)
   1.303 +{
   1.304 +   int i;
   1.305 +
   1.306 +   if (haptic->hwdata) {
   1.307 +
   1.308 +      /* Clean up */
   1.309 +      FFReleaseDevice(haptic->hwdata->device);
   1.310 +
   1.311 +      /* Free */
   1.312 +      SDL_free(haptic->hwdata);
   1.313 +      haptic->hwdata = NULL;
   1.314 +      for (i=0; i<haptic->neffects; i++) {
   1.315 +         if (haptic->effects[i].hweffect != NULL)
   1.316 +            SDL_free(haptic->effects[i].hweffect->effect.lpvTypeSpecificParams);
   1.317 +      }
   1.318 +      SDL_free(haptic->effects);
   1.319 +      haptic->neffects = 0;
   1.320 +   }
   1.321 +}
   1.322 +
   1.323 +
   1.324 +/* 
   1.325 + * Clean up after system specific haptic stuff
   1.326 + */
   1.327 +void
   1.328 +SDL_SYS_HapticQuit(void)
   1.329 +{
   1.330 +   int i;
   1.331 +
   1.332 +   for (i=0; i < SDL_numhaptics; i++) {
   1.333 +      IOObjectRelease(SDL_hapticlist[i].dev);
   1.334 +      /* TODO free effects. */
   1.335 +   }
   1.336 +}
   1.337 +
   1.338 +
   1.339 +/*
   1.340 + * Sets the direction.
   1.341 + */
   1.342 +static int
   1.343 +SDL_SYS_SetDirection( FFEFFECT * effect, SDL_HapticDirection *dir, int axes )
   1.344 +{
   1.345 +   LONG *dir;
   1.346 +   dir = SDL_malloc( sizeof(LONG) * axes );
   1.347 +   if (dir == NULL) {
   1.348 +      SDL_OutOfMemory();
   1.349 +      return -1;
   1.350 +   }
   1.351 +   SDL_memset( dir, 0, sizeof(LONG) * axes );
   1.352 +   effect->rglDirection = dir;
   1.353 +
   1.354 +   switch (dir->type) {
   1.355 +      case SDL_HAPTIC_POLAR:
   1.356 +         effect->dwFlags |= FFEFF_POLAR;
   1.357 +         dir[0] = dir->dir[0];
   1.358 +         return 0;
   1.359 +      case SDL_HAPTIC_CARTESIAN:
   1.360 +         effects->dwFlags |= FFEFF_CARTESIAN;
   1.361 +         dir[0] = dir->dir[0];
   1.362 +         dir[1] = dir->dir[1];
   1.363 +         dir[2] = dir->dir[2];
   1.364 +         return 0;
   1.365 +      case SDL_HAPTIC_SHPERICAL:
   1.366 +         effects->dwFlags |= FFEFF_SPHERICAL;
   1.367 +         dir[0] = dir->dir[0];
   1.368 +         dir[1] = dir->dir[1];
   1.369 +         dir[2] = dir->dir[2];
   1.370 +         return 0;
   1.371 +
   1.372 +      default:
   1.373 +         SDL_SetError("Haptic: Unknown direction type.");
   1.374 +         return -1;
   1.375 +   }
   1.376 +}
   1.377 +
   1.378 +#define CONVERT(x)   (((x)*10000) / 0xFFFF )
   1.379 +/*
   1.380 + * Creates the FFStruct
   1.381 + */
   1.382 +static int
   1.383 +SDL_SYS_ToFFEFFECT( FFEFFECT * dest, SDL_HapticEffect * src )
   1.384 +{
   1.385 +   FFCONSTANTFORCE *constant;
   1.386 +   FFPERIODIC *periodic;
   1.387 +   FFCONDITION *condition;
   1.388 +   FFRAMPFORCE *ramp;
   1.389 +   FFCUSTOMFORCE *custom;
   1.390 +   SDL_HapticConstant *hap_constant;
   1.391 +   SDL_HapticPeriodic *hap-periodic;
   1.392 +   SDL_HapticCondition *hap_condition;
   1.393 +   SDL_HapticRamp *hap_ramp;
   1.394 +
   1.395 +   /* Set global stuff. */
   1.396 +   SDL_memset(dest, 0, sizeof(FFEFFECT));
   1.397 +   dest->dwSize = sizeof(FFEFFECT); /* Set the structure size. */
   1.398 +   dest->dwSamplePeriod = 0; /* Not used by us. */
   1.399 +   dest->dwGain = 10000; /* Gain is set globally, not locally. */
   1.400 +   dest->lpEnvelope.dwSize = sizeof(FFENVELOPE); /* Always should be this. */
   1.401 +
   1.402 +   switch (src->type) {
   1.403 +      case SDL_HAPTIC_CONSTANT:
   1.404 +         hap_constant = &src->constant;
   1.405 +         constant = SDL_malloc( sizeof(FFCONSTANTFORCE) );
   1.406 +
   1.407 +         /* Specifics */
   1.408 +         constant->lMagnitude = CONVERT(hap_constant->level);
   1.409 +         dest->cbTypeSpecificParams = sizeof(FFCONSTANTFORCE); 
   1.410 +         dest->lpvTypeSpecificParams = constant;
   1.411 +
   1.412 +         /* Generics */
   1.413 +         dest->dwDuration = src->length * 1000; /* In microseconds. */
   1.414 +         dest->dwTriggerButton = FFJOFS_BUTTON(hap_constant->button);
   1.415 +         dest->dwTriggerRepeatInterval = hap_constant->interval;
   1.416 +         dest->dwStartDelay = src->delay * 1000; /* In microseconds. */
   1.417 +
   1.418 +         /* Axes */
   1.419 +         dest->cAxes = 2; /* TODO handle */
   1.420 +         dest->rgdwAxes = 0;
   1.421 +
   1.422 +         /* Direction. */
   1.423 +         if (SDL_SYS_SetDirection(dest, hap_constant->direction, dest->cAxes) < 0) {
   1.424 +            return -1;
   1.425 +         }
   1.426 +         
   1.427 +         /* Envelope */
   1.428 +         dest->lpEnvelope.dwAttackLevel = CONVERT(hap_constant->attack_level);
   1.429 +         dest->lpEnvelope.dwAttackTime = hap_constant->attack_length * 1000;
   1.430 +         dest->lpEnvelope.dwFadeLevel = CONVERT(hap_constant->fade_level);
   1.431 +         dest->lpEnvelope.dwFadeTime = hap_constant->fade_length * 1000;
   1.432 +
   1.433 +         break;
   1.434 +
   1.435 +         /* TODO finish */
   1.436 +
   1.437 +      case SDL_HAPTIC_SINE:
   1.438 +      case SDL_HAPTIC_SQUARE:
   1.439 +      case SDL_HAPTIC_TRIANGLE:
   1.440 +      case SDL_HAPTIC_SAWTOOTHUP:
   1.441 +      case SDL_HAPTIC_SAWTOOTHDOWN:
   1.442 +         periodic = &src->periodic;
   1.443 +
   1.444 +         break;
   1.445 +
   1.446 +      case SDL_HAPTIC_SPRING:
   1.447 +      case SDL_HAPTIC_DAMPER:
   1.448 +      case SDL_HAPTIC_INERTIA:
   1.449 +      case SDL_HAPTIC_FRICTION:
   1.450 +         condition = &src->condition;
   1.451 +
   1.452 +         break;
   1.453 +
   1.454 +      case SDL_HAPTIC_RAMP:
   1.455 +         ramp = &src->ramp;
   1.456 +
   1.457 +         break;
   1.458 +
   1.459 +
   1.460 +      default:
   1.461 +         SDL_SetError("Haptic: Unknown effect type.");
   1.462 +         return -1;
   1.463 +   }
   1.464 +
   1.465 +   return 0;
   1.466 +}
   1.467 +
   1.468 +
   1.469 +/*
   1.470 + * Gets the effect type from the generic SDL haptic effect wrapper.
   1.471 + */
   1.472 +CFUUIDRef SDL_SYS_HapticEffectType(struct haptic_effect * effect)
   1.473 +{
   1.474 +   switch (effect->effect->type) {
   1.475 +      case SDL_HAPTIC_CONSTANT:
   1.476 +         return kFFEffectType_ConstantForce_ID;
   1.477 +
   1.478 +      case SDL_HAPTIC_RAMP:
   1.479 +         return kFFEffectType_RampForce_ID;
   1.480 +
   1.481 +      case SDL_HAPTIC_SQUARE:
   1.482 +         return kFFEffectType_Square_ID;
   1.483 +
   1.484 +      case SDL_HAPTIC_SINE:
   1.485 +         return kFFEffectType_Sine_ID;
   1.486 +
   1.487 +      case SDL_HAPTIC_TRIANGLE;
   1.488 +         return kFFEffectType_Triangle_ID;
   1.489 +
   1.490 +      case SDL_HAPTIC_SAWTOOTHUP:
   1.491 +         return kFFEffectType_SawtoothUp_ID;
   1.492 +
   1.493 +      case SDL_HAPTIC_SAWTOOTHDOWN:
   1.494 +         return kFFEffectType_SawtoothDown_ID;
   1.495 +
   1.496 +      case SDL_HAPTIC_SPRING:
   1.497 +         return kFFEffectType_Spring_ID;
   1.498 +
   1.499 +      case SDL_HAPTIC_DAMPER:
   1.500 +         return kFFEffectType_Damper_ID;
   1.501 +
   1.502 +      case SDL_HAPTIC_INERTIA:
   1.503 +         return kFFEffectType_Inertia_ID;
   1.504 +
   1.505 +      case SDL_HAPTIC_FRICTION:
   1.506 +         return kFFEffectType_Friction_ID;
   1.507 +
   1.508 +      case SDL_HAPTIC_CUSTOM:
   1.509 +         return kFFEffectType_CustomForce_ID;
   1.510 +
   1.511 +      default:
   1.512 +         SDL_SetError("Haptic: Unknown effect type.");
   1.513 +         return NULL;
   1.514 +   }
   1.515 +}
   1.516 +
   1.517 +
   1.518 +/*
   1.519 + * Creates a new haptic effect.
   1.520 + */
   1.521 +int
   1.522 +SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect * effect,
   1.523 +      SDL_HapticEffect * base)
   1.524 +{
   1.525 +   HRESULT ret;
   1.526 +   CFUUIDRef type;
   1.527 +
   1.528 +   /* Alloc the effect. */
   1.529 +   effect->hweffect = (struct haptic_hweffect *)
   1.530 +         SDL_malloc(sizeof(struct haptic_hweffect));
   1.531 +   if (effect->hweffect == NULL) {
   1.532 +      SDL_OutOfMemory();
   1.533 +      return -1;
   1.534 +   }
   1.535 +
   1.536 +   /* Get the type. */
   1.537 +   type = SDL_SYS_HapticEffectType(effect);
   1.538 +   if (type == NULL) {
   1.539 +      SDL_free(effect->hweffect);
   1.540 +      effect->hweffect = NULL;
   1.541 +      return -1;
   1.542 +   }
   1.543 +
   1.544 +   /* Get the effect. */
   1.545 +   if (SDL_SYS_ToFFEFFECT( &effect->hweffect->effect, &haptic_effect->effect ) < 0) {
   1.546 +      /* TODO cleanup alloced stuff. */
   1.547 +      return -1;
   1.548 +   }
   1.549 +
   1.550 +   ret = FFDeviceCreateEffect( haptic->hwdata->device, type,
   1.551 +         &effect->hweffect->effect, &effect->hweffect->ref );
   1.552 +}
   1.553 +
   1.554 +
   1.555 +/*
   1.556 + * Updates an effect.
   1.557 + */
   1.558 +int SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
   1.559 +      struct haptic_effect * effect, SDL_HapticEffect * data)
   1.560 +{
   1.561 +   /* TODO */
   1.562 +   return -1;
   1.563 +}
   1.564 +
   1.565 +
   1.566 +/*
   1.567 + * Runs an effect.
   1.568 + */
   1.569 +int
   1.570 +SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect * effect,
   1.571 +                        Uint32 iterations)
   1.572 +{
   1.573 +   HRESULT ret;
   1.574 +   Uint32 iter;
   1.575 +
   1.576 +   /* Check if it's infinite. */
   1.577 +   if (iterations == SDL_HAPTIC_INFINITY) {
   1.578 +      iter = INFINITE;
   1.579 +   }
   1.580 +   else
   1.581 +      iter = iterations;
   1.582 +
   1.583 +   /* Run the effect. */
   1.584 +   ret = FFEffectStart(effect->hweffect->ref, iter, 0);
   1.585 +   if (ret != FF_OK) {
   1.586 +      SDL_SetError("Haptic: Unable to run the effect.");
   1.587 +      return -1;
   1.588 +   }
   1.589 +
   1.590 +   return 0;
   1.591 +}
   1.592 +
   1.593 +
   1.594 +/*
   1.595 + * Stops an effect.
   1.596 + */
   1.597 +int
   1.598 +SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect * effect)
   1.599 +{
   1.600 +   HRESULT ret;
   1.601 +
   1.602 +   ret = FFEffectStop(effect->hweffect->ref);
   1.603 +   if (ret != FF_OK) {
   1.604 +      SDL_SetError("Haptic: Unable to stop the effect.");
   1.605 +      return -1;
   1.606 +   }
   1.607 +
   1.608 +   return 0;
   1.609 +}
   1.610 +
   1.611 +
   1.612 +/*
   1.613 + * Frees the effect.
   1.614 + */
   1.615 +void
   1.616 +SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect * effect)
   1.617 +{
   1.618 +   HRESULT ret;
   1.619 +
   1.620 +   ret = FFDeviceReleaseEffect(haptic->hwdata->device, effect->hweffect->ref);
   1.621 +   if (ret != FF_OK) {
   1.622 +      SDL_SetError("Haptic: Error removing the effect from the device.");
   1.623 +   }
   1.624 +   SDL_free(effect->hweffect->effect.lpvTypeSpecificParams);
   1.625 +   effect->hweffect->effect.lpvTypeSpecificParams = NULL;
   1.626 +   SDL_free(effect->hweffect);
   1.627 +   effect->hweffect = NULL;
   1.628 +}
   1.629 +
   1.630 +
   1.631 +/*
   1.632 + * Gets the status of a haptic effect.
   1.633 + */
   1.634 +int
   1.635 +SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect * effect)
   1.636 +{
   1.637 +   HRESULT ret;
   1.638 +   FFEffectStatusFlag status;
   1.639 +
   1.640 +   ret = FFEffectGetEffectStatus(effect->hweffect.ref, &status);
   1.641 +   if (ret != FF_OK) {
   1.642 +      SDL_SetError("Haptic: Unable to get effect status.");
   1.643 +      return -1;
   1.644 +   }
   1.645 +
   1.646 +   if (status == 0) return SDL_FALSE;
   1.647 +   return SDL_TRUE; /* Assume it's playing or emulated. */
   1.648 +}
   1.649 +
   1.650 +
   1.651 +/*
   1.652 + * Sets the gain.
   1.653 + */
   1.654 +int
   1.655 +SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
   1.656 +{
   1.657 +   HRESULT ret;
   1.658 +   Uint32 val;
   1.659 +
   1.660 +   val = gain * 100; /* Mac OS X uses 0 to 10,000 */
   1.661 +   ret = FFDeviceSetForceFeedbackProperty(haptic->hwdata->device, FFPROP_FFGAIN, &val);
   1.662 +   if (ret != FF_OK) {
   1.663 +      SDL_SetError("Haptic: Error setting gain.");
   1.664 +      return -1;
   1.665 +   }
   1.666 +
   1.667 +   return 0;
   1.668 +}
   1.669 +
   1.670 +
   1.671 +/*
   1.672 + * Sets the autocentering.
   1.673 + */
   1.674 +int
   1.675 +SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
   1.676 +{
   1.677 +   HRESULT ret;
   1.678 +   Uint32 val;
   1.679 +
   1.680 +   /* Mac OS X only has 0 (off) and 1 (on) */
   1.681 +   if (autocenter == 0) val = 0;
   1.682 +   else val = 1;
   1.683 +
   1.684 +   ret = FFDeviceSetForceFeedbackProperty(haptic->hwdata->device,
   1.685 +               FFPROP_FFAUTOCENTER, &val);
   1.686 +   if (ret != FF_OK) {
   1.687 +      SDL_SetError("Haptic: Error setting autocenter.");
   1.688 +      return -1;
   1.689 +   }
   1.690 +  
   1.691 +   return 0;
   1.692 +
   1.693 +}
   1.694 +
   1.695 +
   1.696 +#endif /* SDL_HAPTIC_LINUX */