src/joystick/windows/SDL_windowsjoystick.c
author Sam Lantinga
Thu, 16 Jan 2020 20:49:25 -0800
changeset 13422 fd6a12de91c7
parent 13369 d73580c86f81
child 13480 6a144eb5e1f1
permissions -rw-r--r--
Updated copyright date for 2020
slouken@8972
     1
/*
slouken@8972
     2
  Simple DirectMedia Layer
slouken@13422
     3
  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
slouken@8972
     4
slouken@8972
     5
  This software is provided 'as-is', without any express or implied
slouken@8972
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@8972
     7
  arising from the use of this software.
slouken@8972
     8
slouken@8972
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@8972
    10
  including commercial applications, and to alter it and redistribute it
slouken@8972
    11
  freely, subject to the following restrictions:
slouken@8972
    12
slouken@8972
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@8972
    14
     claim that you wrote the original software. If you use this software
slouken@8972
    15
     in a product, an acknowledgment in the product documentation would be
slouken@8972
    16
     appreciated but is not required.
slouken@8972
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@8972
    18
     misrepresented as being the original software.
slouken@8972
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@8972
    20
*/
slouken@8972
    21
#include "../../SDL_internal.h"
slouken@8972
    22
slouken@8972
    23
#if SDL_JOYSTICK_DINPUT || SDL_JOYSTICK_XINPUT
slouken@8972
    24
slouken@8972
    25
/* DirectInput joystick driver; written by Glenn Maynard, based on Andrei de
slouken@8972
    26
 * A. Formiga's WINMM driver.
slouken@8972
    27
 *
slouken@8972
    28
 * Hats and sliders are completely untested; the app I'm writing this for mostly
slouken@8972
    29
 * doesn't use them and I don't own any joysticks with them.
slouken@8972
    30
 *
slouken@8972
    31
 * We don't bother to use event notification here.  It doesn't seem to work
slouken@8972
    32
 * with polled devices, and it's fine to call IDirectInputDevice8_GetDeviceData and
slouken@8972
    33
 * let it return 0 events. */
slouken@8972
    34
slouken@8972
    35
#include "SDL_error.h"
slouken@8972
    36
#include "SDL_assert.h"
slouken@8972
    37
#include "SDL_events.h"
slouken@8972
    38
#include "SDL_timer.h"
slouken@8972
    39
#include "SDL_mutex.h"
slouken@8972
    40
#include "SDL_joystick.h"
slouken@8972
    41
#include "../SDL_sysjoystick.h"
icculus@10147
    42
#include "../../thread/SDL_systhread.h"
slouken@8972
    43
#include "../../core/windows/SDL_windows.h"
dludwig@9166
    44
#if !defined(__WINRT__)
slouken@8972
    45
#include <dbt.h>
dludwig@9166
    46
#endif
slouken@8972
    47
slouken@8972
    48
#define INITGUID /* Only set here, if set twice will cause mingw32 to break. */
slouken@8972
    49
#include "SDL_windowsjoystick_c.h"
slouken@8972
    50
#include "SDL_dinputjoystick_c.h"
slouken@8972
    51
#include "SDL_xinputjoystick_c.h"
slouken@8972
    52
slouken@8972
    53
#include "../../haptic/windows/SDL_dinputhaptic_c.h"    /* For haptic hot plugging */
slouken@8972
    54
#include "../../haptic/windows/SDL_xinputhaptic_c.h"    /* For haptic hot plugging */
slouken@8972
    55
slouken@8972
    56
slouken@8988
    57
#ifndef DEVICE_NOTIFY_WINDOW_HANDLE
slouken@8988
    58
#define DEVICE_NOTIFY_WINDOW_HANDLE 0x00000000
slouken@8988
    59
#endif
slouken@8988
    60
slouken@8972
    61
/* local variables */
slouken@8972
    62
static SDL_bool s_bDeviceAdded = SDL_FALSE;
slouken@8972
    63
static SDL_bool s_bDeviceRemoved = SDL_FALSE;
slouken@8972
    64
static SDL_cond *s_condJoystickThread = NULL;
slouken@8972
    65
static SDL_mutex *s_mutexJoyStickEnum = NULL;
slouken@8972
    66
