pcsxr-1.9.92
[pcsx_rearmed.git] / macosx / plugins / DFInput / SDL / src / haptic / SDL_haptic.c
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 2008 Edgar Simo
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) any later version.
9
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Lesser General Public License for more details.
14
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19     Sam Lantinga
20     slouken@libsdl.org
21 */
22 #include "SDL_config.h"
23
24 #include "SDL_syshaptic.h"
25 #include "SDL_haptic_c.h"
26 #include "../joystick/SDL_joystick_c.h" /* For SDL_PrivateJoystickValid */
27
28
29 Uint8 SDL_numhaptics = 0;
30 SDL_Haptic **SDL_haptics = NULL;
31
32
33 /*
34  * Initializes the Haptic devices.
35  */
36 int
37 SDL_HapticInit(void)
38 {
39     int arraylen;
40     int status;
41
42     SDL_numhaptics = 0;
43     status = SDL_SYS_HapticInit();
44     if (status >= 0) {
45         arraylen = (status + 1) * sizeof(*SDL_haptics);
46         SDL_haptics = (SDL_Haptic **) SDL_malloc(arraylen);
47         if (SDL_haptics == NULL) {      /* Out of memory. */
48             SDL_numhaptics = 0;
49         } else {
50             SDL_memset(SDL_haptics, 0, arraylen);
51             SDL_numhaptics = status;
52         }
53         status = 0;
54     }
55
56     return status;
57 }
58
59
60 /*
61  * Checks to see if the haptic device is valid
62  */
63 static int
64 ValidHaptic(SDL_Haptic * haptic)
65 {
66     int i;
67     int valid;
68
69     valid = 0;
70     if (haptic != NULL) {
71         for (i = 0; i < SDL_numhaptics; i++) {
72             if (SDL_haptics[i] == haptic) {
73                 valid = 1;
74                 break;
75             }
76         }
77     }
78
79     /* Create the error here. */
80     if (valid == 0) {
81         SDL_SetError("Haptic: Invalid haptic device identifier");
82     }
83
84     return valid;
85 }
86
87
88 /*
89  * Returns the number of available devices.
90  */
91 int
92 SDL_NumHaptics(void)
93 {
94     return SDL_numhaptics;
95 }
96
97
98 /*
99  * Gets the name of a Haptic device by index.
100  */
101 const char *
102 SDL_HapticName(int device_index)
103 {
104     if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
105         SDL_SetError("Haptic: There are %d haptic devices available",
106                      SDL_numhaptics);
107         return NULL;
108     }
109     return SDL_SYS_HapticName(device_index);
110 }
111
112
113 /*
114  * Opens a Haptic device.
115  */
116 SDL_Haptic *
117 SDL_HapticOpen(int device_index)
118 {
119     int i;
120     SDL_Haptic *haptic;
121
122     if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
123         SDL_SetError("Haptic: There are %d haptic devices available",
124                      SDL_numhaptics);
125         return NULL;
126     }
127
128     /* If the haptic is already open, return it */
129     for (i = 0; SDL_haptics[i]; i++) {
130         if (device_index == SDL_haptics[i]->index) {
131             haptic = SDL_haptics[i];
132             ++haptic->ref_count;
133             return haptic;
134         }
135     }
136
137     /* Create the haptic device */
138     haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
139     if (haptic == NULL) {
140         SDL_OutOfMemory();
141         return NULL;
142     }
143
144     /* Initialize the haptic device */
145     SDL_memset(haptic, 0, (sizeof *haptic));
146     haptic->index = device_index;
147     if (SDL_SYS_HapticOpen(haptic) < 0) {
148         SDL_free(haptic);
149         return NULL;
150     }
151
152     /* Disable autocenter and set gain to max. */
153     if (haptic->supported & SDL_HAPTIC_GAIN)
154         SDL_HapticSetGain(haptic, 100);
155     if (haptic->supported & SDL_HAPTIC_AUTOCENTER)
156         SDL_HapticSetAutocenter(haptic, 0);
157
158     /* Add haptic to list */
159     ++haptic->ref_count;
160     for (i = 0; SDL_haptics[i]; i++)
161         /* Skip to next haptic */ ;
162     SDL_haptics[i] = haptic;
163
164     return haptic;
165 }
166
167
168 /*
169  * Returns 1 if the device has been opened.
170  */
171 int
172 SDL_HapticOpened(int device_index)
173 {
174     int i, opened;
175
176     opened = 0;
177     for (i = 0; SDL_haptics[i]; i++) {
178         if (SDL_haptics[i]->index == (Uint8) device_index) {
179             opened = 1;
180             break;
181         }
182     }
183     return opened;
184 }
185
186
187 /*
188  * Returns the index to a haptic device.
189  */
190 int
191 SDL_HapticIndex(SDL_Haptic * haptic)
192 {
193     if (!ValidHaptic(haptic)) {
194         return -1;
195     }
196
197     return haptic->index;
198 }
199
200
201 /*
202  * Returns SDL_TRUE if mouse is haptic, SDL_FALSE if it isn't.
203  */
204 int
205 SDL_MouseIsHaptic(void)
206 {
207     if (SDL_SYS_HapticMouse() < 0)
208         return SDL_FALSE;
209     return SDL_TRUE;
210 }
211
212
213 /*
214  * Returns the haptic device if mouse is haptic or NULL elsewise.
215  */
216 SDL_Haptic *
217 SDL_HapticOpenFromMouse(void)
218 {
219     int device_index;
220
221     device_index = SDL_SYS_HapticMouse();
222
223     if (device_index < 0) {
224         SDL_SetError("Haptic: Mouse isn't a haptic device.");
225         return NULL;
226     }
227
228     return SDL_HapticOpen(device_index);
229 }
230
231
232 /*
233  * Returns SDL_TRUE if joystick has haptic features.
234  */
235 int
236 SDL_JoystickIsHaptic(SDL_Joystick * joystick)
237 {
238     int ret;
239
240     /* Must be a valid joystick */
241     if (!SDL_PrivateJoystickValid(&joystick)) {
242         return -1;
243     }
244
245     ret = SDL_SYS_JoystickIsHaptic(joystick);
246
247     if (ret > 0)
248         return SDL_TRUE;
249     else if (ret == 0)
250         return SDL_FALSE;
251     else
252         return -1;
253 }
254
255
256 /*
257  * Opens a haptic device from a joystick.
258  */
259 SDL_Haptic *
260 SDL_HapticOpenFromJoystick(SDL_Joystick * joystick)
261 {
262     int i;
263     SDL_Haptic *haptic;
264
265     /* Must be a valid joystick */
266     if (!SDL_PrivateJoystickValid(&joystick)) {
267         SDL_SetError("Haptic: Joystick isn't valid.");
268         return NULL;
269     }
270
271     /* Joystick must be haptic */
272     if (SDL_SYS_JoystickIsHaptic(joystick) <= 0) {
273         SDL_SetError("Haptic: Joystick isn't a haptic device.");
274         return NULL;
275     }
276
277     /* Check to see if joystick's haptic is already open */
278     for (i = 0; SDL_haptics[i]; i++) {
279         if (SDL_SYS_JoystickSameHaptic(SDL_haptics[i], joystick)) {
280             haptic = SDL_haptics[i];
281             ++haptic->ref_count;
282             return haptic;
283         }
284     }
285
286     /* Create the haptic device */
287     haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
288     if (haptic == NULL) {
289         SDL_OutOfMemory();
290         return NULL;
291     }
292
293     /* Initialize the haptic device */
294     SDL_memset(haptic, 0, sizeof(SDL_Haptic));
295     if (SDL_SYS_HapticOpenFromJoystick(haptic, joystick) < 0) {
296         SDL_free(haptic);
297         return NULL;
298     }
299
300     /* Add haptic to list */
301     ++haptic->ref_count;
302     for (i = 0; SDL_haptics[i]; i++)
303         /* Skip to next haptic */ ;
304     SDL_haptics[i] = haptic;
305
306     return haptic;
307 }
308
309
310 /*
311  * Closes a SDL_Haptic device.
312  */
313 void
314 SDL_HapticClose(SDL_Haptic * haptic)
315 {
316     int i;
317
318     /* Must be valid */
319     if (!ValidHaptic(haptic)) {
320         return;
321     }
322
323     /* Check if it's still in use */
324     if (--haptic->ref_count < 0) {
325         return;
326     }
327
328     /* Close it, properly removing effects if needed */
329     for (i = 0; i < haptic->neffects; i++) {
330         if (haptic->effects[i].hweffect != NULL) {
331             SDL_HapticDestroyEffect(haptic, i);
332         }
333     }
334     SDL_SYS_HapticClose(haptic);
335
336     /* Remove from the list */
337     for (i = 0; SDL_haptics[i]; ++i) {
338         if (haptic == SDL_haptics[i]) {
339             SDL_haptics[i] = NULL;
340             SDL_memcpy(&SDL_haptics[i], &SDL_haptics[i + 1],
341                        (SDL_numhaptics - i) * sizeof(haptic));
342             break;
343         }
344     }
345
346     /* Free */
347     SDL_free(haptic);
348 }
349
350 /*
351  * Cleans up after the subsystem.
352  */
353 void
354 SDL_HapticQuit(void)
355 {
356     SDL_SYS_HapticQuit();
357     if (SDL_haptics != NULL) {
358         SDL_free(SDL_haptics);
359         SDL_haptics = NULL;
360     }
361     SDL_numhaptics = 0;
362 }
363
364 /*
365  * Returns the number of effects a haptic device has.
366  */
367 int
368 SDL_HapticNumEffects(SDL_Haptic * haptic)
369 {
370     if (!ValidHaptic(haptic)) {
371         return -1;
372     }
373
374     return haptic->neffects;
375 }
376
377
378 /*
379  * Returns the number of effects a haptic device can play.
380  */
381 int
382 SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic)
383 {
384     if (!ValidHaptic(haptic)) {
385         return -1;
386     }
387
388     return haptic->nplaying;
389 }
390
391
392 /*
393  * Returns supported effects by the device.
394  */
395 unsigned int
396 SDL_HapticQuery(SDL_Haptic * haptic)
397 {
398     if (!ValidHaptic(haptic)) {
399         return -1;
400     }
401
402     return haptic->supported;
403 }
404
405
406 /*
407  * Returns the number of axis on the device.
408  */
409 int
410 SDL_HapticNumAxes(SDL_Haptic * haptic)
411 {
412     if (!ValidHaptic(haptic)) {
413         return -1;
414     }
415
416     return haptic->naxes;
417 }
418
419 /*
420  * Checks to see if the device can support the effect.
421  */
422 int
423 SDL_HapticEffectSupported(SDL_Haptic * haptic, SDL_HapticEffect * effect)
424 {
425     if (!ValidHaptic(haptic)) {
426         return -1;
427     }
428
429     if ((haptic->supported & effect->type) != 0)
430         return SDL_TRUE;
431     return SDL_FALSE;
432 }
433
434 /*
435  * Creates a new haptic effect.
436  */
437 int
438 SDL_HapticNewEffect(SDL_Haptic * haptic, SDL_HapticEffect * effect)
439 {
440     int i;
441
442     /* Check for device validity. */
443     if (!ValidHaptic(haptic)) {
444         return -1;
445     }
446
447     /* Check to see if effect is supported */
448     if (SDL_HapticEffectSupported(haptic, effect) == SDL_FALSE) {
449         SDL_SetError("Haptic: Effect not supported by haptic device.");
450         return -1;
451     }
452
453     /* See if there's a free slot */
454     for (i = 0; i < haptic->neffects; i++) {
455         if (haptic->effects[i].hweffect == NULL) {
456
457             /* Now let the backend create the real effect */
458             if (SDL_SYS_HapticNewEffect(haptic, &haptic->effects[i], effect)
459                 != 0) {
460                 return -1;      /* Backend failed to create effect */
461             }
462
463             SDL_memcpy(&haptic->effects[i].effect, effect,
464                        sizeof(SDL_HapticEffect));
465             return i;
466         }
467     }
468
469     SDL_SetError("Haptic: Device has no free space left.");
470     return -1;
471 }
472
473 /*
474  * Checks to see if an effect is valid.
475  */
476 static int
477 ValidEffect(SDL_Haptic * haptic, int effect)
478 {
479     if ((effect < 0) || (effect >= haptic->neffects)) {
480         SDL_SetError("Haptic: Invalid effect identifier.");
481         return 0;
482     }
483     return 1;
484 }
485
486 /*
487  * Updates an effect.
488  */
489 int
490 SDL_HapticUpdateEffect(SDL_Haptic * haptic, int effect,
491                        SDL_HapticEffect * data)
492 {
493     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
494         return -1;
495     }
496
497     /* Can't change type dynamically. */
498     if (data->type != haptic->effects[effect].effect.type) {
499         SDL_SetError("Haptic: Updating effect type is illegal.");
500         return -1;
501     }
502
503     /* Updates the effect */
504     if (SDL_SYS_HapticUpdateEffect(haptic, &haptic->effects[effect], data) <
505         0) {
506         return -1;
507     }
508
509     SDL_memcpy(&haptic->effects[effect].effect, data,
510                sizeof(SDL_HapticEffect));
511     return 0;
512 }
513
514
515 /*
516  * Runs the haptic effect on the device.
517  */
518 int
519 SDL_HapticRunEffect(SDL_Haptic * haptic, int effect, Uint32 iterations)
520 {
521     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
522         return -1;
523     }
524
525     /* Run the effect */
526     if (SDL_SYS_HapticRunEffect(haptic, &haptic->effects[effect], iterations)
527         < 0) {
528         return -1;
529     }
530
531     return 0;
532 }
533
534 /*
535  * Stops the haptic effect on the device.
536  */
537 int
538 SDL_HapticStopEffect(SDL_Haptic * haptic, int effect)
539 {
540     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
541         return -1;
542     }
543
544     /* Stop the effect */
545     if (SDL_SYS_HapticStopEffect(haptic, &haptic->effects[effect]) < 0) {
546         return -1;
547     }
548
549     return 0;
550 }
551
552 /*
553  * Gets rid of a haptic effect.
554  */
555 void
556 SDL_HapticDestroyEffect(SDL_Haptic * haptic, int effect)
557 {
558     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
559         return;
560     }
561
562     /* Not allocated */
563     if (haptic->effects[effect].hweffect == NULL) {
564         return;
565     }
566
567     SDL_SYS_HapticDestroyEffect(haptic, &haptic->effects[effect]);
568 }
569
570 /*
571  * Gets the status of a haptic effect.
572  */
573 int
574 SDL_HapticGetEffectStatus(SDL_Haptic * haptic, int effect)
575 {
576     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
577         return -1;
578     }
579
580     if ((haptic->supported & SDL_HAPTIC_STATUS) == 0) {
581         SDL_SetError("Haptic: Device does not support status queries.");
582         return -1;
583     }
584
585     return SDL_SYS_HapticGetEffectStatus(haptic, &haptic->effects[effect]);
586 }
587
588 /*
589  * Sets the global gain of the device.
590  */
591 int
592 SDL_HapticSetGain(SDL_Haptic * haptic, int gain)
593 {
594     const char *env;
595     int real_gain, max_gain;
596
597     if (!ValidHaptic(haptic)) {
598         return -1;
599     }
600
601     if ((haptic->supported & SDL_HAPTIC_GAIN) == 0) {
602         SDL_SetError("Haptic: Device does not support setting gain.");
603         return -1;
604     }
605
606     if ((gain < 0) || (gain > 100)) {
607         SDL_SetError("Haptic: Gain must be between 0 and 100.");
608         return -1;
609     }
610
611     /* We use the envvar to get the maximum gain. */
612     env = SDL_getenv("SDL_HAPTIC_GAIN_MAX");
613     if (env != NULL) {
614         max_gain = SDL_atoi(env);
615
616         /* Check for sanity. */
617         if (max_gain < 0)
618             max_gain = 0;
619         else if (max_gain > 100)
620             max_gain = 100;
621
622         /* We'll scale it linearly with SDL_HAPTIC_GAIN_MAX */
623         real_gain = (gain * max_gain) / 100;
624     } else {
625         real_gain = gain;
626     }
627
628     if (SDL_SYS_HapticSetGain(haptic, real_gain) < 0) {
629         return -1;
630     }
631
632     return 0;
633 }
634
635 /*
636  * Makes the device autocenter, 0 disables.
637  */
638 int
639 SDL_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
640 {
641     if (!ValidHaptic(haptic)) {
642         return -1;
643     }
644
645     if ((haptic->supported & SDL_HAPTIC_AUTOCENTER) == 0) {
646         SDL_SetError("Haptic: Device does not support setting autocenter.");
647         return -1;
648     }
649
650     if ((autocenter < 0) || (autocenter > 100)) {
651         SDL_SetError("Haptic: Autocenter must be between 0 and 100.");
652         return -1;
653     }
654
655     if (SDL_SYS_HapticSetAutocenter(haptic, autocenter) < 0) {
656         return -1;
657     }
658
659     return 0;
660 }
661
662 /*
663  * Pauses the haptic device.
664  */
665 int
666 SDL_HapticPause(SDL_Haptic * haptic)
667 {
668     if (!ValidHaptic(haptic)) {
669         return -1;
670     }
671
672     if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) {
673         SDL_SetError("Haptic: Device does not support setting pausing.");
674         return -1;
675     }
676
677     return SDL_SYS_HapticPause(haptic);
678 }
679
680 /*
681  * Unpauses the haptic device.
682  */
683 int
684 SDL_HapticUnpause(SDL_Haptic * haptic)
685 {
686     if (!ValidHaptic(haptic)) {
687         return -1;
688     }
689
690     if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) {
691         return 0;               /* Not going to be paused, so we pretend it's unpaused. */
692     }
693
694     return SDL_SYS_HapticUnpause(haptic);
695 }
696
697 /*
698  * Stops all the currently playing effects.
699  */
700 int
701 SDL_HapticStopAll(SDL_Haptic * haptic)
702 {
703     if (!ValidHaptic(haptic)) {
704         return -1;
705     }
706
707     return SDL_SYS_HapticStopAll(haptic);
708 }