src/joystick/windows/SDL_dxjoystick.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 28 Aug 2013 22:09:17 -0400
changeset 7712 66b5b8446275
parent 7711 db9e27a52d77
child 7719 31b5f9ff36ca
permissions -rw-r--r--
Change order we enumerate Windows joysticks.

Make it so XInput devices are listed before DirectInput devices, and that the XInput
devices are sorted by userid in ascending numeric order (so device 0 comes first).
slouken@1895
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6885
     3
  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
slouken@1895
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@1895
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@1895
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@1895
    20
*/
slouken@1895
    21
#include "SDL_config.h"
slouken@1895
    22
slouken@1895
    23
#ifdef SDL_JOYSTICK_DINPUT
slouken@1895
    24
slouken@1895
    25
/* DirectInput joystick driver; written by Glenn Maynard, based on Andrei de
slouken@7191
    26
 * A. Formiga's WINMM driver.
slouken@1895
    27
 *
slouken@1895
    28
 * Hats and sliders are completely untested; the app I'm writing this for mostly
slouken@7191
    29
 * doesn't use them and I don't own any joysticks with them.
slouken@1895
    30
 *
slouken@1895
    31
 * We don't bother to use event notification here.  It doesn't seem to work
slouken@6690
    32
 * with polled devices, and it's fine to call IDirectInputDevice8_GetDeviceData and
slouken@1895
    33
 * let it return 0 events. */
slouken@1895
    34
slouken@1895
    35
#include "SDL_error.h"
icculus@6993
    36
#include "SDL_assert.h"
slouken@1895
    37
#include "SDL_events.h"
slouken@6690
    38
#include "SDL_thread.h"
slouken@6690
    39
#include "SDL_timer.h"
slouken@6690
    40
#include "SDL_mutex.h"
slouken@6690
    41
#include "SDL_events.h"
slouken@6971
    42
#include "SDL_hints.h"
slouken@7260
    43
#include "SDL_joystick.h"
slouken@7260
    44
#include "../SDL_sysjoystick.h"
slouken@6690
    45
#if !SDL_EVENTS_DISABLED
slouken@6690
    46
#include "../../events/SDL_events_c.h"
slouken@6690
    47
#endif
slouken@1895
    48
slouken@7260
    49
#define INITGUID /* Only set here, if set twice will cause mingw32 to break. */
slouken@7260
    50
#include "SDL_dxjoystick_c.h"
slouken@7260
    51
slouken@2761
    52
#ifndef DIDFT_OPTIONAL
slouken@7191
    53
#define DIDFT_OPTIONAL      0x80000000
slouken@2761
    54
#endif
slouken@2761
    55
slouken@2761
    56
slouken@7191
    57
#define INPUT_QSIZE 32      /* Buffer up to 32 input messages */
slouken@7191
    58
#define AXIS_MIN    -32768  /* minimum value for axis coordinate */
slouken@7191
    59
#define AXIS_MAX    32767   /* maximum value for axis coordinate */
slouken@7191
    60
#define JOY_AXIS_THRESHOLD  (((AXIS_MAX)-(AXIS_MIN))/100)   /* 1% motion */
slouken@1895
    61
slouken@2198
    62
/* external variables referenced. */
slouken@2713
    63
extern HWND SDL_HelperWindow;
slouken@2198
    64
slouken@2198
    65
slouken@2198
    66
/* local variables */
icculus@5591
    67
static SDL_bool coinitialized = SDL_FALSE;
icculus@6716
    68
static LPDIRECTINPUT8 dinput = NULL;
slouken@6690
    69
static SDL_bool s_bDeviceAdded = SDL_FALSE;
slouken@6690
    70
static SDL_bool s_bDeviceRemoved = SDL_FALSE;
slouken@6974
    71
static SDL_JoystickID s_nInstanceID = -1;
slouken@6690
    72
static SDL_cond *s_condJoystickThread = NULL;
slouken@6690
    73
static SDL_mutex *s_mutexJoyStickEnum = NULL;
slouken@6690
    74
static SDL_Thread *s_threadJoystick = NULL;
slouken@6690
    75
static SDL_bool s_bJoystickThreadQuit = SDL_FALSE;
urkle@6965
    76
static SDL_bool s_bXInputEnabled = SDL_TRUE;
slouken@6690
    77
icculus@6991
    78
XInputGetState_t SDL_XInputGetState = NULL;
icculus@6991
    79
XInputSetState_t SDL_XInputSetState = NULL;
icculus@6991
    80
XInputGetCapabilities_t SDL_XInputGetCapabilities = NULL;
icculus@6991
    81
DWORD SDL_XInputVersion = 0;
icculus@6991
    82
icculus@6991
    83
static HANDLE s_pXInputDLL = 0;
icculus@6991
    84
static int s_XInputDLLRefCount = 0;
icculus@6991
    85
icculus@6991
    86
int
icculus@6991
    87
WIN_LoadXInputDLL(void)
icculus@6991
    88
{
icculus@6991
    89
    DWORD version = 0;
icculus@6991
    90
icculus@6991
    91
    if (s_pXInputDLL) {
icculus@6991
    92
        SDL_assert(s_XInputDLLRefCount > 0);
icculus@6991
    93
        s_XInputDLLRefCount++;
icculus@6991
    94
        return 0;  /* already loaded */
icculus@6991
    95
    }
icculus@6991
    96
icculus@6991
    97
    version = (1 << 16) | 4;
slouken@7191
    98
    s_pXInputDLL = LoadLibrary( L"XInput1_4.dll" );  /* 1.4 Ships with Windows 8. */
icculus@6991
    99
    if (!s_pXInputDLL) {
icculus@6991
   100
        version = (1 << 16) | 3;
slouken@7191
   101
        s_pXInputDLL = LoadLibrary( L"XInput1_3.dll" );  /* 1.3 Ships with Vista and Win7, can be installed as a redistributable component. */
icculus@6991
   102
    }
icculus@6991
   103
    if (!s_pXInputDLL) {
icculus@6991
   104
        s_pXInputDLL = LoadLibrary( L"bin\\XInput1_3.dll" );
icculus@6991
   105
    }
icculus@6991
   106
    if (!s_pXInputDLL) {
icculus@6991
   107
        return -1;
icculus@6991
   108
    }
icculus@6991
   109
icculus@6991
   110
    SDL_assert(s_XInputDLLRefCount == 0);
icculus@6991
   111
    SDL_XInputVersion = version;
icculus@6991
   112
    s_XInputDLLRefCount = 1;
icculus@6991
   113
icculus@6991
   114
    /* 100 is the ordinal for _XInputGetStateEx, which returns the same struct as XinputGetState, but with extra data in wButtons for the guide button, we think... */
icculus@6991
   115
    SDL_XInputGetState = (XInputGetState_t)GetProcAddress( (HMODULE)s_pXInputDLL, (LPCSTR)100 );
icculus@6991
   116
    SDL_XInputSetState = (XInputSetState_t)GetProcAddress( (HMODULE)s_pXInputDLL, "XInputSetState" );
icculus@6991
   117
    SDL_XInputGetCapabilities = (XInputGetCapabilities_t)GetProcAddress( (HMODULE)s_pXInputDLL, "XInputGetCapabilities" );
icculus@6991
   118
    if ( !SDL_XInputGetState || !SDL_XInputSetState || !SDL_XInputGetCapabilities ) {
icculus@6991
   119
        WIN_UnloadXInputDLL();
icculus@6991
   120
        return -1;
icculus@6991
   121
    }
icculus@6991
   122
icculus@6991
   123
    return 0;
icculus@6991
   124
}
icculus@6991
   125
icculus@6991
   126
void
icculus@6991
   127
WIN_UnloadXInputDLL(void)
icculus@6991
   128
{
icculus@6991
   129
    if ( s_pXInputDLL ) {
icculus@6991
   130
        SDL_assert(s_XInputDLLRefCount > 0);
icculus@6991
   131
        if (--s_XInputDLLRefCount == 0) {
icculus@6991
   132
            FreeLibrary( s_pXInputDLL );
icculus@6991
   133
            s_pXInputDLL = NULL;
icculus@6991
   134
        }
icculus@6991
   135
    } else {
icculus@6991
   136
        SDL_assert(s_XInputDLLRefCount == 0);
icculus@6991
   137
    }
icculus@6991
   138
}
icculus@6991
   139
icculus@6991
   140
slouken@2198
   141
extern HRESULT(WINAPI * DInputCreate) (HINSTANCE hinst, DWORD dwVersion,
slouken@2198
   142
                                       LPDIRECTINPUT * ppDI,
slouken@2198
   143
                                       LPUNKNOWN punkOuter);
slouken@6690
   144
struct JoyStick_DeviceData_
slouken@6690
   145
{
slouken@7191
   146
    SDL_JoystickGUID guid;
slouken@7191
   147
    DIDEVICEINSTANCE dxdevice;
slouken@7191
   148
    char *joystickname;
slouken@7191
   149
    Uint8 send_add_event;
slouken@7191
   150
    SDL_JoystickID nInstanceID;
slouken@7191
   151
    SDL_bool bXInputDevice;
slouken@7191
   152
    Uint8 XInputUserId;
slouken@7191
   153
    struct JoyStick_DeviceData_ *pNext;
slouken@6690
   154
};
slouken@2198
   155
slouken@6690
   156
typedef struct JoyStick_DeviceData_ JoyStick_DeviceData;
slouken@6690
   157
slouken@6690
   158
static JoyStick_DeviceData *SYS_Joystick;    /* array to hold joystick ID values */
slouken@6690
   159
slouken@2198
   160
/* local prototypes */
icculus@7037
   161
static int SetDIerror(const char *function, HRESULT code);
slouken@2198
   162
static BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE *
slouken@2198
   163
                                           pdidInstance, VOID * pContext);
slouken@2198
   164
static BOOL CALLBACK EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev,
slouken@2198
   165
                                            LPVOID pvRef);
slouken@6220
   166
static void SortDevObjects(SDL_Joystick *joystick);
slouken@2198
   167
static Uint8 TranslatePOV(DWORD value);
slouken@2198
   168
static int SDL_PrivateJoystickAxis_Int(SDL_Joystick * joystick, Uint8 axis,
slouken@2198
   169
                                       Sint16 value);
slouken@2198
   170
static int SDL_PrivateJoystickHat_Int(SDL_Joystick * joystick, Uint8 hat,
slouken@2198
   171
                                      Uint8 value);
slouken@2198
   172
static int SDL_PrivateJoystickButton_Int(SDL_Joystick * joystick,
slouken@2198
   173
                                         Uint8 button, Uint8 state);
slouken@2198
   174
slouken@7191
   175
/* Taken from Wine - Thanks! */
slouken@2760
   176
