hidapi: Add support for Wii U/Switch USB GameCube controller adapter.
authorEthan Lee <flibitijibibo@flibitijibibo.com>
Tue, 12 Mar 2019 20:27:54 -0400
changeset 1264164597a7e8771
parent 12640 b708d2c3fe08
child 12642 8a70b87401c3
hidapi: Add support for Wii U/Switch USB GameCube controller adapter.

Note that a single USB device is responsible for all 4 joysticks, so a large
rewrite of the DeviceDriver functions was necessary to allow a single device to
produce multiple joysticks.
include/SDL_hints.h
src/joystick/SDL_gamecontrollerdb.h
src/joystick/SDL_joystick.c
src/joystick/SDL_joystick_c.h
src/joystick/SDL_sysjoystick.h
src/joystick/controller_type.h
src/joystick/hidapi/SDL_hidapi_gamecube.c
src/joystick/hidapi/SDL_hidapi_ps4.c
src/joystick/hidapi/SDL_hidapi_switch.c
src/joystick/hidapi/SDL_hidapi_xbox360.c
src/joystick/hidapi/SDL_hidapi_xboxone.c
src/joystick/hidapi/SDL_hidapijoystick.c
src/joystick/hidapi/SDL_hidapijoystick_c.h
     1.1 --- a/include/SDL_hints.h	Sat Mar 16 17:47:59 2019 -0700
     1.2 +++ b/include/SDL_hints.h	Tue Mar 12 20:27:54 2019 -0400
     1.3 @@ -556,6 +556,17 @@
     1.4  #define SDL_HINT_JOYSTICK_HIDAPI_XBOX   "SDL_JOYSTICK_HIDAPI_XBOX"
     1.5  
     1.6  /**
     1.7 + *  \brief  A variable controlling whether the HIDAPI driver for Nintendo GameCube controllers should be used.
     1.8 + *
     1.9 + *  This variable can be set to the following values:
    1.10 + *    "0"       - HIDAPI driver is not used
    1.11 + *    "1"       - HIDAPI driver is used
    1.12 + *
    1.13 + *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
    1.14 + */
    1.15 +#define SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE "SDL_JOYSTICK_HIDAPI_GAMECUBE"
    1.16 +
    1.17 +/**
    1.18   *  \brief  A variable that controls whether Steam Controllers should be exposed using the SDL joystick and game controller APIs
    1.19   *
    1.20   *  The variable can be set to the following values:
     2.1 --- a/src/joystick/SDL_gamecontrollerdb.h	Sat Mar 16 17:47:59 2019 -0700
     2.2 +++ b/src/joystick/SDL_gamecontrollerdb.h	Tue Mar 12 20:27:54 2019 -0400
     2.3 @@ -564,6 +564,7 @@
     2.4      "03000000b50700001503000010010000,impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
     2.5      "030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,",
     2.6      "03000000d80400008200000003000000,IMS PCU#0 Gamepad Interface,platform:Linux,a:b1,b:b0,x:b3,y:b2,back:b4,start:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,",
     2.7 +    "030000007e0500003703000000016800,Nintendo GameCube Controller,platform:Linux,a:b0,b:b2,x:b1,y:b3,start:b8,rightshoulder:b9,dpup:b7,dpdown:b6,dpleft:b4,dpright:b5,leftx:a0,lefty:a1~,rightx:a2,righty:a3~,lefttrigger:a4,righttrigger:a5,",
     2.8  #endif
     2.9  #if defined(__ANDROID__)
    2.10      "05000000d6020000e5890000dfff3f00,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,",
     3.1 --- a/src/joystick/SDL_joystick.c	Sat Mar 16 17:47:59 2019 -0700
     3.2 +++ b/src/joystick/SDL_joystick.c	Tue Mar 12 20:27:54 2019 -0400
     3.3 @@ -1033,6 +1033,11 @@
     3.4      /* Make sure the list is unlocked while dispatching events to prevent application deadlocks */
     3.5      SDL_UnlockJoysticks();
     3.6  
     3.7 +    /* Special function for HIDAPI devices, as a single device can provide multiple SDL_Joysticks */
     3.8 +#ifdef SDL_JOYSTICK_HIDAPI
     3.9 +    SDL_HIDAPI_UpdateDevices();
    3.10 +#endif /* SDL_JOYSTICK_HIDAPI */
    3.11 +
    3.12      for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
    3.13          if (joystick->attached) {
    3.14              joystick->driver->Update(joystick);
    3.15 @@ -1188,6 +1193,12 @@
    3.16  }
    3.17  
    3.18  SDL_bool
    3.19 +SDL_IsJoystickGameCube(Uint16 vendor, Uint16 product)
    3.20 +{
    3.21 +    return (GuessControllerType(vendor, product) == k_eControllerType_GameCube);
    3.22 +}
    3.23 +
    3.24 +SDL_bool
    3.25  SDL_IsJoystickXInput(SDL_JoystickGUID guid)
    3.26  {
    3.27      return (guid.data[14] == 'x') ? SDL_TRUE : SDL_FALSE;
     4.1 --- a/src/joystick/SDL_joystick_c.h	Sat Mar 16 17:47:59 2019 -0700
     4.2 +++ b/src/joystick/SDL_joystick_c.h	Tue Mar 12 20:27:54 2019 -0400
     4.3 @@ -66,6 +66,9 @@
     4.4  /* Function to return whether a joystick is an Xbox One controller */
     4.5  extern SDL_bool SDL_IsJoystickXboxOne(Uint16 vendor_id, Uint16 product_id);
     4.6  
     4.7 +/* Function to return whether a joystick is a GameCube controller */
     4.8 +extern SDL_bool SDL_IsJoystickGameCube(Uint16 vendor_id, Uint16 product_id);
     4.9 +
    4.10  /* Function to return whether a joystick guid comes from the XInput driver */
    4.11  extern SDL_bool SDL_IsJoystickXInput(SDL_JoystickGUID guid);
    4.12  
     5.1 --- a/src/joystick/SDL_sysjoystick.h	Sat Mar 16 17:47:59 2019 -0700
     5.2 +++ b/src/joystick/SDL_sysjoystick.h	Tue Mar 12 20:27:54 2019 -0400
     5.3 @@ -152,6 +152,9 @@
     5.4  extern SDL_JoystickDriver SDL_LINUX_JoystickDriver;
     5.5  extern SDL_JoystickDriver SDL_WINDOWS_JoystickDriver;
     5.6  
     5.7 +/* Special function to update HIDAPI devices */
     5.8 +extern void SDL_HIDAPI_UpdateDevices(void);
     5.9 +
    5.10  #endif /* SDL_sysjoystick_h_ */
    5.11  
    5.12  /* vi: set ts=4 sw=4 expandtab: */
     6.1 --- a/src/joystick/controller_type.h	Sat Mar 16 17:47:59 2019 -0700
     6.2 +++ b/src/joystick/controller_type.h	Tue Mar 12 20:27:54 2019 -0400
     6.3 @@ -57,6 +57,7 @@
     6.4  	k_eControllerType_SwitchJoyConPair = 41,
     6.5      k_eControllerType_SwitchInputOnlyController = 42,
     6.6  	k_eControllerType_MobileTouch = 43,
     6.7 +        k_eControllerType_GameCube = 44,
     6.8  	k_eControllerType_LastController,			// Don't add game controllers below this enumeration - this enumeration can change value
     6.9  
    6.10  	// Keyboards and Mice
    6.11 @@ -387,6 +388,8 @@
    6.12      { MAKE_CONTROLLER_ID( 0x20d6, 0xa711 ), k_eControllerType_SwitchInputOnlyController },  // PowerA Wired Controller Plus
    6.13      { MAKE_CONTROLLER_ID( 0x0f0d, 0x0092 ), k_eControllerType_SwitchInputOnlyController },  // HORI Pokken Tournament DX Pro Pad
    6.14  
    6.15 +    { MAKE_CONTROLLER_ID( 0x057e, 0x0337 ), k_eControllerType_GameCube }, // Nintendo Wii U/Switch GameCube USB Adapter
    6.16 +
    6.17  
    6.18  	// Valve products - don't add to public list
    6.19      { MAKE_CONTROLLER_ID( 0x0000, 0x11fb ), k_eControllerType_MobileTouch },		// Streaming mobile touch virtual controls
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/joystick/hidapi/SDL_hidapi_gamecube.c	Tue Mar 12 20:27:54 2019 -0400
     7.3 @@ -0,0 +1,339 @@
     7.4 +/*
     7.5 +  Simple DirectMedia Layer
     7.6 +  Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
     7.7 +
     7.8 +  This software is provided 'as-is', without any express or implied
     7.9 +  warranty.  In no event will the authors be held liable for any damages
    7.10 +  arising from the use of this software.
    7.11 +
    7.12 +  Permission is granted to anyone to use this software for any purpose,
    7.13 +  including commercial applications, and to alter it and redistribute it
    7.14 +  freely, subject to the following restrictions:
    7.15 +
    7.16 +  1. The origin of this software must not be misrepresented; you must not
    7.17 +     claim that you wrote the original software. If you use this software
    7.18 +     in a product, an acknowledgment in the product documentation would be
    7.19 +     appreciated but is not required.
    7.20 +  2. Altered source versions must be plainly marked as such, and must not be
    7.21 +     misrepresented as being the original software.
    7.22 +  3. This notice may not be removed or altered from any source distribution.
    7.23 +*/
    7.24 +#include "../../SDL_internal.h"
    7.25 +
    7.26 +#ifdef SDL_JOYSTICK_HIDAPI
    7.27 +
    7.28 +#include "SDL_hints.h"
    7.29 +#include "SDL_log.h"
    7.30 +#include "SDL_events.h"
    7.31 +#include "SDL_timer.h"
    7.32 +#include "SDL_haptic.h"
    7.33 +#include "SDL_joystick.h"
    7.34 +#include "SDL_gamecontroller.h"
    7.35 +#include "../SDL_sysjoystick.h"
    7.36 +#include "SDL_hidapijoystick_c.h"
    7.37 +
    7.38 +
    7.39 +#ifdef SDL_JOYSTICK_HIDAPI_GAMECUBE
    7.40 +
    7.41 +typedef struct {
    7.42 +    SDL_JoystickID joysticks[4];
    7.43 +    Uint8 rumble[5];
    7.44 +    Uint32 rumbleExpiration[4];
    7.45 +    /* Without this variable, hid_write starts to lag a TON */
    7.46 +    Uint8 rumbleUpdate;
    7.47 +} SDL_DriverGameCube_Context;
    7.48 +
    7.49 +static SDL_bool
    7.50 +HIDAPI_DriverGameCube_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number)
    7.51 +{
    7.52 +    return SDL_IsJoystickGameCube(vendor_id, product_id);
    7.53 +}
    7.54 +
    7.55 +static const char *
    7.56 +HIDAPI_DriverGameCube_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
    7.57 +{
    7.58 +    /* Give a user friendly name for this controller */
    7.59 +    if (SDL_IsJoystickGameCube(vendor_id, product_id)) {
    7.60 +        return "Nintendo GameCube Controller";
    7.61 +    }
    7.62 +    return NULL;
    7.63 +}
    7.64 +
    7.65 +static SDL_bool
    7.66 +HIDAPI_DriverGameCube_InitDriver(SDL_HIDAPI_DriverData *context, Uint16 vendor_id, Uint16 product_id, int *num_joysticks)
    7.67 +{
    7.68 +    SDL_DriverGameCube_Context *ctx;
    7.69 +    Uint8 packet[37];
    7.70 +    Uint8 *curSlot;
    7.71 +    Uint8 i;
    7.72 +    int size;
    7.73 +    Uint8 initMagic = 0x13;
    7.74 +    Uint8 rumbleMagic = 0x11;
    7.75 +
    7.76 +    ctx = (SDL_DriverGameCube_Context *)SDL_calloc(1, sizeof(*ctx));
    7.77 +    if (!ctx) {
    7.78 +        SDL_OutOfMemory();
    7.79 +        return SDL_FALSE;
    7.80 +    }
    7.81 +    ctx->joysticks[0] = -1;
    7.82 +    ctx->joysticks[1] = -1;
    7.83 +    ctx->joysticks[2] = -1;
    7.84 +    ctx->joysticks[3] = -1;
    7.85 +    ctx->rumble[0] = rumbleMagic;
    7.86 +
    7.87 +    context->context = ctx;
    7.88 +
    7.89 +    /* This is all that's needed to initialize the device. Really! */
    7.90 +    if (hid_write(context->device, &initMagic, sizeof(initMagic)) <= 0) {
    7.91 +        SDL_SetError("Couldn't initialize WUP-028");
    7.92 +        SDL_free(ctx);
    7.93 +        return SDL_FALSE;
    7.94 +    }
    7.95 +
    7.96 +    /* Add all the applicable joysticks */
    7.97 +    while ((size = hid_read_timeout(context->device, packet, sizeof(packet), 0)) > 0) {
    7.98 +        if (size < 37 || packet[0] != 0x21) {
    7.99 +            continue; /* Nothing to do yet...? */
   7.100 +        }
   7.101 +
   7.102 +        /* Go through all 4 slots */
   7.103 +        curSlot = packet + 1;
   7.104 +        for (i = 0; i < 4; i += 1, curSlot += 9) {
   7.105 +            if (curSlot[0] & 0x30) { /* 0x10 - Wired, 0x20 - Wireless */
   7.106 +                if (ctx->joysticks[i] == -1) {
   7.107 +                    ctx->joysticks[i] = SDL_GetNextJoystickInstanceID();
   7.108 +
   7.109 +                    *num_joysticks += 1;
   7.110 +
   7.111 +                    SDL_PrivateJoystickAdded(ctx->joysticks[i]);
   7.112 +                }
   7.113 +            } else {
   7.114 +                if (ctx->joysticks[i] != -1) {
   7.115 +                    SDL_PrivateJoystickRemoved(ctx->joysticks[i]);
   7.116 +
   7.117 +                    *num_joysticks -= 1;
   7.118 +
   7.119 +                    ctx->joysticks[i] = -1;
   7.120 +                }
   7.121 +                continue;
   7.122 +            }
   7.123 +        }
   7.124 +    }
   7.125 +
   7.126 +    return SDL_TRUE;
   7.127 +}
   7.128 +
   7.129 +static void
   7.130 +HIDAPI_DriverGameCube_QuitDriver(SDL_HIDAPI_DriverData *context, SDL_bool send_event, int *num_joysticks)
   7.131 +{
   7.132 +    SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)context->context;
   7.133 +    Uint8 i;
   7.134 +
   7.135 +    /* Stop all rumble activity */
   7.136 +    for (i = 1; i < 5; i += 1) {
   7.137 +        ctx->rumble[i] = 0;
   7.138 +    }
   7.139 +    hid_write(context->device, ctx->rumble, sizeof(ctx->rumble));
   7.140 +
   7.141 +    /* Remove all joysticks! */
   7.142 +    for (i = 0; i < 4; i += 1) {
   7.143 +        if (ctx->joysticks[i] != -1) {
   7.144 +            *num_joysticks -= 1;
   7.145 +            if (send_event) {
   7.146 +                SDL_PrivateJoystickRemoved(ctx->joysticks[i]);
   7.147 +            }
   7.148 +        }
   7.149 +    }
   7.150 +
   7.151 +    SDL_free(context->context);
   7.152 +}
   7.153 +
   7.154 +static SDL_bool
   7.155 +HIDAPI_DriverGameCube_UpdateDriver(SDL_HIDAPI_DriverData *context, int *num_joysticks)
   7.156 +{
   7.157 +    SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)context->context;
   7.158 +    SDL_Joystick *joystick;
   7.159 +    Uint8 packet[37];
   7.160 +    Uint8 *curSlot;
   7.161 +    Uint32 now;
   7.162 +    Uint8 i;
   7.163 +    int size;
   7.164 +
   7.165 +    /* Read input packet */
   7.166 +    while ((size = hid_read_timeout(context->device, packet, sizeof(packet), 0)) > 0) {
   7.167 +        if (size < 37 || packet[0] != 0x21) {
   7.168 +            continue; /* Nothing to do right now...? */
   7.169 +        }
   7.170 +
   7.171 +        /* Go through all 4 slots */
   7.172 +        curSlot = packet + 1;
   7.173 +        for (i = 0; i < 4; i += 1, curSlot += 9) {
   7.174 +            if (curSlot[0] & 0x30) { /* 0x10 - Wired, 0x20 - Wireless */
   7.175 +                if (ctx->joysticks[i] == -1) {
   7.176 +                    ctx->joysticks[i] = SDL_GetNextJoystickInstanceID();
   7.177 +
   7.178 +                    *num_joysticks += 1;
   7.179 +
   7.180 +                    SDL_PrivateJoystickAdded(ctx->joysticks[i]);
   7.181 +                }
   7.182 +                joystick = SDL_JoystickFromInstanceID(ctx->joysticks[i]);
   7.183 +
   7.184 +                /* Hasn't been opened yet, skip */
   7.185 +                if (joystick == NULL) {
   7.186 +                    continue;
   7.187 +                }
   7.188 +            } else {
   7.189 +                if (ctx->joysticks[i] != -1) {
   7.190 +                    SDL_PrivateJoystickRemoved(ctx->joysticks[i]);
   7.191 +
   7.192 +                    *num_joysticks -= 1;
   7.193 +
   7.194 +                    ctx->joysticks[i] = -1;
   7.195 +                }
   7.196 +                continue;
   7.197 +            }
   7.198 +
   7.199 +            #define READ_BUTTON(off, flag, button) \
   7.200 +                SDL_PrivateJoystickButton( \
   7.201 +                    joystick, \
   7.202 +                    button, \
   7.203 +                    (curSlot[off] & flag) ? SDL_PRESSED : SDL_RELEASED \
   7.204 +                );
   7.205 +            READ_BUTTON(1, 0x01, 0) /* A */
   7.206 +            READ_BUTTON(1, 0x02, 1) /* B */
   7.207 +            READ_BUTTON(1, 0x04, 2) /* X */
   7.208 +            READ_BUTTON(1, 0x08, 3) /* Y */
   7.209 +            READ_BUTTON(1, 0x10, 4) /* DPAD_LEFT */
   7.210 +            READ_BUTTON(1, 0x20, 5) /* DPAD_RIGHT */
   7.211 +            READ_BUTTON(1, 0x40, 6) /* DPAD_DOWN */
   7.212 +            READ_BUTTON(1, 0x80, 7) /* DPAD_UP */
   7.213 +            READ_BUTTON(2, 0x01, 8) /* START */
   7.214 +            READ_BUTTON(2, 0x02, 9) /* RIGHTSHOULDER */
   7.215 +            /* [2] 0x04 - R, [2] 0x08 - L */
   7.216 +            #undef READ_BUTTON
   7.217 +
   7.218 +            /* Axis math taken from SDL_xinputjoystick.c */
   7.219 +            #define READ_AXIS(off, axis) \
   7.220 +                SDL_PrivateJoystickAxis( \
   7.221 +                    joystick, \
   7.222 +                    axis, \
   7.223 +                    (Sint16)(((int)curSlot[off] * 257) - 32768) \
   7.224 +                );
   7.225 +            READ_AXIS(3, 0) /* LEFTX */
   7.226 +            READ_AXIS(4, 1) /* LEFTY */
   7.227 +            READ_AXIS(5, 2) /* RIGHTX */
   7.228 +            READ_AXIS(6, 3) /* RIGHTY */
   7.229 +            READ_AXIS(7, 4) /* TRIGGERLEFT */
   7.230 +            READ_AXIS(8, 5) /* TRIGGERRIGHT */
   7.231 +            #undef READ_AXIS
   7.232 +        }
   7.233 +    }
   7.234 +
   7.235 +    /* Write rumble packet */
   7.236 +    now = SDL_GetTicks();
   7.237 +    for (i = 0; i < 4; i += 1) {
   7.238 +        if (ctx->rumbleExpiration[i] > 0) {
   7.239 +            if (SDL_TICKS_PASSED(now, ctx->rumbleExpiration[i])) {
   7.240 +                ctx->rumble[i + 1] = 0;
   7.241 +                ctx->rumbleExpiration[i] = 0;
   7.242 +                ctx->rumbleUpdate = 1;
   7.243 +            }
   7.244 +        }
   7.245 +    }
   7.246 +    if (ctx->rumbleUpdate) {
   7.247 +        hid_write(context->device, ctx->rumble, sizeof(ctx->rumble));
   7.248 +        ctx->rumbleUpdate = 0;
   7.249 +    }
   7.250 +
   7.251 +    /* If we got here, nothing bad happened! */
   7.252 +    return SDL_TRUE;
   7.253 +}
   7.254 +
   7.255 +static int
   7.256 +HIDAPI_DriverGameCube_NumJoysticks(SDL_HIDAPI_DriverData *context)
   7.257 +{
   7.258 +    SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)context->context;
   7.259 +    int i, joysticks = 0;
   7.260 +    for (i = 0; i < 4; i += 1) {
   7.261 +        if (ctx->joysticks[i] != -1) {
   7.262 +            joysticks += 1;
   7.263 +        }
   7.264 +    }
   7.265 +    return joysticks;
   7.266 +}
   7.267 +
   7.268 +static SDL_JoystickID
   7.269 +HIDAPI_DriverGameCube_InstanceIDForIndex(SDL_HIDAPI_DriverData *context, int index)
   7.270 +{
   7.271 +    SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)context->context;
   7.272 +    Uint8 i;
   7.273 +    for (i = 0; i < 4; i += 1) {
   7.274 +        if (ctx->joysticks[i] != -1) {
   7.275 +            if (index == 0) {
   7.276 +                return ctx->joysticks[i];
   7.277 +            }
   7.278 +            index -= 1;
   7.279 +        }
   7.280 +    }
   7.281 +    return -1; /* Should never get here! */
   7.282 +}
   7.283 +
   7.284 +static SDL_bool
   7.285 +HIDAPI_DriverGameCube_OpenJoystick(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick)
   7.286 +{
   7.287 +    SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)context->context;
   7.288 +    SDL_JoystickID instance = SDL_JoystickInstanceID(joystick);
   7.289 +    Uint8 i;
   7.290 +    for (i = 0; i < 4; i += 1) {
   7.291 +        if (instance == ctx->joysticks[i]) {
   7.292 +            joystick->nbuttons = 10;
   7.293 +            joystick->naxes = 6;
   7.294 +            joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
   7.295 +            return SDL_TRUE;
   7.296 +        }
   7.297 +    }
   7.298 +    return SDL_FALSE; /* Should never get here! */
   7.299 +}
   7.300 +
   7.301 +static int
   7.302 +HIDAPI_DriverGameCube_Rumble(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   7.303 +{
   7.304 +    SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)context->context;
   7.305 +    SDL_JoystickID instance = SDL_JoystickInstanceID(joystick);
   7.306 +    Uint8 i, val;
   7.307 +    for (i = 0; i < 4; i += 1) {
   7.308 +        if (instance == ctx->joysticks[i]) {
   7.309 +            val = (low_frequency_rumble > 0 || high_frequency_rumble > 0);
   7.310 +            if (val != ctx->rumble[i + 1]) {
   7.311 +                ctx->rumble[i + 1] = val;
   7.312 +                ctx->rumbleUpdate = 1;
   7.313 +            }
   7.314 +            if (val && duration_ms < SDL_HAPTIC_INFINITY) {
   7.315 +                ctx->rumbleExpiration[i] = SDL_GetTicks() + duration_ms;
   7.316 +            } else {
   7.317 +                ctx->rumbleExpiration[i] = 0;
   7.318 +            }
   7.319 +            return 0;
   7.320 +        }
   7.321 +    }
   7.322 +    return -1;
   7.323 +}
   7.324 +
   7.325 +SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube =
   7.326 +{
   7.327 +    SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE,
   7.328 +    SDL_TRUE,
   7.329 +    HIDAPI_DriverGameCube_IsSupportedDevice,
   7.330 +    HIDAPI_DriverGameCube_GetDeviceName,
   7.331 +    HIDAPI_DriverGameCube_InitDriver,
   7.332 +    HIDAPI_DriverGameCube_QuitDriver,
   7.333 +    HIDAPI_DriverGameCube_UpdateDriver,
   7.334 +    HIDAPI_DriverGameCube_NumJoysticks,
   7.335 +    HIDAPI_DriverGameCube_InstanceIDForIndex,
   7.336 +    HIDAPI_DriverGameCube_OpenJoystick,
   7.337 +    HIDAPI_DriverGameCube_Rumble
   7.338 +};
   7.339 +
   7.340 +#endif /* SDL_JOYSTICK_HIDAPI_GAMECUBE */
   7.341 +
   7.342 +#endif /* SDL_JOYSTICK_HIDAPI */
     8.1 --- a/src/joystick/hidapi/SDL_hidapi_ps4.c	Sat Mar 16 17:47:59 2019 -0700
     8.2 +++ b/src/joystick/hidapi/SDL_hidapi_ps4.c	Tue Mar 12 20:27:54 2019 -0400
     8.3 @@ -108,6 +108,7 @@
     8.4  } DS4EffectsState_t;
     8.5  
     8.6  typedef struct {
     8.7 +    SDL_JoystickID joystickID;
     8.8      SDL_bool is_dongle;
     8.9      SDL_bool is_bluetooth;
    8.10      SDL_bool audio_supported;
    8.11 @@ -272,10 +273,8 @@
    8.12      return SDL_TRUE;
    8.13  }
    8.14  
    8.15 -static int HIDAPI_DriverPS4_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
    8.16 -
    8.17  static SDL_bool
    8.18 -HIDAPI_DriverPS4_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
    8.19 +HIDAPI_DriverPS4_InitDriver(SDL_HIDAPI_DriverData *context, Uint16 vendor_id, Uint16 product_id, int *num_joysticks)
    8.20  {
    8.21      SDL_DriverPS4_Context *ctx;
    8.22  
    8.23 @@ -284,14 +283,14 @@
    8.24          SDL_OutOfMemory();
    8.25          return SDL_FALSE;
    8.26      }
    8.27 -    *context = ctx;
    8.28 +    context->context = ctx;
    8.29  
    8.30      /* Check for type of connection */
    8.31      ctx->is_dongle = (vendor_id == SONY_USB_VID && product_id == SONY_DS4_DONGLE_PID);
    8.32      if (ctx->is_dongle) {
    8.33          ctx->is_bluetooth = SDL_FALSE;
    8.34      } else if (vendor_id == SONY_USB_VID) {
    8.35 -        ctx->is_bluetooth = !CheckUSBConnected(dev);
    8.36 +        ctx->is_bluetooth = !CheckUSBConnected(context->device);
    8.37      } else {
    8.38          /* Third party controllers appear to all be wired */
    8.39          ctx->is_bluetooth = SDL_FALSE;
    8.40 @@ -314,8 +313,45 @@
    8.41          }
    8.42      }
    8.43  
    8.44 +    ctx->joystickID = SDL_GetNextJoystickInstanceID();
    8.45 +    *num_joysticks += 1;
    8.46 +    SDL_PrivateJoystickAdded(ctx->joystickID);
    8.47 +
    8.48 +    return SDL_TRUE;
    8.49 +}
    8.50 +
    8.51 +static void
    8.52 +HIDAPI_DriverPS4_QuitDriver(SDL_HIDAPI_DriverData *context, SDL_bool send_event, int *num_joysticks)
    8.53 +{
    8.54 +    SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context->context;
    8.55 +
    8.56 +    *num_joysticks -= 1;
    8.57 +    if (send_event) {
    8.58 +        SDL_PrivateJoystickRemoved(ctx->joystickID);
    8.59 +    }
    8.60 +    SDL_free(context->context);
    8.61 +}
    8.62 +
    8.63 +static int
    8.64 +HIDAPI_DriverPS4_NumJoysticks(SDL_HIDAPI_DriverData *context)
    8.65 +{
    8.66 +    return 1;
    8.67 +}
    8.68 +
    8.69 +static SDL_JoystickID
    8.70 +HIDAPI_DriverPS4_InstanceIDForIndex(SDL_HIDAPI_DriverData *context, int index)
    8.71 +{
    8.72 +    SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context->context;
    8.73 +    return ctx->joystickID;
    8.74 +}
    8.75 +
    8.76 +static int HIDAPI_DriverPS4_Rumble(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
    8.77 +
    8.78 +static SDL_bool
    8.79 +HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick)
    8.80 +{
    8.81      /* Initialize LED and effect state */
    8.82 -    HIDAPI_DriverPS4_Rumble(joystick, dev, ctx, 0, 0, 0);
    8.83 +    HIDAPI_DriverPS4_Rumble(context, joystick, 0, 0, 0);
    8.84  
    8.85      /* Initialize the joystick capabilities */
    8.86      joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
    8.87 @@ -326,9 +362,9 @@
    8.88  }
    8.89  
    8.90  static int
    8.91 -HIDAPI_DriverPS4_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
    8.92 +HIDAPI_DriverPS4_Rumble(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
    8.93  {
    8.94 -    SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context;
    8.95 +    SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context->context;
    8.96      DS4EffectsState_t *effects;
    8.97      Uint8 data[78];
    8.98      int report_size, offset;
    8.99 @@ -386,7 +422,7 @@
   8.100          SDL_memcpy(&data[report_size - sizeof(unCRC)], &unCRC, sizeof(unCRC));
   8.101      }
   8.102  
   8.103 -    if (hid_write(dev, data, report_size) != report_size) {
   8.104 +    if (hid_write(context->device, data, report_size) != report_size) {
   8.105          return SDL_SetError("Couldn't send rumble packet");
   8.106      }
   8.107  
   8.108 @@ -508,20 +544,25 @@
   8.109  }
   8.110  
   8.111  static SDL_bool
   8.112 -HIDAPI_DriverPS4_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
   8.113 +HIDAPI_DriverPS4_UpdateDriver(SDL_HIDAPI_DriverData *context, int *num_joysticks)
   8.114  {
   8.115 -    SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context;
   8.116 +    SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context->context;
   8.117 +    SDL_Joystick *joystick = SDL_JoystickFromInstanceID(ctx->joystickID);
   8.118      Uint8 data[USB_PACKET_LENGTH];
   8.119      int size;
   8.120  
   8.121 -    while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
   8.122 +    if (joystick == NULL) {
   8.123 +        return SDL_TRUE; /* Nothing to do right now! */
   8.124 +    }
   8.125 +
   8.126 +    while ((size = hid_read_timeout(context->device, data, sizeof(data), 0)) > 0) {
   8.127          switch (data[0]) {
   8.128          case k_EPS4ReportIdUsbState:
   8.129 -            HIDAPI_DriverPS4_HandleStatePacket(joystick, dev, ctx, (PS4StatePacket_t *)&data[1]);
   8.130 +            HIDAPI_DriverPS4_HandleStatePacket(joystick, context->device, ctx, (PS4StatePacket_t *)&data[1]);
   8.131              break;
   8.132          case k_EPS4ReportIdBluetoothState:
   8.133              /* Bluetooth state packets have two additional bytes at the beginning */
   8.134 -            HIDAPI_DriverPS4_HandleStatePacket(joystick, dev, ctx, (PS4StatePacket_t *)&data[3]);
   8.135 +            HIDAPI_DriverPS4_HandleStatePacket(joystick, context->device, ctx, (PS4StatePacket_t *)&data[3]);
   8.136              break;
   8.137          default:
   8.138  #ifdef DEBUG_JOYSTICK
   8.139 @@ -534,29 +575,26 @@
   8.140      if (ctx->rumble_expiration) {
   8.141          Uint32 now = SDL_GetTicks();
   8.142          if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
   8.143 -            HIDAPI_DriverPS4_Rumble(joystick, dev, context, 0, 0, 0);
   8.144 +            HIDAPI_DriverPS4_Rumble(context, joystick, 0, 0, 0);
   8.145          }
   8.146      }
   8.147  
   8.148      return (size >= 0);
   8.149  }
   8.150  
   8.151 -static void
   8.152 -HIDAPI_DriverPS4_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
   8.153 -{
   8.154 -    SDL_free(context);
   8.155 -}
   8.156 -
   8.157  SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4 =
   8.158  {
   8.159      SDL_HINT_JOYSTICK_HIDAPI_PS4,
   8.160      SDL_TRUE,
   8.161      HIDAPI_DriverPS4_IsSupportedDevice,
   8.162      HIDAPI_DriverPS4_GetDeviceName,
   8.163 -    HIDAPI_DriverPS4_Init,
   8.164 -    HIDAPI_DriverPS4_Rumble,
   8.165 -    HIDAPI_DriverPS4_Update,
   8.166 -    HIDAPI_DriverPS4_Quit
   8.167 +    HIDAPI_DriverPS4_InitDriver,
   8.168 +    HIDAPI_DriverPS4_QuitDriver,
   8.169 +    HIDAPI_DriverPS4_UpdateDriver,
   8.170 +    HIDAPI_DriverPS4_NumJoysticks,
   8.171 +    HIDAPI_DriverPS4_InstanceIDForIndex,
   8.172 +    HIDAPI_DriverPS4_OpenJoystick,
   8.173 +    HIDAPI_DriverPS4_Rumble
   8.174  };
   8.175  
   8.176  #endif /* SDL_JOYSTICK_HIDAPI_PS4 */
     9.1 --- a/src/joystick/hidapi/SDL_hidapi_switch.c	Sat Mar 16 17:47:59 2019 -0700
     9.2 +++ b/src/joystick/hidapi/SDL_hidapi_switch.c	Tue Mar 12 20:27:54 2019 -0400
     9.3 @@ -183,6 +183,7 @@
     9.4  #pragma pack()
     9.5  
     9.6  typedef struct {
     9.7 +    SDL_JoystickID joystickID;
     9.8      hid_device *dev;
     9.9      SDL_bool m_bIsUsingBluetooth;
    9.10      Uint8 m_nCommandNumber;
    9.11 @@ -570,7 +571,7 @@
    9.12  }
    9.13  
    9.14  static SDL_bool
    9.15 -HIDAPI_DriverSwitch_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
    9.16 +HIDAPI_DriverSwitch_InitDriver(SDL_HIDAPI_DriverData *context, Uint16 vendor_id, Uint16 product_id, int *num_joysticks)
    9.17  {
    9.18      SDL_DriverSwitch_Context *ctx;
    9.19      Uint8 input_mode;
    9.20 @@ -580,9 +581,9 @@
    9.21          SDL_OutOfMemory();
    9.22          return SDL_FALSE;
    9.23      }
    9.24 -    ctx->dev = dev;
    9.25 +    ctx->dev = context->device;
    9.26  
    9.27 -    *context = ctx;
    9.28 +    context->context = ctx;
    9.29  
    9.30      /* Initialize rumble data */
    9.31      SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]);
    9.32 @@ -627,6 +628,18 @@
    9.33          }
    9.34      }
    9.35  
    9.36 +    ctx->joystickID = SDL_GetNextJoystickInstanceID();
    9.37 +    *num_joysticks += 1;
    9.38 +    SDL_PrivateJoystickAdded(ctx->joystickID);
    9.39 +
    9.40 +    return SDL_TRUE;
    9.41 +}
    9.42 +
    9.43 +static SDL_bool
    9.44 +HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick)
    9.45 +{
    9.46 +    SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context->context;
    9.47 +
    9.48      /* Set the LED state */
    9.49      SetHomeLED(ctx, 100);
    9.50      SetSlotLED(ctx, (joystick->instance_id % 4));
    9.51 @@ -640,9 +653,9 @@
    9.52  }
    9.53  
    9.54  static int
    9.55 -HIDAPI_DriverSwitch_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
    9.56 +HIDAPI_DriverSwitch_Rumble(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
    9.57  {
    9.58 -    SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context;
    9.59 +    SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context->context;
    9.60  
    9.61      /* Experimentally determined rumble values. These will only matter on some controllers as tested ones
    9.62       * seem to disregard these and just use any non-zero rumble values as a binary flag for constant rumble
    9.63 @@ -847,11 +860,16 @@
    9.64  }
    9.65  
    9.66  static SDL_bool
    9.67 -HIDAPI_DriverSwitch_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
    9.68 +HIDAPI_DriverSwitch_UpdateDriver(SDL_HIDAPI_DriverData *context, int *num_joysticks)
    9.69  {
    9.70 -    SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context;
    9.71 +    SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context->context;
    9.72 +    SDL_Joystick *joystick = SDL_JoystickFromInstanceID(ctx->joystickID);
    9.73      int size;
    9.74  
    9.75 +    if (joystick == NULL) {
    9.76 +        return SDL_TRUE; /* Nothing to do right now! */
    9.77 +    }
    9.78 +
    9.79      while ((size = ReadInput(ctx)) > 0) {
    9.80          switch (ctx->m_rgucReadBuffer[0]) {
    9.81          case k_eSwitchInputReportIDs_SimpleControllerState:
    9.82 @@ -868,7 +886,7 @@
    9.83      if (ctx->m_nRumbleExpiration) {
    9.84          Uint32 now = SDL_GetTicks();
    9.85          if (SDL_TICKS_PASSED(now, ctx->m_nRumbleExpiration)) {
    9.86 -            HIDAPI_DriverSwitch_Rumble(joystick, dev, context, 0, 0, 0);
    9.87 +            HIDAPI_DriverSwitch_Rumble(context, joystick, 0, 0, 0);
    9.88          }
    9.89      }
    9.90  
    9.91 @@ -876,14 +894,31 @@
    9.92  }
    9.93  
    9.94  static void
    9.95 -HIDAPI_DriverSwitch_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
    9.96 +HIDAPI_DriverSwitch_QuitDriver(SDL_HIDAPI_DriverData *context, SDL_bool send_event, int *num_joysticks)
    9.97  {
    9.98 -    SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context;
    9.99 +    SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context->context;
   9.100  
   9.101      /* Restore simple input mode for other applications */
   9.102      SetInputMode(ctx, k_eSwitchInputReportIDs_SimpleControllerState);
   9.103  
   9.104 -    SDL_free(context);
   9.105 +    *num_joysticks -= 1;
   9.106 +    if (send_event) {
   9.107 +        SDL_PrivateJoystickRemoved(ctx->joystickID);
   9.108 +    }
   9.109 +    SDL_free(context->context);
   9.110 +}
   9.111 +
   9.112 +static int
   9.113 +HIDAPI_DriverSwitch_NumJoysticks(SDL_HIDAPI_DriverData *context)
   9.114 +{
   9.115 +    return 1;
   9.116 +}
   9.117 +
   9.118 +static SDL_JoystickID
   9.119 +HIDAPI_DriverSwitch_InstanceIDForIndex(SDL_HIDAPI_DriverData *context, int index)
   9.120 +{
   9.121 +    SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context->context;
   9.122 +    return ctx->joystickID;
   9.123  }
   9.124  
   9.125  SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch =
   9.126 @@ -892,10 +927,13 @@
   9.127      SDL_TRUE,
   9.128      HIDAPI_DriverSwitch_IsSupportedDevice,
   9.129      HIDAPI_DriverSwitch_GetDeviceName,
   9.130 -    HIDAPI_DriverSwitch_Init,
   9.131 -    HIDAPI_DriverSwitch_Rumble,
   9.132 -    HIDAPI_DriverSwitch_Update,
   9.133 -    HIDAPI_DriverSwitch_Quit
   9.134 +    HIDAPI_DriverSwitch_InitDriver,
   9.135 +    HIDAPI_DriverSwitch_QuitDriver,
   9.136 +    HIDAPI_DriverSwitch_UpdateDriver,
   9.137 +    HIDAPI_DriverSwitch_NumJoysticks,
   9.138 +    HIDAPI_DriverSwitch_InstanceIDForIndex,
   9.139 +    HIDAPI_DriverSwitch_OpenJoystick,
   9.140 +    HIDAPI_DriverSwitch_Rumble
   9.141  };
   9.142  
   9.143  #endif /* SDL_JOYSTICK_HIDAPI_SWITCH */
    10.1 --- a/src/joystick/hidapi/SDL_hidapi_xbox360.c	Sat Mar 16 17:47:59 2019 -0700
    10.2 +++ b/src/joystick/hidapi/SDL_hidapi_xbox360.c	Tue Mar 12 20:27:54 2019 -0400
    10.3 @@ -54,6 +54,7 @@
    10.4  
    10.5  
    10.6  typedef struct {
    10.7 +    SDL_JoystickID joystickID;
    10.8      Uint8 last_state[USB_PACKET_LENGTH];
    10.9      Uint32 rumble_expiration;
   10.10  #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
   10.11 @@ -277,7 +278,7 @@
   10.12  }
   10.13  
   10.14  static SDL_bool
   10.15 -HIDAPI_DriverXbox360_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
   10.16 +HIDAPI_DriverXbox360_InitDriver(SDL_HIDAPI_DriverData *context, Uint16 vendor_id, Uint16 product_id, int *num_joysticks)
   10.17  {
   10.18      SDL_DriverXbox360_Context *ctx;
   10.19  
   10.20 @@ -296,10 +297,20 @@
   10.21  #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
   10.22      HIDAPI_DriverXbox360_InitWindowsGamingInput(ctx);
   10.23  #endif
   10.24 -    *context = ctx;
   10.25 +    context->context = ctx;
   10.26  
   10.27 +    ctx->joystickID = SDL_GetNextJoystickInstanceID();
   10.28 +    *num_joysticks += 1;
   10.29 +    SDL_PrivateJoystickAdded(ctx->joystickID);
   10.30 +
   10.31 +    return SDL_TRUE;
   10.32 +}
   10.33 +
   10.34 +static SDL_bool
   10.35 +HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick)
   10.36 +{
   10.37      /* Set the controller LED */
   10.38 -    SetSlotLED(dev, (joystick->instance_id % 4));
   10.39 +    SetSlotLED(context->device, (joystick->instance_id % 4));
   10.40  
   10.41      /* Initialize the joystick capabilities */
   10.42      joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
   10.43 @@ -310,9 +321,22 @@
   10.44  }
   10.45  
   10.46  static int
   10.47 -HIDAPI_DriverXbox360_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   10.48 +HIDAPI_DriverXbox360_NumJoysticks(SDL_HIDAPI_DriverData *context)
   10.49  {
   10.50 -    SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
   10.51 +    return 1;
   10.52 +}
   10.53 +
   10.54 +static SDL_JoystickID
   10.55 +HIDAPI_DriverXbox360_InstanceIDForIndex(SDL_HIDAPI_DriverData *context, int index)
   10.56 +{
   10.57 +    SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context->context;
   10.58 +    return ctx->joystickID;
   10.59 +}
   10.60 +
   10.61 +static int
   10.62 +HIDAPI_DriverXbox360_Rumble(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   10.63 +{
   10.64 +    SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context->context;
   10.65  
   10.66  #ifdef __WIN32__
   10.67      SDL_bool rumbled = SDL_FALSE;
   10.68 @@ -365,7 +389,7 @@
   10.69      rumble_packet[4] = (high_frequency_rumble >> 8);
   10.70  #endif
   10.71  
   10.72 -    if (hid_write(dev, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
   10.73 +    if (hid_write(context->device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
   10.74          return SDL_SetError("Couldn't send rumble packet");
   10.75      }
   10.76  #endif /* __WIN32__ */
   10.77 @@ -705,26 +729,31 @@
   10.78  #endif /* __MACOSX__ */
   10.79  
   10.80  static SDL_bool
   10.81 -HIDAPI_DriverXbox360_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
   10.82 +HIDAPI_DriverXbox360_UpdateDriver(SDL_HIDAPI_DriverData *context, int *num_joysticks)
   10.83  {
   10.84 -    SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
   10.85 +    SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context->context;
   10.86 +    SDL_Joystick *joystick = SDL_JoystickFromInstanceID(ctx->joystickID);
   10.87      Uint8 data[USB_PACKET_LENGTH];
   10.88      int size;
   10.89  
   10.90 -    while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
   10.91 +    if (joystick == NULL) {
   10.92 +        return SDL_TRUE; /* Nothing to do right now! */
   10.93 +    }
   10.94 +
   10.95 +    while ((size = hid_read_timeout(context->device, data, sizeof(data), 0)) > 0) {
   10.96  #ifdef __WIN32__
   10.97 -        HIDAPI_DriverXbox360_HandleStatePacket(joystick, dev, ctx, data, size);
   10.98 +        HIDAPI_DriverXbox360_HandleStatePacket(joystick, context->device, ctx, data, size);
   10.99  #else
  10.100          switch (data[0]) {
  10.101          case 0x00:
  10.102 -            HIDAPI_DriverXbox360_HandleStatePacket(joystick, dev, ctx, data, size);
  10.103 +            HIDAPI_DriverXbox360_HandleStatePacket(joystick, context->device, ctx, data, size);
  10.104              break;
  10.105  #ifdef __MACOSX__
  10.106          case 0x01:
  10.107 -            HIDAPI_DriverXboxOneS_HandleStatePacket(joystick, dev, ctx, data, size);
  10.108 +            HIDAPI_DriverXboxOneS_HandleStatePacket(joystick, context->device, ctx, data, size);
  10.109              break;
  10.110          case 0x02:
  10.111 -            HIDAPI_DriverXboxOneS_HandleGuidePacket(joystick, dev, ctx, data, size);
  10.112 +            HIDAPI_DriverXboxOneS_HandleGuidePacket(joystick, context->device, ctx, data, size);
  10.113              break;
  10.114  #endif
  10.115          default:
  10.116 @@ -742,7 +771,7 @@
  10.117      if (ctx->rumble_expiration) {
  10.118          Uint32 now = SDL_GetTicks();
  10.119          if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
  10.120 -            HIDAPI_DriverXbox360_Rumble(joystick, dev, context, 0, 0, 0);
  10.121 +            HIDAPI_DriverXbox360_Rumble(context, joystick, 0, 0, 0);
  10.122          }
  10.123      }
  10.124  
  10.125 @@ -750,11 +779,9 @@
  10.126  }
  10.127  
  10.128  static void
  10.129 -HIDAPI_DriverXbox360_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
  10.130 +HIDAPI_DriverXbox360_QuitDriver(SDL_HIDAPI_DriverData *context, SDL_bool send_event, int *num_joysticks)
  10.131  {
  10.132 -#if defined(SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT)
  10.133 -    SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
  10.134 -#endif
  10.135 +    SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context->context;
  10.136  
  10.137  #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
  10.138      if (ctx->xinput_enabled) {
  10.139 @@ -765,7 +792,11 @@
  10.140  #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
  10.141      HIDAPI_DriverXbox360_InitWindowsGamingInput(ctx);
  10.142  #endif
  10.143 -    SDL_free(context);
  10.144 +    *num_joysticks -= 1;
  10.145 +    if (send_event) {
  10.146 +        SDL_PrivateJoystickRemoved(ctx->joystickID);
  10.147 +    }
  10.148 +    SDL_free(context->context);
  10.149  }
  10.150  
  10.151  SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360 =
  10.152 @@ -774,10 +805,13 @@
  10.153      SDL_TRUE,
  10.154      HIDAPI_DriverXbox360_IsSupportedDevice,
  10.155      HIDAPI_DriverXbox360_GetDeviceName,
  10.156 -    HIDAPI_DriverXbox360_Init,
  10.157 -    HIDAPI_DriverXbox360_Rumble,
  10.158 -    HIDAPI_DriverXbox360_Update,
  10.159 -    HIDAPI_DriverXbox360_Quit
  10.160 +    HIDAPI_DriverXbox360_InitDriver,
  10.161 +    HIDAPI_DriverXbox360_QuitDriver,
  10.162 +    HIDAPI_DriverXbox360_UpdateDriver,
  10.163 +    HIDAPI_DriverXbox360_NumJoysticks,
  10.164 +    HIDAPI_DriverXbox360_InstanceIDForIndex,
  10.165 +    HIDAPI_DriverXbox360_OpenJoystick,
  10.166 +    HIDAPI_DriverXbox360_Rumble
  10.167  };
  10.168  
  10.169  #endif /* SDL_JOYSTICK_HIDAPI_XBOX360 */
    11.1 --- a/src/joystick/hidapi/SDL_hidapi_xboxone.c	Sat Mar 16 17:47:59 2019 -0700
    11.2 +++ b/src/joystick/hidapi/SDL_hidapi_xboxone.c	Tue Mar 12 20:27:54 2019 -0400
    11.3 @@ -124,6 +124,7 @@
    11.4  };
    11.5  
    11.6  typedef struct {
    11.7 +    SDL_JoystickID joystickID;
    11.8      Uint8 sequence;
    11.9      Uint8 last_state[USB_PACKET_LENGTH];
   11.10      Uint32 rumble_expiration;
   11.11 @@ -143,7 +144,7 @@
   11.12  }
   11.13  
   11.14  static SDL_bool
   11.15 -HIDAPI_DriverXboxOne_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
   11.16 +HIDAPI_DriverXboxOne_InitDriver(SDL_HIDAPI_DriverData *context, Uint16 vendor_id, Uint16 product_id, int *num_joysticks)
   11.17  {
   11.18      SDL_DriverXboxOne_Context *ctx;
   11.19      int i;
   11.20 @@ -154,7 +155,7 @@
   11.21          SDL_OutOfMemory();
   11.22          return SDL_FALSE;
   11.23      }
   11.24 -    *context = ctx;
   11.25 +    context->context = ctx;
   11.26  
   11.27      /* Send the controller init data */
   11.28      for (i = 0; i < SDL_arraysize(xboxone_init_packets); ++i) {
   11.29 @@ -162,7 +163,7 @@
   11.30          if (!packet->vendor_id || (vendor_id == packet->vendor_id && product_id == packet->product_id)) {
   11.31              SDL_memcpy(init_packet, packet->data, packet->size);
   11.32              init_packet[2] = ctx->sequence++;
   11.33 -            if (hid_write(dev, init_packet, packet->size) != packet->size) {
   11.34 +            if (hid_write(context->device, init_packet, packet->size) != packet->size) {
   11.35                  SDL_SetError("Couldn't write Xbox One initialization packet");
   11.36                  SDL_free(ctx);
   11.37                  return SDL_FALSE;
   11.38 @@ -170,6 +171,16 @@
   11.39          }
   11.40      }
   11.41  
   11.42 +    ctx->joystickID = SDL_GetNextJoystickInstanceID();
   11.43 +    *num_joysticks += 1;
   11.44 +    SDL_PrivateJoystickAdded(ctx->joystickID);
   11.45 +
   11.46 +    return SDL_TRUE;
   11.47 +}
   11.48 +
   11.49 +static SDL_bool
   11.50 +HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick)
   11.51 +{
   11.52      /* Initialize the joystick capabilities */
   11.53      joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
   11.54      joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
   11.55 @@ -178,10 +189,35 @@
   11.56      return SDL_TRUE;
   11.57  }
   11.58  
   11.59 +static void
   11.60 +HIDAPI_DriverXboxOne_QuitDriver(SDL_HIDAPI_DriverData *context, SDL_bool send_event, int *num_joysticks)
   11.61 +{
   11.62 +    SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context->context;
   11.63 +
   11.64 +    *num_joysticks -= 1;
   11.65 +    if (send_event) {
   11.66 +        SDL_PrivateJoystickRemoved(ctx->joystickID);
   11.67 +    }
   11.68 +    SDL_free(context->context);
   11.69 +}
   11.70 +
   11.71  static int
   11.72 -HIDAPI_DriverXboxOne_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   11.73 +HIDAPI_DriverXboxOne_NumJoysticks(SDL_HIDAPI_DriverData *context)
   11.74  {
   11.75 -    SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context;
   11.76 +    return 1;
   11.77 +}
   11.78 +
   11.79 +static SDL_JoystickID
   11.80 +HIDAPI_DriverXboxOne_InstanceIDForIndex(SDL_HIDAPI_DriverData *context, int index)
   11.81 +{
   11.82 +    SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context->context;
   11.83 +    return ctx->joystickID;
   11.84 +}
   11.85 +
   11.86 +static int
   11.87 +HIDAPI_DriverXboxOne_Rumble(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   11.88 +{
   11.89 +    SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context->context;
   11.90      Uint8 rumble_packet[] = { 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF };
   11.91  
   11.92      /* The Rock Candy Xbox One Controller limits the range of
   11.93 @@ -194,7 +230,7 @@
   11.94      rumble_packet[8] = (low_frequency_rumble >> 9);
   11.95      rumble_packet[9] = (high_frequency_rumble >> 9);
   11.96  
   11.97 -    if (hid_write(dev, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
   11.98 +    if (hid_write(context->device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
   11.99          return SDL_SetError("Couldn't send rumble packet");
  11.100      }
  11.101  
  11.102 @@ -267,19 +303,24 @@
  11.103  }
  11.104  
  11.105  static SDL_bool
  11.106 -HIDAPI_DriverXboxOne_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
  11.107 +HIDAPI_DriverXboxOne_UpdateDriver(SDL_HIDAPI_DriverData *context, int *num_joysticks)
  11.108  {
  11.109 -    SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context;
  11.110 +    SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context->context;
  11.111 +    SDL_Joystick *joystick = SDL_JoystickFromInstanceID(ctx->joystickID);
  11.112      Uint8 data[USB_PACKET_LENGTH];
  11.113      int size;
  11.114  
  11.115 -    while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
  11.116 +    if (joystick == NULL) {
  11.117 +        return SDL_TRUE; /* Nothing to do right now! */
  11.118 +    }
  11.119 +
  11.120 +    while ((size = hid_read_timeout(context->device, data, sizeof(data), 0)) > 0) {
  11.121          switch (data[0]) {
  11.122          case 0x20:
  11.123 -            HIDAPI_DriverXboxOne_HandleStatePacket(joystick, dev, ctx, data, size);
  11.124 +            HIDAPI_DriverXboxOne_HandleStatePacket(joystick, context->device, ctx, data, size);
  11.125              break;
  11.126          case 0x07:
  11.127 -            HIDAPI_DriverXboxOne_HandleModePacket(joystick, dev, ctx, data, size);
  11.128 +            HIDAPI_DriverXboxOne_HandleModePacket(joystick, context->device, ctx, data, size);
  11.129              break;
  11.130          default:
  11.131  #ifdef DEBUG_JOYSTICK
  11.132 @@ -292,29 +333,26 @@
  11.133      if (ctx->rumble_expiration) {
  11.134          Uint32 now = SDL_GetTicks();
  11.135          if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
  11.136 -            HIDAPI_DriverXboxOne_Rumble(joystick, dev, context, 0, 0, 0);
  11.137 +            HIDAPI_DriverXboxOne_Rumble(context, joystick, 0, 0, 0);
  11.138          }
  11.139      }
  11.140  
  11.141      return (size >= 0);
  11.142  }
  11.143  
  11.144 -static void
  11.145 -HIDAPI_DriverXboxOne_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
  11.146 -{
  11.147 -    SDL_free(context);
  11.148 -}
  11.149 -
  11.150  SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne =
  11.151  {
  11.152      SDL_HINT_JOYSTICK_HIDAPI_XBOX,
  11.153      SDL_TRUE,
  11.154      HIDAPI_DriverXboxOne_IsSupportedDevice,
  11.155      HIDAPI_DriverXboxOne_GetDeviceName,
  11.156 -    HIDAPI_DriverXboxOne_Init,
  11.157 -    HIDAPI_DriverXboxOne_Rumble,
  11.158 -    HIDAPI_DriverXboxOne_Update,
  11.159 -    HIDAPI_DriverXboxOne_Quit
  11.160 +    HIDAPI_DriverXboxOne_InitDriver,
  11.161 +    HIDAPI_DriverXboxOne_QuitDriver,
  11.162 +    HIDAPI_DriverXboxOne_UpdateDriver,
  11.163 +    HIDAPI_DriverXboxOne_NumJoysticks,
  11.164 +    HIDAPI_DriverXboxOne_InstanceIDForIndex,
  11.165 +    HIDAPI_DriverXboxOne_OpenJoystick,
  11.166 +    HIDAPI_DriverXboxOne_Rumble
  11.167  };
  11.168  
  11.169  #endif /* SDL_JOYSTICK_HIDAPI_XBOXONE */
    12.1 --- a/src/joystick/hidapi/SDL_hidapijoystick.c	Sat Mar 16 17:47:59 2019 -0700
    12.2 +++ b/src/joystick/hidapi/SDL_hidapijoystick.c	Tue Mar 12 20:27:54 2019 -0400
    12.3 @@ -50,18 +50,10 @@
    12.4  #endif
    12.5  #endif
    12.6  
    12.7 -struct joystick_hwdata
    12.8 -{
    12.9 -    SDL_HIDAPI_DeviceDriver *driver;
   12.10 -    void *context;
   12.11 -
   12.12 -    SDL_mutex *mutex;
   12.13 -    hid_device *dev;
   12.14 -};
   12.15 -
   12.16  typedef struct _SDL_HIDAPI_Device
   12.17  {
   12.18 -    SDL_JoystickID instance_id;
   12.19 +    SDL_HIDAPI_DriverData devdata;
   12.20 +    SDL_mutex *mutex;
   12.21      char *name;
   12.22      char *path;
   12.23      Uint16 vendor_id;
   12.24 @@ -95,6 +87,9 @@
   12.25  #ifdef SDL_JOYSTICK_HIDAPI_XBOXONE
   12.26      &SDL_HIDAPI_DriverXboxOne,
   12.27  #endif
   12.28 +#ifdef SDL_JOYSTICK_HIDAPI_GAMECUBE
   12.29 +    &SDL_HIDAPI_DriverGameCube,
   12.30 +#endif
   12.31  };
   12.32  static SDL_HIDAPI_Device *SDL_HIDAPI_devices;
   12.33  static int SDL_HIDAPI_numjoysticks = 0;
   12.34 @@ -393,6 +388,36 @@
   12.35  #endif
   12.36  }
   12.37  
   12.38 +static void
   12.39 +HIDAPI_InitDriver(SDL_HIDAPI_Device *device)
   12.40 +{
   12.41 +    device->devdata.device = hid_open_path(device->path, 0);
   12.42 +    if (!device->devdata.device) {
   12.43 +        SDL_SetError("Couldn't open HID device %s", device->path);
   12.44 +        device->driver = NULL;
   12.45 +    } else {
   12.46 +        device->driver->InitDriver(
   12.47 +            &device->devdata,
   12.48 +            device->vendor_id,
   12.49 +            device->product_id,
   12.50 +            &SDL_HIDAPI_numjoysticks
   12.51 +        );
   12.52 +        device->mutex = SDL_CreateMutex();
   12.53 +    }
   12.54 +}
   12.55 +
   12.56 +static void
   12.57 +HIDAPI_QuitDriver(SDL_HIDAPI_Device *device, SDL_bool send_event)
   12.58 +{
   12.59 +    device->driver->QuitDriver(
   12.60 +        &device->devdata,
   12.61 +        send_event,
   12.62 +        &SDL_HIDAPI_numjoysticks
   12.63 +    );
   12.64 +    hid_close(device->devdata.device);
   12.65 +    SDL_DestroyMutex(device->mutex);
   12.66 +    device->driver = NULL;
   12.67 +}
   12.68  
   12.69  const char *
   12.70  HIDAPI_XboxControllerName(Uint16 vendor_id, Uint16 product_id)
   12.71 @@ -605,15 +630,17 @@
   12.72  }
   12.73  
   12.74  static SDL_HIDAPI_Device *
   12.75 -HIDAPI_GetJoystickByIndex(int device_index)
   12.76 +HIDAPI_GetDeviceByIndex(int device_index)
   12.77  {
   12.78      SDL_HIDAPI_Device *device = SDL_HIDAPI_devices;
   12.79 +    int joysticks;
   12.80      while (device) {
   12.81          if (device->driver) {
   12.82 -            if (device_index == 0) {
   12.83 +            joysticks = device->driver->NumJoysticks(&device->devdata);
   12.84 +            if (device_index < joysticks) {
   12.85                  break;
   12.86              }
   12.87 -            --device_index;
   12.88 +            device_index -= joysticks;
   12.89          }
   12.90          device = device->next;
   12.91      }
   12.92 @@ -660,20 +687,12 @@
   12.93      while (device) {
   12.94          if (device->driver) {
   12.95              if (!device->driver->enabled) {
   12.96 -                device->driver = NULL;
   12.97 -
   12.98 -                --SDL_HIDAPI_numjoysticks;
   12.99 -
  12.100 -                SDL_PrivateJoystickRemoved(device->instance_id);
  12.101 +                HIDAPI_QuitDriver(device, SDL_TRUE);
  12.102              }
  12.103          } else {
  12.104              device->driver = HIDAPI_GetDeviceDriver(device);
  12.105              if (device->driver) {
  12.106 -                device->instance_id = SDL_GetNextJoystickInstanceID();
  12.107 -
  12.108 -                ++SDL_HIDAPI_numjoysticks;
  12.109 -
  12.110 -                SDL_PrivateJoystickAdded(device->instance_id);
  12.111 +                HIDAPI_InitDriver(device);
  12.112              }
  12.113          }
  12.114          device = device->next;
  12.115 @@ -723,7 +742,6 @@
  12.116      if (!device) {
  12.117          return;
  12.118      }
  12.119 -    device->instance_id = -1;
  12.120      device->seen = SDL_TRUE;
  12.121      device->vendor_id = info->vendor_id;
  12.122      device->product_id = info->product_id;
  12.123 @@ -818,12 +836,8 @@
  12.124      }
  12.125  
  12.126      if (device->driver) {
  12.127 -        /* It's a joystick! */
  12.128 -        device->instance_id = SDL_GetNextJoystickInstanceID();
  12.129 -
  12.130 -        ++SDL_HIDAPI_numjoysticks;
  12.131 -
  12.132 -        SDL_PrivateJoystickAdded(device->instance_id);
  12.133 +        /* It's a joystick device! */
  12.134 +        HIDAPI_InitDriver(device);
  12.135      }
  12.136  }
  12.137  
  12.138 @@ -840,11 +854,8 @@
  12.139                  SDL_HIDAPI_devices = curr->next;
  12.140              }
  12.141  
  12.142 -            if (device->driver && send_event) {
  12.143 -                /* Need to decrement the joystick count before we post the event */
  12.144 -                --SDL_HIDAPI_numjoysticks;
  12.145 -
  12.146 -                SDL_PrivateJoystickRemoved(device->instance_id);
  12.147 +            if (device->driver) {
  12.148 +                HIDAPI_QuitDriver(device, send_event);
  12.149              }
  12.150  
  12.151              SDL_free(device->name);
  12.152 @@ -931,7 +942,7 @@
  12.153  static const char *
  12.154  HIDAPI_JoystickGetDeviceName(int device_index)
  12.155  {
  12.156 -    return HIDAPI_GetJoystickByIndex(device_index)->name;
  12.157 +    return HIDAPI_GetDeviceByIndex(device_index)->name;
  12.158  }
  12.159  
  12.160  static int
  12.161 @@ -943,89 +954,61 @@
  12.162  static SDL_JoystickGUID
  12.163  HIDAPI_JoystickGetDeviceGUID(int device_index)
  12.164  {
  12.165 -    return HIDAPI_GetJoystickByIndex(device_index)->guid;
  12.166 +    return HIDAPI_GetDeviceByIndex(device_index)->guid;
  12.167  }
  12.168  
  12.169  static SDL_JoystickID
  12.170  HIDAPI_JoystickGetDeviceInstanceID(int device_index)
  12.171  {
  12.172 -    return HIDAPI_GetJoystickByIndex(device_index)->instance_id;
  12.173 +    SDL_HIDAPI_Device *device = SDL_HIDAPI_devices;
  12.174 +    int joysticks;
  12.175 +    while (device) {
  12.176 +        if (device->driver) {
  12.177 +            joysticks = device->driver->NumJoysticks(&device->devdata);
  12.178 +            if (device_index < joysticks) {
  12.179 +                break;
  12.180 +            }
  12.181 +            device_index -= joysticks;
  12.182 +        }
  12.183 +        device = device->next;
  12.184 +    }
  12.185 +    return device->driver->InstanceIDForIndex(&device->devdata, device_index);
  12.186  }
  12.187  
  12.188  static int
  12.189  HIDAPI_JoystickOpen(SDL_Joystick * joystick, int device_index)
  12.190  {
  12.191 -    SDL_HIDAPI_Device *device = HIDAPI_GetJoystickByIndex(device_index);
  12.192 -    struct joystick_hwdata *hwdata;
  12.193 +    SDL_HIDAPI_Device *device = HIDAPI_GetDeviceByIndex(device_index);
  12.194  
  12.195 -    hwdata = (struct joystick_hwdata *)SDL_calloc(1, sizeof(*hwdata));
  12.196 -    if (!hwdata) {
  12.197 -        return SDL_OutOfMemory();
  12.198 -    }
  12.199 -
  12.200 -    hwdata->driver = device->driver;
  12.201 -    hwdata->dev = hid_open_path(device->path, 0);
  12.202 -    if (!hwdata->dev) {
  12.203 -        SDL_free(hwdata);
  12.204 -        return SDL_SetError("Couldn't open HID device %s", device->path);
  12.205 -    }
  12.206 -    hwdata->mutex = SDL_CreateMutex();
  12.207 -
  12.208 -    if (!device->driver->Init(joystick, hwdata->dev, device->vendor_id, device->product_id, &hwdata->context)) {
  12.209 -        hid_close(hwdata->dev);
  12.210 -        SDL_free(hwdata);
  12.211 +    if (!device->driver->OpenJoystick(&device->devdata, joystick)) {
  12.212          return -1;
  12.213      }
  12.214  
  12.215 -    joystick->hwdata = hwdata;
  12.216 +    joystick->hwdata = (struct joystick_hwdata *)device;
  12.217      return 0;
  12.218  }
  12.219  
  12.220  static int
  12.221  HIDAPI_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
  12.222  {
  12.223 -    struct joystick_hwdata *hwdata = joystick->hwdata;
  12.224 -    SDL_HIDAPI_DeviceDriver *driver = hwdata->driver;
  12.225 +    SDL_HIDAPI_Device *device = (SDL_HIDAPI_Device *)joystick->hwdata;
  12.226      int result;
  12.227  
  12.228 -    SDL_LockMutex(hwdata->mutex);
  12.229 -    result = driver->Rumble(joystick, hwdata->dev, hwdata->context, low_frequency_rumble, high_frequency_rumble, duration_ms);
  12.230 -    SDL_UnlockMutex(hwdata->mutex);
  12.231 +    SDL_LockMutex(device->mutex);
  12.232 +    result = device->driver->Rumble(&device->devdata, joystick, low_frequency_rumble, high_frequency_rumble, duration_ms);
  12.233 +    SDL_UnlockMutex(device->mutex);
  12.234      return result;
  12.235  }
  12.236  
  12.237  static void
  12.238  HIDAPI_JoystickUpdate(SDL_Joystick * joystick)
  12.239  {
  12.240 -    struct joystick_hwdata *hwdata = joystick->hwdata;
  12.241 -    SDL_HIDAPI_DeviceDriver *driver = hwdata->driver;
  12.242 -    SDL_bool succeeded;
  12.243 -
  12.244 -    SDL_LockMutex(hwdata->mutex);
  12.245 -    succeeded = driver->Update(joystick, hwdata->dev, hwdata->context);
  12.246 -    SDL_UnlockMutex(hwdata->mutex);
  12.247 -    
  12.248 -    if (!succeeded) {
  12.249 -        SDL_HIDAPI_Device *device;
  12.250 -        for (device = SDL_HIDAPI_devices; device; device = device->next) {
  12.251 -            if (device->instance_id == joystick->instance_id) {
  12.252 -                HIDAPI_DelDevice(device, SDL_TRUE);
  12.253 -                break;
  12.254 -            }
  12.255 -        }
  12.256 -    }
  12.257 +    /* No-op, all updates are done in SDL_HIDAPI_UpdateDevices */
  12.258  }
  12.259  
  12.260  static void
  12.261  HIDAPI_JoystickClose(SDL_Joystick * joystick)
  12.262  {
  12.263 -    struct joystick_hwdata *hwdata = joystick->hwdata;
  12.264 -    SDL_HIDAPI_DeviceDriver *driver = hwdata->driver;
  12.265 -    driver->Quit(joystick, hwdata->dev, hwdata->context);
  12.266 -
  12.267 -    hid_close(hwdata->dev);
  12.268 -    SDL_DestroyMutex(hwdata->mutex);
  12.269 -    SDL_free(hwdata);
  12.270      joystick->hwdata = NULL;
  12.271  }
  12.272  
  12.273 @@ -1050,6 +1033,30 @@
  12.274      hid_exit();
  12.275  }
  12.276  
  12.277 +void
  12.278 +SDL_HIDAPI_UpdateDevices(void)
  12.279 +{
  12.280 +    SDL_HIDAPI_Device *next, *device = SDL_HIDAPI_devices;
  12.281 +    SDL_bool succeeded;
  12.282 +
  12.283 +    while (device) {
  12.284 +        if (device->driver) {
  12.285 +            SDL_LockMutex(device->mutex);
  12.286 +            succeeded = device->driver->UpdateDriver(&device->devdata, &SDL_HIDAPI_numjoysticks);
  12.287 +            SDL_UnlockMutex(device->mutex);
  12.288 +            if (!succeeded) {
  12.289 +                next = device->next;
  12.290 +                HIDAPI_DelDevice(device, SDL_TRUE);
  12.291 +                device = next;
  12.292 +            } else {
  12.293 +                device = device->next;
  12.294 +            }
  12.295 +        } else {
  12.296 +            device = device->next;
  12.297 +        }
  12.298 +    }
  12.299 +}
  12.300 +
  12.301  SDL_JoystickDriver SDL_HIDAPI_JoystickDriver =
  12.302  {
  12.303      HIDAPI_JoystickInit,
    13.1 --- a/src/joystick/hidapi/SDL_hidapijoystick_c.h	Sat Mar 16 17:47:59 2019 -0700
    13.2 +++ b/src/joystick/hidapi/SDL_hidapijoystick_c.h	Tue Mar 12 20:27:54 2019 -0400
    13.3 @@ -30,6 +30,7 @@
    13.4  #define SDL_JOYSTICK_HIDAPI_SWITCH
    13.5  #define SDL_JOYSTICK_HIDAPI_XBOX360
    13.6  #define SDL_JOYSTICK_HIDAPI_XBOXONE
    13.7 +#define SDL_JOYSTICK_HIDAPI_GAMECUBE
    13.8  
    13.9  #ifdef __WINDOWS__
   13.10  /* On Windows, Xbox One controllers are handled by the Xbox 360 driver */
   13.11 @@ -43,16 +44,36 @@
   13.12  #undef SDL_JOYSTICK_HIDAPI_XBOXONE
   13.13  #endif
   13.14  
   13.15 +typedef struct _SDL_HIDAPI_DriverData
   13.16 +{
   13.17 +    hid_device *device;
   13.18 +    void *context;
   13.19 +} SDL_HIDAPI_DriverData;
   13.20 +
   13.21  typedef struct _SDL_HIDAPI_DeviceDriver
   13.22  {
   13.23      const char *hint;
   13.24      SDL_bool enabled;
   13.25      SDL_bool (*IsSupportedDevice)(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number);
   13.26      const char *(*GetDeviceName)(Uint16 vendor_id, Uint16 product_id);
   13.27 -    SDL_bool (*Init)(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context);
   13.28 -    int (*Rumble)(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
   13.29 -    SDL_bool (*Update)(SDL_Joystick *joystick, hid_device *dev, void *context);
   13.30 -    void (*Quit)(SDL_Joystick *joystick, hid_device *dev, void *context);
   13.31 +
   13.32 +    SDL_bool       (*InitDriver)(SDL_HIDAPI_DriverData *context,
   13.33 +                                 Uint16 vendor_id, Uint16 product_id, int *num_joysticks);
   13.34 +    void           (*QuitDriver)(SDL_HIDAPI_DriverData *context,
   13.35 +                                 SDL_bool send_event,
   13.36 +                                 int *num_joysticks);
   13.37 +    SDL_bool       (*UpdateDriver)(SDL_HIDAPI_DriverData *context,
   13.38 +                                   int *num_joysticks);
   13.39 +    int            (*NumJoysticks)(SDL_HIDAPI_DriverData *context);
   13.40 +    SDL_JoystickID (*InstanceIDForIndex)(SDL_HIDAPI_DriverData *context,
   13.41 +                                         int index);
   13.42 +    SDL_bool       (*OpenJoystick)(SDL_HIDAPI_DriverData *context,
   13.43 +                                   SDL_Joystick *joystick);
   13.44 +    int            (*Rumble)(SDL_HIDAPI_DriverData *context,
   13.45 +                             SDL_Joystick *joystick,
   13.46 +                             Uint16 low_frequency_rumble,
   13.47 +                             Uint16 high_frequency_rumble,
   13.48 +                             Uint32 duration_ms);
   13.49  
   13.50  } SDL_HIDAPI_DeviceDriver;
   13.51  
   13.52 @@ -62,6 +83,7 @@
   13.53  extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch;
   13.54  extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360;
   13.55  extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne;
   13.56 +extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube;
   13.57  
   13.58  /* Return true if a HID device is present and supported as a joystick */
   13.59  extern SDL_bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version);