static SDL_Thread *s_threadJoystick = NULL;
slouken@8972
    67
static SDL_bool s_bJoystickThreadQuit = SDL_FALSE;
slouken@8972
    68
slouken@8972
    69
JoyStick_DeviceData *SYS_Joystick;    /* array to hold joystick ID values */
slouken@8972
    70
slouken@8972
    71
static SDL_bool s_bWindowsDeviceChanged = SDL_FALSE;
slouken@8972
    72
slouken@8972
    73
#ifdef __WINRT__
slouken@8972
    74
slouken@8972
    75
typedef struct
slouken@8972
    76
{
slouken@8972
    77
    int unused;
slouken@8972
    78
} SDL_DeviceNotificationData;
slouken@8972
    79
slouken@8972
    80
static void
slouken@8972
    81
SDL_CleanupDeviceNotification(SDL_DeviceNotificationData *data)
slouken@8972
    82
{
slouken@8972
    83
}
slouken@8972
    84
slouken@8972
    85
static int
slouken@8972
    86
SDL_CreateDeviceNotification(SDL_DeviceNotificationData *data)
slouken@8972
    87
{
slouken@8972
    88
    return 0;
slouken@8972
    89
}
slouken@8972
    90
slouken@11470
    91
static SDL_bool
slouken@11470
    92
SDL_WaitForDeviceNotification(SDL_DeviceNotificationData *data, SDL_mutex *mutex)
slouken@8972
    93
{
slouken@11470
    94
    return SDL_FALSE;
slouken@8972
    95
}
slouken@8972
    96
slouken@8972
    97
#else /* !__WINRT__ */
slouken@8972
    98
slouken@8972
    99
typedef struct
slouken@8972
   100
{
slouken@8972
   101
    HRESULT coinitialized;
slouken@8972
   102
    WNDCLASSEX wincl;
slouken@8972
   103
    HWND messageWindow;
slouken@8972
   104
    HDEVNOTIFY hNotify;
slouken@8972
   105
} SDL_DeviceNotificationData;
slouken@8972
   106
slouken@11470
   107
#define IDT_SDL_DEVICE_CHANGE_TIMER_1 1200
slouken@11470
   108
#define IDT_SDL_DEVICE_CHANGE_TIMER_2 1201
slouken@8972
   109
slouken@8972
   110
/* windowproc for our joystick detect thread message only window, to detect any USB device addition/removal */
slouken@8972
   111
static LRESULT CALLBACK
slouken@8972
   112
SDL_PrivateJoystickDetectProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
slouken@8972
   113
{
slouken@8972
   114
    switch (message) {
slouken@8972
   115
    case WM_DEVICECHANGE:
slouken@8972
   116
        switch (wParam) {
slouken@8972
   117
        case DBT_DEVICEARRIVAL:
slouken@8972
   118
        case DBT_DEVICEREMOVECOMPLETE:
slouken@8972
   119
            if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
slouken@11470
   120
                /* notify 300ms and 2 seconds later to ensure all APIs have updated status */
slouken@11470
   121
                SetTimer(hwnd, IDT_SDL_DEVICE_CHANGE_TIMER_1, 300, NULL);
slouken@11470
   122
                SetTimer(hwnd, IDT_SDL_DEVICE_CHANGE_TIMER_2, 2000, NULL);
slouken@8972
   123
            }
slouken@8972
   124
            break;
slouken@8972
   125
        }
slouken@8972
   126
        return 0;
slouken@11470
   127
    case WM_TIMER:
slouken@11470
   128
        KillTimer(hwnd, wParam);
slouken@11470
   129
        s_bWindowsDeviceChanged = SDL_TRUE;
slouken@11470
   130
        return 0;
slouken@8972
   131
    }
slouken@8972
   132
slouken@8972
   133
    return DefWindowProc (hwnd, message, wParam, lParam);
slouken@8972
   134
}
slouken@8972
   135
slouken@8972
   136
static void
slouken@8972
   137
