Browse Source

Improve sensor detection for Linux gamepad

meyraud705 1 year ago
parent
commit
9cfac88054
4 changed files with 55 additions and 15 deletions
  1. 13 0
      src/SDL_utils.c
  2. 2 0
      src/SDL_utils_c.h
  3. 1 15
      src/joystick/SDL_gamepad.c
  4. 39 0
      src/joystick/linux/SDL_sysjoystick.c

+ 13 - 0
src/SDL_utils.c

@@ -48,3 +48,16 @@ int SDL_powerof2(int x)
 
     return value;
 }
+
+SDL_bool SDL_endswith(const char *string, const char *suffix)
+{
+    size_t string_length = string ? SDL_strlen(string) : 0;
+    size_t suffix_length = suffix ? SDL_strlen(suffix) : 0;
+
+    if (suffix_length > 0 && suffix_length <= string_length) {
+        if (SDL_memcmp(string + string_length - suffix_length, suffix, suffix_length) == 0) {
+            return SDL_TRUE;
+        }
+    }
+    return SDL_FALSE;
+}

+ 2 - 0
src/SDL_utils_c.h

@@ -28,4 +28,6 @@
 /* Return the smallest power of 2 greater than or equal to 'x' */
 extern int SDL_powerof2(int x);
 
+SDL_bool SDL_endswith(const char *string, const char *suffix);
+
 #endif /* SDL_utils_h_ */

+ 1 - 15
src/joystick/SDL_gamepad.c

@@ -22,6 +22,7 @@
 
 /* This is the gamepad API for Simple DirectMedia Layer */
 
+#include "../SDL_utils_c.h"
 #include "SDL_sysjoystick.h"
 #include "SDL_joystick_c.h"
 #include "SDL_gamepad_c.h"
@@ -2069,21 +2070,6 @@ SDL_bool SDL_IsGamepad(SDL_JoystickID instance_id)
     return retval;
 }
 
-#ifdef __LINUX__
-static SDL_bool SDL_endswith(const char *string, const char *suffix)
-{
-    size_t string_length = string ? SDL_strlen(string) : 0;
-    size_t suffix_length = suffix ? SDL_strlen(suffix) : 0;
-
-    if (suffix_length > 0 && suffix_length <= string_length) {
-        if (SDL_memcmp(string + string_length - suffix_length, suffix, suffix_length) == 0) {
-            return SDL_TRUE;
-        }
-    }
-    return SDL_FALSE;
-}
-#endif
-
 /*
  * Return 1 if the gamepad should be ignored by SDL
  */

+ 39 - 0
src/joystick/linux/SDL_sysjoystick.c

@@ -41,6 +41,7 @@
 #include <dirent.h>
 #include <linux/joystick.h>
 
+#include "../../SDL_utils_c.h"
 #include "../../events/SDL_events_c.h"
 #include "../../core/linux/SDL_evdev.h"
 #include "../SDL_sysjoystick.h"
@@ -323,6 +324,44 @@ static int IsJoystick(const char *path, int fd, char **name_return, SDL_Joystick
 
 static int IsSensor(const char *path, int fd)
 {
+    struct input_id inpid;
+    char *name;
+    char product_string[128];
+
+    if (ioctl(fd, EVIOCGID, &inpid) < 0) {
+        return 0;
+    }
+
+    if (ioctl(fd, EVIOCGNAME(sizeof(product_string)), product_string) < 0) {
+        return 0;
+    }
+
+    name = SDL_CreateJoystickName(inpid.vendor, inpid.product, NULL, product_string);
+    if (name == NULL) {
+        return 0;
+    }
+
+    if (SDL_endswith(name, " Motion Sensors")) {
+        /* PS3 and PS4 motion controls */
+        SDL_free(name);
+        return 1;
+    }
+    if (SDL_strncmp(name, "Nintendo ", 9) == 0 && SDL_strstr(name, " IMU") != NULL) {
+        /* Nintendo Switch Joy-Con and Pro Controller IMU */
+        SDL_free(name);
+        return 1;
+    }
+    if (SDL_endswith(name, " Accelerometer") ||
+        SDL_endswith(name, " IR") ||
+        SDL_endswith(name, " Motion Plus") ||
+        SDL_endswith(name, " Nunchuk")) {
+        /* Wii extension controls */
+        /* These may create 3 sensor devices but we only support reading from 1: ignore them */
+        SDL_free(name);
+        return 0;
+    }
+
+    SDL_free(name);
     return GuessIsSensor(fd);
 }