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