src/joystick/windows/SDL_dxjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 06 Jun 2013 17:59:01 -0700
changeset 7293 341d22fe9044
parent 7265 3bb309bb6bfe
child 7296 a8145f734ad3
permissions -rw-r--r--
The triggers should be expanded out to the full range to match DirectInput behavior.
The game controller code will scale them back to 0 - 32767 when it converts the triggers axes.
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@6690
   399
slouken@6690
   400
DEFINE_GUID(CLSID_WbemLocator,   0x4590f811,0x1d3a,0x11d0,0x89,0x1F,0x00,0xaa,0x00,0x4b,0x2e,0x24);
slouken@7230
   401
/* The Windows SDK doesn't define this GUID */
slouken@6690
   402
DEFINE_GUID(IID_IWbemLocator,    0xdc12a687,0x737f,0x11cf,0x88,0x4d,0x00,0xaa,0x00,0x4b,0x2e,0x24);
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@7191
   414
    IWbemLocator*           pIWbemLocator  = NULL;
slouken@7191
   415
    IEnumWbemClassObject*   pEnumDevices   = NULL;
slouken@7191
   416
    IWbemClassObject*       pDevices[20];
slouken@7191
   417
    IWbemServices*          pIWbemServices = NULL;
slouken@7191
   418
    DWORD                   uReturned      = 0;
slouken@7191
   419
    BSTR                    bstrNamespace  = NULL;
slouken@7191
   420
    BSTR                    bstrDeviceID   = NULL;
slouken@7191
   421
    BSTR                    bstrClassName  = NULL;
slouken@7191
   422
    SDL_bool                bIsXinputDevice= SDL_FALSE;
slouken@7191
   423
    UINT                    iDevice        = 0;
slouken@7191
   424
    VARIANT                 var;
slouken@7191
   425
    HRESULT                 hr;
slouken@7191
   426
    DWORD bCleanupCOM;
slouken@6690
   427
urkle@6965
   428
    if (!s_bXInputEnabled)
urkle@6965
   429
    {
urkle@6965
   430
        return SDL_FALSE;
urkle@6965
   431
    }
urkle@6965
   432
slouken@7191
   433
    SDL_memset( pDevices, 0x0, sizeof(pDevices) );
slouken@6690
   434
slouken@7191
   435
    /* CoInit if needed */
slouken@7191
   436
    hr = CoInitialize(NULL);
slouken@7191
   437
    bCleanupCOM = SUCCEEDED(hr);
slouken@6690
   438
slouken@7191
   439
    /* Create WMI */
slouken@7191
   440
    hr = CoCreateInstance( &CLSID_WbemLocator,
slouken@7191
   441
        NULL,
slouken@7191
   442
        CLSCTX_INPROC_SERVER,
slouken@7191
   443
        &IID_IWbemLocator,
slouken@7191
   444
        (LPVOID*) &pIWbemLocator);
slouken@7191
   445
    if( FAILED(hr) || pIWbemLocator == NULL )
slouken@7191
   446
        goto LCleanup;
slouken@6690
   447
slouken@7191
   448
    bstrNamespace = SysAllocString( L"\\\\.\\root\\cimv2" );if( bstrNamespace == NULL ) goto LCleanup;
slouken@7191
   449
    bstrClassName = SysAllocString( L"Win32_PNPEntity" );   if( bstrClassName == NULL ) goto LCleanup;
slouken@7191
   450
    bstrDeviceID  = SysAllocString( L"DeviceID" );          if( bstrDeviceID == NULL )  goto LCleanup;
slouken@6690
   451
slouken@7191
   452
    /* Connect to WMI */
slouken@7191
   453
    hr = IWbemLocator_ConnectServer( pIWbemLocator, bstrNamespace, NULL, NULL, 0L,
slouken@7191
   454
        0L, NULL, NULL, &pIWbemServices );
slouken@7191
   455
    if( FAILED(hr) || pIWbemServices == NULL )
slouken@7191
   456
        goto LCleanup;
slouken@6690
   457
slouken@7191
   458
    /* Switch security level to IMPERSONATE. */
slouken@7191
   459
    CoSetProxyBlanket( (IUnknown *)pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
slouken@7191
   460
        RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE );
slouken@6690
   461
slouken@7191
   462
    hr = IWbemServices_CreateInstanceEnum( pIWbemServices, bstrClassName, 0, NULL, &pEnumDevices );
slouken@7191
   463
    if( FAILED(hr) || pEnumDevices == NULL )
slouken@7191
   464
        goto LCleanup;
slouken@6690
   465
slouken@7191
   466
    /* Loop over all devices */
slouken@7191
   467
    for( ;; )
slouken@7191
   468
    {
slouken@7191
   469
        /* Get 20 at a time */
slouken@7191
   470
        hr = IEnumWbemClassObject_Next( pEnumDevices, 10000, 20, pDevices, &uReturned );
slouken@7191
   471
        if( FAILED(hr) )
slouken@7191
   472
            goto LCleanup;
slouken@7191
   473
        if( uReturned == 0 )
slouken@7191
   474
            break;
slouken@6690
   475
slouken@7191
   476
        for( iDevice=0; iDevice<uReturned; iDevice++ )
slouken@7191
   477
        {
slouken@7191
   478
            /* For each device, get its device ID */
slouken@7191
   479
            hr = IWbemClassObject_Get( pDevices[iDevice], bstrDeviceID, 0L, &var, NULL, NULL );
slouken@7191
   480
            if(  SUCCEEDED( hr ) && var.vt == VT_BSTR && var.bstrVal != NULL )
slouken@7191
   481
            {
slouken@7191
   482
                /* Check if the device ID contains "IG_".  If it does, then it's an XInput device */
slouken@7191
   483
                /* This information can not be found from DirectInput */
slouken@7191
   484
                char *pDeviceString = WIN_StringToUTF8( var.bstrVal );
slouken@7191
   485
                if( SDL_strstr( pDeviceString, "IG_" ) )
slouken@7191
   486
                {
slouken@7191
   487
                    /* If it does, then get the VID/PID from var.bstrVal */
slouken@7191
   488
                    long dwPid = 0, dwVid = 0;
slouken@7191
   489
                    char * strPid = NULL;
slouken@7191
   490
                    DWORD dwVidPid = 0;
slouken@7191
   491
                    char * strVid = SDL_strstr( pDeviceString, "VID_" );
slouken@7191
   492
                    if( strVid )
slouken@7191
   493
                    {
slouken@7191
   494
                        dwVid = SDL_strtol( strVid + 4, NULL, 16 );
slouken@7191
   495
                    }
slouken@7191
   496
                    strPid = SDL_strstr( pDeviceString, "PID_" );
slouken@7191
   497
                    if( strPid  )
slouken@7191
   498
                    {
slouken@7191
   499
                        dwPid = SDL_strtol( strPid + 4, NULL, 16 );
slouken@7191
   500
                    }
slouken@6690
   501
slouken@7191
   502
                    /* Compare the VID/PID to the DInput device */
slouken@7191
   503
                    dwVidPid = MAKELONG( dwVid, dwPid );
slouken@7191
   504
                    if( dwVidPid == pGuidProductFromDirectInput->Data1 )
slouken@7191
   505
                    {
slouken@7191
   506
                        bIsXinputDevice = SDL_TRUE;
slouken@7191
   507
                    }
slouken@7191
   508
                }
slouken@7191
   509
                if ( pDeviceString )
slouken@7191
   510
                    SDL_free( pDeviceString );
slouken@7191
   511
slouken@7191
   512
                if ( bIsXinputDevice )
slouken@7191
   513
                    break;
slouken@7191
   514
            }
slouken@7191
   515
            SAFE_RELEASE( pDevices[iDevice] );
slouken@7191
   516
        }
slouken@7191
   517
    }
slouken@7191
   518
slouken@6690
   519
LCleanup:
slouken@6690
   520
slouken@7191
   521
    for( iDevice=0; iDevice<20; iDevice++ )
slouken@7191
   522
        SAFE_RELEASE( pDevices[iDevice] );
slouken@7191
   523
    SAFE_RELEASE( pEnumDevices );
slouken@7191
   524
    SAFE_RELEASE( pIWbemLocator );
slouken@7191
   525
    SAFE_RELEASE( pIWbemServices );
slouken@6690
   526
slouken@7191
   527
    if ( bstrNamespace )
slouken@7191
   528
        SysFreeString( bstrNamespace );
slouken@7191
   529
    if ( bstrClassName )
slouken@7191
   530
        SysFreeString( bstrClassName );
slouken@7191
   531
    if ( bstrDeviceID )
slouken@7191
   532
        SysFreeString( bstrDeviceID );
slouken@6690
   533
slouken@7191
   534
    if( bCleanupCOM )
slouken@7191
   535
        CoUninitialize();
slouken@7191
   536
slouken@7191
   537
    return bIsXinputDevice;
slouken@6690
   538
}
slouken@6690
   539
slouken@6690
   540
slouken@6690
   541
static SDL_bool s_bWindowsDeviceChanged = SDL_FALSE;
slouken@6690
   542
philipp@7133
   543
/* windowproc for our joystick detect thread message only window, to detect any USB device addition/removal
slouken@6690
   544
 */
slouken@6690
   545
LRESULT CALLBACK SDL_PrivateJoystickDetectProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)    {
slouken@7191
   546
    switch (message)    {
slouken@7191
   547
    case WM_DEVICECHANGE:
slouken@7191
   548
        switch (wParam) {
slouken@7191
   549
        case DBT_DEVICEARRIVAL:
slouken@7191
   550
            if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)    {
slouken@7191
   551
                s_bWindowsDeviceChanged = SDL_TRUE;
slouken@7191
   552
            }
slouken@7191
   553
            break;
slouken@7191
   554
        case DBT_DEVICEREMOVECOMPLETE:
slouken@7191
   555
            if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)    {
slouken@7191
   556
                s_bWindowsDeviceChanged = SDL_TRUE;
slouken@7191
   557
            }
slouken@7191
   558
            break;
slouken@7191
   559
        }