SDL_CleanupDeviceNotification(SDL_DeviceNotificationData *data)
slouken@8972
   138
{
slouken@8972
   139
    if (data->hNotify)
slouken@8972
   140
        UnregisterDeviceNotification(data->hNotify);
slouken@8972
   141
slouken@8972
   142
    if (data->messageWindow)
slouken@8972
   143
        DestroyWindow(data->messageWindow);
slouken@8972
   144
slouken@8972
   145
    UnregisterClass(data->wincl.lpszClassName, data->wincl.hInstance);
slouken@8972
   146
slouken@8972
   147
    if (data->coinitialized == S_OK) {
slouken@8972
   148
        WIN_CoUninitialize();
slouken@8972
   149
    }
slouken@8972
   150
}
slouken@8972
   151
slouken@8972
   152
static int
slouken@8972
   153
SDL_CreateDeviceNotification(SDL_DeviceNotificationData *data)
slouken@8972
   154
{
slouken@8972
   155
    DEV_BROADCAST_DEVICEINTERFACE dbh;
slouken@8972
   156
    GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2L, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } };
slouken@8972
   157
slouken@8972
   158
    SDL_zerop(data);
slouken@8972
   159
slouken@8972
   160
    data->coinitialized = WIN_CoInitialize();
slouken@8972
   161
slouken@8972
   162
    data->wincl.hInstance = GetModuleHandle(NULL);
slouken@8972
   163
    data->wincl.lpszClassName = L"Message";
slouken@8972
   164
    data->wincl.lpfnWndProc = SDL_PrivateJoystickDetectProc;      /* This function is called by windows */
slouken@8972
   165
    data->wincl.cbSize = sizeof (WNDCLASSEX);
slouken@8972
   166
slouken@8972
   167
    if (!RegisterClassEx(&data->wincl)) {
slouken@8972
   168
        WIN_SetError("Failed to create register class for joystick autodetect");
slouken@8972
   169
        SDL_CleanupDeviceNotification(data);
slouken@8972
   170
        return -1;
slouken@8972
   171
    }
slouken@8972
   172
slouken@8972
   173
    data->messageWindow = (HWND)CreateWindowEx(0,  L"Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
slouken@8972
   174
    if (!data->messageWindow) {
slouken@8972
   175
        WIN_SetError("Failed to create message window for joystick autodetect");
slouken@8972
   176
        SDL_CleanupDeviceNotification(data);
slouken@8972
   177
        return -1;
slouken@8972
   178
    }
slouken@8972
   179
slouken@8972
   180
    SDL_zero(dbh);
slouken@8972
   181
    dbh.dbcc_size = sizeof(dbh);
slouken@8972
   182
    dbh.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
slouken@8972
   183
    dbh.dbcc_classguid = GUID_DEVINTERFACE_HID;
slouken@8972
   184
slouken@8972
   185
    data->hNotify = RegisterDeviceNotification(data->messageWindow, &dbh, DEVICE_NOTIFY_WINDOW_HANDLE);
slouken@8972
   186
    if (!data->hNotify) {
slouken@8972
   187
        WIN_SetError("Failed to create notify device for joystick autodetect");
slouken@8972
   188
        SDL_CleanupDeviceNotification(data);
slouken@8972
   189
        return -1;
slouken@8972
   190
    }
slouken@8972
   191
    return 0;
slouken@8972
   192
}
slouken@8972
   193
slouken@11470
   194
static SDL_bool
slouken@11470
   195
SDL_WaitForDeviceNotification(SDL_DeviceNotificationData *data, SDL_mutex *mutex)
slouken@8972
   196
{
slouken@8972
   197
    MSG msg;
slouken@11470
   198
    int lastret = 1;
slouken@8972
   199
slouken@8972
   200
    if (!data->messageWindow) {
slouken@11470
   201
        return SDL_FALSE; /* device notifications require a window */
slouken@8972
   202
    }
slouken@8972
   203
slouken@11470
   204
    SDL_UnlockMutex(mutex);
slouken@11470
   205
    while (lastret > 0 && s_bWindowsDeviceChanged == SDL_FALSE) {
slouken@11470
   206
        lastret = GetMessage(&msg, NULL, 0, 0); /* WM_QUIT causes return value of 0 */
slouken@11470
   207
        if (lastret > 0) {
slouken@8972
   208
            TranslateMessage(&msg);
slouken@8972
   209
            DispatchMessage(&msg);
slouken@8972
   210
        }
slouken@8972
   211
    }
slouken@11470
   212
    SDL_LockMutex(mutex);
slouken@11470
   213
    return (lastret != -1) ? SDL_TRUE : SDL_FALSE;
slouken@8972
   214
}
slouken@8972
   215
