src/joystick/windows/SDL_dxjoystick.c
author Ryan C. Gordon <icculus@icculus.org>
Sun, 31 Mar 2013 12:48:50 -0400
changeset 7037 3fedf1f25b94
parent 6993 33f1e384ed56
child 7133 87d4cb9bb66c
permissions -rw-r--r--
Make SDL_SetError and friends unconditionally return -1.

This lets us change things like this...

if (Failed) {
SDL_SetError("We failed");
return -1;
}

...into this...

if (Failed) {
return SDL_SetError("We failed");
}


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