From 03f8528315fa46c95991a34f3325d7b33ae5538c Mon Sep 17 00:00:00 2001
From: Edward Rudd <urkle@outoforder.cc>
Date: Sat, 02 May 2020 21:48:36 +0000
Subject: [PATCH] Update source to SDL2 2.0.12
---
source/src/joystick/hidapi/SDL_hidapijoystick.c | 719 +++++++++++++++++++++++++++++++----------------------------
1 files changed, 380 insertions(+), 339 deletions(-)
diff --git a/source/src/joystick/hidapi/SDL_hidapijoystick.c b/source/src/joystick/hidapi/SDL_hidapijoystick.c
index 064cb82..579d096 100644
--- a/source/src/joystick/hidapi/SDL_hidapijoystick.c
+++ b/source/src/joystick/hidapi/SDL_hidapijoystick.c
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
- Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+ Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -22,15 +22,18 @@
#ifdef SDL_JOYSTICK_HIDAPI
+#include "SDL_assert.h"
+#include "SDL_atomic.h"
#include "SDL_endian.h"
#include "SDL_hints.h"
#include "SDL_log.h"
-#include "SDL_mutex.h"
#include "SDL_thread.h"
#include "SDL_timer.h"
#include "SDL_joystick.h"
#include "../SDL_sysjoystick.h"
#include "SDL_hidapijoystick_c.h"
+#include "SDL_hidapi_rumble.h"
+#include "../../SDL_hints_c.h"
#if defined(__WIN32__)
#include "../../core/windows/SDL_windows.h"
@@ -40,6 +43,7 @@
#include <CoreFoundation/CoreFoundation.h>
#include <mach/mach.h>
#include <IOKit/IOKitLib.h>
+#include <IOKit/hid/IOHIDDevice.h>
#include <IOKit/usb/USBSpec.h>
#endif
@@ -52,32 +56,8 @@
struct joystick_hwdata
{
- SDL_HIDAPI_DeviceDriver *driver;
- void *context;
-
- SDL_mutex *mutex;
- hid_device *dev;
+ SDL_HIDAPI_Device *device;
};
-
-typedef struct _SDL_HIDAPI_Device
-{
- SDL_JoystickID instance_id;
- char *name;
- char *path;
- Uint16 vendor_id;
- Uint16 product_id;
- Uint16 version;
- SDL_JoystickGUID guid;
- int interface_number; /* Available on Windows and Linux */
- Uint16 usage_page; /* Available on Windows and Mac OS X */
- Uint16 usage; /* Available on Windows and Mac OS X */
- SDL_HIDAPI_DeviceDriver *driver;
-
- /* Used during scanning for device changes */
- SDL_bool seen;
-
- struct _SDL_HIDAPI_Device *next;
-} SDL_HIDAPI_Device;
static SDL_HIDAPI_DeviceDriver *SDL_HIDAPI_drivers[] = {
#ifdef SDL_JOYSTICK_HIDAPI_PS4
@@ -91,13 +71,21 @@
#endif
#ifdef SDL_JOYSTICK_HIDAPI_XBOX360
&SDL_HIDAPI_DriverXbox360,
+ &SDL_HIDAPI_DriverXbox360W,
#endif
#ifdef SDL_JOYSTICK_HIDAPI_XBOXONE
&SDL_HIDAPI_DriverXboxOne,
#endif
+#ifdef SDL_JOYSTICK_HIDAPI_GAMECUBE
+ &SDL_HIDAPI_DriverGameCube,
+#endif
};
+static int SDL_HIDAPI_numdrivers = 0;
+static SDL_SpinLock SDL_HIDAPI_spinlock;
static SDL_HIDAPI_Device *SDL_HIDAPI_devices;
static int SDL_HIDAPI_numjoysticks = 0;
+static SDL_bool initialized = SDL_FALSE;
+static SDL_bool shutting_down = SDL_FALSE;
#if defined(SDL_USE_LIBUDEV)
static const SDL_UDEV_Symbols * usyms = NULL;
@@ -231,12 +219,15 @@
SDL_HIDAPI_discovery.m_notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
if (SDL_HIDAPI_discovery.m_notificationPort) {
{
- CFMutableDictionaryRef matchingDict = IOServiceMatching("IOUSBDevice");
-
- /* Note: IOServiceAddMatchingNotification consumes the reference to matchingDict */
io_iterator_t portIterator = 0;
io_object_t entry;
- if (IOServiceAddMatchingNotification(SDL_HIDAPI_discovery.m_notificationPort, kIOMatchedNotification, matchingDict, CallbackIOServiceFunc, &SDL_HIDAPI_discovery.m_bHaveDevicesChanged, &portIterator) == 0) {
+ IOReturn result = IOServiceAddMatchingNotification(
+ SDL_HIDAPI_discovery.m_notificationPort,
+ kIOFirstMatchNotification,
+ IOServiceMatching(kIOHIDDeviceKey),
+ CallbackIOServiceFunc, &SDL_HIDAPI_discovery.m_bHaveDevicesChanged, &portIterator);
+
+ if (result == 0) {
/* Must drain the existing iterator, or we won't receive new notifications */
while ((entry = IOIteratorNext(portIterator)) != 0) {
IOObjectRelease(entry);
@@ -247,12 +238,15 @@
}
}
{
- CFMutableDictionaryRef matchingDict = IOServiceMatching("IOBluetoothDevice");
-
- /* Note: IOServiceAddMatchingNotification consumes the reference to matchingDict */
io_iterator_t portIterator = 0;
io_object_t entry;
- if (IOServiceAddMatchingNotification(SDL_HIDAPI_discovery.m_notificationPort, kIOMatchedNotification, matchingDict, CallbackIOServiceFunc, &SDL_HIDAPI_discovery.m_bHaveDevicesChanged, &portIterator) == 0) {
+ IOReturn result = IOServiceAddMatchingNotification(
+ SDL_HIDAPI_discovery.m_notificationPort,
+ kIOTerminatedNotification,
+ IOServiceMatching(kIOHIDDeviceKey),
+ CallbackIOServiceFunc, &SDL_HIDAPI_discovery.m_bHaveDevicesChanged, &portIterator);
+
+ if (result == 0) {
/* Must drain the existing iterator, or we won't receive new notifications */
while ((entry = IOIteratorNext(portIterator)) != 0) {
IOObjectRelease(entry);
@@ -393,182 +387,18 @@
#endif
}
-
-const char *
-HIDAPI_XboxControllerName(Uint16 vendor_id, Uint16 product_id)
-{
- static struct
- {
- Uint32 vidpid;
- const char *name;
- } names[] = {
- { MAKE_VIDPID(0x0079, 0x18d4), "GPD Win 2 X-Box Controller" },
- { MAKE_VIDPID(0x044f, 0xb326), "Thrustmaster Gamepad GP XID" },
- { MAKE_VIDPID(0x045e, 0x028e), "Microsoft X-Box 360 pad" },
- { MAKE_VIDPID(0x045e, 0x028f), "Microsoft X-Box 360 pad v2" },
- { MAKE_VIDPID(0x045e, 0x0291), "Xbox 360 Wireless Receiver (XBOX)" },
- { MAKE_VIDPID(0x045e, 0x02d1), "Microsoft X-Box One pad" },
- { MAKE_VIDPID(0x045e, 0x02dd), "Microsoft X-Box One pad (Firmware 2015)" },
- { MAKE_VIDPID(0x045e, 0x02e3), "Microsoft X-Box One Elite pad" },
- { MAKE_VIDPID(0x045e, 0x02ea), "Microsoft X-Box One S pad" },
- { MAKE_VIDPID(0x045e, 0x02ff), "Microsoft X-Box One pad" },
- { MAKE_VIDPID(0x045e, 0x0719), "Xbox 360 Wireless Receiver" },
- { MAKE_VIDPID(0x046d, 0xc21d), "Logitech Gamepad F310" },
- { MAKE_VIDPID(0x046d, 0xc21e), "Logitech Gamepad F510" },
- { MAKE_VIDPID(0x046d, 0xc21f), "Logitech Gamepad F710" },
- { MAKE_VIDPID(0x046d, 0xc242), "Logitech Chillstream Controller" },
- { MAKE_VIDPID(0x046d, 0xcaa3), "Logitech DriveFx Racing Wheel" },
- { MAKE_VIDPID(0x056e, 0x2004), "Elecom JC-U3613M" },
- { MAKE_VIDPID(0x06a3, 0xf51a), "Saitek P3600" },
- { MAKE_VIDPID(0x0738, 0x4716), "Mad Catz Wired Xbox 360 Controller" },
- { MAKE_VIDPID(0x0738, 0x4718), "Mad Catz Street Fighter IV FightStick SE" },
- { MAKE_VIDPID(0x0738, 0x4726), "Mad Catz Xbox 360 Controller" },
- { MAKE_VIDPID(0x0738, 0x4728), "Mad Catz Street Fighter IV FightPad" },
- { MAKE_VIDPID(0x0738, 0x4736), "Mad Catz MicroCon Gamepad" },
- { MAKE_VIDPID(0x0738, 0x4738), "Mad Catz Wired Xbox 360 Controller (SFIV)" },
- { MAKE_VIDPID(0x0738, 0x4740), "Mad Catz Beat Pad" },
- { MAKE_VIDPID(0x0738, 0x4758), "Mad Catz Arcade Game Stick" },
- { MAKE_VIDPID(0x0738, 0x4a01), "Mad Catz FightStick TE 2" },
- { MAKE_VIDPID(0x0738, 0x9871), "Mad Catz Portable Drum" },
- { MAKE_VIDPID(0x0738, 0xb726), "Mad Catz Xbox controller - MW2" },
- { MAKE_VIDPID(0x0738, 0xb738), "Mad Catz MVC2TE Stick 2" },
- { MAKE_VIDPID(0x0738, 0xbeef), "Mad Catz JOYTECH NEO SE Advanced GamePad" },
- { MAKE_VIDPID(0x0738, 0xcb02), "Saitek Cyborg Rumble Pad - PC/Xbox 360" },
- { MAKE_VIDPID(0x0738, 0xcb03), "Saitek P3200 Rumble Pad - PC/Xbox 360" },
- { MAKE_VIDPID(0x0738, 0xcb29), "Saitek Aviator Stick AV8R02" },
- { MAKE_VIDPID(0x0738, 0xf738), "Super SFIV FightStick TE S" },
- { MAKE_VIDPID(0x07ff, 0xffff), "Mad Catz GamePad" },
- { MAKE_VIDPID(0x0e6f, 0x0105), "HSM3 Xbox360 dancepad" },
- { MAKE_VIDPID(0x0e6f, 0x0113), "Afterglow AX.1 Gamepad for Xbox 360" },
- { MAKE_VIDPID(0x0e6f, 0x011f), "Rock Candy Gamepad Wired Controller" },
- { MAKE_VIDPID(0x0e6f, 0x0131), "PDP EA Sports Controller" },
- { MAKE_VIDPID(0x0e6f, 0x0133), "Xbox 360 Wired Controller" },
- { MAKE_VIDPID(0x0e6f, 0x0139), "Afterglow Prismatic Wired Controller" },
- { MAKE_VIDPID(0x0e6f, 0x013a), "PDP Xbox One Controller" },
- { MAKE_VIDPID(0x0e6f, 0x0146), "Rock Candy Wired Controller for Xbox One" },
- { MAKE_VIDPID(0x0e6f, 0x0147), "PDP Marvel Xbox One Controller" },
- { MAKE_VIDPID(0x0e6f, 0x015c), "PDP Xbox One Arcade Stick" },
- { MAKE_VIDPID(0x0e6f, 0x0161), "PDP Xbox One Controller" },
- { MAKE_VIDPID(0x0e6f, 0x0162), "PDP Xbox One Controller" },
- { MAKE_VIDPID(0x0e6f, 0x0163), "PDP Xbox One Controller" },
- { MAKE_VIDPID(0x0e6f, 0x0164), "PDP Battlefield One" },
- { MAKE_VIDPID(0x0e6f, 0x0165), "PDP Titanfall 2" },
- { MAKE_VIDPID(0x0e6f, 0x0201), "Pelican PL-3601 'TSZ' Wired Xbox 360 Controller" },
- { MAKE_VIDPID(0x0e6f, 0x0213), "Afterglow Gamepad for Xbox 360" },
- { MAKE_VIDPID(0x0e6f, 0x021f), "Rock Candy Gamepad for Xbox 360" },
- { MAKE_VIDPID(0x0e6f, 0x0246), "Rock Candy Gamepad for Xbox One 2015" },
- { MAKE_VIDPID(0x0e6f, 0x02a4), "PDP Wired Controller for Xbox One - Stealth Series" },
- { MAKE_VIDPID(0x0e6f, 0x02ab), "PDP Controller for Xbox One" },
- { MAKE_VIDPID(0x0e6f, 0x0301), "Logic3 Controller" },
- { MAKE_VIDPID(0x0e6f, 0x0346), "Rock Candy Gamepad for Xbox One 2016" },
- { MAKE_VIDPID(0x0e6f, 0x0401), "Logic3 Controller" },
- { MAKE_VIDPID(0x0e6f, 0x0413), "Afterglow AX.1 Gamepad for Xbox 360" },
- { MAKE_VIDPID(0x0e6f, 0x0501), "PDP Xbox 360 Controller" },
- { MAKE_VIDPID(0x0e6f, 0xf900), "PDP Afterglow AX.1" },
- { MAKE_VIDPID(0x0f0d, 0x000a), "Hori Co. DOA4 FightStick" },
- { MAKE_VIDPID(0x0f0d, 0x000c), "Hori PadEX Turbo" },
- { MAKE_VIDPID(0x0f0d, 0x000d), "Hori Fighting Stick EX2" },
- { MAKE_VIDPID(0x0f0d, 0x0016), "Hori Real Arcade Pro.EX" },
- { MAKE_VIDPID(0x0f0d, 0x001b), "Hori Real Arcade Pro VX" },
- { MAKE_VIDPID(0x0f0d, 0x0063), "Hori Real Arcade Pro Hayabusa (USA) Xbox One" },
- { MAKE_VIDPID(0x0f0d, 0x0067), "HORIPAD ONE" },
- { MAKE_VIDPID(0x0f0d, 0x0078), "Hori Real Arcade Pro V Kai Xbox One" },
- { MAKE_VIDPID(0x11c9, 0x55f0), "Nacon GC-100XF" },
- { MAKE_VIDPID(0x12ab, 0x0004), "Honey Bee Xbox360 dancepad" },
- { MAKE_VIDPID(0x12ab, 0x0301), "PDP AFTERGLOW AX.1" },
- { MAKE_VIDPID(0x12ab, 0x0303), "Mortal Kombat Klassic FightStick" },
- { MAKE_VIDPID(0x1430, 0x4748), "RedOctane Guitar Hero X-plorer" },
- { MAKE_VIDPID(0x1430, 0xf801), "RedOctane Controller" },
- { MAKE_VIDPID(0x146b, 0x0601), "BigBen Interactive XBOX 360 Controller" },
- { MAKE_VIDPID(0x1532, 0x0037), "Razer Sabertooth" },
- { MAKE_VIDPID(0x1532, 0x0a00), "Razer Atrox Arcade Stick" },
- { MAKE_VIDPID(0x1532, 0x0a03), "Razer Wildcat" },
- { MAKE_VIDPID(0x15e4, 0x3f00), "Power A Mini Pro Elite" },
- { MAKE_VIDPID(0x15e4, 0x3f0a), "Xbox Airflo wired controller" },
- { MAKE_VIDPID(0x15e4, 0x3f10), "Batarang Xbox 360 controller" },
- { MAKE_VIDPID(0x162e, 0xbeef), "Joytech Neo-Se Take2" },
- { MAKE_VIDPID(0x1689, 0xfd00), "Razer Onza Tournament Edition" },
- { MAKE_VIDPID(0x1689, 0xfd01), "Razer Onza Classic Edition" },
- { MAKE_VIDPID(0x1689, 0xfe00), "Razer Sabertooth" },
- { MAKE_VIDPID(0x1bad, 0x0002), "Harmonix Rock Band Guitar" },
- { MAKE_VIDPID(0x1bad, 0x0003), "Harmonix Rock Band Drumkit" },
- { MAKE_VIDPID(0x1bad, 0x0130), "Ion Drum Rocker" },
- { MAKE_VIDPID(0x1bad, 0xf016), "Mad Catz Xbox 360 Controller" },
- { MAKE_VIDPID(0x1bad, 0xf018), "Mad Catz Street Fighter IV SE Fighting Stick" },
- { MAKE_VIDPID(0x1bad, 0xf019), "Mad Catz Brawlstick for Xbox 360" },
- { MAKE_VIDPID(0x1bad, 0xf021), "Mad Cats Ghost Recon FS GamePad" },
- { MAKE_VIDPID(0x1bad, 0xf023), "MLG Pro Circuit Controller (Xbox)" },
- { MAKE_VIDPID(0x1bad, 0xf025), "Mad Catz Call Of Duty" },
- { MAKE_VIDPID(0x1bad, 0xf027), "Mad Catz FPS Pro" },
- { MAKE_VIDPID(0x1bad, 0xf028), "Street Fighter IV FightPad" },
- { MAKE_VIDPID(0x1bad, 0xf02e), "Mad Catz Fightpad" },
- { MAKE_VIDPID(0x1bad, 0xf030), "Mad Catz Xbox 360 MC2 MicroCon Racing Wheel" },
- { MAKE_VIDPID(0x1bad, 0xf036), "Mad Catz MicroCon GamePad Pro" },
- { MAKE_VIDPID(0x1bad, 0xf038), "Street Fighter IV FightStick TE" },
- { MAKE_VIDPID(0x1bad, 0xf039), "Mad Catz MvC2 TE" },
- { MAKE_VIDPID(0x1bad, 0xf03a), "Mad Catz SFxT Fightstick Pro" },
- { MAKE_VIDPID(0x1bad, 0xf03d), "Street Fighter IV Arcade Stick TE - Chun Li" },
- { MAKE_VIDPID(0x1bad, 0xf03e), "Mad Catz MLG FightStick TE" },
- { MAKE_VIDPID(0x1bad, 0xf03f), "Mad Catz FightStick SoulCaliber" },
- { MAKE_VIDPID(0x1bad, 0xf042), "Mad Catz FightStick TES+" },
- { MAKE_VIDPID(0x1bad, 0xf080), "Mad Catz FightStick TE2" },
- { MAKE_VIDPID(0x1bad, 0xf501), "HoriPad EX2 Turbo" },
- { MAKE_VIDPID(0x1bad, 0xf502), "Hori Real Arcade Pro.VX SA" },
- { MAKE_VIDPID(0x1bad, 0xf503), "Hori Fighting Stick VX" },
- { MAKE_VIDPID(0x1bad, 0xf504), "Hori Real Arcade Pro. EX" },
- { MAKE_VIDPID(0x1bad, 0xf505), "Hori Fighting Stick EX2B" },
- { MAKE_VIDPID(0x1bad, 0xf506), "Hori Real Arcade Pro.EX Premium VLX" },
- { MAKE_VIDPID(0x1bad, 0xf900), "Harmonix Xbox 360 Controller" },
- { MAKE_VIDPID(0x1bad, 0xf901), "Gamestop Xbox 360 Controller" },
- { MAKE_VIDPID(0x1bad, 0xf903), "Tron Xbox 360 controller" },
- { MAKE_VIDPID(0x1bad, 0xf904), "PDP Versus Fighting Pad" },
- { MAKE_VIDPID(0x1bad, 0xf906), "MortalKombat FightStick" },
- { MAKE_VIDPID(0x1bad, 0xfa01), "MadCatz GamePad" },
- { MAKE_VIDPID(0x1bad, 0xfd00), "Razer Onza TE" },
- { MAKE_VIDPID(0x1bad, 0xfd01), "Razer Onza" },
- { MAKE_VIDPID(0x24c6, 0x5000), "Razer Atrox Arcade Stick" },
- { MAKE_VIDPID(0x24c6, 0x5300), "PowerA MINI PROEX Controller" },
- { MAKE_VIDPID(0x24c6, 0x5303), "Xbox Airflo wired controller" },
- { MAKE_VIDPID(0x24c6, 0x530a), "Xbox 360 Pro EX Controller" },
- { MAKE_VIDPID(0x24c6, 0x531a), "PowerA Pro Ex" },
- { MAKE_VIDPID(0x24c6, 0x5397), "FUS1ON Tournament Controller" },
- { MAKE_VIDPID(0x24c6, 0x541a), "PowerA Xbox One Mini Wired Controller" },
- { MAKE_VIDPID(0x24c6, 0x542a), "Xbox ONE spectra" },
- { MAKE_VIDPID(0x24c6, 0x543a), "PowerA Xbox One wired controller" },
- { MAKE_VIDPID(0x24c6, 0x5500), "Hori XBOX 360 EX 2 with Turbo" },
- { MAKE_VIDPID(0x24c6, 0x5501), "Hori Real Arcade Pro VX-SA" },
- { MAKE_VIDPID(0x24c6, 0x5502), "Hori Fighting Stick VX Alt" },
- { MAKE_VIDPID(0x24c6, 0x5503), "Hori Fighting Edge" },
- { MAKE_VIDPID(0x24c6, 0x5506), "Hori SOULCALIBUR V Stick" },
- { MAKE_VIDPID(0x24c6, 0x550d), "Hori GEM Xbox controller" },
- { MAKE_VIDPID(0x24c6, 0x550e), "Hori Real Arcade Pro V Kai 360" },
- { MAKE_VIDPID(0x24c6, 0x551a), "PowerA FUSION Pro Controller" },
- { MAKE_VIDPID(0x24c6, 0x561a), "PowerA FUSION Controller" },
- { MAKE_VIDPID(0x24c6, 0x5b00), "ThrustMaster Ferrari 458 Racing Wheel" },
- { MAKE_VIDPID(0x24c6, 0x5b02), "Thrustmaster, Inc. GPX Controller" },
- { MAKE_VIDPID(0x24c6, 0x5b03), "Thrustmaster Ferrari 458 Racing Wheel" },
- { MAKE_VIDPID(0x24c6, 0x5d04), "Razer Sabertooth" },
- { MAKE_VIDPID(0x24c6, 0xfafe), "Rock Candy Gamepad for Xbox 360" },
- };
- int i;
- Uint32 vidpid = MAKE_VIDPID(vendor_id, product_id);
-
- for (i = 0; i < SDL_arraysize(names); ++i) {
- if (vidpid == names[i].vidpid) {
- return names[i].name;
- }
- }
- return NULL;
-}
+static void HIDAPI_JoystickDetect(void);
+static void HIDAPI_JoystickClose(SDL_Joystick * joystick);
static SDL_bool
-HIDAPI_IsDeviceSupported(Uint16 vendor_id, Uint16 product_id, Uint16 version)
+HIDAPI_IsDeviceSupported(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name)
{
int i;
+ SDL_GameControllerType type = SDL_GetJoystickGameControllerType(name, vendor_id, product_id, -1, 0, 0, 0);
for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
- if (driver->enabled && driver->IsSupportedDevice(vendor_id, product_id, version, -1)) {
+ if (driver->enabled && driver->IsSupportedDevice(name, type, vendor_id, product_id, version, -1, 0, 0, 0)) {
return SDL_TRUE;
}
}
@@ -583,6 +413,7 @@
const Uint16 USAGE_GAMEPAD = 0x0005;
const Uint16 USAGE_MULTIAXISCONTROLLER = 0x0008;
int i;
+ SDL_GameControllerType type;
if (SDL_ShouldIgnoreJoystick(device->name, device->guid)) {
return NULL;
@@ -595,9 +426,10 @@
return NULL;
}
+ type = SDL_GetJoystickGameControllerType(device->name, device->vendor_id, device->product_id, device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol);
for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
- if (driver->enabled && driver->IsSupportedDevice(device->vendor_id, device->product_id, device->version, device->interface_number)) {
+ if (driver->enabled && driver->IsSupportedDevice(device->name, type, device->vendor_id, device->product_id, device->version, device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol)) {
return driver;
}
}
@@ -605,19 +437,22 @@
}
static SDL_HIDAPI_Device *
-HIDAPI_GetJoystickByIndex(int device_index)
+HIDAPI_GetDeviceByIndex(int device_index, SDL_JoystickID *pJoystickID)
{
SDL_HIDAPI_Device *device = SDL_HIDAPI_devices;
while (device) {
if (device->driver) {
- if (device_index == 0) {
- break;
+ if (device_index < device->num_joysticks) {
+ if (pJoystickID) {
+ *pJoystickID = device->joysticks[device_index];
+ }
+ return device;
}
- --device_index;
+ device_index -= device->num_joysticks;
}
device = device->next;
}
- return device;
+ return NULL;
}
static SDL_HIDAPI_Device *
@@ -634,12 +469,52 @@
return device;
}
+static void
+HIDAPI_SetupDeviceDriver(SDL_HIDAPI_Device *device)
+{
+ if (device->driver) {
+ /* Already setup */
+ return;
+ }
+
+ device->driver = HIDAPI_GetDeviceDriver(device);
+ if (device->driver) {
+ const char *name = device->driver->GetDeviceName(device->vendor_id, device->product_id);
+ if (name) {
+ SDL_free(device->name);
+ device->name = SDL_strdup(name);
+ }
+ }
+
+ /* Initialize the device, which may cause a connected event */
+ if (device->driver && !device->driver->InitDevice(device)) {
+ device->driver = NULL;
+ }
+}
+
+static void
+HIDAPI_CleanupDeviceDriver(SDL_HIDAPI_Device *device)
+{
+ if (!device->driver) {
+ /* Already cleaned up */
+ return;
+ }
+
+ /* Disconnect any joysticks */
+ while (device->num_joysticks) {
+ HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
+ }
+
+ device->driver->FreeDevice(device);
+ device->driver = NULL;
+}
+
static void SDLCALL
SDL_HIDAPIDriverHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
int i;
- SDL_HIDAPI_Device *device = SDL_HIDAPI_devices;
- SDL_bool enabled = (!hint || !*hint || ((*hint != '0') && (SDL_strcasecmp(hint, "false") != 0)));
+ SDL_HIDAPI_Device *device;
+ SDL_bool enabled = SDL_GetStringBoolean(hint, SDL_TRUE);
if (SDL_strcmp(name, SDL_HINT_JOYSTICK_HIDAPI) == 0) {
for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
@@ -651,41 +526,49 @@
SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
if (SDL_strcmp(name, driver->hint) == 0) {
driver->enabled = enabled;
- break;
}
+ }
+ }
+
+ SDL_HIDAPI_numdrivers = 0;
+ for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
+ SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
+ if (driver->enabled) {
+ ++SDL_HIDAPI_numdrivers;
}
}
/* Update device list if driver availability changes */
- while (device) {
- if (device->driver) {
- if (!device->driver->enabled) {
- device->driver = NULL;
+ SDL_LockJoysticks();
- --SDL_HIDAPI_numjoysticks;
-
- SDL_PrivateJoystickRemoved(device->instance_id);
- }
- } else {
- device->driver = HIDAPI_GetDeviceDriver(device);
- if (device->driver) {
- device->instance_id = SDL_GetNextJoystickInstanceID();
-
- ++SDL_HIDAPI_numjoysticks;
-
- SDL_PrivateJoystickAdded(device->instance_id);
- }
+ for (device = SDL_HIDAPI_devices; device; device = device->next) {
+ if (device->driver && !device->driver->enabled) {
+ HIDAPI_CleanupDeviceDriver(device);
}
- device = device->next;
+ HIDAPI_SetupDeviceDriver(device);
}
-}
-static void HIDAPI_JoystickDetect(void);
+ SDL_UnlockJoysticks();
+}
static int
HIDAPI_JoystickInit(void)
{
int i;
+
+ if (initialized) {
+ return 0;
+ }
+
+#if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__TVOS__)
+ /* The hidapi framwork is weak-linked on Apple platforms */
+ int HID_API_EXPORT HID_API_CALL hid_init(void) __attribute__((weak_import));
+
+ if (hid_init == NULL) {
+ SDL_SetError("Couldn't initialize hidapi, framework not available");
+ return -1;
+ }
+#endif /* __MACOSX__ || __IPHONEOS__ || __TVOS__ */
if (hid_init() < 0) {
SDL_SetError("Couldn't initialize hidapi");
@@ -700,7 +583,61 @@
SDL_HIDAPIDriverHintChanged, NULL);
HIDAPI_InitializeDiscovery();
HIDAPI_JoystickDetect();
+ HIDAPI_UpdateDevices();
+
+ initialized = SDL_TRUE;
+
return 0;
+}
+
+SDL_bool
+HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID)
+{
+ SDL_JoystickID joystickID;
+ SDL_JoystickID *joysticks = (SDL_JoystickID *)SDL_realloc(device->joysticks, (device->num_joysticks + 1)*sizeof(*device->joysticks));
+ if (!joysticks) {
+ return SDL_FALSE;
+ }
+
+ joystickID = SDL_GetNextJoystickInstanceID();
+ device->joysticks = joysticks;
+ device->joysticks[device->num_joysticks++] = joystickID;
+ ++SDL_HIDAPI_numjoysticks;
+
+ SDL_PrivateJoystickAdded(joystickID);
+
+ if (pJoystickID) {
+ *pJoystickID = joystickID;
+ }
+ return SDL_TRUE;
+}
+
+void
+HIDAPI_JoystickDisconnected(SDL_HIDAPI_Device *device, SDL_JoystickID joystickID)
+{
+ int i;
+
+ for (i = 0; i < device->num_joysticks; ++i) {
+ if (device->joysticks[i] == joystickID) {
+ SDL_Joystick *joystick = SDL_JoystickFromInstanceID(joystickID);
+ if (joystick) {
+ HIDAPI_JoystickClose(joystick);
+ }
+
+ SDL_memmove(&device->joysticks[i], &device->joysticks[i+1], device->num_joysticks - i - 1);
+ --device->num_joysticks;
+ --SDL_HIDAPI_numjoysticks;
+ if (device->num_joysticks == 0) {
+ SDL_free(device->joysticks);
+ device->joysticks = NULL;
+ }
+
+ if (!shutting_down) {
+ SDL_PrivateJoystickRemoved(joystickID);
+ }
+ return;
+ }
+ }
}
static int
@@ -723,12 +660,19 @@
if (!device) {
return;
}
- device->instance_id = -1;
+ device->path = SDL_strdup(info->path);
+ if (!device->path) {
+ SDL_free(device);
+ return;
+ }
device->seen = SDL_TRUE;
device->vendor_id = info->vendor_id;
device->product_id = info->product_id;
device->version = info->release_number;
device->interface_number = info->interface_number;
+ device->interface_class = info->interface_class;
+ device->interface_subclass = info->interface_subclass;
+ device->interface_protocol = info->interface_protocol;
device->usage_page = info->usage_page;
device->usage = info->usage;
{
@@ -751,9 +695,17 @@
device->guid.data[14] = 'h';
device->guid.data[15] = 0;
}
+ device->dev_lock = SDL_CreateMutex();
/* Need the device name before getting the driver to know whether to ignore this device */
+ if (!device->name) {
+ const char *name = SDL_GetCustomJoystickName(device->vendor_id, device->product_id);
+ if (name) {
+ device->name = SDL_strdup(name);
+ }
+ }
if (!device->name && info->manufacturer_string && info->product_string) {
+ const char *manufacturer_remapped;
char *manufacturer_string = SDL_iconv_string("UTF-8", "WCHAR_T", (char*)info->manufacturer_string, (SDL_wcslen(info->manufacturer_string)+1)*sizeof(wchar_t));
char *product_string = SDL_iconv_string("UTF-8", "WCHAR_T", (char*)info->product_string, (SDL_wcslen(info->product_string)+1)*sizeof(wchar_t));
if (!manufacturer_string && !product_string) {
@@ -765,11 +717,22 @@
product_string = SDL_iconv_string("UTF-8", "UCS-4-INTERNAL", (char*)info->product_string, (SDL_wcslen(info->product_string)+1)*sizeof(wchar_t));
}
}
+
+ manufacturer_remapped = SDL_GetCustomJoystickManufacturer(manufacturer_string);
+ if (manufacturer_remapped != manufacturer_string) {
+ SDL_free(manufacturer_string);
+ manufacturer_string = SDL_strdup(manufacturer_remapped);
+ }
+
if (manufacturer_string && product_string) {
size_t name_size = (SDL_strlen(manufacturer_string) + 1 + SDL_strlen(product_string) + 1);
device->name = (char *)SDL_malloc(name_size);
if (device->name) {
- SDL_snprintf(device->name, name_size, "%s %s", manufacturer_string, product_string);
+ if (SDL_strncasecmp(manufacturer_string, product_string, SDL_strlen(manufacturer_string)) == 0) {
+ SDL_strlcpy(device->name, product_string, name_size);
+ } else {
+ SDL_snprintf(device->name, name_size, "%s %s", manufacturer_string, product_string);
+ }
}
}
if (manufacturer_string) {
@@ -783,32 +746,12 @@
size_t name_size = (6 + 1 + 6 + 1);
device->name = (char *)SDL_malloc(name_size);
if (!device->name) {
+ SDL_free(device->path);
SDL_free(device);
return;
}
SDL_snprintf(device->name, name_size, "0x%.4x/0x%.4x", info->vendor_id, info->product_id);
}
-
- device->driver = HIDAPI_GetDeviceDriver(device);
-
- if (device->driver) {
- const char *name = device->driver->GetDeviceName(device->vendor_id, device->product_id);
- if (name) {
- SDL_free(device->name);
- device->name = SDL_strdup(name);
- }
- }
-
- device->path = SDL_strdup(info->path);
- if (!device->path) {
- SDL_free(device->name);
- SDL_free(device);
- return;
- }
-
-#ifdef DEBUG_HIDAPI
- SDL_Log("Adding HIDAPI device '%s' VID 0x%.4x, PID 0x%.4x, version %d, interface %d, usage page 0x%.4x, usage 0x%.4x, driver = %s\n", device->name, device->vendor_id, device->product_id, device->version, device->interface_number, device->usage_page, device->usage, device->driver ? device->driver->hint : "NONE");
-#endif
/* Add it to the list */
if (last) {
@@ -817,19 +760,16 @@
SDL_HIDAPI_devices = device;
}
- if (device->driver) {
- /* It's a joystick! */
- device->instance_id = SDL_GetNextJoystickInstanceID();
+ HIDAPI_SetupDeviceDriver(device);
- ++SDL_HIDAPI_numjoysticks;
-
- SDL_PrivateJoystickAdded(device->instance_id);
- }
+#ifdef DEBUG_HIDAPI
+ SDL_Log("Added HIDAPI device '%s' VID 0x%.4x, PID 0x%.4x, version %d, interface %d, interface_class %d, interface_subclass %d, interface_protocol %d, usage page 0x%.4x, usage 0x%.4x, path = %s, driver = %s (%s)\n", device->name, device->vendor_id, device->product_id, device->version, device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol, device->usage_page, device->usage, device->path, device->driver ? device->driver->hint : "NONE", device->driver && device->driver->enabled ? "ENABLED" : "DISABLED");
+#endif
}
static void
-HIDAPI_DelDevice(SDL_HIDAPI_Device *device, SDL_bool send_event)
+HIDAPI_DelDevice(SDL_HIDAPI_Device *device)
{
SDL_HIDAPI_Device *curr, *last;
for (curr = SDL_HIDAPI_devices, last = NULL; curr; last = curr, curr = curr->next) {
@@ -840,13 +780,9 @@
SDL_HIDAPI_devices = curr->next;
}
- if (device->driver && send_event) {
- /* Need to decrement the joystick count before we post the event */
- --SDL_HIDAPI_numjoysticks;
+ HIDAPI_CleanupDeviceDriver(device);
- SDL_PrivateJoystickRemoved(device->instance_id);
- }
-
+ SDL_DestroyMutex(device->dev_lock);
SDL_free(device->name);
SDL_free(device->path);
SDL_free(device);
@@ -861,6 +797,8 @@
SDL_HIDAPI_Device *device;
struct hid_device_info *devs, *info;
+ SDL_LockJoysticks();
+
/* Prepare the existing device list */
device = SDL_HIDAPI_devices;
while (device) {
@@ -869,17 +807,19 @@
}
/* Enumerate the devices */
- devs = hid_enumerate(0, 0);
- if (devs) {
- for (info = devs; info; info = info->next) {
- device = HIDAPI_GetJoystickByInfo(info->path, info->vendor_id, info->product_id);
- if (device) {
- device->seen = SDL_TRUE;
- } else {
- HIDAPI_AddDevice(info);
+ if (SDL_HIDAPI_numdrivers > 0) {
+ devs = hid_enumerate(0, 0);
+ if (devs) {
+ for (info = devs; info; info = info->next) {
+ device = HIDAPI_GetJoystickByInfo(info->path, info->vendor_id, info->product_id);
+ if (device) {
+ device->seen = SDL_TRUE;
+ } else {
+ HIDAPI_AddDevice(info);
+ }
}
+ hid_free_enumeration(devs);
}
- hid_free_enumeration(devs);
}
/* Remove any devices that weren't seen */
@@ -888,91 +828,188 @@
SDL_HIDAPI_Device *next = device->next;
if (!device->seen) {
- HIDAPI_DelDevice(device, SDL_TRUE);
+ HIDAPI_DelDevice(device);
}
device = next;
}
+
+ SDL_UnlockJoysticks();
}
SDL_bool
-HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version)
+HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name)
{
SDL_HIDAPI_Device *device;
+ SDL_bool supported = SDL_FALSE;
+ SDL_bool result = SDL_FALSE;
- /* Don't update the device list for devices we know aren't supported */
- if (!HIDAPI_IsDeviceSupported(vendor_id, product_id, version)) {
+ /* Make sure we're initialized, as this could be called from other drivers during startup */
+ if (HIDAPI_JoystickInit() < 0) {
return SDL_FALSE;
}
- /* Make sure the device list is completely up to date when we check for device presence */
- HIDAPI_UpdateDeviceList();
+ /* Only update the device list for devices we know might be supported.
+ If we did this for every device, it would hit the USB driver too hard and potentially
+ lock up the system. This won't catch devices that we support but can only detect using
+ USB interface details, like Xbox controllers, but hopefully the device list update is
+ responsive enough to catch those.
+ */
+ supported = HIDAPI_IsDeviceSupported(vendor_id, product_id, version, name);
+#if defined(SDL_JOYSTICK_HIDAPI_XBOX360) || defined(SDL_JOYSTICK_HIDAPI_XBOXONE)
+ if (!supported &&
+ (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box") || SDL_strstr(name, "XBOX"))) {
+ supported = SDL_TRUE;
+ }
+#endif /* SDL_JOYSTICK_HIDAPI_XBOX360 || SDL_JOYSTICK_HIDAPI_XBOXONE */
+ if (supported) {
+ if (SDL_AtomicTryLock(&SDL_HIDAPI_spinlock)) {
+ HIDAPI_UpdateDeviceList();
+ SDL_AtomicUnlock(&SDL_HIDAPI_spinlock);
+ }
+ }
+ /* Note that this isn't a perfect check - there may be multiple devices with 0 VID/PID,
+ or a different name than we have it listed here, etc, but if we support the device
+ and we have something similar in our device list, mark it as present.
+ */
+ SDL_LockJoysticks();
device = SDL_HIDAPI_devices;
while (device) {
if (device->vendor_id == vendor_id && device->product_id == product_id && device->driver) {
- return SDL_TRUE;
+ result = SDL_TRUE;
}
device = device->next;
}
- return SDL_FALSE;
+ SDL_UnlockJoysticks();
+
+ /* If we're looking for the wireless XBox 360 controller, also look for the dongle */
+ if (!result && vendor_id == USB_VENDOR_MICROSOFT && product_id == 0x02a1) {
+ return HIDAPI_IsDevicePresent(USB_VENDOR_MICROSOFT, 0x0719, version, name);
+ }
+
+#ifdef DEBUG_HIDAPI
+ SDL_Log("HIDAPI_IsDevicePresent() returning %s for 0x%.4x / 0x%.4x\n", result ? "true" : "false", vendor_id, product_id);
+#endif
+ return result;
}
static void
HIDAPI_JoystickDetect(void)
{
- HIDAPI_UpdateDiscovery();
- if (SDL_HIDAPI_discovery.m_bHaveDevicesChanged) {
- /* FIXME: We probably need to schedule an update in a few seconds as well */
- HIDAPI_UpdateDeviceList();
- SDL_HIDAPI_discovery.m_bHaveDevicesChanged = SDL_FALSE;
+ if (SDL_AtomicTryLock(&SDL_HIDAPI_spinlock)) {
+ HIDAPI_UpdateDiscovery();
+ if (SDL_HIDAPI_discovery.m_bHaveDevicesChanged) {
+ /* FIXME: We probably need to schedule an update in a few seconds as well */
+ HIDAPI_UpdateDeviceList();
+ SDL_HIDAPI_discovery.m_bHaveDevicesChanged = SDL_FALSE;
+ }
+ SDL_AtomicUnlock(&SDL_HIDAPI_spinlock);
+ }
+}
+
+void
+HIDAPI_UpdateDevices(void)
+{
+ SDL_HIDAPI_Device *device;
+
+ /* Update the devices, which may change connected joysticks and send events */
+
+ /* Prepare the existing device list */
+ if (SDL_AtomicTryLock(&SDL_HIDAPI_spinlock)) {
+ device = SDL_HIDAPI_devices;
+ while (device) {
+ if (device->driver) {
+ if (SDL_TryLockMutex(device->dev_lock) == 0) {
+ device->driver->UpdateDevice(device);
+ SDL_UnlockMutex(device->dev_lock);
+ }
+ }
+ device = device->next;
+ }
+ SDL_AtomicUnlock(&SDL_HIDAPI_spinlock);
}
}
static const char *
HIDAPI_JoystickGetDeviceName(int device_index)
{
- return HIDAPI_GetJoystickByIndex(device_index)->name;
+ SDL_HIDAPI_Device *device;
+ const char *name = NULL;
+
+ device = HIDAPI_GetDeviceByIndex(device_index, NULL);
+ if (device) {
+ /* FIXME: The device could be freed after this name is returned... */
+ name = device->name;
+ }
+
+ return name;
}
static int
HIDAPI_JoystickGetDevicePlayerIndex(int device_index)
{
- return -1;
+ SDL_HIDAPI_Device *device;
+ SDL_JoystickID instance_id;
+ int player_index = -1;
+
+ device = HIDAPI_GetDeviceByIndex(device_index, &instance_id);
+ if (device) {
+ player_index = device->driver->GetDevicePlayerIndex(device, instance_id);
+ }
+
+ return player_index;
+}
+
+static void
+HIDAPI_JoystickSetDevicePlayerIndex(int device_index, int player_index)
+{
+ SDL_HIDAPI_Device *device;
+ SDL_JoystickID instance_id;
+
+ device = HIDAPI_GetDeviceByIndex(device_index, &instance_id);
+ if (device) {
+ device->driver->SetDevicePlayerIndex(device, instance_id, player_index);
+ }
}
static SDL_JoystickGUID
HIDAPI_JoystickGetDeviceGUID(int device_index)
{
- return HIDAPI_GetJoystickByIndex(device_index)->guid;
+ SDL_HIDAPI_Device *device;
+ SDL_JoystickGUID guid;
+
+ device = HIDAPI_GetDeviceByIndex(device_index, NULL);
+ if (device) {
+ SDL_memcpy(&guid, &device->guid, sizeof(guid));
+ } else {
+ SDL_zero(guid);
+ }
+
+ return guid;
}
static SDL_JoystickID
HIDAPI_JoystickGetDeviceInstanceID(int device_index)
{
- return HIDAPI_GetJoystickByIndex(device_index)->instance_id;
+ SDL_JoystickID joystickID = -1;
+ HIDAPI_GetDeviceByIndex(device_index, &joystickID);
+ return joystickID;
}
static int
HIDAPI_JoystickOpen(SDL_Joystick * joystick, int device_index)
{
- SDL_HIDAPI_Device *device = HIDAPI_GetJoystickByIndex(device_index);
+ SDL_JoystickID joystickID;
+ SDL_HIDAPI_Device *device = HIDAPI_GetDeviceByIndex(device_index, &joystickID);
struct joystick_hwdata *hwdata;
hwdata = (struct joystick_hwdata *)SDL_calloc(1, sizeof(*hwdata));
if (!hwdata) {
return SDL_OutOfMemory();
}
+ hwdata->device = device;
- hwdata->driver = device->driver;
- hwdata->dev = hid_open_path(device->path, 0);
- if (!hwdata->dev) {
- SDL_free(hwdata);
- return SDL_SetError("Couldn't open HID device %s", device->path);
- }
- hwdata->mutex = SDL_CreateMutex();
-
- if (!device->driver->Init(joystick, hwdata->dev, device->vendor_id, device->product_id, &hwdata->context)) {
- hid_close(hwdata->dev);
+ if (!device->driver->OpenJoystick(device, joystick)) {
SDL_free(hwdata);
return -1;
}
@@ -982,51 +1019,44 @@
}
static int
-HIDAPI_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
+HIDAPI_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
- struct joystick_hwdata *hwdata = joystick->hwdata;
- SDL_HIDAPI_DeviceDriver *driver = hwdata->driver;
int result;
- SDL_LockMutex(hwdata->mutex);
- result = driver->Rumble(joystick, hwdata->dev, hwdata->context, low_frequency_rumble, high_frequency_rumble, duration_ms);
- SDL_UnlockMutex(hwdata->mutex);
+ if (joystick->hwdata) {
+ SDL_HIDAPI_Device *device = joystick->hwdata->device;
+
+ result = device->driver->RumbleJoystick(device, joystick, low_frequency_rumble, high_frequency_rumble);
+ } else {
+ SDL_SetError("Rumble failed, device disconnected");
+ result = -1;
+ }
+
return result;
}
static void
HIDAPI_JoystickUpdate(SDL_Joystick * joystick)
{
- struct joystick_hwdata *hwdata = joystick->hwdata;
- SDL_HIDAPI_DeviceDriver *driver = hwdata->driver;
- SDL_bool succeeded;
-
- SDL_LockMutex(hwdata->mutex);
- succeeded = driver->Update(joystick, hwdata->dev, hwdata->context);
- SDL_UnlockMutex(hwdata->mutex);
-
- if (!succeeded) {
- SDL_HIDAPI_Device *device;
- for (device = SDL_HIDAPI_devices; device; device = device->next) {
- if (device->instance_id == joystick->instance_id) {
- HIDAPI_DelDevice(device, SDL_TRUE);
- break;
- }
- }
- }
+ /* This is handled in SDL_HIDAPI_UpdateDevices() */
}
static void
HIDAPI_JoystickClose(SDL_Joystick * joystick)
{
- struct joystick_hwdata *hwdata = joystick->hwdata;
- SDL_HIDAPI_DeviceDriver *driver = hwdata->driver;
- driver->Quit(joystick, hwdata->dev, hwdata->context);
+ if (joystick->hwdata) {
+ SDL_HIDAPI_Device *device = joystick->hwdata->device;
- hid_close(hwdata->dev);
- SDL_DestroyMutex(hwdata->mutex);
- SDL_free(hwdata);
- joystick->hwdata = NULL;
+ /* Wait for pending rumble to complete */
+ while (SDL_AtomicGet(&device->rumble_pending) > 0) {
+ SDL_Delay(10);
+ }
+
+ device->driver->CloseJoystick(device, joystick);
+
+ SDL_free(joystick->hwdata);
+ joystick->hwdata = NULL;
+ }
}
static void
@@ -1034,20 +1064,30 @@
{
int i;
+ shutting_down = SDL_TRUE;
+
HIDAPI_ShutdownDiscovery();
while (SDL_HIDAPI_devices) {
- HIDAPI_DelDevice(SDL_HIDAPI_devices, SDL_FALSE);
+ HIDAPI_DelDevice(SDL_HIDAPI_devices);
}
+
+ SDL_HIDAPI_QuitRumble();
+
for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
SDL_DelHintCallback(driver->hint, SDL_HIDAPIDriverHintChanged, NULL);
}
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI,
SDL_HIDAPIDriverHintChanged, NULL);
- SDL_HIDAPI_numjoysticks = 0;
hid_exit();
+
+ /* Make sure the drivers cleaned up properly */
+ SDL_assert(SDL_HIDAPI_numjoysticks == 0);
+
+ shutting_down = SDL_FALSE;
+ initialized = SDL_FALSE;
}
SDL_JoystickDriver SDL_HIDAPI_JoystickDriver =
@@ -1057,6 +1097,7 @@
HIDAPI_JoystickDetect,
HIDAPI_JoystickGetDeviceName,
HIDAPI_JoystickGetDevicePlayerIndex,
+ HIDAPI_JoystickSetDevicePlayerIndex,
HIDAPI_JoystickGetDeviceGUID,
HIDAPI_JoystickGetDeviceInstanceID,
HIDAPI_JoystickOpen,
--
Gitblit v1.9.3