slouken@8972
   216
#endif /* __WINRT__ */
slouken@8972
   217
slouken@8972
   218
/* Function/thread to scan the system for joysticks. */
slouken@8972
   219
static int
slouken@8972
   220
SDL_JoystickThread(void *_data)
slouken@8972
   221
{
slouken@8972
   222
    SDL_DeviceNotificationData notification_data;
slouken@8972
   223
slouken@8972
   224
#if SDL_JOYSTICK_XINPUT
slouken@8972
   225
    SDL_bool bOpenedXInputDevices[XUSER_MAX_COUNT];
sezeroz@12968
   226
    SDL_zeroa(bOpenedXInputDevices);
slouken@8972
   227
#endif
slouken@8972
   228
slouken@8972
   229
    if (SDL_CreateDeviceNotification(&notification_data) < 0) {
slouken@8972
   230
        return -1;
slouken@8972
   231
    }
slouken@8972
   232
slouken@8972
   233
    SDL_LockMutex(s_mutexJoyStickEnum);
slouken@8972
   234
    while (s_bJoystickThreadQuit == SDL_FALSE) {
slouken@8972
   235
        SDL_bool bXInputChanged = SDL_FALSE;
slouken@8972
   236
slouken@11470
   237
        if (SDL_WaitForDeviceNotification(&notification_data, s_mutexJoyStickEnum) == SDL_FALSE) {
slouken@8972
   238
#if SDL_JOYSTICK_XINPUT
slouken@11470
   239
            /* WM_DEVICECHANGE not working, poll for new XINPUT controllers */
slouken@11470
   240
            SDL_CondWaitTimeout(s_condJoystickThread, s_mutexJoyStickEnum, 1000);
slouken@11470
   241
            if (SDL_XINPUT_Enabled() && XINPUTGETCAPABILITIES) {
slouken@11470
   242
                /* scan for any change in XInput devices */
slouken@11470
   243
                Uint8 userId;
slouken@11470
   244
                for (userId = 0; userId < XUSER_MAX_COUNT; userId++) {
slouken@11470
   245
                    XINPUT_CAPABILITIES capabilities;
slouken@11470
   246
                    const DWORD result = XINPUTGETCAPABILITIES(userId, XINPUT_FLAG_GAMEPAD, &capabilities);
slouken@11470
   247
                    const SDL_bool available = (result == ERROR_SUCCESS);
slouken@11470
   248
                    if (bOpenedXInputDevices[userId] != available) {
slouken@11470
   249
                        bXInputChanged = SDL_TRUE;
slouken@11470
   250
                        bOpenedXInputDevices[userId] = available;
slouken@11470
   251
                    }
slouken@8972
   252
                }
slouken@8972
   253
            }
slouken@11470
   254
#else
slouken@11470
   255
            /* WM_DEVICECHANGE not working, no XINPUT, no point in keeping thread alive */
slouken@11470
   256
            break;
slouken@8972
   257
#endif /* SDL_JOYSTICK_XINPUT */
slouken@12201
   258
        }
slouken@8972
   259
slouken@8972
   260
        if (s_bWindowsDeviceChanged || bXInputChanged) {
slouken@8972
   261
            s_bDeviceRemoved = SDL_TRUE;
slouken@8972
   262
            s_bDeviceAdded = SDL_TRUE;
slouken@8972
   263
            s_bWindowsDeviceChanged = SDL_FALSE;
slouken@8972
   264
        }
slouken@8972
   265
    }
slouken@8972
   266
    SDL_UnlockMutex(s_mutexJoyStickEnum);
slouken@8972
   267
slouken@8972
   268
    SDL_CleanupDeviceNotification(&notification_data);
slouken@8972
   269
slouken@8972
   270
    return 1;
slouken@8972
   271
}
slouken@8972
   272
slouken@12088
   273
