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