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