src/joystick/windows/SDL_dxjoystick.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 28 Aug 2013 16:43:47 -0400
changeset 7707 37e02f8fcfa8
parent 7706 8cc29a668223
child 7709 edd2c14acf66
permissions -rw-r--r--
Reworked XInput and DirectInput joystick code.

Now multiple XInput controllers map correctly to device indexes instead of grabbing
the first available userid, and are completely separated out from DirectInput.

Also, the hardcoded limitation on number of DirectInput devices is gone. I don't
expect there to really ever be more than eight joysticks plugged into a machine, but
it was a leftover limitation for a static array we didn't actually use anymore.

Fixes Bugzilla #1984. (etc?)
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@7707
   748
    SDL_snprintf(name, sizeof (name), "XInput Controller #%d", (int) userid);
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@7707
   769
        Uint8 userid;
icculus@7707
   770
        for (userid = 0; userid < SDL_XINPUT_MAX_DEVICES; userid++) {
icculus@7707
   771
            XINPUT_CAPABILITIES capabilities;
icculus@7707
   772
            if (XINPUTGETCAPABILITIES(userid, XINPUT_FLAG_GAMEPAD, &capabilities) == ERROR_SUCCESS) {
icculus@7707
   773
                /* Current version of XInput mistakenly returns 0 as the Type. Ignore it and ensure the subtype is a gamepad. */
icculus@7707
   774
                /* !!! FIXME: we might want to support steering wheels or guitars or whatever laster. */
icculus@7707
   775
                if (capabilities.SubType == XINPUT_DEVSUBTYPE_GAMEPAD) {
icculus@7707
   776
                    AddXInputDevice(userid, pContext);
icculus@7707
   777
                }
icculus@7707
   778
            }
icculus@7707
   779
        }
icculus@7707
   780
    }
icculus@7707
   781
}
icculus@7707
   782
icculus@7707
   783
slouken@6707
   784
/* detect any new joysticks being inserted into the system */
slouken@6707
   785
void SDL_SYS_JoystickDetect()
slouken@6707
   786
{
slouken@7191
   787
    JoyStick_DeviceData *pCurList = NULL;
slouken@7191
   788
    /* only enum the devices if the joystick thread told us something changed */
slouken@7191
   789
    if ( s_bDeviceAdded || s_bDeviceRemoved )
slouken@7191
   790
    {
icculus@7707
   791
        SDL_LockMutex( s_mutexJoyStickEnum );
icculus@7707
   792
slouken@7191
   793
        s_bDeviceAdded = SDL_FALSE;
slouken@7191
   794
        s_bDeviceRemoved = SDL_FALSE;
slouken@6707
   795
slouken@7191
   796
        pCurList = SYS_Joystick;
slouken@7191
   797
        SYS_Joystick = NULL;
slouken@6707
   798
icculus@7707
   799
        /* Look for XInput devices... */
icculus@7707
   800
        EnumXInputDevices(&pCurList);
slouken@6707
   801
icculus@7707
   802
        /* Look for DirectInput joysticks, wheels, head trackers, gamepads, etc.. */
slouken@7223
   803
        IDirectInput8_EnumDevices(dinput,
slouken@7191
   804
            DI8DEVCLASS_GAMECTRL,
slouken@7191
   805
            EnumJoysticksCallback,
slouken@7191
   806
            &pCurList, DIEDFL_ATTACHEDONLY);
slouken@6707
   807
icculus@7707
   808
        SDL_free(SDL_RawDevList);  /* in case we used this in DirectInput enumerator. */
icculus@7706
   809
        SDL_RawDevList = NULL;
icculus@7707
   810
        SDL_RawDevListCount = 0;
icculus@7706
   811
slouken@7191
   812
        SDL_UnlockMutex( s_mutexJoyStickEnum );
slouken@7191
   813
    }
slouken@7191
   814
slouken@7191
   815
    if ( pCurList )
slouken@7191
   816
    {
slouken@7191
   817
        while ( pCurList )
slouken@7191
   818
        {
slouken@7191
   819
            JoyStick_DeviceData *pListNext = NULL;
slouken@6707
   820
#if !SDL_EVENTS_DISABLED
slouken@7191
   821
            SDL_Event event;
slouken@7191
   822
            event.type = SDL_JOYDEVICEREMOVED;
slouken@6707
   823
slouken@7191
   824
            if (SDL_GetEventState(event.type) == SDL_ENABLE) {
slouken@7191
   825
                event.jdevice.which = pCurList->nInstanceID;
slouken@7191
   826
                if ((SDL_EventOK == NULL)
slouken@7191
   827
                    || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
slouken@7191
   828
                        SDL_PushEvent(&event);
slouken@7191
   829
                }
slouken@7191
   830
            }
slouken@7191
   831
#endif /* !SDL_EVENTS_DISABLED */
slouken@6707
   832
slouken@7191
   833
            pListNext = pCurList->pNext;
slouken@7191
   834
            SDL_free(pCurList->joystickname);
slouken@7191
   835
            SDL_free( pCurList );
slouken@7191
   836
            pCurList = pListNext;
slouken@7191
   837
        }
slouken@6707
   838
slouken@7191
   839
    }
slouken@6707
   840
slouken@7191
   841
    if ( s_bDeviceAdded )
slouken@7191
   842
    {
slouken@7191
   843
        JoyStick_DeviceData *pNewJoystick;
slouken@7191
   844
        int device_index = 0;
slouken@7191
   845
        s_bDeviceAdded = SDL_FALSE;
slouken@7191
   846
        pNewJoystick = SYS_Joystick;
slouken@7191
   847
        while ( pNewJoystick )
slouken@7191
   848
        {
slouken@7191
   849
            if ( pNewJoystick->send_add_event )
slouken@7191
   850
            {
slouken@6707
   851
#if !SDL_EVENTS_DISABLED
slouken@7191
   852
                SDL_Event event;
slouken@7191
   853
                event.type = SDL_JOYDEVICEADDED;
slouken@6707
   854
slouken@7191
   855
                if (SDL_GetEventState(event.type) == SDL_ENABLE) {
slouken@7191
   856
                    event.jdevice.which = device_index;
slouken@7191
   857
                    if ((SDL_EventOK == NULL)
slouken@7191
   858
                        || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
slouken@7191
   859
                            SDL_PushEvent(&event);
slouken@7191
   860
                    }
slouken@7191
   861
                }
slouken@6707
   862
#endif /* !SDL_EVENTS_DISABLED */
slouken@7191
   863
                pNewJoystick->send_add_event = 0;
slouken@7191
   864
            }
slouken@7191
   865
            device_index++;
slouken@7191
   866
            pNewJoystick = pNewJoystick->pNext;
slouken@7191
   867
        }
slouken@7191
   868
    }
slouken@6707
   869
}
slouken@6707
   870
