SDL_syshaptic.c 39 KB

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