Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/sdl/haptic/SDL_haptic.c
9905 views
1
/*
2
Simple DirectMedia Layer
3
Copyright (C) 1997-2025 Sam Lantinga <[email protected]>
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
28
typedef struct SDL_Haptic_VIDPID_Naxes {
29
Uint16 vid;
30
Uint16 pid;
31
Uint16 naxes;
32
} SDL_Haptic_VIDPID_Naxes;
33
34
static 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 */
68
static 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
83
static 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
105
static 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
113
bool SDL_InitHaptics(void)
114
{
115
return SDL_SYS_HapticInit();
116
}
117
118
static 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
137
SDL_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
166
const 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
177
SDL_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
241
SDL_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
253
SDL_HapticID SDL_GetHapticID(SDL_Haptic *haptic)
254
{
255
CHECK_HAPTIC_MAGIC(haptic, 0);
256
257
return haptic->instance_id;
258
}
259
260
const char *SDL_GetHapticName(SDL_Haptic *haptic)
261
{
262
CHECK_HAPTIC_MAGIC(haptic, NULL);
263
264
return SDL_GetPersistentString(haptic->name);
265
}
266
267
bool SDL_IsMouseHaptic(void)
268
{
269
if (SDL_SYS_HapticMouse() < 0) {
270
return false;
271
}
272
return true;
273
}
274
275
SDL_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
289
bool 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
306
SDL_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
385
void 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
430
void SDL_QuitHaptics(void)
431
{
432
while (SDL_haptics) {
433
SDL_CloseHaptic(SDL_haptics);
434
}
435
436
SDL_SYS_HapticQuit();
437
}
438
439
int SDL_GetMaxHapticEffects(SDL_Haptic *haptic)
440
{
441
CHECK_HAPTIC_MAGIC(haptic, -1);
442
443
return haptic->neffects;
444
}
445
446
int SDL_GetMaxHapticEffectsPlaying(SDL_Haptic *haptic)
447
{
448
CHECK_HAPTIC_MAGIC(haptic, -1);
449
450
return haptic->nplaying;
451
}
452
453
Uint32 SDL_GetHapticFeatures(SDL_Haptic *haptic)
454
{
455
CHECK_HAPTIC_MAGIC(haptic, 0);
456
457
return haptic->supported;
458
}
459
460
int SDL_GetNumHapticAxes(SDL_Haptic *haptic)
461
{
462
CHECK_HAPTIC_MAGIC(haptic, -1);
463
464
return haptic->naxes;
465
}
466
467
bool 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
481
int 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
517
static 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
526
bool 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
553
bool 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
569
bool 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
585
void 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
601
bool 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
618
bool 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
654
bool 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
669
bool 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
680
bool 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
691
bool SDL_StopHapticEffects(SDL_Haptic *haptic)
692
{
693
CHECK_HAPTIC_MAGIC(haptic, false);
694
695
return SDL_SYS_HapticStopAll(haptic);
696
}
697
698
bool 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
706
bool 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
742
bool 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
779
bool 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
}
789
790