1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2016 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 #include "SDL_syshaptic.h"
24 #include "SDL_haptic_c.h"
25 #include "../joystick/SDL_joystick_c.h" /* For SDL_PrivateJoystickValid */
26 #include "SDL_assert.h"
27 
28 SDL_Haptic *SDL_haptics = NULL;
29 
30 
31 /*
32  * Initializes the Haptic devices.
33  */
34 int
SDL_HapticInit(void)35 SDL_HapticInit(void)
36 {
37     int status;
38 
39     status = SDL_SYS_HapticInit();
40     if (status >= 0) {
41         status = 0;
42     }
43 
44     return status;
45 }
46 
47 
48 /*
49  * Checks to see if the haptic device is valid
50  */
51 static int
ValidHaptic(SDL_Haptic * haptic)52 ValidHaptic(SDL_Haptic * haptic)
53 {
54     int valid;
55     SDL_Haptic *hapticlist;
56 
57     valid = 0;
58     if (haptic != NULL) {
59         hapticlist = SDL_haptics;
60         while ( hapticlist )
61         {
62             if (hapticlist == haptic) {
63                 valid = 1;
64                 break;
65             }
66             hapticlist = hapticlist->next;
67         }
68     }
69 
70     /* Create the error here. */
71     if (valid == 0) {
72         SDL_SetError("Haptic: Invalid haptic device identifier");
73     }
74 
75     return valid;
76 }
77 
78 
79 /*
80  * Returns the number of available devices.
81  */
82 int
SDL_NumHaptics(void)83 SDL_NumHaptics(void)
84 {
85     return SDL_SYS_NumHaptics();
86 }
87 
88 
89 /*
90  * Gets the name of a Haptic device by index.
91  */
92 const char *
SDL_HapticName(int device_index)93 SDL_HapticName(int device_index)
94 {
95     if ((device_index < 0) || (device_index >= SDL_NumHaptics())) {
96         SDL_SetError("Haptic: There are %d haptic devices available",
97                      SDL_NumHaptics());
98         return NULL;
99     }
100     return SDL_SYS_HapticName(device_index);
101 }
102 
103 
104 /*
105  * Opens a Haptic device.
106  */
107 SDL_Haptic *
SDL_HapticOpen(int device_index)108 SDL_HapticOpen(int device_index)
109 {
110     SDL_Haptic *haptic;
111     SDL_Haptic *hapticlist;
112 
113     if ((device_index < 0) || (device_index >= SDL_NumHaptics())) {
114         SDL_SetError("Haptic: There are %d haptic devices available",
115                      SDL_NumHaptics());
116         return NULL;
117     }
118 
119     hapticlist = SDL_haptics;
120     /* If the haptic is already open, return it
121     * TODO: Should we create haptic instance IDs like the Joystick API?
122     */
123     while ( hapticlist )
124     {
125         if (device_index == hapticlist->index) {
126             haptic = hapticlist;
127             ++haptic->ref_count;
128             return haptic;
129         }
130         hapticlist = hapticlist->next;
131     }
132 
133     /* Create the haptic device */
134     haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
135     if (haptic == NULL) {
136         SDL_OutOfMemory();
137         return NULL;
138     }
139 
140     /* Initialize the haptic device */
141     SDL_memset(haptic, 0, (sizeof *haptic));
142     haptic->rumble_id = -1;
143     haptic->index = device_index;
144     if (SDL_SYS_HapticOpen(haptic) < 0) {
145         SDL_free(haptic);
146         return NULL;
147     }
148 
149     /* Add haptic to list */
150     ++haptic->ref_count;
151     /* Link the haptic in the list */
152     haptic->next = SDL_haptics;
153     SDL_haptics = haptic;
154 
155     /* Disable autocenter and set gain to max. */
156     if (haptic->supported & SDL_HAPTIC_GAIN)
157         SDL_HapticSetGain(haptic, 100);
158     if (haptic->supported & SDL_HAPTIC_AUTOCENTER)
159         SDL_HapticSetAutocenter(haptic, 0);
160 
161     return haptic;
162 }
163 
164 
165 /*
166  * Returns 1 if the device has been opened.
167  */
168 int
SDL_HapticOpened(int device_index)169 SDL_HapticOpened(int device_index)
170 {
171     int opened;
172     SDL_Haptic *hapticlist;
173 
174     /* Make sure it's valid. */
175     if ((device_index < 0) || (device_index >= SDL_NumHaptics())) {
176         SDL_SetError("Haptic: There are %d haptic devices available",
177                      SDL_NumHaptics());
178         return 0;
179     }
180 
181     opened = 0;
182     hapticlist = SDL_haptics;
183     /* TODO Should this use an instance ID? */
184     while ( hapticlist )
185     {
186         if (hapticlist->index == (Uint8) device_index) {
187             opened = 1;
188             break;
189         }
190         hapticlist = hapticlist->next;
191     }
192     return opened;
193 }
194 
195 
196 /*
197  * Returns the index to a haptic device.
198  */
199 int
SDL_HapticIndex(SDL_Haptic * haptic)200 SDL_HapticIndex(SDL_Haptic * haptic)
201 {
202     if (!ValidHaptic(haptic)) {
203         return -1;
204     }
205 
206     return haptic->index;
207 }
208 
209 
210 /*
211  * Returns SDL_TRUE if mouse is haptic, SDL_FALSE if it isn't.
212  */
213 int
SDL_MouseIsHaptic(void)214 SDL_MouseIsHaptic(void)
215 {
216     if (SDL_SYS_HapticMouse() < 0)
217         return SDL_FALSE;
218     return SDL_TRUE;
219 }
220 
221 
222 /*
223  * Returns the haptic device if mouse is haptic or NULL elsewise.
224  */
225 SDL_Haptic *
SDL_HapticOpenFromMouse(void)226 SDL_HapticOpenFromMouse(void)
227 {
228     int device_index;
229 
230     device_index = SDL_SYS_HapticMouse();
231 
232     if (device_index < 0) {
233         SDL_SetError("Haptic: Mouse isn't a haptic device.");
234         return NULL;
235     }
236 
237     return SDL_HapticOpen(device_index);
238 }
239 
240 
241 /*
242  * Returns SDL_TRUE if joystick has haptic features.
243  */
244 int
SDL_JoystickIsHaptic(SDL_Joystick * joystick)245 SDL_JoystickIsHaptic(SDL_Joystick * joystick)
246 {
247     int ret;
248 
249     /* Must be a valid joystick */
250     if (!SDL_PrivateJoystickValid(joystick)) {
251         return -1;
252     }
253 
254     ret = SDL_SYS_JoystickIsHaptic(joystick);
255 
256     if (ret > 0)
257         return SDL_TRUE;
258     else if (ret == 0)
259         return SDL_FALSE;
260     else
261         return -1;
262 }
263 
264 
265 /*
266  * Opens a haptic device from a joystick.
267  */
268 SDL_Haptic *
SDL_HapticOpenFromJoystick(SDL_Joystick * joystick)269 SDL_HapticOpenFromJoystick(SDL_Joystick * joystick)
270 {
271     SDL_Haptic *haptic;
272     SDL_Haptic *hapticlist;
273 
274     /* Make sure there is room. */
275     if (SDL_NumHaptics() <= 0) {
276         SDL_SetError("Haptic: There are %d haptic devices available",
277                      SDL_NumHaptics());
278         return NULL;
279     }
280 
281     /* Must be a valid joystick */
282     if (!SDL_PrivateJoystickValid(joystick)) {
283         SDL_SetError("Haptic: Joystick isn't valid.");
284         return NULL;
285     }
286 
287     /* Joystick must be haptic */
288     if (SDL_SYS_JoystickIsHaptic(joystick) <= 0) {
289         SDL_SetError("Haptic: Joystick isn't a haptic device.");
290         return NULL;
291     }
292 
293     hapticlist = SDL_haptics;
294     /* Check to see if joystick's haptic is already open */
295     while ( hapticlist )
296     {
297         if (SDL_SYS_JoystickSameHaptic(hapticlist, joystick)) {
298             haptic = hapticlist;
299             ++haptic->ref_count;
300             return haptic;
301         }
302         hapticlist = hapticlist->next;
303     }
304 
305     /* Create the haptic device */
306     haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
307     if (haptic == NULL) {
308         SDL_OutOfMemory();
309         return NULL;
310     }
311 
312     /* Initialize the haptic device */
313     SDL_memset(haptic, 0, sizeof(SDL_Haptic));
314     haptic->rumble_id = -1;
315     if (SDL_SYS_HapticOpenFromJoystick(haptic, joystick) < 0) {
316         SDL_free(haptic);
317         return NULL;
318     }
319 
320     /* Add haptic to list */
321     ++haptic->ref_count;
322     /* Link the haptic in the list */
323     haptic->next = SDL_haptics;
324     SDL_haptics = haptic;
325 
326     return haptic;
327 }
328 
329 
330 /*
331  * Closes a SDL_Haptic device.
332  */
333 void
SDL_HapticClose(SDL_Haptic * haptic)334 SDL_HapticClose(SDL_Haptic * haptic)
335 {
336     int i;
337     SDL_Haptic *hapticlist;
338     SDL_Haptic *hapticlistprev;
339 
340     /* Must be valid */
341     if (!ValidHaptic(haptic)) {
342         return;
343     }
344 
345     /* Check if it's still in use */
346     if (--haptic->ref_count > 0) {
347         return;
348     }
349 
350     /* Close it, properly removing effects if needed */
351     for (i = 0; i < haptic->neffects; i++) {
352         if (haptic->effects[i].hweffect != NULL) {
353             SDL_HapticDestroyEffect(haptic, i);
354         }
355     }
356     SDL_SYS_HapticClose(haptic);
357 
358     /* Remove from the list */
359     hapticlist = SDL_haptics;
360     hapticlistprev = NULL;
361     while ( hapticlist )
362     {
363         if (haptic == hapticlist)
364         {
365             if ( hapticlistprev )
366             {
367                 /* unlink this entry */
368                 hapticlistprev->next = hapticlist->next;
369             }
370             else
371             {
372                 SDL_haptics = haptic->next;
373             }
374 
375             break;
376         }
377         hapticlistprev = hapticlist;
378         hapticlist = hapticlist->next;
379     }
380 
381     /* Free */
382     SDL_free(haptic);
383 }
384 
385 /*
386  * Cleans up after the subsystem.
387  */
388 void
SDL_HapticQuit(void)389 SDL_HapticQuit(void)
390 {
391     SDL_SYS_HapticQuit();
392     SDL_assert(SDL_haptics == NULL);
393     SDL_haptics = NULL;
394 }
395 
396 /*
397  * Returns the number of effects a haptic device has.
398  */
399 int
SDL_HapticNumEffects(SDL_Haptic * haptic)400 SDL_HapticNumEffects(SDL_Haptic * haptic)
401 {
402     if (!ValidHaptic(haptic)) {
403         return -1;
404     }
405 
406     return haptic->neffects;
407 }
408 
409 
410 /*
411  * Returns the number of effects a haptic device can play.
412  */
413 int
SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic)414 SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic)
415 {
416     if (!ValidHaptic(haptic)) {
417         return -1;
418     }
419 
420     return haptic->nplaying;
421 }
422 
423 
424 /*
425  * Returns supported effects by the device.
426  */
427 unsigned int
SDL_HapticQuery(SDL_Haptic * haptic)428 SDL_HapticQuery(SDL_Haptic * haptic)
429 {
430     if (!ValidHaptic(haptic)) {
431         return 0; /* same as if no effects were supported */
432     }
433 
434     return haptic->supported;
435 }
436 
437 
438 /*
439  * Returns the number of axis on the device.
440  */
441 int
SDL_HapticNumAxes(SDL_Haptic * haptic)442 SDL_HapticNumAxes(SDL_Haptic * haptic)
443 {
444     if (!ValidHaptic(haptic)) {
445         return -1;
446     }
447 
448     return haptic->naxes;
449 }
450 
451 /*
452  * Checks to see if the device can support the effect.
453  */
454 int
SDL_HapticEffectSupported(SDL_Haptic * haptic,SDL_HapticEffect * effect)455 SDL_HapticEffectSupported(SDL_Haptic * haptic, SDL_HapticEffect * effect)
456 {
457     if (!ValidHaptic(haptic)) {
458         return -1;
459     }
460 
461     if ((haptic->supported & effect->type) != 0)
462         return SDL_TRUE;
463     return SDL_FALSE;
464 }
465 
466 /*
467  * Creates a new haptic effect.
468  */
469 int
SDL_HapticNewEffect(SDL_Haptic * haptic,SDL_HapticEffect * effect)470 SDL_HapticNewEffect(SDL_Haptic * haptic, SDL_HapticEffect * effect)
471 {
472     int i;
473 
474     /* Check for device validity. */
475     if (!ValidHaptic(haptic)) {
476         return -1;
477     }
478 
479     /* Check to see if effect is supported */
480     if (SDL_HapticEffectSupported(haptic, effect) == SDL_FALSE) {
481         return SDL_SetError("Haptic: Effect not supported by haptic device.");
482     }
483 
484     /* See if there's a free slot */
485     for (i = 0; i < haptic->neffects; i++) {
486         if (haptic->effects[i].hweffect == NULL) {
487 
488             /* Now let the backend create the real effect */
489             if (SDL_SYS_HapticNewEffect(haptic, &haptic->effects[i], effect)
490                 != 0) {
491                 return -1;      /* Backend failed to create effect */
492             }
493 
494             SDL_memcpy(&haptic->effects[i].effect, effect,
495                        sizeof(SDL_HapticEffect));
496             return i;
497         }
498     }
499 
500     return SDL_SetError("Haptic: Device has no free space left.");
501 }
502 
503 /*
504  * Checks to see if an effect is valid.
505  */
506 static int
ValidEffect(SDL_Haptic * haptic,int effect)507 ValidEffect(SDL_Haptic * haptic, int effect)
508 {
509     if ((effect < 0) || (effect >= haptic->neffects)) {
510         SDL_SetError("Haptic: Invalid effect identifier.");
511         return 0;
512     }
513     return 1;
514 }
515 
516 /*
517  * Updates an effect.
518  */
519 int
SDL_HapticUpdateEffect(SDL_Haptic * haptic,int effect,SDL_HapticEffect * data)520 SDL_HapticUpdateEffect(SDL_Haptic * haptic, int effect,
521                        SDL_HapticEffect * data)
522 {
523     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
524         return -1;
525     }
526 
527     /* Can't change type dynamically. */
528     if (data->type != haptic->effects[effect].effect.type) {
529         return SDL_SetError("Haptic: Updating effect type is illegal.");
530     }
531 
532     /* Updates the effect */
533     if (SDL_SYS_HapticUpdateEffect(haptic, &haptic->effects[effect], data) <
534         0) {
535         return -1;
536     }
537 
538     SDL_memcpy(&haptic->effects[effect].effect, data,
539                sizeof(SDL_HapticEffect));
540     return 0;
541 }
542 
543 
544 /*
545  * Runs the haptic effect on the device.
546  */
547 int
SDL_HapticRunEffect(SDL_Haptic * haptic,int effect,Uint32 iterations)548 SDL_HapticRunEffect(SDL_Haptic * haptic, int effect, Uint32 iterations)
549 {
550     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
551         return -1;
552     }
553 
554     /* Run the effect */
555     if (SDL_SYS_HapticRunEffect(haptic, &haptic->effects[effect], iterations)
556         < 0) {
557         return -1;
558     }
559 
560     return 0;
561 }
562 
563 /*
564  * Stops the haptic effect on the device.
565  */
566 int
SDL_HapticStopEffect(SDL_Haptic * haptic,int effect)567 SDL_HapticStopEffect(SDL_Haptic * haptic, int effect)
568 {
569     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
570         return -1;
571     }
572 
573     /* Stop the effect */
574     if (SDL_SYS_HapticStopEffect(haptic, &haptic->effects[effect]) < 0) {
575         return -1;
576     }
577 
578     return 0;
579 }
580 
581 /*
582  * Gets rid of a haptic effect.
583  */
584 void
SDL_HapticDestroyEffect(SDL_Haptic * haptic,int effect)585 SDL_HapticDestroyEffect(SDL_Haptic * haptic, int effect)
586 {
587     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
588         return;
589     }
590 
591     /* Not allocated */
592     if (haptic->effects[effect].hweffect == NULL) {
593         return;
594     }
595 
596     SDL_SYS_HapticDestroyEffect(haptic, &haptic->effects[effect]);
597 }
598 
599 /*
600  * Gets the status of a haptic effect.
601  */
602 int
SDL_HapticGetEffectStatus(SDL_Haptic * haptic,int effect)603 SDL_HapticGetEffectStatus(SDL_Haptic * haptic, int effect)
604 {
605     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
606         return -1;
607     }
608 
609     if ((haptic->supported & SDL_HAPTIC_STATUS) == 0) {
610         return SDL_SetError("Haptic: Device does not support status queries.");
611     }
612 
613     return SDL_SYS_HapticGetEffectStatus(haptic, &haptic->effects[effect]);
614 }
615 
616 /*
617  * Sets the global gain of the device.
618  */
619 int
SDL_HapticSetGain(SDL_Haptic * haptic,int gain)620 SDL_HapticSetGain(SDL_Haptic * haptic, int gain)
621 {
622     const char *env;
623     int real_gain, max_gain;
624 
625     if (!ValidHaptic(haptic)) {
626         return -1;
627     }
628 
629     if ((haptic->supported & SDL_HAPTIC_GAIN) == 0) {
630         return SDL_SetError("Haptic: Device does not support setting gain.");
631     }
632 
633     if ((gain < 0) || (gain > 100)) {
634         return SDL_SetError("Haptic: Gain must be between 0 and 100.");
635     }
636 
637     /* We use the envvar to get the maximum gain. */
638     env = SDL_getenv("SDL_HAPTIC_GAIN_MAX");
639     if (env != NULL) {
640         max_gain = SDL_atoi(env);
641 
642         /* Check for sanity. */
643         if (max_gain < 0)
644             max_gain = 0;
645         else if (max_gain > 100)
646             max_gain = 100;
647 
648         /* We'll scale it linearly with SDL_HAPTIC_GAIN_MAX */
649         real_gain = (gain * max_gain) / 100;
650     } else {
651         real_gain = gain;
652     }
653 
654     if (SDL_SYS_HapticSetGain(haptic, real_gain) < 0) {
655         return -1;
656     }
657 
658     return 0;
659 }
660 
661 /*
662  * Makes the device autocenter, 0 disables.
663  */
664 int
SDL_HapticSetAutocenter(SDL_Haptic * haptic,int autocenter)665 SDL_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
666 {
667     if (!ValidHaptic(haptic)) {
668         return -1;
669     }
670 
671     if ((haptic->supported & SDL_HAPTIC_AUTOCENTER) == 0) {
672         return SDL_SetError("Haptic: Device does not support setting autocenter.");
673     }
674 
675     if ((autocenter < 0) || (autocenter > 100)) {
676         return SDL_SetError("Haptic: Autocenter must be between 0 and 100.");
677     }
678 
679     if (SDL_SYS_HapticSetAutocenter(haptic, autocenter) < 0) {
680         return -1;
681     }
682 
683     return 0;
684 }
685 
686 /*
687  * Pauses the haptic device.
688  */
689 int
SDL_HapticPause(SDL_Haptic * haptic)690 SDL_HapticPause(SDL_Haptic * haptic)
691 {
692     if (!ValidHaptic(haptic)) {
693         return -1;
694     }
695 
696     if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) {
697         return SDL_SetError("Haptic: Device does not support setting pausing.");
698     }
699 
700     return SDL_SYS_HapticPause(haptic);
701 }
702 
703 /*
704  * Unpauses the haptic device.
705  */
706 int
SDL_HapticUnpause(SDL_Haptic * haptic)707 SDL_HapticUnpause(SDL_Haptic * haptic)
708 {
709     if (!ValidHaptic(haptic)) {
710         return -1;
711     }
712 
713     if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) {
714         return 0;               /* Not going to be paused, so we pretend it's unpaused. */
715     }
716 
717     return SDL_SYS_HapticUnpause(haptic);
718 }
719 
720 /*
721  * Stops all the currently playing effects.
722  */
723 int
SDL_HapticStopAll(SDL_Haptic * haptic)724 SDL_HapticStopAll(SDL_Haptic * haptic)
725 {
726     if (!ValidHaptic(haptic)) {
727         return -1;
728     }
729 
730     return SDL_SYS_HapticStopAll(haptic);
731 }
732 
733 /*
734  * Checks to see if rumble is supported.
735  */
736 int
SDL_HapticRumbleSupported(SDL_Haptic * haptic)737 SDL_HapticRumbleSupported(SDL_Haptic * haptic)
738 {
739     if (!ValidHaptic(haptic)) {
740         return -1;
741     }
742 
743     /* Most things can use SINE, but XInput only has LEFTRIGHT. */
744     return ((haptic->supported & (SDL_HAPTIC_SINE|SDL_HAPTIC_LEFTRIGHT)) != 0);
745 }
746 
747 /*
748  * Initializes the haptic device for simple rumble playback.
749  */
750 int
SDL_HapticRumbleInit(SDL_Haptic * haptic)751 SDL_HapticRumbleInit(SDL_Haptic * haptic)
752 {
753     SDL_HapticEffect *efx = &haptic->rumble_effect;
754 
755     if (!ValidHaptic(haptic)) {
756         return -1;
757     }
758 
759     /* Already allocated. */
760     if (haptic->rumble_id >= 0) {
761         return 0;
762     }
763 
764     SDL_zerop(efx);
765     if (haptic->supported & SDL_HAPTIC_SINE) {
766         efx->type = SDL_HAPTIC_SINE;
767         efx->periodic.period = 1000;
768         efx->periodic.magnitude = 0x4000;
769         efx->periodic.length = 5000;
770         efx->periodic.attack_length = 0;
771         efx->periodic.fade_length = 0;
772     } else if (haptic->supported & SDL_HAPTIC_LEFTRIGHT) {  /* XInput? */
773         efx->type = SDL_HAPTIC_LEFTRIGHT;
774         efx->leftright.length = 5000;
775         efx->leftright.large_magnitude = 0x4000;
776         efx->leftright.small_magnitude = 0x4000;
777     } else {
778         return SDL_SetError("Device doesn't support rumble");
779     }
780 
781     haptic->rumble_id = SDL_HapticNewEffect(haptic, &haptic->rumble_effect);
782     if (haptic->rumble_id >= 0) {
783         return 0;
784     }
785     return -1;
786 }
787 
788 /*
789  * Runs simple rumble on a haptic device
790  */
791 int
SDL_HapticRumblePlay(SDL_Haptic * haptic,float strength,Uint32 length)792 SDL_HapticRumblePlay(SDL_Haptic * haptic, float strength, Uint32 length)
793 {
794     SDL_HapticEffect *efx;
795     Sint16 magnitude;
796 
797     if (!ValidHaptic(haptic)) {
798         return -1;
799     }
800 
801     if (haptic->rumble_id < 0) {
802         return SDL_SetError("Haptic: Rumble effect not initialized on haptic device");
803     }
804 
805     /* Clamp strength. */
806     if (strength > 1.0f) {
807         strength = 1.0f;
808     } else if (strength < 0.0f) {
809         strength = 0.0f;
810     }
811     magnitude = (Sint16)(32767.0f*strength);
812 
813     efx = &haptic->rumble_effect;
814     if (efx->type == SDL_HAPTIC_SINE) {
815         efx->periodic.magnitude = magnitude;
816         efx->periodic.length = length;
817     } else if (efx->type == SDL_HAPTIC_LEFTRIGHT) {
818         efx->leftright.small_magnitude = efx->leftright.large_magnitude = magnitude;
819         efx->leftright.length = length;
820     } else {
821         SDL_assert(0 && "This should have been caught elsewhere");
822     }
823 
824     if (SDL_HapticUpdateEffect(haptic, haptic->rumble_id, &haptic->rumble_effect) < 0) {
825         return -1;
826     }
827 
828     return SDL_HapticRunEffect(haptic, haptic->rumble_id, 1);
829 }
830 
831 /*
832  * Stops the simple rumble on a haptic device.
833  */
834 int
SDL_HapticRumbleStop(SDL_Haptic * haptic)835 SDL_HapticRumbleStop(SDL_Haptic * haptic)
836 {
837     if (!ValidHaptic(haptic)) {
838         return -1;
839     }
840 
841     if (haptic->rumble_id < 0) {
842         return SDL_SetError("Haptic: Rumble effect not initialized on haptic device");
843     }
844 
845     return SDL_HapticStopEffect(haptic, haptic->rumble_id);
846 }
847 
848 /* vi: set ts=4 sw=4 expandtab: */
849