src/joystick/windows/SDL_windowsjoystick.c
author Sam Lantinga
Fri, 29 May 2020 13:37:21 -0700
changeset 13872 75c33f89d791
parent 13480 6a144eb5e1f1
child 13873 5bb6be4f2425
permissions -rw-r--r--
Fixed bug 5161 - Autodetect controller mappings based on the Linux Gamepad Specification

Jan Bujak

I wrote a new driver for my gamepad on Linux. I'd like SDL to support it out-of-box, as currently it just treats it as a generic joystick instead of a gamepad. From what I can see the only way to do that is to either 1) pick one of the already supported controllers' PID, VID and button layouts and have my driver send that (effectively lying that it's something else), or 2) submit a preconfigured, hardcoded mapping to SDL.

Both of those, in my opinion, are silly when we already have the Linux Gamepad Specification which standarizes this:

https://www.kernel.org/doc/html/v4.15/input/gamepad.html

Unfortunately SDL doesn't make use of it currently. So I've took it upon myself to add it; patch is in the attachments.

Basically what the patch does is that if SDL finds no built-it controller mappings for a given joystick it then asks the joystick backend to autodetect it, and that uses the relevant evdev bits to figure out which button/axis is which. (See the specs for more details.)

With this patch applied my own driver for my controller works out-of-box with SDL with no extra configuration and is correctly recognized as a gamepad; this is also going to be the case for any other driver which follows the Linux Gamepad Specification.
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@13480
   484
WINDOWS_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
slouken@12088
   485
{
slouken@12088
   486
    if (joystick->hwdata->bXInputDevice) {
slouken@13480
   487
        return SDL_XINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble);
slouken@12088
   488
    } else {
slouken@13480
   489
        return SDL_DINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble);
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@13872
   558
static SDL_bool
slouken@13872
   559
WINDOWS_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
slouken@13872
   560
{
slouken@13872
   561
    return SDL_FALSE;
slouken@13872
   562
}
slouken@13872
   563
slouken@12088
   564
SDL_JoystickDriver SDL_WINDOWS_JoystickDriver =
slouken@8972
   565
{
slouken@12088
   566
    WINDOWS_JoystickInit,
slouken@12088
   567
    WINDOWS_JoystickGetCount,
slouken@12088
   568
    WINDOWS_JoystickDetect,
slouken@12088
   569
    WINDOWS_JoystickGetDeviceName,
slouken@12359
   570
    WINDOWS_JoystickGetDevicePlayerIndex,
slouken@13369
   571
    WINDOWS_JoystickSetDevicePlayerIndex,
slouken@12088
   572
    WINDOWS_JoystickGetDeviceGUID,
slouken@12088
   573
    WINDOWS_JoystickGetDeviceInstanceID,
slouken@12088
   574
    WINDOWS_JoystickOpen,
slouken@12088
   575
    WINDOWS_JoystickRumble,
slouken@12088
   576
    WINDOWS_JoystickUpdate,
slouken@12088
   577
    WINDOWS_JoystickClose,
slouken@12088
   578
    WINDOWS_JoystickQuit,
slouken@13872
   579
    WINDOWS_JoystickGetGamepadMapping
slouken@12088
   580
};
slouken@8972
   581
slouken@8972
   582
#endif /* SDL_JOYSTICK_DINPUT || SDL_JOYSTICK_XINPUT */
slouken@8972
   583
slouken@8972
   584
/* vi: set ts=4 sw=4 expandtab: */