slouken@7191
   560
        return 0;
slouken@7191
   561
    }
slouken@6690
   562
slouken@7191
   563
    return DefWindowProc (hwnd, message, wParam, lParam);
slouken@6690
   564
}
slouken@6690
   565
slouken@6690
   566
slouken@6690
   567
DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, \
slouken@7191
   568
    0xC0, 0x4F, 0xB9, 0x51, 0xED);
slouken@6690
   569
slouken@6690
   570
/* Function/thread to scan the system for joysticks.
slouken@6690
   571
 */
slouken@6690
   572
static int
slouken@6690
   573
SDL_JoystickThread(void *_data)
slouken@6690
   574
{
slouken@7191
   575
    HWND messageWindow = 0;
slouken@7191
   576
    HDEVNOTIFY hNotify = 0;
slouken@7191
   577
    DEV_BROADCAST_DEVICEINTERFACE dbh;
slouken@7191
   578
    SDL_bool bOpenedXInputDevices[4];
slouken@7191
   579
    WNDCLASSEX wincl;
slouken@6710
   580
slouken@7191
   581
    SDL_memset( bOpenedXInputDevices, 0x0, sizeof(bOpenedXInputDevices) );
slouken@6690
   582
slouken@7223
   583
    WIN_CoInitialize();
slouken@6690
   584
slouken@7191
   585
    SDL_memset( &wincl, 0x0, sizeof(wincl) );
slouken@7191
   586
    wincl.hInstance = GetModuleHandle( NULL );
slouken@7191
   587
    wincl.lpszClassName = L"Message";
slouken@7191
   588
    wincl.lpfnWndProc = SDL_PrivateJoystickDetectProc;      /* This function is called by windows */
slouken@7191
   589
    wincl.cbSize = sizeof (WNDCLASSEX);
slouken@6712
   590
slouken@7191
   591
    if (!RegisterClassEx (&wincl))
slouken@7191
   592
    {
slouken@7191
   593
        return SDL_SetError("Failed to create register class for joystick autodetect.", GetLastError());
slouken@7191
   594
    }
slouken@6712
   595
slouken@7191
   596
    messageWindow = (HWND)CreateWindowEx( 0,  L"Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL );
slouken@7191
   597
    if ( !messageWindow )
slouken@7191
   598
    {
slouken@7191
   599
        return SDL_SetError("Failed to create message window for joystick autodetect.", GetLastError());
slouken@7191
   600
    }
slouken@6690
   601
slouken@7191
   602
    SDL_memset(&dbh, 0x0, sizeof(dbh));
slouken@6690
   603
slouken@7191
   604
    dbh.dbcc_size = sizeof(dbh);
slouken@7191
   605
    dbh.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
slouken@7191
   606
    dbh.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE;
slouken@6690
   607
slouken@7191
   608
    hNotify = RegisterDeviceNotification( messageWindow, &dbh, DEVICE_NOTIFY_WINDOW_HANDLE );
slouken@7191
   609
    if ( !hNotify )
slouken@7191
   610
    {
slouken@7191
   611
        return SDL_SetError("Failed to create notify device for joystick autodetect.", GetLastError());
slouken@7191
   612
    }
slouken@6690
   613
slouken@7191
   614
    SDL_LockMutex( s_mutexJoyStickEnum );
slouken@7191
   615
    while ( s_bJoystickThreadQuit == SDL_FALSE )
slouken@7191
   616
    {
slouken@7191
   617
        MSG messages;
slouken@7191
   618
        Uint8 userId;
slouken@7191
   619
        int nCurrentOpenedXInputDevices = 0;
slouken@7191
   620
        int nNewOpenedXInputDevices = 0;
slouken@7191
   621
        SDL_CondWaitTimeout( s_condJoystickThread, s_mutexJoyStickEnum, 300 );
slouken@6690
   622
slouken@7191
   623
        while ( s_bJoystickThreadQuit == SDL_FALSE && PeekMessage(&messages, messageWindow, 0, 0, PM_NOREMOVE) )
slouken@7191
   624
        {
slouken@7191
   625
            if ( GetMessage(&messages, messageWindow, 0, 0) != 0 )  {
slouken@7191
   626
                TranslateMessage(&messages);
slouken@7191
   627
                DispatchMessage(&messages);
slouken@7191
   628
            }
slouken@7191
   629
        }
slouken@6690
   630
slouken@7191
   631
        if ( s_bXInputEnabled && XINPUTGETCAPABILITIES )
slouken@7191
   632
        {
slouken@7191
   633
            /* scan for any change in XInput devices */
slouken@7191
   634
            for ( userId = 0; userId < 4; userId++ )
slouken@7191
   635
            {
slouken@7191
   636
                XINPUT_CAPABILITIES capabilities;
slouken@7191
   637
                DWORD result;
slouken@6710
   638
slouken@7191
   639
                if ( bOpenedXInputDevices[userId] == SDL_TRUE )
slouken@7191
   640
                    nCurrentOpenedXInputDevices++;
slouken@6710
   641
slouken@7191
   642
                result = XINPUTGETCAPABILITIES( userId, XINPUT_FLAG_GAMEPAD, &capabilities );
slouken@7191
   643
                if ( result == ERROR_SUCCESS )
slouken@7191
   644
                {
slouken@7191
   645
                    bOpenedXInputDevices[userId] = SDL_TRUE;
slouken@7191
   646
                    nNewOpenedXInputDevices++;
slouken@7191
   647
                }
slouken@7191
   648
                else
slouken@7191
   649
                {
slouken@7191
   650
                    bOpenedXInputDevices[userId] = SDL_FALSE;
slouken@7191
   651
                }
slouken@7191
   652
            }
slouken@7191
   653
        }
slouken@6710
   654
slouken@7191
   655
        if ( s_pKnownJoystickGUIDs && ( s_bWindowsDeviceChanged || nNewOpenedXInputDevices != nCurrentOpenedXInputDevices ) )
slouken@7191
   656
        {
slouken@7191
   657
            SDL_Delay( 300 ); /* wait for direct input to find out about this device */
slouken@6690
   658
slouken@7191
   659
            s_bDeviceRemoved = SDL_TRUE;
slouken@7191
   660
            s_bDeviceAdded = SDL_TRUE;
slouken@7191
   661
            s_bWindowsDeviceChanged = SDL_FALSE;
slouken@7191
   662
        }
slouken@7191
   663
    }
slouken@7191
   664
    SDL_UnlockMutex( s_mutexJoyStickEnum );
slouken@6690
   665
slouken@7191
   666
    if ( hNotify )
slouken@7191
   667
        UnregisterDeviceNotification( hNotify );
slouken@6690
   668
slouken@7191
   669
    if ( messageWindow )
slouken@7191
   670
        DestroyWindow( messageWindow );
slouken@6712
   671
slouken@7191
   672
    UnregisterClass( wincl.lpszClassName, wincl.hInstance );
slouken@7191
   673
    messageWindow = 0;
slouken@7191
   674
    WIN_CoUninitialize();
slouken@7191
   675
    return 1;
slouken@6690
   676
}
slouken@6690
   677
slouken@6690
   678
slouken@1895
   679
/* Function to scan the system for joysticks.
slouken@1895
   680
 * This function should set SDL_numjoysticks to the number of available
slouken@1895
   681
 * joysticks.  Joystick 0 should be the system default joystick.
slouken@1895
   682
 * It should return 0, or -1 on an unrecoverable fatal error.
slouken@1895
   683
 */
slouken@1895
   684
int
slouken@1895
   685
SDL_SYS_JoystickInit(void)
slouken@1895
   686
{
slouken@1895
   687
    HRESULT result;
slouken@2713
   688
    HINSTANCE instance;
slouken@7191
   689
    const char *env = SDL_GetHint(SDL_HINT_XINPUT_ENABLED);
slouken@7191
   690
    if (env && !SDL_atoi(env)) {
slouken@7191
   691
        s_bXInputEnabled = SDL_FALSE;
slouken@7191
   692
    }
slouken@1895
   693
icculus@5591
   694
    result = WIN_CoInitialize();
slouken@2198
   695
    if (FAILED(result)) {
icculus@7037
   696
        return SetDIerror("CoInitialize", result);
slouken@1895
   697
    }
slouken@1895
   698
icculus@5591
   699
    coinitialized = SDL_TRUE;
icculus@5591
   700
slouken@6690
   701
    result = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER,
slouken@6690
   702
                              &IID_IDirectInput8, (LPVOID)&dinput);
slouken@2198
   703
slouken@2198
   704
    if (FAILED(result)) {
icculus@5591
   705
        SDL_SYS_JoystickQuit();
icculus@7037
   706
        return SetDIerror("CoCreateInstance", result);
slouken@2198
   707
    }
slouken@2198
   708
slouken@2198
   709
    /* Because we used CoCreateInstance, we need to Initialize it, first. */
slouken@2713
   710
    instance = GetModuleHandle(NULL);
slouken@2713
   711
    if (instance == NULL) {
icculus@5591
   712
        SDL_SYS_JoystickQuit();
icculus@7037
   713
        return SDL_SetError("GetModuleHandle() failed with error code %d.", GetLastError());
slouken@2713
   714
    }
slouken@6690
   715
    result = IDirectInput8_Initialize(dinput, instance, DIRECTINPUT_VERSION);
slouken@2198
   716
slouken@2198
   717
    if (FAILED(result)) {
icculus@5591
   718
        SDL_SYS_JoystickQuit();
icculus@7037
   719
        return SetDIerror("IDirectInput::Initialize", result);
slouken@2198
   720
    }
slouken@2198
   721
icculus@6990
   722
    s_mutexJoyStickEnum = SDL_CreateMutex();
icculus@6990
   723
    s_condJoystickThread = SDL_CreateCond();
slouken@7191
   724
    s_bDeviceAdded = SDL_TRUE; /* force a scan of the system for joysticks this first time */
icculus@6990
   725
    SDL_SYS_JoystickDetect();
slouken@1895
   726
icculus@6990
   727
    if ((s_bXInputEnabled) && (WIN_LoadXInputDLL() == -1)) {
icculus@6990
   728
        s_bXInputEnabled = SDL_FALSE;  /* oh well. */
urkle@6965
   729
    }
slouken@1895
   730
slouken@7191
   731
    if ( !s_threadJoystick )
slouken@7191
   732
    {
slouken@7191
   733
        s_bJoystickThreadQuit = SDL_FALSE;
slouken@7191
   734
        /* spin up the thread to detect hotplug of devices */
slouken@6690
   735
#if defined(__WIN32__) && !defined(HAVE_LIBC)
slouken@6690
   736
#undef SDL_CreateThread
slouken@7191
   737
        s_threadJoystick= SDL_CreateThread( SDL_JoystickThread, "SDL_joystick", NULL, NULL, NULL );
slouken@6690
   738
#else
slouken@7191
   739
        s_threadJoystick = SDL_CreateThread( SDL_JoystickThread, "SDL_joystick", NULL );
slouken@6690
   740
#endif
slouken@7191
   741
    }
slouken@7191
   742
        return SDL_SYS_NumJoysticks();
slouken@2198
   743
}
slouken@2198
   744