slouken@6707
   871
/* we need to poll if we have pending hotplug device changes or connected devices */
slouken@6707
   872
SDL_bool SDL_SYS_JoystickNeedsPolling()
slouken@6707
   873
{
slouken@7191
   874
    /* we have a new device or one was pulled, we need to think this frame please */
slouken@7191
   875
    if ( s_bDeviceAdded || s_bDeviceRemoved )
slouken@7191
   876
        return SDL_TRUE;
slouken@6707
   877
slouken@7191
   878
    return SDL_FALSE;
slouken@6707
   879
}
slouken@6707
   880
slouken@1895
   881
/* Function to get the device-dependent name of a joystick */
slouken@1895
   882
const char *
slouken@6707
   883
SDL_SYS_JoystickNameForDeviceIndex(int device_index)
slouken@1895
   884
{
slouken@7191
   885
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@6690
   886
slouken@7191
   887
    for (; device_index > 0; device_index--)
slouken@7191
   888
        device = device->pNext;
slouken@6690
   889
slouken@7191
   890
    return device->joystickname;
slouken@1895
   891
}
slouken@1895
   892
slouken@6707
   893
/* Function to perform the mapping between current device instance and this joysticks instance id */
slouken@6707
   894
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
slouken@6707
   895
{
slouken@7191
   896
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@7191
   897
    int index;
slouken@6707
   898
slouken@7191
   899
    for (index = device_index; index > 0; index--)
slouken@7191
   900
        device = device->pNext;
slouken@6707
   901
slouken@7191
   902
    return device->nInstanceID;
slouken@6707
   903
}
slouken@6707
   904
slouken@1895
   905
/* Function to open a joystick for use.
slouken@1895
   906
   The joystick to open is specified by the index field of the joystick.
slouken@1895
   907
   This should fill the nbuttons and naxes fields of the joystick structure.
slouken@1895
   908
   It returns 0, or -1 if there is an error.
slouken@1895
   909
 */
slouken@1895
   910
int
slouken@6690
   911
SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
slouken@1895
   912
{
slouken@1895
   913
    HRESULT result;
slouken@7191
   914
    JoyStick_DeviceData *joystickdevice = SYS_Joystick;
slouken@6690
   915
slouken@7191
   916
    for (; device_index > 0; device_index--)
slouken@7191
   917
        joystickdevice = joystickdevice->pNext;
slouken@2198
   918
slouken@1895
   919
    /* allocate memory for system specific hardware data */
slouken@7191
   920
    joystick->instance_id = joystickdevice->nInstanceID;
urkle@6965
   921
    joystick->closed = 0;
slouken@1895
   922
    joystick->hwdata =
slouken@2713
   923
        (struct joystick_hwdata *) SDL_malloc(sizeof(struct joystick_hwdata));
slouken@1895
   924
    if (joystick->hwdata == NULL) {
icculus@7037
   925
        return SDL_OutOfMemory();
slouken@1895
   926
    }
icculus@7707
   927
    SDL_zerop(joystick->hwdata);
slouken@1895
   928
icculus@7707
   929
    if (joystickdevice->bXInputDevice) {
icculus@7707
   930
        const SDL_bool bIs14OrLater = (SDL_XInputVersion >= ((1<<16)|4));
icculus@7707
   931
        const Uint8 userId = joystickdevice->XInputUserId;
slouken@7191
   932
        XINPUT_CAPABILITIES capabilities;
slouken@1895
   933
icculus@7707
   934
        SDL_assert(s_bXInputEnabled);
icculus@7707
   935
        SDL_assert(XINPUTGETCAPABILITIES);
icculus@7707
   936
        SDL_assert(userId >= 0);
icculus@7707
   937
        SDL_assert(userId < SDL_XINPUT_MAX_DEVICES);
slouken@2198
   938
icculus@7707
   939
        joystick->hwdata->bXInputDevice = SDL_TRUE;
slouken@7684
   940
icculus@7707
   941
        if (XINPUTGETCAPABILITIES(userId, XINPUT_FLAG_GAMEPAD, &capabilities) != ERROR_SUCCESS) {
icculus@7707
   942
            SDL_free(joystick->hwdata);
icculus@7707
   943
            joystick->hwdata = NULL;
icculus@7707
   944
            return SDL_SetError("Failed to obtain XInput device capabilities. Device disconnected?");
icculus@7707
   945
        } else {
icculus@7707
   946
            /* Current version of XInput mistakenly returns 0 as the Type. Ignore it and ensure the subtype is a gamepad. */
icculus@7707
   947
            SDL_assert(capabilities.SubType == XINPUT_DEVSUBTYPE_GAMEPAD);
icculus@7707
   948
            if ((!bIs14OrLater) || (capabilities.Flags & XINPUT_CAPS_FFB_SUPPORTED)) {
icculus@7707
   949
                joystick->hwdata->bXInputHaptic = SDL_TRUE;
icculus@7707
   950
            }
icculus@7707
   951
            joystick->hwdata->userid = userId;
slouken@7684
   952
icculus@7707
   953
            /* The XInput API has a hard coded button/axis mapping, so we just match it */
icculus@7707
   954
            joystick->naxes = 6;
icculus@7707
   955
            joystick->nbuttons = 15;
icculus@7707
   956
            joystick->nballs = 0;
icculus@7707
   957
            joystick->nhats = 0;
icculus@7707
   958
		}
icculus@7707
   959
    } else {  /* use DirectInput, not XInput. */
icculus@7707
   960
        LPDIRECTINPUTDEVICE8 device;
icculus@7707
   961
        DIPROPDWORD dipdw;
slouken@1895
   962
icculus@7707
   963
        joystick->hwdata->buffered = 1;
icculus@7707
   964
        joystick->hwdata->removed = 0;
icculus@7707
   965
        joystick->hwdata->Capabilities.dwSize = sizeof(DIDEVCAPS);
icculus@7707
   966
        joystick->hwdata->guid = joystickdevice->guid;
icculus@7707
   967
icculus@7707
   968
        SDL_zero(dipdw);
icculus@7707
   969
        dipdw.diph.dwSize = sizeof(DIPROPDWORD);
icculus@7707
   970
        dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
slouken@1895
   971
slouken@7191
   972
        result =
slouken@7191
   973
            IDirectInput8_CreateDevice(dinput,
slouken@7191
   974
                                      &(joystickdevice->dxdevice.guidInstance), &device, NULL);
slouken@7191
   975
        if (FAILED(result)) {
slouken@7191
   976
            return SetDIerror("IDirectInput::CreateDevice", result);
slouken@7191
   977
        }
slouken@1895
   978
slouken@7191
   979
        /* Now get the IDirectInputDevice8 interface, instead. */
slouken@7191
   980
        result = IDirectInputDevice8_QueryInterface(device,
slouken@7191
   981
                                                   &IID_IDirectInputDevice8,
slouken@7191
   982
                                                   (LPVOID *) & joystick->
slouken@7191
   983
                                                   hwdata->InputDevice);
slouken@7191
   984
        /* We are done with this object.  Use the stored one from now on. */
slouken@7191
   985
        IDirectInputDevice8_Release(device);
slouken@1895
   986
slouken@7191
   987
        if (FAILED(result)) {
slouken@7191
   988
            return SetDIerror("IDirectInputDevice8::QueryInterface", result);
slouken@7191
   989
        }
slouken@2198
   990
slouken@7191
   991
        /* Acquire shared access. Exclusive access is required for forces,
slouken@7191
   992
         * though. */
slouken@7191
   993
        result =
slouken@7191
   994
            IDirectInputDevice8_SetCooperativeLevel(joystick->hwdata->
slouken@7191
   995
                                                    InputDevice, SDL_HelperWindow,
slouken@7191
   996
                                                    DISCL_NONEXCLUSIVE |
slouken@7191
   997
                                                    DISCL_BACKGROUND);
slouken@7191
   998
        if (FAILED(result)) {
slouken@7191
   999
            return SetDIerror("IDirectInputDevice8::SetCooperativeLevel", result);
slouken@7191
  1000
        }
slouken@2198
  1001
slouken@7191
  1002
        /* Use the extended data structure: DIJOYSTATE2. */
slouken@7191
  1003
        result =
slouken@7191
  1004
            IDirectInputDevice8_SetDataFormat(joystick->hwdata->InputDevice,
slouken@7191
  1005
                                              &c_dfDIJoystick2);
slouken@7191
  1006
        if (FAILED(result)) {
slouken@7191
  1007
            return SetDIerror("IDirectInputDevice8::SetDataFormat", result);
slouken@7191
  1008
        }
slouken@2198
  1009
slouken@7191
  1010
        /* Get device capabilities */
slouken@7191
  1011
        result =
slouken@7191
  1012
            IDirectInputDevice8_GetCapabilities(joystick->hwdata->InputDevice,
slouken@7191
  1013
                                                &joystick->hwdata->Capabilities);
slouken@2198
  1014
slouken@7191
  1015
        if (FAILED(result)) {
slouken@7191
  1016
            return SetDIerror("IDirectInputDevice8::GetCapabilities", result);
slouken@7191
  1017
        }
slouken@2198
  1018
slouken@7191
  1019
        /* Force capable? */
slouken@7191
  1020
        if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
slouken@2198
  1021
slouken@7191
  1022
            result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
slouken@2198
  1023
slouken@7191
  1024
            if (FAILED(result)) {
slouken@7191
  1025
                return SetDIerror("IDirectInputDevice8::Acquire", result);
slouken@7191
  1026
            }
slouken@2198
  1027
slouken@7191
  1028
            /* reset all accuators. */
slouken@7191
  1029
            result =
slouken@7191
  1030
                IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->
slouken@7191
  1031
                                                             InputDevice,
slouken@7191
  1032
                                                             DISFFC_RESET);
slouken@2198
  1033
slouken@7191
  1034
            /* Not necessarily supported, ignore if not supported.
slouken@7191
  1035
            if (FAILED(result)) {
slouken@7191
  1036
                return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand", result);
slouken@7191
  1037
            }
slouken@7191
  1038
            */
slouken@1895
  1039
slouken@7191
  1040
            result = IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
slouken@1895
  1041
slouken@7191
  1042
            if (FAILED(result)) {
slouken@7191
  1043
                return SetDIerror("IDirectInputDevice8::Unacquire", result);
slouken@7191
  1044
            }
slouken@2198
  1045
slouken@7191
  1046
            /* Turn on auto-centering for a ForceFeedback device (until told
slouken@7191
  1047
             * otherwise). */
slouken@7191
  1048
            dipdw.diph.dwObj = 0;
slouken@7191
  1049
            dipdw.diph.dwHow = DIPH_DEVICE;
slouken@7191
  1050
            dipdw.dwData = DIPROPAUTOCENTER_ON;
slouken@6220
  1051
slouken@7191
  1052
            result =
slouken@7191
  1053
                IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
slouken@7191
  1054
                                                DIPROP_AUTOCENTER, &dipdw.diph);
