src/joystick/windows/SDL_dxjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 11 Feb 2011 22:37:15 -0800
changeset 5262 b530ef003506
parent 5090 327f181542f1
child 5535 96594ac5fd1a
permissions -rw-r--r--
Happy 2011! :)
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2011 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 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 = CoInitialize(NULL);
   289     if (FAILED(result)) {
   290         SetDIerror("CoInitialize", result);
   291         return (-1);
   292     }
   293 
   294     result = CoCreateInstance(&CLSID_DirectInput, NULL, CLSCTX_INPROC_SERVER,
   295                               &IID_IDirectInput, (LPVOID)&dinput);
   296 
   297     if (FAILED(result)) {
   298         SetDIerror("CoCreateInstance", result);
   299         return (-1);
   300     }
   301 
   302     /* Because we used CoCreateInstance, we need to Initialize it, first. */
   303     instance = GetModuleHandle(NULL);
   304     if (instance == NULL) {
   305         SDL_SetError("GetModuleHandle() failed with error code %d.",
   306                      GetLastError());
   307         return (-1);
   308     }
   309     result = IDirectInput_Initialize(dinput, instance, DIRECTINPUT_VERSION);
   310 
   311     if (FAILED(result)) {
   312         SetDIerror("IDirectInput::Initialize", result);
   313         return (-1);
   314     }
   315 
   316     /* Look for joysticks, wheels, head trackers, gamepads, etc.. */
   317     result = IDirectInput_EnumDevices(dinput,
   318                                       DIDEVTYPE_JOYSTICK,
   319                                       EnumJoysticksCallback,
   320                                       NULL, DIEDFL_ATTACHEDONLY);
   321 
   322     return SYS_NumJoysticks;
   323 }
   324 
   325 static BOOL CALLBACK
   326 EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
   327 {
   328     SDL_memcpy(&SYS_Joystick[SYS_NumJoysticks], pdidInstance,
   329                sizeof(DIDEVICEINSTANCE));
   330     SYS_JoystickNames[SYS_NumJoysticks] = WIN_StringToUTF8(pdidInstance->tszProductName);
   331     SYS_NumJoysticks++;
   332 
   333     if (SYS_NumJoysticks >= MAX_JOYSTICKS)
   334         return DIENUM_STOP;
   335 
   336     return DIENUM_CONTINUE;
   337 }
   338 
   339 /* Function to get the device-dependent name of a joystick */
   340 const char *
   341 SDL_SYS_JoystickName(int index)
   342 {
   343     return SYS_JoystickNames[index];
   344 }
   345 
   346 /* Function to open a joystick for use.
   347    The joystick to open is specified by the index field of the joystick.
   348    This should fill the nbuttons and naxes fields of the joystick structure.
   349    It returns 0, or -1 if there is an error.
   350  */
   351 int
   352 SDL_SYS_JoystickOpen(SDL_Joystick * joystick)
   353 {
   354     HRESULT result;
   355     LPDIRECTINPUTDEVICE device;
   356     DIPROPDWORD dipdw;
   357 
   358     SDL_memset(&dipdw, 0, sizeof(DIPROPDWORD));
   359     dipdw.diph.dwSize = sizeof(DIPROPDWORD);
   360     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
   361 
   362 
   363     /* allocate memory for system specific hardware data */
   364     joystick->hwdata =
   365         (struct joystick_hwdata *) SDL_malloc(sizeof(struct joystick_hwdata));
   366     if (joystick->hwdata == NULL) {
   367         SDL_OutOfMemory();
   368         return (-1);
   369     }
   370     SDL_memset(joystick->hwdata, 0, sizeof(struct joystick_hwdata));
   371     joystick->hwdata->buffered = 1;
   372     joystick->hwdata->Capabilities.dwSize = sizeof(DIDEVCAPS);
   373 
   374     result =
   375         IDirectInput_CreateDevice(dinput,
   376                                   &SYS_Joystick[joystick->index].
   377                                   guidInstance, &device, NULL);
   378     if (FAILED(result)) {
   379         SetDIerror("IDirectInput::CreateDevice", result);
   380         return (-1);
   381     }
   382 
   383     /* Now get the IDirectInputDevice2 interface, instead. */
   384     result = IDirectInputDevice_QueryInterface(device,
   385                                                &IID_IDirectInputDevice2,
   386                                                (LPVOID *) & joystick->
   387                                                hwdata->InputDevice);
   388     /* We are done with this object.  Use the stored one from now on. */
   389     IDirectInputDevice_Release(device);
   390 
   391     if (FAILED(result)) {
   392         SetDIerror("IDirectInputDevice::QueryInterface", result);
   393         return (-1);
   394     }
   395 
   396     /* Aquire shared access. Exclusive access is required for forces,
   397      * though. */
   398     result =
   399         IDirectInputDevice2_SetCooperativeLevel(joystick->hwdata->
   400                                                 InputDevice, SDL_HelperWindow,
   401                                                 DISCL_EXCLUSIVE |
   402                                                 DISCL_BACKGROUND);
   403     if (FAILED(result)) {
   404         SetDIerror("IDirectInputDevice2::SetCooperativeLevel", result);
   405         return (-1);
   406     }
   407 
   408     /* Use the extended data structure: DIJOYSTATE2. */
   409     result =
   410         IDirectInputDevice2_SetDataFormat(joystick->hwdata->InputDevice,
   411                                           &c_dfDIJoystick2);
   412     if (FAILED(result)) {
   413         SetDIerror("IDirectInputDevice2::SetDataFormat", result);
   414         return (-1);
   415     }
   416 
   417     /* Get device capabilities */
   418     result =
   419         IDirectInputDevice2_GetCapabilities(joystick->hwdata->InputDevice,
   420                                             &joystick->hwdata->Capabilities);
   421 
   422     if (FAILED(result)) {
   423         SetDIerror("IDirectInputDevice2::GetCapabilities", result);
   424         return (-1);
   425     }
   426 
   427     /* Force capable? */
   428     if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
   429 
   430         result = IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
   431 
   432         if (FAILED(result)) {
   433             SetDIerror("IDirectInputDevice2::Acquire", result);
   434             return (-1);
   435         }
   436 
   437         /* reset all accuators. */
   438         result =
   439             IDirectInputDevice2_SendForceFeedbackCommand(joystick->hwdata->
   440                                                          InputDevice,
   441                                                          DISFFC_RESET);
   442 
   443         /* Not necessarily supported, ignore if not supported.
   444         if (FAILED(result)) {
   445             SetDIerror("IDirectInputDevice2::SendForceFeedbackCommand",
   446                        result);
   447             return (-1);
   448         }
   449         */
   450 
   451         result = IDirectInputDevice2_Unacquire(joystick->hwdata->InputDevice);
   452 
   453         if (FAILED(result)) {
   454             SetDIerror("IDirectInputDevice2::Unacquire", result);
   455             return (-1);
   456         }
   457 
   458         /* Turn on auto-centering for a ForceFeedback device (until told
   459          * otherwise). */
   460         dipdw.diph.dwObj = 0;
   461         dipdw.diph.dwHow = DIPH_DEVICE;
   462         dipdw.dwData = DIPROPAUTOCENTER_ON;
   463 
   464         result =
   465             IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
   466                                             DIPROP_AUTOCENTER, &dipdw.diph);
   467 
   468         /* Not necessarily supported, ignore if not supported.
   469         if (FAILED(result)) {
   470             SetDIerror("IDirectInputDevice2::SetProperty", result);
   471             return (-1);
   472         }
   473         */
   474     }
   475 
   476     /* What buttons and axes does it have? */
   477     IDirectInputDevice2_EnumObjects(joystick->hwdata->InputDevice,
   478                                     EnumDevObjectsCallback, joystick,
   479                                     DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV);
   480 
   481     dipdw.diph.dwObj = 0;
   482     dipdw.diph.dwHow = DIPH_DEVICE;
   483     dipdw.dwData = INPUT_QSIZE;
   484 
   485     /* Set the buffer size */
   486     result =
   487         IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
   488                                         DIPROP_BUFFERSIZE, &dipdw.diph);
   489 
   490     if (result == DI_POLLEDDEVICE) {
   491         /* This device doesn't support buffering, so we're forced
   492          * to use less reliable polling. */
   493         joystick->hwdata->buffered = 0;
   494     } else if (FAILED(result)) {
   495         SetDIerror("IDirectInputDevice2::SetProperty", result);
   496         return (-1);
   497     }
   498 
   499     return (0);
   500 }
   501 
   502 static BOOL CALLBACK
   503 EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
   504 {
   505     SDL_Joystick *joystick = (SDL_Joystick *) pvRef;
   506     HRESULT result;
   507     input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs];
   508 
   509     in->ofs = dev->dwOfs;
   510 
   511     if (dev->dwType & DIDFT_BUTTON) {
   512         in->type = BUTTON;
   513         in->num = joystick->nbuttons;
   514         joystick->nbuttons++;
   515     } else if (dev->dwType & DIDFT_POV) {
   516         in->type = HAT;
   517         in->num = joystick->nhats;
   518         joystick->nhats++;
   519     } else if (dev->dwType & DIDFT_AXIS) {
   520         DIPROPRANGE diprg;
   521         DIPROPDWORD dilong;
   522 
   523         in->type = AXIS;
   524         in->num = joystick->naxes;
   525 
   526         diprg.diph.dwSize = sizeof(diprg);
   527         diprg.diph.dwHeaderSize = sizeof(diprg.diph);
   528         diprg.diph.dwObj = dev->dwOfs;
   529         diprg.diph.dwHow = DIPH_BYOFFSET;
   530         diprg.lMin = AXIS_MIN;
   531         diprg.lMax = AXIS_MAX;
   532 
   533         result =
   534             IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
   535                                             DIPROP_RANGE, &diprg.diph);
   536         if (FAILED(result)) {
   537             return DIENUM_CONTINUE;     /* don't use this axis */
   538         }
   539 
   540         /* Set dead zone to 0. */
   541         dilong.diph.dwSize = sizeof(dilong);
   542         dilong.diph.dwHeaderSize = sizeof(dilong.diph);
   543         dilong.diph.dwObj = dev->dwOfs;
   544         dilong.diph.dwHow = DIPH_BYOFFSET;
   545         dilong.dwData = 0;
   546         result =
   547             IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
   548                                             DIPROP_DEADZONE, &dilong.diph);
   549         if (FAILED(result)) {
   550             return DIENUM_CONTINUE;     /* don't use this axis */
   551         }
   552 
   553         joystick->naxes++;
   554     } else {
   555         /* not supported at this time */
   556         return DIENUM_CONTINUE;
   557     }
   558 
   559     joystick->hwdata->NumInputs++;
   560 
   561     if (joystick->hwdata->NumInputs == MAX_INPUTS) {
   562         return DIENUM_STOP;     /* too many */
   563     }
   564 
   565     return DIENUM_CONTINUE;
   566 }
   567 
   568 /* Function to update the state of a joystick - called as a device poll.
   569  * This function shouldn't update the joystick structure directly,
   570  * but instead should call SDL_PrivateJoystick*() to deliver events
   571  * and update joystick device state.
   572  */
   573 void
   574 SDL_SYS_JoystickUpdate_Polled(SDL_Joystick * joystick)
   575 {
   576     DIJOYSTATE2 state;
   577     HRESULT result;
   578     int i;
   579 
   580     result =
   581         IDirectInputDevice2_GetDeviceState(joystick->hwdata->InputDevice,
   582                                            sizeof(DIJOYSTATE2), &state);
   583     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
   584         IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
   585         result =
   586             IDirectInputDevice2_GetDeviceState(joystick->hwdata->InputDevice,
   587                                                sizeof(DIJOYSTATE2), &state);
   588     }
   589 
   590     /* Set each known axis, button and POV. */
   591     for (i = 0; i < joystick->hwdata->NumInputs; ++i) {
   592         const input_t *in = &joystick->hwdata->Inputs[i];
   593 
   594         switch (in->type) {
   595         case AXIS:
   596             switch (in->ofs) {
   597             case DIJOFS_X:
   598                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   599                                             (Sint16) state.lX);
   600                 break;
   601             case DIJOFS_Y:
   602                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   603                                             (Sint16) state.lY);
   604                 break;
   605             case DIJOFS_Z:
   606                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   607                                             (Sint16) state.lZ);
   608                 break;
   609             case DIJOFS_RX:
   610                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   611                                             (Sint16) state.lRx);
   612                 break;
   613             case DIJOFS_RY:
   614                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   615                                             (Sint16) state.lRy);
   616                 break;
   617             case DIJOFS_RZ:
   618                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   619                                             (Sint16) state.lRz);
   620                 break;
   621             case DIJOFS_SLIDER(0):
   622                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   623                                             (Sint16) state.rglSlider[0]);
   624                 break;
   625             case DIJOFS_SLIDER(1):
   626                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   627                                             (Sint16) state.rglSlider[1]);
   628                 break;
   629             }
   630 
   631             break;
   632 
   633         case BUTTON:
   634             SDL_PrivateJoystickButton_Int(joystick, in->num,
   635                                           (Uint8) (state.
   636                                                    rgbButtons[in->ofs -
   637                                                               DIJOFS_BUTTON0]
   638                                                    ? SDL_PRESSED :
   639                                                    SDL_RELEASED));
   640             break;
   641         case HAT:
   642             {
   643                 Uint8 pos = TranslatePOV(state.rgdwPOV[in->ofs -
   644                                                        DIJOFS_POV(0)]);
   645                 SDL_PrivateJoystickHat_Int(joystick, in->num, pos);
   646                 break;
   647             }
   648         }
   649     }
   650 }
   651 
   652 void
   653 SDL_SYS_JoystickUpdate_Buffered(SDL_Joystick * joystick)
   654 {
   655     int i;
   656     HRESULT result;
   657     DWORD numevents;
   658     DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
   659 
   660     numevents = INPUT_QSIZE;
   661     result =
   662         IDirectInputDevice2_GetDeviceData(joystick->hwdata->InputDevice,
   663                                           sizeof(DIDEVICEOBJECTDATA), evtbuf,
   664                                           &numevents, 0);
   665     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
   666         IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
   667         result =
   668             IDirectInputDevice2_GetDeviceData(joystick->hwdata->InputDevice,
   669                                               sizeof(DIDEVICEOBJECTDATA),
   670                                               evtbuf, &numevents, 0);
   671     }
   672 
   673     /* Handle the events or punt */
   674     if (FAILED(result))
   675         return;
   676 
   677     for (i = 0; i < (int) numevents; ++i) {
   678         int j;
   679 
   680         for (j = 0; j < joystick->hwdata->NumInputs; ++j) {
   681             const input_t *in = &joystick->hwdata->Inputs[j];
   682 
   683             if (evtbuf[i].dwOfs != in->ofs)
   684                 continue;
   685 
   686             switch (in->type) {
   687             case AXIS:
   688                 SDL_PrivateJoystickAxis(joystick, in->num,
   689                                         (Sint16) evtbuf[i].dwData);
   690                 break;
   691             case BUTTON:
   692                 SDL_PrivateJoystickButton(joystick, in->num,
   693                                           (Uint8) (evtbuf[i].
   694                                                    dwData ? SDL_PRESSED :
   695                                                    SDL_RELEASED));
   696                 break;
   697             case HAT:
   698                 {
   699                     Uint8 pos = TranslatePOV(evtbuf[i].dwData);
   700                     SDL_PrivateJoystickHat(joystick, in->num, pos);
   701                 }
   702             }
   703         }
   704     }
   705 }
   706 
   707 
   708 static Uint8
   709 TranslatePOV(DWORD value)
   710 {
   711     const int HAT_VALS[] = {
   712         SDL_HAT_UP,
   713         SDL_HAT_UP | SDL_HAT_RIGHT,
   714         SDL_HAT_RIGHT,
   715         SDL_HAT_DOWN | SDL_HAT_RIGHT,
   716         SDL_HAT_DOWN,
   717         SDL_HAT_DOWN | SDL_HAT_LEFT,
   718         SDL_HAT_LEFT,
   719         SDL_HAT_UP | SDL_HAT_LEFT
   720     };
   721 
   722     if (LOWORD(value) == 0xFFFF)
   723         return SDL_HAT_CENTERED;
   724 
   725     /* Round the value up: */
   726     value += 4500 / 2;
   727     value %= 36000;
   728     value /= 4500;
   729 
   730     if (value >= 8)
   731         return SDL_HAT_CENTERED;        /* shouldn't happen */
   732 
   733     return HAT_VALS[value];
   734 }
   735 
   736 /* SDL_PrivateJoystick* doesn't discard duplicate events, so we need to
   737  * do it. */
   738 static int
   739 SDL_PrivateJoystickAxis_Int(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
   740 {
   741     if (joystick->axes[axis] != value)
   742         return SDL_PrivateJoystickAxis(joystick, axis, value);
   743     return 0;
   744 }
   745 
   746 static int
   747 SDL_PrivateJoystickHat_Int(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
   748 {
   749     if (joystick->hats[hat] != value)
   750         return SDL_PrivateJoystickHat(joystick, hat, value);
   751     return 0;
   752 }
   753 
   754 static int
   755 SDL_PrivateJoystickButton_Int(SDL_Joystick * joystick, Uint8 button,
   756                               Uint8 state)
   757 {
   758     if (joystick->buttons[button] != state)
   759         return SDL_PrivateJoystickButton(joystick, button, state);
   760     return 0;
   761 }
   762 
   763 void
   764 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
   765 {
   766     HRESULT result;
   767 
   768     result = IDirectInputDevice2_Poll(joystick->hwdata->InputDevice);
   769     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
   770         IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
   771         IDirectInputDevice2_Poll(joystick->hwdata->InputDevice);
   772     }
   773 
   774     if (joystick->hwdata->buffered)
   775         SDL_SYS_JoystickUpdate_Buffered(joystick);
   776     else
   777         SDL_SYS_JoystickUpdate_Polled(joystick);
   778 }
   779 
   780 /* Function to close a joystick after use */
   781 void
   782 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
   783 {
   784     IDirectInputDevice2_Unacquire(joystick->hwdata->InputDevice);
   785     IDirectInputDevice2_Release(joystick->hwdata->InputDevice);
   786 
   787     if (joystick->hwdata != NULL) {
   788         /* free system specific hardware data */
   789         SDL_free(joystick->hwdata);
   790     }
   791 }
   792 
   793 /* Function to perform any system-specific joystick related cleanup */
   794 void
   795 SDL_SYS_JoystickQuit(void)
   796 {
   797     int i;
   798 
   799     for (i = 0; i < SDL_arraysize(SYS_JoystickNames); ++i) {
   800         if (SYS_JoystickNames[i]) {
   801             SDL_free(SYS_JoystickNames[i]);
   802             SYS_JoystickNames[i] = NULL;
   803         }
   804     }
   805 
   806     IDirectInput_Release(dinput);
   807     dinput = NULL;
   808 }
   809 
   810 #endif /* SDL_JOYSTICK_DINPUT */
   811 
   812 /* vi: set ts=4 sw=4 expandtab: */