Răsfoiți Sursa

Automatically assign player indexes to game controllers, and allow changing the player index for game controllers and joysticks.
Added the functions SDL_JoystickFromPlayerIndex(), SDL_JoystickSetPlayerIndex(), SDL_GameControllerFromPlayerIndex(), and SDL_GameControllerSetPlayerIndex()

Sam Lantinga 5 ani în urmă
părinte
comite
46e1377d49

+ 10 - 0
include/SDL_gamecontroller.h

@@ -214,6 +214,11 @@ extern DECLSPEC SDL_GameController *SDLCALL SDL_GameControllerOpen(int joystick_
  */
 extern DECLSPEC SDL_GameController *SDLCALL SDL_GameControllerFromInstanceID(SDL_JoystickID joyid);
 
+/**
+ * Return the SDL_GameController associated with a player index.
+ */
+extern DECLSPEC SDL_GameController *SDLCALL SDL_GameControllerFromPlayerIndex(int player_index);
+
 /**
  *  Return the name for this currently opened controller
  */
@@ -231,6 +236,11 @@ extern DECLSPEC SDL_GameControllerType SDLCALL SDL_GameControllerGetType(SDL_Gam
  */
 extern DECLSPEC int SDLCALL SDL_GameControllerGetPlayerIndex(SDL_GameController *gamecontroller);
 
+/**
+ *  Set the player index of an opened game controller
+ */
+extern DECLSPEC void SDLCALL SDL_GameControllerSetPlayerIndex(SDL_GameController *gamecontroller, int player_index);
+
 /**
  *  Get the USB vendor ID of an opened controller, if available.
  *  If the vendor ID isn't available this function returns 0.

+ 11 - 1
include/SDL_joystick.h

@@ -192,7 +192,12 @@ extern DECLSPEC SDL_Joystick *SDLCALL SDL_JoystickOpen(int device_index);
 /**
  * Return the SDL_Joystick associated with an instance id.
  */
-extern DECLSPEC SDL_Joystick *SDLCALL SDL_JoystickFromInstanceID(SDL_JoystickID joyid);
+extern DECLSPEC SDL_Joystick *SDLCALL SDL_JoystickFromInstanceID(SDL_JoystickID instance_id);
+
+/**
+ * Return the SDL_Joystick associated with a player index.
+ */
+extern DECLSPEC SDL_Joystick *SDLCALL SDL_JoystickFromPlayerIndex(int player_index);
 
 /**
  *  Return the name for this currently opened joystick.
@@ -207,6 +212,11 @@ extern DECLSPEC const char *SDLCALL SDL_JoystickName(SDL_Joystick * joystick);
  */
 extern DECLSPEC int SDLCALL SDL_JoystickGetPlayerIndex(SDL_Joystick * joystick);
 
+/**
+ *  Set the player index of an opened joystick
+ */
+extern DECLSPEC void SDLCALL SDL_JoystickSetPlayerIndex(SDL_Joystick * joystick, int player_index);
+
 /**
  *  Return the GUID for this opened joystick
  */

+ 4 - 0
src/dynapi/SDL_dynapi_overrides.h

@@ -733,3 +733,7 @@
 #define SDL_wcsncmp SDL_wcsncmp_REAL
 #define SDL_GameControllerTypeForIndex SDL_GameControllerTypeForIndex_REAL
 #define SDL_GameControllerGetType SDL_GameControllerGetType_REAL
+#define SDL_GameControllerFromPlayerIndex SDL_GameControllerFromPlayerIndex_REAL
+#define SDL_GameControllerSetPlayerIndex SDL_GameControllerSetPlayerIndex_REAL
+#define SDL_JoystickFromPlayerIndex SDL_JoystickFromPlayerIndex_REAL
+#define SDL_JoystickSetPlayerIndex SDL_JoystickSetPlayerIndex_REAL

+ 4 - 0
src/dynapi/SDL_dynapi_procs.h

@@ -789,3 +789,7 @@ SDL_DYNAPI_PROC(wchar_t*,SDL_wcsstr,(const wchar_t *a, const wchar_t *b),(a,b),r
 SDL_DYNAPI_PROC(int,SDL_wcsncmp,(const wchar_t *a, const wchar_t *b, size_t c),(a,b,c),return)
 SDL_DYNAPI_PROC(SDL_GameControllerType,SDL_GameControllerTypeForIndex,(int a),(a),return)
 SDL_DYNAPI_PROC(SDL_GameControllerType,SDL_GameControllerGetType,(SDL_GameController *a),(a),return)
+SDL_DYNAPI_PROC(SDL_GameController*,SDL_GameControllerFromPlayerIndex,(int a),(a),return)
+SDL_DYNAPI_PROC(void,SDL_GameControllerSetPlayerIndex,(SDL_GameController *a, int b),(a,b),)
+SDL_DYNAPI_PROC(SDL_Joystick*,SDL_JoystickFromPlayerIndex,(int a),(a),return)
+SDL_DYNAPI_PROC(void,SDL_JoystickSetPlayerIndex,(SDL_Joystick *a, int b),(a,b),)

+ 23 - 1
src/joystick/SDL_gamecontroller.c

@@ -1765,6 +1765,15 @@ SDL_GameControllerGetPlayerIndex(SDL_GameController *gamecontroller)
     return SDL_JoystickGetPlayerIndex(SDL_GameControllerGetJoystick(gamecontroller));
 }
 
+/**
+ *  Set the player index of an opened game controller
+ */
+void
+SDL_GameControllerSetPlayerIndex(SDL_GameController *gamecontroller, int player_index)
+{
+    SDL_JoystickSetPlayerIndex(SDL_GameControllerGetJoystick(gamecontroller), player_index);
+}
+
 Uint16
 SDL_GameControllerGetVendor(SDL_GameController * gamecontroller)
 {
@@ -1809,7 +1818,7 @@ SDL_Joystick *SDL_GameControllerGetJoystick(SDL_GameController * gamecontroller)
 
 
 /*
- * Find the SDL_GameController that owns this instance id
+ * Return the SDL_GameController associated with an instance id.
  */
 SDL_GameController *
 SDL_GameControllerFromInstanceID(SDL_JoystickID joyid)
@@ -1830,6 +1839,19 @@ SDL_GameControllerFromInstanceID(SDL_JoystickID joyid)
 }
 
 
+/**
+ * Return the SDL_GameController associated with a player index.
+ */
+SDL_GameController *SDL_GameControllerFromPlayerIndex(int player_index)
+{
+    SDL_Joystick *joystick = SDL_JoystickFromPlayerIndex(player_index);
+    if (joystick) {
+        return SDL_GameControllerFromInstanceID(joystick->instance_id);
+    }
+    return NULL;
+}
+
+
 /*
  * Get the SDL joystick layer binding for this controller axis mapping
  */

+ 165 - 23
src/joystick/SDL_joystick.c

@@ -83,6 +83,8 @@ static SDL_Joystick *SDL_joysticks = NULL;
 static SDL_bool SDL_updating_joystick = SDL_FALSE;
 static SDL_mutex *SDL_joystick_lock = NULL; /* This needs to support recursive locks */
 static SDL_atomic_t SDL_next_joystick_instance_id;
+static int SDL_joystick_player_count = 0;
+static SDL_JoystickID *SDL_joystick_players = NULL;
 
 void
 SDL_LockJoysticks(void)
@@ -100,6 +102,81 @@ SDL_UnlockJoysticks(void)
     }
 }
 