void WINDOWS_AddJoystickDevice(JoyStick_DeviceData *device)
slouken@8972
   274
{
slouken@8972
   275
    device->send_add_event = SDL_TRUE;
slouken@12088
   276
    device->nInstanceID = SDL_GetNextJoystickInstanceID();
slouken@8972
   277
    device->pNext = SYS_Joystick;
slouken@8972
   278
    SYS_Joystick = device;
slouken@8972
   279
slouken@8972
   280
    s_bDeviceAdded = SDL_TRUE;
slouken@8972
   281
}
slouken@8972
   282
slouken@12088
   283
static void WINDOWS_JoystickDetect(void);
slouken@12088
   284
static void WINDOWS_JoystickQuit(void);
slouken@12088
   285
slouken@8972
   286
/* Function to scan the system for joysticks.
philipp@9311
   287
 * Joystick 0 should be the system default joystick.
slouken@8972
   288
 * It should return 0, or -1 on an unrecoverable fatal error.
slouken@8972
   289
 */
slouken@12088
   290
static int
slouken@12088
   291
WINDOWS_JoystickInit(void)
slouken@8972
   292
{
slouken@8972
   293
    if (SDL_DINPUT_JoystickInit() < 0) {
slouken@12088
   294
        WINDOWS_JoystickQuit();
slouken@8972
   295
        return -1;
slouken@8972
   296
    }
slouken@8972
   297
slouken@8972
   298
    if (SDL_XINPUT_JoystickInit() < 0) {
slouken@12088
   299
        WINDOWS_JoystickQuit();
slouken@8972
   300
        return -1;
slouken@8972
   301
    }
slouken@8972
   302
slouken@8972
   303
    s_mutexJoyStickEnum = SDL_CreateMutex();
slouken@8972
   304
    s_condJoystickThread = SDL_CreateCond();
slouken@8972
   305
    s_bDeviceAdded = SDL_TRUE; /* force a scan of the system for joysticks this first time */
slouken@8972
   306
slouken@12088
   307
    WINDOWS_JoystickDetect();
slouken@8972
   308
slouken@8972
   309
    if (!s_threadJoystick) {
icculus@10146
   310
        /* spin up the thread to detect hotplug of devices */
slouken@8972
   311
        s_bJoystickThreadQuit = SDL_FALSE;
icculus@10146
   312
        s_threadJoystick = SDL_CreateThreadInternal(SDL_JoystickThread, "SDL_joystick", 64 * 1024, NULL);
slouken@8972
   313
    }
slouken@12088
   314
    return 0;
slouken@8972
   315
}
slouken@8972
   316
slouken@8972
   317
/* return the number of joysticks that are connected right now */
slouken@12088
   318
static int
slouken@12088
   319
WINDOWS_JoystickGetCount(void)
slouken@8972
   320
{
slouken@8972
   321
    int nJoysticks = 0;
slouken@8972
   322
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@8972
   323
    while (device) {
slouken@8972
   324
        nJoysticks++;
slouken@8972
   325
        device = device->pNext;
slouken@8972
   326
    }
slouken@8972
   327
slouken@8972
   328
    return nJoysticks;
slouken@8972
   329
}
slouken@8972
   330
slouken@8972
   331
/* detect any new joysticks being inserted into the system */
slouken@12088
   332
static void
slouken@12088
   333
