summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/haptic/SDL_haptic.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/SDL-3.2.8/src/haptic/SDL_haptic.c')
-rw-r--r--contrib/SDL-3.2.8/src/haptic/SDL_haptic.c788
1 files changed, 788 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/haptic/SDL_haptic.c b/contrib/SDL-3.2.8/src/haptic/SDL_haptic.c
new file mode 100644
index 0000000..1c11db6
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/haptic/SDL_haptic.c
@@ -0,0 +1,788 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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_IsJoystickValid
26#include "../SDL_hints_c.h"
27
28typedef struct SDL_Haptic_VIDPID_Naxes {
29 Uint16 vid;
30 Uint16 pid;
31 Uint16 naxes;
32} SDL_Haptic_VIDPID_Naxes;
33
34static void SDL_Haptic_Load_Axes_List(SDL_Haptic_VIDPID_Naxes **entries, int *num_entries)
35{
36 SDL_Haptic_VIDPID_Naxes entry;
37 const char *spot;
38 int length = 0;
39
40 spot = SDL_GetHint(SDL_HINT_JOYSTICK_HAPTIC_AXES);
41 if (!spot)
42 return;
43
44 while (SDL_sscanf(spot, "0x%hx/0x%hx/%hu%n", &entry.vid, &entry.pid, &entry.naxes, &length) == 3) {
45 SDL_assert(length > 0);
46 spot += length;
47 length = 0;
48
49 if ((*num_entries % 8) == 0) {
50 int new_max = *num_entries + 8;
51 SDL_Haptic_VIDPID_Naxes *new_entries =
52 (SDL_Haptic_VIDPID_Naxes *)SDL_realloc(*entries, new_max * sizeof(**entries));
53
54 // Out of memory, go with what we have already
55 if (!new_entries)
56 break;
57
58 *entries = new_entries;
59 }
60 (*entries)[(*num_entries)++] = entry;
61
62 if (spot[0] == ',')
63 spot++;
64 }
65}
66
67// /* Return -1 if not found */
68static int SDL_Haptic_Naxes_List_Index(struct SDL_Haptic_VIDPID_Naxes *entries, int num_entries, Uint16 vid, Uint16 pid)
69{
70 if (!entries)
71 return -1;
72
73 int i;
74 for (i = 0; i < num_entries; ++i) {
75 if (entries[i].vid == vid && entries[i].pid == pid)
76 return i;
77 }
78
79 return -1;
80}
81
82// Check if device needs a custom number of naxes
83static int SDL_Haptic_Get_Naxes(Uint16 vid, Uint16 pid)
84{
85 int num_entries = 0, index = 0, naxes = -1;
86 SDL_Haptic_VIDPID_Naxes *naxes_list = NULL;
87
88 SDL_Haptic_Load_Axes_List(&naxes_list, &num_entries);
89 if (!num_entries || !naxes_list)
90 return -1;
91
92 // Perform "wildcard" pass
93 index = SDL_Haptic_Naxes_List_Index(naxes_list, num_entries, 0xffff, 0xffff);
94 if (index >= 0)
95 naxes = naxes_list[index].naxes;
96
97 index = SDL_Haptic_Naxes_List_Index(naxes_list, num_entries, vid, pid);
98 if (index >= 0)
99 naxes = naxes_list[index].naxes;
100
101 SDL_free(naxes_list);
102 return naxes;
103}
104
105static SDL_Haptic *SDL_haptics = NULL;
106
107#define CHECK_HAPTIC_MAGIC(haptic, result) \
108 if (!SDL_ObjectValid(haptic, SDL_OBJECT_TYPE_HAPTIC)) { \
109 SDL_InvalidParamError("haptic"); \
110 return result; \
111 }
112
113bool SDL_InitHaptics(void)
114{
115 return SDL_SYS_HapticInit();
116}
117
118static bool SDL_GetHapticIndex(SDL_HapticID instance_id, int *driver_index)
119{
120 int num_haptics, device_index;
121
122 if (instance_id > 0) {
123 num_haptics = SDL_SYS_NumHaptics();
124 for (device_index = 0; device_index < num_haptics; ++device_index) {
125 SDL_HapticID haptic_id = SDL_SYS_HapticInstanceID(device_index);
126 if (haptic_id == instance_id) {
127 *driver_index = device_index;
128 return true;
129 }
130 }
131 }
132
133 SDL_SetError("Haptic device %" SDL_PRIu32 " not found", instance_id);
134 return false;
135}
136
137SDL_HapticID *SDL_GetHaptics(int *count)
138{
139 int device_index;
140 int haptic_index = 0, num_haptics = 0;
141 SDL_HapticID *haptics;
142
143 num_haptics = SDL_SYS_NumHaptics();
144
145 haptics = (SDL_HapticID *)SDL_malloc((num_haptics + 1) * sizeof(*haptics));
146 if (haptics) {
147 if (count) {
148 *count = num_haptics;
149 }
150
151 for (device_index = 0; device_index < num_haptics; ++device_index) {
152 haptics[haptic_index] = SDL_SYS_HapticInstanceID(device_index);
153 SDL_assert(haptics[haptic_index] > 0);
154 ++haptic_index;
155 }
156 haptics[haptic_index] = 0;
157 } else {
158 if (count) {
159 *count = 0;
160 }
161 }
162
163 return haptics;
164}
165
166const char *SDL_GetHapticNameForID(SDL_HapticID instance_id)
167{
168 int device_index;
169 const char *name = NULL;
170
171 if (SDL_GetHapticIndex(instance_id, &device_index)) {
172 name = SDL_GetPersistentString(SDL_SYS_HapticName(device_index));
173 }
174 return name;
175}
176
177SDL_Haptic *SDL_OpenHaptic(SDL_HapticID instance_id)
178{
179 SDL_Haptic *haptic;
180 SDL_Haptic *hapticlist;
181 const char *name;
182 int device_index = 0;
183
184 if (!SDL_GetHapticIndex(instance_id, &device_index)) {
185 return NULL;
186 }
187
188 hapticlist = SDL_haptics;
189 /* If the haptic device is already open, return it
190 * it is important that we have a single haptic device for each instance id
191 */
192 while (hapticlist) {
193 if (instance_id == hapticlist->instance_id) {
194 haptic = hapticlist;
195 ++haptic->ref_count;
196 return haptic;
197 }
198 hapticlist = hapticlist->next;
199 }
200
201 // Create the haptic device
202 haptic = (SDL_Haptic *)SDL_calloc(1, sizeof(*haptic));
203 if (!haptic) {
204 return NULL;
205 }
206
207 // Initialize the haptic device
208 SDL_SetObjectValid(haptic, SDL_OBJECT_TYPE_HAPTIC, true);
209 haptic->instance_id = instance_id;
210 haptic->rumble_id = -1;
211 if (!SDL_SYS_HapticOpen(haptic)) {
212 SDL_SetObjectValid(haptic, SDL_OBJECT_TYPE_HAPTIC, false);
213 SDL_free(haptic);
214 return NULL;
215 }
216
217 if (!haptic->name) {
218 name = SDL_SYS_HapticName(device_index);
219 if (name) {
220 haptic->name = SDL_strdup(name);
221 }
222 }
223
224 // Add haptic to list
225 ++haptic->ref_count;
226 // Link the haptic in the list
227 haptic->next = SDL_haptics;
228 SDL_haptics = haptic;
229
230 // Disable autocenter and set gain to max.
231 if (haptic->supported & SDL_HAPTIC_GAIN) {
232 SDL_SetHapticGain(haptic, 100);
233 }
234 if (haptic->supported & SDL_HAPTIC_AUTOCENTER) {
235 SDL_SetHapticAutocenter(haptic, 0);
236 }
237
238 return haptic;
239}
240
241SDL_Haptic *SDL_GetHapticFromID(SDL_HapticID instance_id)
242{
243 SDL_Haptic *haptic;
244
245 for (haptic = SDL_haptics; haptic; haptic = haptic->next) {
246 if (instance_id == haptic->instance_id) {
247 break;
248 }
249 }
250 return haptic;
251}
252
253SDL_HapticID SDL_GetHapticID(SDL_Haptic *haptic)
254{
255 CHECK_HAPTIC_MAGIC(haptic, 0);
256
257 return haptic->instance_id;
258}
259
260const char *SDL_GetHapticName(SDL_Haptic *haptic)
261{
262 CHECK_HAPTIC_MAGIC(haptic, NULL);
263
264 return SDL_GetPersistentString(haptic->name);
265}
266
267bool SDL_IsMouseHaptic(void)
268{
269 if (SDL_SYS_HapticMouse() < 0) {
270 return false;
271 }
272 return true;
273}
274
275SDL_Haptic *SDL_OpenHapticFromMouse(void)
276{
277 int device_index;
278
279 device_index = SDL_SYS_HapticMouse();
280
281 if (device_index < 0) {
282 SDL_SetError("Haptic: Mouse isn't a haptic device.");
283 return NULL;
284 }
285
286 return SDL_OpenHaptic(device_index);
287}
288
289bool SDL_IsJoystickHaptic(SDL_Joystick *joystick)
290{
291 bool result = false;
292
293 SDL_LockJoysticks();
294 {
295 // Must be a valid joystick
296 if (SDL_IsJoystickValid(joystick) &&
297 !SDL_IsGamepad(SDL_GetJoystickID(joystick))) {
298 result = SDL_SYS_JoystickIsHaptic(joystick);
299 }
300 }
301 SDL_UnlockJoysticks();
302
303 return result;
304}
305
306SDL_Haptic *SDL_OpenHapticFromJoystick(SDL_Joystick *joystick)
307{
308 SDL_Haptic *haptic;
309 SDL_Haptic *hapticlist;
310
311 SDL_LockJoysticks();
312 {
313 // Must be a valid joystick
314 if (!SDL_IsJoystickValid(joystick)) {
315 SDL_SetError("Haptic: Joystick isn't valid.");
316 SDL_UnlockJoysticks();
317 return NULL;
318 }
319
320 // Joystick must be haptic
321 if (SDL_IsGamepad(SDL_GetJoystickID(joystick)) ||
322 !SDL_SYS_JoystickIsHaptic(joystick)) {
323 SDL_SetError("Haptic: Joystick isn't a haptic device.");
324 SDL_UnlockJoysticks();
325 return NULL;
326 }
327
328 hapticlist = SDL_haptics;
329 // Check to see if joystick's haptic is already open
330 while (hapticlist) {
331 if (SDL_SYS_JoystickSameHaptic(hapticlist, joystick)) {
332 haptic = hapticlist;
333 ++haptic->ref_count;
334 SDL_UnlockJoysticks();
335 return haptic;
336 }
337 hapticlist = hapticlist->next;
338 }
339
340 // Create the haptic device
341 haptic = (SDL_Haptic *)SDL_calloc(1, sizeof(*haptic));
342 if (!haptic) {
343 SDL_UnlockJoysticks();
344 return NULL;
345 }
346
347 /* Initialize the haptic device
348 * This function should fill in the instance ID and name.
349 */
350 SDL_SetObjectValid(haptic, SDL_OBJECT_TYPE_HAPTIC, true);
351 haptic->rumble_id = -1;
352 if (!SDL_SYS_HapticOpenFromJoystick(haptic, joystick)) {
353 SDL_SetError("Haptic: SDL_SYS_HapticOpenFromJoystick failed.");
354 SDL_SetObjectValid(haptic, SDL_OBJECT_TYPE_HAPTIC, false);
355 SDL_free(haptic);
356 SDL_UnlockJoysticks();
357 return NULL;
358 }
359 SDL_assert(haptic->instance_id != 0);
360 }
361 SDL_UnlockJoysticks();
362
363 // Check if custom number of haptic axes was defined
364 Uint16 vid = SDL_GetJoystickVendor(joystick);
365 Uint16 pid = SDL_GetJoystickProduct(joystick);
366 int general_axes = SDL_GetNumJoystickAxes(joystick);
367
368 int naxes = SDL_Haptic_Get_Naxes(vid, pid);
369 if (naxes > 0)
370 haptic->naxes = naxes;
371
372 // Limit to the actual number of axes found on the device
373 if (general_axes >= 0 && naxes > general_axes)
374 haptic->naxes = general_axes;
375
376 // Add haptic to list
377 ++haptic->ref_count;
378 // Link the haptic in the list
379 haptic->next = SDL_haptics;
380 SDL_haptics = haptic;
381
382 return haptic;
383}
384
385void SDL_CloseHaptic(SDL_Haptic *haptic)
386{
387 int i;
388 SDL_Haptic *hapticlist;
389 SDL_Haptic *hapticlistprev;
390
391 CHECK_HAPTIC_MAGIC(haptic,);
392
393 // Check if it's still in use
394 if (--haptic->ref_count > 0) {
395 return;
396 }
397
398 // Close it, properly removing effects if needed
399 for (i = 0; i < haptic->neffects; i++) {
400 if (haptic->effects[i].hweffect != NULL) {
401 SDL_DestroyHapticEffect(haptic, i);
402 }
403 }
404 SDL_SYS_HapticClose(haptic);
405 SDL_SetObjectValid(haptic, SDL_OBJECT_TYPE_HAPTIC, false);
406
407 // Remove from the list
408 hapticlist = SDL_haptics;
409 hapticlistprev = NULL;
410 while (hapticlist) {
411 if (haptic == hapticlist) {
412 if (hapticlistprev) {
413 // unlink this entry
414 hapticlistprev->next = hapticlist->next;
415 } else {
416 SDL_haptics = haptic->next;
417 }
418
419 break;
420 }
421 hapticlistprev = hapticlist;
422 hapticlist = hapticlist->next;
423 }
424
425 // Free the data associated with this device
426 SDL_free(haptic->name);
427 SDL_free(haptic);
428}
429
430void SDL_QuitHaptics(void)
431{
432 while (SDL_haptics) {
433 SDL_CloseHaptic(SDL_haptics);
434 }
435
436 SDL_SYS_HapticQuit();
437}
438
439int SDL_GetMaxHapticEffects(SDL_Haptic *haptic)
440{
441 CHECK_HAPTIC_MAGIC(haptic, -1);
442
443 return haptic->neffects;
444}
445
446int SDL_GetMaxHapticEffectsPlaying(SDL_Haptic *haptic)
447{
448 CHECK_HAPTIC_MAGIC(haptic, -1);
449
450 return haptic->nplaying;
451}
452
453Uint32 SDL_GetHapticFeatures(SDL_Haptic *haptic)
454{
455 CHECK_HAPTIC_MAGIC(haptic, 0);
456
457 return haptic->supported;
458}
459
460int SDL_GetNumHapticAxes(SDL_Haptic *haptic)
461{
462 CHECK_HAPTIC_MAGIC(haptic, -1);
463
464 return haptic->naxes;
465}
466
467bool SDL_HapticEffectSupported(SDL_Haptic *haptic, const SDL_HapticEffect *effect)
468{
469 CHECK_HAPTIC_MAGIC(haptic, false);
470
471 if (!effect) {
472 return false;
473 }
474
475 if ((haptic->supported & effect->type) != 0) {
476 return true;
477 }
478 return false;
479}
480
481int SDL_CreateHapticEffect(SDL_Haptic *haptic, const SDL_HapticEffect *effect)
482{
483 int i;
484
485 CHECK_HAPTIC_MAGIC(haptic, -1);
486
487 if (!effect) {
488 SDL_InvalidParamError("effect");
489 return -1;
490 }
491
492 // Check to see if effect is supported
493 if (SDL_HapticEffectSupported(haptic, effect) == false) {
494 SDL_SetError("Haptic: Effect not supported by haptic device.");
495 return -1;
496 }
497
498 // See if there's a free slot
499 for (i = 0; i < haptic->neffects; i++) {
500 if (haptic->effects[i].hweffect == NULL) {
501
502 // Now let the backend create the real effect
503 if (!SDL_SYS_HapticNewEffect(haptic, &haptic->effects[i], effect)) {
504 return -1; // Backend failed to create effect
505 }
506
507 SDL_memcpy(&haptic->effects[i].effect, effect,
508 sizeof(SDL_HapticEffect));
509 return i;
510 }
511 }
512
513 SDL_SetError("Haptic: Device has no free space left.");
514 return -1;
515}
516
517static bool ValidEffect(SDL_Haptic *haptic, int effect)
518{
519 if ((effect < 0) || (effect >= haptic->neffects)) {
520 SDL_SetError("Haptic: Invalid effect identifier.");
521 return false;
522 }
523 return true;
524}
525
526bool SDL_UpdateHapticEffect(SDL_Haptic *haptic, int effect, const SDL_HapticEffect *data)
527{
528 CHECK_HAPTIC_MAGIC(haptic, false);
529
530 if (!ValidEffect(haptic, effect)) {
531 return false;
532 }
533
534 if (!data) {
535 return SDL_InvalidParamError("data");
536 }
537
538 // Can't change type dynamically.
539 if (data->type != haptic->effects[effect].effect.type) {
540 return SDL_SetError("Haptic: Updating effect type is illegal.");
541 }
542
543 // Updates the effect
544 if (!SDL_SYS_HapticUpdateEffect(haptic, &haptic->effects[effect], data)) {
545 return false;
546 }
547
548 SDL_memcpy(&haptic->effects[effect].effect, data,
549 sizeof(SDL_HapticEffect));
550 return true;
551}
552
553bool SDL_RunHapticEffect(SDL_Haptic *haptic, int effect, Uint32 iterations)
554{
555 CHECK_HAPTIC_MAGIC(haptic, false);
556
557 if (!ValidEffect(haptic, effect)) {
558 return false;
559 }
560
561 // Run the effect
562 if (!SDL_SYS_HapticRunEffect(haptic, &haptic->effects[effect], iterations)) {
563 return false;
564 }
565
566 return true;
567}
568
569bool SDL_StopHapticEffect(SDL_Haptic *haptic, int effect)
570{
571 CHECK_HAPTIC_MAGIC(haptic, false);
572
573 if (!ValidEffect(haptic, effect)) {
574 return false;
575 }
576
577 // Stop the effect
578 if (!SDL_SYS_HapticStopEffect(haptic, &haptic->effects[effect])) {
579 return false;
580 }
581
582 return true;
583}
584
585void SDL_DestroyHapticEffect(SDL_Haptic *haptic, int effect)
586{
587 CHECK_HAPTIC_MAGIC(haptic,);
588
589 if (!ValidEffect(haptic, effect)) {
590 return;
591 }
592
593 // Not allocated
594 if (haptic->effects[effect].hweffect == NULL) {
595 return;
596 }
597
598 SDL_SYS_HapticDestroyEffect(haptic, &haptic->effects[effect]);
599}
600
601bool SDL_GetHapticEffectStatus(SDL_Haptic *haptic, int effect)
602{
603 CHECK_HAPTIC_MAGIC(haptic, false);
604
605 if (!ValidEffect(haptic, effect)) {
606 return false;
607 }
608
609 if (!(haptic->supported & SDL_HAPTIC_STATUS)) {
610 return SDL_SetError("Haptic: Device does not support status queries.");
611 }
612
613 SDL_ClearError();
614
615 return (SDL_SYS_HapticGetEffectStatus(haptic, &haptic->effects[effect]) > 0);
616}
617
618bool SDL_SetHapticGain(SDL_Haptic *haptic, int gain)
619{
620 const char *env;
621 int real_gain, max_gain;
622
623 CHECK_HAPTIC_MAGIC(haptic, false);
624
625 if (!(haptic->supported & SDL_HAPTIC_GAIN)) {
626 return SDL_SetError("Haptic: Device does not support setting gain.");
627 }
628
629 if ((gain < 0) || (gain > 100)) {
630 return SDL_SetError("Haptic: Gain must be between 0 and 100.");
631 }
632
633 // The user can use an environment variable to override the max gain.
634 env = SDL_getenv("SDL_HAPTIC_GAIN_MAX");
635 if (env) {
636 max_gain = SDL_atoi(env);
637
638 // Check for sanity.
639 if (max_gain < 0) {
640 max_gain = 0;
641 } else if (max_gain > 100) {
642 max_gain = 100;
643 }
644
645 // We'll scale it linearly with SDL_HAPTIC_GAIN_MAX
646 real_gain = (gain * max_gain) / 100;
647 } else {
648 real_gain = gain;
649 }
650
651 return SDL_SYS_HapticSetGain(haptic, real_gain);
652}
653
654bool SDL_SetHapticAutocenter(SDL_Haptic *haptic, int autocenter)
655{
656 CHECK_HAPTIC_MAGIC(haptic, false);
657
658 if (!(haptic->supported & SDL_HAPTIC_AUTOCENTER)) {
659 return SDL_SetError("Haptic: Device does not support setting autocenter.");
660 }
661
662 if ((autocenter < 0) || (autocenter > 100)) {
663 return SDL_SetError("Haptic: Autocenter must be between 0 and 100.");
664 }
665
666 return SDL_SYS_HapticSetAutocenter(haptic, autocenter);
667}
668
669bool SDL_PauseHaptic(SDL_Haptic *haptic)
670{
671 CHECK_HAPTIC_MAGIC(haptic, false);
672
673 if (!(haptic->supported & SDL_HAPTIC_PAUSE)) {
674 return SDL_SetError("Haptic: Device does not support setting pausing.");
675 }
676
677 return SDL_SYS_HapticPause(haptic);
678}
679
680bool SDL_ResumeHaptic(SDL_Haptic *haptic)
681{
682 CHECK_HAPTIC_MAGIC(haptic, false);
683
684 if (!(haptic->supported & SDL_HAPTIC_PAUSE)) {
685 return true; // Not going to be paused, so we pretend it's unpaused.
686 }
687
688 return SDL_SYS_HapticResume(haptic);
689}
690
691bool SDL_StopHapticEffects(SDL_Haptic *haptic)
692{
693 CHECK_HAPTIC_MAGIC(haptic, false);
694
695 return SDL_SYS_HapticStopAll(haptic);
696}
697
698bool SDL_HapticRumbleSupported(SDL_Haptic *haptic)
699{
700 CHECK_HAPTIC_MAGIC(haptic, false);
701
702 // Most things can use SINE, but XInput only has LEFTRIGHT.
703 return (haptic->supported & (SDL_HAPTIC_SINE | SDL_HAPTIC_LEFTRIGHT)) != 0;
704}
705
706bool SDL_InitHapticRumble(SDL_Haptic *haptic)
707{
708 SDL_HapticEffect *efx = &haptic->rumble_effect;
709
710 CHECK_HAPTIC_MAGIC(haptic, false);
711
712 // Already allocated.
713 if (haptic->rumble_id >= 0) {
714 return true;
715 }
716
717 SDL_zerop(efx);
718 if (haptic->supported & SDL_HAPTIC_SINE) {
719 efx->type = SDL_HAPTIC_SINE;
720 efx->periodic.direction.type = SDL_HAPTIC_CARTESIAN;
721 efx->periodic.period = 1000;
722 efx->periodic.magnitude = 0x4000;
723 efx->periodic.length = 5000;
724 efx->periodic.attack_length = 0;
725 efx->periodic.fade_length = 0;
726 } else if (haptic->supported & SDL_HAPTIC_LEFTRIGHT) { // XInput?
727 efx->type = SDL_HAPTIC_LEFTRIGHT;
728 efx->leftright.length = 5000;
729 efx->leftright.large_magnitude = 0x4000;
730 efx->leftright.small_magnitude = 0x4000;
731 } else {
732 return SDL_SetError("Device doesn't support rumble");
733 }
734
735 haptic->rumble_id = SDL_CreateHapticEffect(haptic, &haptic->rumble_effect);
736 if (haptic->rumble_id >= 0) {
737 return true;
738 }
739 return false;
740}
741
742bool SDL_PlayHapticRumble(SDL_Haptic *haptic, float strength, Uint32 length)
743{
744 SDL_HapticEffect *efx;
745 Sint16 magnitude;
746
747 CHECK_HAPTIC_MAGIC(haptic, false);
748
749 if (haptic->rumble_id < 0) {
750 return SDL_SetError("Haptic: Rumble effect not initialized on haptic device");
751 }
752
753 // Clamp strength.
754 if (strength > 1.0f) {
755 strength = 1.0f;
756 } else if (strength < 0.0f) {
757 strength = 0.0f;
758 }
759 magnitude = (Sint16)(32767.0f * strength);
760
761 efx = &haptic->rumble_effect;
762 if (efx->type == SDL_HAPTIC_SINE) {
763 efx->periodic.magnitude = magnitude;
764 efx->periodic.length = length;
765 } else if (efx->type == SDL_HAPTIC_LEFTRIGHT) {
766 efx->leftright.small_magnitude = efx->leftright.large_magnitude = magnitude;
767 efx->leftright.length = length;
768 } else {
769 SDL_assert(!"This should have been caught elsewhere");
770 }
771
772 if (!SDL_UpdateHapticEffect(haptic, haptic->rumble_id, &haptic->rumble_effect)) {
773 return false;
774 }
775
776 return SDL_RunHapticEffect(haptic, haptic->rumble_id, 1);
777}
778
779bool SDL_StopHapticRumble(SDL_Haptic *haptic)
780{
781 CHECK_HAPTIC_MAGIC(haptic, false);
782
783 if (haptic->rumble_id < 0) {
784 return SDL_SetError("Haptic: Rumble effect not initialized on haptic device");
785 }
786
787 return SDL_StopHapticEffect(haptic, haptic->rumble_id);
788}