slouken@6707
   745
/* return the number of joysticks that are connected right now */
slouken@6707
   746
int SDL_SYS_NumJoysticks()
slouken@6707
   747
{
slouken@7191
   748
    int nJoysticks = 0;
slouken@7191
   749
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@7191
   750
    while ( device )
slouken@7191
   751
    {
slouken@7191
   752
        nJoysticks++;
slouken@7191
   753
        device = device->pNext;
slouken@7191
   754
    }
slouken@6707
   755
slouken@7191
   756
    return nJoysticks;
slouken@6707
   757
}
slouken@6707
   758
slouken@6707
   759
static int s_iNewGUID = 0;
slouken@6707
   760
slouken@6707
   761
/* helper function for direct input, gets called for each connected joystick */
slouken@6707
   762
static BOOL CALLBACK
slouken@7191
   763
    EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
slouken@6707
   764
{
slouken@7191
   765
    JoyStick_DeviceData *pNewJoystick;
slouken@7191
   766
    JoyStick_DeviceData *pPrevJoystick = NULL;
slouken@7191
   767
    SDL_bool bXInputDevice;
slouken@7191
   768
    pNewJoystick = *(JoyStick_DeviceData **)pContext;
slouken@7191
   769
    while ( pNewJoystick )
slouken@7191
   770
    {
slouken@7191
   771
        if ( !SDL_memcmp( &pNewJoystick->dxdevice.guidInstance, &pdidInstance->guidInstance, sizeof(pNewJoystick->dxdevice.guidInstance) ) )
slouken@7191
   772
        {
slouken@7191
   773
            /* if we are replacing the front of the list then update it */
slouken@7191
   774
            if ( pNewJoystick == *(JoyStick_DeviceData **)pContext )
slouken@7191
   775
            {
slouken@7191
   776
                *(JoyStick_DeviceData **)pContext = pNewJoystick->pNext;
slouken@7191
   777
            }
slouken@7191
   778
            else if ( pPrevJoystick )
slouken@7191
   779
            {
slouken@7191
   780
                pPrevJoystick->pNext = pNewJoystick->pNext;
slouken@7191
   781
            }
slouken@6712
   782
slouken@7191
   783
            pNewJoystick->pNext = SYS_Joystick;
slouken@7191
   784
            SYS_Joystick = pNewJoystick;
slouken@6707
   785
slouken@7191
   786
            s_pKnownJoystickGUIDs[ s_iNewGUID ] = pdidInstance->guidInstance;
slouken@7191
   787
            s_iNewGUID++;
slouken@7191
   788
            if ( s_iNewGUID < MAX_JOYSTICKS )
slouken@7191
   789
                return DIENUM_CONTINUE; /* already have this joystick loaded, just keep going */
slouken@7191
   790
            else
slouken@7191
   791
                return DIENUM_STOP;
slouken@7191
   792
        }
slouken@6707
   793
slouken@7191
   794
        pPrevJoystick = pNewJoystick;
slouken@7191
   795
        pNewJoystick = pNewJoystick->pNext;
slouken@7191
   796
    }
slouken@6707
   797
slouken@7191
   798
    s_bDeviceAdded = SDL_TRUE;
slouken@6707
   799
slouken@7191
   800
    bXInputDevice = IsXInputDevice( &pdidInstance->guidProduct );
slouken@6707
   801
slouken@7191
   802
    pNewJoystick = (JoyStick_DeviceData *)SDL_malloc( sizeof(JoyStick_DeviceData) );
slouken@6707
   803
slouken@7191
   804
    if ( bXInputDevice )
slouken@7191
   805
    {
slouken@7191
   806
        pNewJoystick->bXInputDevice = SDL_TRUE;
slouken@7191
   807
        pNewJoystick->XInputUserId = INVALID_XINPUT_USERID;
slouken@7191
   808
    }
slouken@7191
   809
    else
slouken@7191
   810
    {
slouken@7191
   811
        pNewJoystick->bXInputDevice = SDL_FALSE;
slouken@7191
   812
    }
slouken@6712
   813
slouken@7191
   814
    SDL_memcpy(&(pNewJoystick->dxdevice), pdidInstance,
slouken@7191
   815
        sizeof(DIDEVICEINSTANCE));
slouken@6707
   816
slouken@7191
   817
    pNewJoystick->joystickname = WIN_StringToUTF8(pdidInstance->tszProductName);
slouken@7191
   818
    pNewJoystick->send_add_event = 1;
slouken@7191
   819
    pNewJoystick->nInstanceID = ++s_nInstanceID;
slouken@7191
   820
    SDL_memcpy( &pNewJoystick->guid, &pdidInstance->guidProduct, sizeof(pNewJoystick->guid) );
slouken@7191
   821
    pNewJoystick->pNext = NULL;
slouken@6707
   822
slouken@7191
   823
    if ( SYS_Joystick )
slouken@7191
   824
    {
slouken@7191
   825
        pNewJoystick->pNext = SYS_Joystick;
slouken@7191
   826
    }
slouken@7191
   827
    SYS_Joystick = pNewJoystick;
slouken@6707
   828
slouken@7191
   829
    s_pKnownJoystickGUIDs[ s_iNewGUID ] = pdidInstance->guidInstance;
slouken@7191
   830
    s_iNewGUID++;
slouken@7191
   831
slouken@7191
   832
    if ( s_iNewGUID < MAX_JOYSTICKS )
slouken@7191
   833
        return DIENUM_CONTINUE; /* already have this joystick loaded, just keep going */
slouken@7191
   834
    else
slouken@7191
   835
        return DIENUM_STOP;
slouken@6707
   836
}
slouken@6707
   837
slouken@6707
   838
/* detect any new joysticks being inserted into the system */
slouken@6707
   839
void SDL_SYS_JoystickDetect()
slouken@6707
   840
{
slouken@7191
   841
    JoyStick_DeviceData *pCurList = NULL;
slouken@7191
   842
    /* only enum the devices if the joystick thread told us something changed */
slouken@7191
   843
    if ( s_bDeviceAdded || s_bDeviceRemoved )
slouken@7191
   844
    {
slouken@7191
   845
        s_bDeviceAdded = SDL_FALSE;
slouken@7191
   846
        s_bDeviceRemoved = SDL_FALSE;
slouken@6707
   847
slouken@7191
   848
        pCurList = SYS_Joystick;
slouken@7191
   849
        SYS_Joystick = NULL;
slouken@7191
   850
        s_iNewGUID = 0;
slouken@7191
   851
        SDL_LockMutex( s_mutexJoyStickEnum );
slouken@6707
   852
slouken@7191
   853
        if ( !s_pKnownJoystickGUIDs )
slouken@7191
   854
            s_pKnownJoystickGUIDs = SDL_malloc( sizeof(GUID)*MAX_JOYSTICKS );
slouken@6707
   855
slouken@7191
   856
        SDL_memset( s_pKnownJoystickGUIDs, 0x0, sizeof(GUID)*MAX_JOYSTICKS );
slouken@6707
   857
slouken@7191
   858
        /* Look for joysticks, wheels, head trackers, gamepads, etc.. */
slouken@7223
   859
        IDirectInput8_EnumDevices(dinput,
slouken@7191
   860
            DI8DEVCLASS_GAMECTRL,
slouken@7191
   861
            EnumJoysticksCallback,
slouken@7191
   862
            &pCurList, DIEDFL_ATTACHEDONLY);
slouken@6707
   863
slouken@7191
   864
        SDL_UnlockMutex( s_mutexJoyStickEnum );
slouken@7191
   865
    }
slouken@7191
   866
slouken@7191
   867
    if ( pCurList )
slouken@7191
   868
    {
slouken@7191
   869
        while ( pCurList )
slouken@7191
   870
        {
slouken@7191
   871
            JoyStick_DeviceData *pListNext = NULL;
slouken@6707
   872
#if !SDL_EVENTS_DISABLED
slouken@7191
   873
            SDL_Event event;
slouken@7191
   874
            event.type = SDL_JOYDEVICEREMOVED;
slouken@6707
   875
slouken@7191
   876
            if (SDL_GetEventState(event.type) == SDL_ENABLE) {
slouken@7191
   877
                event.jdevice.which = pCurList->nInstanceID;
slouken@7191
   878
                if ((SDL_EventOK == NULL)
slouken@7191
   879
                    || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
slouken@7191
   880
                        SDL_PushEvent(&event);
slouken@7191
   881
                }
slouken@7191
   882
            }
slouken@7191
   883
#endif /* !SDL_EVENTS_DISABLED */
slouken@6707
   884
slouken@7191
   885
            pListNext = pCurList->pNext;
slouken@7191
   886
            SDL_free(pCurList->joystickname);
slouken@7191
   887
            SDL_free( pCurList );
slouken@7191
   888
            pCurList = pListNext;
slouken@7191
   889
        }
slouken@6707
   890
slouken@7191
   891
    }
slouken@6707
   892
slouken@7191
   893
    if ( s_bDeviceAdded )
slouken@7191
   894
    {
slouken@7191
   895
        JoyStick_DeviceData *pNewJoystick;
slouken@7191
   896
        int device_index = 0;
slouken@7191
   897
        s_bDeviceAdded = SDL_FALSE;
slouken@7191
   898
        pNewJoystick = SYS_Joystick;
slouken@7191
   899
        while ( pNewJoystick )
slouken@7191
   900
        {
slouken@7191
   901
            if ( pNewJoystick->send_add_event )
slouken@7191
   902
            {
slouken@6707
   903
#if !SDL_EVENTS_DISABLED
slouken@7191
   904
                SDL_Event event;
slouken@7191
   905
                event.type = SDL_JOYDEVICEADDED;
slouken@6707
   906
slouken@7191
   907
                if (SDL_GetEventState(event.type) == SDL_ENABLE) {
slouken@7191
   908
                    event.jdevice.which = device_index;
slouken@7191
   909
                    if ((SDL_EventOK == NULL)
slouken@7191
   910
                        || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
slouken@7191
   911
                            SDL_PushEvent(&event);
slouken@7191
   912
                    }
slouken@7191
   913
                }
slouken@6707
   914
#endif /* !SDL_EVENTS_DISABLED */
slouken@7191
   915
                pNewJoystick->send_add_event = 0;
slouken@7191
   916
            }
slouken@7191
   917
            device_index++;
slouken@7191
   918
            pNewJoystick = pNewJoystick->pNext;
slouken@7191
   919
        }
slouken@7191
   920
    }
slouken@6707
   921
}
slouken@6707
   922