DIOBJECTDATAFORMAT dfDIJoystick2[] = {
slouken@3013
   177
  { &GUID_XAxis,DIJOFS_X,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   178
  { &GUID_YAxis,DIJOFS_Y,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   179
  { &GUID_ZAxis,DIJOFS_Z,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   180
  { &GUID_RxAxis,DIJOFS_RX,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   181
  { &GUID_RyAxis,DIJOFS_RY,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   182
  { &GUID_RzAxis,DIJOFS_RZ,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   183
  { &GUID_Slider,DIJOFS_SLIDER(0),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   184
  { &GUID_Slider,DIJOFS_SLIDER(1),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   185
  { &GUID_POV,DIJOFS_POV(0),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0},
slouken@3013
   186
  { &GUID_POV,DIJOFS_POV(1),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0},
slouken@3013
   187
  { &GUID_POV,DIJOFS_POV(2),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0},
slouken@3013
   188
  { &GUID_POV,DIJOFS_POV(3),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0},
slouken@3013
   189
  { NULL,DIJOFS_BUTTON(0),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   190
  { NULL,DIJOFS_BUTTON(1),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   191
  { NULL,DIJOFS_BUTTON(2),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   192
  { NULL,DIJOFS_BUTTON(3),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   193
  { NULL,DIJOFS_BUTTON(4),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   194
  { NULL,DIJOFS_BUTTON(5),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   195
  { NULL,DIJOFS_BUTTON(6),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   196
  { NULL,DIJOFS_BUTTON(7),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   197
  { NULL,DIJOFS_BUTTON(8),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   198
  { NULL,DIJOFS_BUTTON(9),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   199
  { NULL,DIJOFS_BUTTON(10),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   200
  { NULL,DIJOFS_BUTTON(11),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   201
  { NULL,DIJOFS_BUTTON(12),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   202
  { NULL,DIJOFS_BUTTON(13),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   203
  { NULL,DIJOFS_BUTTON(14),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   204
  { NULL,DIJOFS_BUTTON(15),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   205
  { NULL,DIJOFS_BUTTON(16),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   206
  { NULL,DIJOFS_BUTTON(17),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   207
  { NULL,DIJOFS_BUTTON(18),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   208
  { NULL,DIJOFS_BUTTON(19),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   209
  { NULL,DIJOFS_BUTTON(20),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   210
  { NULL,DIJOFS_BUTTON(21),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   211
  { NULL,DIJOFS_BUTTON(22),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   212
  { NULL,DIJOFS_BUTTON(23),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   213
  { NULL,DIJOFS_BUTTON(24),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   214
  { NULL,DIJOFS_BUTTON(25),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   215
  { NULL,DIJOFS_BUTTON(26),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   216
  { NULL,DIJOFS_BUTTON(27),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   217
  { NULL,DIJOFS_BUTTON(28),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   218
  { NULL,DIJOFS_BUTTON(29),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   219
  { NULL,DIJOFS_BUTTON(30),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   220
  { NULL,DIJOFS_BUTTON(31),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   221
  { NULL,DIJOFS_BUTTON(32),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   222
  { NULL,DIJOFS_BUTTON(33),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   223
  { NULL,DIJOFS_BUTTON(34),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   224
  { NULL,DIJOFS_BUTTON(35),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   225
  { NULL,DIJOFS_BUTTON(36),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   226
  { NULL,DIJOFS_BUTTON(37),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   227
  { NULL,DIJOFS_BUTTON(38),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   228
  { NULL,DIJOFS_BUTTON(39),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   229
  { NULL,DIJOFS_BUTTON(40),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   230
  { NULL,DIJOFS_BUTTON(41),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   231
  { NULL,DIJOFS_BUTTON(42),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   232
  { NULL,DIJOFS_BUTTON(43),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   233
  { NULL,DIJOFS_BUTTON(44),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   234
  { NULL,DIJOFS_BUTTON(45),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   235
  { NULL,DIJOFS_BUTTON(46),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   236
  { NULL,DIJOFS_BUTTON(47),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   237
  { NULL,DIJOFS_BUTTON(48),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   238
  { NULL,DIJOFS_BUTTON(49),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   239
  { NULL,DIJOFS_BUTTON(50),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   240
  { NULL,DIJOFS_BUTTON(51),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   241
  { NULL,DIJOFS_BUTTON(52),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   242
  { NULL,DIJOFS_BUTTON(53),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   243
  { NULL,DIJOFS_BUTTON(54),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   244
  { NULL,DIJOFS_BUTTON(55),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   245
  { NULL,DIJOFS_BUTTON(56),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   246
  { NULL,DIJOFS_BUTTON(57),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   247
  { NULL,DIJOFS_BUTTON(58),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   248
  { NULL,DIJOFS_BUTTON(59),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   249
  { NULL,DIJOFS_BUTTON(60),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   250
  { NULL,DIJOFS_BUTTON(61),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   251
  { NULL,DIJOFS_BUTTON(62),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   252
  { NULL,DIJOFS_BUTTON(63),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   253
  { NULL,DIJOFS_BUTTON(64),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   254
  { NULL,DIJOFS_BUTTON(65),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   255
  { NULL,DIJOFS_BUTTON(66),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   256
  { NULL,DIJOFS_BUTTON(67),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   257
  { NULL,DIJOFS_BUTTON(68),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   258
  { NULL,DIJOFS_BUTTON(69),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   259
  { NULL,DIJOFS_BUTTON(70),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   260
  { NULL,DIJOFS_BUTTON(71),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   261
  { NULL,DIJOFS_BUTTON(72),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   262
  { NULL,DIJOFS_BUTTON(73),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   263
  { NULL,DIJOFS_BUTTON(74),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   264
  { NULL,DIJOFS_BUTTON(75),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   265
  { NULL,DIJOFS_BUTTON(76),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   266
  { NULL,DIJOFS_BUTTON(77),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   267
  { NULL,DIJOFS_BUTTON(78),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   268
  { NULL,DIJOFS_BUTTON(79),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   269
  { NULL,DIJOFS_BUTTON(80),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   270
  { NULL,DIJOFS_BUTTON(81),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   271
  { NULL,DIJOFS_BUTTON(82),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   272
  { NULL,DIJOFS_BUTTON(83),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   273
  { NULL,DIJOFS_BUTTON(84),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   274
  { NULL,DIJOFS_BUTTON(85),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   275
  { NULL,DIJOFS_BUTTON(86),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   276
  { NULL,DIJOFS_BUTTON(87),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   277
  { NULL,DIJOFS_BUTTON(88),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   278
  { NULL,DIJOFS_BUTTON(89),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   279
  { NULL,DIJOFS_BUTTON(90),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   280
  { NULL,DIJOFS_BUTTON(91),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   281
  { NULL,DIJOFS_BUTTON(92),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   282
  { NULL,DIJOFS_BUTTON(93),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   283
  { NULL,DIJOFS_BUTTON(94),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   284
  { NULL,DIJOFS_BUTTON(95),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   285
  { NULL,DIJOFS_BUTTON(96),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   286
  { NULL,DIJOFS_BUTTON(97),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   287
  { NULL,DIJOFS_BUTTON(98),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   288
  { NULL,DIJOFS_BUTTON(99),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   289
  { NULL,DIJOFS_BUTTON(100),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   290
  { NULL,DIJOFS_BUTTON(101),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   291
  { NULL,DIJOFS_BUTTON(102),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   292
  { NULL,DIJOFS_BUTTON(103),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   293
  { NULL,DIJOFS_BUTTON(104),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   294
  { NULL,DIJOFS_BUTTON(105),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   295
  { NULL,DIJOFS_BUTTON(106),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   296
  { NULL,DIJOFS_BUTTON(107),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   297
  { NULL,DIJOFS_BUTTON(108),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   298
  { NULL,DIJOFS_BUTTON(109),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   299
  { NULL,DIJOFS_BUTTON(110),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   300
  { NULL,DIJOFS_BUTTON(111),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   301
  { NULL,DIJOFS_BUTTON(112),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   302
  { NULL,DIJOFS_BUTTON(113),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   303
  { NULL,DIJOFS_BUTTON(114),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   304
  { NULL,DIJOFS_BUTTON(115),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   305
  { NULL,DIJOFS_BUTTON(116),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   306
  { NULL,DIJOFS_BUTTON(117),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   307
  { NULL,DIJOFS_BUTTON(118),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   308
  { NULL,DIJOFS_BUTTON(119),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   309
  { NULL,DIJOFS_BUTTON(120),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   310
  { NULL,DIJOFS_BUTTON(121),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   311
  { NULL,DIJOFS_BUTTON(122),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   312
  { NULL,DIJOFS_BUTTON(123),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   313
  { NULL,DIJOFS_BUTTON(124),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   314
  { NULL,DIJOFS_BUTTON(125),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   315
  { NULL,DIJOFS_BUTTON(126),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   316
  { NULL,DIJOFS_BUTTON(127),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   317
  { &GUID_XAxis,FIELD_OFFSET(DIJOYSTATE2,lVX),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   318
  { &GUID_YAxis,FIELD_OFFSET(DIJOYSTATE2,lVY),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   319
  { &GUID_ZAxis,FIELD_OFFSET(DIJOYSTATE2,lVZ),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   320
  { &GUID_RxAxis,FIELD_OFFSET(DIJOYSTATE2,lVRx),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   321
  { &GUID_RyAxis,FIELD_OFFSET(DIJOYSTATE2,lVRy),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   322
  { &GUID_RzAxis,FIELD_OFFSET(DIJOYSTATE2,lVRz),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   323
  { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglVSlider[0]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   324
  { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglVSlider[1]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   325
  { &GUID_XAxis,FIELD_OFFSET(DIJOYSTATE2,lAX),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   326
  { &GUID_YAxis,FIELD_OFFSET(DIJOYSTATE2,lAY),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   327
  { &GUID_ZAxis,FIELD_OFFSET(DIJOYSTATE2,lAZ),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   328
  { &GUID_RxAxis,FIELD_OFFSET(DIJOYSTATE2,lARx),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   329
  { &GUID_RyAxis,FIELD_OFFSET(DIJOYSTATE2,lARy),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   330
  { &GUID_RzAxis,FIELD_OFFSET(DIJOYSTATE2,lARz),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   331
  { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglASlider[0]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   332
  { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglASlider[1]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   333
  { &GUID_XAxis,FIELD_OFFSET(DIJOYSTATE2,lFX),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   334
  { &GUID_YAxis,FIELD_OFFSET(DIJOYSTATE2,lFY),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   335
  { &GUID_ZAxis,FIELD_OFFSET(DIJOYSTATE2,lFZ),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   336
  { &GUID_RxAxis,FIELD_OFFSET(DIJOYSTATE2,lFRx),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   337
  { &GUID_RyAxis,FIELD_OFFSET(DIJOYSTATE2,lFRy),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   338
  { &GUID_RzAxis,FIELD_OFFSET(DIJOYSTATE2,lFRz),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   339
  { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglFSlider[0]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   340
  { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglFSlider[1]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@2760
   341
};
slouken@2760
   342
slouken@2760
   343
const DIDATAFORMAT c_dfDIJoystick2 = {
slouken@2760
   344
    sizeof(DIDATAFORMAT),
slouken@2760
   345
    sizeof(DIOBJECTDATAFORMAT),
slouken@2760
   346
    DIDF_ABSAXIS,
slouken@2760
   347
    sizeof(DIJOYSTATE2),
slouken@2760
   348
    SDL_arraysize(dfDIJoystick2),
slouken@2760
   349
    dfDIJoystick2
slouken@2760
   350
};
slouken@2760
   351
slouken@2198
   352
slouken@1895
   353
/* Convert a DirectInput return code to a text message */
icculus@7037
   354
static int
slouken@2198
   355
SetDIerror(const char *function, HRESULT code)
slouken@1895
   356
{
slouken@2760
   357
    /*
icculus@7037
   358
    return SDL_SetError("%s() [%s]: %s", function,
slouken@3013
   359
                 DXGetErrorString9A(code), DXGetErrorDescription9A(code));
slouken@2760
   360
     */
icculus@7037
   361
    return SDL_SetError("%s() DirectX error %d", function, code);
slouken@1895
   362
}
slouken@1895
   363
slouken@1895
   364
slouken@6690
   365
#define SAFE_RELEASE(p)                             \
slouken@6690
   366
{                                                   \
slouken@7191
   367
    if (p) {                                        \
slouken@7191
   368
        (p)->lpVtbl->Release((p));                  \
slouken@7191
   369
        (p) = 0;                                    \
slouken@7191
   370
    }                                               \
slouken@6690
   371
}
slouken@6690
   372
icculus@7706
   373
DEFINE_GUID(IID_ValveStreamingGamepad,  MAKELONG( 0x28DE, 0x11FF ),0x0000,0x0000,0x00,0x00,0x50,0x49,0x44,0x56,0x49,0x44);
icculus@7706
   374
DEFINE_GUID(IID_X360WiredGamepad,  MAKELONG( 0x045E, 0x02A1 ),0x0000,0x0000,0x00,0x00,0x50,0x49,0x44,0x56,0x49,0x44);
icculus@7706
   375
DEFINE_GUID(IID_X360WirelessGamepad,  MAKELONG( 0x045E, 0x028E ),0x0000,0x0000,0x00,0x00,0x50,0x49,0x44,0x56,0x49,0x44);
slouken@6690
   376
icculus@7706
   377
static PRAWINPUTDEVICELIST SDL_RawDevList = NULL;
icculus@7706
   378
static UINT SDL_RawDevListCount = 0;
slouken@6690
   379
icculus@7706
   380
static SDL_bool
icculus@7706
   381
SDL_IsXInputDevice( const GUID* pGuidProductFromDirectInput )
slouken@6690
   382
{
slouken@7299
   383
    static const GUID *s_XInputProductGUID[] = {
icculus@7706
   384
        &IID_ValveStreamingGamepad,
icculus@7706
   385
        &IID_X360WiredGamepad,   /* Microsoft's wired X360 controller for Windows. */
icculus@7706
   386
        &IID_X360WirelessGamepad /* Microsoft's wireless X360 controller for Windows. */
slouken@7299
   387
    };
slouken@6690
   388
icculus@7706
   389
    size_t iDevice;
icculus@7706
   390
    SDL_bool retval = SDL_FALSE;
icculus@7706
   391
    UINT i;
icculus@7706
   392
icculus@7706
   393
    if (!s_bXInputEnabled) {
urkle@6965
   394
        return SDL_FALSE;
urkle@6965
   395
    }
urkle@6965
   396
gabomdq@7663
   397
    /* Check for well known XInput device GUIDs */
icculus@7706
   398
    /* This lets us skip RAWINPUT for popular devices. Also, we need to do this for the Valve Streaming Gamepad because it's virtualized and doesn't show up in the device list. */
slouken@7299
   399
    for ( iDevice = 0; iDevice < SDL_arraysize(s_XInputProductGUID); ++iDevice ) {
slouken@7299
   400
        if (SDL_memcmp(pGuidProductFromDirectInput, s_XInputProductGUID[iDevice], sizeof(GUID)) == 0) {
slouken@7299
   401
            return SDL_TRUE;
slouken@7299
   402
        }
slouken@7299
   403
    }
slouken@7299
   404
icculus@7706
   405
    /* Go through RAWINPUT (WinXP and later) to find HID devices. */
icculus@7706
   406
    /* Cache this if we end up using it. */
icculus@7706
   407
    if (SDL_RawDevList == NULL) {
icculus@7706
   408
        if ((GetRawInputDeviceList(NULL, &SDL_RawDevListCount, sizeof (RAWINPUTDEVICELIST)) == -1) || (!SDL_RawDevListCount)) {
icculus@7706
   409
            return SDL_FALSE;  /* oh well. */
icculus@7706
   410
        }
slouken@6690
   411
icculus@7706
   412
        SDL_RawDevList = (PRAWINPUTDEVICELIST) SDL_malloc(sizeof (RAWINPUTDEVICELIST) * SDL_RawDevListCount);
icculus@7706
   413
        if (SDL_RawDevList == NULL) {
icculus@7706
   414
            SDL_OutOfMemory();
icculus@7706
   415
            return SDL_FALSE;
icculus@7706
   416
        }
slouken@6690
   417
icculus@7706
   418
        if (GetRawInputDeviceList(SDL_RawDevList, &SDL_RawDevListCount, sizeof (RAWINPUTDEVICELIST)) == -1) {
icculus@7706
   419
             SDL_free(SDL_RawDevList);
icculus@7706
   420
             SDL_RawDevList = NULL;
icculus@7706
   421
             return SDL_FALSE;  /* oh well. */
slouken@7191
   422
        }
slouken@7191
   423
    }
slouken@7191
   424
icculus@7706
   425
    for (i = 0; i < SDL_RawDevListCount; i++) {
icculus@7706
   426
        RID_DEVICE_INFO rdi;
icculus@7706
   427
        char devName[128];
icculus@7706
   428
        UINT rdiSize = sizeof (rdi);
icculus@7706
   429
        UINT nameSize = SDL_arraysize(devName);
slouken@6690
   430
icculus@7706
   431
        rdi.cbSize = sizeof (rdi);
icculus@7706
   432
        if ( (SDL_RawDevList[i].dwType == RIM_TYPEHID) &&
icculus@7706
   433
             (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != ((UINT)-1)) &&
icculus@7706
   434
             (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == ((LONG)pGuidProductFromDirectInput->Data1)) &&
icculus@7706
   435
             (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != ((UINT)-1)) &&
icculus@7706
   436
             (SDL_strstr(devName, "IG_") != NULL) ) {
icculus@7706
   437
             return SDL_TRUE;
icculus@7706
   438
        }
icculus@7706
   439
    }
slouken@6690
   440
icculus@7706
   441
    return SDL_FALSE;
slouken@6690
   442
}
slouken@6690
   443
slouken@6690
   444
slouken@6690
   445
static SDL_bool s_bWindowsDeviceChanged = SDL_FALSE;
slouken@6690
   446
philipp@7133
   447
/* windowproc for our joystick detect thread message only window, to detect any USB device addition/removal
slouken@6690
   448
 */
slouken@6690
   449
LRESULT CALLBACK SDL_PrivateJoystickDetectProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)    {
slouken@7191
   450
    switch (message)    {
slouken@7191
   451
    case WM_DEVICECHANGE:
slouken@7191
   452
        switch (wParam) {
slouken@7191
   453
        case DBT_DEVICEARRIVAL:
slouken@7191
   454
            if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)    {
slouken@7191
   455
                s_bWindowsDeviceChanged = SDL_TRUE;
slouken@7191
   456
            }
slouken@7191
   457
            break;
slouken@7191
   458
        case DBT_DEVICEREMOVECOMPLETE:
slouken@7191
   459
            if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)    {
slouken@7191
   460
                s_bWindowsDeviceChanged = SDL_TRUE;
slouken@7191
   461
            }
slouken@7191
   462
            break;
slouken@7191
   463
        }
slouken@7191
   464
        return 0;
slouken@7191
   465
    }
slouken@6690
   466
slouken@7191
   467
    return DefWindowProc (hwnd, message, wParam, lParam);
slouken@6690
   468
}
slouken@6690
   469
slouken@6690
   470
slouken@6690
   471
DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, \
slouken@7191
   472
    0xC0, 0x4F, 0xB9, 0x51, 0xED);
slouken@6690
   473
slouken@6690
   474
/* Function/thread to scan the system for joysticks.
slouken@6690
   475
 */
slouken@6690
   476
static int
slouken@6690
   477
SDL_JoystickThread(void *_data)
slouken@6690
   478
{
slouken@7191
   479
    HWND messageWindow = 0;
slouken@7191
   480
    HDEVNOTIFY hNotify = 0;
slouken@7191
   481
    DEV_BROADCAST_DEVICEINTERFACE dbh;
icculus@7707
   482
    SDL_bool bOpenedXInputDevices[SDL_XINPUT_MAX_DEVICES];
slouken@7191
   483
    WNDCLASSEX wincl;
slouken@6710
   484
icculus@7707
   485
    SDL_zero(bOpenedXInputDevices);
slouken@6690
   486
slouken@7223
   487
    WIN_CoInitialize();
slouken@6690
   488
slouken@7191
   489
    SDL_memset( &wincl, 0x0, sizeof(wincl) );
slouken@7191
   490
    wincl.hInstance = GetModuleHandle( NULL );
slouken@7191
   491
    wincl.lpszClassName = L"Message";
slouken@7191
   492
    wincl.lpfnWndProc = SDL_PrivateJoystickDetectProc;      /* This function is called by windows */
slouken@7191
   493
    wincl.cbSize = sizeof (WNDCLASSEX);
slouken@6712
   494
slouken@7191
   495
    if (!RegisterClassEx (&wincl))
slouken@7191
   496
    {
slouken@7191
   497
        return SDL_SetError("Failed to create register class for joystick autodetect.", GetLastError());
slouken@7191
   498
    }
slouken@6712
   499
slouken@7191
   500
    messageWindow = (HWND)CreateWindowEx( 0,  L"Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL );
slouken@7191
   501
    if ( !messageWindow )
slouken@7191
   502
    {
slouken@7191
   503
        return SDL_SetError("Failed to create message window for joystick autodetect.", GetLastError());
slouken@7191
   504
    }
slouken@6690
   505
icculus@7707
   506
    SDL_zero(dbh);
slouken@6690
   507
slouken@7191
   508
    dbh.dbcc_size = sizeof(dbh);
slouken@7191
   509
    dbh.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
slouken@7191
   510
    dbh.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE;
slouken@6690
   511
slouken@7191
   512
    hNotify = RegisterDeviceNotification( messageWindow, &dbh, DEVICE_NOTIFY_WINDOW_HANDLE );
slouken@7191
   513
    if ( !hNotify )
slouken@7191
   514
    {
slouken@7191
   515
        return SDL_SetError("Failed to create notify device for joystick autodetect.", GetLastError());
slouken@7191
   516
    }
slouken@6690
   517
slouken@7191
   518
    SDL_LockMutex( s_mutexJoyStickEnum );
slouken@7191
   519
    while ( s_bJoystickThreadQuit == SDL_FALSE )
slouken@7191
   520
    {
slouken@7191
   521
        MSG messages;
icculus@7707
   522
        SDL_bool bXInputChanged = SDL_FALSE;
icculus@7707
   523
slouken@7191
   524
        SDL_CondWaitTimeout( s_condJoystickThread, s_mutexJoyStickEnum, 300 );
slouken@6690
   525
slouken@7191
   526
        while ( s_bJoystickThreadQuit == SDL_FALSE && PeekMessage(&messages, messageWindow, 0, 0, PM_NOREMOVE) )
slouken@7191
   527
        {
slouken@7191
   528
            if ( GetMessage(&messages, messageWindow, 0, 0) != 0 )  {
slouken@7191
   529
                TranslateMessage(&messages);
slouken@7191
   530
                DispatchMessage(&messages);
slouken@7191
   531
            }
slouken@7191
   532
        }
slouken@6690
   533
icculus@7707
   534
        if ( s_bXInputEnabled && XINPUTGETCAPABILITIES ) {
slouken@7191
   535
            /* scan for any change in XInput devices */
icculus@7707
   536
            Uint8 userId;
icculus@7707
   537
            for (userId = 0; userId < SDL_XINPUT_MAX_DEVICES; userId++) {
slouken@7191
   538
                XINPUT_CAPABILITIES capabilities;
icculus@7707
   539
                const DWORD result = XINPUTGETCAPABILITIES( userId, XINPUT_FLAG_GAMEPAD, &capabilities );
icculus@7707
   540
                const SDL_bool available = (result == ERROR_SUCCESS);
icculus@7707
   541
                if (bOpenedXInputDevices[userId] != available) {
icculus@7707
   542
                    bXInputChanged = SDL_TRUE;
icculus@7707
   543
                    bOpenedXInputDevices[userId] = available;
slouken@7191
   544
                }
slouken@7191
   545
            }
slouken@7191
   546
        }
slouken@6710
   547
icculus@7707
   548
        if (s_bWindowsDeviceChanged || bXInputChanged) {
icculus@7707
   549
            SDL_UnlockMutex( s_mutexJoyStickEnum );  /* let main thread go while we SDL_Delay(). */
slouken@7191
   550
            SDL_Delay( 300 ); /* wait for direct input to find out about this device */
icculus@7707
   551
            SDL_LockMutex( s_mutexJoyStickEnum );
slouken@6690
   552
slouken@7191
   553
            s_bDeviceRemoved = SDL_TRUE;
slouken@7191
   554
            s_bDeviceAdded = SDL_TRUE;
slouken@7191
   555
            s_bWindowsDeviceChanged = SDL_FALSE;
slouken@7191
   556
        }
slouken@7191
   557
    }
slouken@7191
   558
    SDL_UnlockMutex( s_mutexJoyStickEnum );
slouken@6690
   559
slouken@7191
   560
    if ( hNotify )
slouken@7191
   561
        UnregisterDeviceNotification( hNotify );
slouken@6690
   562
slouken@7191
   563
    if ( messageWindow )
slouken@7191
   564
        DestroyWindow( messageWindow );
slouken@6712
   565
slouken@7191
   566
    UnregisterClass( wincl.lpszClassName, wincl.hInstance );
slouken@7191
   567
    messageWindow = 0;
slouken@7191
   568
    WIN_CoUninitialize();
slouken@7191
   569
    return 1;
slouken@6690
   570
}
slouken@6690
   571
slouken@6690
   572
slouken@1895
   573
/* Function to scan the system for joysticks.
slouken@1895
   574
 * This function should set SDL_numjoysticks to the number of available
slouken@1895
   575
 * joysticks.  Joystick 0 should be the system default joystick.
slouken@1895
   576
 * It should return 0, or -1 on an unrecoverable fatal error.
slouken@1895
   577
 */
slouken@1895
   578
int
slouken@1895
   579
SDL_SYS_JoystickInit(void)
slouken@1895
   580
{
slouken@1895
   581
    HRESULT result;
slouken@2713
   582
    HINSTANCE instance;
slouken@7191
   583
    const char *env = SDL_GetHint(SDL_HINT_XINPUT_ENABLED);
slouken@7191
   584
    if (env && !SDL_atoi(env)) {
slouken@7191
   585
        s_bXInputEnabled = SDL_FALSE;
slouken@7191
   586
    }
slouken@1895
   587
icculus@5591
   588
    result = WIN_CoInitialize();
slouken@2198
   589
    if (FAILED(result)) {
icculus@7037
   590
        return SetDIerror("CoInitialize", result);
slouken@1895
   591
    }
slouken@1895
   592
icculus@5591
   593
    coinitialized = SDL_TRUE;
icculus@5591
   594
slouken@6690
   595
    result = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER,
slouken@6690
   596
                              &IID_IDirectInput8, (LPVOID)&dinput);
slouken@2198
   597
slouken@2198
   598
    if (FAILED(result)) {
icculus@5591
   599
        SDL_SYS_JoystickQuit();
icculus@7037
   600
        return SetDIerror("CoCreateInstance", result);
slouken@2198
   601
    }
slouken@2198
   602
slouken@2198
   603
    /* Because we used CoCreateInstance, we need to Initialize it, first. */
slouken@2713
   604
    instance = GetModuleHandle(NULL);
slouken@2713
   605
    if (instance == NULL) {
icculus@5591
   606
        SDL_SYS_JoystickQuit();
icculus@7037
   607
        return SDL_SetError("GetModuleHandle() failed with error code %d.", GetLastError());
slouken@2713
   608
    }
slouken@6690
   609
    result = IDirectInput8_Initialize(dinput, instance, DIRECTINPUT_VERSION);
slouken@2198
   610
slouken@2198
   611
    if (FAILED(result)) {
icculus@5591
   612
        SDL_SYS_JoystickQuit();
icculus@7037
   613
        return SetDIerror("IDirectInput::Initialize", result);
slouken@2198
   614
    }
slouken@2198
   615
icculus@7707
   616
    if ((s_bXInputEnabled) && (WIN_LoadXInputDLL() == -1)) {
icculus@7707
   617
        s_bXInputEnabled = SDL_FALSE;  /* oh well. */
icculus@7707
   618
    }
icculus@7707
   619
icculus@6990
   620
    s_mutexJoyStickEnum = SDL_CreateMutex();
icculus@6990
   621
    s_condJoystickThread = SDL_CreateCond();
slouken@7191
   622
    s_bDeviceAdded = SDL_TRUE; /* force a scan of the system for joysticks this first time */
icculus@7707
   623
icculus@6990
   624
    SDL_SYS_JoystickDetect();
slouken@1895
   625
slouken@7191
   626
    if ( !s_threadJoystick )
slouken@7191
   627
    {
slouken@7191
   628
        s_bJoystickThreadQuit = SDL_FALSE;
slouken@7191
   629
        /* spin up the thread to detect hotplug of devices */
slouken@6690
   630
#if defined(__WIN32__) && !defined(HAVE_LIBC)
slouken@6690
   631
#undef SDL_CreateThread
slouken@7191
   632
        s_threadJoystick= SDL_CreateThread( SDL_JoystickThread, "SDL_joystick", NULL, NULL, NULL );
slouken@6690
   633
#else
slouken@7191
   634
        s_threadJoystick = SDL_CreateThread( SDL_JoystickThread, "SDL_joystick", NULL );
slouken@6690
   635
#endif
slouken@7191
   636
    }
slouken@7191
   637
        return SDL_SYS_NumJoysticks();
slouken@2198
   638
}
slouken@2198
   639
slouken@6707
   640
/* return the number of joysticks that are connected right now */
slouken@6707
   641
int SDL_SYS_NumJoysticks()
slouken@6707
   642
{
slouken@7191
   643
    int nJoysticks = 0;
slouken@7191
   644
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@7191
   645
    while ( device )
slouken@7191
   646
    {
slouken@7191
   647
        nJoysticks++;
slouken@7191
   648
        device = device->pNext;
slouken@7191
   649
    }
slouken@6707
   650
slouken@7191
   651
    return nJoysticks;
slouken@6707
   652
}
slouken@6707
   653
slouken@6707
   654
/* helper function for direct input, gets called for each connected joystick */
slouken@6707
   655
static BOOL CALLBACK
slouken@7191
   656
    EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
slouken@6707
   657
{
slouken@7191
   658
    JoyStick_DeviceData *pNewJoystick;
slouken@7191
   659
    JoyStick_DeviceData *pPrevJoystick = NULL;
icculus@7707
   660
icculus@7707
   661
    if (SDL_IsXInputDevice( &pdidInstance->guidProduct )) {
icculus@7707
   662
        return DIENUM_CONTINUE;  /* ignore XInput devices here, keep going. */
icculus@7707
   663
    }
icculus@7707
   664
slouken@7191
   665
    pNewJoystick = *(JoyStick_DeviceData **)pContext;
slouken@7191
   666
    while ( pNewJoystick )
slouken@7191
   667
    {
slouken@7191
   668
        if ( !SDL_memcmp( &pNewJoystick->dxdevice.guidInstance, &pdidInstance->guidInstance, sizeof(pNewJoystick->dxdevice.guidInstance) ) )
slouken@7191
   669
        {
slouken@7191
   670
            /* if we are replacing the front of the list then update it */
slouken@7191
   671
            if ( pNewJoystick == *(JoyStick_DeviceData **)pContext )
slouken@7191
   672
            {
slouken@7191
   673
                *(JoyStick_DeviceData **)pContext = pNewJoystick->pNext;
slouken@7191
   674
            }
slouken@7191
   675
            else if ( pPrevJoystick )
slouken@7191
   676
            {
slouken@7191
   677
                pPrevJoystick->pNext = pNewJoystick->pNext;
slouken@7191
   678
            }
slouken@6712
   679
slouken@7191
   680
            pNewJoystick->pNext = SYS_Joystick;
slouken@7191
   681
            SYS_Joystick = pNewJoystick;
slouken@6707
   682
icculus@7707
   683
            return DIENUM_CONTINUE; /* already have this joystick loaded, just keep going */
slouken@7191
   684
        }
slouken@6707
   685
slouken@7191
   686
        pPrevJoystick = pNewJoystick;
slouken@7191
   687
        pNewJoystick = pNewJoystick->pNext;
slouken@7191
   688
    }
slouken@6707
   689
icculus@7707
   690
    pNewJoystick = (JoyStick_DeviceData *)SDL_malloc( sizeof(JoyStick_DeviceData) );
icculus@7707
   691
    if (!pNewJoystick) {
icculus@7707
   692
        return DIENUM_CONTINUE; /* better luck next time? */
icculus@7707
   693
    }
slouken@6707
   694
icculus@7707
   695
    SDL_zerop(pNewJoystick);
icculus@7707
   696
    pNewJoystick->joystickname = WIN_StringToUTF8(pdidInstance->tszProductName);
icculus@7707
   697
    if (!pNewJoystick->joystickname) {
icculus@7707
   698
        SDL_free(pNewJoystick);
icculus@7707
   699
        return DIENUM_CONTINUE; /* better luck next time? */
slouken@7191
   700
    }
slouken@6712
   701
slouken@7191
   702
    SDL_memcpy(&(pNewJoystick->dxdevice), pdidInstance,
slouken@7191
   703
        sizeof(DIDEVICEINSTANCE));
slouken@6707
   704
icculus@7707
   705
    pNewJoystick->XInputUserId = INVALID_XINPUT_USERID;
slouken@7191
   706
    pNewJoystick->send_add_event = 1;
slouken@7191
   707
    pNewJoystick->nInstanceID = ++s_nInstanceID;
slouken@7191
   708
    SDL_memcpy( &pNewJoystick->guid, &pdidInstance->guidProduct, sizeof(pNewJoystick->guid) );
icculus@7707
   709
    pNewJoystick->pNext = SYS_Joystick;
slouken@7191
   710
    SYS_Joystick = pNewJoystick;
slouken@6707
   711
icculus@7707
   712
    s_bDeviceAdded = SDL_TRUE;
slouken@7191
   713
icculus@7707
   714
    return DIENUM_CONTINUE; /* get next device, please */
slouken@6707
   715
}
slouken@6707
   716
icculus@7707
   717
static void
icculus@7707
   718
AddXInputDevice(const Uint8 userid, JoyStick_DeviceData **pContext)
icculus@7707
   719
{
icculus@7707
   720
    char name[32];
icculus@7707
   721
    JoyStick_DeviceData *pPrevJoystick = NULL;
icculus@7707
   722
    JoyStick_DeviceData *pNewJoystick = *pContext;
icculus@7707
   723
icculus@7707
   724
    while (pNewJoystick) {
icculus@7707
   725
        if ((pNewJoystick->bXInputDevice) && (pNewJoystick->XInputUserId == userid)) {
icculus@7707
   726
            /* if we are replacing the front of the list then update it */
icculus@7707
   727
            if (pNewJoystick == *pContext) {
icculus@7707
   728
                *pContext = pNewJoystick->pNext;
icculus@7707
   729
            } else if (pPrevJoystick) {
icculus@7707
   730
                pPrevJoystick->pNext = pNewJoystick->pNext;
icculus@7707
   731
            }
icculus@7707
   732
icculus@7707
   733
            pNewJoystick->pNext = SYS_Joystick;
icculus@7707
   734
            SYS_Joystick = pNewJoystick;
icculus@7707
   735
        }
icculus@7707
   736
icculus@7707
   737
        pPrevJoystick = pNewJoystick;
icculus@7707
   738
        pNewJoystick = pNewJoystick->pNext;
icculus@7707
   739
        return;   /* already in the list. */
icculus@7707
   740
    }
icculus@7707
   741
icculus@7707
   742
    pNewJoystick = (JoyStick_DeviceData *) SDL_malloc(sizeof (JoyStick_DeviceData));
icculus@7707
   743
    if (!pNewJoystick) {
icculus@7707
   744
        return; /* better luck next time? */
icculus@7707
   745
    }
icculus@7707
   746
    SDL_zerop(pNewJoystick);
icculus@7707
   747
icculus@7709
   748
    SDL_snprintf(name, sizeof (name), "XInput Controller #%u", ((unsigned int) userid) + 1);
icculus@7707
   749
    pNewJoystick->joystickname = SDL_strdup(name);
icculus@7707
   750
    if (!pNewJoystick->joystickname) {
icculus@7707
   751
        SDL_free(pNewJoystick);
icculus@7707
   752
        return; /* better luck next time? */
icculus@7707
   753
    }
icculus@7707
   754
icculus@7707
   755
    pNewJoystick->bXInputDevice = SDL_TRUE;
icculus@7707
   756
    pNewJoystick->XInputUserId = userid;
icculus@7707
   757
    pNewJoystick->send_add_event = 1;
icculus@7707
   758
    pNewJoystick->nInstanceID = ++s_nInstanceID;
icculus@7707
   759
    pNewJoystick->pNext = SYS_Joystick;
icculus@7707
   760
    SYS_Joystick = pNewJoystick;
icculus@7707
   761
icculus@7707
   762
    s_bDeviceAdded = SDL_TRUE;
icculus@7707
   763
}
icculus@7707
   764
icculus@7707
   765
static void
icculus@7707
   766
EnumXInputDevices(JoyStick_DeviceData **pContext)
icculus@7707
   767
{
icculus@7707
   768
    if (s_bXInputEnabled) {
icculus@7712
   769
        int iuserid;
icculus@7712
   770
        /* iterate in reverse, so these are in the final list in ascending numeric order. */
icculus@7712
   771
        for (iuserid = SDL_XINPUT_MAX_DEVICES-1; iuserid >= 0; iuserid--) {
icculus@7712
   772
            const Uint8 userid = (Uint8) iuserid;
icculus@7707
   773
            XINPUT_CAPABILITIES capabilities;
icculus@7707
   774
            if (XINPUTGETCAPABILITIES(userid, XINPUT_FLAG_GAMEPAD, &capabilities) == ERROR_SUCCESS) {
icculus@7707
   775
                /* Current version of XInput mistakenly returns 0 as the Type. Ignore it and ensure the subtype is a gamepad. */
icculus@7707
   776
                /* !!! FIXME: we might want to support steering wheels or guitars or whatever laster. */
icculus@7707
   777
                if (capabilities.SubType == XINPUT_DEVSUBTYPE_GAMEPAD) {
icculus@7707
   778
                    AddXInputDevice(userid, pContext);
icculus@7707
   779
                }
icculus@7707
   780
            }
icculus@7707
   781
        }
icculus@7707
   782
    }
icculus@7707
   783
}
icculus@7707
   784
icculus@7707
   785
slouken@6707
   786
/* detect any new joysticks being inserted into the system */
slouken@6707
   787
void SDL_SYS_JoystickDetect()
slouken@6707
   788
{
slouken@7191
   789
    JoyStick_DeviceData *pCurList = NULL;
slouken@7191
   790
    /* only enum the devices if the joystick thread told us something changed */
slouken@7191
   791
    if ( s_bDeviceAdded || s_bDeviceRemoved )
slouken@7191
   792
    {
icculus@7707
   793
        SDL_LockMutex( s_mutexJoyStickEnum );
icculus@7707
   794
slouken@7191
   795
        s_bDeviceAdded = SDL_FALSE;
slouken@7191
   796
        s_bDeviceRemoved = SDL_FALSE;
slouken@6707
   797
slouken@7191
   798
        pCurList = SYS_Joystick;
slouken@7191
   799
        SYS_Joystick = NULL;
slouken@6707
   800
icculus@7707
   801
        /* Look for DirectInput joysticks, wheels, head trackers, gamepads, etc.. */
slouken@7223
   802
        IDirectInput8_EnumDevices(dinput,
slouken@7191
   803
            DI8DEVCLASS_GAMECTRL,
slouken@7191
   804
            EnumJoysticksCallback,
slouken@7191
   805
            &pCurList, DIEDFL_ATTACHEDONLY);
slouken@6707
   806
icculus@7707
   807
        SDL_free(SDL_RawDevList);  /* in case we used this in DirectInput enumerator. */
icculus@7706
   808
        SDL_RawDevList = NULL;
icculus@7707
   809
        SDL_RawDevListCount = 0;
icculus@7706
   810
icculus@7712
   811
        /* Look for XInput devices. Do this last, so they're first in the final list. */
icculus@7712
   812
        EnumXInputDevices(&pCurList);
icculus@7712
   813
slouken@7191
   814
        SDL_UnlockMutex( s_mutexJoyStickEnum );
slouken@7191
   815
    }
slouken@7191
   816
slouken@7191
   817
    if ( pCurList )
slouken@7191
   818
    {
slouken@7191
   819
        while ( pCurList )
slouken@7191
   820
        {
slouken@7191
   821
            JoyStick_DeviceData *pListNext = NULL;
slouken@6707
   822
#if !SDL_EVENTS_DISABLED
slouken@7191
   823
            SDL_Event event;
slouken@7191
   824
            event.type = SDL_JOYDEVICEREMOVED;
slouken@6707
   825
slouken@7191
   826
            if (SDL_GetEventState(event.type) == SDL_ENABLE) {
slouken@7191
   827
                event.jdevice.which = pCurList->nInstanceID;
slouken@7191
   828
                if ((SDL_EventOK == NULL)
slouken@7191
   829
                    || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
slouken@7191
   830
                        SDL_PushEvent(&event);
slouken@7191
   831
                }
slouken@7191
   832
            }
slouken@7191
   833
#endif /* !SDL_EVENTS_DISABLED */
slouken@6707
   834
slouken@7191
   835
            pListNext = pCurList->pNext;
slouken@7191
   836
            SDL_free(pCurList->joystickname);
slouken@7191
   837
            SDL_free( pCurList );
slouken@7191
   838
            pCurList = pListNext;
slouken@7191
   839
        }
slouken@6707
   840
slouken@7191
   841
    }
slouken@6707
   842
slouken@7191
   843
    if ( s_bDeviceAdded )
slouken@7191
   844
    {
slouken@7191
   845
        JoyStick_DeviceData *pNewJoystick;
slouken@7191
   846
        int device_index = 0;
slouken@7191
   847
        s_bDeviceAdded = SDL_FALSE;
slouken@7191
   848
        pNewJoystick = SYS_Joystick;
slouken@7191
   849
        while ( pNewJoystick )
slouken@7191
   850
        {
slouken@7191
   851
            if ( pNewJoystick->send_add_event )
slouken@7191
   852
            {
slouken@6707
   853
#if !SDL_EVENTS_DISABLED
slouken@7191
   854
                SDL_Event event;
slouken@7191
   855
                event.type = SDL_JOYDEVICEADDED;
slouken@6707
   856
slouken@7191
   857
                if (SDL_GetEventState(event.type) == SDL_ENABLE) {
slouken@7191
   858
                    event.jdevice.which = device_index;
slouken@7191
   859
                    if ((SDL_EventOK == NULL)
slouken@7191
   860
                        || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
slouken@7191
   861
                            SDL_PushEvent(&event);
slouken@7191
   862
                    }
slouken@7191
   863
                }
slouken@6707
   864
#endif /* !SDL_EVENTS_DISABLED */
slouken@7191
   865
                pNewJoystick->send_add_event = 0;
slouken@7191
   866
            }
slouken@7191
   867
            device_index++;
slouken@7191
   868
            pNewJoystick = pNewJoystick->pNext;
slouken@7191
   869
        }
slouken@7191
   870
    }
slouken@6707
   871
}
slouken@6707
   872
slouken@6707
   873
/* we need to poll if we have pending hotplug device changes or connected devices */
slouken@6707
   874
SDL_bool SDL_SYS_JoystickNeedsPolling()
slouken@6707
   875
{
slouken@7191
   876
    /* we have a new device or one was pulled, we need to think this frame please */
slouken@7191
   877
    if ( s_bDeviceAdded || s_bDeviceRemoved )
slouken@7191
   878
        return SDL_TRUE;
slouken@6707
   879
slouken@7191
   880
    return SDL_FALSE;
slouken@6707
   881
}
slouken@6707
   882
slouken@1895
   883
/* Function to get the device-dependent name of a joystick */
slouken@1895
   884
const char *
slouken@6707
   885
SDL_SYS_JoystickNameForDeviceIndex(int device_index)
slouken@1895
   886
{
slouken@7191
   887
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@6690
   888
slouken@7191
   889
    for (; device_index > 0; device_index--)
slouken@7191
   890
        device = device->pNext;
slouken@6690
   891
slouken@7191
   892
    return device->joystickname;
slouken@1895
   893
}
slouken@1895
   894
slouken@6707
   895
/* Function to perform the mapping between current device instance and this joysticks instance id */
slouken@6707
   896
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
slouken@6707
   897
{
slouken@7191
   898
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@7191
   899
    int index;
slouken@6707
   900
slouken@7191
   901
    for (index = device_index; index > 0; index--)
slouken@7191
   902
        device = device->pNext;
slouken@6707
   903
slouken@7191
   904
    return device->nInstanceID;
slouken@6707
   905
}
slouken@6707
   906
slouken@1895
   907
/* Function to open a joystick for use.
slouken@1895
   908
   The joystick to open is specified by the index field of the joystick.
slouken@1895
   909
   This should fill the nbuttons and naxes fields of the joystick structure.
slouken@1895
   910
   It returns 0, or -1 if there is an error.
slouken@1895
   911
 */
slouken@1895
   912
int
slouken@6690
   913
SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
slouken@1895
   914
{
slouken@1895
   915
    HRESULT result;
slouken@7191
   916
    JoyStick_DeviceData *joystickdevice = SYS_Joystick;
slouken@6690
   917
slouken@7191
   918
    for (; device_index > 0; device_index--)
slouken@7191
   919
        joystickdevice = joystickdevice->pNext;
slouken@2198
   920
slouken@1895
   921
    /* allocate memory for system specific hardware data */
slouken@7191
   922
    joystick->instance_id = joystickdevice->nInstanceID;
urkle@6965
   923
    joystick->closed = 0;
slouken@1895
   924
    joystick->hwdata =
slouken@2713
   925
        (struct joystick_hwdata *) SDL_malloc(sizeof(struct joystick_hwdata));
slouken@1895
   926
    if (joystick->hwdata == NULL) {
icculus@7037
   927
        return SDL_OutOfMemory();
slouken@1895
   928
    }
icculus@7707
   929
    SDL_zerop(joystick->hwdata);
slouken@1895
   930
icculus@7707
   931
    if (joystickdevice->bXInputDevice) {
icculus@7707
   932
        const SDL_bool bIs14OrLater = (SDL_XInputVersion >= ((1<<16)|4));
icculus@7707
   933
        const Uint8 userId = joystickdevice->XInputUserId;
slouken@7191
   934
        XINPUT_CAPABILITIES capabilities;
slouken@1895
   935
icculus@7707
   936
        SDL_assert(s_bXInputEnabled);
icculus@7707
   937
        SDL_assert(XINPUTGETCAPABILITIES);
icculus@7707
   938
        SDL_assert(userId >= 0);
icculus@7707
   939
        SDL_assert(userId < SDL_XINPUT_MAX_DEVICES);
slouken@2198
   940
icculus@7707
   941
        joystick->hwdata->bXInputDevice = SDL_TRUE;
slouken@7684
   942
icculus@7707
   943
        if (XINPUTGETCAPABILITIES(userId, XINPUT_FLAG_GAMEPAD, &capabilities) != ERROR_SUCCESS) {
icculus@7707
   944
            SDL_free(joystick->hwdata);
icculus@7707
   945
            joystick->hwdata = NULL;
icculus@7707
   946
            return SDL_SetError("Failed to obtain XInput device capabilities. Device disconnected?");
icculus@7707
   947
        } else {
icculus@7707
   948
            /* Current version of XInput mistakenly returns 0 as the Type. Ignore it and ensure the subtype is a gamepad. */
icculus@7707
   949
            SDL_assert(capabilities.SubType == XINPUT_DEVSUBTYPE_GAMEPAD);
icculus@7707
   950
            if ((!bIs14OrLater) || (capabilities.Flags & XINPUT_CAPS_FFB_SUPPORTED)) {
icculus@7707
   951
                joystick->hwdata->bXInputHaptic = SDL_TRUE;
icculus@7707
   952
            }
icculus@7707
   953
            joystick->hwdata->userid = userId;
slouken@7684
   954
icculus@7707
   955
            /* The XInput API has a hard coded button/axis mapping, so we just match it */
icculus@7707
   956
            joystick->naxes = 6;
icculus@7707
   957
            joystick->nbuttons = 15;
icculus@7707
   958
            joystick->nballs = 0;
icculus@7707
   959
            joystick->nhats = 0;
icculus@7707
   960
		}
icculus@7707
   961
    } else {  /* use DirectInput, not XInput. */
icculus@7707
   962
        LPDIRECTINPUTDEVICE8 device;
icculus@7707
   963
        DIPROPDWORD dipdw;
slouken@1895
   964
icculus@7707
   965
        joystick->hwdata->buffered = 1;
icculus@7707
   966
        joystick->hwdata->removed = 0;
icculus@7707
   967
        joystick->hwdata->Capabilities.dwSize = sizeof(DIDEVCAPS);
icculus@7707
   968
        joystick->hwdata->guid = joystickdevice->guid;
icculus@7707
   969
icculus@7707
   970
        SDL_zero(dipdw);
icculus@7707
   971
        dipdw.diph.dwSize = sizeof(DIPROPDWORD);
icculus@7707
   972
        dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
slouken@1895
   973
slouken@7191
   974
        result =
slouken@7191
   975
            IDirectInput8_CreateDevice(dinput,
slouken@7191
   976
                                      &(joystickdevice->dxdevice.guidInstance), &device, NULL);
slouken@7191
   977
        if (FAILED(result)) {
slouken@7191
   978
            return SetDIerror("IDirectInput::CreateDevice", result);
slouken@7191
   979
        }
slouken@1895
   980
slouken@7191
   981
        /* Now get the IDirectInputDevice8 interface, instead. */
slouken@7191
   982
        result = IDirectInputDevice8_QueryInterface(device,
slouken@7191
   983
                                                   &IID_IDirectInputDevice8,
slouken@7191
   984
                                                   (LPVOID *) & joystick->
slouken@7191
   985
                                                   hwdata->InputDevice);
slouken@7191
   986
        /* We are done with this object.  Use the stored one from now on. */
slouken@7191
   987
        IDirectInputDevice8_Release(device);
slouken@1895
   988
slouken@7191
   989
        if (FAILED(result)) {
slouken@7191
   990
            return SetDIerror("IDirectInputDevice8::QueryInterface", result);
slouken@7191
   991
        }
slouken@2198
   992
slouken@7191
   993
        /* Acquire shared access. Exclusive access is required for forces,
slouken@7191
   994
         * though. */
slouken@7191
   995
        result =
slouken@7191
   996
            IDirectInputDevice8_SetCooperativeLevel(joystick->hwdata->
slouken@7191
   997
                                                    InputDevice, SDL_HelperWindow,
slouken@7191
   998
                                                    DISCL_NONEXCLUSIVE |
slouken@7191
   999
                                                    DISCL_BACKGROUND);
slouken@7191
  1000
        if (FAILED(result)) {
slouken@7191
  1001
            return SetDIerror("IDirectInputDevice8::SetCooperativeLevel", result);
slouken@7191
  1002
        }
slouken@2198
  1003
slouken@7191
  1004
        /* Use the extended data structure: DIJOYSTATE2. */
slouken@7191
  1005
        result =
slouken@7191
  1006
            IDirectInputDevice8_SetDataFormat(joystick->hwdata->InputDevice,
slouken@7191
  1007
                                              &c_dfDIJoystick2);
slouken@7191
  1008
        if (FAILED(result)) {
slouken@7191
  1009
            return SetDIerror("IDirectInputDevice8::SetDataFormat", result);
slouken@7191
  1010
        }
slouken@2198
  1011
slouken@7191
  1012
        /* Get device capabilities */
slouken@7191
  1013
        result =
slouken@7191
  1014
            IDirectInputDevice8_GetCapabilities(joystick->hwdata->InputDevice,
slouken@7191
  1015
                                                &joystick->hwdata->Capabilities);
slouken@2198
  1016
slouken@7191
  1017
        if (FAILED(result)) {
slouken@7191
  1018
            return SetDIerror("IDirectInputDevice8::GetCapabilities", result);
slouken@7191
  1019
        }
slouken@2198
  1020
slouken@7191
  1021
        /* Force capable? */
slouken@7191
  1022
        if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
slouken@2198
  1023
slouken@7191
  1024
            result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
slouken@2198
  1025
slouken@7191
  1026
            if (FAILED(result)) {
slouken@7191
  1027
                return SetDIerror("IDirectInputDevice8::Acquire", result);
slouken@7191
  1028
            }
slouken@2198
  1029
slouken@7191
  1030
            /* reset all accuators. */
slouken@7191
  1031
            result =
slouken@7191
  1032
                IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->
slouken@7191
  1033
                                                             InputDevice,
slouken@7191
  1034
                                                             DISFFC_RESET);
slouken@2198
  1035
slouken@7191
  1036
            /* Not necessarily supported, ignore if not supported.
slouken@7191
  1037
            if (FAILED(result)) {
slouken@7191
  1038
                return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand", result);
slouken@7191
  1039
            }
slouken@7191
  1040
            */
slouken@1895
  1041
slouken@7191
  1042
            result = IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
slouken@1895
  1043
slouken@7191
  1044
            if (FAILED(result)) {
slouken@7191
  1045
                return SetDIerror("IDirectInputDevice8::Unacquire", result);
slouken@7191
  1046
            }
slouken@2198
  1047
slouken@7191
  1048
            /* Turn on auto-centering for a ForceFeedback device (until told
slouken@7191
  1049
             * otherwise). */
slouken@7191
  1050
            dipdw.diph.dwObj = 0;
slouken@7191
  1051
            dipdw.diph.dwHow = DIPH_DEVICE;
slouken@7191
  1052
            dipdw.dwData = DIPROPAUTOCENTER_ON;
slouken@6220
  1053
slouken@7191
  1054
            result =
slouken@7191
  1055
                IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
slouken@7191
  1056
                                                DIPROP_AUTOCENTER, &dipdw.diph);
slouken@2198
  1057
slouken@7191
  1058
            /* Not necessarily supported, ignore if not supported.
slouken@7191
  1059
            if (FAILED(result)) {
slouken@7191
  1060
                return SetDIerror("IDirectInputDevice8::SetProperty", result);
slouken@7191
  1061
            }
slouken@7191
  1062
            */
slouken@7191
  1063
        }
slouken@2198
  1064
slouken@7191
  1065
        /* What buttons and axes does it have? */
slouken@7191
  1066
        IDirectInputDevice8_EnumObjects(joystick->hwdata->InputDevice,
slouken@7191
  1067
                                        EnumDevObjectsCallback, joystick,
slouken@7191
  1068
                                        DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV);
slouken@2198
  1069
slouken@7191
  1070
        /* Reorder the input objects. Some devices do not report the X axis as
slouken@7191
  1071
         * the first axis, for example. */
slouken@7191
  1072
        SortDevObjects(joystick);
slouken@6690
  1073
slouken@7191
  1074
        dipdw.diph.dwObj = 0;
slouken@7191
  1075
        dipdw.diph.dwHow = DIPH_DEVICE;
slouken@7191
  1076
        dipdw.dwData = INPUT_QSIZE;
slouken@6690
  1077
slouken@7191
  1078
        /* Set the buffer size */
slouken@7191
  1079
        result =
slouken@7191
  1080
            IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
slouken@7191
  1081
                                            DIPROP_BUFFERSIZE, &dipdw.diph);
slouken@6690
  1082
slouken@7191
  1083
        if (result == DI_POLLEDDEVICE) {
slouken@7191
  1084
            /* This device doesn't support buffering, so we're forced
slouken@7191
  1085
             * to use less reliable polling. */
slouken@7191
  1086
            joystick->hwdata->buffered = 0;
slouken@7191
  1087
        } else if (FAILED(result)) {
slouken@7191
  1088
            return SetDIerror("IDirectInputDevice8::SetProperty", result);
slouken@7191
  1089
        }
slouken@7191
  1090
    }
slouken@1895
  1091
    return (0);
slouken@1895
  1092
}
slouken@1895
  1093
slouken@6707
  1094
/* return true if this joystick is plugged in right now */
slouken@6707
  1095
SDL_bool SDL_SYS_JoystickAttached( SDL_Joystick * joystick )
slouken@6707
  1096
{
slouken@7191
  1097
    return joystick->closed == 0 && joystick->hwdata->removed == 0;
slouken@6707
  1098
}
slouken@6707
  1099
slouken@6707
  1100
slouken@6220
  1101
/* Sort using the data offset into the DInput struct.
slouken@6220
  1102
 * This gives a reasonable ordering for the inputs. */
slouken@6220
  1103
static int
slouken@6220
  1104
SortDevFunc(const void *a, const void *b)
slouken@6220
  1105
{
slouken@7191
  1106
    const input_t *inputA = (const input_t*)a;
slouken@7191
  1107
    const input_t *inputB = (const input_t*)b;
slouken@6220
  1108
slouken@7191
  1109
    if (inputA->ofs < inputB->ofs)
slouken@7191
  1110
        return -1;
slouken@7191
  1111
    if (inputA->ofs > inputB->ofs)
slouken@7191
  1112
        return 1;
slouken@7191
  1113
    return 0;
slouken@6220
  1114
}
slouken@6220
  1115
slouken@6220
  1116
/* Sort the input objects and recalculate the indices for each input. */
slouken@6220
  1117
static void
slouken@6220
  1118
SortDevObjects(SDL_Joystick *joystick)
slouken@6220
  1119
{
slouken@7191
  1120
    input_t *inputs = joystick->hwdata->Inputs;
slouken@7191
  1121
    int nButtons = 0;
slouken@7191
  1122
    int nHats = 0;
slouken@7191
  1123
    int nAxis = 0;
slouken@7191
  1124
    int n;
slouken@6220
  1125
slouken@7191
  1126
    SDL_qsort(inputs, joystick->hwdata->NumInputs, sizeof(input_t), SortDevFunc);
slouken@6220
  1127
slouken@7191
  1128
    for (n = 0; n < joystick->hwdata->NumInputs; n++)
slouken@7191
  1129
    {
slouken@7191
  1130
        switch (inputs[n].type)
slouken@7191
  1131
        {
slouken@7191
  1132
        case BUTTON:
slouken@7191
  1133
            inputs[n].num = nButtons;
slouken@7191
  1134
            nButtons++;
slouken@7191
  1135
            break;
slouken@6220
  1136
slouken@7191
  1137
        case HAT:
slouken@7191
  1138
            inputs[n].num = nHats;
slouken@7191
  1139
            nHats++;
slouken@7191
  1140
            break;
slouken@6220
  1141
slouken@7191
  1142
        case AXIS:
slouken@7191
  1143
            inputs[n].num = nAxis;
slouken@7191
  1144
            nAxis++;
slouken@7191
  1145
            break;
slouken@7191
  1146
        }
slouken@7191
  1147
    }
slouken@6220
  1148
}
slouken@6220
  1149
slouken@2198
  1150
static BOOL CALLBACK
slouken@2198
  1151
EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
slouken@2198
  1152
{
slouken@2198
  1153
    SDL_Joystick *joystick = (SDL_Joystick *) pvRef;
slouken@2198
  1154
    HRESULT result;
slouken@2198
  1155
    input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs];
slouken@2198
  1156
slouken@2198
  1157
    if (dev->dwType & DIDFT_BUTTON) {
slouken@2198
  1158
        in->type = BUTTON;
slouken@2198
  1159
        in->num = joystick->nbuttons;
slouken@7191
  1160
        in->ofs = DIJOFS_BUTTON( in->num );
slouken@2198
  1161
        joystick->nbuttons++;
slouken@2198
  1162
    } else if (dev->dwType & DIDFT_POV) {
slouken@2198
  1163
        in->type = HAT;
slouken@2198
  1164
        in->num = joystick->nhats;
slouken@7191
  1165
        in->ofs = DIJOFS_POV( in->num );
slouken@2198
  1166
        joystick->nhats++;
slouken@2198
  1167
    } else if (dev->dwType & DIDFT_AXIS) {
slouken@2198
  1168
        DIPROPRANGE diprg;
slouken@2198
  1169
        DIPROPDWORD dilong;
slouken@2198
  1170
slouken@2198
  1171
        in->type = AXIS;
slouken@2198
  1172
        in->num = joystick->naxes;
slouken@7191
  1173
        /* work our the axis this guy maps too, thanks for the code icculus! */
slouken@7191
  1174
        if ( !SDL_memcmp( &dev->guidType, &GUID_XAxis, sizeof(dev->guidType) ) )
slouken@7191
  1175
            in->ofs = DIJOFS_X;
slouken@7191
  1176
        else if ( !SDL_memcmp( &dev->guidType, &GUID_YAxis, sizeof(dev->guidType) ) )
slouken@7191
  1177
            in->ofs = DIJOFS_Y;
slouken@7191
  1178
        else if ( !SDL_memcmp( &dev->guidType, &GUID_ZAxis, sizeof(dev->guidType) ) )
slouken@7191
  1179
            in->ofs = DIJOFS_Z;
slouken@7191
  1180
        else if ( !SDL_memcmp( &dev->guidType, &GUID_RxAxis, sizeof(dev->guidType) ) )
slouken@7191
  1181
            in->ofs = DIJOFS_RX;
slouken@7191
  1182
        else if ( !SDL_memcmp( &dev->guidType, &GUID_RyAxis, sizeof(dev->guidType) ) )
slouken@7191
  1183
            in->ofs = DIJOFS_RY;
slouken@7191
  1184
        else if ( !SDL_memcmp( &dev->guidType, &GUID_RzAxis, sizeof(dev->guidType) ) )
slouken@7191
  1185
            in->ofs = DIJOFS_RZ;
slouken@7191
  1186
        else if ( !SDL_memcmp( &dev->guidType, &GUID_Slider, sizeof(dev->guidType) ) )
slouken@7191
  1187
        {
slouken@7191
  1188
            in->ofs = DIJOFS_SLIDER( joystick->hwdata->NumSliders );
slouken@7191
  1189
            ++joystick->hwdata->NumSliders;
slouken@7191
  1190
        }
slouken@7191
  1191
        else
slouken@7191
  1192
        {
slouken@7191
  1193
             return DIENUM_CONTINUE; /* not an axis we can grok */
slouken@7191
  1194
        }
slouken@2198
  1195
slouken@2198
  1196
        diprg.diph.dwSize = sizeof(diprg);
slouken@2198
  1197
        diprg.diph.dwHeaderSize = sizeof(diprg.diph);
slouken@6690
  1198
        diprg.diph.dwObj = dev->dwType;
slouken@6690
  1199
        diprg.diph.dwHow = DIPH_BYID;
slouken@2198
  1200
        diprg.lMin = AXIS_MIN;
slouken@2198
  1201
        diprg.lMax = AXIS_MAX;
slouken@2198
  1202
slouken@2198
  1203
        result =
slouken@6690
  1204
            IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
slouken@2198
  1205
                                            DIPROP_RANGE, &diprg.diph);
slouken@2198
  1206
        if (FAILED(result)) {
slouken@2198
  1207
            return DIENUM_CONTINUE;     /* don't use this axis */
slouken@2198
  1208
        }
slouken@2198
  1209
slouken@2198
  1210
        /* Set dead zone to 0. */
slouken@2198
  1211
        dilong.diph.dwSize = sizeof(dilong);
slouken@2198
  1212
        dilong.diph.dwHeaderSize = sizeof(dilong.diph);
slouken@6690
  1213
        dilong.diph.dwObj = dev->dwType;
slouken@6690
  1214
        dilong.diph.dwHow = DIPH_BYID;
slouken@2198
  1215
        dilong.dwData = 0;
slouken@2198
  1216
        result =
slouken@6690
  1217
            IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
slouken@2198
  1218
                                            DIPROP_DEADZONE, &dilong.diph);
slouken@2198
  1219
        if (FAILED(result)) {
slouken@2198
  1220
            return DIENUM_CONTINUE;     /* don't use this axis */
slouken@2198
  1221
        }
slouken@2198
  1222
slouken@2198
  1223
        joystick->naxes++;
slouken@2198
  1224
    } else {
slouken@2198
  1225
        /* not supported at this time */
slouken@2198
  1226
        return DIENUM_CONTINUE;
slouken@2198
  1227
    }
slouken@2198
  1228
slouken@2198
  1229
    joystick->hwdata->NumInputs++;
slouken@2198
  1230
slouken@2198
  1231
    if (joystick->hwdata->NumInputs == MAX_INPUTS) {
slouken@2198
  1232
        return DIENUM_STOP;     /* too many */
slouken@2198
  1233
    }
slouken@2198
  1234
slouken@2198
  1235
    return DIENUM_CONTINUE;
slouken@2198
  1236
}
slouken@2198
  1237
slouken@2198
  1238
/* Function to update the state of a joystick - called as a device poll.
slouken@2198
  1239
 * This function shouldn't update the joystick structure directly,
slouken@2198
  1240
 * but instead should call SDL_PrivateJoystick*() to deliver events
slouken@2198
  1241
 * and update joystick device state.
slouken@2198
  1242
 */
slouken@2198
  1243
void
slouken@2198
  1244
SDL_SYS_JoystickUpdate_Polled(SDL_Joystick * joystick)
slouken@2198
  1245
{
slouken@2198
  1246
    DIJOYSTATE2 state;
slouken@2198
  1247
    HRESULT result;
slouken@2198
  1248
    int i;
slouken@2198
  1249
slouken@2198
  1250
    result =
slouken@6690
  1251
        IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
slouken@2198
  1252
                                           sizeof(DIJOYSTATE2), &state);
slouken@2198
  1253
    if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
slouken@6690
  1254
        IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
slouken@2198
  1255
        result =
slouken@6690
  1256
            IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
slouken@2198
  1257
                                               sizeof(DIJOYSTATE2), &state);
slouken@2198
  1258
    }
slouken@2198
  1259
slouken@7191
  1260
    if ( result != DI_OK )
slouken@7191
  1261
    {
slouken@7191
  1262
        joystick->hwdata->send_remove_event = 1;
slouken@7191
  1263
        joystick->hwdata->removed = 1;
slouken@7191
  1264
        return;
slouken@7191
  1265
    }
slouken@6690
  1266
slouken@2198
  1267
    /* Set each known axis, button and POV. */
slouken@2198
  1268
    for (i = 0; i < joystick->hwdata->NumInputs; ++i) {
slouken@2198
  1269
        const input_t *in = &joystick->hwdata->Inputs[i];
slouken@2198
  1270
slouken@2198
  1271
        switch (in->type) {
slouken@2198
  1272
        case AXIS:
slouken@2198
  1273
            switch (in->ofs) {
slouken@2198
  1274
            case DIJOFS_X:
slouken@2198
  1275
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1276
                                            (Sint16) state.lX);
slouken@2198
  1277
                break;
slouken@2198
  1278
            case DIJOFS_Y:
slouken@2198
  1279
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1280
                                            (Sint16) state.lY);
slouken@2198
  1281
                break;
slouken@2198
  1282
            case DIJOFS_Z:
slouken@2198
  1283
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1284
                                            (Sint16) state.lZ);
slouken@2198
  1285
                break;
slouken@2198
  1286
            case DIJOFS_RX:
slouken@2198
  1287
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1288
                                            (Sint16) state.lRx);
slouken@2198
  1289
                break;
slouken@2198
  1290
            case DIJOFS_RY:
slouken@2198
  1291
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1292
                                            (Sint16) state.lRy);
slouken@2198
  1293
                break;
slouken@2198
  1294
            case DIJOFS_RZ:
slouken@2198
  1295
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1296
                                            (Sint16) state.lRz);
slouken@2198
  1297
                break;
slouken@2198
  1298
            case DIJOFS_SLIDER(0):
slouken@2198
  1299
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1300
                                            (Sint16) state.rglSlider[0]);
slouken@2198
  1301
                break;
slouken@2198
  1302
            case DIJOFS_SLIDER(1):
slouken@2198
  1303
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1304
                                            (Sint16) state.rglSlider[1]);
slouken@2198
  1305
                break;
slouken@2198
  1306
            }
slouken@2198
  1307
slouken@2198
  1308
            break;
slouken@2198
  1309
slouken@2198
  1310
        case BUTTON:
slouken@2198
  1311
            SDL_PrivateJoystickButton_Int(joystick, in->num,
slouken@3013
  1312
                                          (Uint8) (state.
slouken@3013
  1313
                                                   rgbButtons[in->ofs -
slouken@3013
  1314
                                                              DIJOFS_BUTTON0]
slouken@2198
  1315
                                                   ? SDL_PRESSED :
slouken@2198
  1316
                                                   SDL_RELEASED));
slouken@2198
  1317
            break;
slouken@2198
  1318
        case HAT:
slouken@2198
  1319
            {
slouken@2198
  1320
                Uint8 pos = TranslatePOV(state.rgdwPOV[in->ofs -
slouken@2198
  1321
                                                       DIJOFS_POV(0)]);
slouken@2198
  1322
                SDL_PrivateJoystickHat_Int(joystick, in->num, pos);
slouken@2198
  1323
                break;
slouken@2198
  1324
            }
slouken@2198
  1325
        }
slouken@2198
  1326
    }
slouken@2198
  1327
}
slouken@2198
  1328
slouken@2198
  1329
void
slouken@2198
  1330
SDL_SYS_JoystickUpdate_Buffered(SDL_Joystick * joystick)
slouken@2198
  1331
{
slouken@2198
  1332
    int i;
slouken@2198
  1333
    HRESULT result;
slouken@2198
  1334
    DWORD numevents;
slouken@2198
  1335
    DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
slouken@2198
  1336
slouken@2198
  1337
    numevents = INPUT_QSIZE;
slouken@2198
  1338
    result =
slouken@6690
  1339
        IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
slouken@2198
  1340
                                          sizeof(DIDEVICEOBJECTDATA), evtbuf,
slouken@2198
  1341
                                          &numevents, 0);
slouken@2198
  1342
    if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
slouken@6690
  1343
        IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
slouken@2198
  1344
        result =
slouken@6690
  1345
            IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
slouken@2198
  1346
                                              sizeof(DIDEVICEOBJECTDATA),
slouken@2198
  1347
                                              evtbuf, &numevents, 0);
slouken@2198
  1348
    }
slouken@2198
  1349
slouken@2198
  1350
    /* Handle the events or punt */
slouken@2198
  1351
    if (FAILED(result))
slouken@7191
  1352
    {
slouken@7191
  1353
        joystick->hwdata->send_remove_event = 1;
slouken@7191
  1354
        joystick->hwdata->removed = 1;
slouken@2198
  1355
        return;
slouken@7191
  1356
    }
slouken@2198
  1357
slouken@2198
  1358
    for (i = 0; i < (int) numevents; ++i) {
slouken@2198
  1359
        int j;
slouken@2198
  1360
slouken@2198
  1361
        for (j = 0; j < joystick->hwdata->NumInputs; ++j) {
slouken@2198
  1362
            const input_t *in = &joystick->hwdata->Inputs[j];
slouken@2198
  1363
slouken@2198
  1364
            if (evtbuf[i].dwOfs != in->ofs)
slouken@2198
  1365
                continue;
slouken@2198
  1366
slouken@2198
  1367
            switch (in->type) {
slouken@2198
  1368
            case AXIS:
slouken@2198
  1369
                SDL_PrivateJoystickAxis(joystick, in->num,
slouken@2198
  1370
                                        (Sint16) evtbuf[i].dwData);
slouken@2198
  1371
                break;
slouken@2198
  1372
            case BUTTON:
slouken@2198
  1373
                SDL_PrivateJoystickButton(joystick, in->num,
slouken@3013
  1374
                                          (Uint8) (evtbuf[i].
slouken@3013
  1375
                                                   dwData ? SDL_PRESSED :
slouken@2198
  1376
                                                   SDL_RELEASED));
slouken@2198
  1377
                break;
slouken@2198
  1378
            case HAT:
slouken@2198
  1379
                {
slouken@2198
  1380
                    Uint8 pos = TranslatePOV(evtbuf[i].dwData);
slouken@2198
  1381
                    SDL_PrivateJoystickHat(joystick, in->num, pos);
slouken@2198
  1382
                }
slouken@2198
  1383
            }
slouken@2198
  1384
        }
slouken@2198
  1385
    }
slouken@2198
  1386
}
slouken@2198
  1387
slouken@2198
  1388
slouken@6690
  1389
/* Function to return > 0 if a bit array of buttons differs after applying a mask
slouken@6690
  1390
*/
slouken@6690
  1391
int ButtonChanged( int ButtonsNow, int ButtonsPrev, int ButtonMask )
slouken@6690
  1392
{
slouken@7191
  1393
    return ( ButtonsNow & ButtonMask ) != ( ButtonsPrev & ButtonMask );
slouken@6690
  1394
}
slouken@6690
  1395
slouken@6690
  1396
/* Function to update the state of a XInput style joystick.
slouken@6690
  1397
*/
slouken@6690
  1398
void
slouken@6690
  1399
SDL_SYS_JoystickUpdate_XInput(SDL_Joystick * joystick)
slouken@6690
  1400
{
slouken@7191
  1401
    HRESULT result;
slouken@6690
  1402
slouken@7191
  1403
    if ( !XINPUTGETSTATE )
slouken@7191
  1404
        return;
slouken@6690
  1405
slouken@7191
  1406
    result = XINPUTGETSTATE( joystick->hwdata->userid, &joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot] );
slouken@7191
  1407
    if ( result == ERROR_DEVICE_NOT_CONNECTED )
slouken@7191
  1408
    {
slouken@7191
  1409
        joystick->hwdata->send_remove_event = 1;
slouken@7191
  1410
        joystick->hwdata->removed = 1;
slouken@7191
  1411
        return;
slouken@7191
  1412
    }
slouken@6690
  1413
slouken@7191
  1414
    /* only fire events if the data changed from last time */
slouken@7191
  1415
    if ( joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot].dwPacketNumber != 0
slouken@7191
  1416
        && joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot].dwPacketNumber != joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot^1].dwPacketNumber )
slouken@7191
  1417
    {
slouken@7191
  1418
        XINPUT_STATE_EX *pXInputState = &joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot];
slouken@7191
  1419
        XINPUT_STATE_EX *pXInputStatePrev = &joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot ^ 1];
slouken@6690
  1420
slouken@7296
  1421
        SDL_PrivateJoystickAxis( joystick, 0, (Sint16)pXInputState->Gamepad.sThumbLX );
slouken@7321
  1422
        SDL_PrivateJoystickAxis( joystick, 1, (Sint16)(-SDL_max(-32767, pXInputState->Gamepad.sThumbLY)) );
slouken@7296
  1423
        SDL_PrivateJoystickAxis( joystick, 2, (Sint16)pXInputState->Gamepad.sThumbRX );
slouken@7321
  1424
        SDL_PrivateJoystickAxis( joystick, 3, (Sint16)(-SDL_max(-32767, pXInputState->Gamepad.sThumbRY)) );
slouken@7296
  1425
        SDL_PrivateJoystickAxis( joystick, 4, (Sint16)(((int)pXInputState->Gamepad.bLeftTrigger*65535/255) - 32768));
slouken@7296
  1426
        SDL_PrivateJoystickAxis( joystick, 5, (Sint16)(((int)pXInputState->Gamepad.bRightTrigger*65535/255) - 32768));
slouken@6690
  1427
slouken@7191
  1428
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_UP ) )
slouken@7191
  1429
            SDL_PrivateJoystickButton(joystick, 0, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP ? SDL_PRESSED :  SDL_RELEASED );
slouken@7191
  1430
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_DOWN ) )
slouken@7191
  1431
            SDL_PrivateJoystickButton(joystick, 1, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN ? SDL_PRESSED :    SDL_RELEASED );
slouken@7191
  1432
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_LEFT ) )
slouken@7191
  1433
            SDL_PrivateJoystickButton(joystick, 2, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT ? SDL_PRESSED :    SDL_RELEASED );
slouken@7191
  1434
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_RIGHT ) )
slouken@7191
  1435
            SDL_PrivateJoystickButton(joystick, 3, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1436
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_START ) )
slouken@7191
  1437
            SDL_PrivateJoystickButton(joystick, 4, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_START ? SDL_PRESSED :    SDL_RELEASED );
slouken@7191
  1438
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_BACK ) )
slouken@7191
  1439
            SDL_PrivateJoystickButton(joystick, 5, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_BACK ? SDL_PRESSED : SDL_RELEASED );
slouken@7191
  1440
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_THUMB ) )
slouken@7191
  1441
            SDL_PrivateJoystickButton(joystick, 6, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1442
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_RIGHT_THUMB ) )
slouken@7191
  1443
            SDL_PrivateJoystickButton(joystick, 7, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB ? SDL_PRESSED :  SDL_RELEASED );
slouken@7191
  1444
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_SHOULDER ) )
slouken@7191
  1445
            SDL_PrivateJoystickButton(joystick, 8, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER ? SDL_PRESSED :    SDL_RELEASED );
slouken@7191
  1446
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_RIGHT_SHOULDER ) )
slouken@7191
  1447
            SDL_PrivateJoystickButton(joystick, 9, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1448
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_A ) )
slouken@7191
  1449
            SDL_PrivateJoystickButton(joystick, 10, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_A ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1450
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_B ) )
slouken@7191
  1451
            SDL_PrivateJoystickButton(joystick, 11, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_B ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1452
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_X ) )
slouken@7191
  1453
            SDL_PrivateJoystickButton(joystick, 12, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_X ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1454
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_Y ) )
slouken@7191
  1455
            SDL_PrivateJoystickButton(joystick, 13, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_Y ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1456
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons,  0x400 ) )
slouken@7191
  1457
            SDL_PrivateJoystickButton(joystick, 14, pXInputState->Gamepad.wButtons & 0x400 ? SDL_PRESSED :  SDL_RELEASED ); /* 0x400 is the undocumented code for the guide button */
slouken@6690
  1458
slouken@7191
  1459
        joystick->hwdata->currentXInputSlot ^= 1;
slouken@6690
  1460
slouken@7191
  1461
    }
slouken@6690
  1462
}
slouken@6690
  1463
slouken@6690
  1464
slouken@1895
  1465
static Uint8
slouken@1895
  1466
TranslatePOV(DWORD value)
slouken@1895
  1467
{
slouken@1895
  1468
    const int HAT_VALS[] = {
slouken@1895
  1469
        SDL_HAT_UP,
slouken@1895
  1470
        SDL_HAT_UP | SDL_HAT_RIGHT,
slouken@1895
  1471
        SDL_HAT_RIGHT,
slouken@1895
  1472
        SDL_HAT_DOWN | SDL_HAT_RIGHT,
slouken@1895
  1473
        SDL_HAT_DOWN,
slouken@1895
  1474
        SDL_HAT_DOWN | SDL_HAT_LEFT,
slouken@1895
  1475
        SDL_HAT_LEFT,
slouken@1895
  1476
        SDL_HAT_UP | SDL_HAT_LEFT
slouken@1895
  1477
    };
slouken@1895
  1478
slouken@1895
  1479
    if (LOWORD(value) == 0xFFFF)
slouken@1895
  1480
        return SDL_HAT_CENTERED;
slouken@1895
  1481
slouken@1895
  1482
    /* Round the value up: */
slouken@1895
  1483
    value += 4500 / 2;
slouken@1895
  1484
    value %= 36000;
slouken@1895
  1485
    value /= 4500;
slouken@1895
  1486
slouken@1895
  1487
    if (value >= 8)
slouken@1895
  1488
        return SDL_HAT_CENTERED;        /* shouldn't happen */
slouken@1895
  1489
slouken@1895
  1490
    return HAT_VALS[value];
slouken@1895
  1491
}
slouken@1895
  1492
slouken@1895
  1493
/* SDL_PrivateJoystick* doesn't discard duplicate events, so we need to
slouken@1895
  1494
 * do it. */
slouken@1895
  1495
static int
slouken@1895
  1496
SDL_PrivateJoystickAxis_Int(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
slouken@1895
  1497
{
slouken@1895
  1498
    if (joystick->axes[axis] != value)
slouken@1895
  1499
        return SDL_PrivateJoystickAxis(joystick, axis, value);
slouken@1895
  1500
    return 0;
slouken@1895
  1501
}
slouken@1895
  1502
slouken@1895
  1503
static int
slouken@1895
  1504
SDL_PrivateJoystickHat_Int(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
slouken@1895
  1505
{
slouken@1895
  1506
    if (joystick->hats[hat] != value)
slouken@1895
  1507
        return SDL_PrivateJoystickHat(joystick, hat, value);
slouken@1895
  1508
    return 0;
slouken@1895
  1509
}
slouken@1895
  1510
slouken@1895
  1511
static int
slouken@1895
  1512
SDL_PrivateJoystickButton_Int(SDL_Joystick * joystick, Uint8 button,
slouken@1895
  1513
                              Uint8 state)
slouken@1895
  1514
{
slouken@1895
  1515
    if (joystick->buttons[button] != state)
slouken@1895
  1516
        return SDL_PrivateJoystickButton(joystick, button, state);
slouken@1895
  1517
    return 0;
slouken@1895
  1518
}
slouken@1895
  1519
slouken@1895
  1520
void
slouken@1895
  1521
SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
slouken@1895
  1522
{
slouken@1895
  1523
    HRESULT result;
slouken@1895
  1524
slouken@7191
  1525
    if ( joystick->closed || !joystick->hwdata )
slouken@7191
  1526
        return;
slouken@1895
  1527
slouken@7191
  1528
    if (joystick->hwdata->bXInputDevice)
slouken@7191
  1529
    {
slouken@7191
  1530
        SDL_SYS_JoystickUpdate_XInput(joystick);
slouken@7191
  1531
    }
slouken@7191
  1532
    else
slouken@7191
  1533
    {
slouken@7191
  1534
        result = IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
slouken@7191
  1535
        if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
slouken@7191
  1536
            IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
slouken@7191
  1537
            IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
slouken@7191
  1538
        }
slouken@6690
  1539
slouken@7191
  1540
        if (joystick->hwdata->buffered)
slouken@7191
  1541
            SDL_SYS_JoystickUpdate_Buffered(joystick);
slouken@7191
  1542
        else
slouken@7191
  1543
            SDL_SYS_JoystickUpdate_Polled(joystick);
slouken@7191
  1544
    }
slouken@6690
  1545
slouken@7191
  1546
    if ( joystick->hwdata->removed )
slouken@7191
  1547
    {
slouken@7191
  1548
        joystick->closed = 1;
slouken@7191
  1549
        joystick->uncentered = 1;
slouken@7191
  1550
    }
slouken@1895
  1551
}
slouken@1895
  1552
slouken@1895
  1553
/* Function to close a joystick after use */
slouken@1895
  1554
void
slouken@1895
  1555
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
slouken@1895
  1556
{
icculus@7711
  1557
    if (!joystick->hwdata->bXInputDevice) {
slouken@7191
  1558
        IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
slouken@7191
  1559
        IDirectInputDevice8_Release(joystick->hwdata->InputDevice);
slouken@7191
  1560
    }
slouken@1895
  1561
slouken@1895
  1562
    if (joystick->hwdata != NULL) {
slouken@1895
  1563
        /* free system specific hardware data */
slouken@2713
  1564
        SDL_free(joystick->hwdata);
slouken@1895
  1565
    }
slouken@6690
  1566
slouken@7191
  1567
    joystick->closed = 1;
slouken@1895
  1568
}
slouken@1895
  1569
slouken@1895
  1570
/* Function to perform any system-specific joystick related cleanup */
slouken@1895
  1571
void
slouken@1895
  1572
SDL_SYS_JoystickQuit(void)
slouken@1895
  1573
{
slouken@7191
  1574
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@5090
  1575
slouken@7191
  1576
    while ( device )
slouken@7191
  1577
    {
slouken@7191
  1578
        JoyStick_DeviceData *device_next = device->pNext;
slouken@7191
  1579
        SDL_free(device->joystickname);
slouken@7191
  1580
        SDL_free(device);
slouken@7191
  1581
        device = device_next;
slouken@7191
  1582
    }
slouken@7191
  1583
    SYS_Joystick = NULL;
slouken@6690
  1584
slouken@7191
  1585
    if ( s_threadJoystick )
slouken@7191
  1586
    {
slouken@7191
  1587
        SDL_LockMutex( s_mutexJoyStickEnum );
slouken@7191
  1588
        s_bJoystickThreadQuit = SDL_TRUE;
slouken@7191
  1589
        SDL_CondBroadcast( s_condJoystickThread ); /* signal the joystick thread to quit */
slouken@7191
  1590
        SDL_UnlockMutex( s_mutexJoyStickEnum );
slouken@7191
  1591
        SDL_WaitThread( s_threadJoystick, NULL ); /* wait for it to bugger off */
slouken@6690
  1592
slouken@7191
  1593
        SDL_DestroyMutex( s_mutexJoyStickEnum );
slouken@7191
  1594
        SDL_DestroyCond( s_condJoystickThread );
slouken@7191
  1595
        s_condJoystickThread= NULL;
slouken@7191
  1596
        s_mutexJoyStickEnum = NULL;
slouken@7191
  1597
        s_threadJoystick = NULL;
slouken@7191
  1598
    }
slouken@5090
  1599
icculus@5591
  1600
    if (dinput != NULL) {
slouken@6690
  1601
        IDirectInput8_Release(dinput);
icculus@5591
  1602
        dinput = NULL;
icculus@5591
  1603
    }
icculus@5591
  1604
icculus@5591
  1605
    if (coinitialized) {
icculus@5591
  1606
        WIN_CoUninitialize();
icculus@5591
  1607
        coinitialized = SDL_FALSE;
icculus@5591
  1608
    }
slouken@6690
  1609
icculus@6990
  1610
    if (s_bXInputEnabled) {
icculus@6990
  1611
        WIN_UnloadXInputDLL();
icculus@6990
  1612
    }
slouken@6690
  1613
}
slouken@6690
  1614
slouken@6690
  1615
/* return the stable device guid for this device index */
slouken@6738
  1616
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
slouken@6690
  1617
{
slouken@7191
  1618
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@7191
  1619
    int index;
slouken@6690
  1620
slouken@7191
  1621
    for (index = device_index; index > 0; index--)
slouken@7191
  1622
        device = device->pNext;
slouken@6690
  1623
slouken@7191
  1624
    return device->guid;
slouken@6690
  1625
}
slouken@6690
  1626
slouken@6738
  1627
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
slouken@6707
  1628
{
slouken@7191
  1629
    return joystick->hwdata->guid;
slouken@6707
  1630
}
slouken@6707
  1631
slouken@6707
  1632
/* return SDL_TRUE if this device is using XInput */
slouken@6707
  1633
SDL_bool SDL_SYS_IsXInputDeviceIndex(int device_index)
slouken@6690
  1634
{
slouken@7191
  1635
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@7191
  1636
    int index;
slouken@6690
  1637
slouken@7191
  1638
    for (index = device_index; index > 0; index--)
slouken@7191
  1639
        device = device->pNext;
slouken@6690
  1640
slouken@7191
  1641
    return device->bXInputDevice;
slouken@6690
  1642
}
slouken@6690
  1643
slouken@7685
  1644
/* return SDL_TRUE if this device was opened with XInput */
slouken@7685
  1645
SDL_bool SDL_SYS_IsXInputJoystick(SDL_Joystick * joystick)
slouken@7685
  1646
{
slouken@7685
  1647
	return joystick->hwdata->bXInputDevice;
slouken@7685
  1648
}
slouken@7685
  1649
slouken@1895
  1650
#endif /* SDL_JOYSTICK_DINPUT */
slouken@3575
  1651
slouken@1895
  1652
/* vi: set ts=4 sw=4 expandtab: */