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