slouken@6707
   923
/* we need to poll if we have pending hotplug device changes or connected devices */
slouken@6707
   924
SDL_bool SDL_SYS_JoystickNeedsPolling()
slouken@6707
   925
{
slouken@7191
   926
    /* we have a new device or one was pulled, we need to think this frame please */
slouken@7191
   927
    if ( s_bDeviceAdded || s_bDeviceRemoved )
slouken@7191
   928
        return SDL_TRUE;
slouken@6707
   929
slouken@7191
   930
    return SDL_FALSE;
slouken@6707
   931
}
slouken@6707
   932
slouken@1895
   933
/* Function to get the device-dependent name of a joystick */
slouken@1895
   934
const char *
slouken@6707
   935
SDL_SYS_JoystickNameForDeviceIndex(int device_index)
slouken@1895
   936
{
slouken@7191
   937
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@6690
   938
slouken@7191
   939
    for (; device_index > 0; device_index--)
slouken@7191
   940
        device = device->pNext;
slouken@6690
   941
slouken@7191
   942
    return device->joystickname;
slouken@1895
   943
}
slouken@1895
   944
slouken@6707
   945
/* Function to perform the mapping between current device instance and this joysticks instance id */
slouken@6707
   946
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
slouken@6707
   947
{
slouken@7191
   948
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@7191
   949
    int index;
slouken@6707
   950
slouken@7191
   951
    for (index = device_index; index > 0; index--)
slouken@7191
   952
        device = device->pNext;
slouken@6707
   953
slouken@7191
   954
    return device->nInstanceID;
slouken@6707
   955
}
slouken@6707
   956
slouken@1895
   957
/* Function to open a joystick for use.
slouken@1895
   958
   The joystick to open is specified by the index field of the joystick.
slouken@1895
   959
   This should fill the nbuttons and naxes fields of the joystick structure.
slouken@1895
   960
   It returns 0, or -1 if there is an error.
slouken@1895
   961
 */
slouken@1895
   962
int
slouken@6690
   963
SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
slouken@1895
   964
{
slouken@1895
   965
    HRESULT result;
icculus@6716
   966
    LPDIRECTINPUTDEVICE8 device;
slouken@2198
   967
    DIPROPDWORD dipdw;
slouken@7191
   968
    JoyStick_DeviceData *joystickdevice = SYS_Joystick;
slouken@6690
   969
slouken@7191
   970
    for (; device_index > 0; device_index--)
slouken@7191
   971
        joystickdevice = joystickdevice->pNext;
slouken@2198
   972
slouken@2713
   973
    SDL_memset(&dipdw, 0, sizeof(DIPROPDWORD));
slouken@2198
   974
    dipdw.diph.dwSize = sizeof(DIPROPDWORD);
slouken@2198
   975
    dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
slouken@2198
   976
slouken@1895
   977
    /* allocate memory for system specific hardware data */
slouken@7191
   978
    joystick->instance_id = joystickdevice->nInstanceID;
urkle@6965
   979
    joystick->closed = 0;
slouken@1895
   980
    joystick->hwdata =
slouken@2713
   981
        (struct joystick_hwdata *) SDL_malloc(sizeof(struct joystick_hwdata));
slouken@1895
   982
    if (joystick->hwdata == NULL) {
icculus@7037
   983
        return SDL_OutOfMemory();
slouken@1895
   984
    }
slouken@2713
   985
    SDL_memset(joystick->hwdata, 0, sizeof(struct joystick_hwdata));
slouken@1895
   986
    joystick->hwdata->buffered = 1;
slouken@7191
   987
    joystick->hwdata->removed = 0;
slouken@2198
   988
    joystick->hwdata->Capabilities.dwSize = sizeof(DIDEVCAPS);
slouken@7191
   989
    joystick->hwdata->guid = joystickdevice->guid;
slouken@1895
   990
slouken@7191
   991
    if ( joystickdevice->bXInputDevice )
slouken@7191
   992
    {
slouken@7191
   993
        XINPUT_CAPABILITIES capabilities;
slouken@7191
   994
        Uint8 userId = 0;
slouken@7191
   995
        DWORD result;
slouken@7191
   996
        JoyStick_DeviceData *joysticklist = SYS_Joystick;
slouken@7191
   997
        /* scan the opened joysticks and pick the next free xinput userid for this one */
slouken@7191
   998
        for( ; joysticklist; joysticklist = joysticklist->pNext)
slouken@7191
   999
        {
slouken@7191
  1000
            if ( joysticklist->bXInputDevice && joysticklist->XInputUserId == userId )
slouken@7191
  1001
                userId++;
slouken@7191
  1002
        }
slouken@1895
  1003
slouken@7191
  1004
        if ( s_bXInputEnabled && XINPUTGETCAPABILITIES )
slouken@7191
  1005
        {
slouken@7191
  1006
            result = XINPUTGETCAPABILITIES( userId, XINPUT_FLAG_GAMEPAD, &capabilities );
slouken@7191
  1007
            if ( result == ERROR_SUCCESS )
slouken@7191
  1008
            {
icculus@6990
  1009
                const SDL_bool bIs14OrLater = (SDL_XInputVersion >= ((1<<16)|4));
slouken@7191
  1010
                SDL_bool bIsSupported = SDL_FALSE;
slouken@7191
  1011
                /* Current version of XInput mistakenly returns 0 as the Type. Ignore it and ensure the subtype is a gamepad. */
slouken@7191
  1012
                bIsSupported = ( capabilities.SubType == XINPUT_DEVSUBTYPE_GAMEPAD );
slouken@2198
  1013
slouken@7191
  1014
                if ( !bIsSupported )
slouken@7191
  1015
                {
slouken@7191
  1016
                    joystickdevice->bXInputDevice = SDL_FALSE;
slouken@7191
  1017
                }
slouken@7191
  1018
                else
slouken@7191
  1019
                {
slouken@7191
  1020
                    /* valid */
slouken@7191
  1021
                    joystick->hwdata->bXInputDevice = SDL_TRUE;
icculus@6990
  1022
                    if ((!bIs14OrLater) || (capabilities.Flags & XINPUT_CAPS_FFB_SUPPORTED)) {
slouken@7191
  1023
                        joystick->hwdata->bXInputHaptic = SDL_TRUE;
icculus@6990
  1024
                    }
slouken@7191
  1025
                    SDL_memset( joystick->hwdata->XInputState, 0x0, sizeof(joystick->hwdata->XInputState) );
slouken@7191
  1026
                    joystickdevice->XInputUserId = userId;
slouken@7191
  1027
                    joystick->hwdata->userid = userId;
slouken@7191
  1028
                    joystick->hwdata->currentXInputSlot = 0;
slouken@7191
  1029
                    /* The XInput API has a hard coded button/axis mapping, so we just match it */
slouken@7191
  1030
                    joystick->naxes = 6;
slouken@7191
  1031
                    joystick->nbuttons = 15;
slouken@7191
  1032
                    joystick->nballs = 0;
slouken@7191
  1033
                    joystick->nhats = 0;
slouken@7191
  1034
                }
slouken@7191
  1035
            }
slouken@7191
  1036
            else
slouken@7191
  1037
            {
slouken@7191
  1038
                joystickdevice->bXInputDevice = SDL_FALSE;
slouken@7191
  1039
            }
slouken@7191
  1040
        }
slouken@7191
  1041
        else
slouken@7191
  1042
        {
slouken@7191
  1043
            joystickdevice->bXInputDevice = SDL_FALSE;
slouken@7191
  1044
        }
slouken@7191
  1045
    }
slouken@1895
  1046
slouken@7191
  1047
    if ( joystickdevice->bXInputDevice == SDL_FALSE )
slouken@7191
  1048
    {
slouken@7191
  1049
        joystick->hwdata->bXInputDevice = SDL_FALSE;
slouken@1895
  1050
slouken@7191
  1051
        result =
slouken@7191
  1052
            IDirectInput8_CreateDevice(dinput,
slouken@7191
  1053
                                      &(joystickdevice->dxdevice.guidInstance), &device, NULL);
slouken@7191
  1054
        if (FAILED(result)) {
slouken@7191
  1055
            return SetDIerror("IDirectInput::CreateDevice", result);
slouken@7191
  1056
        }
slouken@1895
  1057
slouken@7191
  1058
        /* Now get the IDirectInputDevice8 interface, instead. */
slouken@7191
  1059
        result = IDirectInputDevice8_QueryInterface(device,
slouken@7191
  1060
                                                   &IID_IDirectInputDevice8,
slouken@7191
  1061
                                                   (LPVOID *) & joystick->
slouken@7191
  1062
                                                   hwdata->InputDevice);
slouken@7191
  1063
        /* We are done with this object.  Use the stored one from now on. */
slouken@7191
  1064
        IDirectInputDevice8_Release(device);
slouken@1895
  1065
slouken@7191
  1066
        if (FAILED(result)) {
slouken@7191
  1067
            return SetDIerror("IDirectInputDevice8::QueryInterface", result);
slouken@7191
  1068
        }
slouken@2198
  1069
slouken@7191
  1070
        /* Acquire shared access. Exclusive access is required for forces,
slouken@7191
  1071
         * though. */
slouken@7191
  1072
        result =
slouken@7191
  1073
            IDirectInputDevice8_SetCooperativeLevel(joystick->hwdata->
slouken@7191
  1074
                                                    InputDevice, SDL_HelperWindow,
slouken@7191
  1075
                                                    DISCL_NONEXCLUSIVE |
slouken@7191
  1076
                                                    DISCL_BACKGROUND);
slouken@7191
  1077
        if (FAILED(result)) {
slouken@7191
  1078
            return SetDIerror("IDirectInputDevice8::SetCooperativeLevel", result);
slouken@7191
  1079
        }
slouken@2198
  1080
slouken@7191
  1081
        /* Use the extended data structure: DIJOYSTATE2. */
slouken@7191
  1082
        result =
slouken@7191
  1083
            IDirectInputDevice8_SetDataFormat(joystick->hwdata->InputDevice,
slouken@7191
  1084
                                              &c_dfDIJoystick2);
slouken@7191
  1085
        if (FAILED(result)) {
slouken@7191
  1086
            return SetDIerror("IDirectInputDevice8::SetDataFormat", result);
slouken@7191
  1087
        }
slouken@2198
  1088
slouken@7191
  1089
        /* Get device capabilities */
slouken@7191
  1090
        result =
slouken@7191
  1091
            IDirectInputDevice8_GetCapabilities(joystick->hwdata->InputDevice,
slouken@7191
  1092
                                                &joystick->hwdata->Capabilities);
slouken@2198
  1093
slouken@7191
  1094
        if (FAILED(result)) {
slouken@7191
  1095
            return SetDIerror("IDirectInputDevice8::GetCapabilities", result);
slouken@7191
  1096
        }
slouken@2198
  1097
slouken@7191
  1098
        /* Force capable? */
slouken@7191
  1099
        if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
slouken@2198
  1100
slouken@7191
  1101
            result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
slouken@2198
  1102
slouken@7191
  1103
            if (FAILED(result)) {
slouken@7191
  1104
                return SetDIerror("IDirectInputDevice8::Acquire", result);
slouken@7191
  1105
            }
slouken@2198
  1106
slouken@7191
  1107
            /* reset all accuators. */
slouken@7191
  1108
            result =
slouken@7191
  1109
                IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->
slouken@7191
  1110
                                                             InputDevice,
slouken@7191
  1111
                                                             DISFFC_RESET);
slouken@2198
  1112
slouken@7191
  1113
            /* Not necessarily supported, ignore if not supported.
slouken@7191
  1114
            if (FAILED(result)) {
slouken@7191
  1115
                return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand", result);
slouken@7191
  1116
            }
slouken@7191
  1117
            */
slouken@1895
  1118
slouken@7191
  1119
            result = IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
slouken@1895
  1120
slouken@7191
  1121
            if (FAILED(result)) {
slouken@7191
  1122
                return SetDIerror("IDirectInputDevice8::Unacquire", result);
slouken@7191
  1123
            }
slouken@2198
  1124
slouken@7191
  1125
            /* Turn on auto-centering for a ForceFeedback device (until told
slouken@7191
  1126
             * otherwise). */
slouken@7191
  1127
            dipdw.diph.dwObj = 0;
slouken@7191
  1128
            dipdw.diph.dwHow = DIPH_DEVICE;
slouken@7191
  1129
            dipdw.dwData = DIPROPAUTOCENTER_ON;
slouken@6220
  1130
slouken@7191
  1131
            result =
slouken@7191
  1132
                IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
slouken@7191
  1133
                                                DIPROP_AUTOCENTER, &dipdw.diph);
