소스 검색

Moved raw input event processing from the main thread to the joystick thread

This allows fast joystick event delivery regardless of what the main thread is doing.
Sam Lantinga 4 년 전
부모
커밋
a0c5bfa3bd

+ 2 - 0
include/SDL_config_windows.h

@@ -215,7 +215,9 @@ typedef unsigned int uintptr_t;
 /* Enable various input drivers */
 #define SDL_JOYSTICK_DINPUT 1
 #define SDL_JOYSTICK_HIDAPI 1
+#ifndef __WINRT__
 #define SDL_JOYSTICK_RAWINPUT   1
+#endif
 #define SDL_JOYSTICK_VIRTUAL    1
 #ifdef SDL_WINDOWS10_SDK
 #define SDL_JOYSTICK_WGI    1

+ 2 - 2
src/joystick/hidapi/SDL_hidapijoystick.c

@@ -192,7 +192,7 @@ HIDAPI_InitializeDiscovery()
 #if defined(__WIN32__)
     SDL_HIDAPI_discovery.m_nThreadID = SDL_ThreadID();
 
-    SDL_memset(&SDL_HIDAPI_discovery.m_wndClass, 0x0, sizeof(SDL_HIDAPI_discovery.m_wndClass));
+    SDL_zero(SDL_HIDAPI_discovery.m_wndClass);
     SDL_HIDAPI_discovery.m_wndClass.hInstance = GetModuleHandle(NULL);
     SDL_HIDAPI_discovery.m_wndClass.lpszClassName = "SDL_HIDAPI_DEVICE_DETECTION";
     SDL_HIDAPI_discovery.m_wndClass.lpfnWndProc = ControllerWndProc;      /* This function is called by windows */
@@ -203,8 +203,8 @@ HIDAPI_InitializeDiscovery()
 
     {
         DEV_BROADCAST_DEVICEINTERFACE_A devBroadcast;
-        SDL_memset( &devBroadcast, 0x0, sizeof( devBroadcast ) );
 
+        SDL_zero(devBroadcast);
         devBroadcast.dbcc_size = sizeof( devBroadcast );
         devBroadcast.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
         devBroadcast.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE;

+ 100 - 110
src/joystick/windows/SDL_rawinputjoystick.c

@@ -37,6 +37,7 @@
 #include "SDL_endian.h"
 #include "SDL_events.h"
 #include "SDL_hints.h"
+#include "SDL_mutex.h"
 #include "SDL_timer.h"
 #include "../usb_ids.h"
 #include "../SDL_sysjoystick.h"
@@ -84,12 +85,10 @@ typedef struct WindowsGamingInputGamepadState WindowsGamingInputGamepadState;
 #define GIDC_REMOVAL             2
 #endif
 
-/* external variables referenced. */
-extern HWND SDL_HelperWindow;
-
 
 static SDL_bool SDL_RAWINPUT_inited = SDL_FALSE;
 static int SDL_RAWINPUT_numjoysticks = 0;
+static SDL_mutex *SDL_RAWINPUT_mutex = NULL;
 
 static void RAWINPUT_JoystickClose(SDL_Joystick *joystick);
 
@@ -625,40 +624,10 @@ RAWINPUT_QuitWindowsGamingInput(RAWINPUT_DeviceContext *ctx)
 #endif /* SDL_JOYSTICK_RAWINPUT_WGI */
 
 
-/* Most of the time the raw input messages will get dispatched in the main event loop,
- * but sometimes we want to get any pending device change messages immediately.
- */
-static void
-RAWINPUT_GetPendingDeviceChanges(void)
-{
-    MSG msg;
-    while (PeekMessage(&msg, SDL_HelperWindow, WM_INPUT_DEVICE_CHANGE, WM_INPUT_DEVICE_CHANGE + 1, PM_REMOVE)) {
-        TranslateMessage(&msg);
-        DispatchMessage(&msg);
-    }
-}
-
-static SDL_bool pump_device_events;
-static void
-RAWINPUT_GetPendingDeviceInput(void)
-{
-    if (pump_device_events) {
-        MSG msg;
-        while (PeekMessage(&msg, SDL_HelperWindow, WM_INPUT, WM_INPUT + 1, PM_REMOVE)) {
-            TranslateMessage(&msg);
-            DispatchMessage(&msg);
-        }
-        pump_device_events = SDL_FALSE;
-    }
-}
-
 static int
 RAWINPUT_JoystickInit(void)
 {
-    int ii;
-    RAWINPUTDEVICE rid[SDL_arraysize(subscribed_devices)];
     SDL_assert(!SDL_RAWINPUT_inited);
-    SDL_assert(SDL_HelperWindow);
 
     if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_RAWINPUT, SDL_TRUE)) {
         return -1;
@@ -668,25 +637,9 @@ RAWINPUT_JoystickInit(void)
         return -1;
     }
 