WINDOWS_JoystickDetect(void)
slouken@8972
   334
{
slouken@8972
   335
    JoyStick_DeviceData *pCurList = NULL;
slouken@8972
   336
slouken@8972
   337
    /* only enum the devices if the joystick thread told us something changed */
slouken@8972
   338
    if (!s_bDeviceAdded && !s_bDeviceRemoved) {
slouken@8972
   339
        return;  /* thread hasn't signaled, nothing to do right now. */
slouken@8972
   340
    }
slouken@8972
   341
slouken@8972
   342
    SDL_LockMutex(s_mutexJoyStickEnum);
slouken@8972
   343
slouken@8972
   344
    s_bDeviceAdded = SDL_FALSE;
slouken@8972
   345
    s_bDeviceRemoved = SDL_FALSE;
slouken@8972
   346
slouken@8972
   347
    pCurList = SYS_Joystick;
slouken@8972
   348
    SYS_Joystick = NULL;
slouken@8972
   349
slouken@8972
   350
    /* Look for DirectInput joysticks, wheels, head trackers, gamepads, etc.. */
slouken@8972
   351
    SDL_DINPUT_JoystickDetect(&pCurList);
slouken@8972
   352
slouken@8972
   353
    /* Look for XInput devices. Do this last, so they're first in the final list. */
slouken@8972
   354
    SDL_XINPUT_JoystickDetect(&pCurList);
slouken@8972
   355
slouken@8972
   356
    SDL_UnlockMutex(s_mutexJoyStickEnum);
slouken@8972
   357
slouken@8972
   358
    while (pCurList) {
slouken@8972
   359
        JoyStick_DeviceData *pListNext = NULL;
slouken@8972
   360
slouken@8972
   361
        if (pCurList->bXInputDevice) {
slouken@8972
   362
            SDL_XINPUT_MaybeRemoveDevice(pCurList->XInputUserId);
slouken@8972
   363
        } else {
slouken@8972
   364
            SDL_DINPUT_MaybeRemoveDevice(&pCurList->dxdevice);
slouken@8972
   365
        }
slouken@8972
   366
slouken@10226
   367
        SDL_PrivateJoystickRemoved(pCurList->nInstanceID);
slouken@8972
   368
slouken@8972
   369
        pListNext = pCurList->pNext;
slouken@8972
   370
        SDL_free(pCurList->joystickname);
slouken@8972
   371
        SDL_free(pCurList);
slouken@8972
   372
        pCurList = pListNext;
slouken@8972
   373
    }
slouken@8972
   374
slouken@8972
   375
    if (s_bDeviceAdded) {
slouken@8972
   376
        JoyStick_DeviceData *pNewJoystick;
slouken@8972
   377
        int device_index = 0;
slouken@8972
   378
        s_bDeviceAdded = SDL_FALSE;
slouken@8972
   379
        pNewJoystick = SYS_Joystick;
slouken@8972
   380
        while (pNewJoystick) {
slouken@8972
   381
            if (pNewJoystick->send_add_event) {
slouken@8972
   382
                if (pNewJoystick->bXInputDevice) {
slouken@8972
   383
                    SDL_XINPUT_MaybeAddDevice(pNewJoystick->XInputUserId);
slouken@8972
   384
                } else {
slouken@8972
   385
                    SDL_DINPUT_MaybeAddDevice(&pNewJoystick->dxdevice);
slouken@8972
   386
                }
slouken@8972
   387
slouken@12088
   388
                SDL_PrivateJoystickAdded(pNewJoystick->nInstanceID);
slouken@8972
   389
slouken@8972
   390
                pNewJoystick->send_add_event = SDL_FALSE;
slouken@8972
   391
            }
slouken@8972
   392
            device_index++;
slouken@8972
   393
            pNewJoystick = pNewJoystick->pNext;
slouken@8972
   394
        }
slouken@8972
   395
    }
slouken@8972
   396
}
slouken@8972
   397
slouken@8972
   398
/* Function to get the device-dependent name of a joystick */
slouken@12088
   399
static const char *
slouken@12088
   400
WINDOWS_JoystickGetDeviceName(int device_index)
slouken@8972
   401
{
slouken@8972
   402
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@8972
   403
slouken@8972
   404
    for (; device_index > 0; device_index--)
slouken@8972
   405
        device = device->pNext;
slouken@8972
   406
slouken@8972
   407
    return device->joystickname;
slouken@8972
   408
}
slouken@8972
   409
slouken@12359
   410
static int
slouken@12359
   411
WINDOWS_JoystickGetDevicePlayerIndex(int device_index)
slouken@12359
   412
{
slouken@12359
   413
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@12359
   414
    int index;
slouken@12359
   415
slouken@12359
   416
    for (index = device_index; index > 0; index--)
slouken@12359
   417
        device = device->pNext;
slouken@12359
   418
slouken@12359
   419
    return device->bXInputDevice ? (int)device->XInputUserId : -1;
slouken@12359
   420
}
slouken@12359
   421
slouken@13369
   422
static void
slouken@13369
   423
WINDOWS_JoystickSetDevicePlayerIndex(int device_index, int player_index)
slouken@13369
   424
{
slouken@13369
   425
}
slouken@13369
   426
slouken@12088
   427
/* return the stable device guid for this device index */
slouken@12088
   428
static SDL_JoystickGUID
slouken@12088
   429
