SDL  2.0
SDL_syshaptic.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22 
23 #ifdef SDL_HAPTIC_IOKIT
24 
25 #include "SDL_assert.h"
26 #include "SDL_stdinc.h"
27 #include "SDL_haptic.h"
28 #include "../SDL_syshaptic.h"
29 #include "SDL_joystick.h"
30 #include "../../joystick/SDL_sysjoystick.h" /* For the real SDL_Joystick */
31 #include "../../joystick/darwin/SDL_sysjoystick_c.h" /* For joystick hwdata */
32 #include "SDL_syshaptic_c.h"
33 
34 #include <IOKit/IOKitLib.h>
35 #include <IOKit/hid/IOHIDKeys.h>
36 #include <IOKit/hid/IOHIDUsageTables.h>
37 #include <ForceFeedback/ForceFeedback.h>
38 #include <ForceFeedback/ForceFeedbackConstants.h>
39 
40 #ifndef IO_OBJECT_NULL
41 #define IO_OBJECT_NULL ((io_service_t)0)
42 #endif
43 
44 /*
45  * List of available haptic devices.
46  */
47 typedef struct SDL_hapticlist_item
48 {
49  char name[256]; /* Name of the device. */
50 
51  io_service_t dev; /* Node we use to create the device. */
52  SDL_Haptic *haptic; /* Haptic currently associated with it. */
53 
54  /* Usage pages for determining if it's a mouse or not. */
55  long usage;
56  long usagePage;
57 
58  struct SDL_hapticlist_item *next;
60 
61 
62 /*
63  * Haptic system hardware data.
64  */
65 struct haptic_hwdata
66 {
67  FFDeviceObjectReference device; /* Hardware device. */
68  UInt8 axes[3];
69 };
70 
71 
72 /*
73  * Haptic system effect data.
74  */
75 struct haptic_hweffect
76 {
77  FFEffectObjectReference ref; /* Reference. */
78  struct FFEFFECT effect; /* Hardware effect. */
79 };
80 
81 /*
82  * Prototypes.
83  */
84 static void SDL_SYS_HapticFreeFFEFFECT(FFEFFECT * effect, int type);
85 static int HIDGetDeviceProduct(io_service_t dev, char *name);
86 
88 static SDL_hapticlist_item *SDL_hapticlist_tail = NULL;
89 static int numhaptics = -1;
90 
91 /*
92  * Like strerror but for force feedback errors.
93  */
94 static const char *
95 FFStrError(unsigned int err)
96 {
97  switch (err) {
98  case FFERR_DEVICEFULL:
99  return "device full";
100  /* This should be valid, but for some reason isn't defined... */
101  /* case FFERR_DEVICENOTREG:
102  return "device not registered"; */
103  case FFERR_DEVICEPAUSED:
104  return "device paused";
105  case FFERR_DEVICERELEASED:
106  return "device released";
107  case FFERR_EFFECTPLAYING:
108  return "effect playing";
109  case FFERR_EFFECTTYPEMISMATCH:
110  return "effect type mismatch";
111  case FFERR_EFFECTTYPENOTSUPPORTED:
112  return "effect type not supported";
113  case FFERR_GENERIC:
114  return "undetermined error";
115  case FFERR_HASEFFECTS:
116  return "device has effects";
117  case FFERR_INCOMPLETEEFFECT:
118  return "incomplete effect";
119  case FFERR_INTERNAL:
120  return "internal fault";
121  case FFERR_INVALIDDOWNLOADID:
122  return "invalid download id";
123  case FFERR_INVALIDPARAM:
124  return "invalid parameter";
125  case FFERR_MOREDATA:
126  return "more data";
127  case FFERR_NOINTERFACE:
128  return "interface not supported";
129  case FFERR_NOTDOWNLOADED:
130  return "effect is not downloaded";
131  case FFERR_NOTINITIALIZED:
132  return "object has not been initialized";
133  case FFERR_OUTOFMEMORY:
134  return "out of memory";
135  case FFERR_UNPLUGGED:
136  return "device is unplugged";
137  case FFERR_UNSUPPORTED:
138  return "function call unsupported";
139  case FFERR_UNSUPPORTEDAXIS:
140  return "axis unsupported";
141 
142  default:
143  return "unknown error";
144  }
145 }
146 
147 
148 /*
149  * Initializes the haptic subsystem.
150  */
151 int
152 SDL_SYS_HapticInit(void)
153 {
154  IOReturn result;
155  io_iterator_t iter;
156  CFDictionaryRef match;
157  io_service_t device;
158 
159  if (numhaptics != -1) {
160  return SDL_SetError("Haptic subsystem already initialized!");
161  }
162  numhaptics = 0;
163 
164  /* Get HID devices. */
165  match = IOServiceMatching(kIOHIDDeviceKey);
166  if (match == NULL) {
167  return SDL_SetError("Haptic: Failed to get IOServiceMatching.");
168  }
169 
170  /* Now search I/O Registry for matching devices. */
171  result = IOServiceGetMatchingServices(kIOMasterPortDefault, match, &iter);
172  if (result != kIOReturnSuccess) {
173  return SDL_SetError("Haptic: Couldn't create a HID object iterator.");
174  }
175  /* IOServiceGetMatchingServices consumes dictionary. */
176 
177  if (!IOIteratorIsValid(iter)) { /* No iterator. */
178  return 0;
179  }
180 
181  while ((device = IOIteratorNext(iter)) != IO_OBJECT_NULL) {
183  /* always release as the AddDevice will retain IF it's a forcefeedback device */
184  IOObjectRelease(device);
185  }
186  IOObjectRelease(iter);
187 
188  return numhaptics;
189 }
190 
191 int
192 SDL_SYS_NumHaptics(void)
193 {
194  return numhaptics;
195 }
196 
197 static SDL_hapticlist_item *
198 HapticByDevIndex(int device_index)
199 {
201 
202  if ((device_index < 0) || (device_index >= numhaptics)) {
203  return NULL;
204  }
205 
206  while (device_index > 0) {
207  SDL_assert(item != NULL);
208  --device_index;
209  item = item->next;
210  }
211 
212  return item;
213 }
214 
215 int
216 MacHaptic_MaybeAddDevice( io_object_t device )
217 {
218  IOReturn result;
219  CFMutableDictionaryRef hidProperties;
220  CFTypeRef refCF;
221  SDL_hapticlist_item *item;
222 
223  if (numhaptics == -1) {
224  return -1; /* not initialized. We'll pick these up on enumeration if we init later. */
225  }
226 
227  /* Check for force feedback. */
228  if (FFIsForceFeedback(device) != FF_OK) {
229  return -1;
230  }
231 
232  /* Make sure we don't already have it */
233  for (item = SDL_hapticlist; item ; item = item->next)
234  {
235  if (IOObjectIsEqualTo((io_object_t) item->dev, device)) {
236  /* Already added */
237  return -1;
238  }
239  }
240 
241  item = (SDL_hapticlist_item *)SDL_calloc(1, sizeof(SDL_hapticlist_item));
242  if (item == NULL) {
243  return SDL_SetError("Could not allocate haptic storage");
244  }
245 
246  /* retain it as we are going to keep it around a while */
247  IOObjectRetain(device);
248 
249  /* Set basic device data. */
250  HIDGetDeviceProduct(device, item->name);
251  item->dev = device;
252 
253  /* Set usage pages. */
254  hidProperties = 0;
255  refCF = 0;
256  result = IORegistryEntryCreateCFProperties(device,
257  &hidProperties,
258  kCFAllocatorDefault,
259  kNilOptions);
260  if ((result == KERN_SUCCESS) && hidProperties) {
261  refCF = CFDictionaryGetValue(hidProperties,
262  CFSTR(kIOHIDPrimaryUsagePageKey));
263  if (refCF) {
264  if (!CFNumberGetValue(refCF, kCFNumberLongType, &item->usagePage)) {
265  SDL_SetError("Haptic: Receiving device's usage page.");
266  }
267  refCF = CFDictionaryGetValue(hidProperties,
268  CFSTR(kIOHIDPrimaryUsageKey));
269  if (refCF) {
270  if (!CFNumberGetValue(refCF, kCFNumberLongType, &item->usage)) {
271  SDL_SetError("Haptic: Receiving device's usage.");
272  }
273  }
274  }
275  CFRelease(hidProperties);
276  }
277 
278  if (SDL_hapticlist_tail == NULL) {
279  SDL_hapticlist = SDL_hapticlist_tail = item;
280  } else {
281  SDL_hapticlist_tail->next = item;
282  SDL_hapticlist_tail = item;
283  }
284 
285  /* Device has been added. */
286  ++numhaptics;
287 
288  return numhaptics;
289 }
290 
291 int
292 MacHaptic_MaybeRemoveDevice( io_object_t device )
293 {
294  SDL_hapticlist_item *item;
295  SDL_hapticlist_item *prev = NULL;
296 
297  if (numhaptics == -1) {
298  return -1; /* not initialized. ignore this. */
299  }
300 
301  for (item = SDL_hapticlist; item != NULL; item = item->next) {
302  /* found it, remove it. */
303  if (IOObjectIsEqualTo((io_object_t) item->dev, device)) {
304  const int retval = item->haptic ? item->haptic->index : -1;
305 
306  if (prev != NULL) {
307  prev->next = item->next;
308  } else {
309  SDL_assert(SDL_hapticlist == item);
310  SDL_hapticlist = item->next;
311  }
312  if (item == SDL_hapticlist_tail) {
313  SDL_hapticlist_tail = prev;
314  }
315 
316  /* Need to decrement the haptic count */
317  --numhaptics;
318  /* !!! TODO: Send a haptic remove event? */
319 
320  IOObjectRelease(item->dev);
321  SDL_free(item);
322  return retval;
323  }
324  prev = item;
325  }
326 
327  return -1;
328 }
329 
330 /*
331  * Return the name of a haptic device, does not need to be opened.
332  */
333 const char *
335 {
336  SDL_hapticlist_item *item;
337  item = HapticByDevIndex(index);
338  return item->name;
339 }
340 
341 /*
342  * Gets the device's product name.
343  */
344 static int
345 HIDGetDeviceProduct(io_service_t dev, char *name)
346 {
347  CFMutableDictionaryRef hidProperties, usbProperties;
348  io_registry_entry_t parent1, parent2;
349  kern_return_t ret;
350 
351  hidProperties = usbProperties = 0;
352 
353  ret = IORegistryEntryCreateCFProperties(dev, &hidProperties,
354  kCFAllocatorDefault, kNilOptions);
355  if ((ret != KERN_SUCCESS) || !hidProperties) {
356  return SDL_SetError("Haptic: Unable to create CFProperties.");
357  }
358 
359  /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
360  * get dictionary for USB properties: step up two levels and get CF dictionary for USB properties
361  */
362  if ((KERN_SUCCESS ==
363  IORegistryEntryGetParentEntry(dev, kIOServicePlane, &parent1))
364  && (KERN_SUCCESS ==
365  IORegistryEntryGetParentEntry(parent1, kIOServicePlane, &parent2))
366  && (KERN_SUCCESS ==
367  IORegistryEntryCreateCFProperties(parent2, &usbProperties,
368  kCFAllocatorDefault,
369  kNilOptions))) {
370  if (usbProperties) {
371  CFTypeRef refCF = 0;
372  /* get device info
373  * try hid dictionary first, if fail then go to USB dictionary
374  */
375 
376 
377  /* Get product name */
378  refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDProductKey));
379  if (!refCF) {
380  refCF = CFDictionaryGetValue(usbProperties,
381  CFSTR("USB Product Name"));
382  }
383  if (refCF) {
384  if (!CFStringGetCString(refCF, name, 256,
385  CFStringGetSystemEncoding())) {
386  return SDL_SetError("Haptic: CFStringGetCString error retrieving pDevice->product.");
387  }
388  }
389 
390  CFRelease(usbProperties);
391  } else {
392  return SDL_SetError("Haptic: IORegistryEntryCreateCFProperties failed to create usbProperties.");
393  }
394 
395  /* Release stuff. */
396  if (kIOReturnSuccess != IOObjectRelease(parent2)) {
397  SDL_SetError("Haptic: IOObjectRelease error with parent2.");
398  }
399  if (kIOReturnSuccess != IOObjectRelease(parent1)) {
400  SDL_SetError("Haptic: IOObjectRelease error with parent1.");
401  }
402  } else {
403  return SDL_SetError("Haptic: Error getting registry entries.");
404  }
405 
406  return 0;
407 }
408 
409 
410 #define FF_TEST(ff, s) \
411 if (features.supportedEffects & (ff)) supported |= (s)
412 /*
413  * Gets supported features.
414  */
415 static unsigned int
416 GetSupportedFeatures(SDL_Haptic * haptic)
417 {
418  HRESULT ret;
419  FFDeviceObjectReference device;
420  FFCAPABILITIES features;
421  unsigned int supported;
422  Uint32 val;
423 
424  device = haptic->hwdata->device;
425 
426  ret = FFDeviceGetForceFeedbackCapabilities(device, &features);
427  if (ret != FF_OK) {
428  return SDL_SetError("Haptic: Unable to get device's supported features.");
429  }
430 
431  supported = 0;
432 
433  /* Get maximum effects. */
434  haptic->neffects = features.storageCapacity;
435  haptic->nplaying = features.playbackCapacity;
436 
437  /* Test for effects. */
438  FF_TEST(FFCAP_ET_CONSTANTFORCE, SDL_HAPTIC_CONSTANT);
439  FF_TEST(FFCAP_ET_RAMPFORCE, SDL_HAPTIC_RAMP);
440  /* !!! FIXME: put this back when we have more bits in 2.1 */
441  /* FF_TEST(FFCAP_ET_SQUARE, SDL_HAPTIC_SQUARE); */
442  FF_TEST(FFCAP_ET_SINE, SDL_HAPTIC_SINE);
443  FF_TEST(FFCAP_ET_TRIANGLE, SDL_HAPTIC_TRIANGLE);
444  FF_TEST(FFCAP_ET_SAWTOOTHUP, SDL_HAPTIC_SAWTOOTHUP);
445  FF_TEST(FFCAP_ET_SAWTOOTHDOWN, SDL_HAPTIC_SAWTOOTHDOWN);
446  FF_TEST(FFCAP_ET_SPRING, SDL_HAPTIC_SPRING);
447  FF_TEST(FFCAP_ET_DAMPER, SDL_HAPTIC_DAMPER);
448  FF_TEST(FFCAP_ET_INERTIA, SDL_HAPTIC_INERTIA);
449  FF_TEST(FFCAP_ET_FRICTION, SDL_HAPTIC_FRICTION);
450  FF_TEST(FFCAP_ET_CUSTOMFORCE, SDL_HAPTIC_CUSTOM);
451 
452  /* Check if supports gain. */
453  ret = FFDeviceGetForceFeedbackProperty(device, FFPROP_FFGAIN,
454  &val, sizeof(val));
455  if (ret == FF_OK) {
456  supported |= SDL_HAPTIC_GAIN;
457  } else if (ret != FFERR_UNSUPPORTED) {
458  return SDL_SetError("Haptic: Unable to get if device supports gain: %s.",
459  FFStrError(ret));
460  }
461 
462  /* Checks if supports autocenter. */
463  ret = FFDeviceGetForceFeedbackProperty(device, FFPROP_AUTOCENTER,
464  &val, sizeof(val));
465  if (ret == FF_OK) {
466  supported |= SDL_HAPTIC_AUTOCENTER;
467  } else if (ret != FFERR_UNSUPPORTED) {
468  return SDL_SetError
469  ("Haptic: Unable to get if device supports autocenter: %s.",
470  FFStrError(ret));
471  }
472 
473  /* Check for axes, we have an artificial limit on axes */
474  haptic->naxes = ((features.numFfAxes) > 3) ? 3 : features.numFfAxes;
475  /* Actually store the axes we want to use */
476  SDL_memcpy(haptic->hwdata->axes, features.ffAxes,
477  haptic->naxes * sizeof(Uint8));
478 
479  /* Always supported features. */
480  supported |= SDL_HAPTIC_STATUS | SDL_HAPTIC_PAUSE;
481 
482  haptic->supported = supported;
483  return 0;
484 }
485 
486 
487 /*
488  * Opens the haptic device from the file descriptor.
489  */
490 static int
491 SDL_SYS_HapticOpenFromService(SDL_Haptic * haptic, io_service_t service)
492 {
493  HRESULT ret;
494  int ret2;
495 
496  /* Allocate the hwdata */
497  haptic->hwdata = (struct haptic_hwdata *)
498  SDL_malloc(sizeof(*haptic->hwdata));
499  if (haptic->hwdata == NULL) {
500  SDL_OutOfMemory();
501  goto creat_err;
502  }
503  SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
504 
505  /* Open the device */
506  ret = FFCreateDevice(service, &haptic->hwdata->device);
507  if (ret != FF_OK) {
508  SDL_SetError("Haptic: Unable to create device from service: %s.",
509  FFStrError(ret));
510  goto creat_err;
511  }
512 
513  /* Get supported features. */
514  ret2 = GetSupportedFeatures(haptic);
515  if (ret2 < 0) {
516  goto open_err;
517  }
518 
519 
520  /* Reset and then enable actuators. */
521  ret = FFDeviceSendForceFeedbackCommand(haptic->hwdata->device,
522  FFSFFC_RESET);
523  if (ret != FF_OK) {
524  SDL_SetError("Haptic: Unable to reset device: %s.", FFStrError(ret));
525  goto open_err;
526  }
527  ret = FFDeviceSendForceFeedbackCommand(haptic->hwdata->device,
528  FFSFFC_SETACTUATORSON);
529  if (ret != FF_OK) {
530  SDL_SetError("Haptic: Unable to enable actuators: %s.",
531  FFStrError(ret));
532  goto open_err;
533  }
534 
535 
536  /* Allocate effects memory. */
537  haptic->effects = (struct haptic_effect *)
538  SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
539  if (haptic->effects == NULL) {
540  SDL_OutOfMemory();
541  goto open_err;
542  }
543  /* Clear the memory */
544  SDL_memset(haptic->effects, 0,
545  sizeof(struct haptic_effect) * haptic->neffects);
546 
547  return 0;
548 
549  /* Error handling */
550  open_err:
551  FFReleaseDevice(haptic->hwdata->device);
552  creat_err:
553  if (haptic->hwdata != NULL) {
554  SDL_free(haptic->hwdata);
555  haptic->hwdata = NULL;
556  }
557  return -1;
558 
559 }
560 
561 
562 /*
563  * Opens a haptic device for usage.
564  */
565 int
566 SDL_SYS_HapticOpen(SDL_Haptic * haptic)
567 {
568  SDL_hapticlist_item *item;
569  item = HapticByDevIndex(haptic->index);
570 
571  return SDL_SYS_HapticOpenFromService(haptic, item->dev);
572 }
573 
574 
575 /*
576  * Opens a haptic device from first mouse it finds for usage.
577  */
578 int
580 {
581  int device_index = 0;
582  SDL_hapticlist_item *item;
583 
584  for (item = SDL_hapticlist; item; item = item->next) {
585  if ((item->usagePage == kHIDPage_GenericDesktop) &&
586  (item->usage == kHIDUsage_GD_Mouse)) {
587  return device_index;
588  }
589  ++device_index;
590  }
591 
592  return -1;
593 }
594 
595 
596 /*
597  * Checks to see if a joystick has haptic features.
598  */
599 int
600 SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
601 {
602  if (joystick->driver != &SDL_DARWIN_JoystickDriver) {
603  return SDL_FALSE;
604  }
605  if (joystick->hwdata->ffservice != 0) {
606  return SDL_TRUE;
607  }
608  return SDL_FALSE;
609 }
610 
611 
612 /*
613  * Checks to see if the haptic device and joystick are in reality the same.
614  */
615 int
616 SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
617 {
618  if (joystick->driver != &SDL_DARWIN_JoystickDriver) {
619  return 0;
620  }
621  if (IOObjectIsEqualTo((io_object_t) ((size_t)haptic->hwdata->device),
622  joystick->hwdata->ffservice)) {
623  return 1;
624  }
625  return 0;
626 }
627 
628 
629 /*
630  * Opens a SDL_Haptic from a SDL_Joystick.
631  */
632 int
633 SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
634 {
635  int device_index = 0;
636  SDL_hapticlist_item *item;
637 
638  if (joystick->driver != &SDL_DARWIN_JoystickDriver) {
639  return -1;
640  }
641  for (item = SDL_hapticlist; item; item = item->next) {
642  if (IOObjectIsEqualTo((io_object_t) item->dev,
643  joystick->hwdata->ffservice)) {
644  haptic->index = device_index;
645  break;
646  }
647  ++device_index;
648  }
649 
650  return SDL_SYS_HapticOpenFromService(haptic, joystick->hwdata->ffservice);
651 }
652 
653 
654 /*
655  * Closes the haptic device.
656  */
657 void
658 SDL_SYS_HapticClose(SDL_Haptic * haptic)
659 {
660  if (haptic->hwdata) {
661 
662  /* Free Effects. */
663  SDL_free(haptic->effects);
664  haptic->effects = NULL;
665  haptic->neffects = 0;
666 
667  /* Clean up */
668  FFReleaseDevice(haptic->hwdata->device);
669 
670  /* Free */
671  SDL_free(haptic->hwdata);
672  haptic->hwdata = NULL;
673  }
674 }
675 
676 
677 /*
678  * Clean up after system specific haptic stuff
679  */
680 void
681 SDL_SYS_HapticQuit(void)
682 {
683  SDL_hapticlist_item *item;
684  SDL_hapticlist_item *next = NULL;
685 
686  for (item = SDL_hapticlist; item; item = next) {
687  next = item->next;
688  /* Opened and not closed haptics are leaked, this is on purpose.
689  * Close your haptic devices after usage. */
690 
691  /* Free the io_service_t */
692  IOObjectRelease(item->dev);
693  SDL_free(item);
694  }
695 
696  numhaptics = -1;
698  SDL_hapticlist_tail = NULL;
699 }
700 
701 
702 /*
703  * Converts an SDL trigger button to an FFEFFECT trigger button.
704  */
705 static DWORD
706 FFGetTriggerButton(Uint16 button)
707 {
708  DWORD dwTriggerButton;
709 
710  dwTriggerButton = FFEB_NOTRIGGER;
711 
712  if (button != 0) {
713  dwTriggerButton = FFJOFS_BUTTON(button - 1);
714  }
715 
716  return dwTriggerButton;
717 }
718 
719 
720 /*
721  * Sets the direction.
722  */
723 static int
724 SDL_SYS_SetDirection(FFEFFECT * effect, SDL_HapticDirection * dir, int naxes)
725 {
726  LONG *rglDir;
727 
728  /* Handle no axes a part. */
729  if (naxes == 0) {
730  effect->dwFlags |= FFEFF_SPHERICAL; /* Set as default. */
731  effect->rglDirection = NULL;
732  return 0;
733  }
734 
735  /* Has axes. */
736  rglDir = SDL_malloc(sizeof(LONG) * naxes);
737  if (rglDir == NULL) {
738  return SDL_OutOfMemory();
739  }
740  SDL_memset(rglDir, 0, sizeof(LONG) * naxes);
741  effect->rglDirection = rglDir;
742 
743  switch (dir->type) {
744  case SDL_HAPTIC_POLAR:
745  effect->dwFlags |= FFEFF_POLAR;
746  rglDir[0] = dir->dir[0];
747  return 0;
749  effect->dwFlags |= FFEFF_CARTESIAN;
750  rglDir[0] = dir->dir[0];
751  if (naxes > 1) {
752  rglDir[1] = dir->dir[1];
753  }
754  if (naxes > 2) {
755  rglDir[2] = dir->dir[2];
756  }
757  return 0;
759  effect->dwFlags |= FFEFF_SPHERICAL;
760  rglDir[0] = dir->dir[0];
761  if (naxes > 1) {
762  rglDir[1] = dir->dir[1];
763  }
764  if (naxes > 2) {
765  rglDir[2] = dir->dir[2];
766  }
767  return 0;
768 
769  default:
770  return SDL_SetError("Haptic: Unknown direction type.");
771  }
772 }
773 
774 
775 /* Clamps and converts. */
776 #define CCONVERT(x) (((x) > 0x7FFF) ? 10000 : ((x)*10000) / 0x7FFF)
777 /* Just converts. */
778 #define CONVERT(x) (((x)*10000) / 0x7FFF)
779 /*
780  * Creates the FFEFFECT from a SDL_HapticEffect.
781  */
782 static int
783 SDL_SYS_ToFFEFFECT(SDL_Haptic * haptic, FFEFFECT * dest, SDL_HapticEffect * src)
784 {
785  int i;
786  FFCONSTANTFORCE *constant = NULL;
787  FFPERIODIC *periodic = NULL;
788  FFCONDITION *condition = NULL; /* Actually an array of conditions - one per axis. */
789  FFRAMPFORCE *ramp = NULL;
790  FFCUSTOMFORCE *custom = NULL;
791  FFENVELOPE *envelope = NULL;
792  SDL_HapticConstant *hap_constant = NULL;
793  SDL_HapticPeriodic *hap_periodic = NULL;
794  SDL_HapticCondition *hap_condition = NULL;
795  SDL_HapticRamp *hap_ramp = NULL;
796  SDL_HapticCustom *hap_custom = NULL;
797  DWORD *axes = NULL;
798 
799  /* Set global stuff. */
800  SDL_memset(dest, 0, sizeof(FFEFFECT));
801  dest->dwSize = sizeof(FFEFFECT); /* Set the structure size. */
802  dest->dwSamplePeriod = 0; /* Not used by us. */
803  dest->dwGain = 10000; /* Gain is set globally, not locally. */
804  dest->dwFlags = FFEFF_OBJECTOFFSETS; /* Seems obligatory. */
805 
806  /* Envelope. */
807  envelope = SDL_malloc(sizeof(FFENVELOPE));
808  if (envelope == NULL) {
809  return SDL_OutOfMemory();
810  }
811  SDL_memset(envelope, 0, sizeof(FFENVELOPE));
812  dest->lpEnvelope = envelope;
813  envelope->dwSize = sizeof(FFENVELOPE); /* Always should be this. */
814 
815  /* Axes. */
816  dest->cAxes = haptic->naxes;
817  if (dest->cAxes > 0) {
818  axes = SDL_malloc(sizeof(DWORD) * dest->cAxes);
819  if (axes == NULL) {
820  return SDL_OutOfMemory();
821  }
822  axes[0] = haptic->hwdata->axes[0]; /* Always at least one axis. */
823  if (dest->cAxes > 1) {
824  axes[1] = haptic->hwdata->axes[1];
825  }
826  if (dest->cAxes > 2) {
827  axes[2] = haptic->hwdata->axes[2];
828  }
829  dest->rgdwAxes = axes;
830  }
831 
832 
833  /* The big type handling switch, even bigger then Linux's version. */
834  switch (src->type) {
835  case SDL_HAPTIC_CONSTANT:
836  hap_constant = &src->constant;
837  constant = SDL_malloc(sizeof(FFCONSTANTFORCE));
838  if (constant == NULL) {
839  return SDL_OutOfMemory();
840  }
841  SDL_memset(constant, 0, sizeof(FFCONSTANTFORCE));
842 
843  /* Specifics */
844  constant->lMagnitude = CONVERT(hap_constant->level);
845  dest->cbTypeSpecificParams = sizeof(FFCONSTANTFORCE);
846  dest->lpvTypeSpecificParams = constant;
847 
848  /* Generics */
849  dest->dwDuration = hap_constant->length * 1000; /* In microseconds. */
850  dest->dwTriggerButton = FFGetTriggerButton(hap_constant->button);
851  dest->dwTriggerRepeatInterval = hap_constant->interval;
852  dest->dwStartDelay = hap_constant->delay * 1000; /* In microseconds. */
853 
854  /* Direction. */
855  if (SDL_SYS_SetDirection(dest, &hap_constant->direction, dest->cAxes)
856  < 0) {
857  return -1;
858  }
859 
860  /* Envelope */
861  if ((hap_constant->attack_length == 0)
862  && (hap_constant->fade_length == 0)) {
863  SDL_free(envelope);
864  dest->lpEnvelope = NULL;
865  } else {
866  envelope->dwAttackLevel = CCONVERT(hap_constant->attack_level);
867  envelope->dwAttackTime = hap_constant->attack_length * 1000;
868  envelope->dwFadeLevel = CCONVERT(hap_constant->fade_level);
869  envelope->dwFadeTime = hap_constant->fade_length * 1000;
870  }
871 
872  break;
873 
874  case SDL_HAPTIC_SINE:
875  /* !!! FIXME: put this back when we have more bits in 2.1 */
876  /* case SDL_HAPTIC_SQUARE: */
877  case SDL_HAPTIC_TRIANGLE:
880  hap_periodic = &src->periodic;
881  periodic = SDL_malloc(sizeof(FFPERIODIC));
882  if (periodic == NULL) {
883  return SDL_OutOfMemory();
884  }
885  SDL_memset(periodic, 0, sizeof(FFPERIODIC));
886 
887  /* Specifics */
888  periodic->dwMagnitude = CONVERT(SDL_abs(hap_periodic->magnitude));
889  periodic->lOffset = CONVERT(hap_periodic->offset);
890  periodic->dwPhase =
891  (hap_periodic->phase + (hap_periodic->magnitude < 0 ? 18000 : 0)) % 36000;
892  periodic->dwPeriod = hap_periodic->period * 1000;
893  dest->cbTypeSpecificParams = sizeof(FFPERIODIC);
894  dest->lpvTypeSpecificParams = periodic;
895 
896  /* Generics */
897  dest->dwDuration = hap_periodic->length * 1000; /* In microseconds. */
898  dest->dwTriggerButton = FFGetTriggerButton(hap_periodic->button);
899  dest->dwTriggerRepeatInterval = hap_periodic->interval;
900  dest->dwStartDelay = hap_periodic->delay * 1000; /* In microseconds. */
901 
902  /* Direction. */
903  if (SDL_SYS_SetDirection(dest, &hap_periodic->direction, dest->cAxes)
904  < 0) {
905  return -1;
906  }
907 
908  /* Envelope */
909  if ((hap_periodic->attack_length == 0)
910  && (hap_periodic->fade_length == 0)) {
911  SDL_free(envelope);
912  dest->lpEnvelope = NULL;
913  } else {
914  envelope->dwAttackLevel = CCONVERT(hap_periodic->attack_level);
915  envelope->dwAttackTime = hap_periodic->attack_length * 1000;
916  envelope->dwFadeLevel = CCONVERT(hap_periodic->fade_level);
917  envelope->dwFadeTime = hap_periodic->fade_length * 1000;
918  }
919 
920  break;
921 
922  case SDL_HAPTIC_SPRING:
923  case SDL_HAPTIC_DAMPER:
924  case SDL_HAPTIC_INERTIA:
925  case SDL_HAPTIC_FRICTION:
926  hap_condition = &src->condition;
927  if (dest->cAxes > 0) {
928  condition = SDL_malloc(sizeof(FFCONDITION) * dest->cAxes);
929  if (condition == NULL) {
930  return SDL_OutOfMemory();
931  }
932  SDL_memset(condition, 0, sizeof(FFCONDITION));
933 
934  /* Specifics */
935  for (i = 0; i < dest->cAxes; i++) {
936  condition[i].lOffset = CONVERT(hap_condition->center[i]);
937  condition[i].lPositiveCoefficient =
938  CONVERT(hap_condition->right_coeff[i]);
939  condition[i].lNegativeCoefficient =
940  CONVERT(hap_condition->left_coeff[i]);
941  condition[i].dwPositiveSaturation =
942  CCONVERT(hap_condition->right_sat[i] / 2);
943  condition[i].dwNegativeSaturation =
944  CCONVERT(hap_condition->left_sat[i] / 2);
945  condition[i].lDeadBand = CCONVERT(hap_condition->deadband[i] / 2);
946  }
947  }
948 
949  dest->cbTypeSpecificParams = sizeof(FFCONDITION) * dest->cAxes;
950  dest->lpvTypeSpecificParams = condition;
951 
952  /* Generics */
953  dest->dwDuration = hap_condition->length * 1000; /* In microseconds. */
954  dest->dwTriggerButton = FFGetTriggerButton(hap_condition->button);
955  dest->dwTriggerRepeatInterval = hap_condition->interval;
956  dest->dwStartDelay = hap_condition->delay * 1000; /* In microseconds. */
957 
958  /* Direction. */
959  if (SDL_SYS_SetDirection(dest, &hap_condition->direction, dest->cAxes)
960  < 0) {
961  return -1;
962  }
963 
964  /* Envelope - Not actually supported by most CONDITION implementations. */
965  SDL_free(dest->lpEnvelope);
966  dest->lpEnvelope = NULL;
967 
968  break;
969 
970  case SDL_HAPTIC_RAMP:
971  hap_ramp = &src->ramp;
972  ramp = SDL_malloc(sizeof(FFRAMPFORCE));
973  if (ramp == NULL) {
974  return SDL_OutOfMemory();
975  }
976  SDL_memset(ramp, 0, sizeof(FFRAMPFORCE));
977 
978  /* Specifics */
979  ramp->lStart = CONVERT(hap_ramp->start);
980  ramp->lEnd = CONVERT(hap_ramp->end);
981  dest->cbTypeSpecificParams = sizeof(FFRAMPFORCE);
982  dest->lpvTypeSpecificParams = ramp;
983 
984  /* Generics */
985  dest->dwDuration = hap_ramp->length * 1000; /* In microseconds. */
986  dest->dwTriggerButton = FFGetTriggerButton(hap_ramp->button);
987  dest->dwTriggerRepeatInterval = hap_ramp->interval;
988  dest->dwStartDelay = hap_ramp->delay * 1000; /* In microseconds. */
989 
990  /* Direction. */
991  if (SDL_SYS_SetDirection(dest, &hap_ramp->direction, dest->cAxes) < 0) {
992  return -1;
993  }
994 
995  /* Envelope */
996  if ((hap_ramp->attack_length == 0) && (hap_ramp->fade_length == 0)) {
997  SDL_free(envelope);
998  dest->lpEnvelope = NULL;
999  } else {
1000  envelope->dwAttackLevel = CCONVERT(hap_ramp->attack_level);
1001  envelope->dwAttackTime = hap_ramp->attack_length * 1000;
1002  envelope->dwFadeLevel = CCONVERT(hap_ramp->fade_level);
1003  envelope->dwFadeTime = hap_ramp->fade_length * 1000;
1004  }
1005 
1006  break;
1007 
1008  case SDL_HAPTIC_CUSTOM:
1009  hap_custom = &src->custom;
1010  custom = SDL_malloc(sizeof(FFCUSTOMFORCE));
1011  if (custom == NULL) {
1012  return SDL_OutOfMemory();
1013  }
1014  SDL_memset(custom, 0, sizeof(FFCUSTOMFORCE));
1015 
1016  /* Specifics */
1017  custom->cChannels = hap_custom->channels;
1018  custom->dwSamplePeriod = hap_custom->period * 1000;
1019  custom->cSamples = hap_custom->samples;
1020  custom->rglForceData =
1021  SDL_malloc(sizeof(LONG) * custom->cSamples * custom->cChannels);
1022  for (i = 0; i < hap_custom->samples * hap_custom->channels; i++) { /* Copy data. */
1023  custom->rglForceData[i] = CCONVERT(hap_custom->data[i]);
1024  }
1025  dest->cbTypeSpecificParams = sizeof(FFCUSTOMFORCE);
1026  dest->lpvTypeSpecificParams = custom;
1027 
1028  /* Generics */
1029  dest->dwDuration = hap_custom->length * 1000; /* In microseconds. */
1030  dest->dwTriggerButton = FFGetTriggerButton(hap_custom->button);
1031  dest->dwTriggerRepeatInterval = hap_custom->interval;
1032  dest->dwStartDelay = hap_custom->delay * 1000; /* In microseconds. */
1033 
1034  /* Direction. */
1035  if (SDL_SYS_SetDirection(dest, &hap_custom->direction, dest->cAxes) <
1036  0) {
1037  return -1;
1038  }
1039 
1040  /* Envelope */
1041  if ((hap_custom->attack_length == 0)
1042  && (hap_custom->fade_length == 0)) {
1043  SDL_free(envelope);
1044  dest->lpEnvelope = NULL;
1045  } else {
1046  envelope->dwAttackLevel = CCONVERT(hap_custom->attack_level);
1047  envelope->dwAttackTime = hap_custom->attack_length * 1000;
1048  envelope->dwFadeLevel = CCONVERT(hap_custom->fade_level);
1049  envelope->dwFadeTime = hap_custom->fade_length * 1000;
1050  }
1051 
1052  break;
1053 
1054 
1055  default:
1056  return SDL_SetError("Haptic: Unknown effect type.");
1057  }
1058 
1059  return 0;
1060 }
1061 
1062 
1063 /*
1064  * Frees an FFEFFECT allocated by SDL_SYS_ToFFEFFECT.
1065  */
1066 static void
1067 SDL_SYS_HapticFreeFFEFFECT(FFEFFECT * effect, int type)
1068 {
1069  FFCUSTOMFORCE *custom;
1070 
1071  SDL_free(effect->lpEnvelope);
1072  effect->lpEnvelope = NULL;
1073  SDL_free(effect->rgdwAxes);
1074  effect->rgdwAxes = NULL;
1075  if (effect->lpvTypeSpecificParams != NULL) {
1076  if (type == SDL_HAPTIC_CUSTOM) { /* Must free the custom data. */
1077  custom = (FFCUSTOMFORCE *) effect->lpvTypeSpecificParams;
1078  SDL_free(custom->rglForceData);
1079  custom->rglForceData = NULL;
1080  }
1081  SDL_free(effect->lpvTypeSpecificParams);
1082  effect->lpvTypeSpecificParams = NULL;
1083  }
1084  SDL_free(effect->rglDirection);
1085  effect->rglDirection = NULL;
1086 }
1087 
1088 
1089 /*
1090  * Gets the effect type from the generic SDL haptic effect wrapper.
1091  */
1092 CFUUIDRef
1093 SDL_SYS_HapticEffectType(Uint16 type)
1094 {
1095  switch (type) {
1096  case SDL_HAPTIC_CONSTANT:
1097  return kFFEffectType_ConstantForce_ID;
1098 
1099  case SDL_HAPTIC_RAMP:
1100  return kFFEffectType_RampForce_ID;
1101 
1102  /* !!! FIXME: put this back when we have more bits in 2.1 */
1103  /* case SDL_HAPTIC_SQUARE:
1104  return kFFEffectType_Square_ID; */
1105 
1106  case SDL_HAPTIC_SINE:
1107  return kFFEffectType_Sine_ID;
1108 
1109  case SDL_HAPTIC_TRIANGLE:
1110  return kFFEffectType_Triangle_ID;
1111 
1112  case SDL_HAPTIC_SAWTOOTHUP:
1113  return kFFEffectType_SawtoothUp_ID;
1114 
1116  return kFFEffectType_SawtoothDown_ID;
1117 
1118  case SDL_HAPTIC_SPRING:
1119  return kFFEffectType_Spring_ID;
1120 
1121  case SDL_HAPTIC_DAMPER:
1122  return kFFEffectType_Damper_ID;
1123 
1124  case SDL_HAPTIC_INERTIA:
1125  return kFFEffectType_Inertia_ID;
1126 
1127  case SDL_HAPTIC_FRICTION:
1128  return kFFEffectType_Friction_ID;
1129 
1130  case SDL_HAPTIC_CUSTOM:
1131  return kFFEffectType_CustomForce_ID;
1132 
1133  default:
1134  SDL_SetError("Haptic: Unknown effect type.");
1135  return NULL;
1136  }
1137 }
1138 
1139 
1140 /*
1141  * Creates a new haptic effect.
1142  */
1143 int
1144 SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
1146 {
1147  HRESULT ret;
1148  CFUUIDRef type;
1149 
1150  /* Alloc the effect. */
1151  effect->hweffect = (struct haptic_hweffect *)
1152  SDL_malloc(sizeof(struct haptic_hweffect));
1153  if (effect->hweffect == NULL) {
1154  SDL_OutOfMemory();
1155  goto err_hweffect;
1156  }
1157 
1158  /* Get the type. */
1159  type = SDL_SYS_HapticEffectType(base->type);
1160  if (type == NULL) {
1161  goto err_hweffect;
1162  }
1163 
1164  /* Get the effect. */
1165  if (SDL_SYS_ToFFEFFECT(haptic, &effect->hweffect->effect, base) < 0) {
1166  goto err_effectdone;
1167  }
1168 
1169  /* Create the actual effect. */
1170  ret = FFDeviceCreateEffect(haptic->hwdata->device, type,
1171  &effect->hweffect->effect,
1172  &effect->hweffect->ref);
1173  if (ret != FF_OK) {
1174  SDL_SetError("Haptic: Unable to create effect: %s.", FFStrError(ret));
1175  goto err_effectdone;
1176  }
1177 
1178  return 0;
1179 
1180  err_effectdone:
1181  SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect, base->type);
1182  err_hweffect:
1183  SDL_free(effect->hweffect);
1184  effect->hweffect = NULL;
1185  return -1;
1186 }
1187 
1188 
1189 /*
1190  * Updates an effect.
1191  */
1192 int
1193 SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
1194  struct haptic_effect *effect,
1196 {
1197  HRESULT ret;
1198  FFEffectParameterFlag flags;
1199  FFEFFECT temp;
1200 
1201  /* Get the effect. */
1202  SDL_memset(&temp, 0, sizeof(FFEFFECT));
1203  if (SDL_SYS_ToFFEFFECT(haptic, &temp, data) < 0) {
1204  goto err_update;
1205  }
1206 
1207  /* Set the flags. Might be worthwhile to diff temp with loaded effect and
1208  * only change those parameters. */
1209  flags = FFEP_DIRECTION |
1210  FFEP_DURATION |
1211  FFEP_ENVELOPE |
1212  FFEP_STARTDELAY |
1213  FFEP_TRIGGERBUTTON |
1214  FFEP_TRIGGERREPEATINTERVAL | FFEP_TYPESPECIFICPARAMS;
1215 
1216  /* Create the actual effect. */
1217  ret = FFEffectSetParameters(effect->hweffect->ref, &temp, flags);
1218  if (ret != FF_OK) {
1219  SDL_SetError("Haptic: Unable to update effect: %s.", FFStrError(ret));
1220  goto err_update;
1221  }
1222 
1223  /* Copy it over. */
1224  SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect, data->type);
1225  SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(FFEFFECT));
1226 
1227  return 0;
1228 
1229  err_update:
1230  SDL_SYS_HapticFreeFFEFFECT(&temp, data->type);
1231  return -1;
1232 }
1233 
1234 
1235 /*
1236  * Runs an effect.
1237  */
1238 int
1239 SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
1241 {
1242  HRESULT ret;
1243  Uint32 iter;
1244 
1245  /* Check if it's infinite. */
1247  iter = FF_INFINITE;
1248  } else
1249  iter = iterations;
1250 
1251  /* Run the effect. */
1252  ret = FFEffectStart(effect->hweffect->ref, iter, 0);
1253  if (ret != FF_OK) {
1254  return SDL_SetError("Haptic: Unable to run the effect: %s.",
1255  FFStrError(ret));
1256  }
1257 
1258  return 0;
1259 }
1260 
1261 
1262 /*
1263  * Stops an effect.
1264  */
1265 int
1266 SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
1267 {
1268  HRESULT ret;
1269 
1270  ret = FFEffectStop(effect->hweffect->ref);
1271  if (ret != FF_OK) {
1272  return SDL_SetError("Haptic: Unable to stop the effect: %s.",
1273  FFStrError(ret));
1274  }
1275 
1276  return 0;
1277 }
1278 
1279 
1280 /*
1281  * Frees the effect.
1282  */
1283 void
1284 SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
1285 {
1286  HRESULT ret;
1287 
1288  ret = FFDeviceReleaseEffect(haptic->hwdata->device, effect->hweffect->ref);
1289  if (ret != FF_OK) {
1290  SDL_SetError("Haptic: Error removing the effect from the device: %s.",
1291  FFStrError(ret));
1292  }
1293  SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect,
1294  effect->effect.type);
1295  SDL_free(effect->hweffect);
1296  effect->hweffect = NULL;
1297 }
1298 
1299 
1300 /*
1301  * Gets the status of a haptic effect.
1302  */
1303 int
1305  struct haptic_effect *effect)
1306 {
1307  HRESULT ret;
1308  FFEffectStatusFlag status;
1309 
1310  ret = FFEffectGetEffectStatus(effect->hweffect->ref, &status);
1311  if (ret != FF_OK) {
1312  SDL_SetError("Haptic: Unable to get effect status: %s.",
1313  FFStrError(ret));
1314  return -1;
1315  }
1316 
1317  if (status == 0) {
1318  return SDL_FALSE;
1319  }
1320  return SDL_TRUE; /* Assume it's playing or emulated. */
1321 }
1322 
1323 
1324 /*
1325  * Sets the gain.
1326  */
1327 int
1328 SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
1329 {
1330  HRESULT ret;
1331  Uint32 val;
1332 
1333  val = gain * 100; /* Mac OS X uses 0 to 10,000 */
1334  ret = FFDeviceSetForceFeedbackProperty(haptic->hwdata->device,
1335  FFPROP_FFGAIN, &val);
1336  if (ret != FF_OK) {
1337  return SDL_SetError("Haptic: Error setting gain: %s.", FFStrError(ret));
1338  }
1339 
1340  return 0;
1341 }
1342 
1343 
1344 /*
1345  * Sets the autocentering.
1346  */
1347 int
1348 SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
1349 {
1350  HRESULT ret;
1351  Uint32 val;
1352 
1353  /* Mac OS X only has 0 (off) and 1 (on) */
1354  if (autocenter == 0) {
1355  val = 0;
1356  } else {
1357  val = 1;
1358  }
1359 
1360  ret = FFDeviceSetForceFeedbackProperty(haptic->hwdata->device,
1361  FFPROP_AUTOCENTER, &val);
1362  if (ret != FF_OK) {
1363  return SDL_SetError("Haptic: Error setting autocenter: %s.",
1364  FFStrError(ret));
1365  }
1366 
1367  return 0;
1368 }
1369 
1370 
1371 /*
1372  * Pauses the device.
1373  */
1374 int
1375 SDL_SYS_HapticPause(SDL_Haptic * haptic)
1376 {
1377  HRESULT ret;
1378 
1379  ret = FFDeviceSendForceFeedbackCommand(haptic->hwdata->device,
1380  FFSFFC_PAUSE);
1381  if (ret != FF_OK) {
1382  return SDL_SetError("Haptic: Error pausing device: %s.", FFStrError(ret));
1383  }
1384 
1385  return 0;
1386 }
1387 
1388 
1389 /*
1390  * Unpauses the device.
1391  */
1392 int
1393 SDL_SYS_HapticUnpause(SDL_Haptic * haptic)
1394 {
1395  HRESULT ret;
1396 
1397  ret = FFDeviceSendForceFeedbackCommand(haptic->hwdata->device,
1398  FFSFFC_CONTINUE);
1399  if (ret != FF_OK) {
1400  return SDL_SetError("Haptic: Error pausing device: %s.", FFStrError(ret));
1401  }
1402 
1403  return 0;
1404 }
1405 
1406 
1407 /*
1408  * Stops all currently playing effects.
1409  */
1410 int
1411 SDL_SYS_HapticStopAll(SDL_Haptic * haptic)
1412 {
1413  HRESULT ret;
1414 
1415  ret = FFDeviceSendForceFeedbackCommand(haptic->hwdata->device,
1416  FFSFFC_STOPALL);
1417  if (ret != FF_OK) {
1418  return SDL_SetError("Haptic: Error stopping device: %s.", FFStrError(ret));
1419  }
1420 
1421  return 0;
1422 }
1423 
1424 #endif /* SDL_HAPTIC_IOKIT */
1425 
1426 /* vi: set ts=4 sw=4 expandtab: */
SDL_HapticCustom::channels
Uint8 channels
Definition: SDL_haptic.h:719
SDL_memset
#define SDL_memset
Definition: SDL_dynapi_overrides.h:386
SDL_HAPTIC_CARTESIAN
#define SDL_HAPTIC_CARTESIAN
Uses cartesian coordinates for the direction.
Definition: SDL_haptic.h:330
SDL_SYS_HapticPause
int SDL_SYS_HapticPause(SDL_Haptic *haptic)
Uint32
uint32_t Uint32
Definition: SDL_stdinc.h:203
SDL_HAPTIC_CUSTOM
#define SDL_HAPTIC_CUSTOM
Custom effect is supported.
Definition: SDL_haptic.h:269
SDL_HAPTIC_SPHERICAL
#define SDL_HAPTIC_SPHERICAL
Uses spherical coordinates for the direction.
Definition: SDL_haptic.h:337
SDL_HapticCustom::fade_length
Uint16 fade_length
Definition: SDL_haptic.h:727
SDL_HapticDirection::dir
Sint32 dir[3]
Definition: SDL_haptic.h:453
SDL_HapticCustom::samples
Uint16 samples
Definition: SDL_haptic.h:721
SDL_HapticCustom::direction
SDL_HapticDirection direction
Definition: SDL_haptic.h:708
SDL_abs
#define SDL_abs
Definition: SDL_dynapi_overrides.h:381
SDL_HapticRamp::interval
Uint16 interval
Definition: SDL_haptic.h:651
SDL_HapticPeriodic::period
Uint16 period
Definition: SDL_haptic.h:566
NULL
#define NULL
Definition: begin_code.h:167
SDL_HapticCondition
A structure containing a template for a Condition effect.
Definition: SDL_haptic.h:602
SDL_SYS_HapticName
const char * SDL_SYS_HapticName(int index)
SDL_HapticConstant::attack_length
Uint16 attack_length
Definition: SDL_haptic.h:486
SDL_joystick.h
base
set set set set set set set set set set set set set set set set set set set set *set set set macro pixldst base
Definition: pixman-arm-simd-asm.h:108
SDL_HapticRamp::end
Sint16 end
Definition: SDL_haptic.h:655
SDL_HapticRamp::length
Uint32 length
Definition: SDL_haptic.h:646
SDL_HapticCondition::left_coeff
Sint16 left_coeff[3]
Definition: SDL_haptic.h:621
SDL_SYS_HapticUnpause
int SDL_SYS_HapticUnpause(SDL_Haptic *haptic)
SDL_HapticPeriodic::phase
Uint16 phase
Definition: SDL_haptic.h:569
SDL_hapticlist_item
Definition: SDL_windowshaptic_c.h:67
SDL_HAPTIC_STATUS
#define SDL_HAPTIC_STATUS
Device can be queried for effect status.
Definition: SDL_haptic.h:300
iterations
static int iterations
Definition: testsprite2.c:45
SDL_HapticConstant::interval
Uint16 interval
Definition: SDL_haptic.h:480
SDL_SYS_HapticInit
int SDL_SYS_HapticInit(void)
SDL_HapticConstant::direction
SDL_HapticDirection direction
Definition: SDL_haptic.h:472
SDL_HapticCondition::length
Uint32 length
Definition: SDL_haptic.h:610
SDL_HAPTIC_DAMPER
#define SDL_HAPTIC_DAMPER
Damper effect supported - uses axes velocity.
Definition: SDL_haptic.h:242
SDL_HapticCustom
A structure containing a template for the SDL_HAPTIC_CUSTOM effect.
Definition: SDL_haptic.h:704
SDL_SYS_HapticUpdateEffect
int SDL_SYS_HapticUpdateEffect(SDL_Haptic *haptic, struct haptic_effect *effect, SDL_HapticEffect *data)
SDL_HapticCondition::deadband
Uint16 deadband[3]
Definition: SDL_haptic.h:622
index
GLuint index
Definition: SDL_opengl_glext.h:663
SDL_HAPTIC_AUTOCENTER
#define SDL_HAPTIC_AUTOCENTER
Device can set autocenter.
Definition: SDL_haptic.h:291
haptic_effect::effect
SDL_HapticEffect effect
Definition: SDL_syshaptic.h:32
result
GLuint64EXT * result
Definition: SDL_opengl_glext.h:9435
SDL_HAPTIC_INFINITY
#define SDL_HAPTIC_INFINITY
Used to play a device an infinite number of times.
Definition: SDL_haptic.h:352
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
SDL_SYS_HapticDestroyEffect
void SDL_SYS_HapticDestroyEffect(SDL_Haptic *haptic, struct haptic_effect *effect)
haptic_hwdata
Definition: SDL_windowshaptic_c.h:34
SDL_SYS_HapticRunEffect
int SDL_SYS_HapticRunEffect(SDL_Haptic *haptic, struct haptic_effect *effect, Uint32 iterations)
SDL_HapticCondition::interval
Uint16 interval
Definition: SDL_haptic.h:615
haptic_hweffect
Definition: SDL_windowshaptic_c.h:53
SDL_HapticPeriodic::delay
Uint16 delay
Definition: SDL_haptic.h:559
SDL_HapticConstant::attack_level
Uint16 attack_level
Definition: SDL_haptic.h:487
SDL_HapticPeriodic::attack_length
Uint16 attack_length
Definition: SDL_haptic.h:572
SDL_haptic.h
The SDL haptic subsystem allows you to control haptic (force feedback) devices.
SDL_HapticCustom::length
Uint32 length
Definition: SDL_haptic.h:711
SDL_HapticPeriodic::magnitude
Sint16 magnitude
Definition: SDL_haptic.h:567
SDL_HapticRamp::start
Sint16 start
Definition: SDL_haptic.h:654
condition
GLenum condition
Definition: SDL_opengl_glext.h:8673
SDL_HapticConstant::delay
Uint16 delay
Definition: SDL_haptic.h:476
SDL_SYS_HapticQuit
void SDL_SYS_HapticQuit(void)
SDL_HapticCondition::left_sat
Uint16 left_sat[3]
Definition: SDL_haptic.h:619
SDL_HapticConstant::fade_level
Uint16 fade_level
Definition: SDL_haptic.h:489
SDL_memcpy
#define SDL_memcpy
Definition: SDL_dynapi_overrides.h:387
SDL_FALSE
@ SDL_FALSE
Definition: SDL_stdinc.h:163
SDL_SYS_HapticSetGain
int SDL_SYS_HapticSetGain(SDL_Haptic *haptic, int gain)
usage
GLsizeiptr const void GLenum usage
Definition: SDL_opengl_glext.h:540
retval
SDL_bool retval
Definition: testgamecontroller.c:65
SDL_SYS_HapticGetEffectStatus
int SDL_SYS_HapticGetEffectStatus(SDL_Haptic *haptic, struct haptic_effect *effect)
SDL_HapticPeriodic::fade_level
Uint16 fade_level
Definition: SDL_haptic.h:575
SDL_HapticRamp::delay
Uint16 delay
Definition: SDL_haptic.h:647
SDL_HapticCustom::fade_level
Uint16 fade_level
Definition: SDL_haptic.h:728
ref
GLenum GLint ref
Definition: SDL_opengl_glext.h:660
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
SDL_HapticEffect
The generic template for any haptic effect.
Definition: SDL_haptic.h:800
SDL_HapticDirection::type
Uint8 type
Definition: SDL_haptic.h:452
SDL_HapticCustom::delay
Uint16 delay
Definition: SDL_haptic.h:712
SDL_DARWIN_JoystickDriver
SDL_JoystickDriver SDL_DARWIN_JoystickDriver
SDL_HapticCondition::delay
Uint16 delay
Definition: SDL_haptic.h:611
SDL_HapticPeriodic::offset
Sint16 offset
Definition: SDL_haptic.h:568
name
GLuint const GLchar * name
Definition: SDL_opengl_glext.h:663
SDL_HAPTIC_SINE
#define SDL_HAPTIC_SINE
Sine wave effect supported.
Definition: SDL_haptic.h:172
SDL_SYS_HapticStopEffect
int SDL_SYS_HapticStopEffect(SDL_Haptic *haptic, struct haptic_effect *effect)
SDL_HapticRamp::button
Uint16 button
Definition: SDL_haptic.h:650
MacHaptic_MaybeRemoveDevice
int MacHaptic_MaybeRemoveDevice(io_object_t device)
Uint16
uint16_t Uint16
Definition: SDL_stdinc.h:191
SDL_assert.h
haptic_effect
Definition: SDL_syshaptic.h:30
SDL_HapticPeriodic::length
Uint32 length
Definition: SDL_haptic.h:558
SDL_HapticConstant::button
Uint16 button
Definition: SDL_haptic.h:479
SDL_SYS_HapticStopAll
int SDL_SYS_HapticStopAll(SDL_Haptic *haptic)
SDL_HapticPeriodic::fade_length
Uint16 fade_length
Definition: SDL_haptic.h:574
SDL_HAPTIC_SAWTOOTHDOWN
#define SDL_HAPTIC_SAWTOOTHDOWN
Sawtoothdown wave effect supported.
Definition: SDL_haptic.h:213
SDL_SYS_HapticClose
void SDL_SYS_HapticClose(SDL_Haptic *haptic)
SDL_assert
#define SDL_assert(condition)
Definition: SDL_assert.h:169
SDL_HapticCondition::center
Sint16 center[3]
Definition: SDL_haptic.h:623
SDL_HapticRamp::fade_length
Uint16 fade_length
Definition: SDL_haptic.h:660
SDL_OutOfMemory
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_HAPTIC_INERTIA
#define SDL_HAPTIC_INERTIA
Inertia effect supported - uses axes acceleration.
Definition: SDL_haptic.h:252
SDL_hapticlist_item::next
struct SDL_hapticlist_item * next
Definition: SDL_windowshaptic_c.h:77
SDL_HAPTIC_GAIN
#define SDL_HAPTIC_GAIN
Device can set global gain.
Definition: SDL_haptic.h:282
SDL_HapticPeriodic
A structure containing a template for a Periodic effect.
Definition: SDL_haptic.h:549
SDL_SYS_HapticOpen
int SDL_SYS_HapticOpen(SDL_Haptic *haptic)
SDL_SYS_HapticMouse
int SDL_SYS_HapticMouse(void)
SDL_calloc
#define SDL_calloc
Definition: SDL_dynapi_overrides.h:375
SDL_SYS_HapticNewEffect
int SDL_SYS_HapticNewEffect(SDL_Haptic *haptic, struct haptic_effect *effect, SDL_HapticEffect *base)
haptic
static SDL_Haptic * haptic
Definition: testhaptic.c:25
SDL_HapticPeriodic::interval
Uint16 interval
Definition: SDL_haptic.h:563
haptic_hwdata::axes
DWORD axes[3]
Definition: SDL_windowshaptic_c.h:39
SDL_HapticCondition::right_coeff
Sint16 right_coeff[3]
Definition: SDL_haptic.h:620
SDL_HapticRamp::attack_length
Uint16 attack_length
Definition: SDL_haptic.h:658
SDL_HapticConstant::length
Uint32 length
Definition: SDL_haptic.h:475
src
GLenum src
Definition: SDL_opengl_glext.h:1740
SDL_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
SDL_HapticCustom::attack_level
Uint16 attack_level
Definition: SDL_haptic.h:726
SDL_HapticConstant::level
Sint16 level
Definition: SDL_haptic.h:483
SDL_hapticlist_item::haptic
SDL_Haptic * haptic
Definition: SDL_windowshaptic_c.h:70
SDL_HapticCondition::direction
SDL_HapticDirection direction
Definition: SDL_haptic.h:607
val
GLuint GLfloat * val
Definition: SDL_opengl_glext.h:1495
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
SDL_HapticCustom::period
Uint16 period
Definition: SDL_haptic.h:720
SDL_HapticRamp
A structure containing a template for a Ramp effect.
Definition: SDL_haptic.h:639
SDL_HAPTIC_SPRING
#define SDL_HAPTIC_SPRING
Spring effect supported - uses axes position.
Definition: SDL_haptic.h:232
SDL_stdinc.h
SDL_SYS_HapticSetAutocenter
int SDL_SYS_HapticSetAutocenter(SDL_Haptic *haptic, int autocenter)
SDL_HapticConstant::fade_length
Uint16 fade_length
Definition: SDL_haptic.h:488
SDL_hapticlist_item::name
char * name
Definition: SDL_windowshaptic_c.h:69
SDL_HapticRamp::direction
SDL_HapticDirection direction
Definition: SDL_haptic.h:643
SDL_HAPTIC_POLAR
#define SDL_HAPTIC_POLAR
Uses polar coordinates for the direction.
Definition: SDL_haptic.h:323
SDL_HapticCustom::attack_length
Uint16 attack_length
Definition: SDL_haptic.h:725
SDL_SYS_NumHaptics
int SDL_SYS_NumHaptics(void)
SDL_hapticlist
SDL_hapticlist_item * SDL_hapticlist
SDL_SYS_JoystickIsHaptic
int SDL_SYS_JoystickIsHaptic(SDL_Joystick *joystick)
haptic_effect::hweffect
struct haptic_hweffect * hweffect
Definition: SDL_syshaptic.h:33
SDL_SYS_JoystickSameHaptic
int SDL_SYS_JoystickSameHaptic(SDL_Haptic *haptic, SDL_Joystick *joystick)
SDL_HapticCustom::interval
Uint16 interval
Definition: SDL_haptic.h:716
SDL_HapticRamp::attack_level
Uint16 attack_level
Definition: SDL_haptic.h:659
SDL_HapticCustom::button
Uint16 button
Definition: SDL_haptic.h:715
SDL_malloc
#define SDL_malloc
Definition: SDL_dynapi_overrides.h:374
SDL_SYS_HapticOpenFromJoystick
int SDL_SYS_HapticOpenFromJoystick(SDL_Haptic *haptic, SDL_Joystick *joystick)
SDL_HAPTIC_SAWTOOTHUP
#define SDL_HAPTIC_SAWTOOTHUP
Sawtoothup wave effect supported.
Definition: SDL_haptic.h:204
SDL_HAPTIC_CONSTANT
#define SDL_HAPTIC_CONSTANT
Constant effect supported.
Definition: SDL_haptic.h:163
flags
GLbitfield flags
Definition: SDL_opengl_glext.h:1483
SDL_HapticCondition::button
Uint16 button
Definition: SDL_haptic.h:614
SDL_HapticPeriodic::button
Uint16 button
Definition: SDL_haptic.h:562
SDL_HapticPeriodic::direction
SDL_HapticDirection direction
Definition: SDL_haptic.h:555
device
static SDL_AudioDeviceID device
Definition: loopwave.c:37
SDL_HapticCondition::right_sat
Uint16 right_sat[3]
Definition: SDL_haptic.h:618
type
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
SDL_HAPTIC_TRIANGLE
#define SDL_HAPTIC_TRIANGLE
Triangle wave effect supported.
Definition: SDL_haptic.h:195
SDL_HAPTIC_FRICTION
#define SDL_HAPTIC_FRICTION
Friction effect supported - uses axes movement.
Definition: SDL_haptic.h:262
SDL_HAPTIC_PAUSE
#define SDL_HAPTIC_PAUSE
Device can be paused.
Definition: SDL_haptic.h:310
SDL_HapticCustom::data
Uint16 * data
Definition: SDL_haptic.h:722
SDL_HapticConstant
A structure containing a template for a Constant effect.
Definition: SDL_haptic.h:468
SDL_HapticPeriodic::attack_level
Uint16 attack_level
Definition: SDL_haptic.h:573
button
SDL_Texture * button
Definition: testgamecontroller.c:67
i
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
SDL_HAPTIC_RAMP
#define SDL_HAPTIC_RAMP
Ramp effect supported.
Definition: SDL_haptic.h:222
MacHaptic_MaybeAddDevice
int MacHaptic_MaybeAddDevice(io_object_t device)
SDL_HapticRamp::fade_level
Uint16 fade_level
Definition: SDL_haptic.h:661
SDL_HapticEffect::type
Uint16 type
Definition: SDL_haptic.h:803
SDL_HapticDirection
Structure that represents a haptic direction.
Definition: SDL_haptic.h:450
Uint8
uint8_t Uint8
Definition: SDL_stdinc.h:179