slouken@2198
  1134
slouken@7191
  1135
            /* Not necessarily supported, ignore if not supported.
slouken@7191
  1136
            if (FAILED(result)) {
slouken@7191
  1137
                return SetDIerror("IDirectInputDevice8::SetProperty", result);
slouken@7191
  1138
            }
slouken@7191
  1139
            */
slouken@7191
  1140
        }
slouken@2198
  1141
slouken@7191
  1142
        /* What buttons and axes does it have? */
slouken@7191
  1143
        IDirectInputDevice8_EnumObjects(joystick->hwdata->InputDevice,
slouken@7191
  1144
                                        EnumDevObjectsCallback, joystick,
slouken@7191
  1145
                                        DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV);
slouken@2198
  1146
slouken@7191
  1147
        /* Reorder the input objects. Some devices do not report the X axis as
slouken@7191
  1148
         * the first axis, for example. */
slouken@7191
  1149
        SortDevObjects(joystick);
slouken@6690
  1150
slouken@7191
  1151
        dipdw.diph.dwObj = 0;
slouken@7191
  1152
        dipdw.diph.dwHow = DIPH_DEVICE;
slouken@7191
  1153
        dipdw.dwData = INPUT_QSIZE;
slouken@6690
  1154
slouken@7191
  1155
        /* Set the buffer size */
slouken@7191
  1156
        result =
slouken@7191
  1157
            IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
slouken@7191
  1158
                                            DIPROP_BUFFERSIZE, &dipdw.diph);
slouken@6690
  1159
slouken@7191
  1160
        if (result == DI_POLLEDDEVICE) {
slouken@7191
  1161
            /* This device doesn't support buffering, so we're forced
slouken@7191
  1162
             * to use less reliable polling. */
slouken@7191
  1163
            joystick->hwdata->buffered = 0;
slouken@7191
  1164
        } else if (FAILED(result)) {
slouken@7191
  1165
            return SetDIerror("IDirectInputDevice8::SetProperty", result);
slouken@7191
  1166
        }
slouken@7191
  1167
    }
slouken@1895
  1168
    return (0);
slouken@1895
  1169
}
slouken@1895
  1170
slouken@6707
  1171
/* return true if this joystick is plugged in right now */
slouken@6707
  1172
SDL_bool SDL_SYS_JoystickAttached( SDL_Joystick * joystick )
slouken@6707
  1173
{
slouken@7191
  1174
    return joystick->closed == 0 && joystick->hwdata->removed == 0;
slouken@6707
  1175
}
slouken@6707
  1176
slouken@6707
  1177
slouken@6220
  1178
/* Sort using the data offset into the DInput struct.
slouken@6220
  1179
 * This gives a reasonable ordering for the inputs. */
slouken@6220
  1180
static int
slouken@6220
  1181
SortDevFunc(const void *a, const void *b)
slouken@6220
  1182
{
slouken@7191
  1183
    const input_t *inputA = (const input_t*)a;
slouken@7191
  1184
    const input_t *inputB = (const input_t*)b;
slouken@6220
  1185
slouken@7191
  1186
    if (inputA->ofs < inputB->ofs)
slouken@7191
  1187
        return -1;
slouken@7191
  1188
    if (inputA->ofs > inputB->ofs)
slouken@7191
  1189
        return 1;
slouken@7191
  1190
    return 0;
slouken@6220
  1191
}
slouken@6220
  1192
slouken@6220
  1193
/* Sort the input objects and recalculate the indices for each input. */
slouken@6220
  1194
static void
slouken@6220
  1195
SortDevObjects(SDL_Joystick *joystick)
slouken@6220
  1196
{
slouken@7191
  1197
    input_t *inputs = joystick->hwdata->Inputs;
slouken@7191
  1198
    int nButtons = 0;
slouken@7191
  1199
    int nHats = 0;
slouken@7191
  1200
    int nAxis = 0;
slouken@7191
  1201
    int n;
slouken@6220
  1202
slouken@7191
  1203
    SDL_qsort(inputs, joystick->hwdata->NumInputs, sizeof(input_t), SortDevFunc);
slouken@6220
  1204
slouken@7191
  1205
    for (n = 0; n < joystick->hwdata->NumInputs; n++)
slouken@7191
  1206
    {
slouken@7191
  1207
        switch (inputs[n].type)
slouken@7191
  1208
        {
slouken@7191
  1209
        case BUTTON:
slouken@7191
  1210
            inputs[n].num = nButtons;
slouken@7191
  1211
            nButtons++;
slouken@7191
  1212
            break;
slouken@6220
  1213
slouken@7191
  1214
        case HAT:
slouken@7191
  1215
            inputs[n].num = nHats;
slouken@7191
  1216
            nHats++;
slouken@7191
  1217
            break;
slouken@6220
  1218
slouken@7191
  1219
        case AXIS:
slouken@7191
  1220
            inputs[n].num = nAxis;
slouken@7191
  1221
            nAxis++;
slouken@7191
  1222
            break;
slouken@7191
  1223
        }
slouken@7191
  1224
    }
slouken@6220
  1225
}
slouken@6220
  1226
slouken@2198
  1227
static BOOL CALLBACK
slouken@2198
  1228
EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
slouken@2198
  1229
{
slouken@2198
  1230
    SDL_Joystick *joystick = (SDL_Joystick *) pvRef;
slouken@2198
  1231
    HRESULT result;
slouken@2198
  1232
    input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs];
slouken@2198
  1233