slouken@2198
  1055
slouken@7191
  1056
            /* Not necessarily supported, ignore if not supported.
slouken@7191
  1057
            if (FAILED(result)) {
slouken@7191
  1058
                return SetDIerror("IDirectInputDevice8::SetProperty", result);
slouken@7191
  1059
            }
slouken@7191
  1060
            */
slouken@7191
  1061
        }
slouken@2198
  1062
slouken@7191
  1063
        /* What buttons and axes does it have? */
slouken@7191
  1064
        IDirectInputDevice8_EnumObjects(joystick->hwdata->InputDevice,
slouken@7191
  1065
                                        EnumDevObjectsCallback, joystick,
slouken@7191
  1066
                                        DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV);
slouken@2198
  1067
slouken@7191
  1068
        /* Reorder the input objects. Some devices do not report the X axis as
slouken@7191
  1069
         * the first axis, for example. */
slouken@7191
  1070
        SortDevObjects(joystick);
slouken@6690
  1071
slouken@7191
  1072
        dipdw.diph.dwObj = 0;
slouken@7191
  1073
        dipdw.diph.dwHow = DIPH_DEVICE;
slouken@7191
  1074
        dipdw.dwData = INPUT_QSIZE;
slouken@6690
  1075
slouken@7191
  1076
        /* Set the buffer size */
slouken@7191
  1077
        result =
slouken@7191
  1078
            IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
slouken@7191
  1079
                                            DIPROP_BUFFERSIZE, &dipdw.diph);
slouken@6690
  1080
slouken@7191
  1081
        if (result == DI_POLLEDDEVICE) {
slouken@7191
  1082
            /* This device doesn't support buffering, so we're forced
slouken@7191
  1083
             * to use less reliable polling. */
slouken@7191
  1084
            joystick->hwdata->buffered = 0;
slouken@7191
  1085
        } else if (FAILED(result)) {
slouken@7191
  1086
            return SetDIerror("IDirectInputDevice8::SetProperty", result);
slouken@7191
  1087
        }
slouken@7191
  1088
    }
slouken@1895
  1089
    return (0);
slouken@1895
  1090
}
slouken@1895
  1091
slouken@6707
  1092