+static int
+SDL_FindFreePlayerIndex()
+{
+    int player_index;
+
+    for (player_index = 0; player_index < SDL_joystick_player_count; ++player_index) {
+        if (SDL_joystick_players[player_index] == -1) {
+            return player_index;
+        }
+    }
+    return player_index;
+}
+
+static int
+SDL_GetPlayerIndexForJoystickID(SDL_JoystickID instance_id)
+{
+    int player_index;
+
+    for (player_index = 0; player_index < SDL_joystick_player_count; ++player_index) {
+        if (instance_id == SDL_joystick_players[player_index]) {
+            break;
+        }
+    }
+    if (player_index == SDL_joystick_player_count) {
+        player_index = -1;
+    }
+    return player_index;
+}
+
+static SDL_JoystickID
+SDL_GetJoystickIDForPlayerIndex(int player_index)
+{
+    if (player_index < 0 || player_index >= SDL_joystick_player_count) {
+        return -1;
+    }
+    return SDL_joystick_players[player_index];
+}
+
+static SDL_bool
+SDL_SetJoystickIDForPlayerIndex(int player_index, SDL_JoystickID instance_id)
+{
+    SDL_JoystickID existing_instance = SDL_GetJoystickIDForPlayerIndex(player_index);
+    SDL_JoystickDriver *driver;
+    int device_index;
+
+    if (player_index < 0) {
+        return SDL_FALSE;
+    }
+    if (player_index >= SDL_joystick_player_count) {
+        SDL_JoystickID *new_players = (SDL_JoystickID *)SDL_realloc(SDL_joystick_players, (player_index + 1)*sizeof(*SDL_joystick_players));
+        if (!new_players) {
+            SDL_OutOfMemory();
+            return SDL_FALSE;
+        }
+
+        SDL_joystick_players = new_players;
+        while (SDL_joystick_player_count <= player_index) {
+            SDL_joystick_players[SDL_joystick_player_count++] = -1;
+        }
+    }
+
+    SDL_joystick_players[player_index] = instance_id;
+
+    /* Update the driver with the new index */
+    device_index = SDL_JoystickGetDeviceIndexFromInstanceID(instance_id);
+    if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
+        driver->SetDevicePlayerIndex(device_index, player_index);
+    }
+
+    /* Move any existing joystick to another slot */
+    if (existing_instance >= 0) {
+        SDL_SetJoystickIDForPlayerIndex(SDL_FindFreePlayerIndex(), existing_instance);
+    }
+    return SDL_TRUE;
+}
 
 static void SDLCALL
 SDL_JoystickAllowBackgroundEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
@@ -228,16 +305,16 @@ SDL_JoystickNameForIndex(int device_index)
     return name;
 }
 
+/*
+ *  Get the player index of a joystick, or -1 if it's not available
+ */
 int
 SDL_JoystickGetDevicePlayerIndex(int device_index)
 {
-    SDL_JoystickDriver *driver;
-    int player_index = -1;
+    int player_index;
 
     SDL_LockJoysticks();
-    if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
-        player_index = driver->GetDevicePlayerIndex(device_index);
-    }
+    player_index = SDL_GetPlayerIndexForJoystickID(SDL_JoystickGetDeviceInstanceID(device_index));
     SDL_UnlockJoysticks();
 
     return player_index;
