sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_dinputjoystick.c (53235B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 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_rawinputjoystick_c.h"
     30 #include "SDL_xinputjoystick_c.h"
     31 #include "../hidapi/SDL_hidapijoystick_c.h"
     32 
     33 #ifndef DIDFT_OPTIONAL
     34 #define DIDFT_OPTIONAL      0x80000000
     35 #endif
     36 
     37 #define INPUT_QSIZE 32      /* Buffer up to 32 input messages */
     38 #define JOY_AXIS_THRESHOLD  (((SDL_JOYSTICK_AXIS_MAX)-(SDL_JOYSTICK_AXIS_MIN))/100)   /* 1% motion */
     39 
     40 #define CONVERT_MAGNITUDE(x)    (((x)*10000) / 0x7FFF)
     41 
     42 /* external variables referenced. */
     43 extern HWND SDL_HelperWindow;
     44 
     45 /* local variables */
     46 static SDL_bool coinitialized = SDL_FALSE;
     47 static LPDIRECTINPUT8 dinput = NULL;
     48 static PRAWINPUTDEVICELIST SDL_RawDevList = NULL;
     49 static UINT SDL_RawDevListCount = 0;
     50 
     51 /* Taken from Wine - Thanks! */
     52 static DIOBJECTDATAFORMAT dfDIJoystick2[] = {
     53     { &GUID_XAxis, DIJOFS_X, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
     54     { &GUID_YAxis, DIJOFS_Y, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
     55     { &GUID_ZAxis, DIJOFS_Z, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
     56     { &GUID_RxAxis, DIJOFS_RX, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
     57     { &GUID_RyAxis, DIJOFS_RY, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
     58     { &GUID_RzAxis, DIJOFS_RZ, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
     59     { &GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
     60     { &GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
     61     { &GUID_POV, DIJOFS_POV(0), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
     62     { &GUID_POV, DIJOFS_POV(1), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
     63     { &GUID_POV, DIJOFS_POV(2), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
     64     { &GUID_POV, DIJOFS_POV(3), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
     65     { NULL, DIJOFS_BUTTON(0), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     66     { NULL, DIJOFS_BUTTON(1), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     67     { NULL, DIJOFS_BUTTON(2), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     68     { NULL, DIJOFS_BUTTON(3), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     69     { NULL, DIJOFS_BUTTON(4), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     70     { NULL, DIJOFS_BUTTON(5), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     71     { NULL, DIJOFS_BUTTON(6), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     72     { NULL, DIJOFS_BUTTON(7), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     73     { NULL, DIJOFS_BUTTON(8), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     74     { NULL, DIJOFS_BUTTON(9), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     75     { NULL, DIJOFS_BUTTON(10), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     76     { NULL, DIJOFS_BUTTON(11), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     77     { NULL, DIJOFS_BUTTON(12), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     78     { NULL, DIJOFS_BUTTON(13), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     79     { NULL, DIJOFS_BUTTON(14), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     80     { NULL, DIJOFS_BUTTON(15), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     81     { NULL, DIJOFS_BUTTON(16), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     82     { NULL, DIJOFS_BUTTON(17), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     83     { NULL, DIJOFS_BUTTON(18), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     84     { NULL, DIJOFS_BUTTON(19), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     85     { NULL, DIJOFS_BUTTON(20), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     86     { NULL, DIJOFS_BUTTON(21), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     87     { NULL, DIJOFS_BUTTON(22), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     88     { NULL, DIJOFS_BUTTON(23), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     89     { NULL, DIJOFS_BUTTON(24), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     90     { NULL, DIJOFS_BUTTON(25), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     91     { NULL, DIJOFS_BUTTON(26), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     92     { NULL, DIJOFS_BUTTON(27), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     93     { NULL, DIJOFS_BUTTON(28), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     94     { NULL, DIJOFS_BUTTON(29), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     95     { NULL, DIJOFS_BUTTON(30), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     96     { NULL, DIJOFS_BUTTON(31), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     97     { NULL, DIJOFS_BUTTON(32), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     98     { NULL, DIJOFS_BUTTON(33), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
     99     { NULL, DIJOFS_BUTTON(34), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    100     { NULL, DIJOFS_BUTTON(35), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    101     { NULL, DIJOFS_BUTTON(36), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    102     { NULL, DIJOFS_BUTTON(37), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    103     { NULL, DIJOFS_BUTTON(38), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    104     { NULL, DIJOFS_BUTTON(39), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    105     { NULL, DIJOFS_BUTTON(40), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    106     { NULL, DIJOFS_BUTTON(41), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    107     { NULL, DIJOFS_BUTTON(42), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    108     { NULL, DIJOFS_BUTTON(43), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    109     { NULL, DIJOFS_BUTTON(44), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    110     { NULL, DIJOFS_BUTTON(45), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    111     { NULL, DIJOFS_BUTTON(46), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    112     { NULL, DIJOFS_BUTTON(47), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    113     { NULL, DIJOFS_BUTTON(48), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    114     { NULL, DIJOFS_BUTTON(49), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    115     { NULL, DIJOFS_BUTTON(50), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    116     { NULL, DIJOFS_BUTTON(51), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    117     { NULL, DIJOFS_BUTTON(52), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    118     { NULL, DIJOFS_BUTTON(53), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    119     { NULL, DIJOFS_BUTTON(54), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    120     { NULL, DIJOFS_BUTTON(55), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    121     { NULL, DIJOFS_BUTTON(56), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    122     { NULL, DIJOFS_BUTTON(57), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    123     { NULL, DIJOFS_BUTTON(58), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    124     { NULL, DIJOFS_BUTTON(59), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    125     { NULL, DIJOFS_BUTTON(60), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    126     { NULL, DIJOFS_BUTTON(61), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    127     { NULL, DIJOFS_BUTTON(62), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    128     { NULL, DIJOFS_BUTTON(63), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    129     { NULL, DIJOFS_BUTTON(64), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    130     { NULL, DIJOFS_BUTTON(65), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    131     { NULL, DIJOFS_BUTTON(66), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    132     { NULL, DIJOFS_BUTTON(67), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    133     { NULL, DIJOFS_BUTTON(68), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    134     { NULL, DIJOFS_BUTTON(69), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    135     { NULL, DIJOFS_BUTTON(70), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    136     { NULL, DIJOFS_BUTTON(71), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    137     { NULL, DIJOFS_BUTTON(72), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    138     { NULL, DIJOFS_BUTTON(73), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    139     { NULL, DIJOFS_BUTTON(74), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    140     { NULL, DIJOFS_BUTTON(75), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    141     { NULL, DIJOFS_BUTTON(76), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    142     { NULL, DIJOFS_BUTTON(77), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    143     { NULL, DIJOFS_BUTTON(78), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    144     { NULL, DIJOFS_BUTTON(79), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    145     { NULL, DIJOFS_BUTTON(80), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    146     { NULL, DIJOFS_BUTTON(81), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    147     { NULL, DIJOFS_BUTTON(82), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    148     { NULL, DIJOFS_BUTTON(83), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    149     { NULL, DIJOFS_BUTTON(84), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    150     { NULL, DIJOFS_BUTTON(85), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    151     { NULL, DIJOFS_BUTTON(86), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    152     { NULL, DIJOFS_BUTTON(87), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    153     { NULL, DIJOFS_BUTTON(88), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    154     { NULL, DIJOFS_BUTTON(89), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    155     { NULL, DIJOFS_BUTTON(90), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    156     { NULL, DIJOFS_BUTTON(91), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    157     { NULL, DIJOFS_BUTTON(92), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    158     { NULL, DIJOFS_BUTTON(93), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    159     { NULL, DIJOFS_BUTTON(94), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    160     { NULL, DIJOFS_BUTTON(95), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    161     { NULL, DIJOFS_BUTTON(96), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    162     { NULL, DIJOFS_BUTTON(97), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    163     { NULL, DIJOFS_BUTTON(98), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    164     { NULL, DIJOFS_BUTTON(99), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    165     { NULL, DIJOFS_BUTTON(100), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    166     { NULL, DIJOFS_BUTTON(101), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    167     { NULL, DIJOFS_BUTTON(102), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    168     { NULL, DIJOFS_BUTTON(103), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    169     { NULL, DIJOFS_BUTTON(104), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    170     { NULL, DIJOFS_BUTTON(105), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    171     { NULL, DIJOFS_BUTTON(106), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    172     { NULL, DIJOFS_BUTTON(107), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    173     { NULL, DIJOFS_BUTTON(108), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    174     { NULL, DIJOFS_BUTTON(109), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    175     { NULL, DIJOFS_BUTTON(110), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    176     { NULL, DIJOFS_BUTTON(111), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    177     { NULL, DIJOFS_BUTTON(112), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    178     { NULL, DIJOFS_BUTTON(113), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    179     { NULL, DIJOFS_BUTTON(114), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    180     { NULL, DIJOFS_BUTTON(115), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    181     { NULL, DIJOFS_BUTTON(116), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    182     { NULL, DIJOFS_BUTTON(117), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    183     { NULL, DIJOFS_BUTTON(118), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    184     { NULL, DIJOFS_BUTTON(119), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    185     { NULL, DIJOFS_BUTTON(120), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    186     { NULL, DIJOFS_BUTTON(121), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    187     { NULL, DIJOFS_BUTTON(122), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    188     { NULL, DIJOFS_BUTTON(123), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    189     { NULL, DIJOFS_BUTTON(124), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    190     { NULL, DIJOFS_BUTTON(125), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    191     { NULL, DIJOFS_BUTTON(126), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    192     { NULL, DIJOFS_BUTTON(127), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
    193     { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lVX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    194     { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lVY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    195     { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lVZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    196     { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lVRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    197     { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lVRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    198     { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lVRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    199     { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglVSlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    200     { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglVSlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    201     { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lAX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    202     { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lAY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    203     { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lAZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    204     { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lARx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    205     { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lARy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    206     { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lARz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    207     { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglASlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    208     { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglASlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    209     { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lFX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    210     { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lFY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    211     { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lFZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    212     { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lFRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    213     { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lFRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    214     { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lFRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    215     { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglFSlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    216     { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglFSlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
    217 };
    218 
    219 const DIDATAFORMAT SDL_c_dfDIJoystick2 = {
    220     sizeof(DIDATAFORMAT),
    221     sizeof(DIOBJECTDATAFORMAT),
    222     DIDF_ABSAXIS,
    223     sizeof(DIJOYSTATE2),
    224     SDL_arraysize(dfDIJoystick2),
    225     dfDIJoystick2
    226 };
    227 
    228 /* Convert a DirectInput return code to a text message */
    229 static int
    230 SetDIerror(const char *function, HRESULT code)
    231 {
    232     return SDL_SetError("%s() DirectX error 0x%8.8lx", function, code);
    233 }
    234 
    235 #if 0 /* Microsoft recommended implementation, but slower than checking raw devices */
    236 #define COBJMACROS
    237 #include <wbemidl.h>
    238 #include <oleauto.h>
    239 
    240 static const IID CLSID_WbemLocator = { 0x4590f811, 0x1d3a, 0x11d0,{ 0x89, 0x1f, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24 } };
    241 static const IID IID_IWbemLocator = { 0xdc12a687, 0x737f, 0x11cf,{ 0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24 } };
    242 
    243 static SDL_bool
    244 WIN_IsXInputDevice(const WCHAR *name, const GUID* pGuidProductFromDirectInput)
    245 {
    246     IWbemLocator*           pIWbemLocator = NULL;
    247     IEnumWbemClassObject*   pEnumDevices = NULL;
    248     IWbemClassObject*       pDevices[20];
    249     IWbemServices*          pIWbemServices = NULL;
    250     BSTR                    bstrNamespace = NULL;
    251     BSTR                    bstrDeviceID = NULL;
    252     BSTR                    bstrClassName = NULL;
    253     DWORD                   uReturned = 0;
    254     SDL_bool                bIsXinputDevice = SDL_FALSE;
    255     UINT                    iDevice = 0;
    256     VARIANT                 var;
    257     HRESULT                 hr;
    258 
    259     if (!SDL_XINPUT_Enabled()) {
    260         return SDL_FALSE;
    261     }
    262 
    263     if (SDL_wcsstr(name, L" XINPUT ") != NULL) {
    264         /* This is a duplicate interface for a controller that will show up with XInput,
    265            e.g. Xbox One Elite Series 2 in Bluetooth mode.
    266          */
    267         return SDL_TRUE;
    268     }
    269 
    270     SDL_zeroa(pDevices);
    271 
    272     // Create WMI
    273     hr = CoCreateInstance(&CLSID_WbemLocator,
    274         NULL,
    275         CLSCTX_INPROC_SERVER,
    276         &IID_IWbemLocator,
    277         (LPVOID*)&pIWbemLocator);
    278     if (FAILED(hr) || pIWbemLocator == NULL)
    279         goto LCleanup;
    280 
    281     bstrNamespace = SysAllocString(L"\\\\.\\root\\cimv2"); if (bstrNamespace == NULL) goto LCleanup;
    282     bstrClassName = SysAllocString(L"Win32_PNPEntity");   if (bstrClassName == NULL) goto LCleanup;
    283     bstrDeviceID = SysAllocString(L"DeviceID");          if (bstrDeviceID == NULL)  goto LCleanup;
    284 
    285     // Connect to WMI 
    286     hr = IWbemLocator_ConnectServer(pIWbemLocator, bstrNamespace, NULL, NULL, 0L,
    287         0L, NULL, NULL, &pIWbemServices);
    288     if (FAILED(hr) || pIWbemServices == NULL) {
    289         goto LCleanup;
    290     }
    291 
    292     // Switch security level to IMPERSONATE. 
    293     CoSetProxyBlanket((IUnknown *)pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
    294         RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
    295 
    296     hr = IWbemServices_CreateInstanceEnum(pIWbemServices, bstrClassName, 0, NULL, &pEnumDevices);
    297     if (FAILED(hr) || pEnumDevices == NULL)
    298         goto LCleanup;
    299 
    300     // Loop over all devices
    301     for (;;) {
    302         // Get 20 at a time
    303         hr = IEnumWbemClassObject_Next(pEnumDevices, 10000, SDL_arraysize(pDevices), pDevices, &uReturned);
    304         if (FAILED(hr)) {
    305             goto LCleanup;
    306         }
    307         if (uReturned == 0) {
    308             break;
    309         }
    310 
    311         for (iDevice = 0; iDevice < uReturned; iDevice++) {
    312             // For each device, get its device ID
    313             hr = IWbemClassObject_Get(pDevices[iDevice], bstrDeviceID, 0L, &var, NULL, NULL);
    314             if (SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != NULL) {
    315                 // Check if the device ID contains "IG_".  If it does, then it's an XInput device
    316                 // This information can not be found from DirectInput 
    317                 if (SDL_wcsstr(var.bstrVal, L"IG_")) {
    318                     char *bstrVal = WIN_StringToUTF8(var.bstrVal);
    319 
    320                     // If it does, then get the VID/PID from var.bstrVal
    321                     DWORD dwPid = 0, dwVid = 0, dwVidPid;
    322                     const char *strVid, *strPid;
    323                     strVid = SDL_strstr(bstrVal, "VID_");
    324                     if (strVid && SDL_sscanf(strVid, "VID_%4X", &dwVid) != 1)
    325                         dwVid = 0;
    326                     strPid = SDL_strstr(bstrVal, "PID_");
    327                     if (strPid && SDL_sscanf(strPid, "PID_%4X", &dwPid) != 1)
    328                         dwPid = 0;
    329 
    330                     SDL_free(bstrVal);
    331 
    332                     // Compare the VID/PID to the DInput device
    333                     dwVidPid = MAKELONG(dwVid, dwPid);
    334                     if (dwVidPid == pGuidProductFromDirectInput->Data1) {
    335                         bIsXinputDevice = SDL_TRUE;
    336                         goto LCleanup;
    337                     }
    338                 }
    339             }
    340             IWbemClassObject_Release(pDevices[iDevice]);
    341         }
    342     }
    343 
    344 LCleanup:
    345     if (bstrNamespace) {
    346         SysFreeString(bstrNamespace);
    347     }
    348     if (bstrDeviceID) {
    349         SysFreeString(bstrDeviceID);
    350     }
    351     if (bstrClassName) {
    352         SysFreeString(bstrClassName);
    353     }
    354     for (iDevice = 0; iDevice < SDL_arraysize(pDevices); iDevice++) {
    355         if (pDevices[iDevice]) {
    356             IWbemClassObject_Release(pDevices[iDevice]);
    357         }
    358     }
    359     if (pEnumDevices) {
    360         IEnumWbemClassObject_Release(pEnumDevices);
    361     }
    362     if (pIWbemLocator) {
    363         IWbemLocator_Release(pIWbemLocator);
    364     }
    365     if (pIWbemServices) {
    366         IWbemServices_Release(pIWbemServices);
    367     }
    368 
    369     return bIsXinputDevice;
    370 }
    371 #endif /* 0 */
    372 
    373 static SDL_bool
    374 SDL_IsXInputDevice(const WCHAR *name, const GUID* pGuidProductFromDirectInput)
    375 {
    376     UINT i;
    377 
    378     if (!SDL_XINPUT_Enabled()) {
    379         return SDL_FALSE;
    380     }
    381 
    382     if (SDL_wcsstr(name, L" XINPUT ") != NULL) {
    383         /* This is a duplicate interface for a controller that will show up with XInput,
    384            e.g. Xbox One Elite Series 2 in Bluetooth mode.
    385          */
    386         return SDL_TRUE;
    387     }
    388 
    389     if (SDL_memcmp(&pGuidProductFromDirectInput->Data4[2], "PIDVID", 6) == 0) {
    390         Uint16 vendor_id = (Uint16)LOWORD(pGuidProductFromDirectInput->Data1);
    391         Uint16 product_id = (Uint16)HIWORD(pGuidProductFromDirectInput->Data1);
    392         SDL_GameControllerType type = SDL_GetJoystickGameControllerType("", vendor_id, product_id, -1, 0, 0, 0);
    393         if (type == SDL_CONTROLLER_TYPE_XBOX360 ||
    394             type == SDL_CONTROLLER_TYPE_XBOXONE ||
    395             (vendor_id == 0x28DE && product_id == 0x11FF)) {
    396             return SDL_TRUE;
    397         }
    398     }
    399 
    400     /* Go through RAWINPUT (WinXP and later) to find HID devices. */
    401     /* Cache this if we end up using it. */
    402     if (SDL_RawDevList == NULL) {
    403         if ((GetRawInputDeviceList(NULL, &SDL_RawDevListCount, sizeof(RAWINPUTDEVICELIST)) == -1) || (!SDL_RawDevListCount)) {
    404             return SDL_FALSE;  /* oh well. */
    405         }
    406 
    407         SDL_RawDevList = (PRAWINPUTDEVICELIST)SDL_malloc(sizeof(RAWINPUTDEVICELIST) * SDL_RawDevListCount);
    408         if (SDL_RawDevList == NULL) {
    409             SDL_OutOfMemory();
    410             return SDL_FALSE;
    411         }
    412 
    413         if (GetRawInputDeviceList(SDL_RawDevList, &SDL_RawDevListCount, sizeof(RAWINPUTDEVICELIST)) == -1) {
    414             SDL_free(SDL_RawDevList);
    415             SDL_RawDevList = NULL;
    416             return SDL_FALSE;  /* oh well. */
    417         }
    418     }
    419 
    420     for (i = 0; i < SDL_RawDevListCount; i++) {
    421         RID_DEVICE_INFO rdi;
    422         char devName[MAX_PATH];
    423         UINT rdiSize = sizeof(rdi);
    424         UINT nameSize = SDL_arraysize(devName);
    425 
    426         rdi.cbSize = sizeof(rdi);
    427         if ((SDL_RawDevList[i].dwType == RIM_TYPEHID) &&
    428             (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != ((UINT)-1)) &&
    429             (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == ((LONG)pGuidProductFromDirectInput->Data1)) &&
    430             (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != ((UINT)-1)) &&
    431             (SDL_strstr(devName, "IG_") != NULL)) {
    432             return SDL_TRUE;
    433         }
    434     }
    435 
    436     return SDL_FALSE;
    437 }
    438 
    439 void FreeRumbleEffectData(DIEFFECT *effect)
    440 {
    441     if (!effect) {
    442         return;
    443     }
    444     SDL_free(effect->rgdwAxes);
    445     SDL_free(effect->rglDirection);
    446     SDL_free(effect->lpvTypeSpecificParams);
    447     SDL_free(effect);
    448 }
    449 
    450 DIEFFECT *CreateRumbleEffectData(Sint16 magnitude)
    451 {
    452     DIEFFECT *effect;
    453     DIPERIODIC *periodic;
    454 
    455     /* Create the effect */
    456     effect = (DIEFFECT *)SDL_calloc(1, sizeof(*effect));
    457     if (!effect) {
    458         return NULL;
    459     }
    460     effect->dwSize = sizeof(*effect);
    461     effect->dwGain = 10000;
    462     effect->dwFlags = DIEFF_OBJECTOFFSETS;
    463     effect->dwDuration = SDL_MAX_RUMBLE_DURATION_MS * 1000; /* In microseconds. */
    464     effect->dwTriggerButton = DIEB_NOTRIGGER;
    465 
    466     effect->cAxes = 2;
    467     effect->rgdwAxes = (DWORD *)SDL_calloc(effect->cAxes, sizeof(DWORD));
    468     if (!effect->rgdwAxes) {
    469         FreeRumbleEffectData(effect);
    470         return NULL;
    471     }
    472 
    473     effect->rglDirection = (LONG *)SDL_calloc(effect->cAxes, sizeof(LONG));
    474     if (!effect->rglDirection) {
    475         FreeRumbleEffectData(effect);
    476         return NULL;
    477     }
    478     effect->dwFlags |= DIEFF_CARTESIAN;
    479 
    480     periodic = (DIPERIODIC *)SDL_calloc(1, sizeof(*periodic));
    481     if (!periodic) {
    482         FreeRumbleEffectData(effect);
    483         return NULL;
    484     }
    485     periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude);
    486     periodic->dwPeriod = 1000000;
    487 
    488     effect->cbTypeSpecificParams = sizeof(*periodic);
    489     effect->lpvTypeSpecificParams = periodic;
    490 
    491     return effect;
    492 }
    493 
    494 int
    495 SDL_DINPUT_JoystickInit(void)
    496 {
    497     HRESULT result;
    498     HINSTANCE instance;
    499 
    500     result = WIN_CoInitialize();
    501     if (FAILED(result)) {
    502         return SetDIerror("CoInitialize", result);
    503     }
    504 
    505     coinitialized = SDL_TRUE;
    506 
    507     result = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER,
    508         &IID_IDirectInput8, (LPVOID *)&dinput);
    509 
    510     if (FAILED(result)) {
    511         return SetDIerror("CoCreateInstance", result);
    512     }
    513 
    514     /* Because we used CoCreateInstance, we need to Initialize it, first. */
    515     instance = GetModuleHandle(NULL);
    516     if (instance == NULL) {
    517         IDirectInput8_Release(dinput);
    518         dinput = NULL;
    519         return SDL_SetError("GetModuleHandle() failed with error code %lu.", GetLastError());
    520     }
    521     result = IDirectInput8_Initialize(dinput, instance, DIRECTINPUT_VERSION);
    522 
    523     if (FAILED(result)) {
    524         IDirectInput8_Release(dinput);
    525         dinput = NULL;
    526         return SetDIerror("IDirectInput::Initialize", result);
    527     }
    528     return 0;
    529 }
    530 
    531 /* helper function for direct input, gets called for each connected joystick */
    532 static BOOL CALLBACK
    533 EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
    534 {
    535     JoyStick_DeviceData *pNewJoystick;
    536     JoyStick_DeviceData *pPrevJoystick = NULL;
    537     const DWORD devtype = (pdidInstance->dwDevType & 0xFF);
    538     Uint16 *guid16;
    539     Uint16 vendor = 0;
    540     Uint16 product = 0;
    541     Uint16 version = 0;
    542     WCHAR hidPath[MAX_PATH];
    543     char *name;
    544 
    545     if (devtype == DI8DEVTYPE_SUPPLEMENTAL) {
    546         /* Add any supplemental devices that should be ignored here */
    547 #define MAKE_TABLE_ENTRY(VID, PID)    ((((DWORD)PID)<<16)|VID)
    548         static DWORD ignored_devices[] = {
    549             MAKE_TABLE_ENTRY(0, 0)
    550         };
    551 #undef MAKE_TABLE_ENTRY
    552         unsigned int i;
    553 
    554         for (i = 0; i < SDL_arraysize(ignored_devices); ++i) {
    555             if (pdidInstance->guidProduct.Data1 == ignored_devices[i]) {
    556                 return DIENUM_CONTINUE;
    557             }
    558         }
    559     }
    560 
    561     if (SDL_IsXInputDevice(pdidInstance->tszProductName, &pdidInstance->guidProduct)) {
    562         return DIENUM_CONTINUE;  /* ignore XInput devices here, keep going. */
    563     }
    564 
    565     {
    566         HRESULT result;
    567         LPDIRECTINPUTDEVICE8 device;
    568         LPDIRECTINPUTDEVICE8 InputDevice;
    569         DIPROPGUIDANDPATH dipdw2;
    570 
    571         result = IDirectInput8_CreateDevice(dinput, &(pdidInstance->guidInstance), &device, NULL);
    572         if (FAILED(result)) {
    573             return DIENUM_CONTINUE; /* better luck next time? */
    574         }
    575 
    576         /* Now get the IDirectInputDevice8 interface, instead. */
    577         result = IDirectInputDevice8_QueryInterface(device, &IID_IDirectInputDevice8, (LPVOID *)&InputDevice);
    578         /* We are done with this object.  Use the stored one from now on. */
    579         IDirectInputDevice8_Release(device);
    580         if (FAILED(result)) {
    581             return DIENUM_CONTINUE; /* better luck next time? */
    582         }
    583         dipdw2.diph.dwSize = sizeof(dipdw2);
    584         dipdw2.diph.dwHeaderSize = sizeof(dipdw2.diph);
    585         dipdw2.diph.dwObj = 0; // device property
    586         dipdw2.diph.dwHow = DIPH_DEVICE;
    587 
    588         result = IDirectInputDevice8_GetProperty(InputDevice, DIPROP_GUIDANDPATH, &dipdw2.diph);
    589         IDirectInputDevice8_Release(InputDevice);
    590         if (FAILED(result)) {
    591             return DIENUM_CONTINUE; /* better luck next time? */
    592         }
    593 
    594         /* Get device path, compare that instead of GUID, additionally update GUIDs of joysticks with matching paths, in case they're not open yet. */
    595         SDL_wcslcpy(hidPath, dipdw2.wszPath, SDL_arraysize(hidPath));
    596     }
    597 
    598     pNewJoystick = *(JoyStick_DeviceData **)pContext;
    599     while (pNewJoystick) {
    600         if (SDL_wcscmp(pNewJoystick->hidPath, hidPath) == 0) {
    601             /* if we are replacing the front of the list then update it */
    602             if (pNewJoystick == *(JoyStick_DeviceData **)pContext) {
    603                 *(JoyStick_DeviceData **)pContext = pNewJoystick->pNext;
    604             } else if (pPrevJoystick) {
    605                 pPrevJoystick->pNext = pNewJoystick->pNext;
    606             }
    607 
    608             /* Update with new guid/etc, if it has changed */
    609             SDL_memcpy(&pNewJoystick->dxdevice, pdidInstance, sizeof(DIDEVICEINSTANCE));
    610 
    611             pNewJoystick->pNext = SYS_Joystick;
    612             SYS_Joystick = pNewJoystick;
    613 
    614             return DIENUM_CONTINUE; /* already have this joystick loaded, just keep going */
    615         }
    616 
    617         pPrevJoystick = pNewJoystick;
    618         pNewJoystick = pNewJoystick->pNext;
    619     }
    620 
    621     pNewJoystick = (JoyStick_DeviceData *)SDL_malloc(sizeof(JoyStick_DeviceData));
    622     if (!pNewJoystick) {
    623         return DIENUM_CONTINUE; /* better luck next time? */
    624     }
    625 
    626     SDL_zerop(pNewJoystick);
    627     SDL_wcslcpy(pNewJoystick->hidPath, hidPath, SDL_arraysize(pNewJoystick->hidPath));
    628     SDL_memcpy(&pNewJoystick->dxdevice, pdidInstance, sizeof(DIDEVICEINSTANCE));
    629     SDL_memset(pNewJoystick->guid.data, 0, sizeof(pNewJoystick->guid.data));
    630 
    631     if (SDL_memcmp(&pdidInstance->guidProduct.Data4[2], "PIDVID", 6) == 0) {
    632         vendor = (Uint16)LOWORD(pdidInstance->guidProduct.Data1);
    633         product = (Uint16)HIWORD(pdidInstance->guidProduct.Data1);
    634     }
    635 
    636     name = WIN_StringToUTF8(pdidInstance->tszProductName);
    637     pNewJoystick->joystickname = SDL_CreateJoystickName(vendor, product, NULL, name);
    638     SDL_free(name);
    639 
    640     if (!pNewJoystick->joystickname) {
    641         SDL_free(pNewJoystick);
    642         return DIENUM_CONTINUE; /* better luck next time? */
    643     }
    644 
    645     guid16 = (Uint16 *)pNewJoystick->guid.data;
    646     if (SDL_memcmp(&pdidInstance->guidProduct.Data4[2], "PIDVID", 6) == 0) {
    647         *guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_USB);
    648         *guid16++ = 0;
    649         *guid16++ = SDL_SwapLE16(vendor);
    650         *guid16++ = 0;
    651         *guid16++ = SDL_SwapLE16(product);
    652         *guid16++ = 0;
    653         *guid16++ = SDL_SwapLE16(version);
    654         *guid16++ = 0;
    655     } else {
    656         *guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_BLUETOOTH);
    657         *guid16++ = 0;
    658         SDL_strlcpy((char*)guid16, pNewJoystick->joystickname, sizeof(pNewJoystick->guid.data) - 4);
    659     }
    660 
    661     if (SDL_ShouldIgnoreJoystick(pNewJoystick->joystickname, pNewJoystick->guid)) {
    662         SDL_free(pNewJoystick->joystickname);
    663         SDL_free(pNewJoystick);
    664         return DIENUM_CONTINUE;
    665     }
    666 
    667 #ifdef SDL_JOYSTICK_HIDAPI
    668     if (HIDAPI_IsDevicePresent(vendor, product, 0, pNewJoystick->joystickname)) {
    669         /* The HIDAPI driver is taking care of this device */
    670         SDL_free(pNewJoystick->joystickname);
    671         SDL_free(pNewJoystick);
    672         return DIENUM_CONTINUE;
    673     }
    674 #endif
    675 
    676 #ifdef SDL_JOYSTICK_RAWINPUT
    677     if (RAWINPUT_IsDevicePresent(vendor, product, 0, pNewJoystick->joystickname)) {
    678         /* The RAWINPUT driver is taking care of this device */
    679         SDL_free(pNewJoystick);
    680         return DIENUM_CONTINUE;
    681     }
    682 #endif
    683 
    684     WINDOWS_AddJoystickDevice(pNewJoystick);
    685 
    686     return DIENUM_CONTINUE; /* get next device, please */
    687 }
    688 
    689 void
    690 SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext)
    691 {
    692     IDirectInput8_EnumDevices(dinput, DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, pContext, DIEDFL_ATTACHEDONLY);
    693 
    694     if (SDL_RawDevList) {
    695         SDL_free(SDL_RawDevList);  /* in case we used this in DirectInput detection */
    696         SDL_RawDevList = NULL;
    697     }
    698     SDL_RawDevListCount = 0;
    699 }
    700 
    701 typedef struct
    702 {
    703     Uint16 vendor;
    704     Uint16 product;
    705     Uint16 version;
    706     SDL_bool present;
    707 } EnumJoystickPresentData;
    708 
    709 static BOOL CALLBACK
    710 EnumJoystickPresentCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
    711 {
    712     EnumJoystickPresentData *data = (EnumJoystickPresentData *)pContext;
    713     Uint16 vendor = 0;
    714     Uint16 product = 0;
    715     Uint16 version = 0;
    716 
    717     if (SDL_memcmp(&pdidInstance->guidProduct.Data4[2], "PIDVID", 6) == 0) {
    718         vendor = (Uint16)LOWORD(pdidInstance->guidProduct.Data1);
    719         product = (Uint16)HIWORD(pdidInstance->guidProduct.Data1);
    720         if (data->vendor == vendor && data->product == product && data->version == version) {
    721             data->present = SDL_TRUE;
    722             return DIENUM_STOP;
    723         }
    724     }
    725     return DIENUM_CONTINUE;
    726 }
    727 
    728 SDL_bool
    729 SDL_DINPUT_JoystickPresent(Uint16 vendor, Uint16 product, Uint16 version)
    730 {
    731     EnumJoystickPresentData data;
    732 
    733     if (dinput == NULL) {
    734         return SDL_FALSE;
    735     }
    736 
    737     data.vendor = vendor;
    738     data.product = product;
    739     data.version = version;
    740     data.present = SDL_FALSE;
    741     IDirectInput8_EnumDevices(dinput, DI8DEVCLASS_GAMECTRL, EnumJoystickPresentCallback, &data, DIEDFL_ATTACHEDONLY);
    742 
    743     return data.present;
    744 }
    745 
    746 static BOOL CALLBACK
    747 EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
    748 {
    749     SDL_Joystick *joystick = (SDL_Joystick *)pvRef;
    750     HRESULT result;
    751     input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs];
    752 
    753     if (dev->dwType & DIDFT_BUTTON) {
    754         in->type = BUTTON;
    755         in->num = joystick->nbuttons;
    756         in->ofs = DIJOFS_BUTTON(in->num);
    757         joystick->nbuttons++;
    758     } else if (dev->dwType & DIDFT_POV) {
    759         in->type = HAT;
    760         in->num = joystick->nhats;
    761         in->ofs = DIJOFS_POV(in->num);
    762         joystick->nhats++;
    763     } else if (dev->dwType & DIDFT_AXIS) {
    764         DIPROPRANGE diprg;
    765         DIPROPDWORD dilong;
    766 
    767         in->type = AXIS;
    768         in->num = joystick->naxes;
    769         if (!SDL_memcmp(&dev->guidType, &GUID_XAxis, sizeof(dev->guidType)))
    770             in->ofs = DIJOFS_X;
    771         else if (!SDL_memcmp(&dev->guidType, &GUID_YAxis, sizeof(dev->guidType)))
    772             in->ofs = DIJOFS_Y;
    773         else if (!SDL_memcmp(&dev->guidType, &GUID_ZAxis, sizeof(dev->guidType)))
    774             in->ofs = DIJOFS_Z;
    775         else if (!SDL_memcmp(&dev->guidType, &GUID_RxAxis, sizeof(dev->guidType)))
    776             in->ofs = DIJOFS_RX;
    777         else if (!SDL_memcmp(&dev->guidType, &GUID_RyAxis, sizeof(dev->guidType)))
    778             in->ofs = DIJOFS_RY;
    779         else if (!SDL_memcmp(&dev->guidType, &GUID_RzAxis, sizeof(dev->guidType)))
    780             in->ofs = DIJOFS_RZ;
    781         else if (!SDL_memcmp(&dev->guidType, &GUID_Slider, sizeof(dev->guidType))) {
    782             in->ofs = DIJOFS_SLIDER(joystick->hwdata->NumSliders);
    783             ++joystick->hwdata->NumSliders;
    784         } else {
    785             return DIENUM_CONTINUE; /* not an axis we can grok */
    786         }
    787 
    788         diprg.diph.dwSize = sizeof(diprg);
    789         diprg.diph.dwHeaderSize = sizeof(diprg.diph);
    790         diprg.diph.dwObj = dev->dwType;
    791         diprg.diph.dwHow = DIPH_BYID;
    792         diprg.lMin = SDL_JOYSTICK_AXIS_MIN;
    793         diprg.lMax = SDL_JOYSTICK_AXIS_MAX;
    794 
    795         result =
    796             IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
    797             DIPROP_RANGE, &diprg.diph);
    798         if (FAILED(result)) {
    799             return DIENUM_CONTINUE;     /* don't use this axis */
    800         }
    801 
    802         /* Set dead zone to 0. */
    803         dilong.diph.dwSize = sizeof(dilong);
    804         dilong.diph.dwHeaderSize = sizeof(dilong.diph);
    805         dilong.diph.dwObj = dev->dwType;
    806         dilong.diph.dwHow = DIPH_BYID;
    807         dilong.dwData = 0;
    808         result =
    809             IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
    810             DIPROP_DEADZONE, &dilong.diph);
    811         if (FAILED(result)) {
    812             return DIENUM_CONTINUE;     /* don't use this axis */
    813         }
    814 
    815         joystick->naxes++;
    816     } else {
    817         /* not supported at this time */
    818         return DIENUM_CONTINUE;
    819     }
    820 
    821     joystick->hwdata->NumInputs++;
    822 
    823     if (joystick->hwdata->NumInputs == MAX_INPUTS) {
    824         return DIENUM_STOP;     /* too many */
    825     }
    826 
    827     return DIENUM_CONTINUE;
    828 }
    829 
    830 /* Sort using the data offset into the DInput struct.
    831  * This gives a reasonable ordering for the inputs.
    832  */
    833 static int
    834 SortDevFunc(const void *a, const void *b)
    835 {
    836     const input_t *inputA = (const input_t*)a;
    837     const input_t *inputB = (const input_t*)b;
    838 
    839     if (inputA->ofs < inputB->ofs)
    840         return -1;
    841     if (inputA->ofs > inputB->ofs)
    842         return 1;
    843     return 0;
    844 }
    845 
    846 /* Sort the input objects and recalculate the indices for each input. */
    847 static void
    848 SortDevObjects(SDL_Joystick *joystick)
    849 {
    850     input_t *inputs = joystick->hwdata->Inputs;
    851     int nButtons = 0;
    852     int nHats = 0;
    853     int nAxis = 0;
    854     int n;
    855 
    856     SDL_qsort(inputs, joystick->hwdata->NumInputs, sizeof(input_t), SortDevFunc);
    857 
    858     for (n = 0; n < joystick->hwdata->NumInputs; n++) {
    859         switch (inputs[n].type) {
    860         case BUTTON:
    861             inputs[n].num = nButtons;
    862             nButtons++;
    863             break;
    864 
    865         case HAT:
    866             inputs[n].num = nHats;
    867             nHats++;
    868             break;
    869 
    870         case AXIS:
    871             inputs[n].num = nAxis;
    872             nAxis++;
    873             break;
    874         }
    875     }
    876 }
    877 
    878 int
    879 SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice)
    880 {
    881     HRESULT result;
    882     LPDIRECTINPUTDEVICE8 device;
    883     DIPROPDWORD dipdw;
    884 
    885     joystick->hwdata->buffered = SDL_TRUE;
    886     joystick->hwdata->Capabilities.dwSize = sizeof(DIDEVCAPS);
    887 
    888     SDL_zero(dipdw);
    889     dipdw.diph.dwSize = sizeof(DIPROPDWORD);
    890     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
    891 
    892     result =
    893         IDirectInput8_CreateDevice(dinput,
    894         &(joystickdevice->dxdevice.guidInstance), &device, NULL);
    895     if (FAILED(result)) {
    896         return SetDIerror("IDirectInput::CreateDevice", result);
    897     }
    898 
    899     /* Now get the IDirectInputDevice8 interface, instead. */
    900     result = IDirectInputDevice8_QueryInterface(device,
    901         &IID_IDirectInputDevice8,
    902         (LPVOID *)& joystick->
    903         hwdata->InputDevice);
    904     /* We are done with this object.  Use the stored one from now on. */
    905     IDirectInputDevice8_Release(device);
    906 
    907     if (FAILED(result)) {
    908         return SetDIerror("IDirectInputDevice8::QueryInterface", result);
    909     }
    910 
    911     /* Acquire shared access. Exclusive access is required for forces,
    912     * though. */
    913     result =
    914         IDirectInputDevice8_SetCooperativeLevel(joystick->hwdata->
    915         InputDevice, SDL_HelperWindow,
    916         DISCL_EXCLUSIVE |
    917         DISCL_BACKGROUND);
    918     if (FAILED(result)) {
    919         return SetDIerror("IDirectInputDevice8::SetCooperativeLevel", result);
    920     }
    921 
    922     /* Use the extended data structure: DIJOYSTATE2. */
    923     result =
    924         IDirectInputDevice8_SetDataFormat(joystick->hwdata->InputDevice,
    925         &SDL_c_dfDIJoystick2);
    926     if (FAILED(result)) {
    927         return SetDIerror("IDirectInputDevice8::SetDataFormat", result);
    928     }
    929 
    930     /* Get device capabilities */
    931     result =
    932         IDirectInputDevice8_GetCapabilities(joystick->hwdata->InputDevice,
    933         &joystick->hwdata->Capabilities);
    934     if (FAILED(result)) {
    935         return SetDIerror("IDirectInputDevice8::GetCapabilities", result);
    936     }
    937 
    938     /* Force capable? */
    939     if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
    940         result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
    941         if (FAILED(result)) {
    942             return SetDIerror("IDirectInputDevice8::Acquire", result);
    943         }
    944 
    945         /* reset all actuators. */
    946         result =
    947             IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->
    948             InputDevice,
    949             DISFFC_RESET);
    950 
    951         /* Not necessarily supported, ignore if not supported.
    952         if (FAILED(result)) {
    953         return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand", result);
    954         }
    955         */
    956 
    957         result = IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
    958 
    959         if (FAILED(result)) {
    960             return SetDIerror("IDirectInputDevice8::Unacquire", result);
    961         }
    962 
    963         /* Turn on auto-centering for a ForceFeedback device (until told
    964         * otherwise). */
    965         dipdw.diph.dwObj = 0;
    966         dipdw.diph.dwHow = DIPH_DEVICE;
    967         dipdw.dwData = DIPROPAUTOCENTER_ON;
    968 
    969         result =
    970             IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
    971             DIPROP_AUTOCENTER, &dipdw.diph);
    972 
    973         /* Not necessarily supported, ignore if not supported.
    974         if (FAILED(result)) {
    975         return SetDIerror("IDirectInputDevice8::SetProperty", result);
    976         }
    977         */
    978     }
    979 
    980     /* What buttons and axes does it have? */
    981     IDirectInputDevice8_EnumObjects(joystick->hwdata->InputDevice,
    982         EnumDevObjectsCallback, joystick,
    983         DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV);
    984 
    985     /* Reorder the input objects. Some devices do not report the X axis as
    986     * the first axis, for example. */
    987     SortDevObjects(joystick);
    988 
    989     dipdw.diph.dwObj = 0;
    990     dipdw.diph.dwHow = DIPH_DEVICE;
    991     dipdw.dwData = INPUT_QSIZE;
    992 
    993     /* Set the buffer size */
    994     result =
    995         IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
    996         DIPROP_BUFFERSIZE, &dipdw.diph);
    997 
    998     if (result == DI_POLLEDDEVICE) {
    999         /* This device doesn't support buffering, so we're forced
   1000          * to use less reliable polling. */
   1001         joystick->hwdata->buffered = SDL_FALSE;
   1002     } else if (FAILED(result)) {
   1003         return SetDIerror("IDirectInputDevice8::SetProperty", result);
   1004     }
   1005     return 0;
   1006 }
   1007 
   1008 static int
   1009 SDL_DINPUT_JoystickInitRumble(SDL_Joystick * joystick, Sint16 magnitude)
   1010 {
   1011     HRESULT result;
   1012 
   1013     /* Reset and then enable actuators */
   1014     result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_RESET);
   1015     if (result == DIERR_INPUTLOST || result == DIERR_NOTEXCLUSIVEACQUIRED) {
   1016         result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
   1017         if (SUCCEEDED(result)) {
   1018             result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_RESET);
   1019         }
   1020     }
   1021     if (FAILED(result)) {
   1022         return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand(DISFFC_RESET)", result);
   1023     }
   1024 
   1025     result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_SETACTUATORSON);
   1026     if (FAILED(result)) {
   1027         return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand(DISFFC_SETACTUATORSON)", result);
   1028     }
   1029 
   1030     /* Create the effect */
   1031     joystick->hwdata->ffeffect = CreateRumbleEffectData(magnitude);
   1032     if (!joystick->hwdata->ffeffect) {
   1033         return SDL_OutOfMemory();
   1034     }
   1035 
   1036     result = IDirectInputDevice8_CreateEffect(joystick->hwdata->InputDevice, &GUID_Sine,
   1037                                               joystick->hwdata->ffeffect, &joystick->hwdata->ffeffect_ref, NULL);
   1038     if (FAILED(result)) {
   1039         return SetDIerror("IDirectInputDevice8::CreateEffect", result);
   1040     }
   1041     return 0;
   1042 }
   1043 
   1044 int
   1045 SDL_DINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
   1046 {
   1047     HRESULT result;
   1048 
   1049     /* Scale and average the two rumble strengths */
   1050     Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
   1051 
   1052     if (!(joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK)) {
   1053         return SDL_Unsupported();
   1054     }
   1055 
   1056     if (joystick->hwdata->ff_initialized) {
   1057         DIPERIODIC *periodic = ((DIPERIODIC *)joystick->hwdata->ffeffect->lpvTypeSpecificParams);
   1058         periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude);
   1059 
   1060         result = IDirectInputEffect_SetParameters(joystick->hwdata->ffeffect_ref, joystick->hwdata->ffeffect, (DIEP_DURATION | DIEP_TYPESPECIFICPARAMS));
   1061         if (result == DIERR_INPUTLOST) {
   1062             result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
   1063             if (SUCCEEDED(result)) {
   1064                 result = IDirectInputEffect_SetParameters(joystick->hwdata->ffeffect_ref, joystick->hwdata->ffeffect, (DIEP_DURATION | DIEP_TYPESPECIFICPARAMS));
   1065             }
   1066         }
   1067         if (FAILED(result)) {
   1068             return SetDIerror("IDirectInputDevice8::SetParameters", result);
   1069         }
   1070     } else {
   1071         if (SDL_DINPUT_JoystickInitRumble(joystick, magnitude) < 0) {
   1072             return -1;
   1073         }
   1074         joystick->hwdata->ff_initialized = SDL_TRUE;
   1075     }
   1076 
   1077     result = IDirectInputEffect_Start(joystick->hwdata->ffeffect_ref, 1, 0);
   1078     if (result == DIERR_INPUTLOST || result == DIERR_NOTEXCLUSIVEACQUIRED) {
   1079         result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
   1080         if (SUCCEEDED(result)) {
   1081             result = IDirectInputEffect_Start(joystick->hwdata->ffeffect_ref, 1, 0);
   1082         }
   1083     }
   1084     if (FAILED(result)) {
   1085         return SetDIerror("IDirectInputDevice8::Start", result);
   1086     }
   1087     return 0;
   1088 }
   1089 
   1090 static Uint8
   1091 TranslatePOV(DWORD value)
   1092 {
   1093     const int HAT_VALS[] = {
   1094         SDL_HAT_UP,
   1095         SDL_HAT_UP | SDL_HAT_RIGHT,
   1096         SDL_HAT_RIGHT,
   1097         SDL_HAT_DOWN | SDL_HAT_RIGHT,
   1098         SDL_HAT_DOWN,
   1099         SDL_HAT_DOWN | SDL_HAT_LEFT,
   1100         SDL_HAT_LEFT,
   1101         SDL_HAT_UP | SDL_HAT_LEFT
   1102     };
   1103 
   1104     if (LOWORD(value) == 0xFFFF)
   1105         return SDL_HAT_CENTERED;
   1106 
   1107     /* Round the value up: */
   1108     value += 4500 / 2;
   1109     value %= 36000;
   1110     value /= 4500;
   1111 
   1112     if (value >= 8)
   1113         return SDL_HAT_CENTERED;        /* shouldn't happen */
   1114 
   1115     return HAT_VALS[value];
   1116 }
   1117 
   1118 static void
   1119 UpdateDINPUTJoystickState_Buffered(SDL_Joystick * joystick)
   1120 {
   1121     int i;
   1122     HRESULT result;
   1123     DWORD numevents;
   1124     DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
   1125 
   1126     numevents = INPUT_QSIZE;
   1127     result =
   1128         IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
   1129         sizeof(DIDEVICEOBJECTDATA), evtbuf,
   1130         &numevents, 0);
   1131     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
   1132         IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
   1133         result =
   1134             IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
   1135             sizeof(DIDEVICEOBJECTDATA),
   1136             evtbuf, &numevents, 0);
   1137     }
   1138 
   1139     /* Handle the events or punt */
   1140     if (FAILED(result)) {
   1141         return;
   1142     }
   1143 
   1144     for (i = 0; i < (int)numevents; ++i) {
   1145         int j;
   1146 
   1147         for (j = 0; j < joystick->hwdata->NumInputs; ++j) {
   1148             const input_t *in = &joystick->hwdata->Inputs[j];
   1149 
   1150             if (evtbuf[i].dwOfs != in->ofs)
   1151                 continue;
   1152 
   1153             switch (in->type) {
   1154             case AXIS:
   1155                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)evtbuf[i].dwData);
   1156                 break;
   1157             case BUTTON:
   1158                 SDL_PrivateJoystickButton(joystick, in->num,
   1159                     (Uint8)(evtbuf[i].dwData ? SDL_PRESSED : SDL_RELEASED));
   1160                 break;
   1161             case HAT:
   1162                 {
   1163                     Uint8 pos = TranslatePOV(evtbuf[i].dwData);
   1164                     SDL_PrivateJoystickHat(joystick, in->num, pos);
   1165                 }
   1166                 break;
   1167             }
   1168         }
   1169     }
   1170 }
   1171 
   1172 /* Function to update the state of a joystick - called as a device poll.
   1173  * This function shouldn't update the joystick structure directly,
   1174  * but instead should call SDL_PrivateJoystick*() to deliver events
   1175  * and update joystick device state.
   1176  */
   1177 static void
   1178 UpdateDINPUTJoystickState_Polled(SDL_Joystick * joystick)
   1179 {
   1180     DIJOYSTATE2 state;
   1181     HRESULT result;
   1182     int i;
   1183 
   1184     result =
   1185         IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
   1186         sizeof(DIJOYSTATE2), &state);
   1187     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
   1188         IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
   1189         result =
   1190             IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
   1191             sizeof(DIJOYSTATE2), &state);
   1192     }
   1193 
   1194     if (result != DI_OK) {
   1195         return;
   1196     }
   1197 
   1198     /* Set each known axis, button and POV. */
   1199     for (i = 0; i < joystick->hwdata->NumInputs; ++i) {
   1200         const input_t *in = &joystick->hwdata->Inputs[i];
   1201 
   1202         switch (in->type) {
   1203         case AXIS:
   1204             switch (in->ofs) {
   1205             case DIJOFS_X:
   1206                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lX);
   1207                 break;
   1208             case DIJOFS_Y:
   1209                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lY);
   1210                 break;
   1211             case DIJOFS_Z:
   1212                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lZ);
   1213                 break;
   1214             case DIJOFS_RX:
   1215                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRx);
   1216                 break;
   1217             case DIJOFS_RY:
   1218                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRy);
   1219                 break;
   1220             case DIJOFS_RZ:
   1221                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRz);
   1222                 break;
   1223             case DIJOFS_SLIDER(0):
   1224                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.rglSlider[0]);
   1225                 break;
   1226             case DIJOFS_SLIDER(1):
   1227                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.rglSlider[1]);
   1228                 break;
   1229             }
   1230             break;
   1231 
   1232         case BUTTON:
   1233             SDL_PrivateJoystickButton(joystick, in->num,
   1234                 (Uint8)(state.rgbButtons[in->ofs - DIJOFS_BUTTON0] ? SDL_PRESSED : SDL_RELEASED));
   1235             break;
   1236         case HAT:
   1237         {
   1238             Uint8 pos = TranslatePOV(state.rgdwPOV[in->ofs - DIJOFS_POV(0)]);
   1239             SDL_PrivateJoystickHat(joystick, in->num, pos);
   1240             break;
   1241         }
   1242         }
   1243     }
   1244 }
   1245 
   1246 void
   1247 SDL_DINPUT_JoystickUpdate(SDL_Joystick * joystick)
   1248 {
   1249     HRESULT result;
   1250 
   1251     result = IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
   1252     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
   1253         IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
   1254         IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
   1255     }
   1256 
   1257     if (joystick->hwdata->buffered) {
   1258         UpdateDINPUTJoystickState_Buffered(joystick);
   1259     } else {
   1260         UpdateDINPUTJoystickState_Polled(joystick);
   1261     }
   1262 }
   1263 
   1264 void
   1265 SDL_DINPUT_JoystickClose(SDL_Joystick * joystick)
   1266 {
   1267     if (joystick->hwdata->ffeffect_ref) {
   1268         IDirectInputEffect_Unload(joystick->hwdata->ffeffect_ref);
   1269         joystick->hwdata->ffeffect_ref = NULL;
   1270     }
   1271     if (joystick->hwdata->ffeffect) {
   1272         FreeRumbleEffectData(joystick->hwdata->ffeffect);
   1273         joystick->hwdata->ffeffect = NULL;
   1274     }
   1275     IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
   1276     IDirectInputDevice8_Release(joystick->hwdata->InputDevice);
   1277     joystick->hwdata->ff_initialized = SDL_FALSE;
   1278 }
   1279 
   1280 void
   1281 SDL_DINPUT_JoystickQuit(void)
   1282 {
   1283     if (dinput != NULL) {
   1284         IDirectInput8_Release(dinput);
   1285         dinput = NULL;
   1286     }
   1287 
   1288     if (coinitialized) {
   1289         WIN_CoUninitialize();
   1290         coinitialized = SDL_FALSE;
   1291     }
   1292 }
   1293 
   1294 #else /* !SDL_JOYSTICK_DINPUT */
   1295 
   1296 typedef struct JoyStick_DeviceData JoyStick_DeviceData;
   1297 
   1298 int
   1299 SDL_DINPUT_JoystickInit(void)
   1300 {
   1301     return 0;
   1302 }
   1303 
   1304 void
   1305 SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext)
   1306 {
   1307 }
   1308 
   1309 SDL_bool
   1310 SDL_DINPUT_JoystickPresent(Uint16 vendor, Uint16 product, Uint16 version)
   1311 {
   1312     return SDL_FALSE;
   1313 }
   1314 
   1315 int
   1316 SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice)
   1317 {
   1318     return SDL_Unsupported();
   1319 }
   1320 
   1321 int
   1322 SDL_DINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
   1323 {
   1324     return SDL_Unsupported();
   1325 }
   1326 
   1327 void
   1328 SDL_DINPUT_JoystickUpdate(SDL_Joystick * joystick)
   1329 {
   1330 }
   1331 
   1332 void
   1333 SDL_DINPUT_JoystickClose(SDL_Joystick * joystick)
   1334 {
   1335 }
   1336 
   1337 void
   1338 SDL_DINPUT_JoystickQuit(void)
   1339 {
   1340 }
   1341 
   1342 #endif /* SDL_JOYSTICK_DINPUT */
   1343 
   1344 /* vi: set ts=4 sw=4 expandtab: */