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