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