/* return true if this joystick is plugged in right now */
slouken@6707
  1093
SDL_bool SDL_SYS_JoystickAttached( SDL_Joystick * joystick )
slouken@6707
  1094
{
slouken@7191
  1095
    return joystick->closed == 0 && joystick->hwdata->removed == 0;
slouken@6707
  1096
}
slouken@6707
  1097
slouken@6707
  1098
slouken@6220
  1099
/* Sort using the data offset into the DInput struct.
slouken@6220
  1100
 * This gives a reasonable ordering for the inputs. */
slouken@6220
  1101
static int
slouken@6220
  1102
SortDevFunc(const void *a, const void *b)
slouken@6220
  1103
{
slouken@7191
  1104
    const input_t *inputA = (const input_t*)a;
slouken@7191
  1105
    const input_t *inputB = (const input_t*)b;
slouken@6220
  1106
slouken@7191
  1107
    if (inputA->ofs < inputB->ofs)
slouken@7191
  1108
        return -1;
slouken@7191
  1109
    if (inputA->ofs > inputB->ofs)
slouken@7191
  1110
        return 1;
slouken@7191
  1111
    return 0;
slouken@6220
  1112
}
slouken@6220
  1113
slouken@6220
  1114
/* Sort the input objects and recalculate the indices for each input. */
slouken@6220
  1115
static void
slouken@6220
  1116
SortDevObjects(SDL_Joystick *joystick)
slouken@6220
  1117
{
slouken@7191
  1118
    input_t *inputs = joystick->hwdata->Inputs;
slouken@7191
  1119
    int nButtons = 0;
slouken@7191
  1120
    int nHats = 0;
slouken@7191
  1121
    int nAxis = 0;
slouken@7191
  1122
    int n;
slouken@6220
  1123
slouken@7191
  1124
    SDL_qsort(inputs, joystick->hwdata->NumInputs, sizeof(input_t), SortDevFunc);
slouken@6220
  1125
slouken@7191
  1126
    for (n = 0; n < joystick->hwdata->NumInputs; n++)
slouken@7191
  1127
    {
slouken@7191
  1128
        switch (inputs[n].type)
slouken@7191
  1129
        {
slouken@7191
  1130
        case BUTTON:
slouken@7191
  1131
            inputs[n].num = nButtons;
slouken@7191
  1132
            nButtons++;
slouken@7191
  1133
            break;
slouken@6220
  1134
slouken@7191
  1135
        case HAT:
slouken@7191
  1136
            inputs[n].num = nHats;
slouken@7191
  1137
            nHats++;
slouken@7191
  1138
            break;
slouken@6220
  1139
slouken@7191
  1140
        case AXIS:
slouken@7191
  1141
            inputs[n].num = nAxis;
slouken@7191
  1142
            nAxis++;
slouken@7191
  1143
            break;
slouken@7191
  1144
        }
slouken@7191
  1145
    }
slouken@6220
  1146
}
slouken@6220
  1147
slouken@2198
  1148
static BOOL CALLBACK
slouken@2198
  1149
EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
slouken@2198
  1150
{
slouken@2198
  1151
    SDL_Joystick *joystick = (SDL_Joystick *) pvRef;
slouken@2198
  1152
    HRESULT result;
slouken@2198
  1153
    input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs];
slouken@2198
  1154
slouken@2198
  1155
    if (dev->dwType & DIDFT_BUTTON) {
slouken@2198
  1156
        in->type = BUTTON;
slouken@2198
  1157
        in->num = joystick->nbuttons;
slouken@7191
  1158
        in->ofs = DIJOFS_BUTTON( in->num );
slouken@2198
  1159
        joystick->nbuttons++;
slouken@2198
  1160
    } else if (dev->dwType & DIDFT_POV) {
slouken@2198
  1161
        in->type = HAT;
slouken@2198
  1162
        in->num = joystick->nhats;
slouken@7191
  1163
        in->ofs = DIJOFS_POV( in->num );
slouken@2198
  1164
        joystick->nhats++;
slouken@2198
  1165
    } else if (dev->dwType & DIDFT_AXIS) {
slouken@2198
  1166
        DIPROPRANGE diprg;
slouken@2198
  1167
        DIPROPDWORD dilong;
slouken@2198
  1168
slouken@2198
  1169
        in->type = AXIS;
slouken@2198
  1170
        in->num = joystick->naxes;
slouken@7191
  1171
        /* work our the axis this guy maps too, thanks for the code icculus! */
slouken@7191
  1172
        if ( !SDL_memcmp( &dev->guidType, &GUID_XAxis, sizeof(dev->guidType) ) )
slouken@7191
  1173
            in->ofs = DIJOFS_X;
slouken@7191
  1174
        else if ( !SDL_memcmp( &dev->guidType, &GUID_YAxis, sizeof(dev->guidType) ) )
slouken@7191
  1175
            in->ofs = DIJOFS_Y;
slouken@7191
  1176
        else if ( !SDL_memcmp( &dev->guidType, &GUID_ZAxis, sizeof(dev->guidType) ) )
slouken@7191
  1177
            in->ofs = DIJOFS_Z;
slouken@7191
  1178
        else if ( !SDL_memcmp( &dev->guidType, &GUID_RxAxis, sizeof(dev->guidType) ) )
slouken@7191
  1179
            in->ofs = DIJOFS_RX;
slouken@7191
  1180
        else if ( !SDL_memcmp( &dev->guidType, &GUID_RyAxis, sizeof(dev->guidType) ) )
slouken@7191
  1181
            in->ofs = DIJOFS_RY;
slouken@7191
  1182
        else if ( !SDL_memcmp( &dev->guidType, &GUID_RzAxis, sizeof(dev->guidType) ) )
slouken@7191
  1183
            in->ofs = DIJOFS_RZ;
slouken@7191
  1184
        else if ( !SDL_memcmp( &dev->guidType, &GUID_Slider, sizeof(dev->guidType) ) )
slouken@7191
  1185
        {
slouken@7191
  1186
            in->ofs = DIJOFS_SLIDER( joystick->hwdata->NumSliders );
slouken@7191
  1187
            ++joystick->hwdata->NumSliders;
slouken@7191
  1188
        }
slouken@7191
  1189
        else
slouken@7191
  1190
        {
slouken@7191
  1191
             return DIENUM_CONTINUE; /* not an axis we can grok */
slouken@7191
  1192
        }
slouken@2198
  1193
slouken@2198
  1194
        diprg.diph.dwSize = sizeof(diprg);
slouken@2198
  1195
        diprg.diph.dwHeaderSize = sizeof(diprg.diph);
slouken@6690
  1196
        diprg.diph.dwObj = dev->dwType;
slouken@6690
  1197
        diprg.diph.dwHow = DIPH_BYID;
slouken@2198
  1198
        diprg.lMin = AXIS_MIN;
slouken@2198
  1199
        diprg.lMax = AXIS_MAX;
slouken@2198
  1200
slouken@2198
  1201
        result =
slouken@6690
  1202
            IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
slouken@2198
  1203
                                            DIPROP_RANGE, &diprg.diph);
