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