summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/SDL2/src/joystick/windows/SDL_windowsjoystick.c
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/SDL2/src/joystick/windows/SDL_windowsjoystick.c')
-rw-r--r--3rdparty/SDL2/src/joystick/windows/SDL_windowsjoystick.c569
1 files changed, 569 insertions, 0 deletions
diff --git a/3rdparty/SDL2/src/joystick/windows/SDL_windowsjoystick.c b/3rdparty/SDL2/src/joystick/windows/SDL_windowsjoystick.c
new file mode 100644
index 00000000000..7123c6151bc
--- /dev/null
+++ b/3rdparty/SDL2/src/joystick/windows/SDL_windowsjoystick.c
@@ -0,0 +1,569 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_JOYSTICK_DINPUT || SDL_JOYSTICK_XINPUT
+
+/* DirectInput joystick driver; written by Glenn Maynard, based on Andrei de
+ * A. Formiga's WINMM driver.
+ *
+ * Hats and sliders are completely untested; the app I'm writing this for mostly
+ * doesn't use them and I don't own any joysticks with them.
+ *
+ * We don't bother to use event notification here. It doesn't seem to work
+ * with polled devices, and it's fine to call IDirectInputDevice8_GetDeviceData and
+ * let it return 0 events. */
+
+#include "SDL_error.h"
+#include "SDL_assert.h"
+#include "SDL_events.h"
+#include "SDL_thread.h"
+#include "SDL_timer.h"
+#include "SDL_mutex.h"
+#include "SDL_events.h"
+#include "SDL_hints.h"
+#include "SDL_joystick.h"
+#include "../SDL_sysjoystick.h"
+#if !SDL_EVENTS_DISABLED
+#include "../../events/SDL_events_c.h"
+#endif
+#include "../../core/windows/SDL_windows.h"
+#if !defined(__WINRT__)
+#include <dbt.h>
+#endif
+
+#define INITGUID /* Only set here, if set twice will cause mingw32 to break. */
+#include "SDL_windowsjoystick_c.h"
+#include "SDL_dinputjoystick_c.h"
+#include "SDL_xinputjoystick_c.h"
+
+#include "../../haptic/windows/SDL_dinputhaptic_c.h" /* For haptic hot plugging */
+#include "../../haptic/windows/SDL_xinputhaptic_c.h" /* For haptic hot plugging */
+
+
+#ifndef DEVICE_NOTIFY_WINDOW_HANDLE
+#define DEVICE_NOTIFY_WINDOW_HANDLE 0x00000000
+#endif
+
+/* local variables */
+static SDL_bool s_bDeviceAdded = SDL_FALSE;
+static SDL_bool s_bDeviceRemoved = SDL_FALSE;
+static SDL_JoystickID s_nInstanceID = -1;
+static SDL_cond *s_condJoystickThread = NULL;
+static SDL_mutex *s_mutexJoyStickEnum = NULL;
+static SDL_Thread *s_threadJoystick = 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__
+
+typedef struct
+{
+ int unused;
+} SDL_DeviceNotificationData;
+
+static void
+SDL_CleanupDeviceNotification(SDL_DeviceNotificationData *data)
+{
+}
+
+static int
+SDL_CreateDeviceNotification(SDL_DeviceNotificationData *data)
+{
+ return 0;
+}
+
+static void
+SDL_CheckDeviceNotification(SDL_DeviceNotificationData *data)
+{
+}
+
+#else /* !__WINRT__ */
+
+typedef struct
+{
+ HRESULT coinitialized;
+ WNDCLASSEX wincl;
+ HWND messageWindow;
+ HDEVNOTIFY hNotify;
+} SDL_DeviceNotificationData;
+
+
+/* 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)
+{
+ switch (message) {
+ 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;
+ }
+ break;
+ }
+ return 0;
+ }
+
+ return DefWindowProc (hwnd, message, wParam, lParam);
+}
+
+static void
+SDL_CleanupDeviceNotification(SDL_DeviceNotificationData *data)
+{
+ if (data->hNotify)
+ UnregisterDeviceNotification(data->hNotify);
+
+ if (data->messageWindow)
+ DestroyWindow(data->messageWindow);
+
+ UnregisterClass(data->wincl.lpszClassName, data->wincl.hInstance);
+
+ if (data->coinitialized == S_OK) {
+ WIN_CoUninitialize();
+ }
+}
+
+static int
+SDL_CreateDeviceNotification(SDL_DeviceNotificationData *data)
+{
+ DEV_BROADCAST_DEVICEINTERFACE dbh;
+ GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2L, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } };
+
+ SDL_zerop(data);
+
+ data->coinitialized = WIN_CoInitialize();
+
+ data->wincl.hInstance = GetModuleHandle(NULL);
+ data->wincl.lpszClassName = L"Message";
+ data->wincl.lpfnWndProc = SDL_PrivateJoystickDetectProc; /* This function is called by windows */
+ data->wincl.cbSize = sizeof (WNDCLASSEX);
+
+ if (!RegisterClassEx(&data->wincl)) {
+ WIN_SetError("Failed to create register class for joystick autodetect");
+ SDL_CleanupDeviceNotification(data);
+ return -1;
+ }
+
+ data->messageWindow = (HWND)CreateWindowEx(0, L"Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
+ if (!data->messageWindow) {
+ WIN_SetError("Failed to create message window for joystick autodetect");
+ SDL_CleanupDeviceNotification(data);
+ return -1;
+ }
+
+ SDL_zero(dbh);
+ dbh.dbcc_size = sizeof(dbh);
+ dbh.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
+ dbh.dbcc_classguid = GUID_DEVINTERFACE_HID;
+
+ data->hNotify = RegisterDeviceNotification(data->messageWindow, &dbh, DEVICE_NOTIFY_WINDOW_HANDLE);
+ if (!data->hNotify) {
+ WIN_SetError("Failed to create notify device for joystick autodetect");
+ SDL_CleanupDeviceNotification(data);
+ return -1;
+ }
+ return 0;
+}
+
+static void
+SDL_CheckDeviceNotification(SDL_DeviceNotificationData *data)
+{
+ MSG msg;
+
+ if (!data->messageWindow) {
+ return;
+ }
+
+ while (PeekMessage(&msg, data->messageWindow, 0, 0, PM_NOREMOVE)) {
+ if (GetMessage(&msg, data->messageWindow, 0, 0) != 0) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+}
+
+#endif /* __WINRT__ */
+
+/* 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_zero(bOpenedXInputDevices);
+#endif
+
+ if (SDL_CreateDeviceNotification(&notification_data) < 0) {
+ return -1;
+ }
+
+ SDL_LockMutex(s_mutexJoyStickEnum);
+ while (s_bJoystickThreadQuit == SDL_FALSE) {
+ SDL_bool bXInputChanged = SDL_FALSE;
+
+ SDL_CondWaitTimeout(s_condJoystickThread, s_mutexJoyStickEnum, 300);
+
+ SDL_CheckDeviceNotification(&notification_data);
+
+#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;
+ }
+ }
+ }
+#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;
+ }
+ }
+ SDL_UnlockMutex(s_mutexJoyStickEnum);
+
+ SDL_CleanupDeviceNotification(&notification_data);
+
+ return 1;
+}
+
+void SDL_SYS_AddJoystickDevice(JoyStick_DeviceData *device)
+{
+ device->send_add_event = SDL_TRUE;
+ device->nInstanceID = ++s_nInstanceID;
+ device->pNext = SYS_Joystick;
+ SYS_Joystick = device;
+
+ s_bDeviceAdded = SDL_TRUE;
+}
+
+/* Function to scan the system for joysticks.
+ * Joystick 0 should be the system default joystick.
+ * It should return 0, or -1 on an unrecoverable fatal error.
+ */
+int
+SDL_SYS_JoystickInit(void)
+{
+ if (SDL_DINPUT_JoystickInit() < 0) {
+ SDL_SYS_JoystickQuit();
+ return -1;
+ }
+
+ if (SDL_XINPUT_JoystickInit() < 0) {
+ SDL_SYS_JoystickQuit();
+ 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 */
+
+ SDL_SYS_JoystickDetect();
+
+ if (!s_threadJoystick) {
+ s_bJoystickThreadQuit = SDL_FALSE;
+ /* spin up the thread to detect hotplug of devices */
+#if defined(__WIN32__) && !defined(HAVE_LIBC)
+#undef SDL_CreateThread
+#if SDL_DYNAMIC_API
+ s_threadJoystick= SDL_CreateThread_REAL(SDL_JoystickThread, "SDL_joystick", NULL, NULL, NULL);
+#else
+ s_threadJoystick= SDL_CreateThread(SDL_JoystickThread, "SDL_joystick", NULL, NULL, NULL);
+#endif
+#else
+ s_threadJoystick = SDL_CreateThread(SDL_JoystickThread, "SDL_joystick", NULL);
+#endif
+ }
+ return SDL_SYS_NumJoysticks();
+}
+
+/* return the number of joysticks that are connected right now */
+int
+SDL_SYS_NumJoysticks()
+{
+ int nJoysticks = 0;
+ JoyStick_DeviceData *device = SYS_Joystick;
+ while (device) {
+ nJoysticks++;
+ device = device->pNext;
+ }
+
+ return nJoysticks;
+}
+
+/* detect any new joysticks being inserted into the system */
+void
+SDL_SYS_JoystickDetect()
+{
+ JoyStick_DeviceData *pCurList = NULL;
+#if !SDL_EVENTS_DISABLED
+ SDL_Event event;
+#endif
+
+ /* only enum the devices if the joystick thread told us something changed */
+ if (!s_bDeviceAdded && !s_bDeviceRemoved) {
+ return; /* thread hasn't signaled, nothing to do right now. */
+ }
+
+ SDL_LockMutex(s_mutexJoyStickEnum);
+
+ s_bDeviceAdded = SDL_FALSE;
+ s_bDeviceRemoved = SDL_FALSE;
+
+ pCurList = SYS_Joystick;
+ SYS_Joystick = NULL;
+
+ /* Look for DirectInput joysticks, wheels, head trackers, gamepads, etc.. */
+ SDL_DINPUT_JoystickDetect(&pCurList);
+
+ /* Look for XInput devices. Do this last, so they're first in the final list. */
+ SDL_XINPUT_JoystickDetect(&pCurList);
+
+ SDL_UnlockMutex(s_mutexJoyStickEnum);
+
+ while (pCurList) {
+ JoyStick_DeviceData *pListNext = NULL;
+
+ if (pCurList->bXInputDevice) {
+ SDL_XINPUT_MaybeRemoveDevice(pCurList->XInputUserId);
+ } else {
+ SDL_DINPUT_MaybeRemoveDevice(&pCurList->dxdevice);
+ }
+
+#if !SDL_EVENTS_DISABLED
+ SDL_zero(event);
+ event.type = SDL_JOYDEVICEREMOVED;
+
+ if (SDL_GetEventState(event.type) == SDL_ENABLE) {
+ event.jdevice.which = pCurList->nInstanceID;
+ if ((!SDL_EventOK) || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
+ SDL_PushEvent(&event);
+ }
+ }
+#endif /* !SDL_EVENTS_DISABLED */
+
+ pListNext = pCurList->pNext;
+ SDL_free(pCurList->joystickname);
+ SDL_free(pCurList);
+ 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);
+ }
+
+#if !SDL_EVENTS_DISABLED
+ SDL_zero(event);
+ event.type = SDL_JOYDEVICEADDED;
+
+ if (SDL_GetEventState(event.type) == SDL_ENABLE) {
+ event.jdevice.which = device_index;
+ if ((!SDL_EventOK) || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
+ SDL_PushEvent(&event);
+ }
+ }
+#endif /* !SDL_EVENTS_DISABLED */
+ pNewJoystick->send_add_event = SDL_FALSE;
+ }
+ device_index++;
+ pNewJoystick = pNewJoystick->pNext;
+ }
+ }
+}
+
+/* Function to get the device-dependent name of a joystick */
+const char *
+SDL_SYS_JoystickNameForDeviceIndex(int device_index)
+{
+ JoyStick_DeviceData *device = SYS_Joystick;
+
+ for (; device_index > 0; device_index--)
+ device = device->pNext;
+
+ return device->joystickname;
+}
+
+/* Function to perform the mapping between current device instance and this joysticks instance id */
+SDL_JoystickID
+SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
+{
+ JoyStick_DeviceData *device = SYS_Joystick;
+ int index;
+
+ for (index = device_index; index > 0; index--)
+ device = device->pNext;
+
+ return device->nInstanceID;
+}
+
+/* Function to open a joystick for use.
+ The joystick to open is specified by the device index.
+ This should fill the nbuttons and naxes fields of the joystick structure.
+ It returns 0, or -1 if there is an error.
+ */
+int
+SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
+{
+ JoyStick_DeviceData *joystickdevice = SYS_Joystick;
+
+ for (; device_index > 0; device_index--)
+ joystickdevice = joystickdevice->pNext;
+
+ /* allocate memory for system specific hardware data */
+ joystick->instance_id = joystickdevice->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;
+
+ if (joystickdevice->bXInputDevice) {
+ return SDL_XINPUT_JoystickOpen(joystick, joystickdevice);
+ } else {
+ return SDL_DINPUT_JoystickOpen(joystick, joystickdevice);
+ }
+}
+
+/* return true if this joystick is plugged in right now */
+SDL_bool
+SDL_SYS_JoystickAttached(SDL_Joystick * joystick)
+{
+ return joystick->hwdata && !joystick->hwdata->removed;
+}
+
+void
+SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
+{
+ if (!joystick->hwdata || joystick->hwdata->removed) {
+ return;
+ }
+
+ if (joystick->hwdata->bXInputDevice) {
+ SDL_XINPUT_JoystickUpdate(joystick);
+ } else {
+ SDL_DINPUT_JoystickUpdate(joystick);
+ }
+
+ if (joystick->hwdata->removed) {
+ joystick->force_recentering = SDL_TRUE;
+ }
+}
+
+/* Function to close a joystick after use */
+void
+SDL_SYS_JoystickClose(SDL_Joystick * joystick)
+{
+ if (joystick->hwdata->bXInputDevice) {
+ SDL_XINPUT_JoystickClose(joystick);
+ } else {
+ SDL_DINPUT_JoystickClose(joystick);
+ }
+
+ SDL_free(joystick->hwdata);
+}
+
+/* Function to perform any system-specific joystick related cleanup */
+void
+SDL_SYS_JoystickQuit(void)
+{
+ JoyStick_DeviceData *device = SYS_Joystick;
+
+ while (device) {
+ JoyStick_DeviceData *device_next = device->pNext;
+ SDL_free(device->joystickname);
+ SDL_free(device);
+ device = device_next;
+ }
+ 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);
+ 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;
+ }
+
+ SDL_DINPUT_JoystickQuit();
+ SDL_XINPUT_JoystickQuit();
+}
+
+/* return the stable device guid for this device index */
+SDL_JoystickGUID
+SDL_SYS_JoystickGetDeviceGUID(int device_index)
+{
+ JoyStick_DeviceData *device = SYS_Joystick;
+ int index;
+
+ for (index = device_index; index > 0; index--)
+ device = device->pNext;
+
+ return device->guid;
+}
+
+SDL_JoystickGUID
+SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
+{
+ return joystick->hwdata->guid;
+}
+
+#endif /* SDL_JOYSTICK_DINPUT || SDL_JOYSTICK_XINPUT */
+
+/* vi: set ts=4 sw=4 expandtab: */