slouken@2198
  1234
    if (dev->dwType & DIDFT_BUTTON) {
slouken@2198
  1235
        in->type = BUTTON;
slouken@2198
  1236
        in->num = joystick->nbuttons;
slouken@7191
  1237
        in->ofs = DIJOFS_BUTTON( in->num );
slouken@2198
  1238
        joystick->nbuttons++;
slouken@2198
  1239
    } else if (dev->dwType & DIDFT_POV) {
slouken@2198
  1240
        in->type = HAT;
slouken@2198
  1241
        in->num = joystick->nhats;
slouken@7191
  1242
        in->ofs = DIJOFS_POV( in->num );
slouken@2198
  1243
        joystick->nhats++;
slouken@2198
  1244
    } else if (dev->dwType & DIDFT_AXIS) {
slouken@2198
  1245
        DIPROPRANGE diprg;
slouken@2198
  1246
        DIPROPDWORD dilong;
slouken@2198
  1247
slouken@2198
  1248
        in->type = AXIS;
slouken@2198
  1249
        in->num = joystick->naxes;
slouken@7191
  1250
        /* work our the axis this guy maps too, thanks for the code icculus! */
slouken@7191
  1251
        if ( !SDL_memcmp( &dev->guidType, &GUID_XAxis, sizeof(dev->guidType) ) )
slouken@7191
  1252
            in->ofs = DIJOFS_X;
slouken@7191
  1253
        else if ( !SDL_memcmp( &dev->guidType, &GUID_YAxis, sizeof(dev->guidType) ) )
slouken@7191
  1254
            in->ofs = DIJOFS_Y;
slouken@7191
  1255
        else if ( !SDL_memcmp( &dev->guidType, &GUID_ZAxis, sizeof(dev->guidType) ) )
slouken@7191
  1256
            in->ofs = DIJOFS_Z;
slouken@7191
  1257
        else if ( !SDL_memcmp( &dev->guidType, &GUID_RxAxis, sizeof(dev->guidType) ) )
slouken@7191
  1258
            in->ofs = DIJOFS_RX;
slouken@7191
  1259
        else if ( !SDL_memcmp( &dev->guidType, &GUID_RyAxis, sizeof(dev->guidType) ) )
slouken@7191
  1260
            in->ofs = DIJOFS_RY;
slouken@7191
  1261
        else if ( !SDL_memcmp( &dev->guidType, &GUID_RzAxis, sizeof(dev->guidType) ) )
slouken@7191
  1262
            in->ofs = DIJOFS_RZ;
slouken@7191
  1263
        else if ( !SDL_memcmp( &dev->guidType, &GUID_Slider, sizeof(dev->guidType) ) )
slouken@7191
  1264
        {
slouken@7191
  1265
            in->ofs = DIJOFS_SLIDER( joystick->hwdata->NumSliders );
slouken@7191
  1266
            ++joystick->hwdata->NumSliders;
slouken@7191
  1267
        }
slouken@7191
  1268
        else
slouken@7191
  1269
        {
slouken@7191
  1270
             return DIENUM_CONTINUE; /* not an axis we can grok */
slouken@7191
  1271
        }
slouken@2198
  1272
slouken@2198
  1273
        diprg.diph.dwSize = sizeof(diprg);
slouken@2198
  1274
        diprg.diph.dwHeaderSize = sizeof(diprg.diph);
slouken@6690
  1275
        diprg.diph.dwObj = dev->dwType;
slouken@6690
  1276
        diprg.diph.dwHow = DIPH_BYID;
slouken@2198
  1277
        diprg.lMin = AXIS_MIN;
slouken@2198
  1278
        diprg.lMax = AXIS_MAX;
slouken@2198
  1279
slouken@2198
  1280
        result =
slouken@6690
  1281
            IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
slouken@2198
  1282
                                            DIPROP_RANGE, &diprg.diph);
slouken@2198
  1283
        if (FAILED(result)) {
slouken@2198
  1284
            return DIENUM_CONTINUE;     /* don't use this axis */
slouken@2198
  1285
        }
slouken@2198
  1286
slouken@2198
  1287
        /* Set dead zone to 0. */
slouken@2198
  1288
        dilong.diph.dwSize = sizeof(dilong);
slouken@2198
  1289
        dilong.diph.dwHeaderSize = sizeof(dilong.diph);
slouken@6690
  1290
        dilong.diph.dwObj = dev->dwType;
slouken@6690
  1291
        dilong.diph.dwHow = DIPH_BYID;
slouken@2198
  1292
        dilong.dwData = 0;
slouken@2198
  1293
        result =
slouken@6690
  1294
            IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
slouken@2198
  1295
                                            DIPROP_DEADZONE, &dilong.diph);
slouken@2198
  1296
        if (FAILED(result)) {
slouken@2198
  1297
            return DIENUM_CONTINUE;     /* don't use this axis */
slouken@2198
  1298
        }
slouken@2198
  1299
slouken@2198
  1300
        joystick->naxes++;
slouken@2198
  1301
    } else {
slouken@2198
  1302
        /* not supported at this time */
slouken@2198
  1303
        return DIENUM_CONTINUE;
slouken@2198
  1304
    }
slouken@2198
  1305
slouken@2198
  1306
    joystick->hwdata->NumInputs++;
slouken@2198
  1307
slouken@2198
  1308
    if (joystick->hwdata->NumInputs == MAX_INPUTS) {
slouken@2198
  1309
        return DIENUM_STOP;     /* too many */
slouken@2198
  1310
    }
slouken@2198
  1311
slouken@2198
  1312
    return DIENUM_CONTINUE;
slouken@2198
  1313
}
slouken@2198
  1314
slouken@2198
  1315
/* Function to update the state of a joystick - called as a device poll.
slouken@2198
  1316
 * This function shouldn't update the joystick structure directly,
slouken@2198
  1317
 * but instead should call SDL_PrivateJoystick*() to deliver events
slouken@2198
  1318
 * and update joystick device state.
slouken@2198
  1319
 */
slouken@2198
  1320
void
slouken@2198
  1321
SDL_SYS_JoystickUpdate_Polled(SDL_Joystick * joystick)
slouken@2198
  1322
{
slouken@2198
  1323
    DIJOYSTATE2 state;
slouken@2198
  1324
    HRESULT result;
slouken@2198
  1325
    int i;
slouken@2198
  1326
slouken@2198
  1327
    result =
slouken@6690
  1328
        IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
slouken@2198
  1329
                                           sizeof(DIJOYSTATE2), &state);
slouken@2198
  1330
    if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
slouken@6690
  1331
        IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
slouken@2198
  1332
        result =
slouken@6690
  1333
            IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
slouken@2198
  1334
                                               sizeof(DIJOYSTATE2), &state);
slouken@2198
  1335
    }
slouken@2198
  1336
slouken@7191
  1337
    if ( result != DI_OK )
slouken@7191
  1338
    {
slouken@7191
  1339
        joystick->hwdata->send_remove_event = 1;
slouken@7191
  1340
        joystick->hwdata->removed = 1;
slouken@7191
  1341
        return;
slouken@7191
  1342
    }
slouken@6690
  1343
slouken@2198
  1344
    /* Set each known axis, button and POV. */
slouken@2198
  1345
    for (i = 0; i < joystick->hwdata->NumInputs; ++i) {
slouken@2198
  1346
        const input_t *in = &joystick->hwdata->Inputs[i];
slouken@2198
  1347
slouken@2198
  1348
        switch (in->type) {
slouken@2198
  1349
        case AXIS:
slouken@2198
  1350
            switch (in->ofs) {
slouken@2198
  1351
            case DIJOFS_X:
slouken@2198
  1352
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1353
                                            (Sint16) state.lX);
slouken@2198
  1354
                break;
slouken@2198
  1355
            case DIJOFS_Y:
slouken@2198
  1356
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1357
                                            (Sint16) state.lY);
slouken@2198
  1358
                break;
slouken@2198
  1359
            case DIJOFS_Z:
slouken@2198
  1360
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1361
                                            (Sint16) state.lZ);
slouken@2198
  1362
                break;
slouken@2198
  1363
            case DIJOFS_RX:
slouken@2198
  1364
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1365
                                            (Sint16) state.lRx);
slouken@2198
  1366
                break;
slouken@2198
  1367
            case DIJOFS_RY:
slouken@2198
  1368
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1369
                                            (Sint16) state.lRy);
slouken@2198
  1370
                break;
slouken@2198
  1371
            case DIJOFS_RZ:
slouken@2198
  1372
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1373
                                            (Sint16) state.lRz);
slouken@2198
  1374
                break;
slouken@2198
  1375
            case DIJOFS_SLIDER(0):
slouken@2198
  1376
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1377
                                            (Sint16) state.rglSlider[0]);
slouken@2198
  1378
                break;
slouken@2198
  1379
            case DIJOFS_SLIDER(1):
slouken@2198
  1380
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1381
                                            (Sint16) state.rglSlider[1]);
slouken@2198
  1382
                break;
slouken@2198
  1383
            }
slouken@2198
  1384
slouken@2198
  1385
            break;
slouken@2198
  1386
slouken@2198
  1387
        case BUTTON:
slouken@2198
  1388
            SDL_PrivateJoystickButton_Int(joystick, in->num,
slouken@3013
  1389
                                          (Uint8) (state.
slouken@3013
  1390
                                                   rgbButtons[in->ofs -
slouken@3013
  1391
                                                              DIJOFS_BUTTON0]
slouken@2198
  1392
                                                   ? SDL_PRESSED :
slouken@2198
  1393
                                                   SDL_RELEASED));
slouken@2198
  1394
            break;
slouken@2198
  1395
        case HAT:
slouken@2198
  1396
            {
slouken@2198
  1397
                Uint8 pos = TranslatePOV(state.rgdwPOV[in->ofs -
slouken@2198
  1398
                                                       DIJOFS_POV(0)]);
slouken@2198
  1399
                SDL_PrivateJoystickHat_Int(joystick, in->num, pos);
slouken@2198
  1400
                break;
slouken@2198
  1401
            }