-    for (ii = 0; ii < SDL_arraysize(subscribed_devices); ii++) {
-        rid[ii].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
-        rid[ii].usUsage = subscribed_devices[ii];
-        rid[ii].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; /* Receive messages when in background, including device add/remove */
-        rid[ii].hwndTarget = SDL_HelperWindow;
-    }
-
-    if (!RegisterRawInputDevices(rid, SDL_arraysize(rid), sizeof(RAWINPUTDEVICE))) {
-        SDL_SetError("Couldn't initialize RAWINPUT");
-        WIN_UnloadHIDDLL();
-        return -1;
-    }
-
+    SDL_RAWINPUT_mutex = SDL_CreateMutex();
     SDL_RAWINPUT_inited = SDL_TRUE;
 
-    /* Get initial controller connect messages */
-    RAWINPUT_GetPendingDeviceChanges();
-    pump_device_events = SDL_TRUE;
-
     return 0;
 }
 
@@ -930,8 +883,6 @@ RAWINPUT_PostUpdate(void)
     guide_button_candidate.joystick = NULL;
 
 #endif /* SDL_JOYSTICK_RAWINPUT_MATCHING */
-
-    pump_device_events = SDL_TRUE;
 }
 
 SDL_bool
@@ -945,9 +896,6 @@ RAWINPUT_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, co
 {
     SDL_RAWINPUT_Device *device;
 
-    /* Make sure the device list is completely up to date when we check for device presence */
-    RAWINPUT_GetPendingDeviceChanges();
-
     /* If we're being asked about a device, that means another API just detected one, so rescan */
 #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
     xinput_device_change = SDL_TRUE;
@@ -983,8 +931,6 @@ RAWINPUT_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, co
 static void
 RAWINPUT_JoystickDetect(void)
 {
-    RAWINPUT_GetPendingDeviceChanges();
-
     RAWINPUT_PostUpdate();
 }
 
@@ -1727,8 +1673,6 @@ RAWINPUT_UpdateOtherAPIs(SDL_Joystick *joystick)
 static void
 RAWINPUT_JoystickUpdate(SDL_Joystick *joystick)
 {
-    RAWINPUT_GetPendingDeviceInput();
-
     RAWINPUT_UpdateOtherAPIs(joystick);
 }
 
@@ -1776,74 +1720,115 @@ RAWINPUT_JoystickClose(SDL_Joystick *joystick)
     }
 }
 