WINDOWS_JoystickGetDeviceGUID(int device_index)
slouken@12088
   430
{
slouken@12088
   431
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@12088
   432
    int index;
slouken@12088
   433
slouken@12088
   434
    for (index = device_index; index > 0; index--)
slouken@12088
   435
        device = device->pNext;
slouken@12088
   436
slouken@12088
   437
    return device->guid;
slouken@12088
   438
}
slouken@12088
   439
slouken@8972
   440
/* Function to perform the mapping between current device instance and this joysticks instance id */
slouken@12088
   441
static SDL_JoystickID
slouken@12088
   442
WINDOWS_JoystickGetDeviceInstanceID(int device_index)
slouken@8972
   443
{
slouken@8972
   444
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@8972
   445
    int index;
slouken@8972
   446
slouken@8972
   447
    for (index = device_index; index > 0; index--)
slouken@8972
   448
        device = device->pNext;
slouken@8972
   449
slouken@8972
   450
    return device->nInstanceID;
slouken@8972
   451
}
slouken@8972
   452
slouken@8972
   453
/* Function to open a joystick for use.
philipp@9380
   454
   The joystick to open is specified by the device index.
slouken@8972
   455
   This should fill the nbuttons and naxes fields of the joystick structure.
slouken@8972
   456
   It returns 0, or -1 if there is an error.
slouken@8972
   457
 */
slouken@12088
   458
static int
slouken@12088
   459
WINDOWS_JoystickOpen(SDL_Joystick * joystick, int device_index)
slouken@8972
   460
{
slouken@8972
   461
    JoyStick_DeviceData *joystickdevice = SYS_Joystick;
slouken@8972
   462
slouken@8972
   463
    for (; device_index > 0; device_index--)
slouken@8972
   464
        joystickdevice = joystickdevice->pNext;
slouken@8972
   465
slouken@8972
   466
    /* allocate memory for system specific hardware data */
slouken@8972
   467
    joystick->instance_id = joystickdevice->nInstanceID;
slouken@8972
   468
    joystick->hwdata =
slouken@8972
   469
        (struct joystick_hwdata *) SDL_malloc(sizeof(struct joystick_hwdata));
slouken@8972
   470
    if (joystick->hwdata == NULL) {
slouken@8972
   471
        return SDL_OutOfMemory();
slouken@8972
   472
    }
slouken@8972
   473
    SDL_zerop(joystick->hwdata);
slouken@8972
   474
    joystick->hwdata->guid = joystickdevice->guid;
slouken@8972
   475
slouken@8972
   476
    if (joystickdevice->bXInputDevice) {
slouken@8972
   477
        return SDL_XINPUT_JoystickOpen(joystick, joystickdevice);
slouken@8972
   478
    } else {
slouken@8972
   479
        return SDL_DINPUT_JoystickOpen(joystick, joystickdevice);
slouken@8972
   480
    }
slouken@8972
   481
}
slouken@8972
   482
slouken@12088
   483
static int
slouken@12088
   484
WINDOWS_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
slouken@12088
   485
{
slouken@12088
   486
    if (joystick->hwdata->bXInputDevice) {
slouken@12088
   487
        return SDL_XINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble, duration_ms);
slouken@12088
   488
    } else {
slouken@12088
   489
        return SDL_DINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble, duration_ms);
slouken@12088
   490
    }
slouken@12088
   491
}
slouken@12088
   492
slouken@12088
   493
static void
slouken@12088
   494
WINDOWS_JoystickUpdate(SDL_Joystick * joystick)
slouken@8972
   495
{
slouken@12090
   496
    if (!joystick->hwdata) {
slouken@8972
   497
        return;
slouken@8972
   498
    }
slouken@8972
   499
slouken@8972
   500
    if (joystick->hwdata->bXInputDevice) {
slouken@8972
   501
        SDL_XINPUT_JoystickUpdate(joystick);
slouken@8972
   502
    } else {
slouken@8972
   503
        SDL_DINPUT_JoystickUpdate(joystick);
slouken@8972
   504
    }
slouken@8972
   505
}
slouken@8972
   506
slouken@8972
   507
/* Function to close a joystick after use */
slouken@12088
   508
static void
slouken@12088
   509
