Add SDL_HINT_JOYSTICK_HAPTIC_AXES

Allows users to overwrite the number of haptic axes defined for a given
joystick. Also supports a "wildcard" VID:PID of `0xFFFF/0xFFFF`
This commit is contained in:
Tomasz Pakuła 2025-02-20 19:48:51 +01:00 committed by Sam Lantinga
parent db817a37f4
commit 58388e8db4
2 changed files with 113 additions and 0 deletions

View file

@ -2191,6 +2191,28 @@ extern "C" {
*/ */
#define SDL_HINT_JOYSTICK_ZERO_CENTERED_DEVICES "SDL_JOYSTICK_ZERO_CENTERED_DEVICES" #define SDL_HINT_JOYSTICK_ZERO_CENTERED_DEVICES "SDL_JOYSTICK_ZERO_CENTERED_DEVICES"
/**
* A variable containing a list of devices and their desired number of haptic
* (force feedback) enabled axis.
*
* The format of the string is a comma separated list of USB VID/PID pairs in
* hexadecimal form plus the number of desired axes, e.g.
*
* `0xAAAA/0xBBBB/1,0xCCCC/0xDDDD/3`
*
* This hint supports a "wildcard" device that will set the number of haptic
* axes on all initialized haptic devices which were not defined explicitly
* in this hint.
*
* `0xFFFF/0xFFFF/1`
*
* This hint should be set before a controller is opened. The number of
* haptic axes won't exceed the number of real axes found on the device.
*
* \since This hint is available since SDL 3.2.5.
*/
#define SDL_HINT_JOYSTICK_HAPTIC_AXES "SDL_JOYSTICK_HAPTIC_AXES"
/** /**
* A variable that controls keycode representation in keyboard events. * A variable that controls keycode representation in keyboard events.
* *

View file

@ -23,6 +23,84 @@
#include "SDL_syshaptic.h" #include "SDL_syshaptic.h"
#include "SDL_haptic_c.h" #include "SDL_haptic_c.h"
#include "../joystick/SDL_joystick_c.h" // For SDL_IsJoystickValid #include "../joystick/SDL_joystick_c.h" // For SDL_IsJoystickValid
#include "../SDL_hints_c.h"
typedef struct SDL_Haptic_VIDPID_Naxes {
Uint16 vid;
Uint16 pid;
Uint16 naxes;
} SDL_Haptic_VIDPID_Naxes;
static void SDL_Haptic_Load_Axes_List(SDL_Haptic_VIDPID_Naxes **entries, int *num_entries)
{
SDL_Haptic_VIDPID_Naxes entry;
const char *spot;
int length = 0;
spot = SDL_GetHint(SDL_HINT_JOYSTICK_HAPTIC_AXES);
if (!spot)
return;
while (SDL_sscanf(spot, "0x%hx/0x%hx/%hu%n", &entry.vid, &entry.pid, &entry.naxes, &length) == 3) {
SDL_assert(length > 0);
spot += length;
length = 0;
if ((*num_entries % 8) == 0) {
int new_max = *num_entries + 8;
SDL_Haptic_VIDPID_Naxes *new_entries =
(SDL_Haptic_VIDPID_Naxes *)SDL_realloc(*entries, new_max * sizeof(**entries));
// Out of memory, go with what we have already
if (!new_entries)
break;
*entries = new_entries;
}
(*entries)[(*num_entries)++] = entry;
if (spot[0] == ',')
spot++;
}
}
// /* Return -1 if not found */
static int SDL_Haptic_Naxes_List_Index(struct SDL_Haptic_VIDPID_Naxes *entries, int num_entries, Uint16 vid, Uint16 pid)
{
if (!entries)
return -1;
int i;
for (i = 0; i < num_entries; ++i) {
if (entries[i].vid == vid && entries[i].pid == pid)
return i;
}
return -1;
}
// Check if device needs a custom number of naxes
static int SDL_Haptic_Get_Naxes(Uint16 vid, Uint16 pid)
{
int num_entries = 0, index = 0, naxes = -1;
SDL_Haptic_VIDPID_Naxes *naxes_list = NULL;
SDL_Haptic_Load_Axes_List(&naxes_list, &num_entries);
if (!num_entries || !naxes_list)
return -1;
// Perform "wildcard" pass
index = SDL_Haptic_Naxes_List_Index(naxes_list, num_entries, 0xffff, 0xffff);
if (index >= 0)
naxes = naxes_list[index].naxes;
index = SDL_Haptic_Naxes_List_Index(naxes_list, num_entries, vid, pid);
if (index >= 0)
naxes = naxes_list[index].naxes;
SDL_free(naxes_list);
return naxes;
}
static SDL_Haptic *SDL_haptics = NULL; static SDL_Haptic *SDL_haptics = NULL;
@ -282,6 +360,19 @@ SDL_Haptic *SDL_OpenHapticFromJoystick(SDL_Joystick *joystick)
} }
SDL_UnlockJoysticks(); SDL_UnlockJoysticks();
// Check if custom number of haptic axes was defined
Uint16 vid = SDL_GetJoystickVendor(joystick);
Uint16 pid = SDL_GetJoystickProduct(joystick);
int general_axes = SDL_GetNumJoystickAxes(joystick);
int naxes = SDL_Haptic_Get_Naxes(vid, pid);
if (naxes > 0)
haptic->naxes = naxes;
// Limit to the actual number of axes found on the device
if (general_axes >= 0 && naxes > general_axes)
haptic->naxes = general_axes;
// Add haptic to list // Add haptic to list
++haptic->ref_count; ++haptic->ref_count;
// Link the haptic in the list // Link the haptic in the list