| | |
| | | * let it return 0 events. */ |
| | | |
| | | #include "SDL_error.h" |
| | | #include "SDL_assert.h" |
| | | #include "SDL_events.h" |
| | | #include "SDL_hints.h" |
| | | #include "SDL_timer.h" |
| | | #include "SDL_mutex.h" |
| | | #include "SDL_joystick.h" |
| | |
| | | #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 */ |
| | |
| | | #endif |
| | | |
| | | /* local variables */ |
| | | static SDL_bool s_bDeviceAdded = SDL_FALSE; |
| | | static SDL_bool s_bDeviceRemoved = SDL_FALSE; |
| | | static SDL_bool s_bJoystickThread = SDL_FALSE; |
| | | static SDL_bool s_bWindowsDeviceChanged = SDL_FALSE; |
| | | static SDL_cond *s_condJoystickThread = NULL; |
| | | static SDL_mutex *s_mutexJoyStickEnum = NULL; |
| | | static SDL_Thread *s_threadJoystick = NULL; |
| | | static SDL_Thread *s_joystickThread = NULL; |
| | | static SDL_bool s_bJoystickThreadQuit = SDL_FALSE; |
| | | |
| | | JoyStick_DeviceData *SYS_Joystick; /* array to hold joystick ID values */ |
| | | |
| | | static SDL_bool s_bWindowsDeviceChanged = SDL_FALSE; |
| | | |
| | | #ifdef __WINRT__ |
| | | |
| | |
| | | |
| | | /* 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: |
| | |
| | | } |
| | | return 0; |
| | | case WM_TIMER: |
| | | KillTimer(hwnd, wParam); |
| | | s_bWindowsDeviceChanged = SDL_TRUE; |
| | | return 0; |
| | | if (wParam == IDT_SDL_DEVICE_CHANGE_TIMER_1 || |
| | | wParam == IDT_SDL_DEVICE_CHANGE_TIMER_2) { |
| | | KillTimer(hwnd, wParam); |
| | | s_bWindowsDeviceChanged = SDL_TRUE; |
| | | return 0; |
| | | } |
| | | break; |
| | | } |
| | | |
| | | 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); |
| | | |
| | |
| | | SDL_CleanupDeviceNotification(data); |
| | | return -1; |
| | | } |
| | | |
| | | #if SDL_JOYSTICK_RAWINPUT |
| | | RAWINPUT_RegisterNotifications(data->messageWindow); |
| | | #endif |
| | | return 0; |
| | | } |
| | | |
| | |
| | | |
| | | #endif /* __WINRT__ */ |
| | | |
| | | static SDL_DeviceNotificationData s_notification_data; |
| | | |
| | | /* Function/thread to scan the system for joysticks. */ |
| | | static int |
| | | SDL_JoystickThread(void *_data) |
| | | { |
| | | SDL_DeviceNotificationData notification_data; |
| | | |
| | | #if SDL_JOYSTICK_XINPUT |
| | | SDL_bool bOpenedXInputDevices[XUSER_MAX_COUNT]; |
| | | SDL_zeroa(bOpenedXInputDevices); |
| | | #endif |
| | | |
| | | if (SDL_CreateDeviceNotification(¬ification_data) < 0) { |
| | | if (SDL_CreateDeviceNotification(&s_notification_data) < 0) { |
| | | return -1; |
| | | } |
| | | |
| | | SDL_LockMutex(s_mutexJoyStickEnum); |
| | | while (s_bJoystickThreadQuit == SDL_FALSE) { |
| | | SDL_bool bXInputChanged = SDL_FALSE; |
| | | |
| | | if (SDL_WaitForDeviceNotification(¬ification_data, s_mutexJoyStickEnum) == SDL_FALSE) { |
| | | if (SDL_WaitForDeviceNotification(&s_notification_data, s_mutexJoyStickEnum) == SDL_FALSE) { |
| | | #if SDL_JOYSTICK_XINPUT |
| | | /* WM_DEVICECHANGE not working, poll for new XINPUT controllers */ |
| | | SDL_CondWaitTimeout(s_condJoystickThread, s_mutexJoyStickEnum, 1000); |
| | |
| | | const DWORD result = XINPUTGETCAPABILITIES(userId, XINPUT_FLAG_GAMEPAD, &capabilities); |
| | | const SDL_bool available = (result == ERROR_SUCCESS); |
| | | if (bOpenedXInputDevices[userId] != available) { |
| | | bXInputChanged = SDL_TRUE; |
| | | s_bWindowsDeviceChanged = SDL_TRUE; |
| | | bOpenedXInputDevices[userId] = available; |
| | | } |
| | | } |
| | |
| | | break; |
| | | #endif /* SDL_JOYSTICK_XINPUT */ |
| | | } |
| | | |
| | | if (s_bWindowsDeviceChanged || bXInputChanged) { |
| | | s_bDeviceRemoved = SDL_TRUE; |
| | | s_bDeviceAdded = SDL_TRUE; |
| | | s_bWindowsDeviceChanged = SDL_FALSE; |
| | | } |
| | | } |
| | | SDL_UnlockMutex(s_mutexJoyStickEnum); |
| | | |
| | | SDL_CleanupDeviceNotification(¬ification_data); |
| | | SDL_CleanupDeviceNotification(&s_notification_data); |
| | | |
| | | return 1; |
| | | } |
| | | |
| | | /* spin up the thread to detect hotplug of devices */ |
| | | static int |
| | | SDL_StartJoystickThread(void) |
| | | { |
| | | s_mutexJoyStickEnum = SDL_CreateMutex(); |
| | | if (!s_mutexJoyStickEnum) { |
| | | return -1; |
| | | } |
| | | |
| | | s_condJoystickThread = SDL_CreateCond(); |
| | | if (!s_condJoystickThread) { |
| | | return -1; |
| | | } |
| | | |
| | | s_bJoystickThreadQuit = SDL_FALSE; |
| | | s_joystickThread = SDL_CreateThreadInternal(SDL_JoystickThread, "SDL_joystick", 64 * 1024, NULL); |
| | | if (!s_joystickThread) { |
| | | return -1; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | static void |
| | | SDL_StopJoystickThread(void) |
| | | { |
| | | if (!s_joystickThread) { |
| | | return; |
| | | } |
| | | |
| | | SDL_LockMutex(s_mutexJoyStickEnum); |
| | | s_bJoystickThreadQuit = SDL_TRUE; |
| | | SDL_CondBroadcast(s_condJoystickThread); /* signal the joystick thread to quit */ |
| | | SDL_UnlockMutex(s_mutexJoyStickEnum); |
| | | #ifndef __WINRT__ |
| | | PostThreadMessage(SDL_GetThreadID(s_joystickThread), WM_QUIT, 0, 0); |
| | | #endif |
| | | SDL_WaitThread(s_joystickThread, NULL); /* wait for it to bugger off */ |
| | | |
| | | SDL_DestroyCond(s_condJoystickThread); |
| | | s_condJoystickThread = NULL; |
| | | |
| | | SDL_DestroyMutex(s_mutexJoyStickEnum); |
| | | s_mutexJoyStickEnum = NULL; |
| | | |
| | | s_joystickThread = NULL; |
| | | } |
| | | |
| | | void WINDOWS_AddJoystickDevice(JoyStick_DeviceData *device) |
| | |
| | | device->nInstanceID = SDL_GetNextJoystickInstanceID(); |
| | | device->pNext = SYS_Joystick; |
| | | SYS_Joystick = device; |
| | | |
| | | s_bDeviceAdded = SDL_TRUE; |
| | | } |
| | | |
| | | static void WINDOWS_JoystickDetect(void); |
| | |
| | | return -1; |
| | | } |
| | | |
| | | s_mutexJoyStickEnum = SDL_CreateMutex(); |
| | | s_condJoystickThread = SDL_CreateCond(); |
| | | s_bDeviceAdded = SDL_TRUE; /* force a scan of the system for joysticks this first time */ |
| | | s_bWindowsDeviceChanged = SDL_TRUE; /* force a scan of the system for joysticks this first time */ |
| | | |
| | | WINDOWS_JoystickDetect(); |
| | | |
| | | if (!s_threadJoystick) { |
| | | /* spin up the thread to detect hotplug of devices */ |
| | | s_bJoystickThreadQuit = SDL_FALSE; |
| | | s_threadJoystick = SDL_CreateThreadInternal(SDL_JoystickThread, "SDL_joystick", 64 * 1024, NULL); |
| | | s_bJoystickThread = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_THREAD, SDL_FALSE); |
| | | if (s_bJoystickThread) { |
| | | if (SDL_StartJoystickThread() < 0) { |
| | | return -1; |
| | | } |
| | | } else { |
| | | if (SDL_CreateDeviceNotification(&s_notification_data) < 0) { |
| | | return -1; |
| | | } |
| | | } |
| | | return 0; |
| | | } |
| | |
| | | static void |
| | | WINDOWS_JoystickDetect(void) |
| | | { |
| | | int device_index = 0; |
| | | JoyStick_DeviceData *pCurList = NULL; |
| | | |
| | | /* only enum the devices if the joystick thread told us something changed */ |
| | | if (!s_bDeviceAdded && !s_bDeviceRemoved) { |
| | | if (!s_bWindowsDeviceChanged) { |
| | | return; /* thread hasn't signaled, nothing to do right now. */ |
| | | } |
| | | |
| | | SDL_LockMutex(s_mutexJoyStickEnum); |
| | | if (s_mutexJoyStickEnum) { |
| | | SDL_LockMutex(s_mutexJoyStickEnum); |
| | | } |
| | | |
| | | s_bDeviceAdded = SDL_FALSE; |
| | | s_bDeviceRemoved = SDL_FALSE; |
| | | s_bWindowsDeviceChanged = SDL_FALSE; |
| | | |
| | | pCurList = SYS_Joystick; |
| | | SYS_Joystick = NULL; |
| | |
| | | /* Look for XInput devices. Do this last, so they're first in the final list. */ |
| | | SDL_XINPUT_JoystickDetect(&pCurList); |
| | | |
| | | SDL_UnlockMutex(s_mutexJoyStickEnum); |
| | | if (s_mutexJoyStickEnum) { |
| | | SDL_UnlockMutex(s_mutexJoyStickEnum); |
| | | } |
| | | |
| | | while (pCurList) { |
| | | JoyStick_DeviceData *pListNext = NULL; |
| | | |
| | | if (pCurList->bXInputDevice) { |
| | | #if SDL_HAPTIC_XINPUT |
| | | SDL_XINPUT_MaybeRemoveDevice(pCurList->XInputUserId); |
| | | #endif |
| | | } else { |
| | | #if SDL_HAPTIC_DINPUT |
| | | SDL_DINPUT_MaybeRemoveDevice(&pCurList->dxdevice); |
| | | #endif |
| | | } |
| | | |
| | | SDL_PrivateJoystickRemoved(pCurList->nInstanceID); |
| | |
| | | pCurList = pListNext; |
| | | } |
| | | |
| | | if (s_bDeviceAdded) { |
| | | JoyStick_DeviceData *pNewJoystick; |
| | | int device_index = 0; |
| | | s_bDeviceAdded = SDL_FALSE; |
| | | pNewJoystick = SYS_Joystick; |
| | | while (pNewJoystick) { |
| | | if (pNewJoystick->send_add_event) { |
| | | if (pNewJoystick->bXInputDevice) { |
| | | SDL_XINPUT_MaybeAddDevice(pNewJoystick->XInputUserId); |
| | | } else { |
| | | SDL_DINPUT_MaybeAddDevice(&pNewJoystick->dxdevice); |
| | | } |
| | | |
| | | SDL_PrivateJoystickAdded(pNewJoystick->nInstanceID); |
| | | |
| | | pNewJoystick->send_add_event = SDL_FALSE; |
| | | for (device_index = 0, pCurList = SYS_Joystick; pCurList; ++device_index, pCurList = pCurList->pNext) { |
| | | if (pCurList->send_add_event) { |
| | | if (pCurList->bXInputDevice) { |
| | | #if SDL_HAPTIC_XINPUT |
| | | SDL_XINPUT_MaybeAddDevice(pCurList->XInputUserId); |
| | | #endif |
| | | } else { |
| | | #if SDL_HAPTIC_DINPUT |
| | | SDL_DINPUT_MaybeAddDevice(&pCurList->dxdevice); |
| | | #endif |
| | | } |
| | | device_index++; |
| | | pNewJoystick = pNewJoystick->pNext; |
| | | |
| | | SDL_PrivateJoystickAdded(pCurList->nInstanceID); |
| | | |
| | | pCurList->send_add_event = SDL_FALSE; |
| | | } |
| | | } |
| | | } |
| | |
| | | WINDOWS_JoystickGetDeviceName(int device_index) |
| | | { |
| | | JoyStick_DeviceData *device = SYS_Joystick; |
| | | int index; |
| | | |
| | | for (; device_index > 0; device_index--) |
| | | for (index = device_index; index > 0; index--) |
| | | device = device->pNext; |
| | | |
| | | return device->joystickname; |
| | |
| | | static int |
| | | WINDOWS_JoystickOpen(SDL_Joystick * joystick, int device_index) |
| | | { |
| | | JoyStick_DeviceData *joystickdevice = SYS_Joystick; |
| | | JoyStick_DeviceData *device = SYS_Joystick; |
| | | int index; |
| | | |
| | | for (; device_index > 0; device_index--) |
| | | joystickdevice = joystickdevice->pNext; |
| | | for (index = device_index; index > 0; index--) |
| | | device = device->pNext; |
| | | |
| | | /* allocate memory for system specific hardware data */ |
| | | joystick->instance_id = joystickdevice->nInstanceID; |
| | | joystick->instance_id = device->nInstanceID; |
| | | joystick->hwdata = |
| | | (struct joystick_hwdata *) SDL_malloc(sizeof(struct joystick_hwdata)); |
| | | if (joystick->hwdata == NULL) { |
| | | return SDL_OutOfMemory(); |
| | | } |
| | | SDL_zerop(joystick->hwdata); |
| | | joystick->hwdata->guid = joystickdevice->guid; |
| | | joystick->hwdata->guid = device->guid; |
| | | |
| | | if (joystickdevice->bXInputDevice) { |
| | | return SDL_XINPUT_JoystickOpen(joystick, joystickdevice); |
| | | if (device->bXInputDevice) { |
| | | return SDL_XINPUT_JoystickOpen(joystick, device); |
| | | } else { |
| | | return SDL_DINPUT_JoystickOpen(joystick, joystickdevice); |
| | | return SDL_DINPUT_JoystickOpen(joystick, device); |
| | | } |
| | | } |
| | | |
| | |
| | | } else { |
| | | return SDL_DINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble); |
| | | } |
| | | } |
| | | |
| | | static int |
| | | WINDOWS_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble) |
| | | { |
| | | return SDL_Unsupported(); |
| | | } |
| | | |
| | | static SDL_bool |
| | | WINDOWS_JoystickHasLED(SDL_Joystick * joystick) |
| | | { |
| | | return SDL_FALSE; |
| | | } |
| | | |
| | | static int |
| | | WINDOWS_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue) |
| | | { |
| | | return SDL_Unsupported(); |
| | | } |
| | | |
| | | static int |
| | | WINDOWS_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) |
| | | { |
| | | return SDL_Unsupported(); |
| | | } |
| | | |
| | | static void |
| | |
| | | } |
| | | SYS_Joystick = NULL; |
| | | |
| | | if (s_threadJoystick) { |
| | | SDL_LockMutex(s_mutexJoyStickEnum); |
| | | 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); |
| | | SDL_DestroyCond(s_condJoystickThread); |
| | | s_condJoystickThread= NULL; |
| | | s_mutexJoyStickEnum = NULL; |
| | | s_threadJoystick = NULL; |
| | | if (s_bJoystickThread) { |
| | | SDL_StopJoystickThread(); |
| | | } else { |
| | | SDL_CleanupDeviceNotification(&s_notification_data); |
| | | } |
| | | |
| | | SDL_DINPUT_JoystickQuit(); |
| | | SDL_XINPUT_JoystickQuit(); |
| | | |
| | | s_bDeviceAdded = SDL_FALSE; |
| | | s_bDeviceRemoved = SDL_FALSE; |
| | | s_bWindowsDeviceChanged = SDL_FALSE; |
| | | } |
| | | |
| | | static SDL_bool |
| | | WINDOWS_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) |
| | | { |
| | | return SDL_FALSE; |
| | | } |
| | | |
| | | SDL_JoystickDriver SDL_WINDOWS_JoystickDriver = |
| | |
| | | WINDOWS_JoystickGetDeviceInstanceID, |
| | | WINDOWS_JoystickOpen, |
| | | WINDOWS_JoystickRumble, |
| | | WINDOWS_JoystickRumbleTriggers, |
| | | WINDOWS_JoystickHasLED, |
| | | WINDOWS_JoystickSetLED, |
| | | WINDOWS_JoystickSetSensorsEnabled, |
| | | WINDOWS_JoystickUpdate, |
| | | WINDOWS_JoystickClose, |
| | | WINDOWS_JoystickQuit, |
| | | WINDOWS_JoystickGetGamepadMapping |
| | | }; |
| | | |
| | | #endif /* SDL_JOYSTICK_DINPUT || SDL_JOYSTICK_XINPUT */ |