@@ -323,7 +400,6 @@ SDL_JoystickOpen(int device_index)
     joystick->driver = driver;
     joystick->instance_id = instance_id;
     joystick->attached = SDL_TRUE;
-    joystick->player_index = -1;
     joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
 
     if (driver->Open(joystick, device_index) < 0) {
@@ -391,16 +467,16 @@ SDL_JoystickOpen(int device_index)
 /*
  * Checks to make sure the joystick is valid.
  */
-int
+SDL_bool
 SDL_PrivateJoystickValid(SDL_Joystick * joystick)
 {
-    int valid;
+    SDL_bool valid;
 
     if (joystick == NULL) {
         SDL_SetError("Joystick hasn't been opened yet");
-        valid = 0;
+        valid = SDL_FALSE;
     } else {
-        valid = 1;
+        valid = SDL_TRUE;
     }
 
     return valid;
@@ -589,16 +665,36 @@ SDL_JoystickInstanceID(SDL_Joystick * joystick)
 }
 
 /*
- * Find the SDL_Joystick that owns this instance id
+ * Return the SDL_Joystick associated with an instance id.
  */
 SDL_Joystick *
-SDL_JoystickFromInstanceID(SDL_JoystickID joyid)
+SDL_JoystickFromInstanceID(SDL_JoystickID instance_id)
 {
     SDL_Joystick *joystick;
 
     SDL_LockJoysticks();
     for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
-        if (joystick->instance_id == joyid) {
+        if (joystick->instance_id == instance_id) {
+            break;
+        }
+    }
+    SDL_UnlockJoysticks();
+    return joystick;
+}
+
+/**
+ * Return the SDL_Joystick associated with a player index.
+ */
+SDL_Joystick *
+SDL_JoystickFromPlayerIndex(int player_index)
+{
+    SDL_JoystickID instance_id;
+    SDL_Joystick *joystick;
+
+    SDL_LockJoysticks();
+    instance_id = SDL_GetJoystickIDForPlayerIndex(player_index);
+    for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
+        if (joystick->instance_id == instance_id) {
             break;
         }
     }
@@ -619,13 +715,38 @@ SDL_JoystickName(SDL_Joystick * joystick)
     return SDL_FixupJoystickName(joystick->name);
 }
 
+/**
+ *  Get the player index of an opened joystick, or -1 if it's not available
+ */
 int
 SDL_JoystickGetPlayerIndex(SDL_Joystick * joystick)
 {
+    int player_index;
+
     if (!SDL_PrivateJoystickValid(joystick)) {
         return -1;
     }
-    return joystick->player_index;
+
+    SDL_LockJoysticks();
+    player_index = SDL_GetPlayerIndexForJoystickID(joystick->instance_id);
+    SDL_UnlockJoysticks();
+
+    return player_index;
+}
+
+/**
+ *  Set the player index of an opened joystick
+ */
+void
+SDL_JoystickSetPlayerIndex(SDL_Joystick * joystick, int player_index)
+{
+    if (!SDL_PrivateJoystickValid(joystick)) {
+        return;
+    }
+
+    SDL_LockJoysticks();
+    SDL_SetJoystickIDForPlayerIndex(player_index, joystick->instance_id);
+    SDL_UnlockJoysticks();
 }
 
 int
@@ -718,6 +839,11 @@ SDL_JoystickQuit(void)
        SDL_joystick_drivers[i]->Quit();
     }
 
+    if (SDL_joystick_players) {
+        SDL_free(SDL_joystick_players);
+        SDL_joystick_players = NULL;
+        SDL_joystick_player_count = 0;
+    }
     SDL_UnlockJoysticks();
 
 #if !SDL_EVENTS_DISABLED
@@ -755,20 +881,36 @@ SDL_PrivateJoystickShouldIgnoreEvent()
 
 void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance)
 {
-#if !SDL_EVENTS_DISABLED
-    SDL_Event event;
-    int device_index;
-
-    device_index = SDL_JoystickGetDeviceIndexFromInstanceID(device_instance);
+    SDL_JoystickDriver *driver;
+    int driver_device_index;
+    int player_index = -1;
+    int device_index = SDL_JoystickGetDeviceIndexFromInstanceID(device_instance);
     if (device_index < 0) {
         return;
     }
 
-    event.type = SDL_JOYDEVICEADDED;
+    SDL_LockJoysticks();
+    if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &driver_device_index)) {
+        player_index = driver->GetDevicePlayerIndex(driver_device_index);
+    }
+    if (player_index < 0 && SDL_IsGameController(device_index)) {
+        player_index = SDL_FindFreePlayerIndex();
+    }
+    if (player_index >= 0) {
+        SDL_SetJoystickIDForPlayerIndex(player_index, device_instance);
+    }
+    SDL_UnlockJoysticks();
 
