src/joystick/windows/SDL_dxjoystick.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 24 Aug 2012 19:34:28 -0400
changeset 6403 8d34c6248f4a
parent 6220 c36934808194
child 6690 9548c8a58103
permissions -rwxr-xr-x
Fixed a bunch of compiler warnings with Cygwin/MingW.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #ifdef SDL_JOYSTICK_DINPUT
    24 
    25 /* DirectInput joystick driver; written by Glenn Maynard, based on Andrei de
    26  * A. Formiga's WINMM driver. 
    27  *
    28  * Hats and sliders are completely untested; the app I'm writing this for mostly
    29  * doesn't use them and I don't own any joysticks with them. 
    30  *
    31  * We don't bother to use event notification here.  It doesn't seem to work
    32  * with polled devices, and it's fine to call IDirectInputDevice2_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 #include "../SDL_joystick_c.h"
    40 #define INITGUID /* Only set here, if set twice will cause mingw32 to break. */
    41 #include "SDL_dxjoystick_c.h"
    42 
    43 
    44 #ifndef DIDFT_OPTIONAL
    45 #define DIDFT_OPTIONAL		0x80000000
    46 #endif
    47 
    48 
    49 #define INPUT_QSIZE	32      /* Buffer up to 32 input messages */
    50 #define MAX_JOYSTICKS	8
    51 #define AXIS_MIN	-32768  /* minimum value for axis coordinate */
    52 #define AXIS_MAX	32767   /* maximum value for axis coordinate */
    53 #define JOY_AXIS_THRESHOLD	(((AXIS_MAX)-(AXIS_MIN))/100)   /* 1% motion */
    54 
    55 /* external variables referenced. */
    56 extern HWND SDL_HelperWindow;
    57 
    58 
    59 /* local variables */
    60 static SDL_bool coinitialized = SDL_FALSE;
    61 static LPDIRECTINPUT dinput = NULL;
    62 extern HRESULT(WINAPI * DInputCreate) (HINSTANCE hinst, DWORD dwVersion,
    63                                        LPDIRECTINPUT * ppDI,
    64                                        LPUNKNOWN punkOuter);
    65 static DIDEVICEINSTANCE SYS_Joystick[MAX_JOYSTICKS];    /* array to hold joystick ID values */
    66 static char *SYS_JoystickNames[MAX_JOYSTICKS];
    67 static int SYS_NumJoysticks;
    68 
    69 
    70 /* local prototypes */
    71 static void SetDIerror(const char *function, HRESULT code);
    72 static BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE *
    73                                            pdidInstance, VOID * pContext);
    74 static BOOL CALLBACK EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev,
    75                                             LPVOID pvRef);
    76 static void SortDevObjects(SDL_Joystick *joystick);
    77 static Uint8 TranslatePOV(DWORD value);
    78 static int SDL_PrivateJoystickAxis_Int(SDL_Joystick * joystick, Uint8 axis,
    79                                        Sint16 value);
    80 static int SDL_PrivateJoystickHat_Int(SDL_Joystick * joystick, Uint8 hat,
    81                                       Uint8 value);
    82 static int SDL_PrivateJoystickButton_Int(SDL_Joystick * joystick,
    83                                          Uint8 button, Uint8 state);
    84 
    85 /* Taken from Wine - Thanks! */
    86 DIOBJECTDATAFORMAT dfDIJoystick2[] = {
    87   { &GUID_XAxis,DIJOFS_X,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
    88   { &GUID_YAxis,DIJOFS_Y,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
    89   { &GUID_ZAxis,DIJOFS_Z,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
    90   { &GUID_RxAxis,DIJOFS_RX,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
    91   { &GUID_RyAxis,DIJOFS_RY,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
    92   { &GUID_RzAxis,DIJOFS_RZ,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
    93   { &GUID_Slider,DIJOFS_SLIDER(0),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
    94   { &GUID_Slider,DIJOFS_SLIDER(1),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
    95   { &GUID_POV,DIJOFS_POV(0),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0},
    96   { &GUID_POV,DIJOFS_POV(1),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0},
    97   { &GUID_POV,DIJOFS_POV(2),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0},
    98   { &GUID_POV,DIJOFS_POV(3),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0},
    99   { NULL,DIJOFS_BUTTON(0),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   100   { NULL,DIJOFS_BUTTON(1),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   101   { NULL,DIJOFS_BUTTON(2),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   102   { NULL,DIJOFS_BUTTON(3),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   103   { NULL,DIJOFS_BUTTON(4),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   104   { NULL,DIJOFS_BUTTON(5),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   105   { NULL,DIJOFS_BUTTON(6),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   106   { NULL,DIJOFS_BUTTON(7),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   107   { NULL,DIJOFS_BUTTON(8),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   108   { NULL,DIJOFS_BUTTON(9),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   109   { NULL,DIJOFS_BUTTON(10),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   110   { NULL,DIJOFS_BUTTON(11),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   111   { NULL,DIJOFS_BUTTON(12),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   112   { NULL,DIJOFS_BUTTON(13),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   113   { NULL,DIJOFS_BUTTON(14),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   114   { NULL,DIJOFS_BUTTON(15),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   115   { NULL,DIJOFS_BUTTON(16),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   116   { NULL,DIJOFS_BUTTON(17),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   117   { NULL,DIJOFS_BUTTON(18),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   118   { NULL,DIJOFS_BUTTON(19),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   119   { NULL,DIJOFS_BUTTON(20),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   120   { NULL,DIJOFS_BUTTON(21),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   121   { NULL,DIJOFS_BUTTON(22),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   122   { NULL,DIJOFS_BUTTON(23),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   123   { NULL,DIJOFS_BUTTON(24),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   124   { NULL,DIJOFS_BUTTON(25),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   125   { NULL,DIJOFS_BUTTON(26),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   126   { NULL,DIJOFS_BUTTON(27),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   127   { NULL,DIJOFS_BUTTON(28),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   128   { NULL,DIJOFS_BUTTON(29),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   129   { NULL,DIJOFS_BUTTON(30),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   130   { NULL,DIJOFS_BUTTON(31),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   131   { NULL,DIJOFS_BUTTON(32),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   132   { NULL,DIJOFS_BUTTON(33),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   133   { NULL,DIJOFS_BUTTON(34),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   134   { NULL,DIJOFS_BUTTON(35),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   135   { NULL,DIJOFS_BUTTON(36),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   136   { NULL,DIJOFS_BUTTON(37),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   137   { NULL,DIJOFS_BUTTON(38),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   138   { NULL,DIJOFS_BUTTON(39),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   139   { NULL,DIJOFS_BUTTON(40),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   140   { NULL,DIJOFS_BUTTON(41),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   141   { NULL,DIJOFS_BUTTON(42),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   142   { NULL,DIJOFS_BUTTON(43),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   143   { NULL,DIJOFS_BUTTON(44),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   144   { NULL,DIJOFS_BUTTON(45),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   145   { NULL,DIJOFS_BUTTON(46),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   146   { NULL,DIJOFS_BUTTON(47),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   147   { NULL,DIJOFS_BUTTON(48),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   148   { NULL,DIJOFS_BUTTON(49),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   149   { NULL,DIJOFS_BUTTON(50),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   150   { NULL,DIJOFS_BUTTON(51),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   151   { NULL,DIJOFS_BUTTON(52),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   152   { NULL,DIJOFS_BUTTON(53),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   153   { NULL,DIJOFS_BUTTON(54),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   154   { NULL,DIJOFS_BUTTON(55),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   155   { NULL,DIJOFS_BUTTON(56),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   156   { NULL,DIJOFS_BUTTON(57),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   157   { NULL,DIJOFS_BUTTON(58),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   158   { NULL,DIJOFS_BUTTON(59),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   159   { NULL,DIJOFS_BUTTON(60),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   160   { NULL,DIJOFS_BUTTON(61),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   161   { NULL,DIJOFS_BUTTON(62),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   162   { NULL,DIJOFS_BUTTON(63),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   163   { NULL,DIJOFS_BUTTON(64),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   164   { NULL,DIJOFS_BUTTON(65),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   165   { NULL,DIJOFS_BUTTON(66),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   166   { NULL,DIJOFS_BUTTON(67),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   167   { NULL,DIJOFS_BUTTON(68),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   168   { NULL,DIJOFS_BUTTON(69),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   169   { NULL,DIJOFS_BUTTON(70),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   170   { NULL,DIJOFS_BUTTON(71),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   171   { NULL,DIJOFS_BUTTON(72),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   172   { NULL,DIJOFS_BUTTON(73),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   173   { NULL,DIJOFS_BUTTON(74),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   174   { NULL,DIJOFS_BUTTON(75),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   175   { NULL,DIJOFS_BUTTON(76),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   176   { NULL,DIJOFS_BUTTON(77),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   177   { NULL,DIJOFS_BUTTON(78),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   178   { NULL,DIJOFS_BUTTON(79),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   179   { NULL,DIJOFS_BUTTON(80),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   180   { NULL,DIJOFS_BUTTON(81),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   181   { NULL,DIJOFS_BUTTON(82),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   182   { NULL,DIJOFS_BUTTON(83),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   183   { NULL,DIJOFS_BUTTON(84),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   184   { NULL,DIJOFS_BUTTON(85),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   185   { NULL,DIJOFS_BUTTON(86),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   186   { NULL,DIJOFS_BUTTON(87),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   187   { NULL,DIJOFS_BUTTON(88),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   188   { NULL,DIJOFS_BUTTON(89),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   189   { NULL,DIJOFS_BUTTON(90),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   190   { NULL,DIJOFS_BUTTON(91),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   191   { NULL,DIJOFS_BUTTON(92),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   192   { NULL,DIJOFS_BUTTON(93),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   193   { NULL,DIJOFS_BUTTON(94),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   194   { NULL,DIJOFS_BUTTON(95),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   195   { NULL,DIJOFS_BUTTON(96),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   196   { NULL,DIJOFS_BUTTON(97),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   197   { NULL,DIJOFS_BUTTON(98),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   198   { NULL,DIJOFS_BUTTON(99),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   199   { NULL,DIJOFS_BUTTON(100),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   200   { NULL,DIJOFS_BUTTON(101),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   201   { NULL,DIJOFS_BUTTON(102),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   202   { NULL,DIJOFS_BUTTON(103),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   203   { NULL,DIJOFS_BUTTON(104),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   204   { NULL,DIJOFS_BUTTON(105),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   205   { NULL,DIJOFS_BUTTON(106),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   206   { NULL,DIJOFS_BUTTON(107),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   207   { NULL,DIJOFS_BUTTON(108),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   208   { NULL,DIJOFS_BUTTON(109),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   209   { NULL,DIJOFS_BUTTON(110),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   210   { NULL,DIJOFS_BUTTON(111),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   211   { NULL,DIJOFS_BUTTON(112),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   212   { NULL,DIJOFS_BUTTON(113),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   213   { NULL,DIJOFS_BUTTON(114),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   214   { NULL,DIJOFS_BUTTON(115),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   215   { NULL,DIJOFS_BUTTON(116),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   216   { NULL,DIJOFS_BUTTON(117),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   217   { NULL,DIJOFS_BUTTON(118),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   218   { NULL,DIJOFS_BUTTON(119),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   219   { NULL,DIJOFS_BUTTON(120),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   220   { NULL,DIJOFS_BUTTON(121),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   221   { NULL,DIJOFS_BUTTON(122),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   222   { NULL,DIJOFS_BUTTON(123),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   223   { NULL,DIJOFS_BUTTON(124),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   224   { NULL,DIJOFS_BUTTON(125),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   225   { NULL,DIJOFS_BUTTON(126),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   226   { NULL,DIJOFS_BUTTON(127),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
   227   { &GUID_XAxis,FIELD_OFFSET(DIJOYSTATE2,lVX),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   228   { &GUID_YAxis,FIELD_OFFSET(DIJOYSTATE2,lVY),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   229   { &GUID_ZAxis,FIELD_OFFSET(DIJOYSTATE2,lVZ),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   230   { &GUID_RxAxis,FIELD_OFFSET(DIJOYSTATE2,lVRx),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   231   { &GUID_RyAxis,FIELD_OFFSET(DIJOYSTATE2,lVRy),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   232   { &GUID_RzAxis,FIELD_OFFSET(DIJOYSTATE2,lVRz),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   233   { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglVSlider[0]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   234   { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglVSlider[1]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   235   { &GUID_XAxis,FIELD_OFFSET(DIJOYSTATE2,lAX),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   236   { &GUID_YAxis,FIELD_OFFSET(DIJOYSTATE2,lAY),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   237   { &GUID_ZAxis,FIELD_OFFSET(DIJOYSTATE2,lAZ),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   238   { &GUID_RxAxis,FIELD_OFFSET(DIJOYSTATE2,lARx),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   239   { &GUID_RyAxis,FIELD_OFFSET(DIJOYSTATE2,lARy),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   240   { &GUID_RzAxis,FIELD_OFFSET(DIJOYSTATE2,lARz),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   241   { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglASlider[0]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   242   { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglASlider[1]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   243   { &GUID_XAxis,FIELD_OFFSET(DIJOYSTATE2,lFX),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   244   { &GUID_YAxis,FIELD_OFFSET(DIJOYSTATE2,lFY),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   245   { &GUID_ZAxis,FIELD_OFFSET(DIJOYSTATE2,lFZ),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   246   { &GUID_RxAxis,FIELD_OFFSET(DIJOYSTATE2,lFRx),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   247   { &GUID_RyAxis,FIELD_OFFSET(DIJOYSTATE2,lFRy),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   248   { &GUID_RzAxis,FIELD_OFFSET(DIJOYSTATE2,lFRz),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   249   { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglFSlider[0]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   250   { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglFSlider[1]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
   251 };
   252 
   253 const DIDATAFORMAT c_dfDIJoystick2 = {
   254     sizeof(DIDATAFORMAT),
   255     sizeof(DIOBJECTDATAFORMAT),
   256     DIDF_ABSAXIS,
   257     sizeof(DIJOYSTATE2),
   258     SDL_arraysize(dfDIJoystick2),
   259     dfDIJoystick2
   260 };
   261 
   262 
   263 /* Convert a DirectInput return code to a text message */
   264 static void
   265 SetDIerror(const char *function, HRESULT code)
   266 {
   267     /*
   268     SDL_SetError("%s() [%s]: %s", function,
   269                  DXGetErrorString9A(code), DXGetErrorDescription9A(code));
   270      */
   271     SDL_SetError("%s() DirectX error %d", function, code);
   272 }
   273 
   274 
   275 /* Function to scan the system for joysticks.
   276  * This function should set SDL_numjoysticks to the number of available
   277  * joysticks.  Joystick 0 should be the system default joystick.
   278  * It should return 0, or -1 on an unrecoverable fatal error.
   279  */
   280 int
   281 SDL_SYS_JoystickInit(void)
   282 {
   283     HRESULT result;
   284     HINSTANCE instance;
   285 
   286     SYS_NumJoysticks = 0;
   287 
   288     result = WIN_CoInitialize();
   289     if (FAILED(result)) {
   290         SetDIerror("CoInitialize", result);
   291         return (-1);
   292     }
   293 
   294     coinitialized = SDL_TRUE;
   295 
   296     result = CoCreateInstance(&CLSID_DirectInput, NULL, CLSCTX_INPROC_SERVER,
   297                               &IID_IDirectInput, (LPVOID)&dinput);
   298 
   299     if (FAILED(result)) {
   300         SDL_SYS_JoystickQuit();
   301         SetDIerror("CoCreateInstance", result);
   302         return (-1);
   303     }
   304 
   305     /* Because we used CoCreateInstance, we need to Initialize it, first. */
   306     instance = GetModuleHandle(NULL);
   307     if (instance == NULL) {
   308         SDL_SYS_JoystickQuit();
   309         SDL_SetError("GetModuleHandle() failed with error code %d.",
   310                      GetLastError());
   311         return (-1);
   312     }
   313     result = IDirectInput_Initialize(dinput, instance, DIRECTINPUT_VERSION);
   314 
   315     if (FAILED(result)) {
   316         SDL_SYS_JoystickQuit();
   317         SetDIerror("IDirectInput::Initialize", result);
   318         return (-1);
   319     }
   320 
   321     /* Look for joysticks, wheels, head trackers, gamepads, etc.. */
   322     result = IDirectInput_EnumDevices(dinput,
   323                                       DIDEVTYPE_JOYSTICK,
   324                                       EnumJoysticksCallback,
   325                                       NULL, DIEDFL_ATTACHEDONLY);
   326 
   327     return SYS_NumJoysticks;
   328 }
   329 
   330 static BOOL CALLBACK
   331 EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
   332 {
   333     SDL_memcpy(&SYS_Joystick[SYS_NumJoysticks], pdidInstance,
   334                sizeof(DIDEVICEINSTANCE));
   335     SYS_JoystickNames[SYS_NumJoysticks] = WIN_StringToUTF8(pdidInstance->tszProductName);
   336     SYS_NumJoysticks++;
   337 
   338     if (SYS_NumJoysticks >= MAX_JOYSTICKS)
   339         return DIENUM_STOP;
   340 
   341     return DIENUM_CONTINUE;
   342 }
   343 
   344 /* Function to get the device-dependent name of a joystick */
   345 const char *
   346 SDL_SYS_JoystickName(int index)
   347 {
   348     return SYS_JoystickNames[index];
   349 }
   350 
   351 /* Function to open a joystick for use.
   352    The joystick to open is specified by the index field of the joystick.
   353    This should fill the nbuttons and naxes fields of the joystick structure.
   354    It returns 0, or -1 if there is an error.
   355  */
   356 int
   357 SDL_SYS_JoystickOpen(SDL_Joystick * joystick)
   358 {
   359     HRESULT result;
   360     LPDIRECTINPUTDEVICE device;
   361     DIPROPDWORD dipdw;
   362 
   363     SDL_memset(&dipdw, 0, sizeof(DIPROPDWORD));
   364     dipdw.diph.dwSize = sizeof(DIPROPDWORD);
   365     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
   366 
   367 
   368     /* allocate memory for system specific hardware data */
   369     joystick->hwdata =
   370         (struct joystick_hwdata *) SDL_malloc(sizeof(struct joystick_hwdata));
   371     if (joystick->hwdata == NULL) {
   372         SDL_OutOfMemory();
   373         return (-1);
   374     }
   375     SDL_memset(joystick->hwdata, 0, sizeof(struct joystick_hwdata));
   376     joystick->hwdata->buffered = 1;
   377     joystick->hwdata->Capabilities.dwSize = sizeof(DIDEVCAPS);
   378 
   379     result =
   380         IDirectInput_CreateDevice(dinput,
   381                                   &SYS_Joystick[joystick->index].
   382                                   guidInstance, &device, NULL);
   383     if (FAILED(result)) {
   384         SetDIerror("IDirectInput::CreateDevice", result);
   385         return (-1);
   386     }
   387 
   388     /* Now get the IDirectInputDevice2 interface, instead. */
   389     result = IDirectInputDevice_QueryInterface(device,
   390                                                &IID_IDirectInputDevice2,
   391                                                (LPVOID *) & joystick->
   392                                                hwdata->InputDevice);
   393     /* We are done with this object.  Use the stored one from now on. */
   394     IDirectInputDevice_Release(device);
   395 
   396     if (FAILED(result)) {
   397         SetDIerror("IDirectInputDevice::QueryInterface", result);
   398         return (-1);
   399     }
   400 
   401     /* Aquire shared access. Exclusive access is required for forces,
   402      * though. */
   403     result =
   404         IDirectInputDevice2_SetCooperativeLevel(joystick->hwdata->
   405                                                 InputDevice, SDL_HelperWindow,
   406                                                 DISCL_EXCLUSIVE |
   407                                                 DISCL_BACKGROUND);
   408     if (FAILED(result)) {
   409         SetDIerror("IDirectInputDevice2::SetCooperativeLevel", result);
   410         return (-1);
   411     }
   412 
   413     /* Use the extended data structure: DIJOYSTATE2. */
   414     result =
   415         IDirectInputDevice2_SetDataFormat(joystick->hwdata->InputDevice,
   416                                           &c_dfDIJoystick2);
   417     if (FAILED(result)) {
   418         SetDIerror("IDirectInputDevice2::SetDataFormat", result);
   419         return (-1);
   420     }
   421 
   422     /* Get device capabilities */
   423     result =
   424         IDirectInputDevice2_GetCapabilities(joystick->hwdata->InputDevice,
   425                                             &joystick->hwdata->Capabilities);
   426 
   427     if (FAILED(result)) {
   428         SetDIerror("IDirectInputDevice2::GetCapabilities", result);
   429         return (-1);
   430     }
   431 
   432     /* Force capable? */
   433     if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
   434 
   435         result = IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
   436 
   437         if (FAILED(result)) {
   438             SetDIerror("IDirectInputDevice2::Acquire", result);
   439             return (-1);
   440         }
   441 
   442         /* reset all accuators. */
   443         result =
   444             IDirectInputDevice2_SendForceFeedbackCommand(joystick->hwdata->
   445                                                          InputDevice,
   446                                                          DISFFC_RESET);
   447 
   448         /* Not necessarily supported, ignore if not supported.
   449         if (FAILED(result)) {
   450             SetDIerror("IDirectInputDevice2::SendForceFeedbackCommand",
   451                        result);
   452             return (-1);
   453         }
   454         */
   455 
   456         result = IDirectInputDevice2_Unacquire(joystick->hwdata->InputDevice);
   457 
   458         if (FAILED(result)) {
   459             SetDIerror("IDirectInputDevice2::Unacquire", result);
   460             return (-1);
   461         }
   462 
   463         /* Turn on auto-centering for a ForceFeedback device (until told
   464          * otherwise). */
   465         dipdw.diph.dwObj = 0;
   466         dipdw.diph.dwHow = DIPH_DEVICE;
   467         dipdw.dwData = DIPROPAUTOCENTER_ON;
   468 
   469         result =
   470             IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
   471                                             DIPROP_AUTOCENTER, &dipdw.diph);
   472 
   473         /* Not necessarily supported, ignore if not supported.
   474         if (FAILED(result)) {
   475             SetDIerror("IDirectInputDevice2::SetProperty", result);
   476             return (-1);
   477         }
   478         */
   479     }
   480 
   481     /* What buttons and axes does it have? */
   482     IDirectInputDevice2_EnumObjects(joystick->hwdata->InputDevice,
   483                                     EnumDevObjectsCallback, joystick,
   484                                     DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV);
   485 
   486 	/* Reorder the input objects. Some devices do not report the X axis as
   487 	 * the first axis, for example. */
   488 	SortDevObjects(joystick);
   489 
   490     dipdw.diph.dwObj = 0;
   491     dipdw.diph.dwHow = DIPH_DEVICE;
   492     dipdw.dwData = INPUT_QSIZE;
   493 
   494     /* Set the buffer size */
   495     result =
   496         IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
   497                                         DIPROP_BUFFERSIZE, &dipdw.diph);
   498 
   499     if (result == DI_POLLEDDEVICE) {
   500         /* This device doesn't support buffering, so we're forced
   501          * to use less reliable polling. */
   502         joystick->hwdata->buffered = 0;
   503     } else if (FAILED(result)) {
   504         SetDIerror("IDirectInputDevice2::SetProperty", result);
   505         return (-1);
   506     }
   507 
   508     return (0);
   509 }
   510 
   511 /* Sort using the data offset into the DInput struct.
   512  * This gives a reasonable ordering for the inputs. */
   513 static int
   514 SortDevFunc(const void *a, const void *b)
   515 {
   516 	const input_t *inputA = (const input_t*)a;
   517 	const input_t *inputB = (const input_t*)b;
   518 
   519 	if (inputA->ofs < inputB->ofs)
   520 		return -1;
   521 	if (inputA->ofs > inputB->ofs)
   522 		return 1;
   523 	return 0;
   524 }
   525 
   526 /* Sort the input objects and recalculate the indices for each input. */
   527 static void
   528 SortDevObjects(SDL_Joystick *joystick)
   529 {
   530 	input_t *inputs = joystick->hwdata->Inputs;
   531 	int nButtons = 0;
   532 	int nHats = 0;
   533 	int nAxis = 0;
   534 	int n;
   535 
   536 	SDL_qsort(inputs, joystick->hwdata->NumInputs, sizeof(input_t), SortDevFunc);
   537 
   538 	for (n = 0; n < joystick->hwdata->NumInputs; n++)
   539 	{
   540 		switch (inputs[n].type)
   541 		{
   542 		case BUTTON:
   543 			inputs[n].num = nButtons;
   544 			nButtons++;
   545 			break;
   546 
   547 		case HAT:
   548 			inputs[n].num = nHats;
   549 			nHats++;
   550 			break;
   551 
   552 		case AXIS:
   553 			inputs[n].num = nAxis;
   554 			nAxis++;
   555 			break;
   556 		}
   557 	}
   558 }
   559 
   560 static BOOL CALLBACK
   561 EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
   562 {
   563     SDL_Joystick *joystick = (SDL_Joystick *) pvRef;
   564     HRESULT result;
   565     input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs];
   566 
   567     in->ofs = dev->dwOfs;
   568 
   569     if (dev->dwType & DIDFT_BUTTON) {
   570         in->type = BUTTON;
   571         in->num = joystick->nbuttons;
   572         joystick->nbuttons++;
   573     } else if (dev->dwType & DIDFT_POV) {
   574         in->type = HAT;
   575         in->num = joystick->nhats;
   576         joystick->nhats++;
   577     } else if (dev->dwType & DIDFT_AXIS) {
   578         DIPROPRANGE diprg;
   579         DIPROPDWORD dilong;
   580 
   581         in->type = AXIS;
   582         in->num = joystick->naxes;
   583 
   584         diprg.diph.dwSize = sizeof(diprg);
   585         diprg.diph.dwHeaderSize = sizeof(diprg.diph);
   586         diprg.diph.dwObj = dev->dwOfs;
   587         diprg.diph.dwHow = DIPH_BYOFFSET;
   588         diprg.lMin = AXIS_MIN;
   589         diprg.lMax = AXIS_MAX;
   590 
   591         result =
   592             IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
   593                                             DIPROP_RANGE, &diprg.diph);
   594         if (FAILED(result)) {
   595             return DIENUM_CONTINUE;     /* don't use this axis */
   596         }
   597 
   598         /* Set dead zone to 0. */
   599         dilong.diph.dwSize = sizeof(dilong);
   600         dilong.diph.dwHeaderSize = sizeof(dilong.diph);
   601         dilong.diph.dwObj = dev->dwOfs;
   602         dilong.diph.dwHow = DIPH_BYOFFSET;
   603         dilong.dwData = 0;
   604         result =
   605             IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
   606                                             DIPROP_DEADZONE, &dilong.diph);
   607         if (FAILED(result)) {
   608             return DIENUM_CONTINUE;     /* don't use this axis */
   609         }
   610 
   611         joystick->naxes++;
   612     } else {
   613         /* not supported at this time */
   614         return DIENUM_CONTINUE;
   615     }
   616 
   617     joystick->hwdata->NumInputs++;
   618 
   619     if (joystick->hwdata->NumInputs == MAX_INPUTS) {
   620         return DIENUM_STOP;     /* too many */
   621     }
   622 
   623     return DIENUM_CONTINUE;
   624 }
   625 
   626 /* Function to update the state of a joystick - called as a device poll.
   627  * This function shouldn't update the joystick structure directly,
   628  * but instead should call SDL_PrivateJoystick*() to deliver events
   629  * and update joystick device state.
   630  */
   631 void
   632 SDL_SYS_JoystickUpdate_Polled(SDL_Joystick * joystick)
   633 {
   634     DIJOYSTATE2 state;
   635     HRESULT result;
   636     int i;
   637 
   638     result =
   639         IDirectInputDevice2_GetDeviceState(joystick->hwdata->InputDevice,
   640                                            sizeof(DIJOYSTATE2), &state);
   641     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
   642         IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
   643         result =
   644             IDirectInputDevice2_GetDeviceState(joystick->hwdata->InputDevice,
   645                                                sizeof(DIJOYSTATE2), &state);
   646     }
   647 
   648     /* Set each known axis, button and POV. */
   649     for (i = 0; i < joystick->hwdata->NumInputs; ++i) {
   650         const input_t *in = &joystick->hwdata->Inputs[i];
   651 
   652         switch (in->type) {
   653         case AXIS:
   654             switch (in->ofs) {
   655             case DIJOFS_X:
   656                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   657                                             (Sint16) state.lX);
   658                 break;
   659             case DIJOFS_Y:
   660                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   661                                             (Sint16) state.lY);
   662                 break;
   663             case DIJOFS_Z:
   664                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   665                                             (Sint16) state.lZ);
   666                 break;
   667             case DIJOFS_RX:
   668                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   669                                             (Sint16) state.lRx);
   670                 break;
   671             case DIJOFS_RY:
   672                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   673                                             (Sint16) state.lRy);
   674                 break;
   675             case DIJOFS_RZ:
   676                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   677                                             (Sint16) state.lRz);
   678                 break;
   679             case DIJOFS_SLIDER(0):
   680                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   681                                             (Sint16) state.rglSlider[0]);
   682                 break;
   683             case DIJOFS_SLIDER(1):
   684                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   685                                             (Sint16) state.rglSlider[1]);
   686                 break;
   687             }
   688 
   689             break;
   690 
   691         case BUTTON:
   692             SDL_PrivateJoystickButton_Int(joystick, in->num,
   693                                           (Uint8) (state.
   694                                                    rgbButtons[in->ofs -
   695                                                               DIJOFS_BUTTON0]
   696                                                    ? SDL_PRESSED :
   697                                                    SDL_RELEASED));
   698             break;
   699         case HAT:
   700             {
   701                 Uint8 pos = TranslatePOV(state.rgdwPOV[in->ofs -
   702                                                        DIJOFS_POV(0)]);
   703                 SDL_PrivateJoystickHat_Int(joystick, in->num, pos);
   704                 break;
   705             }
   706         }
   707     }
   708 }
   709 
   710 void
   711 SDL_SYS_JoystickUpdate_Buffered(SDL_Joystick * joystick)
   712 {
   713     int i;
   714     HRESULT result;
   715     DWORD numevents;
   716     DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
   717 
   718     numevents = INPUT_QSIZE;
   719     result =
   720         IDirectInputDevice2_GetDeviceData(joystick->hwdata->InputDevice,
   721                                           sizeof(DIDEVICEOBJECTDATA), evtbuf,
   722                                           &numevents, 0);
   723     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
   724         IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
   725         result =
   726             IDirectInputDevice2_GetDeviceData(joystick->hwdata->InputDevice,
   727                                               sizeof(DIDEVICEOBJECTDATA),
   728                                               evtbuf, &numevents, 0);
   729     }
   730 
   731     /* Handle the events or punt */
   732     if (FAILED(result))
   733         return;
   734 
   735     for (i = 0; i < (int) numevents; ++i) {
   736         int j;
   737 
   738         for (j = 0; j < joystick->hwdata->NumInputs; ++j) {
   739             const input_t *in = &joystick->hwdata->Inputs[j];
   740 
   741             if (evtbuf[i].dwOfs != in->ofs)
   742                 continue;
   743 
   744             switch (in->type) {
   745             case AXIS:
   746                 SDL_PrivateJoystickAxis(joystick, in->num,
   747                                         (Sint16) evtbuf[i].dwData);
   748                 break;
   749             case BUTTON:
   750                 SDL_PrivateJoystickButton(joystick, in->num,
   751                                           (Uint8) (evtbuf[i].
   752                                                    dwData ? SDL_PRESSED :
   753                                                    SDL_RELEASED));
   754                 break;
   755             case HAT:
   756                 {
   757                     Uint8 pos = TranslatePOV(evtbuf[i].dwData);
   758                     SDL_PrivateJoystickHat(joystick, in->num, pos);
   759                 }
   760             }
   761         }
   762     }
   763 }
   764 
   765 
   766 static Uint8
   767 TranslatePOV(DWORD value)
   768 {
   769     const int HAT_VALS[] = {
   770         SDL_HAT_UP,
   771         SDL_HAT_UP | SDL_HAT_RIGHT,
   772         SDL_HAT_RIGHT,
   773         SDL_HAT_DOWN | SDL_HAT_RIGHT,
   774         SDL_HAT_DOWN,
   775         SDL_HAT_DOWN | SDL_HAT_LEFT,
   776         SDL_HAT_LEFT,
   777         SDL_HAT_UP | SDL_HAT_LEFT
   778     };
   779 
   780     if (LOWORD(value) == 0xFFFF)
   781         return SDL_HAT_CENTERED;
   782 
   783     /* Round the value up: */
   784     value += 4500 / 2;
   785     value %= 36000;
   786     value /= 4500;
   787 
   788     if (value >= 8)
   789         return SDL_HAT_CENTERED;        /* shouldn't happen */
   790 
   791     return HAT_VALS[value];
   792 }
   793 
   794 /* SDL_PrivateJoystick* doesn't discard duplicate events, so we need to
   795  * do it. */
   796 static int
   797 SDL_PrivateJoystickAxis_Int(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
   798 {
   799     if (joystick->axes[axis] != value)
   800         return SDL_PrivateJoystickAxis(joystick, axis, value);
   801     return 0;
   802 }
   803 
   804 static int
   805 SDL_PrivateJoystickHat_Int(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
   806 {
   807     if (joystick->hats[hat] != value)
   808         return SDL_PrivateJoystickHat(joystick, hat, value);
   809     return 0;
   810 }
   811 
   812 static int
   813 SDL_PrivateJoystickButton_Int(SDL_Joystick * joystick, Uint8 button,
   814                               Uint8 state)
   815 {
   816     if (joystick->buttons[button] != state)
   817         return SDL_PrivateJoystickButton(joystick, button, state);
   818     return 0;
   819 }
   820 
   821 void
   822 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
   823 {
   824     HRESULT result;
   825 
   826     result = IDirectInputDevice2_Poll(joystick->hwdata->InputDevice);
   827     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
   828         IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
   829         IDirectInputDevice2_Poll(joystick->hwdata->InputDevice);
   830     }
   831 
   832     if (joystick->hwdata->buffered)
   833         SDL_SYS_JoystickUpdate_Buffered(joystick);
   834     else
   835         SDL_SYS_JoystickUpdate_Polled(joystick);
   836 }
   837 
   838 /* Function to close a joystick after use */
   839 void
   840 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
   841 {
   842     IDirectInputDevice2_Unacquire(joystick->hwdata->InputDevice);
   843     IDirectInputDevice2_Release(joystick->hwdata->InputDevice);
   844 
   845     if (joystick->hwdata != NULL) {
   846         /* free system specific hardware data */
   847         SDL_free(joystick->hwdata);
   848     }
   849 }
   850 
   851 /* Function to perform any system-specific joystick related cleanup */
   852 void
   853 SDL_SYS_JoystickQuit(void)
   854 {
   855     int i;
   856 
   857     for (i = 0; i < SDL_arraysize(SYS_JoystickNames); ++i) {
   858         if (SYS_JoystickNames[i]) {
   859             SDL_free(SYS_JoystickNames[i]);
   860             SYS_JoystickNames[i] = NULL;
   861         }
   862     }
   863 
   864     if (dinput != NULL) {
   865         IDirectInput_Release(dinput);
   866         dinput = NULL;
   867     }
   868 
   869     if (coinitialized) {
   870         WIN_CoUninitialize();
   871         coinitialized = SDL_FALSE;
   872     }
   873 }
   874 
   875 #endif /* SDL_JOYSTICK_DINPUT */
   876 
   877 /* vi: set ts=4 sw=4 expandtab: */