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