-    if (SDL_GetEventState(event.type) == SDL_ENABLE) {
-        event.jdevice.which = device_index;
-        SDL_PushEvent(&event);
+#if !SDL_EVENTS_DISABLED
+    {
+        SDL_Event event;
+
+        event.type = SDL_JOYDEVICEADDED;
+
+        if (SDL_GetEventState(event.type) == SDL_ENABLE) {
+            event.jdevice.which = device_index;
+            SDL_PushEvent(&event);
+        }
     }
 #endif /* !SDL_EVENTS_DISABLED */
 }

+ 1 - 1
src/joystick/SDL_joystick_c.h

@@ -101,7 +101,7 @@ extern void SDL_PrivateJoystickBatteryLevel(SDL_Joystick * joystick,
                                             SDL_JoystickPowerLevel ePowerLevel);
 
 /* Internal sanity checking functions */
-extern int SDL_PrivateJoystickValid(SDL_Joystick * joystick);
+extern SDL_bool SDL_PrivateJoystickValid(SDL_Joystick * joystick);
 
 #endif /* SDL_joystick_c_h_ */
 

+ 3 - 1
src/joystick/SDL_sysjoystick.h

@@ -43,7 +43,6 @@ struct _SDL_Joystick
 {
     SDL_JoystickID instance_id; /* Device instance, monotonically increasing from 0 */
     char *name;                 /* Joystick name - system dependent */
-    int player_index;           /* Joystick player index, or -1 if unavailable */
     SDL_JoystickGUID guid;      /* Joystick guid */
 
     int naxes;                  /* Number of axis controls on the joystick */
@@ -110,6 +109,9 @@ typedef struct _SDL_JoystickDriver
     /* Function to get the player index of a joystick */
     int (*GetDevicePlayerIndex)(int device_index);
 
+    /* Function to get the player index of a joystick */
+    void (*SetDevicePlayerIndex)(int device_index, int player_index);
+
     /* Function to return the stable GUID for a plugged in device */
     SDL_JoystickGUID (*GetDeviceGUID)(int device_index);
 

+ 6 - 0
src/joystick/android/SDL_sysjoystick.c

@@ -587,6 +587,11 @@ ANDROID_JoystickGetDevicePlayerIndex(int device_index)
     return -1;
 }
 
+static void
+ANDROID_JoystickSetDevicePlayerIndex(int device_index, int player_index)
+{
+}
+
 static SDL_JoystickGUID
 ANDROID_JoystickGetDeviceGUID(int device_index)
 {
@@ -696,6 +701,7 @@ SDL_JoystickDriver SDL_ANDROID_JoystickDriver =
     ANDROID_JoystickDetect,
     ANDROID_JoystickGetDeviceName,
     ANDROID_JoystickGetDevicePlayerIndex,
+    ANDROID_JoystickSetDevicePlayerIndex,
     ANDROID_JoystickGetDeviceGUID,
     ANDROID_JoystickGetDeviceInstanceID,
     ANDROID_JoystickOpen,

+ 6 - 0
src/joystick/bsd/SDL_sysjoystick.c

@@ -276,6 +276,11 @@ BSD_JoystickGetDevicePlayerIndex(int device_index)
     return -1;
 }
 
+static void
+BSD_JoystickSetDevicePlayerIndex(int device_index, int player_index)
+{
+}
+
 /* Function to perform the mapping from device index to the instance id for this index */
 static SDL_JoystickID
 BSD_JoystickGetDeviceInstanceID(int device_index)
@@ -764,6 +769,7 @@ SDL_JoystickDriver SDL_BSD_JoystickDriver =
     BSD_JoystickDetect,
     BSD_JoystickGetDeviceName,
     BSD_JoystickGetDevicePlayerIndex,
+    BSD_JoystickSetDevicePlayerIndex,
     BSD_JoystickGetDeviceGUID,
     BSD_JoystickGetDeviceInstanceID,
     BSD_JoystickOpen,

+ 6 - 0
src/joystick/darwin/SDL_sysjoystick.c

@@ -734,6 +734,11 @@ DARWIN_JoystickGetDevicePlayerIndex(int device_index)
     return -1;
 }
 
+static void
+DARWIN_JoystickSetDevicePlayerIndex(int device_index, int player_index)
+{
+}
+
 static SDL_JoystickGUID
 DARWIN_JoystickGetDeviceGUID( int device_index )
 {
@@ -1033,6 +1038,7 @@ SDL_JoystickDriver SDL_DARWIN_JoystickDriver =
     DARWIN_JoystickDetect,
     DARWIN_JoystickGetDeviceName,
     DARWIN_JoystickGetDevicePlayerIndex,
+    DARWIN_JoystickSetDevicePlayerIndex,
     DARWIN_JoystickGetDeviceGUID,
     DARWIN_JoystickGetDeviceInstanceID,
     DARWIN_JoystickOpen,

+ 6 - 0
src/joystick/dummy/SDL_sysjoystick.c

@@ -58,6 +58,11 @@ DUMMY_JoystickGetDevicePlayerIndex(int device_index)
     return -1;
 }
 
