Jelajahi Sumber

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`
Tomasz Pakuła 1 bulan lalu
induk
melakukan
58388e8db4
2 mengubah file dengan 113 tambahan dan 0 penghapusan
  1. 22 0
      include/SDL3/SDL_hints.h
  2. 91 0
      src/haptic/SDL_haptic.c

+ 22 - 0
include/SDL3/SDL_hints.h

@@ -2191,6 +2191,28 @@ extern "C" {
  */
 #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.
  *

+ 91 - 0
src/haptic/SDL_haptic.c

@@ -23,6 +23,84 @@
 #include "SDL_syshaptic.h"
 #include "SDL_haptic_c.h"
 #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;
 
@@ -282,6 +360,19 @@ SDL_Haptic *SDL_OpenHapticFromJoystick(SDL_Joystick *joystick)
     }
     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
     ++haptic->ref_count;
     // Link the haptic in the list