slouken@2198
  1402
        }
slouken@2198
  1403
    }
slouken@2198
  1404
}
slouken@2198
  1405
slouken@2198
  1406
void
slouken@2198
  1407
SDL_SYS_JoystickUpdate_Buffered(SDL_Joystick * joystick)
slouken@2198
  1408
{
slouken@2198
  1409
    int i;
slouken@2198
  1410
    HRESULT result;
slouken@2198
  1411
    DWORD numevents;
slouken@2198
  1412
    DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
slouken@2198
  1413
slouken@2198
  1414
    numevents = INPUT_QSIZE;
slouken@2198
  1415
    result =
slouken@6690
  1416
        IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
slouken@2198
  1417
                                          sizeof(DIDEVICEOBJECTDATA), evtbuf,
slouken@2198
  1418
                                          &numevents, 0);
slouken@2198
  1419
    if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
slouken@6690
  1420
        IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
slouken@2198
  1421
        result =
slouken@6690
  1422
            IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
slouken@2198
  1423
                                              sizeof(DIDEVICEOBJECTDATA),
slouken@2198
  1424
                                              evtbuf, &numevents, 0);
slouken@2198
  1425
    }
slouken@2198
  1426
slouken@2198
  1427
    /* Handle the events or punt */
slouken@2198
  1428
    if (FAILED(result))
slouken@7191
  1429
    {
slouken@7191
  1430
        joystick->hwdata->send_remove_event = 1;
slouken@7191
  1431
        joystick->hwdata->removed = 1;
slouken@2198
  1432
        return;
slouken@7191
  1433
    }
slouken@2198
  1434
slouken@2198
  1435
    for (i = 0; i < (int) numevents; ++i) {
slouken@2198
  1436
        int j;
slouken@2198
  1437
slouken@2198
  1438
        for (j = 0; j < joystick->hwdata->NumInputs; ++j) {
slouken@2198
  1439
            const input_t *in = &joystick->hwdata->Inputs[j];
slouken@2198
  1440
slouken@2198
  1441
            if (evtbuf[i].dwOfs != in->ofs)
slouken@2198
  1442
                continue;
slouken@2198
  1443
slouken@2198
  1444
            switch (in->type) {
slouken@2198
  1445
            case AXIS:
slouken@2198
  1446
                SDL_PrivateJoystickAxis(joystick, in->num,
slouken@2198
  1447
                                        (Sint16) evtbuf[i].dwData);
slouken@2198
  1448
                break;
slouken@2198
  1449
            case BUTTON:
slouken@2198
  1450
                SDL_PrivateJoystickButton(joystick, in->num,
slouken@3013
  1451
                                          (Uint8) (evtbuf[i].
slouken@3013
  1452
                                                   dwData ? SDL_PRESSED :
slouken@2198
  1453
                                                   SDL_RELEASED));
slouken@2198
  1454
                break;
slouken@2198
  1455
            case HAT:
slouken@2198
  1456
                {
slouken@2198
  1457
                    Uint8 pos = TranslatePOV(evtbuf[i].dwData);
slouken@2198
  1458
                    SDL_PrivateJoystickHat(joystick, in->num, pos);
slouken@2198
  1459
                }
slouken@2198
  1460
            }
slouken@2198
  1461
        }
slouken@2198
  1462
    }
slouken@2198
  1463
}
slouken@2198
  1464
slouken@2198
  1465
slouken@6690
  1466
/* Function to return > 0 if a bit array of buttons differs after applying a mask
slouken@6690
  1467
*/
slouken@6690
  1468
int ButtonChanged( int ButtonsNow, int ButtonsPrev, int ButtonMask )
slouken@6690
  1469
{
slouken@7191
  1470
    return ( ButtonsNow & ButtonMask ) != ( ButtonsPrev & ButtonMask );
slouken@6690
  1471
}
slouken@6690
  1472
slouken@6690
  1473
/* Function to update the state of a XInput style joystick.
slouken@6690
  1474
*/
slouken@6690
  1475
void
slouken@6690
  1476
SDL_SYS_JoystickUpdate_XInput(SDL_Joystick * joystick)
slouken@6690
  1477
{
slouken@7191
  1478
    HRESULT result;
slouken@6690
  1479
slouken@7191
  1480
    if ( !XINPUTGETSTATE )
slouken@7191
  1481
        return;
slouken@6690
  1482
slouken@7191
  1483
    result = XINPUTGETSTATE( joystick->hwdata->userid, &joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot] );
slouken@7191
  1484
    if ( result == ERROR_DEVICE_NOT_CONNECTED )
slouken@7191
  1485
    {
slouken@7191
  1486
        joystick->hwdata->send_remove_event = 1;
slouken@7191
  1487
        joystick->hwdata->removed = 1;
slouken@7191
  1488
        return;
slouken@7191
  1489
    }
slouken@6690
  1490
slouken@7191
  1491
    /* only fire events if the data changed from last time */
slouken@7191
  1492
    if ( joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot].dwPacketNumber != 0
slouken@7191
  1493
        && joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot].dwPacketNumber != joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot^1].dwPacketNumber )
slouken@7191
  1494
    {
slouken@7191
  1495
        XINPUT_STATE_EX *pXInputState = &joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot];
slouken@7191
  1496
        XINPUT_STATE_EX *pXInputStatePrev = &joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot ^ 1];
slouken@6690
  1497
slouken@7191
  1498
        SDL_PrivateJoystickAxis(joystick, 0, (Sint16)pXInputState->Gamepad.sThumbLX );
slouken@7191
  1499
        SDL_PrivateJoystickAxis(joystick, 1, (Sint16)(-1*pXInputState->Gamepad.sThumbLY-1) );
slouken@7191
  1500
        SDL_PrivateJoystickAxis(joystick, 2, (Sint16)pXInputState->Gamepad.sThumbRX );
slouken@7191
  1501
        SDL_PrivateJoystickAxis(joystick, 3, (Sint16)(-1*pXInputState->Gamepad.sThumbRY-1) );
slouken@7293
  1502
        SDL_PrivateJoystickAxis(joystick, 4, (Sint16)(((int)pXInputState->Gamepad.bLeftTrigger*65535/255) - 32768));
slouken@7293
  1503
        SDL_PrivateJoystickAxis(joystick, 5, (Sint16)(((int)pXInputState->Gamepad.bRightTrigger*65535/255) - 32768));
slouken@6690
  1504
slouken@7191
  1505
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_UP ) )
slouken@7191
  1506
            SDL_PrivateJoystickButton(joystick, 0, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP ? SDL_PRESSED :  SDL_RELEASED );
slouken@7191
  1507
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_DOWN ) )
slouken@7191
  1508
            SDL_PrivateJoystickButton(joystick, 1, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN ? SDL_PRESSED :    SDL_RELEASED );
slouken@7191
  1509
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_LEFT ) )
slouken@7191
  1510
            SDL_PrivateJoystickButton(joystick, 2, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT ? SDL_PRESSED :    SDL_RELEASED );
slouken@7191
  1511
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_RIGHT ) )
slouken@7191
  1512
            SDL_PrivateJoystickButton(joystick, 3, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1513
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_START ) )
slouken@7191
  1514
            SDL_PrivateJoystickButton(joystick, 4, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_START ? SDL_PRESSED :    SDL_RELEASED );
slouken@7191
  1515
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_BACK ) )
slouken@7191
  1516
            SDL_PrivateJoystickButton(joystick, 5, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_BACK ? SDL_PRESSED : SDL_RELEASED );
slouken@7191
  1517
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_THUMB ) )
slouken@7191
  1518
            SDL_PrivateJoystickButton(joystick, 6, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1519
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_RIGHT_THUMB ) )
slouken@7191
  1520
            SDL_PrivateJoystickButton(joystick, 7, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB ? SDL_PRESSED :  SDL_RELEASED );
slouken@7191
  1521
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_SHOULDER ) )
slouken@7191
  1522
            SDL_PrivateJoystickButton(joystick, 8, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER ? SDL_PRESSED :    SDL_RELEASED );
slouken@7191
  1523
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_RIGHT_SHOULDER ) )
slouken@7191
  1524
            SDL_PrivateJoystickButton(joystick, 9, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1525
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_A ) )
slouken@7191
  1526
            SDL_PrivateJoystickButton(joystick, 10, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_A ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1527
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_B ) )
slouken@7191
  1528
            SDL_PrivateJoystickButton(joystick, 11, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_B ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1529
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_X ) )
slouken@7191
  1530
            SDL_PrivateJoystickButton(joystick, 12, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_X ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1531
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_Y ) )
slouken@7191
  1532
            SDL_PrivateJoystickButton(joystick, 13, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_Y ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1533
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons,  0x400 ) )
slouken@7191
  1534
            SDL_PrivateJoystickButton(joystick, 14, pXInputState->Gamepad.wButtons & 0x400 ? SDL_PRESSED :  SDL_RELEASED ); /* 0x400 is the undocumented code for the guide button */
slouken@6690
  1535
slouken@7191
  1536
        joystick->hwdata->currentXInputSlot ^= 1;
slouken@6690
  1537
slouken@7191
  1538
    }
slouken@6690
  1539
}
slouken@6690
  1540
slouken@6690
  1541
slouken@1895
  1542
static Uint8
slouken@1895
  1543
