keep joystick thread from waking unnecessarily, and from possibly blocking for 300ms at shutdown if a joystick was just plugged in
CR: SamL
1.1 --- a/src/joystick/windows/SDL_windowsjoystick.c Fri Sep 08 15:08:50 2017 -0700
1.2 +++ b/src/joystick/windows/SDL_windowsjoystick.c Fri Sep 08 07:15:47 2017 -0700
1.3 @@ -89,9 +89,10 @@
1.4 return 0;
1.5 }
1.6
1.7 -static void
1.8 -SDL_CheckDeviceNotification(SDL_DeviceNotificationData *data)
1.9 +static SDL_bool
1.10 +SDL_WaitForDeviceNotification(SDL_DeviceNotificationData *data, SDL_mutex *mutex)
1.11 {
1.12 + return SDL_FALSE;
1.13 }
1.14
1.15 #else /* !__WINRT__ */
1.16 @@ -104,6 +105,8 @@
1.17 HDEVNOTIFY hNotify;
1.18 } SDL_DeviceNotificationData;
1.19
1.20 +#define IDT_SDL_DEVICE_CHANGE_TIMER_1 1200
1.21 +#define IDT_SDL_DEVICE_CHANGE_TIMER_2 1201
1.22
1.23 /* windowproc for our joystick detect thread message only window, to detect any USB device addition/removal */
1.24 static LRESULT CALLBACK
1.25 @@ -113,17 +116,19 @@
1.26 case WM_DEVICECHANGE:
1.27 switch (wParam) {
1.28 case DBT_DEVICEARRIVAL:
1.29 - if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
1.30 - s_bWindowsDeviceChanged = SDL_TRUE;
1.31 - }
1.32 - break;
1.33 case DBT_DEVICEREMOVECOMPLETE:
1.34 if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
1.35 - s_bWindowsDeviceChanged = SDL_TRUE;
1.36 + /* notify 300ms and 2 seconds later to ensure all APIs have updated status */
1.37 + SetTimer(hwnd, IDT_SDL_DEVICE_CHANGE_TIMER_1, 300, NULL);
1.38 + SetTimer(hwnd, IDT_SDL_DEVICE_CHANGE_TIMER_2, 2000, NULL);
1.39 }
1.40 break;
1.41 }
1.42 return 0;
1.43 + case WM_TIMER:
1.44 + KillTimer(hwnd, wParam);
1.45 + s_bWindowsDeviceChanged = SDL_TRUE;
1.46 + return 0;
1.47 }
1.48
1.49 return DefWindowProc (hwnd, message, wParam, lParam);
1.50 @@ -187,21 +192,26 @@
1.51 return 0;
1.52 }
1.53
1.54 -static void
1.55 -SDL_CheckDeviceNotification(SDL_DeviceNotificationData *data)
1.56 +static SDL_bool
1.57 +SDL_WaitForDeviceNotification(SDL_DeviceNotificationData *data, SDL_mutex *mutex)
1.58 {
1.59 MSG msg;
1.60 + int lastret = 1;
1.61
1.62 if (!data->messageWindow) {
1.63 - return;
1.64 + return SDL_FALSE; /* device notifications require a window */
1.65 }
1.66
1.67 - while (PeekMessage(&msg, data->messageWindow, 0, 0, PM_NOREMOVE)) {
1.68 - if (GetMessage(&msg, data->messageWindow, 0, 0) != 0) {
1.69 + SDL_UnlockMutex(mutex);
1.70 + while (lastret > 0 && s_bWindowsDeviceChanged == SDL_FALSE) {
1.71 + lastret = GetMessage(&msg, NULL, 0, 0); /* WM_QUIT causes return value of 0 */
1.72 + if (lastret > 0) {
1.73 TranslateMessage(&msg);
1.74 DispatchMessage(&msg);
1.75 }
1.76 }
1.77 + SDL_LockMutex(mutex);
1.78 + return (lastret != -1) ? SDL_TRUE : SDL_FALSE;
1.79 }
1.80
1.81 #endif /* __WINRT__ */
1.82 @@ -225,31 +235,30 @@
1.83 while (s_bJoystickThreadQuit == SDL_FALSE) {
1.84 SDL_bool bXInputChanged = SDL_FALSE;
1.85
1.86 - SDL_CondWaitTimeout(s_condJoystickThread, s_mutexJoyStickEnum, 300);
1.87 -
1.88 - SDL_CheckDeviceNotification(¬ification_data);
1.89 -
1.90 + if (SDL_WaitForDeviceNotification(¬ification_data, s_mutexJoyStickEnum) == SDL_FALSE) {
1.91 #if SDL_JOYSTICK_XINPUT
1.92 - if (SDL_XINPUT_Enabled() && XINPUTGETCAPABILITIES) {
1.93 - /* scan for any change in XInput devices */
1.94 - Uint8 userId;
1.95 - for (userId = 0; userId < XUSER_MAX_COUNT; userId++) {
1.96 - XINPUT_CAPABILITIES capabilities;
1.97 - const DWORD result = XINPUTGETCAPABILITIES(userId, XINPUT_FLAG_GAMEPAD, &capabilities);
1.98 - const SDL_bool available = (result == ERROR_SUCCESS);
1.99 - if (bOpenedXInputDevices[userId] != available) {
1.100 - bXInputChanged = SDL_TRUE;
1.101 - bOpenedXInputDevices[userId] = available;
1.102 + /* WM_DEVICECHANGE not working, poll for new XINPUT controllers */
1.103 + SDL_CondWaitTimeout(s_condJoystickThread, s_mutexJoyStickEnum, 1000);
1.104 + if (SDL_XINPUT_Enabled() && XINPUTGETCAPABILITIES) {
1.105 + /* scan for any change in XInput devices */
1.106 + Uint8 userId;
1.107 + for (userId = 0; userId < XUSER_MAX_COUNT; userId++) {
1.108 + XINPUT_CAPABILITIES capabilities;
1.109 + const DWORD result = XINPUTGETCAPABILITIES(userId, XINPUT_FLAG_GAMEPAD, &capabilities);
1.110 + const SDL_bool available = (result == ERROR_SUCCESS);
1.111 + if (bOpenedXInputDevices[userId] != available) {
1.112 + bXInputChanged = SDL_TRUE;
1.113 + bOpenedXInputDevices[userId] = available;
1.114 + }
1.115 }
1.116 }
1.117 - }
1.118 +#else
1.119 + /* WM_DEVICECHANGE not working, no XINPUT, no point in keeping thread alive */
1.120 + break;
1.121 #endif /* SDL_JOYSTICK_XINPUT */
1.122 + }
1.123
1.124 if (s_bWindowsDeviceChanged || bXInputChanged) {
1.125 - SDL_UnlockMutex(s_mutexJoyStickEnum); /* let main thread go while we SDL_Delay(). */
1.126 - SDL_Delay(300); /* wait for direct input to find out about this device */
1.127 - SDL_LockMutex(s_mutexJoyStickEnum);
1.128 -
1.129 s_bDeviceRemoved = SDL_TRUE;
1.130 s_bDeviceAdded = SDL_TRUE;
1.131 s_bWindowsDeviceChanged = SDL_FALSE;
1.132 @@ -496,6 +505,9 @@
1.133 s_bJoystickThreadQuit = SDL_TRUE;
1.134 SDL_CondBroadcast(s_condJoystickThread); /* signal the joystick thread to quit */
1.135 SDL_UnlockMutex(s_mutexJoyStickEnum);
1.136 +#ifndef __WINRT__
1.137 + PostThreadMessage(SDL_GetThreadID(s_threadJoystick), WM_QUIT, 0, 0);
1.138 +#endif
1.139 SDL_WaitThread(s_threadJoystick, NULL); /* wait for it to bugger off */
1.140
1.141 SDL_DestroyMutex(s_mutexJoyStickEnum);