+static void
+DUMMY_JoystickSetDevicePlayerIndex(int device_index, int player_index)
+{
+}
+
 static SDL_JoystickGUID
 DUMMY_JoystickGetDeviceGUID(int device_index)
 {
@@ -106,6 +111,7 @@ SDL_JoystickDriver SDL_DUMMY_JoystickDriver =
     DUMMY_JoystickDetect,
     DUMMY_JoystickGetDeviceName,
     DUMMY_JoystickGetDevicePlayerIndex,
+    DUMMY_JoystickSetDevicePlayerIndex,
     DUMMY_JoystickGetDeviceGUID,
     DUMMY_JoystickGetDeviceInstanceID,
     DUMMY_JoystickOpen,

+ 6 - 0
src/joystick/emscripten/SDL_sysjoystick.c

@@ -288,6 +288,11 @@ EMSCRIPTEN_JoystickGetDevicePlayerIndex(int device_index)
     return -1;
 }
 
+static void
+EMSCRIPTEN_JoystickSetDevicePlayerIndex(int device_index, int player_index)
+{
+}
+
 static SDL_JoystickID
 EMSCRIPTEN_JoystickGetDeviceInstanceID(int device_index)
 {
@@ -406,6 +411,7 @@ SDL_JoystickDriver SDL_EMSCRIPTEN_JoystickDriver =
     EMSCRIPTEN_JoystickDetect,
     EMSCRIPTEN_JoystickGetDeviceName,
     EMSCRIPTEN_JoystickGetDevicePlayerIndex,
+    EMSCRIPTEN_JoystickSetDevicePlayerIndex,
     EMSCRIPTEN_JoystickGetDeviceGUID,
     EMSCRIPTEN_JoystickGetDeviceInstanceID,
     EMSCRIPTEN_JoystickOpen,

+ 5 - 0
src/joystick/haiku/SDL_haikujoystick.cc

@@ -104,6 +104,10 @@ extern "C"
         return -1;
     }
 
+    static void HAIKU_JoystickGetDevicePlayerIndex(int device_index, int player_index)
+    {
+    }
+
 /* Function to perform the mapping from device index to the instance id for this index */
     static SDL_JoystickID HAIKU_JoystickGetDeviceInstanceID(int device_index)
     {
@@ -262,6 +266,7 @@ extern "C"
         HAIKU_JoystickDetect,
         HAIKU_JoystickGetDeviceName,
         HAIKU_JoystickGetDevicePlayerIndex,
+        HAIKU_JoystickSetDevicePlayerIndex,
         HAIKU_JoystickGetDeviceGUID,
         HAIKU_JoystickGetDeviceInstanceID,
         HAIKU_JoystickOpen,

+ 21 - 1
src/joystick/hidapi/SDL_hidapi_gamecube.c

@@ -140,6 +140,25 @@ error:
     return SDL_FALSE;
 }
 
+static int
+HIDAPI_DriverGameCube_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
+{
+    SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
+    Uint8 i;
+
+    for (i = 0; i < 4; ++i) {
+        if (instance_id == ctx->joysticks[i]) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+static void
+HIDAPI_DriverGameCube_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
+{
+}
+
 static SDL_bool
 HIDAPI_DriverGameCube_UpdateDevice(SDL_HIDAPI_Device *device)
 {
@@ -253,7 +272,6 @@ HIDAPI_DriverGameCube_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joys
             joystick->nbuttons = 12;
             joystick->naxes = 6;
             joystick->epowerlevel = ctx->wireless[i] ? SDL_JOYSTICK_POWER_UNKNOWN : SDL_JOYSTICK_POWER_WIRED;
-            joystick->player_index = i;
             return SDL_TRUE;
         }
     }
@@ -331,6 +349,8 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube =
     HIDAPI_DriverGameCube_IsSupportedDevice,
     HIDAPI_DriverGameCube_GetDeviceName,
     HIDAPI_DriverGameCube_InitDevice,
+    HIDAPI_DriverGameCube_GetDevicePlayerIndex,
+    HIDAPI_DriverGameCube_SetDevicePlayerIndex,
     HIDAPI_DriverGameCube_UpdateDevice,
     HIDAPI_DriverGameCube_OpenJoystick,
     HIDAPI_DriverGameCube_RumbleJoystick,

+ 13 - 0
src/joystick/hidapi/SDL_hidapi_ps4.c

@@ -199,6 +199,17 @@ HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device)
     return HIDAPI_JoystickConnected(device, NULL);
 }
 
+static int
+HIDAPI_DriverPS4_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
+{
+    return -1;
+}
+
+static void
+HIDAPI_DriverPS4_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
+{
+}
+
 static int HIDAPI_DriverPS4_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
 
 static SDL_bool
@@ -499,6 +510,8 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4 =
     HIDAPI_DriverPS4_IsSupportedDevice,
     HIDAPI_DriverPS4_GetDeviceName,
     HIDAPI_DriverPS4_InitDevice,
+    HIDAPI_DriverPS4_GetDevicePlayerIndex,
+    HIDAPI_DriverPS4_SetDevicePlayerIndex,
     HIDAPI_DriverPS4_UpdateDevice,
     HIDAPI_DriverPS4_OpenJoystick,
     HIDAPI_DriverPS4_RumbleJoystick,

+ 13 - 0
src/joystick/hidapi/SDL_hidapi_switch.c

@@ -628,6 +628,17 @@ HIDAPI_DriverSwitch_InitDevice(SDL_HIDAPI_Device *device)
     return HIDAPI_JoystickConnected(device, NULL);
 }
 
