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