-LRESULT RAWINPUT_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+SDL_bool
+RAWINPUT_RegisterNotifications(HWND hWnd)
 {
-    if (!SDL_RAWINPUT_inited)
-        return -1;
+    RAWINPUTDEVICE rid[SDL_arraysize(subscribed_devices)];
+    int i;
 
-    switch (msg)
-    {
-        case WM_INPUT_DEVICE_CHANGE:
-        {
-            HANDLE hDevice = (HANDLE)lParam;
-            switch (wParam) {
-            case GIDC_ARRIVAL:
-                RAWINPUT_AddDevice(hDevice);
-                break;
-            case GIDC_REMOVAL: {
-                SDL_RAWINPUT_Device *device;
-                device = RAWINPUT_DeviceFromHandle(hDevice);
-                if (device) {
-                    RAWINPUT_DelDevice(device, SDL_TRUE);
+    for (i = 0; i < SDL_arraysize(subscribed_devices); i++) {
+        rid[i].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
+        rid[i].usUsage = subscribed_devices[i];
+        rid[i].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; /* Receive messages when in background, including device add/remove */
+        rid[i].hwndTarget = hWnd;
+    }
+
+    if (!RegisterRawInputDevices(rid, SDL_arraysize(rid), sizeof(RAWINPUTDEVICE))) {
+        SDL_SetError("Couldn't register for raw input events");
+        return SDL_FALSE;
+    }
+    return SDL_TRUE;
+}
+
+void
+RAWINPUT_UnregisterNotifications()
+{
+    int i;
+    RAWINPUTDEVICE rid[SDL_arraysize(subscribed_devices)];
+
+    for (i = 0; i < SDL_arraysize(subscribed_devices); i++) {
+        rid[i].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
+        rid[i].usUsage = subscribed_devices[i];
+        rid[i].dwFlags = RIDEV_REMOVE;
+        rid[i].hwndTarget = NULL;
+    }
+
+    if (!RegisterRawInputDevices(rid, SDL_arraysize(rid), sizeof(RAWINPUTDEVICE))) {
+        SDL_SetError("Couldn't unregister for raw input events");
+        return;
+    }
+}
+    
+LRESULT CALLBACK
+RAWINPUT_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    LRESULT result = -1;
+
+    SDL_LockMutex(SDL_RAWINPUT_mutex);
+
+    if (SDL_RAWINPUT_inited) {
+        switch (msg) {
+            case WM_INPUT_DEVICE_CHANGE:
+            {
+                HANDLE hDevice = (HANDLE)lParam;
+                switch (wParam) {
+                case GIDC_ARRIVAL:
+                    RAWINPUT_AddDevice(hDevice);
+                    break;
+                case GIDC_REMOVAL:
+                {
+                    SDL_RAWINPUT_Device *device;
+                    device = RAWINPUT_DeviceFromHandle(hDevice);
+                    if (device) {
+                        RAWINPUT_DelDevice(device, SDL_TRUE);
+                    }
+                    break;
+                }
+                default:
+                    break;
                 }
-            } break;
-            default:
-                return 0;
             }
-        }
-        return 0;
-
-        case WM_INPUT:
-        {
-            Uint8 data[sizeof(RAWINPUTHEADER) + sizeof(RAWHID) + USB_PACKET_LENGTH];
-            UINT buffer_size = SDL_arraysize(data);
-
-            if ((int)GetRawInputData((HRAWINPUT)lParam, RID_INPUT, data, &buffer_size, sizeof(RAWINPUTHEADER)) > 0) {
-                PRAWINPUT raw_input = (PRAWINPUT)data;
-                SDL_RAWINPUT_Device *device = RAWINPUT_DeviceFromHandle(raw_input->header.hDevice);
-                if (device) {
-                    SDL_Joystick *joystick = device->joystick;
-                    if (joystick) {
-                        RAWINPUT_HandleStatePacket(joystick, raw_input->data.hid.bRawData, raw_input->data.hid.dwSizeHid);
+            result = 0;
+            break;
+
+            case WM_INPUT:
+            {
+                Uint8 data[sizeof(RAWINPUTHEADER) + sizeof(RAWHID) + USB_PACKET_LENGTH];
+                UINT buffer_size = SDL_arraysize(data);
+
+                if ((int)GetRawInputData((HRAWINPUT)lParam, RID_INPUT, data, &buffer_size, sizeof(RAWINPUTHEADER)) > 0) {
+                    PRAWINPUT raw_input = (PRAWINPUT)data;
+                    SDL_RAWINPUT_Device *device = RAWINPUT_DeviceFromHandle(raw_input->header.hDevice);
+                    if (device) {
+                        SDL_Joystick *joystick = device->joystick;
+                        if (joystick) {
+                            RAWINPUT_HandleStatePacket(joystick, raw_input->data.hid.bRawData, raw_input->data.hid.dwSizeHid);
+                        }
                     }
                 }
             }
+            result = 0;
+            break;
         }
-        return 0;
     }
-    return -1;
+
+    SDL_UnlockMutex(SDL_RAWINPUT_mutex);
+
+    if (result >= 0) {
+        return result;
+    }
+    return CallWindowProc(DefWindowProc, hWnd, msg, wParam, lParam);
 }
 
 static void
 RAWINPUT_JoystickQuit(void)
 {
-    int ii;
-    RAWINPUTDEVICE rid[SDL_arraysize(subscribed_devices)];
-    
-    if (!SDL_RAWINPUT_inited)
+    if (!SDL_RAWINPUT_inited) {
         return;
-
-    for (ii = 0; ii < SDL_arraysize(subscribed_devices); ii++) {
-        rid[ii].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
-        rid[ii].usUsage = subscribed_devices[ii];
-        rid[ii].dwFlags = RIDEV_REMOVE;
-        rid[ii].hwndTarget = NULL;
     }
 
-    if (!RegisterRawInputDevices(rid, SDL_arraysize(rid), sizeof(RAWINPUTDEVICE))) {
-        SDL_Log("Couldn't un-register RAWINPUT");
-    }
-    
+    SDL_LockMutex(SDL_RAWINPUT_mutex);
+
     while (SDL_RAWINPUT_devices) {
         RAWINPUT_DelDevice(SDL_RAWINPUT_devices, SDL_FALSE);
     }
@@ -1853,6 +1838,11 @@ RAWINPUT_JoystickQuit(void)
     SDL_RAWINPUT_numjoysticks = 0;
 
     SDL_RAWINPUT_inited = SDL_FALSE;
+
+    SDL_UnlockMutex(SDL_RAWINPUT_mutex);
+    SDL_DestroyMutex(SDL_RAWINPUT_mutex);
+    SDL_RAWINPUT_mutex = NULL;
+
 }
 
 static SDL_bool

+ 5 - 1
src/joystick/windows/SDL_rawinputjoystick_c.h

@@ -27,8 +27,12 @@ extern SDL_bool RAWINPUT_IsEnabled();
 /* Return true if a RawInput device is present and supported as a joystick */
 extern SDL_bool RAWINPUT_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name);
 
+/* Registers for input events */
+extern SDL_bool RAWINPUT_RegisterNotifications(HWND hWnd);
+extern void RAWINPUT_UnregisterNotifications();
+
 /* Returns 0 if message was handled */
-extern LRESULT RAWINPUT_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+extern LRESULT CALLBACK RAWINPUT_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
 
 
 /* vi: set ts=4 sw=4 expandtab: */

+ 16 - 3
src/joystick/windows/SDL_windowsjoystick.c

@@ -49,6 +49,7 @@
 #include "SDL_windowsjoystick_c.h"
 #include "SDL_dinputjoystick_c.h"
 #include "SDL_xinputjoystick_c.h"
+#include "SDL_rawinputjoystick_c.h"
 
 #include "../../haptic/windows/SDL_dinputhaptic_c.h"    /* For haptic hot plugging */
 #include "../../haptic/windows/SDL_xinputhaptic_c.h"    /* For haptic hot plugging */
@@ -109,9 +110,9 @@ typedef struct
 
 /* windowproc for our joystick detect thread message only window, to detect any USB device addition/removal */
 static LRESULT CALLBACK
-SDL_PrivateJoystickDetectProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+SDL_PrivateJoystickDetectProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
-    switch (message) {
+    switch (msg) {
     case WM_DEVICECHANGE:
         switch (wParam) {
         case DBT_DEVICEARRIVAL:
@@ -130,12 +131,20 @@ SDL_PrivateJoystickDetectProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
         return 0;
     }
 
-    return DefWindowProc (hwnd, message, wParam, lParam);
+#if SDL_JOYSTICK_RAWINPUT
+    return CallWindowProc(RAWINPUT_WindowProc, hwnd, msg, wParam, lParam);
+#else
+    return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
+#endif
 }
 
 static void
 SDL_CleanupDeviceNotification(SDL_DeviceNotificationData *data)
 {
+#if SDL_JOYSTICK_RAWINPUT
+    RAWINPUT_UnregisterNotifications();
+#endif
+
     if (data->hNotify)
         UnregisterDeviceNotification(data->hNotify);
 
@@ -188,6 +197,10 @@ SDL_CreateDeviceNotification(SDL_DeviceNotificationData *data)
         SDL_CleanupDeviceNotification(data);
         return -1;
     }
+
+#if SDL_JOYSTICK_RAWINPUT
+    RAWINPUT_RegisterNotifications(data->messageWindow);
+#endif
     return 0;
 }
 

+ 2 - 13
src/video/windows/SDL_windowswindow.c

@@ -30,7 +30,6 @@
 #include "../../events/SDL_keyboard_c.h"
 #include "../../events/SDL_mouse_c.h"
 
-#include "../../joystick/windows/SDL_rawinputjoystick_c.h"
 #include "SDL_windowsvideo.h"
 #include "SDL_windowswindow.h"
 #include "SDL_hints.h"
@@ -811,18 +810,8 @@ WIN_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
     }
 }
 
-static LRESULT CALLBACK SDL_HelperWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
-#if SDL_JOYSTICK_RAWINPUT
-    if (RAWINPUT_WindowProc(hWnd, msg, wParam, lParam) == 0) {
-        return 0;
-    }
-#endif
-    return DefWindowProc(hWnd, msg, wParam, lParam);
-}
-
 /*
- * Creates a HelperWindow used for DirectInput and RawInput events.
+ * Creates a HelperWindow used for DirectInput.
  */
 int
 SDL_HelperWindowCreate(void)
@@ -837,7 +826,7 @@ SDL_HelperWindowCreate(void)
 
     /* Create the class. */
     SDL_zero(wce);
-    wce.lpfnWndProc = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_RAWINPUT, SDL_TRUE) ? SDL_HelperWindowProc : DefWindowProc;
+    wce.lpfnWndProc = DefWindowProc;
     wce.lpszClassName = (LPCWSTR) SDL_HelperWindowClassName;
     wce.hInstance = hInstance;