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