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 2020-11-27 13:08:40 -08:00
parent 4fbefbe20d
commit a0c5bfa3bd
6 changed files with 125 additions and 127 deletions

View File

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

View File

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

View File

@ -37,6 +37,7 @@
#include "SDL_endian.h" #include "SDL_endian.h"
#include "SDL_events.h" #include "SDL_events.h"
#include "SDL_hints.h" #include "SDL_hints.h"
#include "SDL_mutex.h"
#include "SDL_timer.h" #include "SDL_timer.h"
#include "../usb_ids.h" #include "../usb_ids.h"
#include "../SDL_sysjoystick.h" #include "../SDL_sysjoystick.h"
@ -84,12 +85,10 @@ typedef struct WindowsGamingInputGamepadState WindowsGamingInputGamepadState;
#define GIDC_REMOVAL 2 #define GIDC_REMOVAL 2
#endif #endif
/* external variables referenced. */
extern HWND SDL_HelperWindow;
static SDL_bool SDL_RAWINPUT_inited = SDL_FALSE; static SDL_bool SDL_RAWINPUT_inited = SDL_FALSE;
static int SDL_RAWINPUT_numjoysticks = 0; static int SDL_RAWINPUT_numjoysticks = 0;
static SDL_mutex *SDL_RAWINPUT_mutex = NULL;
static void RAWINPUT_JoystickClose(SDL_Joystick *joystick); static void RAWINPUT_JoystickClose(SDL_Joystick *joystick);
@ -625,40 +624,10 @@ RAWINPUT_QuitWindowsGamingInput(RAWINPUT_DeviceContext *ctx)
#endif /* SDL_JOYSTICK_RAWINPUT_WGI */ #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 static int
RAWINPUT_JoystickInit(void) RAWINPUT_JoystickInit(void)
{ {
int ii;
RAWINPUTDEVICE rid[SDL_arraysize(subscribed_devices)];
SDL_assert(!SDL_RAWINPUT_inited); SDL_assert(!SDL_RAWINPUT_inited);
SDL_assert(SDL_HelperWindow);
if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_RAWINPUT, SDL_TRUE)) { if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_RAWINPUT, SDL_TRUE)) {
return -1; return -1;
@ -668,25 +637,9 @@ RAWINPUT_JoystickInit(void)
return -1; return -1;
} }
for (ii = 0; ii < SDL_arraysize(subscribed_devices); ii++) { SDL_RAWINPUT_mutex = SDL_CreateMutex();
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_inited = SDL_TRUE; SDL_RAWINPUT_inited = SDL_TRUE;
/* Get initial controller connect messages */
RAWINPUT_GetPendingDeviceChanges();
pump_device_events = SDL_TRUE;
return 0; return 0;
} }
@ -930,8 +883,6 @@ RAWINPUT_PostUpdate(void)
guide_button_candidate.joystick = NULL; guide_button_candidate.joystick = NULL;
#endif /* SDL_JOYSTICK_RAWINPUT_MATCHING */ #endif /* SDL_JOYSTICK_RAWINPUT_MATCHING */
pump_device_events = SDL_TRUE;
} }
SDL_bool SDL_bool
@ -945,9 +896,6 @@ RAWINPUT_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, co
{ {
SDL_RAWINPUT_Device *device; 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 */ /* If we're being asked about a device, that means another API just detected one, so rescan */
#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
xinput_device_change = SDL_TRUE; xinput_device_change = SDL_TRUE;
@ -983,8 +931,6 @@ RAWINPUT_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, co
static void static void
RAWINPUT_JoystickDetect(void) RAWINPUT_JoystickDetect(void)
{ {
RAWINPUT_GetPendingDeviceChanges();
RAWINPUT_PostUpdate(); RAWINPUT_PostUpdate();
} }
@ -1727,8 +1673,6 @@ RAWINPUT_UpdateOtherAPIs(SDL_Joystick *joystick)
static void static void
RAWINPUT_JoystickUpdate(SDL_Joystick *joystick) RAWINPUT_JoystickUpdate(SDL_Joystick *joystick)
{ {
RAWINPUT_GetPendingDeviceInput();
RAWINPUT_UpdateOtherAPIs(joystick); RAWINPUT_UpdateOtherAPIs(joystick);
} }
@ -1776,13 +1720,54 @@ 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) RAWINPUTDEVICE rid[SDL_arraysize(subscribed_devices)];
return -1; int i;
switch (msg) 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: case WM_INPUT_DEVICE_CHANGE:
{ {
HANDLE hDevice = (HANDLE)lParam; HANDLE hDevice = (HANDLE)lParam;
@ -1790,18 +1775,21 @@ LRESULT RAWINPUT_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
case GIDC_ARRIVAL: case GIDC_ARRIVAL:
RAWINPUT_AddDevice(hDevice); RAWINPUT_AddDevice(hDevice);
break; break;
case GIDC_REMOVAL: { case GIDC_REMOVAL:
{
SDL_RAWINPUT_Device *device; SDL_RAWINPUT_Device *device;
device = RAWINPUT_DeviceFromHandle(hDevice); device = RAWINPUT_DeviceFromHandle(hDevice);
if (device) { if (device) {
RAWINPUT_DelDevice(device, SDL_TRUE); RAWINPUT_DelDevice(device, SDL_TRUE);
} }
} break; break;
}
default: default:
return 0; break;
} }
} }
return 0; result = 0;
break;
case WM_INPUT: case WM_INPUT:
{ {
@ -1819,30 +1807,27 @@ LRESULT RAWINPUT_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
} }
} }
} }
return 0; result = 0;
break;
} }
return -1; }
SDL_UnlockMutex(SDL_RAWINPUT_mutex);
if (result >= 0) {
return result;
}
return CallWindowProc(DefWindowProc, hWnd, msg, wParam, lParam);
} }
static void static void
RAWINPUT_JoystickQuit(void) RAWINPUT_JoystickQuit(void)
{ {
int ii; if (!SDL_RAWINPUT_inited) {
RAWINPUTDEVICE rid[SDL_arraysize(subscribed_devices)];
if (!SDL_RAWINPUT_inited)
return; 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_LockMutex(SDL_RAWINPUT_mutex);
SDL_Log("Couldn't un-register RAWINPUT");
}
while (SDL_RAWINPUT_devices) { while (SDL_RAWINPUT_devices) {
RAWINPUT_DelDevice(SDL_RAWINPUT_devices, SDL_FALSE); RAWINPUT_DelDevice(SDL_RAWINPUT_devices, SDL_FALSE);
@ -1853,6 +1838,11 @@ RAWINPUT_JoystickQuit(void)
SDL_RAWINPUT_numjoysticks = 0; SDL_RAWINPUT_numjoysticks = 0;
SDL_RAWINPUT_inited = SDL_FALSE; SDL_RAWINPUT_inited = SDL_FALSE;
SDL_UnlockMutex(SDL_RAWINPUT_mutex);
SDL_DestroyMutex(SDL_RAWINPUT_mutex);
SDL_RAWINPUT_mutex = NULL;
} }
static SDL_bool static SDL_bool

View File

@ -27,8 +27,12 @@ extern SDL_bool RAWINPUT_IsEnabled();
/* Return true if a RawInput device is present and supported as a joystick */ /* 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); 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 */ /* 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: */ /* vi: set ts=4 sw=4 expandtab: */

View File

@ -49,6 +49,7 @@
#include "SDL_windowsjoystick_c.h" #include "SDL_windowsjoystick_c.h"
#include "SDL_dinputjoystick_c.h" #include "SDL_dinputjoystick_c.h"
#include "SDL_xinputjoystick_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_dinputhaptic_c.h" /* For haptic hot plugging */
#include "../../haptic/windows/SDL_xinputhaptic_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 */ /* windowproc for our joystick detect thread message only window, to detect any USB device addition/removal */
static LRESULT CALLBACK 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: case WM_DEVICECHANGE:
switch (wParam) { switch (wParam) {
case DBT_DEVICEARRIVAL: case DBT_DEVICEARRIVAL:
@ -130,12 +131,20 @@ SDL_PrivateJoystickDetectProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
return 0; 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 static void
SDL_CleanupDeviceNotification(SDL_DeviceNotificationData *data) SDL_CleanupDeviceNotification(SDL_DeviceNotificationData *data)
{ {
#if SDL_JOYSTICK_RAWINPUT
RAWINPUT_UnregisterNotifications();
#endif
if (data->hNotify) if (data->hNotify)
UnregisterDeviceNotification(data->hNotify); UnregisterDeviceNotification(data->hNotify);
@ -188,6 +197,10 @@ SDL_CreateDeviceNotification(SDL_DeviceNotificationData *data)
SDL_CleanupDeviceNotification(data); SDL_CleanupDeviceNotification(data);
return -1; return -1;
} }
#if SDL_JOYSTICK_RAWINPUT
RAWINPUT_RegisterNotifications(data->messageWindow);
#endif
return 0; return 0;
} }

View File

@ -30,7 +30,6 @@
#include "../../events/SDL_keyboard_c.h" #include "../../events/SDL_keyboard_c.h"
#include "../../events/SDL_mouse_c.h" #include "../../events/SDL_mouse_c.h"
#include "../../joystick/windows/SDL_rawinputjoystick_c.h"
#include "SDL_windowsvideo.h" #include "SDL_windowsvideo.h"
#include "SDL_windowswindow.h" #include "SDL_windowswindow.h"
#include "SDL_hints.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 int
SDL_HelperWindowCreate(void) SDL_HelperWindowCreate(void)
@ -837,7 +826,7 @@ SDL_HelperWindowCreate(void)
/* Create the class. */ /* Create the class. */
SDL_zero(wce); 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.lpszClassName = (LPCWSTR) SDL_HelperWindowClassName;
wce.hInstance = hInstance; wce.hInstance = hInstance;