src/joystick/windows/SDL_dxjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 17 Oct 2013 23:40:13 -0700
changeset 7831 214cd9137ea9
parent 7719 31b5f9ff36ca
child 7844 97fa86ce5a2e
permissions -rw-r--r--
Fixed bug 2069 - Device addition/removal queries all USB devices rather than only HID devices.

Andreas Ertelt
SDL_dxjoystick.c is setting the classguid for device (dis)connect events to USB Devices in general:
dbh.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE;

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