Procházet zdrojové kódy

Mac OS X: Look for joystick hotplug in its own CFRunLoop.

This allows the joystick hotplug to function without the main event loop
 (specifically: without SDL_INIT_VIDEO), and moves explicit polling for
 joysticks where it belongs at the low-level: in SDL_SYS_JoystickDetect().

This lets apps call SDL_JoystickUpdate() to get hotplug events and keep
 SDL_NumJoysticks() correct, as expected. As SDL_PumpEvents() (and
 SDL_PollEvents, etc) calls SDL_JoystickUpdate(), existing apps will function
 as before.

Thanks to "raskie" on the forums for pointing this out!
Ryan C. Gordon před 11 roky
rodič
revize
5d7562c7e2
1 změnil soubory, kde provedl 16 přidání a 10 odebrání
  1. 16 10
      src/joystick/darwin/SDL_sysjoystick.c

+ 16 - 10
src/joystick/darwin/SDL_sysjoystick.c

@@ -38,6 +38,8 @@
 #include "../../events/SDL_events_c.h"
 #endif
 
+#define SDL_JOYSTICK_RUNLOOP_MODE CFSTR("SDLJoystick")
+
 /* The base object of the HID Manager API */
 static IOHIDManagerRef hidman = NULL;
 
@@ -67,6 +69,11 @@ FreeDevice(recDevice *removeDevice)
 {
     recDevice *pDeviceNext = NULL;
     if (removeDevice) {
+        if (removeDevice->deviceRef) {
+            IOHIDDeviceUnscheduleFromRunLoop(removeDevice->deviceRef, CFRunLoopGetCurrent(), SDL_JOYSTICK_RUNLOOP_MODE);
+            removeDevice->deviceRef = NULL;
+        }
+
         /* save next device prior to disposing of this device */
         pDeviceNext = removeDevice->pNext;
 
@@ -378,7 +385,7 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic
 
     /* Get notified when this device is disconnected. */
     IOHIDDeviceRegisterRemovalCallback(ioHIDDeviceObject, JoystickDeviceWasRemovedCallback, device);
-    IOHIDDeviceScheduleWithRunLoop(ioHIDDeviceObject, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+    IOHIDDeviceScheduleWithRunLoop(ioHIDDeviceObject, CFRunLoopGetCurrent(), SDL_JOYSTICK_RUNLOOP_MODE);
 
     /* Allocate an instance ID for this device */
     device->instance_id = ++s_joystick_instance_id;
@@ -420,25 +427,19 @@ ConfigHIDManager(CFArrayRef matchingArray)
 {
     CFRunLoopRef runloop = CFRunLoopGetCurrent();
 
-    /* Run in a custom RunLoop mode just while initializing,
-       so we can detect sticks without messing with everything else. */
-    CFStringRef tempRunLoopMode = CFSTR("SDLJoystickInit");
-
     if (IOHIDManagerOpen(hidman, kIOHIDOptionsTypeNone) != kIOReturnSuccess) {
         return SDL_FALSE;
     }
 
     IOHIDManagerRegisterDeviceMatchingCallback(hidman, JoystickDeviceWasAddedCallback, NULL);
-    IOHIDManagerScheduleWithRunLoop(hidman, runloop, tempRunLoopMode);
+    IOHIDManagerScheduleWithRunLoop(hidman, runloop, SDL_JOYSTICK_RUNLOOP_MODE);
     IOHIDManagerSetDeviceMatchingMultiple(hidman, matchingArray);
 
-    while (CFRunLoopRunInMode(tempRunLoopMode,0,TRUE)==kCFRunLoopRunHandledSource) {
+    while (CFRunLoopRunInMode(SDL_JOYSTICK_RUNLOOP_MODE,0,TRUE) == kCFRunLoopRunHandledSource) {
         /* no-op. Callback fires once per existing device. */
     }
 
-    /* Put this in the normal RunLoop mode now, for future hotplug events. */
-    IOHIDManagerUnscheduleFromRunLoop(hidman, runloop, tempRunLoopMode);
-    IOHIDManagerScheduleWithRunLoop(hidman, runloop, kCFRunLoopDefaultMode);
+    /* future hotplug events will come through SDL_JOYSTICK_RUNLOOP_MODE now. */
 
     return SDL_TRUE;  /* good to go. */
 }
@@ -544,6 +545,10 @@ SDL_SYS_NumJoysticks()
 void
 SDL_SYS_JoystickDetect()
 {
+    while (CFRunLoopRunInMode(SDL_JOYSTICK_RUNLOOP_MODE,0,TRUE) == kCFRunLoopRunHandledSource) {
+        /* no-op. Pending callbacks will fire in CFRunLoopRunInMode(). */
+    }
+
     if (s_bDeviceAdded || s_bDeviceRemoved) {
         recDevice *device = gpDeviceList;
         s_bDeviceAdded = SDL_FALSE;
@@ -793,6 +798,7 @@ SDL_SYS_JoystickQuit(void)
     }
 
     if (hidman) {
+        IOHIDManagerUnscheduleFromRunLoop(hidman, CFRunLoopGetCurrent(), SDL_JOYSTICK_RUNLOOP_MODE);
         IOHIDManagerClose(hidman, kIOHIDOptionsTypeNone);
         CFRelease(hidman);
         hidman = NULL;