+static int
+HIDAPI_DriverSwitch_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
+{
+    return -1;
+}
+
+static void
+HIDAPI_DriverSwitch_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
+{
+}
+
 static SDL_bool
 HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
 {
@@ -1109,6 +1120,8 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch =
     HIDAPI_DriverSwitch_IsSupportedDevice,
     HIDAPI_DriverSwitch_GetDeviceName,
     HIDAPI_DriverSwitch_InitDevice,
+    HIDAPI_DriverSwitch_GetDevicePlayerIndex,
+    HIDAPI_DriverSwitch_SetDevicePlayerIndex,
     HIDAPI_DriverSwitch_UpdateDevice,
     HIDAPI_DriverSwitch_OpenJoystick,
     HIDAPI_DriverSwitch_RumbleJoystick,

+ 21 - 1
src/joystick/hidapi/SDL_hidapi_xbox360.c

@@ -305,10 +305,25 @@ HIDAPI_DriverXbox360_InitDevice(SDL_HIDAPI_Device *device)
     return HIDAPI_JoystickConnected(device, NULL);
 }
 
+static int
+HIDAPI_DriverXbox360_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
+{
+    return -1;
+}
+
+static void
+HIDAPI_DriverXbox360_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
+{
+    if (device->dev) {
+        SetSlotLED(device->dev, (player_index % 4));
+    }
+}
+
 static SDL_bool
 HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
 {
     SDL_DriverXbox360_Context *ctx;
+    int player_index;
 
     ctx = (SDL_DriverXbox360_Context *)SDL_calloc(1, sizeof(*ctx));
     if (!ctx) {
@@ -336,7 +351,10 @@ HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joyst
 #endif
 
     /* Set the controller LED */
-    SetSlotLED(device->dev, (joystick->instance_id % 4));
+    player_index = SDL_JoystickGetPlayerIndex(joystick);
+    if (player_index >= 0) {
+        SetSlotLED(device->dev, (player_index % 4));
+    }
 
     /* Initialize the joystick capabilities */
     joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
@@ -837,6 +855,8 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360 =
     HIDAPI_DriverXbox360_IsSupportedDevice,
     HIDAPI_DriverXbox360_GetDeviceName,
     HIDAPI_DriverXbox360_InitDevice,
+    HIDAPI_DriverXbox360_GetDevicePlayerIndex,
+    HIDAPI_DriverXbox360_SetDevicePlayerIndex,
     HIDAPI_DriverXbox360_UpdateDevice,
     HIDAPI_DriverXbox360_OpenJoystick,
     HIDAPI_DriverXbox360_RumbleJoystick,

+ 15 - 1
src/joystick/hidapi/SDL_hidapi_xbox360w.c

@@ -94,7 +94,7 @@ HIDAPI_DriverXbox360W_InitDevice(SDL_HIDAPI_Device *device)
     SDL_DriverXbox360W_Context *ctx;
 
     /* Requests controller presence information from the wireless dongle */
-	const Uint8 init_packet[] = { 0x08, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    const Uint8 init_packet[] = { 0x08, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 
     ctx = (SDL_DriverXbox360W_Context *)SDL_calloc(1, sizeof(*ctx));
     if (!ctx) {
@@ -118,6 +118,18 @@ HIDAPI_DriverXbox360W_InitDevice(SDL_HIDAPI_Device *device)
     return SDL_TRUE;
 }
 
+static int
+HIDAPI_DriverXbox360W_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
+{
+    return -1;
+}
+
+static void
+HIDAPI_DriverXbox360W_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
+{
+    SetSlotLED(device->dev, (player_index % 4));
+}
+
 static SDL_bool
 HIDAPI_DriverXbox360W_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
 {
@@ -300,6 +312,8 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W =
     HIDAPI_DriverXbox360W_IsSupportedDevice,
     HIDAPI_DriverXbox360W_GetDeviceName,
     HIDAPI_DriverXbox360W_InitDevice,
+    HIDAPI_DriverXbox360W_GetDevicePlayerIndex,
+    HIDAPI_DriverXbox360W_SetDevicePlayerIndex,
     HIDAPI_DriverXbox360W_UpdateDevice,
     HIDAPI_DriverXbox360W_OpenJoystick,
     HIDAPI_DriverXbox360W_RumbleJoystick,

+ 13 - 0
src/joystick/hidapi/SDL_hidapi_xboxone.c

@@ -260,6 +260,17 @@ HIDAPI_DriverXboxOne_InitDevice(SDL_HIDAPI_Device *device)
     return HIDAPI_JoystickConnected(device, NULL);
 }
 
+static int
+HIDAPI_DriverXboxOne_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
+{
+    return -1;
+}
+
+static void
+HIDAPI_DriverXboxOne_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
+{
+}
+
 static SDL_bool
 HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
 {
@@ -468,6 +479,8 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne =
     HIDAPI_DriverXboxOne_IsSupportedDevice,
     HIDAPI_DriverXboxOne_GetDeviceName,
     HIDAPI_DriverXboxOne_InitDevice,
+    HIDAPI_DriverXboxOne_GetDevicePlayerIndex,
+    HIDAPI_DriverXboxOne_SetDevicePlayerIndex,
     HIDAPI_DriverXboxOne_UpdateDevice,
     HIDAPI_DriverXboxOne_OpenJoystick,
     HIDAPI_DriverXboxOne_RumbleJoystick,

+ 27 - 1
src/joystick/hidapi/SDL_hidapijoystick.c

@@ -894,7 +894,32 @@ HIDAPI_JoystickGetDeviceName(int device_index)
 static int
 HIDAPI_JoystickGetDevicePlayerIndex(int device_index)
 {
-    return -1;
+    SDL_HIDAPI_Device *device;
+    SDL_JoystickID instance_id;
+    int player_index = -1;
+
+    SDL_LockMutex(SDL_HIDAPI_mutex);
+    device = HIDAPI_GetDeviceByIndex(device_index, &instance_id);
+    if (device) {
+        player_index = device->driver->GetDevicePlayerIndex(device, instance_id);
+    }
+    SDL_UnlockMutex(SDL_HIDAPI_mutex);
+
+    return player_index;
+}
+
+static void
+HIDAPI_JoystickSetDevicePlayerIndex(int device_index, int player_index)
+{
+    SDL_HIDAPI_Device *device;
+    SDL_JoystickID instance_id;
+
+    SDL_LockMutex(SDL_HIDAPI_mutex);
+    device = HIDAPI_GetDeviceByIndex(device_index, &instance_id);
+    if (device) {
+        device->driver->SetDevicePlayerIndex(device, instance_id, player_index);
+    }
+    SDL_UnlockMutex(SDL_HIDAPI_mutex);
 }
 
 static SDL_JoystickGUID
@@ -1023,6 +1048,7 @@ SDL_JoystickDriver SDL_HIDAPI_JoystickDriver =
     HIDAPI_JoystickDetect,
     HIDAPI_JoystickGetDeviceName,
     HIDAPI_JoystickGetDevicePlayerIndex,
+    HIDAPI_JoystickSetDevicePlayerIndex,
     HIDAPI_JoystickGetDeviceGUID,
     HIDAPI_JoystickGetDeviceInstanceID,
     HIDAPI_JoystickOpen,

+ 2 - 0
src/joystick/hidapi/SDL_hidapijoystick_c.h

@@ -81,6 +81,8 @@ typedef struct _SDL_HIDAPI_DeviceDriver
     SDL_bool (*IsSupportedDevice)(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name);
     const char *(*GetDeviceName)(Uint16 vendor_id, Uint16 product_id);
     SDL_bool (*InitDevice)(SDL_HIDAPI_Device *device);
+    int (*GetDevicePlayerIndex)(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id);
+    void (*SetDevicePlayerIndex)(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index);
     SDL_bool (*UpdateDevice)(SDL_HIDAPI_Device *device);
     SDL_bool (*OpenJoystick)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick);
     int (*RumbleJoystick)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);

+ 10 - 34
src/joystick/iphoneos/SDL_sysjoystick.m

@@ -469,6 +469,15 @@ IOS_JoystickGetDevicePlayerIndex(int device_index)
     return device ? (int)device->controller.playerIndex : -1;
 }
 
+static void
+IOS_JoystickSetDevicePlayerIndex(int device_index, int player_index)
+{
+    SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index);
+    if (device) {
+        device->controller.playerIndex = player_index;
+    }
+}
+
 static SDL_JoystickGUID
 IOS_JoystickGetDeviceGUID( int device_index )
 {
@@ -616,7 +625,6 @@ IOS_MFIJoystickUpdate(SDL_Joystick * joystick)
         GCController *controller = joystick->hwdata->controller;
         Uint8 hatstate = SDL_HAT_CENTERED;
         int i;
-        int updateplayerindex = 0;
         int pause_button_index = 0;
 
         if (controller.extendedGamepad) {
@@ -670,17 +678,10 @@ IOS_MFIJoystickUpdate(SDL_Joystick * joystick)
             hatstate = IOS_MFIJoystickHatStateForDPad(gamepad.dpad);
 
             for (i = 0; i < SDL_arraysize(axes); i++) {
-                /* The triggers (axes 2 and 5) are resting at -32768 but SDL
-                 * initializes its values to 0. We only want to make sure the
-                 * player index is up to date if the user actually moves an axis. */
-                if ((i != 2 && i != 5) || axes[i] != -32768) {
-                    updateplayerindex |= (joystick->axes[i].value != axes[i]);
-                }
                 SDL_PrivateJoystickAxis(joystick, i, axes[i]);
             }
 
             for (i = 0; i < button_count; i++) {
-                updateplayerindex |= (joystick->buttons[i] != buttons[i]);
                 SDL_PrivateJoystickButton(joystick, i, buttons[i]);
             }
         } else if (controller.gamepad) {
@@ -701,7 +702,6 @@ IOS_MFIJoystickUpdate(SDL_Joystick * joystick)
             hatstate = IOS_MFIJoystickHatStateForDPad(gamepad.dpad);
 
             for (i = 0; i < button_count; i++) {
-                updateplayerindex |= (joystick->buttons[i] != buttons[i]);
                 SDL_PrivateJoystickButton(joystick, i, buttons[i]);
             }
         }
@@ -715,7 +715,6 @@ IOS_MFIJoystickUpdate(SDL_Joystick * joystick)
             };
 
             for (i = 0; i < SDL_arraysize(axes); i++) {
-                updateplayerindex |= (joystick->axes[i].value != axes[i]);
                 SDL_PrivateJoystickAxis(joystick, i, axes[i]);
             }
 
@@ -737,14 +736,12 @@ IOS_MFIJoystickUpdate(SDL_Joystick * joystick)
 #pragma clang diagnostic pop
 
             for (i = 0; i < button_count; i++) {
-                updateplayerindex |= (joystick->buttons[i] != buttons[i]);
                 SDL_PrivateJoystickButton(joystick, i, buttons[i]);
             }
         }
 #endif /* TARGET_OS_TV */
 
         if (joystick->nhats > 0) {
-            updateplayerindex |= (joystick->hats[0] != hatstate);
             SDL_PrivateJoystickHat(joystick, 0, hatstate);
         }
 
