Skip to content

Commit dac06e0

Browse files
committed
Add hidapi SDL_Haptic carrier and SDL_Haptic lg4ff implementation
effect rendering is ported from https://github.com/berarma/new-lg4ff
1 parent 974d39f commit dac06e0

File tree

8 files changed

+1737
-18
lines changed

8 files changed

+1737
-18
lines changed

Xcode/SDL/SDL.xcodeproj/project.pbxproj

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@
7272
75E0915A241EA924004729E1 /* SDL_virtualjoystick.c in Sources */ = {isa = PBXBuildFile; fileRef = 75E09158241EA924004729E1 /* SDL_virtualjoystick.c */; };
7373
75E09163241EA924004729E1 /* SDL_virtualjoystick_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 75E09159241EA924004729E1 /* SDL_virtualjoystick_c.h */; };
7474
89E5801E2D03602200DAF6D3 /* SDL_hidapi_lg4ff.c in Sources */ = {isa = PBXBuildFile; fileRef = 89E5801D2D03602200DAF6D3 /* SDL_hidapi_lg4ff.c */; };
75+
89E580232D03606400DAF6D3 /* SDL_hidapihaptic.c in Sources */ = {isa = PBXBuildFile; fileRef = 89E5801F2D03606400DAF6D3 /* SDL_hidapihaptic.c */; };
76+
89E580242D03606400DAF6D3 /* SDL_hidapihaptic_lg4ff.c in Sources */ = {isa = PBXBuildFile; fileRef = 89E580212D03606400DAF6D3 /* SDL_hidapihaptic_lg4ff.c */; };
77+
89E580252D03606400DAF6D3 /* SDL_hidapihaptic_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 89E580202D03606400DAF6D3 /* SDL_hidapihaptic_c.h */; };
7578
9846B07C287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */ = {isa = PBXBuildFile; fileRef = 9846B07B287A9020000C35C8 /* SDL_hidapi_shield.c */; };
7679
A1626A3E2617006A003F1973 /* SDL_triangle.c in Sources */ = {isa = PBXBuildFile; fileRef = A1626A3D2617006A003F1973 /* SDL_triangle.c */; };
7780
A1626A522617008D003F1973 /* SDL_triangle.h in Headers */ = {isa = PBXBuildFile; fileRef = A1626A512617008C003F1973 /* SDL_triangle.h */; };
@@ -625,6 +628,9 @@
625628
75E09158241EA924004729E1 /* SDL_virtualjoystick.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_virtualjoystick.c; sourceTree = "<group>"; };
626629
75E09159241EA924004729E1 /* SDL_virtualjoystick_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_virtualjoystick_c.h; sourceTree = "<group>"; };
627630
89E5801D2D03602200DAF6D3 /* SDL_hidapi_lg4ff.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_lg4ff.c; sourceTree = "<group>"; };
631+
89E5801F2D03606400DAF6D3 /* SDL_hidapihaptic.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_hidapihaptic.c; sourceTree = "<group>"; };
632+
89E580202D03606400DAF6D3 /* SDL_hidapihaptic_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_hidapihaptic_c.h; sourceTree = "<group>"; };
633+
89E580212D03606400DAF6D3 /* SDL_hidapihaptic_lg4ff.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_hidapihaptic_lg4ff.c; sourceTree = "<group>"; };
628634
9846B07B287A9020000C35C8 /* SDL_hidapi_shield.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_shield.c; sourceTree = "<group>"; };
629635
A1626A3D2617006A003F1973 /* SDL_triangle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_triangle.c; sourceTree = "<group>"; };
630636
A1626A512617008C003F1973 /* SDL_triangle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_triangle.h; sourceTree = "<group>"; };
@@ -1503,6 +1509,16 @@
15031509
path = virtual;
15041510
sourceTree = "<group>";
15051511
};
1512+
89E580222D03606400DAF6D3 /* hidapi */ = {
1513+
isa = PBXGroup;
1514+
children = (
1515+
89E5801F2D03606400DAF6D3 /* SDL_hidapihaptic.c */,
1516+
89E580202D03606400DAF6D3 /* SDL_hidapihaptic_c.h */,
1517+
89E580212D03606400DAF6D3 /* SDL_hidapihaptic_lg4ff.c */,
1518+
);
1519+
path = hidapi;
1520+
sourceTree = "<group>";
1521+
};
15061522
A75FDAA423E2790500529352 /* ios */ = {
15071523
isa = PBXGroup;
15081524
children = (
@@ -1561,6 +1577,7 @@
15611577
A7D8A5C223E2513D00DCD162 /* haptic */ = {
15621578
isa = PBXGroup;
15631579
children = (
1580+
89E580222D03606400DAF6D3 /* hidapi */,
15641581
A7D8A5CD23E2513D00DCD162 /* darwin */,
15651582
A7D8A5C323E2513D00DCD162 /* dummy */,
15661583
A7D8A5C623E2513D00DCD162 /* SDL_haptic_c.h */,
@@ -2604,6 +2621,7 @@
26042621
F31013C82C24E98200FBE946 /* SDL_keymap_c.h in Headers */,
26052622
63134A222A7902CF0021E9A6 /* SDL_pen.h in Headers */,
26062623
63134A252A7902FD0021E9A6 /* SDL_pen_c.h in Headers */,
2624+
89E580252D03606400DAF6D3 /* SDL_hidapihaptic_c.h in Headers */,
26072625
F36C34312C0F876500991150 /* SDL_offscreenvulkan.h in Headers */,
26082626
F3F7D9192933074E00816151 /* SDL_pixels.h in Headers */,
26092627
A7D8B2C023E2514200DCD162 /* SDL_pixels_c.h in Headers */,
@@ -2918,6 +2936,8 @@
29182936
A7D8BBDD23E2574800DCD162 /* SDL_uikitmodes.m in Sources */,
29192937
A7D8BA3723E2514400DCD162 /* SDL_d3dmath.c in Sources */,
29202938
F3A9AE9C2C8A13C100AAC390 /* SDL_pipeline_gpu.c in Sources */,
2939+
89E580232D03606400DAF6D3 /* SDL_hidapihaptic.c in Sources */,
2940+
89E580242D03606400DAF6D3 /* SDL_hidapihaptic_lg4ff.c in Sources */,
29212941
75E0915A241EA924004729E1 /* SDL_virtualjoystick.c in Sources */,
29222942
A7D8ABEB23E2514100DCD162 /* SDL_nullvideo.c in Sources */,
29232943
F3990E072A78833C000D8759 /* hid.m in Sources */,

cmake/sdlchecks.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,7 @@ macro(CheckHIDAPI)
11221122
set(HAVE_SDL_JOYSTICK TRUE)
11231123
set(HAVE_HIDAPI_JOYSTICK TRUE)
11241124
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/joystick/hidapi/*.c")
1125+
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/haptic/hidapi/*.c")
11251126
endif()
11261127
else()
11271128
set(SDL_HIDAPI_DISABLED 1)

src/haptic/SDL_haptic.c

Lines changed: 115 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
#include "SDL_internal.h"
2222

2323
#include "SDL_syshaptic.h"
24+
#ifdef SDL_JOYSTICK_HIDAPI
25+
#include "SDL_hidapihaptic.h"
26+
#endif //SDL_JOYSTICK_HIDAPI
2427
#include "SDL_haptic_c.h"
2528
#include "../joystick/SDL_joystick_c.h" // For SDL_IsJoystickValid
2629

@@ -34,7 +37,17 @@ static SDL_Haptic *SDL_haptics = NULL;
3437

3538
bool SDL_InitHaptics(void)
3639
{
37-
return SDL_SYS_HapticInit();
40+
if (!SDL_SYS_HapticInit()) {
41+
return false;
42+
}
43+
#ifdef SDL_JOYSTICK_HIDAPI
44+
if (!SDL_HIDAPI_HapticInit()) {
45+
SDL_SYS_HapticQuit();
46+
return false;
47+
}
48+
#endif //SDL_JOYSTICK_HIDAPI
49+
50+
return true;
3851
}
3952

4053
static bool SDL_GetHapticIndex(SDL_HapticID instance_id, int *driver_index)
@@ -127,7 +140,6 @@ SDL_Haptic *SDL_OpenHaptic(SDL_HapticID instance_id)
127140
}
128141

129142
// Initialize the haptic device
130-
SDL_SetObjectValid(haptic, SDL_OBJECT_TYPE_HAPTIC, true);
131143
haptic->instance_id = instance_id;
132144
haptic->rumble_id = -1;
133145
if (!SDL_SYS_HapticOpen(haptic)) {
@@ -156,6 +168,7 @@ SDL_Haptic *SDL_OpenHaptic(SDL_HapticID instance_id)
156168
SDL_SetHapticAutocenter(haptic, 0);
157169
}
158170

171+
SDL_SetObjectValid(haptic, SDL_OBJECT_TYPE_HAPTIC, true);
159172
return haptic;
160173
}
161174

@@ -216,7 +229,11 @@ bool SDL_IsJoystickHaptic(SDL_Joystick *joystick)
216229
// Must be a valid joystick
217230
if (SDL_IsJoystickValid(joystick) &&
218231
!SDL_IsGamepad(SDL_GetJoystickID(joystick))) {
232+
#ifdef SDL_JOYSTICK_HIDAPI
233+
result = SDL_SYS_JoystickIsHaptic(joystick) || SDL_HIDAPI_JoystickIsHaptic(joystick);
234+
#else //SDL_JOYSTICK_HIDAPI
219235
result = SDL_SYS_JoystickIsHaptic(joystick);
236+
#endif //SDL_JOYSTICK_HIDAPI
220237
}
221238
}
222239
SDL_UnlockJoysticks();
@@ -231,16 +248,8 @@ SDL_Haptic *SDL_OpenHapticFromJoystick(SDL_Joystick *joystick)
231248

232249
SDL_LockJoysticks();
233250
{
234-
// Must be a valid joystick
235-
if (!SDL_IsJoystickValid(joystick)) {
236-
SDL_SetError("Haptic: Joystick isn't valid.");
237-
SDL_UnlockJoysticks();
238-
return NULL;
239-
}
240-
241-
// Joystick must be haptic
242-
if (SDL_IsGamepad(SDL_GetJoystickID(joystick)) ||
243-
!SDL_SYS_JoystickIsHaptic(joystick)) {
251+
// Joystick must be valid and haptic
252+
if (!SDL_IsJoystickHaptic(joystick)) {
244253
SDL_SetError("Haptic: Joystick isn't a haptic device.");
245254
SDL_UnlockJoysticks();
246255
return NULL;
@@ -249,7 +258,11 @@ SDL_Haptic *SDL_OpenHapticFromJoystick(SDL_Joystick *joystick)
249258
hapticlist = SDL_haptics;
250259
// Check to see if joystick's haptic is already open
251260
while (hapticlist) {
261+
#ifdef SDL_JOYSTICK_HIDAPI
262+
if (SDL_SYS_JoystickSameHaptic(hapticlist, joystick) || SDL_HIDAPI_JoystickSameHaptic(hapticlist, joystick)) {
263+
#else
252264
if (SDL_SYS_JoystickSameHaptic(hapticlist, joystick)) {
265+
#endif //SDL_JOYSTICK_HIDAPI
253266
haptic = hapticlist;
254267
++haptic->ref_count;
255268
SDL_UnlockJoysticks();
@@ -269,6 +282,16 @@ SDL_Haptic *SDL_OpenHapticFromJoystick(SDL_Joystick *joystick)
269282
* This function should fill in the instance ID and name.
270283
*/
271284
haptic->rumble_id = -1;
285+
#ifdef SDL_JOYSTICK_HIDAPI
286+
if (SDL_HIDAPI_JoystickIsHaptic(joystick)) {
287+
if (!SDL_HIDAPI_HapticOpenFromJoystick(haptic, joystick)) {
288+
SDL_SetError("Haptic: SDL_HIDAPI_HapticOpenFromJoystick failed.");
289+
SDL_free(haptic);
290+
SDL_UnlockJoysticks();
291+
return NULL;
292+
}
293+
} else
294+
#endif //SDL_JOYSTICK_HIDAPI
272295
if (!SDL_SYS_HapticOpenFromJoystick(haptic, joystick)) {
273296
SDL_SetError("Haptic: SDL_SYS_HapticOpenFromJoystick failed.");
274297
SDL_free(haptic);
@@ -285,6 +308,7 @@ SDL_Haptic *SDL_OpenHapticFromJoystick(SDL_Joystick *joystick)
285308
haptic->next = SDL_haptics;
286309
SDL_haptics = haptic;
287310

311+
SDL_SetObjectValid(haptic, SDL_OBJECT_TYPE_HAPTIC, true);
288312
return haptic;
289313
}
290314

@@ -301,13 +325,20 @@ void SDL_CloseHaptic(SDL_Haptic *haptic)
301325
return;
302326
}
303327

304-
// Close it, properly removing effects if needed
305-
for (i = 0; i < haptic->neffects; i++) {
306-
if (haptic->effects[i].hweffect != NULL) {
307-
SDL_DestroyHapticEffect(haptic, i);
328+
#ifdef SDL_JOYSTICK_HIDAPI
329+
if (SDL_HIDAPI_HapticIsHidapi(haptic)) {
330+
SDL_HIDAPI_HapticClose(haptic);
331+
} else
332+
#endif //SDL_JOYSTICK_HIDAPI
333+
{
334+
// Close it, properly removing effects if needed
335+
for (i = 0; i < haptic->neffects; i++) {
336+
if (haptic->effects[i].hweffect != NULL) {
337+
SDL_DestroyHapticEffect(haptic, i);
338+
}
308339
}
340+
SDL_SYS_HapticClose(haptic);
309341
}
310-
SDL_SYS_HapticClose(haptic);
311342
SDL_SetObjectValid(haptic, SDL_OBJECT_TYPE_HAPTIC, false);
312343

313344
// Remove from the list
@@ -339,6 +370,7 @@ void SDL_QuitHaptics(void)
339370
SDL_CloseHaptic(SDL_haptics);
340371
}
341372

373+
SDL_HIDAPI_HapticQuit();
342374
SDL_SYS_HapticQuit();
343375
}
344376

@@ -401,6 +433,12 @@ int SDL_CreateHapticEffect(SDL_Haptic *haptic, const SDL_HapticEffect *effect)
401433
return -1;
402434
}
403435

436+
#ifdef SDL_JOYSTICK_HIDAPI
437+
if (SDL_HIDAPI_HapticIsHidapi(haptic)) {
438+
return SDL_HIDAPI_HapticNewEffect(haptic, effect);
439+
}
440+
#endif //SDL_JOYSTICK_HIDAPI
441+
404442
// See if there's a free slot
405443
for (i = 0; i < haptic->neffects; i++) {
406444
if (haptic->effects[i].hweffect == NULL) {
@@ -433,6 +471,12 @@ bool SDL_UpdateHapticEffect(SDL_Haptic *haptic, int effect, const SDL_HapticEffe
433471
{
434472
CHECK_HAPTIC_MAGIC(haptic, false);
435473

474+
#ifdef SDL_JOYSTICK_HIDAPI
475+
if (SDL_HIDAPI_HapticIsHidapi(haptic)) {
476+
return SDL_HIDAPI_HapticUpdateEffect(haptic, effect, data);
477+
}
478+
#endif //SDL_JOYSTICK_HIDAPI
479+
436480
if (!ValidEffect(haptic, effect)) {
437481
return false;
438482
}
@@ -460,6 +504,12 @@ bool SDL_RunHapticEffect(SDL_Haptic *haptic, int effect, Uint32 iterations)
460504
{
461505
CHECK_HAPTIC_MAGIC(haptic, false);
462506

507+
#ifdef SDL_JOYSTICK_HIDAPI
508+
if (SDL_HIDAPI_HapticIsHidapi(haptic)) {
509+
return SDL_HIDAPI_HapticRunEffect(haptic, effect, iterations);
510+
}
511+
#endif //SDL_JOYSTICK_HIDAPI
512+
463513
if (!ValidEffect(haptic, effect)) {
464514
return false;
465515
}
@@ -476,6 +526,12 @@ bool SDL_StopHapticEffect(SDL_Haptic *haptic, int effect)
476526
{
477527
CHECK_HAPTIC_MAGIC(haptic, false);
478528

529+
#ifdef SDL_JOYSTICK_HIDAPI
530+
if (SDL_HIDAPI_HapticIsHidapi(haptic)) {
531+
return SDL_HIDAPI_HapticStopEffect(haptic, effect);
532+
}
533+
#endif //SDL_JOYSTICK_HIDAPI
534+
479535
if (!ValidEffect(haptic, effect)) {
480536
return false;
481537
}
@@ -492,6 +548,12 @@ void SDL_DestroyHapticEffect(SDL_Haptic *haptic, int effect)
492548
{
493549
CHECK_HAPTIC_MAGIC(haptic,);
494550

551+
#ifdef SDL_JOYSTICK_HIDAPI
552+
if (SDL_HIDAPI_HapticIsHidapi(haptic)) {
553+
return SDL_HIDAPI_HapticDestroyEffect(haptic, effect);
554+
}
555+
#endif //SDL_JOYSTICK_HIDAPI
556+
495557
if (!ValidEffect(haptic, effect)) {
496558
return;
497559
}
@@ -508,6 +570,12 @@ bool SDL_GetHapticEffectStatus(SDL_Haptic *haptic, int effect)
508570
{
509571
CHECK_HAPTIC_MAGIC(haptic, false);
510572

573+
#ifdef SDL_JOYSTICK_HIDAPI
574+
if (SDL_HIDAPI_HapticIsHidapi(haptic)) {
575+
return SDL_HIDAPI_HapticGetEffectStatus(haptic, effect);
576+
}
577+
#endif //SDL_JOYSTICK_HIDAPI
578+
511579
if (!ValidEffect(haptic, effect)) {
512580
return false;
513581
}
@@ -554,6 +622,12 @@ bool SDL_SetHapticGain(SDL_Haptic *haptic, int gain)
554622
real_gain = gain;
555623
}
556624

625+
#ifdef SDL_JOYSTICK_HIDAPI
626+
if (SDL_HIDAPI_HapticIsHidapi(haptic)) {
627+
return SDL_HIDAPI_HapticSetGain(haptic, real_gain);
628+
}
629+
#endif //SDL_JOYSTICK_HIDAPI
630+
557631
return SDL_SYS_HapticSetGain(haptic, real_gain);
558632
}
559633

@@ -569,6 +643,12 @@ bool SDL_SetHapticAutocenter(SDL_Haptic *haptic, int autocenter)
569643
return SDL_SetError("Haptic: Autocenter must be between 0 and 100.");
570644
}
571645

646+
#ifdef SDL_JOYSTICK_HIDAPI
647+
if (SDL_HIDAPI_HapticIsHidapi(haptic)) {
648+
return SDL_HIDAPI_HapticSetAutocenter(haptic, autocenter);
649+
}
650+
#endif //SDL_JOYSTICK_HIDAPI
651+
572652
return SDL_SYS_HapticSetAutocenter(haptic, autocenter);
573653
}
574654

@@ -580,6 +660,12 @@ bool SDL_PauseHaptic(SDL_Haptic *haptic)
580660
return SDL_SetError("Haptic: Device does not support setting pausing.");
581661
}
582662

663+
#ifdef SDL_JOYSTICK_HIDAPI
664+
if (SDL_HIDAPI_HapticIsHidapi(haptic)) {
665+
return SDL_HIDAPI_HapticPause(haptic);
666+
}
667+
#endif //SDL_JOYSTICK_HIDAPI
668+
583669
return SDL_SYS_HapticPause(haptic);
584670
}
585671

@@ -591,13 +677,25 @@ bool SDL_ResumeHaptic(SDL_Haptic *haptic)
591677
return true; // Not going to be paused, so we pretend it's unpaused.
592678
}
593679

680+
#ifdef SDL_JOYSTICK_HIDAPI
681+
if (SDL_HIDAPI_HapticIsHidapi(haptic)) {
682+
return SDL_HIDAPI_HapticResume(haptic);
683+
}
684+
#endif //SDL_JOYSTICK_HIDAPI
685+
594686
return SDL_SYS_HapticResume(haptic);
595687
}
596688

597689
bool SDL_StopHapticEffects(SDL_Haptic *haptic)
598690
{
599691
CHECK_HAPTIC_MAGIC(haptic, false);
600692

693+
#ifdef SDL_JOYSTICK_HIDAPI
694+
if (SDL_HIDAPI_HapticIsHidapi(haptic)) {
695+
return SDL_HIDAPI_HapticStopAll(haptic);
696+
}
697+
#endif //SDL_JOYSTICK_HIDAPI
698+
601699
return SDL_SYS_HapticStopAll(haptic);
602700
}
603701

0 commit comments

Comments
 (0)