slouken@2198
  1204
        if (FAILED(result)) {
slouken@2198
  1205
            return DIENUM_CONTINUE;     /* don't use this axis */
slouken@2198
  1206
        }
slouken@2198
  1207
slouken@2198
  1208
        /* Set dead zone to 0. */
slouken@2198
  1209
        dilong.diph.dwSize = sizeof(dilong);
slouken@2198
  1210
        dilong.diph.dwHeaderSize = sizeof(dilong.diph);
slouken@6690
  1211
        dilong.diph.dwObj = dev->dwType;
slouken@6690
  1212
        dilong.diph.dwHow = DIPH_BYID;
slouken@2198
  1213
        dilong.dwData = 0;
slouken@2198
  1214
        result =
slouken@6690
  1215
            IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
slouken@2198
  1216
                                            DIPROP_DEADZONE, &dilong.diph);
slouken@2198
  1217
        if (FAILED(result)) {
slouken@2198
  1218
            return DIENUM_CONTINUE;     /* don't use this axis */
slouken@2198
  1219
        }
slouken@2198
  1220
slouken@2198
  1221
        joystick->naxes++;
slouken@2198
  1222
    } else {
slouken@2198
  1223
        /* not supported at this time */
slouken@2198
  1224
        return DIENUM_CONTINUE;
slouken@2198
  1225
    }
slouken@2198
  1226
slouken@2198
  1227
    joystick->hwdata->NumInputs++;
slouken@2198
  1228
slouken@2198
  1229
    if (joystick->hwdata->NumInputs == MAX_INPUTS) {
slouken@2198
  1230
        return DIENUM_STOP;     /* too many */
slouken@2198
  1231
    }
slouken@2198
  1232
slouken@2198
  1233
    return DIENUM_CONTINUE;
slouken@2198
  1234
}
slouken@2198
  1235
slouken@2198
  1236
/* Function to update the state of a joystick - called as a device poll.
slouken@2198
  1237
 * This function shouldn't update the joystick structure directly,
slouken@2198
  1238
 * but instead should call SDL_PrivateJoystick*() to deliver events
slouken@2198
  1239
 * and update joystick device state.
slouken@2198
  1240
 */
slouken@2198
  1241
void
slouken@2198
  1242
SDL_SYS_JoystickUpdate_Polled(SDL_Joystick * joystick)
slouken@2198
  1243
{
slouken@2198
  1244
    DIJOYSTATE2 state;
slouken@2198
  1245
    HRESULT result;
slouken@2198
  1246
    int i;
slouken@2198
  1247
slouken@2198
  1248
    result =
slouken@6690
  1249
        IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
slouken@2198
  1250
                                           sizeof(DIJOYSTATE2), &state);
slouken@2198
  1251
    if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
slouken@6690
  1252
        IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
slouken@2198
  1253
        result =
slouken@6690
  1254
            IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
slouken@2198
  1255
                                               sizeof(DIJOYSTATE2), &state);
slouken@2198
  1256
    }
slouken@2198
  1257
slouken@7191
  1258
    if ( result != DI_OK )
slouken@7191
  1259
    {
slouken@7191
  1260
        joystick->hwdata->send_remove_event = 1;
slouken@7191
  1261
        joystick->hwdata->removed = 1;
slouken@7191
  1262
        return;
slouken@7191
  1263
    }
slouken@6690
  1264
slouken@2198
  1265
    /* Set each known axis, button and POV. */
slouken@2198
  1266
    for (i = 0; i < joystick->hwdata->NumInputs; ++i) {
slouken@2198
  1267
        const input_t *in = &joystick->hwdata->Inputs[i];
slouken@2198
  1268
slouken@2198
  1269
        switch (in->type) {
slouken@2198
  1270
        case AXIS:
slouken@2198
  1271
            switch (in->ofs) {
slouken@2198
  1272
            case DIJOFS_X:
slouken@2198
  1273
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1274
                                            (Sint16) state.lX);
slouken@2198
  1275
                break;
slouken@2198
  1276
            case DIJOFS_Y:
slouken@2198
  1277
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1278
                                            (Sint16) state.lY);
slouken@2198
  1279
                break;
slouken@2198
  1280
            case DIJOFS_Z:
slouken@2198
  1281
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1282
                                            (Sint16) state.lZ);
slouken@2198
  1283
                break;
slouken@2198
  1284
            case DIJOFS_RX:
slouken@2198
  1285
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1286
                                            (Sint16) state.lRx);
slouken@2198
  1287
                break;
slouken@2198
  1288
            case DIJOFS_RY:
slouken@2198
  1289
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1290
                                            (Sint16) state.lRy);
slouken@2198
  1291
                break;
slouken@2198
  1292
            case DIJOFS_RZ:
slouken@2198
  1293
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1294
                                            (Sint16) state.lRz);
slouken@2198
  1295
                break;
slouken@2198
  1296
            case DIJOFS_SLIDER(0):
slouken@2198
  1297
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1298
                                            (Sint16) state.rglSlider[0]);
slouken@2198
  1299
                break;
slouken@2198
  1300
            case DIJOFS_SLIDER(1):
slouken@2198
  1301
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1302
                                            (Sint16) state.rglSlider[1]);
slouken@2198
  1303
                break;
slouken@2198
  1304
            }
slouken@2198
  1305
slouken@2198
  1306
            break;
slouken@2198
  1307
slouken@2198
  1308
        case BUTTON:
slouken@2198
  1309
            SDL_PrivateJoystickButton_Int(joystick, in->num,
slouken@3013
  1310
                                          (Uint8) (state.
slouken@3013
  1311
                                                   rgbButtons[in->ofs -
slouken@3013
  1312
                                                              DIJOFS_BUTTON0]
slouken@2198
  1313
                                                   ? SDL_PRESSED :
slouken@2198
  1314
                                                   SDL_RELEASED));
slouken@2198
  1315
            break;
slouken@2198
  1316
        case HAT:
slouken@2198
  1317
            {
slouken@2198
  1318
                Uint8 pos = TranslatePOV(state.rgdwPOV[in->ofs -
slouken@2198
  1319
                                                       DIJOFS_POV(0)]);
slouken@2198
  1320
                SDL_PrivateJoystickHat_Int(joystick, in->num, pos);
slouken@2198
  1321
                break;
slouken@2198
  1322
            }