@@ -752,31 +749,9 @@ IOS_MFIJoystickUpdate(SDL_Joystick * joystick)
             for (i = 0; i < joystick->hwdata->num_pause_presses; i++) {
                 SDL_PrivateJoystickButton(joystick, pause_button_index, SDL_PRESSED);
                 SDL_PrivateJoystickButton(joystick, pause_button_index, SDL_RELEASED);
-                updateplayerindex = YES;
             }
             joystick->hwdata->num_pause_presses = 0;
         }
-
-        if (updateplayerindex && controller.playerIndex == -1) {
-            BOOL usedPlayerIndexSlots[4] = {NO, NO, NO, NO};
-
-            /* Find the player index of all other connected controllers. */
-            for (GCController *c in [GCController controllers]) {
-                if (c != controller && c.playerIndex >= 0) {
-                    usedPlayerIndexSlots[c.playerIndex] = YES;
-                }
-            }
-
-            /* Set this controller's player index to the first unused index.
-             * FIXME: This logic isn't great... but SDL doesn't expose this
-             * concept in its external API, so we don't have much to go on. */
-            for (i = 0; i < SDL_arraysize(usedPlayerIndexSlots); i++) {
-                if (!usedPlayerIndexSlots[i]) {
-                    controller.playerIndex = i;
-                    break;
-                }
-            }
-        }
     }
 #endif /* SDL_JOYSTICK_MFI */
 }
