src/joystick/windows/SDL_dxjoystick.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 28 Aug 2013 16:35:32 -0400
changeset 7706 8cc29a668223
parent 7685 89f669598b87
child 7707 37e02f8fcfa8
permissions -rw-r--r--
Better XInput detection code for DirectInput device enumeration.

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