Atlas - SDL_hidapijoystick.c

Home / ext / SDL2 / src / joystick / hidapi Lines: 2 | Size: 38794 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "../../SDL_internal.h" 22 23#ifdef SDL_JOYSTICK_HIDAPI 24 25#include "SDL_endian.h" 26#include "SDL_hints.h" 27#include "SDL_log.h" 28#include "SDL_thread.h" 29#include "SDL_timer.h" 30#include "SDL_joystick.h" 31#include "../SDL_sysjoystick.h" 32#include "SDL_hidapijoystick_c.h" 33 34#if defined(__WIN32__) 35#include "../../core/windows/SDL_windows.h" 36#endif 37 38#if defined(__MACOSX__) 39#include <CoreFoundation/CoreFoundation.h> 40#include <mach/mach.h> 41#include <IOKit/IOKitLib.h> 42#include <IOKit/usb/USBSpec.h> 43#endif 44 45#if defined(__LINUX__) 46#include "../../core/linux/SDL_udev.h" 47#ifdef SDL_USE_LIBUDEV 48#include <poll.h> 49#endif 50#endif 51 52struct joystick_hwdata 53{ 54 SDL_HIDAPI_DeviceDriver *driver; 55 void *context; 56 57 hid_device *dev; 58}; 59 60typedef struct _SDL_HIDAPI_Device 61{ 62 SDL_JoystickID instance_id; 63 char *name; 64 char *path; 65 Uint16 vendor_id; 66 Uint16 product_id; 67 Uint16 version; 68 SDL_JoystickGUID guid; 69 int interface_number; /* Available on Windows and Linux */ 70 Uint16 usage_page; /* Available on Windows and Mac OS X */ 71 Uint16 usage; /* Available on Windows and Mac OS X */ 72 SDL_HIDAPI_DeviceDriver *driver; 73 74 /* Used during scanning for device changes */ 75 SDL_bool seen; 76 77 struct _SDL_HIDAPI_Device *next; 78} SDL_HIDAPI_Device; 79 80static SDL_HIDAPI_DeviceDriver *SDL_HIDAPI_drivers[] = { 81#ifdef SDL_JOYSTICK_HIDAPI_PS4 82 &SDL_HIDAPI_DriverPS4, 83#endif 84#ifdef SDL_JOYSTICK_HIDAPI_STEAM 85 &SDL_HIDAPI_DriverSteam, 86#endif 87#ifdef SDL_JOYSTICK_HIDAPI_SWITCH 88 &SDL_HIDAPI_DriverSwitch, 89#endif 90#ifdef SDL_JOYSTICK_HIDAPI_XBOX360 91 &SDL_HIDAPI_DriverXbox360, 92#endif 93#ifdef SDL_JOYSTICK_HIDAPI_XBOXONE 94 &SDL_HIDAPI_DriverXboxOne, 95#endif 96}; 97static SDL_HIDAPI_Device *SDL_HIDAPI_devices; 98static int SDL_HIDAPI_numjoysticks = 0; 99 100static struct 101{ 102 SDL_bool m_bHaveDevicesChanged; 103 SDL_bool m_bCanGetNotifications; 104 Uint32 m_unLastDetect; 105 106#if defined(__WIN32__) 107 SDL_threadID m_nThreadID; 108 WNDCLASSEXA m_wndClass; 109 HWND m_hwndMsg; 110 HDEVNOTIFY m_hNotify; 111 double m_flLastWin32MessageCheck; 112#endif 113 114#if defined(__MACOSX__) 115 IONotificationPortRef m_notificationPort; 116 mach_port_t m_notificationMach; 117#endif 118 119#if defined(SDL_USE_LIBUDEV) 120 struct udev *m_pUdev; 121 struct udev_monitor *m_pUdevMonitor; 122 int m_nUdevFd; 123#endif 124} SDL_HIDAPI_discovery; 125 126 127#ifdef __WIN32__ 128struct _DEV_BROADCAST_HDR 129{ 130 DWORD dbch_size; 131 DWORD dbch_devicetype; 132 DWORD dbch_reserved; 133}; 134 135typedef struct _DEV_BROADCAST_DEVICEINTERFACE_A 136{ 137 DWORD dbcc_size; 138 DWORD dbcc_devicetype; 139 DWORD dbcc_reserved; 140 GUID dbcc_classguid; 141 char dbcc_name[ 1 ]; 142} DEV_BROADCAST_DEVICEINTERFACE_A, *PDEV_BROADCAST_DEVICEINTERFACE_A; 143 144typedef struct _DEV_BROADCAST_HDR DEV_BROADCAST_HDR; 145#define DBT_DEVICEARRIVAL 0x8000 /* system detected a new device */ 146#define DBT_DEVICEREMOVECOMPLETE 0x8004 /* device was removed from the system */ 147#define DBT_DEVTYP_DEVICEINTERFACE 0x00000005 /* device interface class */ 148#define DBT_DEVNODES_CHANGED 0x0007 149#define DBT_CONFIGCHANGED 0x0018 150#define DBT_DEVICETYPESPECIFIC 0x8005 /* type specific event */ 151#define DBT_DEVINSTSTARTED 0x8008 /* device installed and started */ 152 153#include <initguid.h> 154DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); 155 156static LRESULT CALLBACK ControllerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 157{ 158 switch (message) { 159 case WM_DEVICECHANGE: 160 switch (wParam) { 161 case DBT_DEVICEARRIVAL: 162 case DBT_DEVICEREMOVECOMPLETE: 163 if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) { 164 SDL_HIDAPI_discovery.m_bHaveDevicesChanged = SDL_TRUE; 165 } 166 break; 167 } 168 return TRUE; 169 } 170 171 return DefWindowProc(hwnd, message, wParam, lParam); 172} 173#endif /* __WIN32__ */ 174 175 176#if defined(__MACOSX__) 177static void CallbackIOServiceFunc(void *context, io_iterator_t portIterator) 178{ 179 /* Must drain the iterator, or we won't receive new notifications */ 180 io_object_t entry; 181 while ((entry = IOIteratorNext(portIterator)) != 0) { 182 IOObjectRelease(entry); 183 *(SDL_bool*)context = SDL_TRUE; 184 } 185} 186#endif /* __MACOSX__ */ 187 188static void 189HIDAPI_InitializeDiscovery() 190{ 191 SDL_HIDAPI_discovery.m_bHaveDevicesChanged = SDL_TRUE; 192 SDL_HIDAPI_discovery.m_bCanGetNotifications = SDL_FALSE; 193 SDL_HIDAPI_discovery.m_unLastDetect = 0; 194 195#if defined(__WIN32__) 196 SDL_HIDAPI_discovery.m_nThreadID = SDL_ThreadID(); 197 198 SDL_memset(&SDL_HIDAPI_discovery.m_wndClass, 0x0, sizeof(SDL_HIDAPI_discovery.m_wndClass)); 199 SDL_HIDAPI_discovery.m_wndClass.hInstance = GetModuleHandle(NULL); 200 SDL_HIDAPI_discovery.m_wndClass.lpszClassName = "SDL_HIDAPI_DEVICE_DETECTION"; 201 SDL_HIDAPI_discovery.m_wndClass.lpfnWndProc = ControllerWndProc; /* This function is called by windows */ 202 SDL_HIDAPI_discovery.m_wndClass.cbSize = sizeof(WNDCLASSEX); 203 204 RegisterClassExA(&SDL_HIDAPI_discovery.m_wndClass); 205 SDL_HIDAPI_discovery.m_hwndMsg = CreateWindowExA(0, "SDL_HIDAPI_DEVICE_DETECTION", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL); 206 207 { 208 DEV_BROADCAST_DEVICEINTERFACE_A devBroadcast; 209 SDL_memset( &devBroadcast, 0x0, sizeof( devBroadcast ) ); 210 211 devBroadcast.dbcc_size = sizeof( devBroadcast ); 212 devBroadcast.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; 213 devBroadcast.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE; 214 215 /* DEVICE_NOTIFY_ALL_INTERFACE_CLASSES is important, makes GUID_DEVINTERFACE_USB_DEVICE ignored, 216 * but that seems to be necessary to get a notice after each individual usb input device actually 217 * installs, rather than just as the composite device is seen. 218 */ 219 SDL_HIDAPI_discovery.m_hNotify = RegisterDeviceNotification( SDL_HIDAPI_discovery.m_hwndMsg, &devBroadcast, DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES ); 220 SDL_HIDAPI_discovery.m_bCanGetNotifications = ( SDL_HIDAPI_discovery.m_hNotify != 0 ); 221 } 222#endif /* __WIN32__ */ 223 224#if defined(__MACOSX__) 225 SDL_HIDAPI_discovery.m_notificationPort = IONotificationPortCreate(kIOMasterPortDefault); 226 if (SDL_HIDAPI_discovery.m_notificationPort) { 227 { 228 CFMutableDictionaryRef matchingDict = IOServiceMatching("IOUSBDevice"); 229 230 /* Note: IOServiceAddMatchingNotification consumes the reference to matchingDict */ 231 io_iterator_t portIterator = 0; 232 io_object_t entry; 233 if (IOServiceAddMatchingNotification(SDL_HIDAPI_discovery.m_notificationPort, kIOMatchedNotification, matchingDict, CallbackIOServiceFunc, &SDL_HIDAPI_discovery.m_bHaveDevicesChanged, &portIterator) == 0) { 234 /* Must drain the existing iterator, or we won't receive new notifications */ 235 while ((entry = IOIteratorNext(portIterator)) != 0) { 236 IOObjectRelease(entry); 237 } 238 } else { 239 IONotificationPortDestroy(SDL_HIDAPI_discovery.m_notificationPort); 240 SDL_HIDAPI_discovery.m_notificationPort = nil; 241 } 242 } 243 { 244 CFMutableDictionaryRef matchingDict = IOServiceMatching("IOBluetoothDevice"); 245 246 /* Note: IOServiceAddMatchingNotification consumes the reference to matchingDict */ 247 io_iterator_t portIterator = 0; 248 io_object_t entry; 249 if (IOServiceAddMatchingNotification(SDL_HIDAPI_discovery.m_notificationPort, kIOMatchedNotification, matchingDict, CallbackIOServiceFunc, &SDL_HIDAPI_discovery.m_bHaveDevicesChanged, &portIterator) == 0) { 250 /* Must drain the existing iterator, or we won't receive new notifications */ 251 while ((entry = IOIteratorNext(portIterator)) != 0) { 252 IOObjectRelease(entry); 253 } 254 } else { 255 IONotificationPortDestroy(SDL_HIDAPI_discovery.m_notificationPort); 256 SDL_HIDAPI_discovery.m_notificationPort = nil; 257 } 258 } 259 } 260 261 SDL_HIDAPI_discovery.m_notificationMach = MACH_PORT_NULL; 262 if (SDL_HIDAPI_discovery.m_notificationPort) { 263 SDL_HIDAPI_discovery.m_notificationMach = IONotificationPortGetMachPort(SDL_HIDAPI_discovery.m_notificationPort); 264 } 265 266 SDL_HIDAPI_discovery.m_bCanGetNotifications = (SDL_HIDAPI_discovery.m_notificationMach != MACH_PORT_NULL); 267 268#endif // __MACOSX__ 269 270#if defined(SDL_USE_LIBUDEV) 271 SDL_HIDAPI_discovery.m_pUdev = NULL; 272 SDL_HIDAPI_discovery.m_pUdevMonitor = NULL; 273 SDL_HIDAPI_discovery.m_nUdevFd = -1; 274 275 SDL_HIDAPI_discovery.m_pUdev = udev_new(); 276 if (SDL_HIDAPI_discovery.m_pUdev) { 277 SDL_HIDAPI_discovery.m_pUdevMonitor = udev_monitor_new_from_netlink(SDL_HIDAPI_discovery.m_pUdev, "udev"); 278 if (SDL_HIDAPI_discovery.m_pUdevMonitor) { 279 udev_monitor_enable_receiving(SDL_HIDAPI_discovery.m_pUdevMonitor); 280 SDL_HIDAPI_discovery.m_nUdevFd = udev_monitor_get_fd(SDL_HIDAPI_discovery.m_pUdevMonitor); 281 SDL_HIDAPI_discovery.m_bCanGetNotifications = true; 282 } 283 } 284 285#endif /* SDL_USE_LIBUDEV */ 286} 287 288static void 289HIDAPI_UpdateDiscovery() 290{ 291 if (!SDL_HIDAPI_discovery.m_bCanGetNotifications) { 292 const Uint32 SDL_HIDAPI_DETECT_INTERVAL_MS = 3000; /* Update every 3 seconds */ 293 Uint32 now = SDL_GetTicks(); 294 if (!SDL_HIDAPI_discovery.m_unLastDetect || SDL_TICKS_PASSED(now, SDL_HIDAPI_discovery.m_unLastDetect + SDL_HIDAPI_DETECT_INTERVAL_MS)) { 295 SDL_HIDAPI_discovery.m_bHaveDevicesChanged = SDL_TRUE; 296 SDL_HIDAPI_discovery.m_unLastDetect = now; 297 } 298 return; 299 } 300 301#if defined(__WIN32__) 302 /* We'll only get messages on the same thread that created the window */ 303 if (SDL_ThreadID() == SDL_HIDAPI_discovery.m_nThreadID) { 304 MSG msg; 305 while (PeekMessage(&msg, SDL_HIDAPI_discovery.m_hwndMsg, 0, 0, PM_NOREMOVE)) { 306 if (GetMessageA(&msg, SDL_HIDAPI_discovery.m_hwndMsg, 0, 0) != 0) { 307 TranslateMessage(&msg); 308 DispatchMessage(&msg); 309 } 310 } 311 } 312#endif 313 314#if defined(__MACOSX__) 315 if (SDL_HIDAPI_discovery.m_notificationPort) { 316 struct { mach_msg_header_t hdr; char payload[ 4096 ]; } msg; 317 while (mach_msg(&msg.hdr, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0, sizeof(msg), SDL_HIDAPI_discovery.m_notificationMach, 0, MACH_PORT_NULL) == KERN_SUCCESS) { 318 IODispatchCalloutFromMessage(NULL, &msg.hdr, SDL_HIDAPI_discovery.m_notificationPort); 319 } 320 } 321#endif 322 323#if defined(SDL_USE_LIBUDEV) 324 if (SDL_HIDAPI_discovery.m_nUdevFd >= 0) { 325 /* Drain all notification events. 326 * We don't expect a lot of device notifications so just 327 * do a new discovery on any kind or number of notifications. 328 * This could be made more restrictive if necessary. 329 */ 330 for (;;) { 331 struct pollfd PollUdev; 332 333 PollUdev.fd = SDL_HIDAPI_discovery.m_nUdevFd; 334 PollUdev.events = POLLIN; 335 if (poll(&PollUdev, 1, 0) != 1) { 336 break; 337 } 338 339 SDL_HIDAPI_discovery.m_bHaveDevicesChanged = true; 340 341 struct udev_device *pUdevDevice = udev_monitor_receive_device(SDL_HIDAPI_discovery.m_pUdevMonitor); 342 if (pUdevDevice) { 343 udev_device_unref(pUdevDevice); 344 } 345 } 346 } 347#endif 348} 349 350static void 351HIDAPI_ShutdownDiscovery() 352{ 353#if defined(__WIN32__) 354 if (SDL_HIDAPI_discovery.m_hNotify) 355 UnregisterDeviceNotification(SDL_HIDAPI_discovery.m_hNotify); 356 357 if (SDL_HIDAPI_discovery.m_hwndMsg) { 358 DestroyWindow(SDL_HIDAPI_discovery.m_hwndMsg); 359 } 360 361 UnregisterClassA(SDL_HIDAPI_discovery.m_wndClass.lpszClassName, SDL_HIDAPI_discovery.m_wndClass.hInstance); 362#endif 363 364#if defined(__MACOSX__) 365 if (SDL_HIDAPI_discovery.m_notificationPort) { 366 IONotificationPortDestroy(SDL_HIDAPI_discovery.m_notificationPort); 367 } 368#endif 369 370#if defined(SDL_USE_LIBUDEV) 371 if (SDL_HIDAPI_discovery.m_pUdevMonitor) { 372 udev_monitor_unref(SDL_HIDAPI_discovery.m_pUdevMonitor); 373 } 374 if (SDL_HIDAPI_discovery.m_pUdev) { 375 udev_unref(SDL_HIDAPI_discovery.m_pUdev); 376 } 377#endif 378} 379 380 381const char * 382HIDAPI_XboxControllerName(Uint16 vendor_id, Uint16 product_id) 383{ 384 static struct 385 { 386 Uint32 vidpid; 387 const char *name; 388 } names[] = { 389 { MAKE_VIDPID(0x0079, 0x18d4), "GPD Win 2 X-Box Controller" }, 390 { MAKE_VIDPID(0x044f, 0xb326), "Thrustmaster Gamepad GP XID" }, 391 { MAKE_VIDPID(0x045e, 0x028e), "Microsoft X-Box 360 pad" }, 392 { MAKE_VIDPID(0x045e, 0x028f), "Microsoft X-Box 360 pad v2" }, 393 { MAKE_VIDPID(0x045e, 0x0291), "Xbox 360 Wireless Receiver (XBOX)" }, 394 { MAKE_VIDPID(0x045e, 0x02d1), "Microsoft X-Box One pad" }, 395 { MAKE_VIDPID(0x045e, 0x02dd), "Microsoft X-Box One pad (Firmware 2015)" }, 396 { MAKE_VIDPID(0x045e, 0x02e3), "Microsoft X-Box One Elite pad" }, 397 { MAKE_VIDPID(0x045e, 0x02ea), "Microsoft X-Box One S pad" }, 398 { MAKE_VIDPID(0x045e, 0x02ff), "Microsoft X-Box One pad" }, 399 { MAKE_VIDPID(0x045e, 0x0719), "Xbox 360 Wireless Receiver" }, 400 { MAKE_VIDPID(0x046d, 0xc21d), "Logitech Gamepad F310" }, 401 { MAKE_VIDPID(0x046d, 0xc21e), "Logitech Gamepad F510" }, 402 { MAKE_VIDPID(0x046d, 0xc21f), "Logitech Gamepad F710" }, 403 { MAKE_VIDPID(0x046d, 0xc242), "Logitech Chillstream Controller" }, 404 { MAKE_VIDPID(0x046d, 0xcaa3), "Logitech DriveFx Racing Wheel" }, 405 { MAKE_VIDPID(0x056e, 0x2004), "Elecom JC-U3613M" }, 406 { MAKE_VIDPID(0x06a3, 0xf51a), "Saitek P3600" }, 407 { MAKE_VIDPID(0x0738, 0x4716), "Mad Catz Wired Xbox 360 Controller" }, 408 { MAKE_VIDPID(0x0738, 0x4718), "Mad Catz Street Fighter IV FightStick SE" }, 409 { MAKE_VIDPID(0x0738, 0x4726), "Mad Catz Xbox 360 Controller" }, 410 { MAKE_VIDPID(0x0738, 0x4728), "Mad Catz Street Fighter IV FightPad" }, 411 { MAKE_VIDPID(0x0738, 0x4736), "Mad Catz MicroCon Gamepad" }, 412 { MAKE_VIDPID(0x0738, 0x4738), "Mad Catz Wired Xbox 360 Controller (SFIV)" }, 413 { MAKE_VIDPID(0x0738, 0x4740), "Mad Catz Beat Pad" }, 414 { MAKE_VIDPID(0x0738, 0x4758), "Mad Catz Arcade Game Stick" }, 415 { MAKE_VIDPID(0x0738, 0x4a01), "Mad Catz FightStick TE 2" }, 416 { MAKE_VIDPID(0x0738, 0x9871), "Mad Catz Portable Drum" }, 417 { MAKE_VIDPID(0x0738, 0xb726), "Mad Catz Xbox controller - MW2" }, 418 { MAKE_VIDPID(0x0738, 0xb738), "Mad Catz MVC2TE Stick 2" }, 419 { MAKE_VIDPID(0x0738, 0xbeef), "Mad Catz JOYTECH NEO SE Advanced GamePad" }, 420 { MAKE_VIDPID(0x0738, 0xcb02), "Saitek Cyborg Rumble Pad - PC/Xbox 360" }, 421 { MAKE_VIDPID(0x0738, 0xcb03), "Saitek P3200 Rumble Pad - PC/Xbox 360" }, 422 { MAKE_VIDPID(0x0738, 0xcb29), "Saitek Aviator Stick AV8R02" }, 423 { MAKE_VIDPID(0x0738, 0xf738), "Super SFIV FightStick TE S" }, 424 { MAKE_VIDPID(0x07ff, 0xffff), "Mad Catz GamePad" }, 425 { MAKE_VIDPID(0x0e6f, 0x0105), "HSM3 Xbox360 dancepad" }, 426 { MAKE_VIDPID(0x0e6f, 0x0113), "Afterglow AX.1 Gamepad for Xbox 360" }, 427 { MAKE_VIDPID(0x0e6f, 0x011f), "Rock Candy Gamepad Wired Controller" }, 428 { MAKE_VIDPID(0x0e6f, 0x0131), "PDP EA Sports Controller" }, 429 { MAKE_VIDPID(0x0e6f, 0x0133), "Xbox 360 Wired Controller" }, 430 { MAKE_VIDPID(0x0e6f, 0x0139), "Afterglow Prismatic Wired Controller" }, 431 { MAKE_VIDPID(0x0e6f, 0x013a), "PDP Xbox One Controller" }, 432 { MAKE_VIDPID(0x0e6f, 0x0146), "Rock Candy Wired Controller for Xbox One" }, 433 { MAKE_VIDPID(0x0e6f, 0x0147), "PDP Marvel Xbox One Controller" }, 434 { MAKE_VIDPID(0x0e6f, 0x015c), "PDP Xbox One Arcade Stick" }, 435 { MAKE_VIDPID(0x0e6f, 0x0161), "PDP Xbox One Controller" }, 436 { MAKE_VIDPID(0x0e6f, 0x0162), "PDP Xbox One Controller" }, 437 { MAKE_VIDPID(0x0e6f, 0x0163), "PDP Xbox One Controller" }, 438 { MAKE_VIDPID(0x0e6f, 0x0164), "PDP Battlefield One" }, 439 { MAKE_VIDPID(0x0e6f, 0x0165), "PDP Titanfall 2" }, 440 { MAKE_VIDPID(0x0e6f, 0x0201), "Pelican PL-3601 'TSZ' Wired Xbox 360 Controller" }, 441 { MAKE_VIDPID(0x0e6f, 0x0213), "Afterglow Gamepad for Xbox 360" }, 442 { MAKE_VIDPID(0x0e6f, 0x021f), "Rock Candy Gamepad for Xbox 360" }, 443 { MAKE_VIDPID(0x0e6f, 0x0246), "Rock Candy Gamepad for Xbox One 2015" }, 444 { MAKE_VIDPID(0x0e6f, 0x02a4), "PDP Wired Controller for Xbox One - Stealth Series" }, 445 { MAKE_VIDPID(0x0e6f, 0x02ab), "PDP Controller for Xbox One" }, 446 { MAKE_VIDPID(0x0e6f, 0x0301), "Logic3 Controller" }, 447 { MAKE_VIDPID(0x0e6f, 0x0346), "Rock Candy Gamepad for Xbox One 2016" }, 448 { MAKE_VIDPID(0x0e6f, 0x0401), "Logic3 Controller" }, 449 { MAKE_VIDPID(0x0e6f, 0x0413), "Afterglow AX.1 Gamepad for Xbox 360" }, 450 { MAKE_VIDPID(0x0e6f, 0x0501), "PDP Xbox 360 Controller" }, 451 { MAKE_VIDPID(0x0e6f, 0xf900), "PDP Afterglow AX.1" }, 452 { MAKE_VIDPID(0x0f0d, 0x000a), "Hori Co. DOA4 FightStick" }, 453 { MAKE_VIDPID(0x0f0d, 0x000c), "Hori PadEX Turbo" }, 454 { MAKE_VIDPID(0x0f0d, 0x000d), "Hori Fighting Stick EX2" }, 455 { MAKE_VIDPID(0x0f0d, 0x0016), "Hori Real Arcade Pro.EX" }, 456 { MAKE_VIDPID(0x0f0d, 0x001b), "Hori Real Arcade Pro VX" }, 457 { MAKE_VIDPID(0x0f0d, 0x0063), "Hori Real Arcade Pro Hayabusa (USA) Xbox One" }, 458 { MAKE_VIDPID(0x0f0d, 0x0067), "HORIPAD ONE" }, 459 { MAKE_VIDPID(0x0f0d, 0x0078), "Hori Real Arcade Pro V Kai Xbox One" }, 460 { MAKE_VIDPID(0x11c9, 0x55f0), "Nacon GC-100XF" }, 461 { MAKE_VIDPID(0x12ab, 0x0004), "Honey Bee Xbox360 dancepad" }, 462 { MAKE_VIDPID(0x12ab, 0x0301), "PDP AFTERGLOW AX.1" }, 463 { MAKE_VIDPID(0x12ab, 0x0303), "Mortal Kombat Klassic FightStick" }, 464 { MAKE_VIDPID(0x1430, 0x4748), "RedOctane Guitar Hero X-plorer" }, 465 { MAKE_VIDPID(0x1430, 0xf801), "RedOctane Controller" }, 466 { MAKE_VIDPID(0x146b, 0x0601), "BigBen Interactive XBOX 360 Controller" }, 467 { MAKE_VIDPID(0x1532, 0x0037), "Razer Sabertooth" }, 468 { MAKE_VIDPID(0x1532, 0x0a00), "Razer Atrox Arcade Stick" }, 469 { MAKE_VIDPID(0x1532, 0x0a03), "Razer Wildcat" }, 470 { MAKE_VIDPID(0x15e4, 0x3f00), "Power A Mini Pro Elite" }, 471 { MAKE_VIDPID(0x15e4, 0x3f0a), "Xbox Airflo wired controller" }, 472 { MAKE_VIDPID(0x15e4, 0x3f10), "Batarang Xbox 360 controller" }, 473 { MAKE_VIDPID(0x162e, 0xbeef), "Joytech Neo-Se Take2" }, 474 { MAKE_VIDPID(0x1689, 0xfd00), "Razer Onza Tournament Edition" }, 475 { MAKE_VIDPID(0x1689, 0xfd01), "Razer Onza Classic Edition" }, 476 { MAKE_VIDPID(0x1689, 0xfe00), "Razer Sabertooth" }, 477 { MAKE_VIDPID(0x1bad, 0x0002), "Harmonix Rock Band Guitar" }, 478 { MAKE_VIDPID(0x1bad, 0x0003), "Harmonix Rock Band Drumkit" }, 479 { MAKE_VIDPID(0x1bad, 0x0130), "Ion Drum Rocker" }, 480 { MAKE_VIDPID(0x1bad, 0xf016), "Mad Catz Xbox 360 Controller" }, 481 { MAKE_VIDPID(0x1bad, 0xf018), "Mad Catz Street Fighter IV SE Fighting Stick" }, 482 { MAKE_VIDPID(0x1bad, 0xf019), "Mad Catz Brawlstick for Xbox 360" }, 483 { MAKE_VIDPID(0x1bad, 0xf021), "Mad Cats Ghost Recon FS GamePad" }, 484 { MAKE_VIDPID(0x1bad, 0xf023), "MLG Pro Circuit Controller (Xbox)" }, 485 { MAKE_VIDPID(0x1bad, 0xf025), "Mad Catz Call Of Duty" }, 486 { MAKE_VIDPID(0x1bad, 0xf027), "Mad Catz FPS Pro" }, 487 { MAKE_VIDPID(0x1bad, 0xf028), "Street Fighter IV FightPad" }, 488 { MAKE_VIDPID(0x1bad, 0xf02e), "Mad Catz Fightpad" }, 489 { MAKE_VIDPID(0x1bad, 0xf030), "Mad Catz Xbox 360 MC2 MicroCon Racing Wheel" }, 490 { MAKE_VIDPID(0x1bad, 0xf036), "Mad Catz MicroCon GamePad Pro" }, 491 { MAKE_VIDPID(0x1bad, 0xf038), "Street Fighter IV FightStick TE" }, 492 { MAKE_VIDPID(0x1bad, 0xf039), "Mad Catz MvC2 TE" }, 493 { MAKE_VIDPID(0x1bad, 0xf03a), "Mad Catz SFxT Fightstick Pro" }, 494 { MAKE_VIDPID(0x1bad, 0xf03d), "Street Fighter IV Arcade Stick TE - Chun Li" }, 495 { MAKE_VIDPID(0x1bad, 0xf03e), "Mad Catz MLG FightStick TE" }, 496 { MAKE_VIDPID(0x1bad, 0xf03f), "Mad Catz FightStick SoulCaliber" }, 497 { MAKE_VIDPID(0x1bad, 0xf042), "Mad Catz FightStick TES+" }, 498 { MAKE_VIDPID(0x1bad, 0xf080), "Mad Catz FightStick TE2" }, 499 { MAKE_VIDPID(0x1bad, 0xf501), "HoriPad EX2 Turbo" }, 500 { MAKE_VIDPID(0x1bad, 0xf502), "Hori Real Arcade Pro.VX SA" }, 501 { MAKE_VIDPID(0x1bad, 0xf503), "Hori Fighting Stick VX" }, 502 { MAKE_VIDPID(0x1bad, 0xf504), "Hori Real Arcade Pro. EX" }, 503 { MAKE_VIDPID(0x1bad, 0xf505), "Hori Fighting Stick EX2B" }, 504 { MAKE_VIDPID(0x1bad, 0xf506), "Hori Real Arcade Pro.EX Premium VLX" }, 505 { MAKE_VIDPID(0x1bad, 0xf900), "Harmonix Xbox 360 Controller" }, 506 { MAKE_VIDPID(0x1bad, 0xf901), "Gamestop Xbox 360 Controller" }, 507 { MAKE_VIDPID(0x1bad, 0xf903), "Tron Xbox 360 controller" }, 508 { MAKE_VIDPID(0x1bad, 0xf904), "PDP Versus Fighting Pad" }, 509 { MAKE_VIDPID(0x1bad, 0xf906), "MortalKombat FightStick" }, 510 { MAKE_VIDPID(0x1bad, 0xfa01), "MadCatz GamePad" }, 511 { MAKE_VIDPID(0x1bad, 0xfd00), "Razer Onza TE" }, 512 { MAKE_VIDPID(0x1bad, 0xfd01), "Razer Onza" }, 513 { MAKE_VIDPID(0x24c6, 0x5000), "Razer Atrox Arcade Stick" }, 514 { MAKE_VIDPID(0x24c6, 0x5300), "PowerA MINI PROEX Controller" }, 515 { MAKE_VIDPID(0x24c6, 0x5303), "Xbox Airflo wired controller" }, 516 { MAKE_VIDPID(0x24c6, 0x530a), "Xbox 360 Pro EX Controller" }, 517 { MAKE_VIDPID(0x24c6, 0x531a), "PowerA Pro Ex" }, 518 { MAKE_VIDPID(0x24c6, 0x5397), "FUS1ON Tournament Controller" }, 519 { MAKE_VIDPID(0x24c6, 0x541a), "PowerA Xbox One Mini Wired Controller" }, 520 { MAKE_VIDPID(0x24c6, 0x542a), "Xbox ONE spectra" }, 521 { MAKE_VIDPID(0x24c6, 0x543a), "PowerA Xbox One wired controller" }, 522 { MAKE_VIDPID(0x24c6, 0x5500), "Hori XBOX 360 EX 2 with Turbo" }, 523 { MAKE_VIDPID(0x24c6, 0x5501), "Hori Real Arcade Pro VX-SA" }, 524 { MAKE_VIDPID(0x24c6, 0x5502), "Hori Fighting Stick VX Alt" }, 525 { MAKE_VIDPID(0x24c6, 0x5503), "Hori Fighting Edge" }, 526 { MAKE_VIDPID(0x24c6, 0x5506), "Hori SOULCALIBUR V Stick" }, 527 { MAKE_VIDPID(0x24c6, 0x550d), "Hori GEM Xbox controller" }, 528 { MAKE_VIDPID(0x24c6, 0x550e), "Hori Real Arcade Pro V Kai 360" }, 529 { MAKE_VIDPID(0x24c6, 0x551a), "PowerA FUSION Pro Controller" }, 530 { MAKE_VIDPID(0x24c6, 0x561a), "PowerA FUSION Controller" }, 531 { MAKE_VIDPID(0x24c6, 0x5b00), "ThrustMaster Ferrari 458 Racing Wheel" }, 532 { MAKE_VIDPID(0x24c6, 0x5b02), "Thrustmaster, Inc. GPX Controller" }, 533 { MAKE_VIDPID(0x24c6, 0x5b03), "Thrustmaster Ferrari 458 Racing Wheel" }, 534 { MAKE_VIDPID(0x24c6, 0x5d04), "Razer Sabertooth" }, 535 { MAKE_VIDPID(0x24c6, 0xfafe), "Rock Candy Gamepad for Xbox 360" }, 536 }; 537 int i; 538 Uint32 vidpid = MAKE_VIDPID(vendor_id, product_id); 539 540 for (i = 0; i < SDL_arraysize(names); ++i) { 541 if (vidpid == names[i].vidpid) { 542 return names[i].name; 543 } 544 } 545 return NULL; 546} 547 548static SDL_bool 549HIDAPI_IsDeviceSupported(Uint16 vendor_id, Uint16 product_id, Uint16 version) 550{ 551 int i; 552 553 for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) { 554 SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i]; 555 if (driver->enabled && driver->IsSupportedDevice(vendor_id, product_id, version, -1, 0, 0)) { 556 return SDL_TRUE; 557 } 558 } 559 return SDL_FALSE; 560} 561 562static SDL_HIDAPI_DeviceDriver * 563HIDAPI_GetDeviceDriver(SDL_HIDAPI_Device *device) 564{ 565 int i; 566 567 if (SDL_ShouldIgnoreJoystick(device->name, device->guid)) { 568 return NULL; 569 } 570 571 for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) { 572 SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i]; 573 if (driver->enabled && driver->IsSupportedDevice(device->vendor_id, device->product_id, device->version, device->interface_number, device->usage_page, device->usage)) { 574 return driver; 575 } 576 } 577 return NULL; 578} 579 580static SDL_HIDAPI_Device * 581HIDAPI_GetJoystickByIndex(int device_index) 582{ 583 SDL_HIDAPI_Device *device = SDL_HIDAPI_devices; 584 while (device) { 585 if (device->driver) { 586 if (device_index == 0) { 587 break; 588 } 589 --device_index; 590 } 591 device = device->next; 592 } 593 return device; 594} 595 596static SDL_HIDAPI_Device * 597HIDAPI_GetJoystickByInfo(const char *path, Uint16 vendor_id, Uint16 product_id) 598{ 599 SDL_HIDAPI_Device *device = SDL_HIDAPI_devices; 600 while (device) { 601 if (device->vendor_id == vendor_id && device->product_id == product_id && 602 SDL_strcmp(device->path, path) == 0) { 603 break; 604 } 605 device = device->next; 606 } 607 return device; 608} 609 610static void SDLCALL 611SDL_HIDAPIDriverHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 612{ 613 int i; 614 SDL_HIDAPI_Device *device = SDL_HIDAPI_devices; 615 SDL_bool enabled = (!hint || !*hint || ((*hint != '0') && (SDL_strcasecmp(hint, "false") != 0))); 616 617 if (SDL_strcmp(name, SDL_HINT_JOYSTICK_HIDAPI) == 0) { 618 for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) { 619 SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i]; 620 driver->enabled = SDL_GetHintBoolean(driver->hint, enabled); 621 } 622 } else { 623 for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) { 624 SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i]; 625 if (SDL_strcmp(name, driver->hint) == 0) { 626 driver->enabled = enabled; 627 break; 628 } 629 } 630 } 631 632 /* Update device list if driver availability changes */ 633 while (device) { 634 if (device->driver) { 635 if (!device->driver->enabled) { 636 device->driver = NULL; 637 638 --SDL_HIDAPI_numjoysticks; 639 640 SDL_PrivateJoystickRemoved(device->instance_id); 641 } 642 } else { 643 device->driver = HIDAPI_GetDeviceDriver(device); 644 if (device->driver) { 645 device->instance_id = SDL_GetNextJoystickInstanceID(); 646 647 ++SDL_HIDAPI_numjoysticks; 648 649 SDL_PrivateJoystickAdded(device->instance_id); 650 } 651 } 652 device = device->next; 653 } 654} 655 656static void HIDAPI_JoystickDetect(void); 657 658static int 659HIDAPI_JoystickInit(void) 660{ 661 int i; 662 663 if (hid_init() < 0) { 664 SDL_SetError("Couldn't initialize hidapi"); 665 return -1; 666 } 667 668 for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) { 669 SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i]; 670 SDL_AddHintCallback(driver->hint, SDL_HIDAPIDriverHintChanged, NULL); 671 } 672 SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI, 673 SDL_HIDAPIDriverHintChanged, NULL); 674 HIDAPI_InitializeDiscovery(); 675 HIDAPI_JoystickDetect(); 676 return 0; 677} 678 679static int 680HIDAPI_JoystickGetCount(void) 681{ 682 return SDL_HIDAPI_numjoysticks; 683} 684 685static void 686HIDAPI_AddDevice(struct hid_device_info *info) 687{ 688 SDL_HIDAPI_Device *device; 689 SDL_HIDAPI_Device *curr, *last = NULL; 690 691 for (curr = SDL_HIDAPI_devices, last = NULL; curr; last = curr, curr = curr->next) { 692 continue; 693 } 694 695 device = (SDL_HIDAPI_Device *)SDL_calloc(1, sizeof(*device)); 696 if (!device) { 697 return; 698 } 699 device->instance_id = -1; 700 device->seen = SDL_TRUE; 701 device->vendor_id = info->vendor_id; 702 device->product_id = info->product_id; 703 device->version = info->release_number; 704 device->interface_number = info->interface_number; 705 device->usage_page = info->usage_page; 706 device->usage = info->usage; 707 { 708 /* FIXME: Is there any way to tell whether this is a Bluetooth device? */ 709 const Uint16 vendor = device->vendor_id; 710 const Uint16 product = device->product_id; 711 const Uint16 version = device->version; 712 Uint16 *guid16 = (Uint16 *)device->guid.data; 713 714 *guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_USB); 715 *guid16++ = 0; 716 *guid16++ = SDL_SwapLE16(vendor); 717 *guid16++ = 0; 718 *guid16++ = SDL_SwapLE16(product); 719 *guid16++ = 0; 720 *guid16++ = SDL_SwapLE16(version); 721 *guid16++ = 0; 722 723 /* Note that this is a HIDAPI device for special handling elsewhere */ 724 device->guid.data[14] = 'h'; 725 device->guid.data[15] = 0; 726 } 727 device->driver = HIDAPI_GetDeviceDriver(device); 728 729 if (device->driver) { 730 const char *name = device->driver->GetDeviceName(device->vendor_id, device->product_id); 731 if (name) { 732 device->name = SDL_strdup(name); 733 } 734 } 735 736 if (!device->name && info->manufacturer_string && info->product_string) { 737 char *manufacturer_string = SDL_iconv_string("UTF-8", "WCHAR_T", (char*)info->manufacturer_string, (SDL_wcslen(info->manufacturer_string)+1)*sizeof(wchar_t)); 738 char *product_string = SDL_iconv_string("UTF-8", "WCHAR_T", (char*)info->product_string, (SDL_wcslen(info->product_string)+1)*sizeof(wchar_t)); 739 if (!manufacturer_string && !product_string) { 740 if (sizeof(wchar_t) == sizeof(Uint16)) { 741 manufacturer_string = SDL_iconv_string("UTF-8", "UCS-2-INTERNAL", (char*)info->manufacturer_string, (SDL_wcslen(info->manufacturer_string)+1)*sizeof(wchar_t)); 742 product_string = SDL_iconv_string("UTF-8", "UCS-2-INTERNAL", (char*)info->product_string, (SDL_wcslen(info->product_string)+1)*sizeof(wchar_t)); 743 } else if (sizeof(wchar_t) == sizeof(Uint32)) { 744 manufacturer_string = SDL_iconv_string("UTF-8", "UCS-4-INTERNAL", (char*)info->manufacturer_string, (SDL_wcslen(info->manufacturer_string)+1)*sizeof(wchar_t)); 745 product_string = SDL_iconv_string("UTF-8", "UCS-4-INTERNAL", (char*)info->product_string, (SDL_wcslen(info->product_string)+1)*sizeof(wchar_t)); 746 } 747 } 748 if (manufacturer_string && product_string) { 749 size_t name_size = (SDL_strlen(manufacturer_string) + 1 + SDL_strlen(product_string) + 1); 750 device->name = (char *)SDL_malloc(name_size); 751 if (device->name) { 752 SDL_snprintf(device->name, name_size, "%s %s", manufacturer_string, product_string); 753 } 754 } 755 if (manufacturer_string) { 756 SDL_free(manufacturer_string); 757 } 758 if (product_string) { 759 SDL_free(product_string); 760 } 761 } 762 if (!device->name) { 763 size_t name_size = (6 + 1 + 6 + 1); 764 device->name = (char *)SDL_malloc(name_size); 765 if (!device->name) { 766 SDL_free(device); 767 return; 768 } 769 SDL_snprintf(device->name, name_size, "0x%.4x/0x%.4x", info->vendor_id, info->product_id); 770 } 771 772 device->path = SDL_strdup(info->path); 773 if (!device->path) { 774 SDL_free(device->name); 775 SDL_free(device); 776 return; 777 } 778 779#ifdef DEBUG_HIDAPI 780 SDL_Log("Adding HIDAPI device '%s' VID 0x%.4x, PID 0x%.4x, version %d, interface %d, usage page 0x%.4x, usage 0x%.4x\n", device->name, device->vendor_id, device->product_id, device->version, device->interface_number, device->usage_page, device->usage); 781#endif 782 783 /* Add it to the list */ 784 if (last) { 785 last->next = device; 786 } else { 787 SDL_HIDAPI_devices = device; 788 } 789 790 if (device->driver) { 791 /* It's a joystick! */ 792 device->instance_id = SDL_GetNextJoystickInstanceID(); 793 794 ++SDL_HIDAPI_numjoysticks; 795 796 SDL_PrivateJoystickAdded(device->instance_id); 797 } 798} 799 800 801static void 802HIDAPI_DelDevice(SDL_HIDAPI_Device *device, SDL_bool send_event) 803{ 804 SDL_HIDAPI_Device *curr, *last; 805 for (curr = SDL_HIDAPI_devices, last = NULL; curr; last = curr, curr = curr->next) { 806 if (curr == device) { 807 if (last) { 808 last->next = curr->next; 809 } else { 810 SDL_HIDAPI_devices = curr->next; 811 } 812 813 if (device->driver && send_event) { 814 /* Need to decrement the joystick count before we post the event */ 815 --SDL_HIDAPI_numjoysticks; 816 817 SDL_PrivateJoystickRemoved(device->instance_id); 818 } 819 820 SDL_free(device->name); 821 SDL_free(device->path); 822 SDL_free(device); 823 return; 824 } 825 } 826} 827 828static void 829HIDAPI_UpdateDeviceList(void) 830{ 831 SDL_HIDAPI_Device *device; 832 struct hid_device_info *devs, *info; 833 834 /* Prepare the existing device list */ 835 device = SDL_HIDAPI_devices; 836 while (device) { 837 device->seen = SDL_FALSE; 838 device = device->next; 839 } 840 841 /* Enumerate the devices */ 842 devs = hid_enumerate(0, 0); 843 if (devs) { 844 for (info = devs; info; info = info->next) { 845 device = HIDAPI_GetJoystickByInfo(info->path, info->vendor_id, info->product_id); 846 if (device) { 847 device->seen = SDL_TRUE; 848 } else { 849 HIDAPI_AddDevice(info); 850 } 851 } 852 hid_free_enumeration(devs); 853 } 854 855 /* Remove any devices that weren't seen */ 856 device = SDL_HIDAPI_devices; 857 while (device) { 858 SDL_HIDAPI_Device *next = device->next; 859 860 if (!device->seen) { 861 HIDAPI_DelDevice(device, SDL_TRUE); 862 } 863 device = next; 864 } 865} 866 867SDL_bool 868HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version) 869{ 870 SDL_HIDAPI_Device *device; 871 872 /* Don't update the device list for devices we know aren't supported */ 873 if (!HIDAPI_IsDeviceSupported(vendor_id, product_id, version)) { 874 return SDL_FALSE; 875 } 876 877 /* Make sure the device list is completely up to date when we check for device presence */ 878 HIDAPI_UpdateDeviceList(); 879 880 device = SDL_HIDAPI_devices; 881 while (device) { 882 if (device->vendor_id == vendor_id && device->product_id == product_id && device->driver) { 883 return SDL_TRUE; 884 } 885 device = device->next; 886 } 887 return SDL_FALSE; 888} 889 890static void 891HIDAPI_JoystickDetect(void) 892{ 893 HIDAPI_UpdateDiscovery(); 894 if (SDL_HIDAPI_discovery.m_bHaveDevicesChanged) { 895 /* FIXME: We probably need to schedule an update in a few seconds as well */ 896 HIDAPI_UpdateDeviceList(); 897 SDL_HIDAPI_discovery.m_bHaveDevicesChanged = SDL_FALSE; 898 } 899} 900 901static const char * 902HIDAPI_JoystickGetDeviceName(int device_index) 903{ 904 return HIDAPI_GetJoystickByIndex(device_index)->name; 905} 906 907static SDL_JoystickGUID 908HIDAPI_JoystickGetDeviceGUID(int device_index) 909{ 910 return HIDAPI_GetJoystickByIndex(device_index)->guid; 911} 912 913static SDL_JoystickID 914HIDAPI_JoystickGetDeviceInstanceID(int device_index) 915{ 916 return HIDAPI_GetJoystickByIndex(device_index)->instance_id; 917} 918 919static int 920HIDAPI_JoystickOpen(SDL_Joystick * joystick, int device_index) 921{ 922 SDL_HIDAPI_Device *device = HIDAPI_GetJoystickByIndex(device_index); 923 struct joystick_hwdata *hwdata; 924 925 hwdata = (struct joystick_hwdata *)SDL_calloc(1, sizeof(*hwdata)); 926 if (!hwdata) { 927 return SDL_OutOfMemory(); 928 } 929 930 hwdata->driver = device->driver; 931 hwdata->dev = hid_open_path(device->path, 0); 932 if (!hwdata->dev) { 933 SDL_free(hwdata); 934 return SDL_SetError("Couldn't open HID device %s", device->path); 935 } 936 937 if (!device->driver->Init(joystick, hwdata->dev, device->vendor_id, device->product_id, &hwdata->context)) { 938 hid_close(hwdata->dev); 939 SDL_free(hwdata); 940 return -1; 941 } 942 943 joystick->hwdata = hwdata; 944 return 0; 945} 946 947static int 948HIDAPI_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms) 949{ 950 struct joystick_hwdata *hwdata = joystick->hwdata; 951 SDL_HIDAPI_DeviceDriver *driver = hwdata->driver; 952 return driver->Rumble(joystick, hwdata->dev, hwdata->context, low_frequency_rumble, high_frequency_rumble, duration_ms); 953} 954 955static void 956HIDAPI_JoystickUpdate(SDL_Joystick * joystick) 957{ 958 struct joystick_hwdata *hwdata = joystick->hwdata; 959 SDL_HIDAPI_DeviceDriver *driver = hwdata->driver; 960 if (!driver->Update(joystick, hwdata->dev, hwdata->context)) { 961 SDL_HIDAPI_Device *device; 962 for (device = SDL_HIDAPI_devices; device; device = device->next) { 963 if (device->instance_id == joystick->instance_id) { 964 HIDAPI_DelDevice(device, SDL_TRUE); 965 break; 966 } 967 } 968 } 969} 970 971static void 972HIDAPI_JoystickClose(SDL_Joystick * joystick) 973{ 974 struct joystick_hwdata *hwdata = joystick->hwdata; 975 SDL_HIDAPI_DeviceDriver *driver = hwdata->driver; 976 driver->Quit(joystick, hwdata->dev, hwdata->context); 977 978 hid_close(hwdata->dev); 979 SDL_free(hwdata); 980 joystick->hwdata = NULL; 981} 982 983static void 984HIDAPI_JoystickQuit(void) 985{ 986 int i; 987 988 HIDAPI_ShutdownDiscovery(); 989 990 while (SDL_HIDAPI_devices) { 991 HIDAPI_DelDevice(SDL_HIDAPI_devices, SDL_FALSE); 992 } 993 for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) { 994 SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i]; 995 SDL_DelHintCallback(driver->hint, SDL_HIDAPIDriverHintChanged, NULL); 996 } 997 SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI, 998 SDL_HIDAPIDriverHintChanged, NULL); 999 SDL_HIDAPI_numjoysticks = 0; 1000 1001 hid_exit(); 1002} 1003 1004SDL_JoystickDriver SDL_HIDAPI_JoystickDriver = 1005{ 1006 HIDAPI_JoystickInit, 1007 HIDAPI_JoystickGetCount, 1008 HIDAPI_JoystickDetect, 1009 HIDAPI_JoystickGetDeviceName, 1010 HIDAPI_JoystickGetDeviceGUID, 1011 HIDAPI_JoystickGetDeviceInstanceID, 1012 HIDAPI_JoystickOpen, 1013 HIDAPI_JoystickRumble, 1014 HIDAPI_JoystickUpdate, 1015 HIDAPI_JoystickClose, 1016 HIDAPI_JoystickQuit, 1017}; 1018 1019#endif /* SDL_JOYSTICK_HIDAPI */ 1020 1021/* vi: set ts=4 sw=4 expandtab: */ 1022
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.