src/joystick/windows/SDL_dxjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 31 Dec 2011 09:28:07 -0500
changeset 6138 4c64952a58fb
parent 5591 17beb16fa838
child 6220 c36934808194
permissions -rwxr-xr-x
Happy New Year!
     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 static HINSTANCE DInputDLL = NULL;
    69 
    70 
    71 /* local prototypes */
    72 static void SetDIerror(const char *function, HRESULT code);
    73 static BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE *
    74                                            pdidInstance, VOID * pContext);
    75 static BOOL CALLBACK EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev,
    76                                             LPVOID pvRef);
    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     dipdw.diph.dwObj = 0;
   487     dipdw.diph.dwHow = DIPH_DEVICE;
   488     dipdw.dwData = INPUT_QSIZE;
   489 
   490     /* Set the buffer size */
   491     result =
   492         IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
   493                                         DIPROP_BUFFERSIZE, &dipdw.diph);
   494 
   495     if (result == DI_POLLEDDEVICE) {
   496         /* This device doesn't support buffering, so we're forced
   497          * to use less reliable polling. */
   498         joystick->hwdata->buffered = 0;
   499     } else if (FAILED(result)) {
   500         SetDIerror("IDirectInputDevice2::SetProperty", result);
   501         return (-1);
   502     }
   503 
   504     return (0);
   505 }
   506 
   507 static BOOL CALLBACK
   508 EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
   509 {
   510     SDL_Joystick *joystick = (SDL_Joystick *) pvRef;
   511     HRESULT result;
   512     input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs];
   513 
   514     in->ofs = dev->dwOfs;
   515 
   516     if (dev->dwType & DIDFT_BUTTON) {
   517         in->type = BUTTON;
   518         in->num = joystick->nbuttons;
   519         joystick->nbuttons++;
   520     } else if (dev->dwType & DIDFT_POV) {
   521         in->type = HAT;
   522         in->num = joystick->nhats;
   523         joystick->nhats++;
   524     } else if (dev->dwType & DIDFT_AXIS) {
   525         DIPROPRANGE diprg;
   526         DIPROPDWORD dilong;
   527 
   528         in->type = AXIS;
   529         in->num = joystick->naxes;
   530 
   531         diprg.diph.dwSize = sizeof(diprg);
   532         diprg.diph.dwHeaderSize = sizeof(diprg.diph);
   533         diprg.diph.dwObj = dev->dwOfs;
   534         diprg.diph.dwHow = DIPH_BYOFFSET;
   535         diprg.lMin = AXIS_MIN;
   536         diprg.lMax = AXIS_MAX;
   537 
   538         result =
   539             IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
   540                                             DIPROP_RANGE, &diprg.diph);
   541         if (FAILED(result)) {
   542             return DIENUM_CONTINUE;     /* don't use this axis */
   543         }
   544 
   545         /* Set dead zone to 0. */
   546         dilong.diph.dwSize = sizeof(dilong);
   547         dilong.diph.dwHeaderSize = sizeof(dilong.diph);
   548         dilong.diph.dwObj = dev->dwOfs;
   549         dilong.diph.dwHow = DIPH_BYOFFSET;
   550         dilong.dwData = 0;
   551         result =
   552             IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
   553                                             DIPROP_DEADZONE, &dilong.diph);
   554         if (FAILED(result)) {
   555             return DIENUM_CONTINUE;     /* don't use this axis */
   556         }
   557 
   558         joystick->naxes++;
   559     } else {
   560         /* not supported at this time */
   561         return DIENUM_CONTINUE;
   562     }
   563 
   564     joystick->hwdata->NumInputs++;
   565 
   566     if (joystick->hwdata->NumInputs == MAX_INPUTS) {
   567         return DIENUM_STOP;     /* too many */
   568     }
   569 
   570     return DIENUM_CONTINUE;
   571 }
   572 
   573 /* Function to update the state of a joystick - called as a device poll.
   574  * This function shouldn't update the joystick structure directly,
   575  * but instead should call SDL_PrivateJoystick*() to deliver events
   576  * and update joystick device state.
   577  */
   578 void
   579 SDL_SYS_JoystickUpdate_Polled(SDL_Joystick * joystick)
   580 {
   581     DIJOYSTATE2 state;
   582     HRESULT result;
   583     int i;
   584 
   585     result =
   586         IDirectInputDevice2_GetDeviceState(joystick->hwdata->InputDevice,
   587                                            sizeof(DIJOYSTATE2), &state);
   588     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
   589         IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
   590         result =
   591             IDirectInputDevice2_GetDeviceState(joystick->hwdata->InputDevice,
   592                                                sizeof(DIJOYSTATE2), &state);
   593     }
   594 
   595     /* Set each known axis, button and POV. */
   596     for (i = 0; i < joystick->hwdata->NumInputs; ++i) {
   597         const input_t *in = &joystick->hwdata->Inputs[i];
   598 
   599         switch (in->type) {
   600         case AXIS:
   601             switch (in->ofs) {
   602             case DIJOFS_X:
   603                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   604                                             (Sint16) state.lX);
   605                 break;
   606             case DIJOFS_Y:
   607                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   608                                             (Sint16) state.lY);
   609                 break;
   610             case DIJOFS_Z:
   611                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   612                                             (Sint16) state.lZ);
   613                 break;
   614             case DIJOFS_RX:
   615                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   616                                             (Sint16) state.lRx);
   617                 break;
   618             case DIJOFS_RY:
   619                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   620                                             (Sint16) state.lRy);
   621                 break;
   622             case DIJOFS_RZ:
   623                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   624                                             (Sint16) state.lRz);
   625                 break;
   626             case DIJOFS_SLIDER(0):
   627                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   628                                             (Sint16) state.rglSlider[0]);
   629                 break;
   630             case DIJOFS_SLIDER(1):
   631                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   632                                             (Sint16) state.rglSlider[1]);
   633                 break;
   634             }
   635 
   636             break;
   637 
   638         case BUTTON:
   639             SDL_PrivateJoystickButton_Int(joystick, in->num,
   640                                           (Uint8) (state.
   641                                                    rgbButtons[in->ofs -
   642                                                               DIJOFS_BUTTON0]
   643                                                    ? SDL_PRESSED :
   644                                                    SDL_RELEASED));
   645             break;
   646         case HAT:
   647             {
   648                 Uint8 pos = TranslatePOV(state.rgdwPOV[in->ofs -
   649                                                        DIJOFS_POV(0)]);
   650                 SDL_PrivateJoystickHat_Int(joystick, in->num, pos);
   651                 break;
   652             }
   653         }
   654     }
   655 }
   656 
   657 void
   658 SDL_SYS_JoystickUpdate_Buffered(SDL_Joystick * joystick)
   659 {
   660     int i;
   661     HRESULT result;
   662     DWORD numevents;
   663     DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
   664 
   665     numevents = INPUT_QSIZE;
   666     result =
   667         IDirectInputDevice2_GetDeviceData(joystick->hwdata->InputDevice,
   668                                           sizeof(DIDEVICEOBJECTDATA), evtbuf,
   669                                           &numevents, 0);
   670     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
   671         IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
   672         result =
   673             IDirectInputDevice2_GetDeviceData(joystick->hwdata->InputDevice,
   674                                               sizeof(DIDEVICEOBJECTDATA),
   675                                               evtbuf, &numevents, 0);
   676     }
   677 
   678     /* Handle the events or punt */
   679     if (FAILED(result))
   680         return;
   681 
   682     for (i = 0; i < (int) numevents; ++i) {
   683         int j;
   684 
   685         for (j = 0; j < joystick->hwdata->NumInputs; ++j) {
   686             const input_t *in = &joystick->hwdata->Inputs[j];
   687 
   688             if (evtbuf[i].dwOfs != in->ofs)
   689                 continue;
   690 
   691             switch (in->type) {
   692             case AXIS:
   693                 SDL_PrivateJoystickAxis(joystick, in->num,
   694                                         (Sint16) evtbuf[i].dwData);
   695                 break;
   696             case BUTTON:
   697                 SDL_PrivateJoystickButton(joystick, in->num,
   698                                           (Uint8) (evtbuf[i].
   699                                                    dwData ? SDL_PRESSED :
   700                                                    SDL_RELEASED));
   701                 break;
   702             case HAT:
   703                 {
   704                     Uint8 pos = TranslatePOV(evtbuf[i].dwData);
   705                     SDL_PrivateJoystickHat(joystick, in->num, pos);
   706                 }
   707             }
   708         }
   709     }
   710 }
   711 
   712 
   713 static Uint8
   714 TranslatePOV(DWORD value)
   715 {
   716     const int HAT_VALS[] = {
   717         SDL_HAT_UP,
   718         SDL_HAT_UP | SDL_HAT_RIGHT,
   719         SDL_HAT_RIGHT,
   720         SDL_HAT_DOWN | SDL_HAT_RIGHT,
   721         SDL_HAT_DOWN,
   722         SDL_HAT_DOWN | SDL_HAT_LEFT,
   723         SDL_HAT_LEFT,
   724         SDL_HAT_UP | SDL_HAT_LEFT
   725     };
   726 
   727     if (LOWORD(value) == 0xFFFF)
   728         return SDL_HAT_CENTERED;
   729 
   730     /* Round the value up: */
   731     value += 4500 / 2;
   732     value %= 36000;
   733     value /= 4500;
   734 
   735     if (value >= 8)
   736         return SDL_HAT_CENTERED;        /* shouldn't happen */
   737 
   738     return HAT_VALS[value];
   739 }
   740 
   741 /* SDL_PrivateJoystick* doesn't discard duplicate events, so we need to
   742  * do it. */
   743 static int
   744 SDL_PrivateJoystickAxis_Int(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
   745 {
   746     if (joystick->axes[axis] != value)
   747         return SDL_PrivateJoystickAxis(joystick, axis, value);
   748     return 0;
   749 }
   750 
   751 static int
   752 SDL_PrivateJoystickHat_Int(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
   753 {
   754     if (joystick->hats[hat] != value)
   755         return SDL_PrivateJoystickHat(joystick, hat, value);
   756     return 0;
   757 }
   758 
   759 static int
   760 SDL_PrivateJoystickButton_Int(SDL_Joystick * joystick, Uint8 button,
   761                               Uint8 state)
   762 {
   763     if (joystick->buttons[button] != state)
   764         return SDL_PrivateJoystickButton(joystick, button, state);
   765     return 0;
   766 }
   767 
   768 void
   769 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
   770 {
   771     HRESULT result;
   772 
   773     result = IDirectInputDevice2_Poll(joystick->hwdata->InputDevice);
   774     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
   775         IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
   776         IDirectInputDevice2_Poll(joystick->hwdata->InputDevice);
   777     }
   778 
   779     if (joystick->hwdata->buffered)
   780         SDL_SYS_JoystickUpdate_Buffered(joystick);
   781     else
   782         SDL_SYS_JoystickUpdate_Polled(joystick);
   783 }
   784 
   785 /* Function to close a joystick after use */
   786 void
   787 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
   788 {
   789     IDirectInputDevice2_Unacquire(joystick->hwdata->InputDevice);
   790     IDirectInputDevice2_Release(joystick->hwdata->InputDevice);
   791 
   792     if (joystick->hwdata != NULL) {
   793         /* free system specific hardware data */
   794         SDL_free(joystick->hwdata);
   795     }
   796 }
   797 
   798 /* Function to perform any system-specific joystick related cleanup */
   799 void
   800 SDL_SYS_JoystickQuit(void)
   801 {
   802     int i;
   803 
   804     for (i = 0; i < SDL_arraysize(SYS_JoystickNames); ++i) {
   805         if (SYS_JoystickNames[i]) {
   806             SDL_free(SYS_JoystickNames[i]);
   807             SYS_JoystickNames[i] = NULL;
   808         }
   809     }
   810 
   811     if (dinput != NULL) {
   812         IDirectInput_Release(dinput);
   813         dinput = NULL;
   814     }
   815 
   816     if (coinitialized) {
   817         WIN_CoUninitialize();
   818         coinitialized = SDL_FALSE;
   819     }
   820 }
   821 
   822 #endif /* SDL_JOYSTICK_DINPUT */
   823 
   824 /* vi: set ts=4 sw=4 expandtab: */