TranslatePOV(DWORD value)
slouken@1895
  1544
{
slouken@1895
  1545
    const int HAT_VALS[] = {
slouken@1895
  1546
        SDL_HAT_UP,
slouken@1895
  1547
        SDL_HAT_UP | SDL_HAT_RIGHT,
slouken@1895
  1548
        SDL_HAT_RIGHT,
slouken@1895
  1549
        SDL_HAT_DOWN | SDL_HAT_RIGHT,
slouken@1895
  1550
        SDL_HAT_DOWN,
slouken@1895
  1551
        SDL_HAT_DOWN | SDL_HAT_LEFT,
slouken@1895
  1552
        SDL_HAT_LEFT,
slouken@1895
  1553
        SDL_HAT_UP | SDL_HAT_LEFT
slouken@1895
  1554
    };
slouken@1895
  1555
slouken@1895
  1556
    if (LOWORD(value) == 0xFFFF)
slouken@1895
  1557
        return SDL_HAT_CENTERED;
slouken@1895
  1558
slouken@1895
  1559
    /* Round the value up: */
slouken@1895
  1560
    value += 4500 / 2;
slouken@1895
  1561
    value %= 36000;
slouken@1895
  1562
    value /= 4500;
slouken@1895
  1563
slouken@1895
  1564
    if (value >= 8)
slouken@1895
  1565
        return SDL_HAT_CENTERED;        /* shouldn't happen */
slouken@1895
  1566
slouken@1895
  1567
    return HAT_VALS[value];
slouken@1895
  1568
}
slouken@1895
  1569
slouken@1895
  1570
/* SDL_PrivateJoystick* doesn't discard duplicate events, so we need to
slouken@1895
  1571
 * do it. */
slouken@1895
  1572
static int
slouken@1895
  1573
SDL_PrivateJoystickAxis_Int(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
slouken@1895
  1574
{
slouken@1895
  1575
    if (joystick->axes[axis] != value)
slouken@1895
  1576
        return SDL_PrivateJoystickAxis(joystick, axis, value);
slouken@1895
  1577
    return 0;
slouken@1895
  1578
}
slouken@1895
  1579
slouken@1895
  1580
static int
slouken@1895
  1581
SDL_PrivateJoystickHat_Int(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
slouken@1895
  1582
{
slouken@1895
  1583
    if (joystick->hats[hat] != value)
slouken@1895
  1584
        return SDL_PrivateJoystickHat(joystick, hat, value);
slouken@1895
  1585
    return 0;
slouken@1895
  1586
}
slouken@1895
  1587
slouken@1895
  1588
static int
slouken@1895
  1589
SDL_PrivateJoystickButton_Int(SDL_Joystick * joystick, Uint8 button,
slouken@1895
  1590
                              Uint8 state)
slouken@1895
  1591
{
slouken@1895
  1592
    if (joystick->buttons[button] != state)
slouken@1895
  1593
        return SDL_PrivateJoystickButton(joystick, button, state);
slouken@1895
  1594
    return 0;
slouken@1895
  1595
}
slouken@1895
  1596
slouken@1895
  1597
void
slouken@1895
  1598
SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
slouken@1895
  1599
{
slouken@1895
  1600
    HRESULT result;
slouken@1895
  1601
slouken@7191
  1602
    if ( joystick->closed || !joystick->hwdata )
slouken@7191
  1603
        return;
slouken@1895
  1604
slouken@7191
  1605
    if (joystick->hwdata->bXInputDevice)
slouken@7191
  1606
    {
slouken@7191
  1607
        SDL_SYS_JoystickUpdate_XInput(joystick);
slouken@7191
  1608
    }
slouken@7191
  1609
    else
slouken@7191
  1610
    {
slouken@7191
  1611
        result = IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
slouken@7191
  1612
        if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
slouken@7191
  1613
            IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
slouken@7191
  1614
            IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
slouken@7191
  1615
        }
slouken@6690
  1616
slouken@7191
  1617
        if (joystick->hwdata->buffered)
slouken@7191
  1618
            SDL_SYS_JoystickUpdate_Buffered(joystick);
slouken@7191
  1619
        else
slouken@7191
  1620
            SDL_SYS_JoystickUpdate_Polled(joystick);
slouken@7191
  1621
    }
slouken@6690
  1622
slouken@7191
  1623
    if ( joystick->hwdata->removed )
slouken@7191
  1624
    {
slouken@7191
  1625
        joystick->closed = 1;
slouken@7191
  1626
        joystick->uncentered = 1;
slouken@7191
  1627
    }
slouken@1895
  1628
}
slouken@1895
  1629
slouken@1895
  1630
/* Function to close a joystick after use */
slouken@1895
  1631
void
slouken@1895
  1632
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
slouken@1895
  1633
{
slouken@7191
  1634
    if ( joystick->hwdata->bXInputDevice )
slouken@7191
  1635
    {
slouken@7191
  1636
        JoyStick_DeviceData *joysticklist = SYS_Joystick;
slouken@7191
  1637
        /* scan the opened joysticks and clear the userid for this instance */
slouken@7191
  1638
        for( ; joysticklist; joysticklist = joysticklist->pNext)
slouken@7191
  1639
        {
slouken@7191
  1640
            if ( joysticklist->bXInputDevice && joysticklist->nInstanceID == joystick->instance_id )
slouken@7191
  1641
            {
slouken@7191
  1642
                joysticklist->XInputUserId = INVALID_XINPUT_USERID;
slouken@7191
  1643
            }
slouken@7191
  1644
        }
slouken@6690
  1645
slouken@7191
  1646
    }
slouken@7191
  1647
    else
slouken@7191
  1648
    {
slouken@7191
  1649
        IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
slouken@7191
  1650
        IDirectInputDevice8_Release(joystick->hwdata->InputDevice);
slouken@7191
  1651
    }
slouken@1895
  1652
slouken@1895
  1653
    if (joystick->hwdata != NULL) {
slouken@1895
  1654
        /* free system specific hardware data */
slouken@2713
  1655
        SDL_free(joystick->hwdata);
slouken@1895
  1656
    }
slouken@6690
  1657
slouken@7191
  1658
    joystick->closed = 1;
slouken@1895
  1659
}
slouken@1895
  1660
slouken@1895
  1661
/* Function to perform any system-specific joystick related cleanup */
slouken@1895
  1662
void
slouken@1895
  1663
SDL_SYS_JoystickQuit(void)
slouken@1895
  1664
{
slouken@7191
  1665
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@5090
  1666
slouken@7191
  1667
    while ( device )
slouken@7191
  1668
    {
slouken@7191
  1669
        JoyStick_DeviceData *device_next = device->pNext;
slouken@7191
  1670
        SDL_free(device->joystickname);
slouken@7191
  1671
        SDL_free(device);
slouken@7191
  1672
        device = device_next;
slouken@7191
  1673
    }
slouken@7191
  1674
    SYS_Joystick = NULL;
slouken@6690
  1675
slouken@7191
  1676
    if ( s_threadJoystick )
slouken@7191
  1677
    {
slouken@7191
  1678
        SDL_LockMutex( s_mutexJoyStickEnum );
slouken@7191
  1679
        s_bJoystickThreadQuit = SDL_TRUE;
slouken@7191
  1680
        SDL_CondBroadcast( s_condJoystickThread ); /* signal the joystick thread to quit */
slouken@7191
  1681
        SDL_UnlockMutex( s_mutexJoyStickEnum );
slouken@7191
  1682
        SDL_WaitThread( s_threadJoystick, NULL ); /* wait for it to bugger off */
slouken@6690
  1683
slouken@7191
  1684
        SDL_DestroyMutex( s_mutexJoyStickEnum );
slouken@7191
  1685
        SDL_DestroyCond( s_condJoystickThread );
slouken@7191
  1686
        s_condJoystickThread= NULL;
slouken@7191
  1687
        s_mutexJoyStickEnum = NULL;
slouken@7191
  1688
        s_threadJoystick = NULL;
slouken@7191
  1689
    }
slouken@5090
  1690
icculus@5591
  1691
    if (dinput != NULL) {
slouken@6690
  1692
        IDirectInput8_Release(dinput);
icculus@5591
  1693
        dinput = NULL;
icculus@5591
  1694
    }
icculus@5591
  1695
icculus@5591
  1696
    if (coinitialized) {
icculus@5591
  1697
        WIN_CoUninitialize();
icculus@5591
  1698
        coinitialized = SDL_FALSE;
icculus@5591
  1699
    }
slouken@6690
  1700
slouken@7191
  1701
    if ( s_pKnownJoystickGUIDs )
slouken@7191
  1702
    {
slouken@7191
  1703
        SDL_free( s_pKnownJoystickGUIDs );
slouken@7191
  1704
        s_pKnownJoystickGUIDs = NULL;
slouken@7191
  1705
    }
slouken@6690
  1706
icculus@6990
  1707
    if (s_bXInputEnabled) {
icculus@6990
  1708
        WIN_UnloadXInputDLL();
icculus@6990
  1709
    }
slouken@6690
  1710
}
slouken@6690
  1711
slouken@6690
  1712
slouken@6690
  1713
/* return the stable device guid for this device index */
slouken@6738
  1714
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
slouken@6690
  1715
{
slouken@7191
  1716
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@7191
  1717
    int index;
slouken@6690
  1718
slouken@7191
  1719
    for (index = device_index; index > 0; index--)
slouken@7191
  1720
        device = device->pNext;
slouken@6690
  1721
slouken@7191
  1722
    return device->guid;
slouken@6690
  1723
}
slouken@6690
  1724
slouken@6738
  1725
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
slouken@6707
  1726
{
slouken@7191
  1727
    return joystick->hwdata->guid;
slouken@6707
  1728
}
slouken@6707
  1729
slouken@6707
  1730
/* return SDL_TRUE if this device is using XInput */
slouken@6707
  1731
SDL_bool SDL_SYS_IsXInputDeviceIndex(int device_index)
slouken@6690
  1732
{
slouken@7191
  1733
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@7191
  1734
    int index;
slouken@6690
  1735
slouken@7191
  1736
    for (index = device_index; index > 0; index--)
slouken@7191
  1737
        device = device->pNext;
slouken@6690
  1738
slouken@7191
  1739
    return device->bXInputDevice;
slouken@6690
  1740
}
slouken@6690
  1741
slouken@1895
  1742
#endif /* SDL_JOYSTICK_DINPUT */
slouken@3575
  1743
slouken@1895
  1744
/* vi: set ts=4 sw=4 expandtab: */