Skip to content

Commit

Permalink
keep joystick thread from waking unnecessarily, and from possibly blo…
Browse files Browse the repository at this point in the history
…cking for 300ms at shutdown if a joystick was just plugged in

CR: SamL
  • Loading branch information
slouken committed Sep 8, 2017
1 parent cedbb31 commit 0ddac33
Showing 1 changed file with 43 additions and 31 deletions.
74 changes: 43 additions & 31 deletions src/joystick/windows/SDL_windowsjoystick.c
Expand Up @@ -89,9 +89,10 @@ SDL_CreateDeviceNotification(SDL_DeviceNotificationData *data)
return 0;
}

static void
SDL_CheckDeviceNotification(SDL_DeviceNotificationData *data)
static SDL_bool
SDL_WaitForDeviceNotification(SDL_DeviceNotificationData *data, SDL_mutex *mutex)
{
return SDL_FALSE;
}

#else /* !__WINRT__ */
Expand All @@ -104,6 +105,8 @@ typedef struct
HDEVNOTIFY hNotify;
} 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 */
static LRESULT CALLBACK
Expand All @@ -113,17 +116,19 @@ SDL_PrivateJoystickDetectProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
case WM_DEVICECHANGE:
switch (wParam) {
case DBT_DEVICEARRIVAL:
if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
s_bWindowsDeviceChanged = SDL_TRUE;
}
break;
case DBT_DEVICEREMOVECOMPLETE:
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;
}
return 0;
case WM_TIMER:
KillTimer(hwnd, wParam);
s_bWindowsDeviceChanged = SDL_TRUE;
return 0;
}

return DefWindowProc (hwnd, message, wParam, lParam);
Expand Down Expand Up @@ -187,21 +192,26 @@ SDL_CreateDeviceNotification(SDL_DeviceNotificationData *data)
return 0;
}

static void
SDL_CheckDeviceNotification(SDL_DeviceNotificationData *data)
static SDL_bool
SDL_WaitForDeviceNotification(SDL_DeviceNotificationData *data, SDL_mutex *mutex)
{
MSG msg;
int lastret = 1;

if (!data->messageWindow) {
return;
return SDL_FALSE; /* device notifications require a window */
}

while (PeekMessage(&msg, data->messageWindow, 0, 0, PM_NOREMOVE)) {
if (GetMessage(&msg, data->messageWindow, 0, 0) != 0) {
SDL_UnlockMutex(mutex);
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);
DispatchMessage(&msg);
}
}
SDL_LockMutex(mutex);
return (lastret != -1) ? SDL_TRUE : SDL_FALSE;
}

#endif /* __WINRT__ */
Expand All @@ -225,31 +235,30 @@ SDL_JoystickThread(void *_data)
while (s_bJoystickThreadQuit == SDL_FALSE) {
SDL_bool bXInputChanged = SDL_FALSE;

SDL_CondWaitTimeout(s_condJoystickThread, s_mutexJoyStickEnum, 300);

SDL_CheckDeviceNotification(&notification_data);

if (SDL_WaitForDeviceNotification(&notification_data, s_mutexJoyStickEnum) == SDL_FALSE) {
#if SDL_JOYSTICK_XINPUT
if (SDL_XINPUT_Enabled() && XINPUTGETCAPABILITIES) {
/* scan for any change in XInput devices */
Uint8 userId;
for (userId = 0; userId < XUSER_MAX_COUNT; userId++) {
XINPUT_CAPABILITIES capabilities;
const DWORD result = XINPUTGETCAPABILITIES(userId, XINPUT_FLAG_GAMEPAD, &capabilities);
const SDL_bool available = (result == ERROR_SUCCESS);
if (bOpenedXInputDevices[userId] != available) {
bXInputChanged = SDL_TRUE;
bOpenedXInputDevices[userId] = available;
/* WM_DEVICECHANGE not working, poll for new XINPUT controllers */
SDL_CondWaitTimeout(s_condJoystickThread, s_mutexJoyStickEnum, 1000);
if (SDL_XINPUT_Enabled() && XINPUTGETCAPABILITIES) {
/* scan for any change in XInput devices */
Uint8 userId;
for (userId = 0; userId < XUSER_MAX_COUNT; userId++) {
XINPUT_CAPABILITIES capabilities;
const DWORD result = XINPUTGETCAPABILITIES(userId, XINPUT_FLAG_GAMEPAD, &capabilities);
const SDL_bool available = (result == ERROR_SUCCESS);
if (bOpenedXInputDevices[userId] != available) {
bXInputChanged = SDL_TRUE;
bOpenedXInputDevices[userId] = available;
}
}
}
}
#else
/* WM_DEVICECHANGE not working, no XINPUT, no point in keeping thread alive */
break;
#endif /* SDL_JOYSTICK_XINPUT */
}

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_bDeviceAdded = SDL_TRUE;
s_bWindowsDeviceChanged = SDL_FALSE;
Expand Down Expand Up @@ -496,6 +505,9 @@ SDL_SYS_JoystickQuit(void)
s_bJoystickThreadQuit = SDL_TRUE;
SDL_CondBroadcast(s_condJoystickThread); /* signal the joystick thread to quit */
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_DestroyMutex(s_mutexJoyStickEnum);
Expand Down

0 comments on commit 0ddac33

Please sign in to comment.