@@ -874,6 +849,7 @@ SDL_JoystickDriver SDL_IOS_JoystickDriver =
     IOS_JoystickDetect,
     IOS_JoystickGetDeviceName,
     IOS_JoystickGetDevicePlayerIndex,
+    IOS_JoystickSetDevicePlayerIndex,
     IOS_JoystickGetDeviceGUID,
     IOS_JoystickGetDeviceInstanceID,
     IOS_JoystickOpen,

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

@@ -569,6 +569,11 @@ LINUX_JoystickGetDevicePlayerIndex(int device_index)
     return -1;
 }
 
+static void
+LINUX_JoystickSetDevicePlayerIndex(int device_index, int player_index)
+{
+}
+
 static SDL_JoystickGUID
 LINUX_JoystickGetDeviceGUID( int device_index )
 {
@@ -1086,6 +1091,7 @@ SDL_JoystickDriver SDL_LINUX_JoystickDriver =
     LINUX_JoystickDetect,
     LINUX_JoystickGetDeviceName,
     LINUX_JoystickGetDevicePlayerIndex,
+    LINUX_JoystickSetDevicePlayerIndex,
     LINUX_JoystickGetDeviceGUID,
     LINUX_JoystickGetDeviceInstanceID,
     LINUX_JoystickOpen,

+ 6 - 0
src/joystick/windows/SDL_windowsjoystick.c

@@ -419,6 +419,11 @@ WINDOWS_JoystickGetDevicePlayerIndex(int device_index)
     return device->bXInputDevice ? (int)device->XInputUserId : -1;
 }
 
+static void
+WINDOWS_JoystickSetDevicePlayerIndex(int device_index, int player_index)
+{
+}
+
 /* return the stable device guid for this device index */
 static SDL_JoystickGUID
 WINDOWS_JoystickGetDeviceGUID(int device_index)
@@ -557,6 +562,7 @@ SDL_JoystickDriver SDL_WINDOWS_JoystickDriver =
     WINDOWS_JoystickDetect,
     WINDOWS_JoystickGetDeviceName,
     WINDOWS_JoystickGetDevicePlayerIndex,
+    WINDOWS_JoystickSetDevicePlayerIndex,
     WINDOWS_JoystickGetDeviceGUID,
     WINDOWS_JoystickGetDeviceInstanceID,
     WINDOWS_JoystickOpen,

+ 2 - 2
test/testgamecontroller.c

@@ -316,9 +316,9 @@ main(int argc, char *argv[])
             name = SDL_JoystickNameForIndex(i);
             description = "Joystick";
         }
-        SDL_Log("%s %d: %s (guid %s, VID 0x%.4x, PID 0x%.4x)\n",
+        SDL_Log("%s %d: %s (guid %s, VID 0x%.4x, PID 0x%.4x, player index = %d)\n",
             description, i, name ? name : "Unknown", guid,
-            SDL_JoystickGetDeviceVendor(i), SDL_JoystickGetDeviceProduct(i));
+            SDL_JoystickGetDeviceVendor(i), SDL_JoystickGetDeviceProduct(i), SDL_JoystickGetDevicePlayerIndex(i));
     }
     SDL_Log("There are %d game controller(s) attached (%d joystick(s))\n", nController, SDL_NumJoysticks());