src/joystick/windows/SDL_dinputjoystick.c
author Ryan C. Gordon
Tue, 24 Jan 2017 16:18:25 -0500
changeset 10850 c9dc0068b0e7
parent 10821 b0b8395f5cf9
child 11201 813a8510bd0c
permissions -rw-r--r--
configure: report libsamplerate support status.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #include "../SDL_sysjoystick.h"
    24 
    25 #if SDL_JOYSTICK_DINPUT
    26 
    27 #include "SDL_windowsjoystick_c.h"
    28 #include "SDL_dinputjoystick_c.h"
    29 #include "SDL_xinputjoystick_c.h"
    30 
    31 #ifndef DIDFT_OPTIONAL
    32 #define DIDFT_OPTIONAL      0x80000000
    33 #endif
    34 
    35 #define INPUT_QSIZE 32      /* Buffer up to 32 input messages */
    36 #define JOY_AXIS_THRESHOLD  (((SDL_JOYSTICK_AXIS_MAX)-(SDL_JOYSTICK_AXIS_MIN))/100)   /* 1% motion */
    37 
    38 /* external variables referenced. */
    39 extern HWND SDL_HelperWindow;
    40 
    41 /* local variables */
    42 static SDL_bool coinitialized = SDL_FALSE;
    43 static LPDIRECTINPUT8 dinput = NULL;
    44 static PRAWINPUTDEVICELIST SDL_RawDevList = NULL;
    45 static UINT SDL_RawDevListCount = 0;
    46 
    47 /* Taken from Wine - Thanks! */
    48 static DIOBJECTDATAFORMAT dfDIJoystick2[] = {
    49         { &GUID_XAxis, DIJOFS_X, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    50         { &GUID_YAxis, DIJOFS_Y, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    51         { &GUID_ZAxis, DIJOFS_Z, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    52         { &GUID_RxAxis, DIJOFS_RX, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    53         { &GUID_RyAxis, DIJOFS_RY, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    54         { &GUID_RzAxis, DIJOFS_RZ, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    55         { &GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    56         { &GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    57         { &GUID_POV, DIJOFS_POV(0), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
    58         { &GUID_POV, DIJOFS_POV(1), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
    59         { &GUID_POV, DIJOFS_POV(2), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
    60         { &GUID_POV, DIJOFS_POV(3), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
    61         { NULL, DIJOFS_BUTTON(0), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    62         { NULL, DIJOFS_BUTTON(1), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    63         { NULL, DIJOFS_BUTTON(2), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    64         { NULL, DIJOFS_BUTTON(3), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    65         { NULL, DIJOFS_BUTTON(4), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    66         { NULL, DIJOFS_BUTTON(5), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    67         { NULL, DIJOFS_BUTTON(6), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    68         { NULL, DIJOFS_BUTTON(7), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    69         { NULL, DIJOFS_BUTTON(8), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    70         { NULL, DIJOFS_BUTTON(9), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    71         { NULL, DIJOFS_BUTTON(10), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    72         { NULL, DIJOFS_BUTTON(11), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    73         { NULL, DIJOFS_BUTTON(12), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    74         { NULL, DIJOFS_BUTTON(13), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    75         { NULL, DIJOFS_BUTTON(14), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    76         { NULL, DIJOFS_BUTTON(15), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    77         { NULL, DIJOFS_BUTTON(16), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    78         { NULL, DIJOFS_BUTTON(17), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    79         { NULL, DIJOFS_BUTTON(18), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    80         { NULL, DIJOFS_BUTTON(19), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    81         { NULL, DIJOFS_BUTTON(20), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    82         { NULL, DIJOFS_BUTTON(21), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    83         { NULL, DIJOFS_BUTTON(22), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    84         { NULL, DIJOFS_BUTTON(23), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    85         { NULL, DIJOFS_BUTTON(24), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    86         { NULL, DIJOFS_BUTTON(25), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    87         { NULL, DIJOFS_BUTTON(26), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    88         { NULL, DIJOFS_BUTTON(27), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    89         { NULL, DIJOFS_BUTTON(28), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    90         { NULL, DIJOFS_BUTTON(29), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    91         { NULL, DIJOFS_BUTTON(30), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    92         { NULL, DIJOFS_BUTTON(31), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    93         { NULL, DIJOFS_BUTTON(32), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    94         { NULL, DIJOFS_BUTTON(33), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    95         { NULL, DIJOFS_BUTTON(34), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    96         { NULL, DIJOFS_BUTTON(35), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    97         { NULL, DIJOFS_BUTTON(36), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    98         { NULL, DIJOFS_BUTTON(37), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    99         { NULL, DIJOFS_BUTTON(38), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   100         { NULL, DIJOFS_BUTTON(39), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   101         { NULL, DIJOFS_BUTTON(40), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   102         { NULL, DIJOFS_BUTTON(41), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   103         { NULL, DIJOFS_BUTTON(42), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   104         { NULL, DIJOFS_BUTTON(43), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   105         { NULL, DIJOFS_BUTTON(44), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   106         { NULL, DIJOFS_BUTTON(45), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   107         { NULL, DIJOFS_BUTTON(46), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   108         { NULL, DIJOFS_BUTTON(47), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   109         { NULL, DIJOFS_BUTTON(48), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   110         { NULL, DIJOFS_BUTTON(49), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   111         { NULL, DIJOFS_BUTTON(50), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   112         { NULL, DIJOFS_BUTTON(51), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   113         { NULL, DIJOFS_BUTTON(52), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   114         { NULL, DIJOFS_BUTTON(53), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   115         { NULL, DIJOFS_BUTTON(54), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   116         { NULL, DIJOFS_BUTTON(55), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   117         { NULL, DIJOFS_BUTTON(56), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   118         { NULL, DIJOFS_BUTTON(57), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   119         { NULL, DIJOFS_BUTTON(58), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   120         { NULL, DIJOFS_BUTTON(59), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   121         { NULL, DIJOFS_BUTTON(60), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   122         { NULL, DIJOFS_BUTTON(61), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   123         { NULL, DIJOFS_BUTTON(62), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   124         { NULL, DIJOFS_BUTTON(63), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   125         { NULL, DIJOFS_BUTTON(64), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   126         { NULL, DIJOFS_BUTTON(65), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   127         { NULL, DIJOFS_BUTTON(66), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   128         { NULL, DIJOFS_BUTTON(67), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   129         { NULL, DIJOFS_BUTTON(68), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   130         { NULL, DIJOFS_BUTTON(69), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   131         { NULL, DIJOFS_BUTTON(70), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   132         { NULL, DIJOFS_BUTTON(71), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   133         { NULL, DIJOFS_BUTTON(72), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   134         { NULL, DIJOFS_BUTTON(73), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   135         { NULL, DIJOFS_BUTTON(74), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   136         { NULL, DIJOFS_BUTTON(75), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   137         { NULL, DIJOFS_BUTTON(76), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   138         { NULL, DIJOFS_BUTTON(77), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   139         { NULL, DIJOFS_BUTTON(78), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   140         { NULL, DIJOFS_BUTTON(79), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   141         { NULL, DIJOFS_BUTTON(80), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   142         { NULL, DIJOFS_BUTTON(81), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   143         { NULL, DIJOFS_BUTTON(82), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   144         { NULL, DIJOFS_BUTTON(83), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   145         { NULL, DIJOFS_BUTTON(84), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   146         { NULL, DIJOFS_BUTTON(85), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   147         { NULL, DIJOFS_BUTTON(86), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   148         { NULL, DIJOFS_BUTTON(87), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   149         { NULL, DIJOFS_BUTTON(88), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   150         { NULL, DIJOFS_BUTTON(89), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   151         { NULL, DIJOFS_BUTTON(90), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   152         { NULL, DIJOFS_BUTTON(91), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   153         { NULL, DIJOFS_BUTTON(92), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   154         { NULL, DIJOFS_BUTTON(93), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   155         { NULL, DIJOFS_BUTTON(94), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   156         { NULL, DIJOFS_BUTTON(95), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   157         { NULL, DIJOFS_BUTTON(96), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   158         { NULL, DIJOFS_BUTTON(97), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   159         { NULL, DIJOFS_BUTTON(98), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   160         { NULL, DIJOFS_BUTTON(99), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   161         { NULL, DIJOFS_BUTTON(100), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   162         { NULL, DIJOFS_BUTTON(101), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   163         { NULL, DIJOFS_BUTTON(102), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   164         { NULL, DIJOFS_BUTTON(103), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   165         { NULL, DIJOFS_BUTTON(104), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   166         { NULL, DIJOFS_BUTTON(105), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   167         { NULL, DIJOFS_BUTTON(106), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   168         { NULL, DIJOFS_BUTTON(107), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   169         { NULL, DIJOFS_BUTTON(108), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   170         { NULL, DIJOFS_BUTTON(109), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   171         { NULL, DIJOFS_BUTTON(110), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   172         { NULL, DIJOFS_BUTTON(111), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   173         { NULL, DIJOFS_BUTTON(112), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   174         { NULL, DIJOFS_BUTTON(113), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   175         { NULL, DIJOFS_BUTTON(114), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   176         { NULL, DIJOFS_BUTTON(115), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   177         { NULL, DIJOFS_BUTTON(116), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   178         { NULL, DIJOFS_BUTTON(117), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   179         { NULL, DIJOFS_BUTTON(118), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   180         { NULL, DIJOFS_BUTTON(119), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   181         { NULL, DIJOFS_BUTTON(120), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   182         { NULL, DIJOFS_BUTTON(121), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   183         { NULL, DIJOFS_BUTTON(122), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   184         { NULL, DIJOFS_BUTTON(123), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   185         { NULL, DIJOFS_BUTTON(124), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   186         { NULL, DIJOFS_BUTTON(125), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   187         { NULL, DIJOFS_BUTTON(126), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   188         { NULL, DIJOFS_BUTTON(127), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
   189         { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lVX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   190         { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lVY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   191         { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lVZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   192         { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lVRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   193         { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lVRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   194         { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lVRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   195         { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglVSlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   196         { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglVSlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   197         { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lAX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   198         { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lAY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   199         { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lAZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   200         { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lARx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   201         { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lARy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   202         { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lARz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   203         { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglASlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   204         { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglASlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   205         { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lFX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   206         { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lFY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   207         { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lFZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   208         { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lFRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   209         { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lFRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   210         { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lFRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   211         { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglFSlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   212         { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglFSlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
   213 };
   214 
   215 const DIDATAFORMAT SDL_c_dfDIJoystick2 = {
   216     sizeof(DIDATAFORMAT),
   217     sizeof(DIOBJECTDATAFORMAT),
   218     DIDF_ABSAXIS,
   219     sizeof(DIJOYSTATE2),
   220     SDL_arraysize(dfDIJoystick2),
   221     dfDIJoystick2
   222 };
   223 
   224 /* Convert a DirectInput return code to a text message */
   225 static int
   226 SetDIerror(const char *function, HRESULT code)
   227 {
   228     /*
   229     return SDL_SetError("%s() [%s]: %s", function,
   230     DXGetErrorString9A(code), DXGetErrorDescription9A(code));
   231     */
   232     return SDL_SetError("%s() DirectX error 0x%8.8lx", function, code);
   233 }
   234 
   235 static SDL_bool
   236 SDL_IsXInputDevice(const GUID* pGuidProductFromDirectInput)
   237 {
   238     static GUID IID_ValveStreamingGamepad = { MAKELONG(0x28DE, 0x11FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
   239     static GUID IID_X360WiredGamepad = { MAKELONG(0x045E, 0x02A1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
   240     static GUID IID_X360WirelessGamepad = { MAKELONG(0x045E, 0x028E), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
   241     static GUID IID_XOneWiredGamepad = { MAKELONG(0x045E, 0x02FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
   242     static GUID IID_XOneWirelessGamepad = { MAKELONG(0x045E, 0x02DD), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
   243     static GUID IID_XOneNewWirelessGamepad = { MAKELONG(0x045E, 0x02D1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
   244     static GUID IID_XOneSWirelessGamepad = { MAKELONG(0x045E, 0x02EA), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
   245     static GUID IID_XOneSBluetoothGamepad = { MAKELONG(0x045E, 0x02E0), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
   246     static GUID IID_XOneEliteWirelessGamepad = { MAKELONG(0x045E, 0x02E3), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
   247 
   248     static const GUID *s_XInputProductGUID[] = {
   249         &IID_ValveStreamingGamepad,
   250         &IID_X360WiredGamepad,         /* Microsoft's wired X360 controller for Windows. */
   251         &IID_X360WirelessGamepad,      /* Microsoft's wireless X360 controller for Windows. */
   252         &IID_XOneWiredGamepad,         /* Microsoft's wired Xbox One controller for Windows. */
   253         &IID_XOneWirelessGamepad,      /* Microsoft's wireless Xbox One controller for Windows. */
   254         &IID_XOneNewWirelessGamepad,   /* Microsoft's updated wireless Xbox One controller (w/ 3.5 mm jack) for Windows. */
   255         &IID_XOneSWirelessGamepad,     /* Microsoft's wireless Xbox One S controller for Windows. */
   256         &IID_XOneSBluetoothGamepad,    /* Microsoft's Bluetooth Xbox One S controller for Windows. */
   257         &IID_XOneEliteWirelessGamepad  /* Microsoft's wireless Xbox One Elite controller for Windows. */
   258     };
   259 
   260     size_t iDevice;
   261     UINT i;
   262 
   263     if (!SDL_XINPUT_Enabled()) {
   264         return SDL_FALSE;
   265     }
   266 
   267     /* Check for well known XInput device GUIDs */
   268     /* This lets us skip RAWINPUT for popular devices. Also, we need to do this for the Valve Streaming Gamepad because it's virtualized and doesn't show up in the device list. */
   269     for (iDevice = 0; iDevice < SDL_arraysize(s_XInputProductGUID); ++iDevice) {
   270         if (SDL_memcmp(pGuidProductFromDirectInput, s_XInputProductGUID[iDevice], sizeof(GUID)) == 0) {
   271             return SDL_TRUE;
   272         }
   273     }
   274 
   275     /* Go through RAWINPUT (WinXP and later) to find HID devices. */
   276     /* Cache this if we end up using it. */
   277     if (SDL_RawDevList == NULL) {
   278         if ((GetRawInputDeviceList(NULL, &SDL_RawDevListCount, sizeof(RAWINPUTDEVICELIST)) == -1) || (!SDL_RawDevListCount)) {
   279             return SDL_FALSE;  /* oh well. */
   280         }
   281 
   282         SDL_RawDevList = (PRAWINPUTDEVICELIST)SDL_malloc(sizeof(RAWINPUTDEVICELIST) * SDL_RawDevListCount);
   283         if (SDL_RawDevList == NULL) {
   284             SDL_OutOfMemory();
   285             return SDL_FALSE;
   286         }
   287 
   288         if (GetRawInputDeviceList(SDL_RawDevList, &SDL_RawDevListCount, sizeof(RAWINPUTDEVICELIST)) == -1) {
   289             SDL_free(SDL_RawDevList);
   290             SDL_RawDevList = NULL;
   291             return SDL_FALSE;  /* oh well. */
   292         }
   293     }
   294 
   295     for (i = 0; i < SDL_RawDevListCount; i++) {
   296         RID_DEVICE_INFO rdi;
   297         char devName[128];
   298         UINT rdiSize = sizeof(rdi);
   299         UINT nameSize = SDL_arraysize(devName);
   300 
   301         rdi.cbSize = sizeof(rdi);
   302         if ((SDL_RawDevList[i].dwType == RIM_TYPEHID) &&
   303             (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != ((UINT)-1)) &&
   304             (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == ((LONG)pGuidProductFromDirectInput->Data1)) &&
   305             (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != ((UINT)-1)) &&
   306             (SDL_strstr(devName, "IG_") != NULL)) {
   307             return SDL_TRUE;
   308         }
   309     }
   310 
   311     return SDL_FALSE;
   312 }
   313 
   314 int
   315 SDL_DINPUT_JoystickInit(void)
   316 {
   317     HRESULT result;
   318     HINSTANCE instance;
   319 
   320     result = WIN_CoInitialize();
   321     if (FAILED(result)) {
   322         return SetDIerror("CoInitialize", result);
   323     }
   324 
   325     coinitialized = SDL_TRUE;
   326 
   327     result = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER,
   328         &IID_IDirectInput8, (LPVOID)&dinput);
   329 
   330     if (FAILED(result)) {
   331         return SetDIerror("CoCreateInstance", result);
   332     }
   333 
   334     /* Because we used CoCreateInstance, we need to Initialize it, first. */
   335     instance = GetModuleHandle(NULL);
   336     if (instance == NULL) {
   337         return SDL_SetError("GetModuleHandle() failed with error code %lu.", GetLastError());
   338     }
   339     result = IDirectInput8_Initialize(dinput, instance, DIRECTINPUT_VERSION);
   340 
   341     if (FAILED(result)) {
   342         return SetDIerror("IDirectInput::Initialize", result);
   343     }
   344     return 0;
   345 }
   346 
   347 /* helper function for direct input, gets called for each connected joystick */
   348 static BOOL CALLBACK
   349 EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
   350 {
   351     const Uint16 BUS_USB = 0x03;
   352     const Uint16 BUS_BLUETOOTH = 0x05;
   353     JoyStick_DeviceData *pNewJoystick;
   354     JoyStick_DeviceData *pPrevJoystick = NULL;
   355     const DWORD devtype = (pdidInstance->dwDevType & 0xFF);
   356     Uint16 *guid16;
   357 
   358     if (devtype == DI8DEVTYPE_SUPPLEMENTAL) {
   359         /* Add any supplemental devices that should be ignored here */
   360 #define MAKE_TABLE_ENTRY(VID, PID)	((((DWORD)PID)<<16)|VID)
   361 		static DWORD ignored_devices[] = {
   362 			MAKE_TABLE_ENTRY(0, 0)
   363 		};
   364 #undef MAKE_TABLE_ENTRY
   365 		unsigned int i;
   366 
   367 		for (i = 0; i < SDL_arraysize(ignored_devices); ++i) {
   368 			if (pdidInstance->guidProduct.Data1 == ignored_devices[i]) {
   369 				return DIENUM_CONTINUE;
   370 			}
   371 		}
   372     }
   373 
   374     if (SDL_IsXInputDevice(&pdidInstance->guidProduct)) {
   375         return DIENUM_CONTINUE;  /* ignore XInput devices here, keep going. */
   376     }
   377 
   378     pNewJoystick = *(JoyStick_DeviceData **)pContext;
   379     while (pNewJoystick) {
   380         if (!SDL_memcmp(&pNewJoystick->dxdevice.guidInstance, &pdidInstance->guidInstance, sizeof(pNewJoystick->dxdevice.guidInstance))) {
   381             /* if we are replacing the front of the list then update it */
   382             if (pNewJoystick == *(JoyStick_DeviceData **)pContext) {
   383                 *(JoyStick_DeviceData **)pContext = pNewJoystick->pNext;
   384             } else if (pPrevJoystick) {
   385                 pPrevJoystick->pNext = pNewJoystick->pNext;
   386             }
   387 
   388             pNewJoystick->pNext = SYS_Joystick;
   389             SYS_Joystick = pNewJoystick;
   390 
   391             return DIENUM_CONTINUE; /* already have this joystick loaded, just keep going */
   392         }
   393 
   394         pPrevJoystick = pNewJoystick;
   395         pNewJoystick = pNewJoystick->pNext;
   396     }
   397 
   398     pNewJoystick = (JoyStick_DeviceData *)SDL_malloc(sizeof(JoyStick_DeviceData));
   399     if (!pNewJoystick) {
   400         return DIENUM_CONTINUE; /* better luck next time? */
   401     }
   402 
   403     SDL_zerop(pNewJoystick);
   404     pNewJoystick->joystickname = WIN_StringToUTF8(pdidInstance->tszProductName);
   405     if (!pNewJoystick->joystickname) {
   406         SDL_free(pNewJoystick);
   407         return DIENUM_CONTINUE; /* better luck next time? */
   408     }
   409 
   410     SDL_memcpy(&(pNewJoystick->dxdevice), pdidInstance,
   411         sizeof(DIDEVICEINSTANCE));
   412 
   413     SDL_memset(pNewJoystick->guid.data, 0, sizeof(pNewJoystick->guid.data));
   414 
   415     guid16 = (Uint16 *)pNewJoystick->guid.data;
   416     if (SDL_memcmp(&pdidInstance->guidProduct.Data4[2], "PIDVID", 6) == 0) {
   417         *guid16++ = SDL_SwapLE16(BUS_USB);
   418         *guid16++ = 0;
   419         *guid16++ = SDL_SwapLE16((Uint16)LOWORD(pdidInstance->guidProduct.Data1)); /* vendor */
   420         *guid16++ = 0;
   421         *guid16++ = SDL_SwapLE16((Uint16)HIWORD(pdidInstance->guidProduct.Data1)); /* product */
   422         *guid16++ = 0;
   423         *guid16++ = 0; /* version */
   424         *guid16++ = 0;
   425     } else {
   426         *guid16++ = SDL_SwapLE16(BUS_BLUETOOTH);
   427         *guid16++ = 0;
   428         SDL_strlcpy((char*)guid16, pNewJoystick->joystickname, sizeof(pNewJoystick->guid.data) - 4);
   429     }
   430 
   431     SDL_SYS_AddJoystickDevice(pNewJoystick);
   432 
   433     return DIENUM_CONTINUE; /* get next device, please */
   434 }
   435 
   436 void
   437 SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext)
   438 {
   439     IDirectInput8_EnumDevices(dinput, DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, pContext, DIEDFL_ATTACHEDONLY);
   440 
   441     if (SDL_RawDevList) {
   442         SDL_free(SDL_RawDevList);  /* in case we used this in DirectInput detection */
   443         SDL_RawDevList = NULL;
   444     }
   445     SDL_RawDevListCount = 0;
   446 }
   447 
   448 static BOOL CALLBACK
   449 EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
   450 {
   451     SDL_Joystick *joystick = (SDL_Joystick *)pvRef;
   452     HRESULT result;
   453     input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs];
   454 
   455     if (dev->dwType & DIDFT_BUTTON) {
   456         in->type = BUTTON;
   457         in->num = joystick->nbuttons;
   458         in->ofs = DIJOFS_BUTTON(in->num);
   459         joystick->nbuttons++;
   460     } else if (dev->dwType & DIDFT_POV) {
   461         in->type = HAT;
   462         in->num = joystick->nhats;
   463         in->ofs = DIJOFS_POV(in->num);
   464         joystick->nhats++;
   465     } else if (dev->dwType & DIDFT_AXIS) {
   466         DIPROPRANGE diprg;
   467         DIPROPDWORD dilong;
   468 
   469         in->type = AXIS;
   470         in->num = joystick->naxes;
   471         if (!SDL_memcmp(&dev->guidType, &GUID_XAxis, sizeof(dev->guidType)))
   472             in->ofs = DIJOFS_X;
   473         else if (!SDL_memcmp(&dev->guidType, &GUID_YAxis, sizeof(dev->guidType)))
   474             in->ofs = DIJOFS_Y;
   475         else if (!SDL_memcmp(&dev->guidType, &GUID_ZAxis, sizeof(dev->guidType)))
   476             in->ofs = DIJOFS_Z;
   477         else if (!SDL_memcmp(&dev->guidType, &GUID_RxAxis, sizeof(dev->guidType)))
   478             in->ofs = DIJOFS_RX;
   479         else if (!SDL_memcmp(&dev->guidType, &GUID_RyAxis, sizeof(dev->guidType)))
   480             in->ofs = DIJOFS_RY;
   481         else if (!SDL_memcmp(&dev->guidType, &GUID_RzAxis, sizeof(dev->guidType)))
   482             in->ofs = DIJOFS_RZ;
   483         else if (!SDL_memcmp(&dev->guidType, &GUID_Slider, sizeof(dev->guidType))) {
   484             in->ofs = DIJOFS_SLIDER(joystick->hwdata->NumSliders);
   485             ++joystick->hwdata->NumSliders;
   486         } else {
   487             return DIENUM_CONTINUE; /* not an axis we can grok */
   488         }
   489 
   490         diprg.diph.dwSize = sizeof(diprg);
   491         diprg.diph.dwHeaderSize = sizeof(diprg.diph);
   492         diprg.diph.dwObj = dev->dwType;
   493         diprg.diph.dwHow = DIPH_BYID;
   494         diprg.lMin = SDL_JOYSTICK_AXIS_MIN;
   495         diprg.lMax = SDL_JOYSTICK_AXIS_MAX;
   496 
   497         result =
   498             IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
   499             DIPROP_RANGE, &diprg.diph);
   500         if (FAILED(result)) {
   501             return DIENUM_CONTINUE;     /* don't use this axis */
   502         }
   503 
   504         /* Set dead zone to 0. */
   505         dilong.diph.dwSize = sizeof(dilong);
   506         dilong.diph.dwHeaderSize = sizeof(dilong.diph);
   507         dilong.diph.dwObj = dev->dwType;
   508         dilong.diph.dwHow = DIPH_BYID;
   509         dilong.dwData = 0;
   510         result =
   511             IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
   512             DIPROP_DEADZONE, &dilong.diph);
   513         if (FAILED(result)) {
   514             return DIENUM_CONTINUE;     /* don't use this axis */
   515         }
   516 
   517         joystick->naxes++;
   518     } else {
   519         /* not supported at this time */
   520         return DIENUM_CONTINUE;
   521     }
   522 
   523     joystick->hwdata->NumInputs++;
   524 
   525     if (joystick->hwdata->NumInputs == MAX_INPUTS) {
   526         return DIENUM_STOP;     /* too many */
   527     }
   528 
   529     return DIENUM_CONTINUE;
   530 }
   531 
   532 /* Sort using the data offset into the DInput struct.
   533  * This gives a reasonable ordering for the inputs.
   534  */
   535 static int
   536 SortDevFunc(const void *a, const void *b)
   537 {
   538     const input_t *inputA = (const input_t*)a;
   539     const input_t *inputB = (const input_t*)b;
   540 
   541     if (inputA->ofs < inputB->ofs)
   542         return -1;
   543     if (inputA->ofs > inputB->ofs)
   544         return 1;
   545     return 0;
   546 }
   547 
   548 /* Sort the input objects and recalculate the indices for each input. */
   549 static void
   550 SortDevObjects(SDL_Joystick *joystick)
   551 {
   552     input_t *inputs = joystick->hwdata->Inputs;
   553     int nButtons = 0;
   554     int nHats = 0;
   555     int nAxis = 0;
   556     int n;
   557 
   558     SDL_qsort(inputs, joystick->hwdata->NumInputs, sizeof(input_t), SortDevFunc);
   559 
   560     for (n = 0; n < joystick->hwdata->NumInputs; n++) {
   561         switch (inputs[n].type) {
   562         case BUTTON:
   563             inputs[n].num = nButtons;
   564             nButtons++;
   565             break;
   566 
   567         case HAT:
   568             inputs[n].num = nHats;
   569             nHats++;
   570             break;
   571 
   572         case AXIS:
   573             inputs[n].num = nAxis;
   574             nAxis++;
   575             break;
   576         }
   577     }
   578 }
   579 
   580 int
   581 SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice)
   582 {
   583     HRESULT result;
   584     LPDIRECTINPUTDEVICE8 device;
   585     DIPROPDWORD dipdw;
   586 
   587     joystick->hwdata->buffered = SDL_TRUE;
   588     joystick->hwdata->Capabilities.dwSize = sizeof(DIDEVCAPS);
   589 
   590     SDL_zero(dipdw);
   591     dipdw.diph.dwSize = sizeof(DIPROPDWORD);
   592     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
   593 
   594     result =
   595         IDirectInput8_CreateDevice(dinput,
   596         &(joystickdevice->dxdevice.guidInstance), &device, NULL);
   597     if (FAILED(result)) {
   598         return SetDIerror("IDirectInput::CreateDevice", result);
   599     }
   600 
   601     /* Now get the IDirectInputDevice8 interface, instead. */
   602     result = IDirectInputDevice8_QueryInterface(device,
   603         &IID_IDirectInputDevice8,
   604         (LPVOID *)& joystick->
   605         hwdata->InputDevice);
   606     /* We are done with this object.  Use the stored one from now on. */
   607     IDirectInputDevice8_Release(device);
   608 
   609     if (FAILED(result)) {
   610         return SetDIerror("IDirectInputDevice8::QueryInterface", result);
   611     }
   612 
   613     /* Acquire shared access. Exclusive access is required for forces,
   614     * though. */
   615     result =
   616         IDirectInputDevice8_SetCooperativeLevel(joystick->hwdata->
   617         InputDevice, SDL_HelperWindow,
   618         DISCL_EXCLUSIVE |
   619         DISCL_BACKGROUND);
   620     if (FAILED(result)) {
   621         return SetDIerror("IDirectInputDevice8::SetCooperativeLevel", result);
   622     }
   623 
   624     /* Use the extended data structure: DIJOYSTATE2. */
   625     result =
   626         IDirectInputDevice8_SetDataFormat(joystick->hwdata->InputDevice,
   627         &SDL_c_dfDIJoystick2);
   628     if (FAILED(result)) {
   629         return SetDIerror("IDirectInputDevice8::SetDataFormat", result);
   630     }
   631 
   632     /* Get device capabilities */
   633     result =
   634         IDirectInputDevice8_GetCapabilities(joystick->hwdata->InputDevice,
   635         &joystick->hwdata->Capabilities);
   636     if (FAILED(result)) {
   637         return SetDIerror("IDirectInputDevice8::GetCapabilities", result);
   638     }
   639 
   640     /* Force capable? */
   641     if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
   642 
   643         result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
   644         if (FAILED(result)) {
   645             return SetDIerror("IDirectInputDevice8::Acquire", result);
   646         }
   647 
   648         /* reset all actuators. */
   649         result =
   650             IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->
   651             InputDevice,
   652             DISFFC_RESET);
   653 
   654         /* Not necessarily supported, ignore if not supported.
   655         if (FAILED(result)) {
   656         return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand", result);
   657         }
   658         */
   659 
   660         result = IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
   661 
   662         if (FAILED(result)) {
   663             return SetDIerror("IDirectInputDevice8::Unacquire", result);
   664         }
   665 
   666         /* Turn on auto-centering for a ForceFeedback device (until told
   667         * otherwise). */
   668         dipdw.diph.dwObj = 0;
   669         dipdw.diph.dwHow = DIPH_DEVICE;
   670         dipdw.dwData = DIPROPAUTOCENTER_ON;
   671 
   672         result =
   673             IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
   674             DIPROP_AUTOCENTER, &dipdw.diph);
   675 
   676         /* Not necessarily supported, ignore if not supported.
   677         if (FAILED(result)) {
   678         return SetDIerror("IDirectInputDevice8::SetProperty", result);
   679         }
   680         */
   681     }
   682 
   683     /* What buttons and axes does it have? */
   684     IDirectInputDevice8_EnumObjects(joystick->hwdata->InputDevice,
   685         EnumDevObjectsCallback, joystick,
   686         DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV);
   687 
   688     /* Reorder the input objects. Some devices do not report the X axis as
   689     * the first axis, for example. */
   690     SortDevObjects(joystick);
   691 
   692     dipdw.diph.dwObj = 0;
   693     dipdw.diph.dwHow = DIPH_DEVICE;
   694     dipdw.dwData = INPUT_QSIZE;
   695 
   696     /* Set the buffer size */
   697     result =
   698         IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
   699         DIPROP_BUFFERSIZE, &dipdw.diph);
   700 
   701     if (result == DI_POLLEDDEVICE) {
   702         /* This device doesn't support buffering, so we're forced
   703          * to use less reliable polling. */
   704         joystick->hwdata->buffered = SDL_FALSE;
   705     } else if (FAILED(result)) {
   706         return SetDIerror("IDirectInputDevice8::SetProperty", result);
   707     }
   708     return 0;
   709 }
   710 
   711 static Uint8
   712 TranslatePOV(DWORD value)
   713 {
   714     const int HAT_VALS[] = {
   715         SDL_HAT_UP,
   716         SDL_HAT_UP | SDL_HAT_RIGHT,
   717         SDL_HAT_RIGHT,
   718         SDL_HAT_DOWN | SDL_HAT_RIGHT,
   719         SDL_HAT_DOWN,
   720         SDL_HAT_DOWN | SDL_HAT_LEFT,
   721         SDL_HAT_LEFT,
   722         SDL_HAT_UP | SDL_HAT_LEFT
   723     };
   724 
   725     if (LOWORD(value) == 0xFFFF)
   726         return SDL_HAT_CENTERED;
   727 
   728     /* Round the value up: */
   729     value += 4500 / 2;
   730     value %= 36000;
   731     value /= 4500;
   732 
   733     if (value >= 8)
   734         return SDL_HAT_CENTERED;        /* shouldn't happen */
   735 
   736     return HAT_VALS[value];
   737 }
   738 
   739 static void
   740 UpdateDINPUTJoystickState_Buffered(SDL_Joystick * joystick)
   741 {
   742     int i;
   743     HRESULT result;
   744     DWORD numevents;
   745     DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
   746 
   747     numevents = INPUT_QSIZE;
   748     result =
   749         IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
   750         sizeof(DIDEVICEOBJECTDATA), evtbuf,
   751         &numevents, 0);
   752     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
   753         IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
   754         result =
   755             IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
   756             sizeof(DIDEVICEOBJECTDATA),
   757             evtbuf, &numevents, 0);
   758     }
   759 
   760     /* Handle the events or punt */
   761     if (FAILED(result)) {
   762         joystick->hwdata->send_remove_event = SDL_TRUE;
   763         joystick->hwdata->removed = SDL_TRUE;
   764         return;
   765     }
   766 
   767     for (i = 0; i < (int)numevents; ++i) {
   768         int j;
   769 
   770         for (j = 0; j < joystick->hwdata->NumInputs; ++j) {
   771             const input_t *in = &joystick->hwdata->Inputs[j];
   772 
   773             if (evtbuf[i].dwOfs != in->ofs)
   774                 continue;
   775 
   776             switch (in->type) {
   777             case AXIS:
   778                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)evtbuf[i].dwData);
   779                 break;
   780             case BUTTON:
   781                 SDL_PrivateJoystickButton(joystick, in->num,
   782                     (Uint8)(evtbuf[i].dwData ? SDL_PRESSED : SDL_RELEASED));
   783                 break;
   784             case HAT:
   785                 {
   786                     Uint8 pos = TranslatePOV(evtbuf[i].dwData);
   787                     SDL_PrivateJoystickHat(joystick, in->num, pos);
   788                 }
   789                 break;
   790             }
   791         }
   792     }
   793 }
   794 
   795 /* Function to update the state of a joystick - called as a device poll.
   796  * This function shouldn't update the joystick structure directly,
   797  * but instead should call SDL_PrivateJoystick*() to deliver events
   798  * and update joystick device state.
   799  */
   800 static void
   801 UpdateDINPUTJoystickState_Polled(SDL_Joystick * joystick)
   802 {
   803     DIJOYSTATE2 state;
   804     HRESULT result;
   805     int i;
   806 
   807     result =
   808         IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
   809         sizeof(DIJOYSTATE2), &state);
   810     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
   811         IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
   812         result =
   813             IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
   814             sizeof(DIJOYSTATE2), &state);
   815     }
   816 
   817     if (result != DI_OK) {
   818         joystick->hwdata->send_remove_event = SDL_TRUE;
   819         joystick->hwdata->removed = SDL_TRUE;
   820         return;
   821     }
   822 
   823     /* Set each known axis, button and POV. */
   824     for (i = 0; i < joystick->hwdata->NumInputs; ++i) {
   825         const input_t *in = &joystick->hwdata->Inputs[i];
   826 
   827         switch (in->type) {
   828         case AXIS:
   829             switch (in->ofs) {
   830             case DIJOFS_X:
   831                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lX);
   832                 break;
   833             case DIJOFS_Y:
   834                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lY);
   835                 break;
   836             case DIJOFS_Z:
   837                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lZ);
   838                 break;
   839             case DIJOFS_RX:
   840                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRx);
   841                 break;
   842             case DIJOFS_RY:
   843                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRy);
   844                 break;
   845             case DIJOFS_RZ:
   846                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRz);
   847                 break;
   848             case DIJOFS_SLIDER(0):
   849                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.rglSlider[0]);
   850                 break;
   851             case DIJOFS_SLIDER(1):
   852                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.rglSlider[1]);
   853                 break;
   854             }
   855             break;
   856 
   857         case BUTTON:
   858             SDL_PrivateJoystickButton(joystick, in->num,
   859                 (Uint8)(state.rgbButtons[in->ofs - DIJOFS_BUTTON0] ? SDL_PRESSED : SDL_RELEASED));
   860             break;
   861         case HAT:
   862         {
   863             Uint8 pos = TranslatePOV(state.rgdwPOV[in->ofs - DIJOFS_POV(0)]);
   864             SDL_PrivateJoystickHat(joystick, in->num, pos);
   865             break;
   866         }
   867         }
   868     }
   869 }
   870 
   871 void
   872 SDL_DINPUT_JoystickUpdate(SDL_Joystick * joystick)
   873 {
   874     HRESULT result;
   875 
   876     result = IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
   877     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
   878         IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
   879         IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
   880     }
   881 
   882     if (joystick->hwdata->buffered) {
   883         UpdateDINPUTJoystickState_Buffered(joystick);
   884     } else {
   885         UpdateDINPUTJoystickState_Polled(joystick);
   886     }
   887 }
   888 
   889 void
   890 SDL_DINPUT_JoystickClose(SDL_Joystick * joystick)
   891 {
   892     IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
   893     IDirectInputDevice8_Release(joystick->hwdata->InputDevice);
   894 }
   895 
   896 void
   897 SDL_DINPUT_JoystickQuit(void)
   898 {
   899     if (dinput != NULL) {
   900         IDirectInput8_Release(dinput);
   901         dinput = NULL;
   902     }
   903 
   904     if (coinitialized) {
   905         WIN_CoUninitialize();
   906         coinitialized = SDL_FALSE;
   907     }
   908 }
   909 
   910 #else /* !SDL_JOYSTICK_DINPUT */
   911 
   912 typedef struct JoyStick_DeviceData JoyStick_DeviceData;
   913 
   914 int
   915 SDL_DINPUT_JoystickInit(void)
   916 {
   917     return 0;
   918 }
   919 
   920 void
   921 SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext)
   922 {
   923 }
   924 
   925 int
   926 SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice)
   927 {
   928     return SDL_Unsupported();
   929 }
   930 
   931 void
   932 SDL_DINPUT_JoystickUpdate(SDL_Joystick * joystick)
   933 {
   934 }
   935 
   936 void
   937 SDL_DINPUT_JoystickClose(SDL_Joystick * joystick)
   938 {
   939 }
   940 
   941 void
   942 SDL_DINPUT_JoystickQuit(void)
   943 {
   944 }
   945 
   946 #endif /* SDL_JOYSTICK_DINPUT */
   947 
   948 /* vi: set ts=4 sw=4 expandtab: */