src/joystick/windows/SDL_dxjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 21 Aug 2013 10:31:44 -0700
changeset 7684 dee82553d409
parent 7663 53fe1b64eb2d
child 7685 89f669598b87
permissions -rw-r--r--
Fix SDL xinput code to work at all when xinput has devices at high indexes but no device connected at lower index, for instance 0->disconnected, 1->wireles, 2->wired. Previously the SDL code assumed the indexes were always used up in order which is not true at all and lead to a bunch of failure cases where controllers would go unrecognized.

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