WinRT: added hotplug support for joysticks/game-controllers
authorDavid Ludwig <dludwig@pobox.com>
Tue, 21 May 2013 20:08:53 -0400
changeset 8473 218549868b0b
parent 8472 53cfc3c75475
child 8474 cbf580f6ea1b
WinRT: added hotplug support for joysticks/game-controllers
src/joystick/windowsrt/SDL_xinputjoystick.c
--- a/src/joystick/windowsrt/SDL_xinputjoystick.c	Mon May 20 11:09:08 2013 -0400
+++ b/src/joystick/windowsrt/SDL_xinputjoystick.c	Tue May 21 20:08:53 2013 -0400
@@ -37,6 +37,7 @@
 #include "../SDL_sysjoystick.h"
 #include "../SDL_joystick_c.h"
 #include "SDL_events.h"
+#include "../../events/SDL_events_c.h"
 
 #include <Windows.h>
 #include <Xinput.h>
@@ -46,6 +47,7 @@
     DWORD userIndex;    // The XInput device index, in the range [0, XUSER_MAX_COUNT-1] (probably [0,3]).
     XINPUT_STATE XInputState;   // the last-read in XInputState, kept around to compare old and new values
     SDL_bool isDeviceConnected; // was the device connected (on the last polling, or during backend-initialization)?
+    SDL_bool isDeviceRemovalEventPending;   // was the device removed, and is the associated removal event pending?
 };
 
 /* Keep track of data on all XInput devices, regardless of whether or not
@@ -96,11 +98,67 @@
 
 void SDL_SYS_JoystickDetect()
 {
+    DWORD i;
+    XINPUT_STATE tempXInputState;
+    HRESULT result;
+    SDL_Event event;
+
+    /* Iterate through each possible XInput device, seeing if any devices
+       have been connected, or if they were removed.
+     */
+    for (i = 0; i < XUSER_MAX_COUNT; ++i) {
+        /* See if any new devices are connected. */
+        if (!g_XInputData[i].isDeviceConnected && !g_XInputData[i].isDeviceRemovalEventPending) {
+            result = XInputGetState(i, &tempXInputState);
+            if (result == ERROR_SUCCESS) {
+                /* Yup, a device is connected.  Mark the device as connected,
+                   then tell others about it (via an SDL_JOYDEVICEADDED event.)
+                 */
+                g_XInputData[i].isDeviceConnected = SDL_TRUE;
+
+#if !SDL_EVENTS_DISABLED
+                SDL_zero(event);
+                event.type = SDL_JOYDEVICEADDED;
+                
+                if (SDL_GetEventState(event.type) == SDL_ENABLE) {
+                    event.jdevice.which = i;
+                    if ((SDL_EventOK == NULL)
+                        || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
+                        SDL_PushEvent(&event);
+                    }
+                }
+#endif
+            }
+        } else if (g_XInputData[i].isDeviceRemovalEventPending) {
+            /* A device was previously marked as removed (by
+               SDL_SYS_JoystickUpdate).  Tell others about the device removal.
+            */
+
+            g_XInputData[i].isDeviceRemovalEventPending = SDL_FALSE;
+
+#if !SDL_EVENTS_DISABLED
+            SDL_zero(event);
+            event.type = SDL_JOYDEVICEREMOVED;
+                
+            if (SDL_GetEventState(event.type) == SDL_ENABLE) {
+                event.jdevice.which = i; //joystick->hwdata->userIndex;
+                if ((SDL_EventOK == NULL)
+                    || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
+                    SDL_PushEvent(&event);
+                }
+            }
+#endif
+        }
+    }
 }
 
 SDL_bool SDL_SYS_JoystickNeedsPolling()
 {
-    return SDL_FALSE;
+    /* Since XInput, or WinRT, provides any events to indicate when a game
+       controller gets connected, and instead indicates device availability
+       solely through polling, we'll poll (for new devices).
+     */
+    return SDL_TRUE;
 }
 
 /* Internal function to retreive device capabilities.
@@ -261,12 +319,11 @@
     /* Poll for new data */
     result = XInputGetState(joystick->hwdata->userIndex, &joystick->hwdata->XInputState);
     if (result == ERROR_DEVICE_NOT_CONNECTED) {
-        /* TODO, WinRT: set a flag to indicate that a device-removal event
-           needs to be emitted.
-         */
-        //joystick->hwdata->send_remove_event = 1;
-        //joystick->hwdata->removed = 1;
-        joystick->hwdata->isDeviceConnected = SDL_FALSE;
+        if (joystick->hwdata->isDeviceConnected) {
+            joystick->hwdata->isDeviceConnected = SDL_FALSE;
+            joystick->hwdata->isDeviceRemovalEventPending = SDL_TRUE;
+            /* TODO, WinRT: make sure isDeviceRemovalEventPending gets cleared as appropriate, and that quick re-plugs don't cause trouble */
+        }
         return;
     }