slouken@2198
  1323
        }
slouken@2198
  1324
    }
slouken@2198
  1325
}
slouken@2198
  1326
slouken@2198
  1327
void
slouken@2198
  1328
SDL_SYS_JoystickUpdate_Buffered(SDL_Joystick * joystick)
slouken@2198
  1329
{
slouken@2198
  1330
    int i;
slouken@2198
  1331
    HRESULT result;
slouken@2198
  1332
    DWORD numevents;
slouken@2198
  1333
    DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
slouken@2198
  1334
slouken@2198
  1335
    numevents = INPUT_QSIZE;
slouken@2198
  1336
    result =
slouken@6690
  1337
        IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
slouken@2198
  1338
                                          sizeof(DIDEVICEOBJECTDATA), evtbuf,
slouken@2198
  1339
                                          &numevents, 0);
slouken@2198
  1340
    if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
slouken@6690
  1341
        IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
slouken@2198
  1342
        result =
slouken@6690
  1343
            IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
slouken@2198
  1344
                                              sizeof(DIDEVICEOBJECTDATA),
slouken@2198
  1345
                                              evtbuf, &numevents, 0);
slouken@2198
  1346
    }
slouken@2198
  1347
slouken@2198
  1348
    /* Handle the events or punt */
slouken@2198
  1349
    if (FAILED(result))
slouken@7191
  1350
    {
slouken@7191
  1351
        joystick->hwdata->send_remove_event = 1;
slouken@7191
  1352
        joystick->hwdata->removed = 1;
slouken@2198
  1353
        return;
slouken@7191
  1354
    }
slouken@2198
  1355
slouken@2198
  1356
    for (i = 0; i < (int) numevents; ++i) {
slouken@2198
  1357
        int j;
slouken@2198
  1358
slouken@2198
  1359
        for (j = 0; j < joystick->hwdata->NumInputs; ++j) {
slouken@2198
  1360
            const input_t *in = &joystick->hwdata->Inputs[j];
slouken@2198
  1361
slouken@2198
  1362
            if (evtbuf[i].dwOfs != in->ofs)
slouken@2198
  1363
                continue;
slouken@2198
  1364
slouken@2198
  1365
            switch (in->type) {
slouken@2198
  1366
            case AXIS:
slouken@2198
  1367
                SDL_PrivateJoystickAxis(joystick, in->num,
slouken@2198
  1368
                                        (Sint16) evtbuf[i].dwData);
slouken@2198
  1369
                break;
slouken@2198
  1370
            case BUTTON:
slouken@2198
  1371
                SDL_PrivateJoystickButton(joystick, in->num,
slouken@3013
  1372
                                          (Uint8) (evtbuf[i].
slouken@3013
  1373
                                                   dwData ? SDL_PRESSED :
slouken@2198
  1374
                                                   SDL_RELEASED));
slouken@2198
  1375
                break;
slouken@2198
  1376
            case HAT:
slouken@2198
  1377
                {
slouken@2198
  1378
                    Uint8 pos = TranslatePOV(evtbuf[i].dwData);
slouken@2198
  1379
                    SDL_PrivateJoystickHat(joystick, in->num, pos);
slouken@2198
  1380
                }
slouken@2198
  1381
            }
slouken@2198
  1382
        }
slouken@2198
  1383
    }
slouken@2198
  1384
}
slouken@2198
  1385
slouken@2198
  1386
slouken@6690
  1387
/* Function to return > 0 if a bit array of buttons differs after applying a mask
slouken@6690
  1388
*/
slouken@6690
  1389
int ButtonChanged( int ButtonsNow, int ButtonsPrev, int ButtonMask )
slouken@6690
  1390
{
slouken@7191
  1391
    return ( ButtonsNow & ButtonMask ) != ( ButtonsPrev & ButtonMask );
slouken@6690
  1392
}
slouken@6690
  1393
slouken@6690
  1394
/* Function to update the state of a XInput style joystick.
slouken@6690
  1395
*/
slouken@6690
  1396
void
slouken@6690
  1397
SDL_SYS_JoystickUpdate_XInput(SDL_Joystick * joystick)
slouken@6690
  1398
{
slouken@7191
  1399
    HRESULT result;
slouken@6690
  1400
slouken@7191
  1401
    if ( !XINPUTGETSTATE )
slouken@7191
  1402
        return;
slouken@6690
  1403
slouken@7191
  1404
    result = XINPUTGETSTATE( joystick->hwdata->userid, &joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot] );
slouken@7191
  1405
    if ( result == ERROR_DEVICE_NOT_CONNECTED )
slouken@7191
  1406
    {
slouken@7191
  1407
        joystick->hwdata->send_remove_event = 1;
slouken@7191
  1408
        joystick->hwdata->removed = 1;
slouken@7191
  1409
        return;
slouken@7191
  1410
    }
slouken@6690
  1411
slouken@7191
  1412
    /* only fire events if the data changed from last time */
slouken@7191
  1413
    if ( joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot].dwPacketNumber != 0
slouken@7191
  1414
        && joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot].dwPacketNumber != joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot^1].dwPacketNumber )
slouken@7191
  1415
    {
slouken@7191
  1416
        XINPUT_STATE_EX *pXInputState = &joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot];
slouken@7191
  1417
        XINPUT_STATE_EX *pXInputStatePrev = &joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot ^ 1];
slouken@6690
  1418
slouken@7296
  1419
        SDL_PrivateJoystickAxis( joystick, 0, (Sint16)pXInputState->Gamepad.sThumbLX );
slouken@7321
  1420
        SDL_PrivateJoystickAxis( joystick, 1, (Sint16)(-SDL_max(-32767, pXInputState->Gamepad.sThumbLY)) );
slouken@7296
  1421
        SDL_PrivateJoystickAxis( joystick, 2, (Sint16)pXInputState->Gamepad.sThumbRX );
slouken@7321
  1422
        SDL_PrivateJoystickAxis( joystick, 3, (Sint16)(-SDL_max(-32767, pXInputState->Gamepad.sThumbRY)) );
slouken@7296
  1423
        SDL_PrivateJoystickAxis( joystick, 4, (Sint16)(((int)pXInputState->Gamepad.bLeftTrigger*65535/255) - 32768));
slouken@7296
  1424
        SDL_PrivateJoystickAxis( joystick, 5, (Sint16)(((int)pXInputState->Gamepad.bRightTrigger*65535/255) - 32768));
slouken@6690
  1425
slouken@7191
  1426
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_UP ) )
slouken@7191
  1427
            SDL_PrivateJoystickButton(joystick, 0, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP ? SDL_PRESSED :  SDL_RELEASED );
