src/joystick/windows/SDL_dxjoystick.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 29 Nov 2012 15:24:56 -0500
changeset 6716 1616f6b3738c
parent 6712 05f046f5886b
child 6738 b408d5a406a3
permissions -rw-r--r--
Move all DirectInput code from DI2 to DI8.

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