WINDOWS_JoystickClose(SDL_Joystick * joystick)
slouken@8972
   510
{
slouken@8972
   511
    if (joystick->hwdata->bXInputDevice) {
slouken@8972
   512
        SDL_XINPUT_JoystickClose(joystick);
slouken@8972
   513
    } else {
slouken@8972
   514
        SDL_DINPUT_JoystickClose(joystick);
slouken@8972
   515
    }
slouken@8972
   516
slouken@8972
   517
    SDL_free(joystick->hwdata);
slouken@8972
   518
}
slouken@8972
   519
slouken@8972
   520
/* Function to perform any system-specific joystick related cleanup */
slouken@12088
   521
static void
slouken@12088
   522
WINDOWS_JoystickQuit(void)
slouken@8972
   523
{
slouken@8972
   524
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@8972
   525
slouken@8972
   526
    while (device) {
slouken@8972
   527
        JoyStick_DeviceData *device_next = device->pNext;
slouken@8972
   528
        SDL_free(device->joystickname);
slouken@8972
   529
        SDL_free(device);
slouken@8972
   530
        device = device_next;
slouken@8972
   531
    }
slouken@8972
   532
    SYS_Joystick = NULL;
slouken@8972
   533
slouken@8972
   534
    if (s_threadJoystick) {
slouken@8972
   535
        SDL_LockMutex(s_mutexJoyStickEnum);
slouken@8972
   536
        s_bJoystickThreadQuit = SDL_TRUE;
slouken@8972
   537
        SDL_CondBroadcast(s_condJoystickThread); /* signal the joystick thread to quit */
slouken@8972
   538
        SDL_UnlockMutex(s_mutexJoyStickEnum);
slouken@11470
   539
#ifndef __WINRT__
slouken@11470
   540
        PostThreadMessage(SDL_GetThreadID(s_threadJoystick), WM_QUIT, 0, 0);
slouken@11470
   541
#endif
slouken@8972
   542
        SDL_WaitThread(s_threadJoystick, NULL); /* wait for it to bugger off */
slouken@8972
   543
slouken@8972
   544
        SDL_DestroyMutex(s_mutexJoyStickEnum);
slouken@8972
   545
        SDL_DestroyCond(s_condJoystickThread);
slouken@8972
   546
        s_condJoystickThread= NULL;
slouken@8972
   547
        s_mutexJoyStickEnum = NULL;
slouken@8972
   548
        s_threadJoystick = NULL;
slouken@8972
   549
    }
slouken@8972
   550
slouken@8972
   551
    SDL_DINPUT_JoystickQuit();
slouken@8972
   552
    SDL_XINPUT_JoystickQuit();
slouken@10479
   553
slouken@10479
   554
    s_bDeviceAdded = SDL_FALSE;
slouken@10479
   555
    s_bDeviceRemoved = SDL_FALSE;
slouken@8972
   556
}
slouken@8972
   557
slouken@12088
   558
SDL_JoystickDriver SDL_WINDOWS_JoystickDriver =
slouken@8972
   559
{
slouken@12088
   560
    WINDOWS_JoystickInit,
slouken@12088
   561
    WINDOWS_JoystickGetCount,
slouken@12088
   562
    WINDOWS_JoystickDetect,
slouken@12088
   563
    WINDOWS_JoystickGetDeviceName,
slouken@12359
   564
    WINDOWS_JoystickGetDevicePlayerIndex,
slouken@13369
   565
    WINDOWS_JoystickSetDevicePlayerIndex,
slouken@12088
   566
    WINDOWS_JoystickGetDeviceGUID,
slouken@12088
   567
    WINDOWS_JoystickGetDeviceInstanceID,
slouken@12088
   568
    WINDOWS_JoystickOpen,
slouken@12088
   569
    WINDOWS_JoystickRumble,
slouken@12088
   570
    WINDOWS_JoystickUpdate,
slouken@12088
   571
    WINDOWS_JoystickClose,
slouken@12088
   572
    WINDOWS_JoystickQuit,
slouken@12088
   573
};
slouken@8972
   574
slouken@8972
   575
#endif /* SDL_JOYSTICK_DINPUT || SDL_JOYSTICK_XINPUT */
slouken@8972
   576
slouken@8972
   577
/* vi: set ts=4 sw=4 expandtab: */