slouken@7191
  1428
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_DOWN ) )
slouken@7191
  1429
            SDL_PrivateJoystickButton(joystick, 1, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN ? SDL_PRESSED :    SDL_RELEASED );
slouken@7191
  1430
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_LEFT ) )
slouken@7191
  1431
            SDL_PrivateJoystickButton(joystick, 2, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT ? SDL_PRESSED :    SDL_RELEASED );
slouken@7191
  1432
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_RIGHT ) )
slouken@7191
  1433
            SDL_PrivateJoystickButton(joystick, 3, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1434
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_START ) )
slouken@7191
  1435
            SDL_PrivateJoystickButton(joystick, 4, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_START ? SDL_PRESSED :    SDL_RELEASED );
slouken@7191
  1436
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_BACK ) )
slouken@7191
  1437
            SDL_PrivateJoystickButton(joystick, 5, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_BACK ? SDL_PRESSED : SDL_RELEASED );
slouken@7191
  1438
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_THUMB ) )
slouken@7191
  1439
            SDL_PrivateJoystickButton(joystick, 6, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1440
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_RIGHT_THUMB ) )
slouken@7191
  1441
            SDL_PrivateJoystickButton(joystick, 7, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB ? SDL_PRESSED :  SDL_RELEASED );
slouken@7191
  1442
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_SHOULDER ) )
slouken@7191
  1443
            SDL_PrivateJoystickButton(joystick, 8, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER ? SDL_PRESSED :    SDL_RELEASED );
slouken@7191
  1444
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_RIGHT_SHOULDER ) )
slouken@7191
  1445
            SDL_PrivateJoystickButton(joystick, 9, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1446
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_A ) )
slouken@7191
  1447
            SDL_PrivateJoystickButton(joystick, 10, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_A ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1448
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_B ) )
slouken@7191
  1449
            SDL_PrivateJoystickButton(joystick, 11, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_B ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1450
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_X ) )
slouken@7191
  1451
            SDL_PrivateJoystickButton(joystick, 12, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_X ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1452
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_Y ) )
slouken@7191
  1453
            SDL_PrivateJoystickButton(joystick, 13, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_Y ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1454
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons,  0x400 ) )
slouken@7191
  1455
            SDL_PrivateJoystickButton(joystick, 14, pXInputState->Gamepad.wButtons & 0x400 ? SDL_PRESSED :  SDL_RELEASED ); /* 0x400 is the undocumented code for the guide button */
slouken@6690
  1456
slouken@7191
  1457
        joystick->hwdata->currentXInputSlot ^= 1;
slouken@6690
  1458
slouken@7191
  1459
    }
slouken@6690
  1460
}
slouken@6690
  1461
slouken@6690
  1462
slouken@1895
  1463
static Uint8
slouken@1895
  1464
TranslatePOV(DWORD value)
slouken@1895
  1465
{
slouken@1895
  1466
    const int HAT_VALS[] = {
slouken@1895
  1467
        SDL_HAT_UP,
slouken@1895
  1468
        SDL_HAT_UP | SDL_HAT_RIGHT,
slouken@1895
  1469
        SDL_HAT_RIGHT,
slouken@1895
  1470
        SDL_HAT_DOWN | SDL_HAT_RIGHT,
slouken@1895
  1471
        SDL_HAT_DOWN,
slouken@1895
  1472
        SDL_HAT_DOWN | SDL_HAT_LEFT,
slouken@1895
  1473
        SDL_HAT_LEFT,
slouken@1895
  1474
        SDL_HAT_UP | SDL_HAT_LEFT
slouken@1895
  1475
    };
slouken@1895
  1476
slouken@1895
  1477
    if (LOWORD(value) == 0xFFFF)
slouken@1895
  1478
        return SDL_HAT_CENTERED;
slouken@1895
  1479
slouken@1895
  1480
    /* Round the value up: */
slouken@1895
  1481
    value += 4500 / 2;
slouken@1895
  1482
    value %= 36000;
slouken@1895
  1483
    value /= 4500;
slouken@1895
  1484
slouken@1895
  1485
    if (value >= 8)
slouken@1895
  1486
        return SDL_HAT_CENTERED;        /* shouldn't happen */
slouken@1895
  1487
slouken@1895
  1488
    return HAT_VALS[value];
slouken@1895
  1489
}
slouken@1895
  1490
slouken@1895
  1491
/* SDL_PrivateJoystick* doesn't discard duplicate events, so we need to
slouken@1895
  1492
 * do it. */
slouken@1895
  1493
static int
slouken@1895
  1494
