src/joystick/windows/SDL_dxjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 27 Jun 2013 11:21:37 -0700
changeset 7321 46de847fef38
parent 7299 280e86365933
child 7663 53fe1b64eb2d
permissions -rw-r--r--
Fixed bug: SDL2 Xinput joystick axis jumps from positive to negative

Franz Schrober

Attached is my patch. It ensures that the values are correctly limitted between -32767 and 32767 (otherwise the negator - and the conversion to sint16 would corrupt the result)

I am using Motioninjoy (Dualshock 3 Sixaxxis controller on Windows 7) together with a recent SDL2 (post rc1) and noticed with the testjoystick binary that the axis 3 (left analog up/down) jumps when going in down direction from 32257 to -32768. This seems obviously wrong and I have never seen this before. In my games the people are now going backwards before they start to sprint forward when the player actually wants to run as fast as possible backwards. This also happens on the axis 2 (right analog stick up/down)

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