keep joystick thread from waking unnecessarily, and from possibly blocking for 300ms at shutdown if a joystick was just plugged in

CR: SamL
This commit is contained in:
Sam Lantinga 2017-09-08 07:15:47 -07:00
parent cedbb3118c
commit 0ddac338b0

View file

@ -89,9 +89,10 @@ SDL_CreateDeviceNotification(SDL_DeviceNotificationData *data)
return 0; return 0;
} }
static void static SDL_bool
SDL_CheckDeviceNotification(SDL_DeviceNotificationData *data) SDL_WaitForDeviceNotification(SDL_DeviceNotificationData *data, SDL_mutex *mutex)
{ {
return SDL_FALSE;
} }
#else /* !__WINRT__ */ #else /* !__WINRT__ */
@ -104,6 +105,8 @@ typedef struct
HDEVNOTIFY hNotify; HDEVNOTIFY hNotify;
} SDL_DeviceNotificationData; } SDL_DeviceNotificationData;
#define IDT_SDL_DEVICE_CHANGE_TIMER_1 1200
#define IDT_SDL_DEVICE_CHANGE_TIMER_2 1201
/* 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
@ -113,17 +116,19 @@ SDL_PrivateJoystickDetectProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
case WM_DEVICECHANGE: case WM_DEVICECHANGE:
switch (wParam) { switch (wParam) {
case DBT_DEVICEARRIVAL: case DBT_DEVICEARRIVAL:
if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
s_bWindowsDeviceChanged = SDL_TRUE;
}
break;
case DBT_DEVICEREMOVECOMPLETE: case DBT_DEVICEREMOVECOMPLETE:
if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) { if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
s_bWindowsDeviceChanged = SDL_TRUE; /* notify 300ms and 2 seconds later to ensure all APIs have updated status */
SetTimer(hwnd, IDT_SDL_DEVICE_CHANGE_TIMER_1, 300, NULL);
SetTimer(hwnd, IDT_SDL_DEVICE_CHANGE_TIMER_2, 2000, NULL);
} }
break; break;
} }
return 0; return 0;
case WM_TIMER:
KillTimer(hwnd, wParam);
s_bWindowsDeviceChanged = SDL_TRUE;
return 0;
} }
return DefWindowProc (hwnd, message, wParam, lParam); return DefWindowProc (hwnd, message, wParam, lParam);
@ -187,21 +192,26 @@ SDL_CreateDeviceNotification(SDL_DeviceNotificationData *data)
return 0; return 0;
} }
static void static SDL_bool
SDL_CheckDeviceNotification(SDL_DeviceNotificationData *data) SDL_WaitForDeviceNotification(SDL_DeviceNotificationData *data, SDL_mutex *mutex)
{ {
MSG msg; MSG msg;
int lastret = 1;
if (!data->messageWindow) { if (!data->messageWindow) {
return; return SDL_FALSE; /* device notifications require a window */
} }
while (PeekMessage(&msg, data->messageWindow, 0, 0, PM_NOREMOVE)) { SDL_UnlockMutex(mutex);
if (GetMessage(&msg, data->messageWindow, 0, 0) != 0) { while (lastret > 0 && s_bWindowsDeviceChanged == SDL_FALSE) {
lastret = GetMessage(&msg, NULL, 0, 0); /* WM_QUIT causes return value of 0 */
if (lastret > 0) {
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessage(&msg);
} }
} }
SDL_LockMutex(mutex);
return (lastret != -1) ? SDL_TRUE : SDL_FALSE;
} }
#endif /* __WINRT__ */ #endif /* __WINRT__ */
@ -225,11 +235,10 @@ SDL_JoystickThread(void *_data)
while (s_bJoystickThreadQuit == SDL_FALSE) { while (s_bJoystickThreadQuit == SDL_FALSE) {
SDL_bool bXInputChanged = SDL_FALSE; SDL_bool bXInputChanged = SDL_FALSE;
SDL_CondWaitTimeout(s_condJoystickThread, s_mutexJoyStickEnum, 300); if (SDL_WaitForDeviceNotification(&notification_data, s_mutexJoyStickEnum) == SDL_FALSE) {
SDL_CheckDeviceNotification(&notification_data);
#if SDL_JOYSTICK_XINPUT #if SDL_JOYSTICK_XINPUT
/* WM_DEVICECHANGE not working, poll for new XINPUT controllers */
SDL_CondWaitTimeout(s_condJoystickThread, s_mutexJoyStickEnum, 1000);
if (SDL_XINPUT_Enabled() && XINPUTGETCAPABILITIES) { if (SDL_XINPUT_Enabled() && XINPUTGETCAPABILITIES) {
/* scan for any change in XInput devices */ /* scan for any change in XInput devices */
Uint8 userId; Uint8 userId;
@ -243,13 +252,13 @@ SDL_JoystickThread(void *_data)
} }
} }
} }
#else
/* WM_DEVICECHANGE not working, no XINPUT, no point in keeping thread alive */
break;
#endif /* SDL_JOYSTICK_XINPUT */ #endif /* SDL_JOYSTICK_XINPUT */
}
if (s_bWindowsDeviceChanged || bXInputChanged) { if (s_bWindowsDeviceChanged || bXInputChanged) {
SDL_UnlockMutex(s_mutexJoyStickEnum); /* let main thread go while we SDL_Delay(). */
SDL_Delay(300); /* wait for direct input to find out about this device */
SDL_LockMutex(s_mutexJoyStickEnum);
s_bDeviceRemoved = SDL_TRUE; s_bDeviceRemoved = SDL_TRUE;
s_bDeviceAdded = SDL_TRUE; s_bDeviceAdded = SDL_TRUE;
s_bWindowsDeviceChanged = SDL_FALSE; s_bWindowsDeviceChanged = SDL_FALSE;
@ -496,6 +505,9 @@ SDL_SYS_JoystickQuit(void)
s_bJoystickThreadQuit = SDL_TRUE; s_bJoystickThreadQuit = SDL_TRUE;
SDL_CondBroadcast(s_condJoystickThread); /* signal the joystick thread to quit */ SDL_CondBroadcast(s_condJoystickThread); /* signal the joystick thread to quit */
SDL_UnlockMutex(s_mutexJoyStickEnum); SDL_UnlockMutex(s_mutexJoyStickEnum);
#ifndef __WINRT__
PostThreadMessage(SDL_GetThreadID(s_threadJoystick), WM_QUIT, 0, 0);
#endif
SDL_WaitThread(s_threadJoystick, NULL); /* wait for it to bugger off */ SDL_WaitThread(s_threadJoystick, NULL); /* wait for it to bugger off */
SDL_DestroyMutex(s_mutexJoyStickEnum); SDL_DestroyMutex(s_mutexJoyStickEnum);