SDL_PrivateJoystickAxis_Int(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
slouken@1895
  1495
{
slouken@1895
  1496
    if (joystick->axes[axis] != value)
slouken@1895
  1497
        return SDL_PrivateJoystickAxis(joystick, axis, value);
slouken@1895
  1498
    return 0;
slouken@1895
  1499
}
slouken@1895
  1500
slouken@1895
  1501
static int
slouken@1895
  1502
SDL_PrivateJoystickHat_Int(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
slouken@1895
  1503
{
slouken@1895
  1504
    if (joystick->hats[hat] != value)
slouken@1895
  1505
        return SDL_PrivateJoystickHat(joystick, hat, value);
slouken@1895
  1506
    return 0;
slouken@1895
  1507
}
slouken@1895
  1508
slouken@1895
  1509
static int
slouken@1895
  1510
SDL_PrivateJoystickButton_Int(SDL_Joystick * joystick, Uint8 button,
slouken@1895
  1511
                              Uint8 state)
slouken@1895
  1512
{
slouken@1895
  1513
    if (joystick->buttons[button] != state)
slouken@1895
  1514
        return SDL_PrivateJoystickButton(joystick, button, state);
slouken@1895
  1515
    return 0;
slouken@1895
  1516
}
slouken@1895
  1517
slouken@1895
  1518
void
slouken@1895
  1519
SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
slouken@1895
  1520
{
slouken@1895
  1521
    HRESULT result;
slouken@1895
  1522
slouken@7191
  1523
    if ( joystick->closed || !joystick->hwdata )
slouken@7191
  1524
        return;
slouken@1895
  1525
slouken@7191
  1526
    if (joystick->hwdata->bXInputDevice)
slouken@7191
  1527
    {
slouken@7191
  1528
        SDL_SYS_JoystickUpdate_XInput(joystick);
slouken@7191
  1529
    }
slouken@7191
  1530
    else
slouken@7191
  1531
    {
slouken@7191
  1532
        result = IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
slouken@7191
  1533
        if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
slouken@7191
  1534
            IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
slouken@7191
  1535
            IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
slouken@7191
  1536
        }
slouken@6690
  1537
slouken@7191
  1538
        if (joystick->hwdata->buffered)
slouken@7191
  1539
            SDL_SYS_JoystickUpdate_Buffered(joystick);
slouken@7191
  1540
        else
slouken@7191
  1541
            SDL_SYS_JoystickUpdate_Polled(joystick);
slouken@7191
  1542
    }
slouken@6690
  1543
slouken@7191
  1544
    if ( joystick->hwdata->removed )
slouken@7191
  1545
    {
slouken@7191
  1546
        joystick->closed = 1;
slouken@7191
  1547
        joystick->uncentered = 1;
slouken@7191
  1548
    }
slouken@1895
  1549
}
slouken@1895
  1550
slouken@1895
  1551
/* Function to close a joystick after use */
slouken@1895
  1552
void
slouken@1895
  1553
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
slouken@1895
  1554
{
slouken@7191
  1555
    if ( joystick->hwdata->bXInputDevice )
slouken@7191
  1556
    {
slouken@7191
  1557
        JoyStick_DeviceData *joysticklist = SYS_Joystick;
slouken@7191
  1558
        /* scan the opened joysticks and clear the userid for this instance */
slouken@7191
  1559
        for( ; joysticklist; joysticklist = joysticklist->pNext)
slouken@7191
  1560
        {
slouken@7191
  1561
            if ( joysticklist->bXInputDevice && joysticklist->nInstanceID == joystick->instance_id )
slouken@7191
  1562
            {
slouken@7191
  1563
                joysticklist->XInputUserId = INVALID_XINPUT_USERID;
slouken@7191
  1564
            }
slouken@7191
  1565
        }
slouken@6690
  1566
slouken@7191
  1567
    }
slouken@7191
  1568
    else
slouken@7191
  1569
    {
slouken@7191
  1570
        IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
slouken@7191
  1571
        IDirectInputDevice8_Release(joystick->hwdata->InputDevice);
slouken@7191
  1572
    }
slouken@1895
  1573
slouken@1895
  1574
    if (joystick->hwdata != NULL) {
slouken@1895
  1575
        /* free system specific hardware data */
slouken@2713
  1576
        SDL_free(joystick->hwdata);
slouken@1895
  1577
    }
slouken@6690
  1578
slouken@7191
  1579
    joystick->closed = 1;
slouken@1895
  1580
}
slouken@1895
  1581
slouken@1895
  1582
/* Function to perform any system-specific joystick related cleanup */
slouken@1895
  1583
void
slouken@1895
  1584
SDL_SYS_JoystickQuit(void)
slouken@1895
  1585
{
slouken@7191
  1586
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@5090
  1587
slouken@7191
  1588
    while ( device )
slouken@7191
  1589
    {
slouken@7191
  1590
        JoyStick_DeviceData *device_next = device->pNext;
slouken@7191
  1591
        SDL_free(device->joystickname);
slouken@7191
  1592
        SDL_free(device);
slouken@7191
  1593
        device = device_next;
slouken@7191
  1594
    }
slouken@7191
  1595
    SYS_Joystick = NULL;
slouken@6690
  1596
slouken@7191
  1597
    if ( s_threadJoystick )
slouken@7191
  1598
    {
slouken@7191
  1599
        SDL_LockMutex( s_mutexJoyStickEnum );
slouken@7191
  1600
        s_bJoystickThreadQuit = SDL_TRUE;
slouken@7191
  1601
        SDL_CondBroadcast( s_condJoystickThread ); /* signal the joystick thread to quit */
slouken@7191
  1602
        SDL_UnlockMutex( s_mutexJoyStickEnum );
slouken@7191
  1603
        SDL_WaitThread( s_threadJoystick, NULL ); /* wait for it to bugger off */
slouken@6690
  1604
slouken@7191
  1605
        SDL_DestroyMutex( s_mutexJoyStickEnum );
slouken@7191
  1606
        SDL_DestroyCond( s_condJoystickThread );
slouken@7191
  1607
        s_condJoystickThread= NULL;
slouken@7191
  1608
        s_mutexJoyStickEnum = NULL;
slouken@7191
  1609
        s_threadJoystick = NULL;
slouken@7191
  1610
    }
slouken@5090
  1611
icculus@5591
  1612
    if (dinput != NULL) {
slouken@6690
  1613
        IDirectInput8_Release(dinput);
icculus@5591
  1614
        dinput = NULL;
icculus@5591
  1615
    }
icculus@5591
  1616
icculus@5591
  1617
    if (coinitialized) {
icculus@5591
  1618
        WIN_CoUninitialize();
icculus@5591
  1619
        coinitialized = SDL_FALSE;
icculus@5591
  1620
    }
slouken@6690
  1621
icculus@6990
  1622
    if (s_bXInputEnabled) {
icculus@6990
  1623
        WIN_UnloadXInputDLL();
icculus@6990
  1624
    }
slouken@6690
  1625
}
slouken@6690
  1626
slouken@6690
  1627
/* return the stable device guid for this device index */
slouken@6738
  1628
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
slouken@6690
  1629
{
slouken@7191
  1630
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@7191
  1631
    int index;
slouken@6690
  1632
slouken@7191
  1633
    for (index = device_index; index > 0; index--)
slouken@7191
  1634
        device = device->pNext;
slouken@6690
  1635
slouken@7191
  1636
    return device->guid;
slouken@6690
  1637
}
slouken@6690
  1638
slouken@6738
  1639
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
slouken@6707
  1640
{
slouken@7191
  1641
    return joystick->hwdata->guid;
slouken@6707
  1642
}
slouken@6707
  1643
slouken@6707
  1644
/* return SDL_TRUE if this device is using XInput */
slouken@6707
  1645
SDL_bool SDL_SYS_IsXInputDeviceIndex(int device_index)
slouken@6690
  1646
{
slouken@7191
  1647
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@7191
  1648
    int index;
slouken@6690
  1649
slouken@7191
  1650
    for (index = device_index; index > 0; index--)
slouken@7191
  1651
        device = device->pNext;
slouken@6690
  1652
slouken@7191
  1653
    return device->bXInputDevice;
slouken@6690
  1654
}
slouken@6690
  1655
slouken@7685
  1656
/* return SDL_TRUE if this device was opened with XInput */
slouken@7685
  1657
SDL_bool SDL_SYS_IsXInputJoystick(SDL_Joystick * joystick)
slouken@7685
  1658
{
slouken@7685
  1659
	return joystick->hwdata->bXInputDevice;
slouken@7685
  1660
}
slouken@7685
  1661
slouken@1895
  1662
#endif /* SDL_JOYSTICK_DINPUT */
slouken@3575
  1663
slouken@1895
  1664
/* vi: set ts=4 sw=4 expandtab: */