src/joystick/windows/SDL_dinputjoystick.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 20 May 2020 16:58:33 -0400
changeset 13838 02e41b30186f
parent 13778 6c6a14452dcf
child 13914 348d0896fc9e
permissions -rw-r--r--
windows: Fix calls to CoCreateInstance() so last parameter is a LPVOID *.
     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     /*
   233     return SDL_SetError("%s() [%s]: %s", function,
   234     DXGetErrorString9A(code), DXGetErrorDescription9A(code));
   235     */
   236     return SDL_SetError("%s() DirectX error 0x%8.8lx", function, code);
   237 }
   238 
   239 #if 0 /* Microsoft recommended implementation, but slower than checking raw devices */
   240 #define COBJMACROS
   241 #include <wbemidl.h>
   242 #include <oleauto.h>
   243 
   244 static const IID CLSID_WbemLocator = { 0x4590f811, 0x1d3a, 0x11d0,{ 0x89, 0x1f, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24 } };
   245 static const IID IID_IWbemLocator = { 0xdc12a687, 0x737f, 0x11cf,{ 0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24 } };
   246 
   247 static SDL_bool
   248 WIN_IsXInputDevice(const WCHAR *name, const GUID* pGuidProductFromDirectInput)
   249 {
   250     IWbemLocator*           pIWbemLocator = NULL;
   251     IEnumWbemClassObject*   pEnumDevices = NULL;
   252     IWbemClassObject*       pDevices[20];
   253     IWbemServices*          pIWbemServices = NULL;
   254     BSTR                    bstrNamespace = NULL;
   255     BSTR                    bstrDeviceID = NULL;
   256     BSTR                    bstrClassName = NULL;
   257     DWORD                   uReturned = 0;
   258     SDL_bool                bIsXinputDevice = SDL_FALSE;
   259     UINT                    iDevice = 0;
   260     VARIANT                 var;
   261     HRESULT                 hr;
   262 
   263     if (!SDL_XINPUT_Enabled()) {
   264         return SDL_FALSE;
   265     }
   266 
   267     if (SDL_wcsstr(name, L" XINPUT ") != NULL) {
   268         /* This is a duplicate interface for a controller that will show up with XInput,
   269            e.g. Xbox One Elite Series 2 in Bluetooth mode.
   270          */
   271         return SDL_TRUE;
   272     }
   273 
   274     SDL_zeroa(pDevices);
   275 
   276     // Create WMI
   277     hr = CoCreateInstance(&CLSID_WbemLocator,
   278         NULL,
   279         CLSCTX_INPROC_SERVER,
   280         &IID_IWbemLocator,
   281         (LPVOID*)&pIWbemLocator);
   282     if (FAILED(hr) || pIWbemLocator == NULL)
   283         goto LCleanup;
   284 
   285     bstrNamespace = SysAllocString(L"\\\\.\\root\\cimv2"); if (bstrNamespace == NULL) goto LCleanup;
   286     bstrClassName = SysAllocString(L"Win32_PNPEntity");   if (bstrClassName == NULL) goto LCleanup;
   287     bstrDeviceID = SysAllocString(L"DeviceID");          if (bstrDeviceID == NULL)  goto LCleanup;
   288 
   289     // Connect to WMI 
   290     hr = IWbemLocator_ConnectServer(pIWbemLocator, bstrNamespace, NULL, NULL, 0L,
   291         0L, NULL, NULL, &pIWbemServices);
   292     if (FAILED(hr) || pIWbemServices == NULL) {
   293         goto LCleanup;
   294     }
   295 
   296     // Switch security level to IMPERSONATE. 
   297     CoSetProxyBlanket((IUnknown *)pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
   298         RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
   299 
   300     hr = IWbemServices_CreateInstanceEnum(pIWbemServices, bstrClassName, 0, NULL, &pEnumDevices);
   301     if (FAILED(hr) || pEnumDevices == NULL)
   302         goto LCleanup;
   303 
   304     // Loop over all devices
   305     for (;;) {
   306         // Get 20 at a time
   307         hr = IEnumWbemClassObject_Next(pEnumDevices, 10000, SDL_arraysize(pDevices), pDevices, &uReturned);
   308         if (FAILED(hr)) {
   309             goto LCleanup;
   310         }
   311         if (uReturned == 0) {
   312             break;
   313         }
   314 
   315         for (iDevice = 0; iDevice < uReturned; iDevice++) {
   316             // For each device, get its device ID
   317             hr = IWbemClassObject_Get(pDevices[iDevice], bstrDeviceID, 0L, &var, NULL, NULL);
   318             if (SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != NULL) {
   319                 // Check if the device ID contains "IG_".  If it does, then it's an XInput device
   320                 // This information can not be found from DirectInput 
   321                 if (SDL_wcsstr(var.bstrVal, L"IG_")) {
   322                     char *bstrVal = WIN_StringToUTF8(var.bstrVal);
   323 
   324                     // If it does, then get the VID/PID from var.bstrVal
   325                     DWORD dwPid = 0, dwVid = 0, dwVidPid;
   326                     const char *strVid, *strPid;
   327                     strVid = SDL_strstr(bstrVal, "VID_");
   328                     if (strVid && SDL_sscanf(strVid, "VID_%4X", &dwVid) != 1)
   329                         dwVid = 0;
   330                     strPid = SDL_strstr(bstrVal, "PID_");
   331                     if (strPid && SDL_sscanf(strPid, "PID_%4X", &dwPid) != 1)
   332                         dwPid = 0;
   333 
   334                     SDL_free(bstrVal);
   335 
   336                     // Compare the VID/PID to the DInput device
   337                     dwVidPid = MAKELONG(dwVid, dwPid);
   338                     if (dwVidPid == pGuidProductFromDirectInput->Data1) {
   339                         bIsXinputDevice = SDL_TRUE;
   340                         goto LCleanup;
   341                     }
   342                 }
   343             }
   344             IWbemClassObject_Release(pDevices[iDevice]);
   345         }
   346     }
   347 
   348 LCleanup:
   349     if (bstrNamespace) {
   350         SysFreeString(bstrNamespace);
   351     }
   352     if (bstrDeviceID) {
   353         SysFreeString(bstrDeviceID);
   354     }
   355     if (bstrClassName) {
   356         SysFreeString(bstrClassName);
   357     }
   358     for (iDevice = 0; iDevice < SDL_arraysize(pDevices); iDevice++) {
   359         if (pDevices[iDevice]) {
   360             IWbemClassObject_Release(pDevices[iDevice]);
   361         }
   362     }
   363     if (pEnumDevices) {
   364         IEnumWbemClassObject_Release(pEnumDevices);
   365     }
   366     if (pIWbemLocator) {
   367         IWbemLocator_Release(pIWbemLocator);
   368     }
   369     if (pIWbemServices) {
   370         IWbemServices_Release(pIWbemServices);
   371     }
   372 
   373     return bIsXinputDevice;
   374 }
   375 #endif /* 0 */
   376 
   377 static SDL_bool
   378 SDL_IsXInputDevice(const WCHAR *name, const GUID* pGuidProductFromDirectInput)
   379 {
   380     UINT i;
   381 
   382     if (!SDL_XINPUT_Enabled()) {
   383         return SDL_FALSE;
   384     }
   385 
   386     if (SDL_wcsstr(name, L" XINPUT ") != NULL) {
   387         /* This is a duplicate interface for a controller that will show up with XInput,
   388            e.g. Xbox One Elite Series 2 in Bluetooth mode.
   389          */
   390         return SDL_TRUE;
   391     }
   392 
   393     if (SDL_memcmp(&pGuidProductFromDirectInput->Data4[2], "PIDVID", 6) == 0) {
   394         Uint16 vendor_id = (Uint16)LOWORD(pGuidProductFromDirectInput->Data1);
   395         Uint16 product_id = (Uint16)HIWORD(pGuidProductFromDirectInput->Data1);
   396         SDL_GameControllerType type = SDL_GetJoystickGameControllerType("", vendor_id, product_id, -1, 0, 0, 0);
   397         if (type == SDL_CONTROLLER_TYPE_XBOX360 ||
   398             type == SDL_CONTROLLER_TYPE_XBOXONE ||
   399             (vendor_id == 0x28DE && product_id == 0x11FF)) {
   400             return SDL_TRUE;
   401         }
   402     }
   403 
   404     /* Go through RAWINPUT (WinXP and later) to find HID devices. */
   405     /* Cache this if we end up using it. */
   406     if (SDL_RawDevList == NULL) {
   407         if ((GetRawInputDeviceList(NULL, &SDL_RawDevListCount, sizeof(RAWINPUTDEVICELIST)) == -1) || (!SDL_RawDevListCount)) {
   408             return SDL_FALSE;  /* oh well. */
   409         }
   410 
   411         SDL_RawDevList = (PRAWINPUTDEVICELIST)SDL_malloc(sizeof(RAWINPUTDEVICELIST) * SDL_RawDevListCount);
   412         if (SDL_RawDevList == NULL) {
   413             SDL_OutOfMemory();
   414             return SDL_FALSE;
   415         }
   416 
   417         if (GetRawInputDeviceList(SDL_RawDevList, &SDL_RawDevListCount, sizeof(RAWINPUTDEVICELIST)) == -1) {
   418             SDL_free(SDL_RawDevList);
   419             SDL_RawDevList = NULL;
   420             return SDL_FALSE;  /* oh well. */
   421         }
   422     }
   423 
   424     for (i = 0; i < SDL_RawDevListCount; i++) {
   425         RID_DEVICE_INFO rdi;
   426         char devName[128];
   427         UINT rdiSize = sizeof(rdi);
   428         UINT nameSize = SDL_arraysize(devName);
   429 
   430         rdi.cbSize = sizeof(rdi);
   431         if ((SDL_RawDevList[i].dwType == RIM_TYPEHID) &&
   432             (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != ((UINT)-1)) &&
   433             (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == ((LONG)pGuidProductFromDirectInput->Data1)) &&
   434             (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != ((UINT)-1)) &&
   435             (SDL_strstr(devName, "IG_") != NULL)) {
   436             return SDL_TRUE;
   437         }
   438     }
   439 
   440     return SDL_FALSE;
   441 }
   442 
   443 void FreeRumbleEffectData(DIEFFECT *effect)
   444 {
   445     if (!effect) {
   446         return;
   447     }
   448     SDL_free(effect->rgdwAxes);
   449     SDL_free(effect->rglDirection);
   450     SDL_free(effect->lpvTypeSpecificParams);
   451     SDL_free(effect);
   452 }
   453 
   454 DIEFFECT *CreateRumbleEffectData(Sint16 magnitude)
   455 {
   456     DIEFFECT *effect;
   457     DIPERIODIC *periodic;
   458 
   459     /* Create the effect */
   460     effect = (DIEFFECT *)SDL_calloc(1, sizeof(*effect));
   461     if (!effect) {
   462         return NULL;
   463     }
   464     effect->dwSize = sizeof(*effect);
   465     effect->dwGain = 10000;
   466     effect->dwFlags = DIEFF_OBJECTOFFSETS;
   467     effect->dwDuration = SDL_MAX_RUMBLE_DURATION_MS * 1000; /* In microseconds. */
   468     effect->dwTriggerButton = DIEB_NOTRIGGER;
   469 
   470     effect->cAxes = 2;
   471     effect->rgdwAxes = (DWORD *)SDL_calloc(effect->cAxes, sizeof(DWORD));
   472     if (!effect->rgdwAxes) {
   473         FreeRumbleEffectData(effect);
   474         return NULL;
   475     }
   476 
   477     effect->rglDirection = (LONG *)SDL_calloc(effect->cAxes, sizeof(LONG));
   478     if (!effect->rglDirection) {
   479         FreeRumbleEffectData(effect);
   480         return NULL;
   481     }
   482     effect->dwFlags |= DIEFF_CARTESIAN;
   483 
   484     periodic = (DIPERIODIC *)SDL_calloc(1, sizeof(*periodic));
   485     if (!periodic) {
   486         FreeRumbleEffectData(effect);
   487         return NULL;
   488     }
   489     periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude);
   490     periodic->dwPeriod = 1000000;
   491 
   492     effect->cbTypeSpecificParams = sizeof(*periodic);
   493     effect->lpvTypeSpecificParams = periodic;
   494 
   495     return effect;
   496 }
   497 
   498 int
   499 SDL_DINPUT_JoystickInit(void)
   500 {
   501     HRESULT result;
   502     HINSTANCE instance;
   503 
   504     result = WIN_CoInitialize();
   505     if (FAILED(result)) {
   506         return SetDIerror("CoInitialize", result);
   507     }
   508 
   509     coinitialized = SDL_TRUE;
   510 
   511     result = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER,
   512         &IID_IDirectInput8, (LPVOID *)&dinput);
   513 
   514     if (FAILED(result)) {
   515         return SetDIerror("CoCreateInstance", result);
   516     }
   517 
   518     /* Because we used CoCreateInstance, we need to Initialize it, first. */
   519     instance = GetModuleHandle(NULL);
   520     if (instance == NULL) {
   521         return SDL_SetError("GetModuleHandle() failed with error code %lu.", GetLastError());
   522     }
   523     result = IDirectInput8_Initialize(dinput, instance, DIRECTINPUT_VERSION);
   524 
   525     if (FAILED(result)) {
   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             pNewJoystick->dxdevice = *pdidInstance;
   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)) {
   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     data.vendor = vendor;
   734     data.product = product;
   735     data.version = version;
   736     data.present = SDL_FALSE;
   737     IDirectInput8_EnumDevices(dinput, DI8DEVCLASS_GAMECTRL, EnumJoystickPresentCallback, &data, DIEDFL_ATTACHEDONLY);
   738 
   739     return data.present;
   740 }
   741 
   742 static BOOL CALLBACK
   743 EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
   744 {
   745     SDL_Joystick *joystick = (SDL_Joystick *)pvRef;
   746     HRESULT result;
   747     input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs];
   748 
   749     if (dev->dwType & DIDFT_BUTTON) {
   750         in->type = BUTTON;
   751         in->num = joystick->nbuttons;
   752         in->ofs = DIJOFS_BUTTON(in->num);
   753         joystick->nbuttons++;
   754     } else if (dev->dwType & DIDFT_POV) {
   755         in->type = HAT;
   756         in->num = joystick->nhats;
   757         in->ofs = DIJOFS_POV(in->num);
   758         joystick->nhats++;
   759     } else if (dev->dwType & DIDFT_AXIS) {
   760         DIPROPRANGE diprg;
   761         DIPROPDWORD dilong;
   762 
   763         in->type = AXIS;
   764         in->num = joystick->naxes;
   765         if (!SDL_memcmp(&dev->guidType, &GUID_XAxis, sizeof(dev->guidType)))
   766             in->ofs = DIJOFS_X;
   767         else if (!SDL_memcmp(&dev->guidType, &GUID_YAxis, sizeof(dev->guidType)))
   768             in->ofs = DIJOFS_Y;
   769         else if (!SDL_memcmp(&dev->guidType, &GUID_ZAxis, sizeof(dev->guidType)))
   770             in->ofs = DIJOFS_Z;
   771         else if (!SDL_memcmp(&dev->guidType, &GUID_RxAxis, sizeof(dev->guidType)))
   772             in->ofs = DIJOFS_RX;
   773         else if (!SDL_memcmp(&dev->guidType, &GUID_RyAxis, sizeof(dev->guidType)))
   774             in->ofs = DIJOFS_RY;
   775         else if (!SDL_memcmp(&dev->guidType, &GUID_RzAxis, sizeof(dev->guidType)))
   776             in->ofs = DIJOFS_RZ;
   777         else if (!SDL_memcmp(&dev->guidType, &GUID_Slider, sizeof(dev->guidType))) {
   778             in->ofs = DIJOFS_SLIDER(joystick->hwdata->NumSliders);
   779             ++joystick->hwdata->NumSliders;
   780         } else {
   781             return DIENUM_CONTINUE; /* not an axis we can grok */
   782         }
   783 
   784         diprg.diph.dwSize = sizeof(diprg);
   785         diprg.diph.dwHeaderSize = sizeof(diprg.diph);
   786         diprg.diph.dwObj = dev->dwType;
   787         diprg.diph.dwHow = DIPH_BYID;
   788         diprg.lMin = SDL_JOYSTICK_AXIS_MIN;
   789         diprg.lMax = SDL_JOYSTICK_AXIS_MAX;
   790 
   791         result =
   792             IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
   793             DIPROP_RANGE, &diprg.diph);
   794         if (FAILED(result)) {
   795             return DIENUM_CONTINUE;     /* don't use this axis */
   796         }
   797 
   798         /* Set dead zone to 0. */
   799         dilong.diph.dwSize = sizeof(dilong);
   800         dilong.diph.dwHeaderSize = sizeof(dilong.diph);
   801         dilong.diph.dwObj = dev->dwType;
   802         dilong.diph.dwHow = DIPH_BYID;
   803         dilong.dwData = 0;
   804         result =
   805             IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
   806             DIPROP_DEADZONE, &dilong.diph);
   807         if (FAILED(result)) {
   808             return DIENUM_CONTINUE;     /* don't use this axis */
   809         }
   810 
   811         joystick->naxes++;
   812     } else {
   813         /* not supported at this time */
   814         return DIENUM_CONTINUE;
   815     }
   816 
   817     joystick->hwdata->NumInputs++;
   818 
   819     if (joystick->hwdata->NumInputs == MAX_INPUTS) {
   820         return DIENUM_STOP;     /* too many */
   821     }
   822 
   823     return DIENUM_CONTINUE;
   824 }
   825 
   826 /* Sort using the data offset into the DInput struct.
   827  * This gives a reasonable ordering for the inputs.
   828  */
   829 static int
   830 SortDevFunc(const void *a, const void *b)
   831 {
   832     const input_t *inputA = (const input_t*)a;
   833     const input_t *inputB = (const input_t*)b;
   834 
   835     if (inputA->ofs < inputB->ofs)
   836         return -1;
   837     if (inputA->ofs > inputB->ofs)
   838         return 1;
   839     return 0;
   840 }
   841 
   842 /* Sort the input objects and recalculate the indices for each input. */
   843 static void
   844 SortDevObjects(SDL_Joystick *joystick)
   845 {
   846     input_t *inputs = joystick->hwdata->Inputs;
   847     int nButtons = 0;
   848     int nHats = 0;
   849     int nAxis = 0;
   850     int n;
   851 
   852     SDL_qsort(inputs, joystick->hwdata->NumInputs, sizeof(input_t), SortDevFunc);
   853 
   854     for (n = 0; n < joystick->hwdata->NumInputs; n++) {
   855         switch (inputs[n].type) {
   856         case BUTTON:
   857             inputs[n].num = nButtons;
   858             nButtons++;
   859             break;
   860 
   861         case HAT:
   862             inputs[n].num = nHats;
   863             nHats++;
   864             break;
   865 
   866         case AXIS:
   867             inputs[n].num = nAxis;
   868             nAxis++;
   869             break;
   870         }
   871     }
   872 }
   873 
   874 int
   875 SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice)
   876 {
   877     HRESULT result;
   878     LPDIRECTINPUTDEVICE8 device;
   879     DIPROPDWORD dipdw;
   880 
   881     joystick->hwdata->buffered = SDL_TRUE;
   882     joystick->hwdata->Capabilities.dwSize = sizeof(DIDEVCAPS);
   883 
   884     SDL_zero(dipdw);
   885     dipdw.diph.dwSize = sizeof(DIPROPDWORD);
   886     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
   887 
   888     result =
   889         IDirectInput8_CreateDevice(dinput,
   890         &(joystickdevice->dxdevice.guidInstance), &device, NULL);
   891     if (FAILED(result)) {
   892         return SetDIerror("IDirectInput::CreateDevice", result);
   893     }
   894 
   895     /* Now get the IDirectInputDevice8 interface, instead. */
   896     result = IDirectInputDevice8_QueryInterface(device,
   897         &IID_IDirectInputDevice8,
   898         (LPVOID *)& joystick->
   899         hwdata->InputDevice);
   900     /* We are done with this object.  Use the stored one from now on. */
   901     IDirectInputDevice8_Release(device);
   902 
   903     if (FAILED(result)) {
   904         return SetDIerror("IDirectInputDevice8::QueryInterface", result);
   905     }
   906 
   907     /* Acquire shared access. Exclusive access is required for forces,
   908     * though. */
   909     result =
   910         IDirectInputDevice8_SetCooperativeLevel(joystick->hwdata->
   911         InputDevice, SDL_HelperWindow,
   912         DISCL_EXCLUSIVE |
   913         DISCL_BACKGROUND);
   914     if (FAILED(result)) {
   915         return SetDIerror("IDirectInputDevice8::SetCooperativeLevel", result);
   916     }
   917 
   918     /* Use the extended data structure: DIJOYSTATE2. */
   919     result =
   920         IDirectInputDevice8_SetDataFormat(joystick->hwdata->InputDevice,
   921         &SDL_c_dfDIJoystick2);
   922     if (FAILED(result)) {
   923         return SetDIerror("IDirectInputDevice8::SetDataFormat", result);
   924     }
   925 
   926     /* Get device capabilities */
   927     result =
   928         IDirectInputDevice8_GetCapabilities(joystick->hwdata->InputDevice,
   929         &joystick->hwdata->Capabilities);
   930     if (FAILED(result)) {
   931         return SetDIerror("IDirectInputDevice8::GetCapabilities", result);
   932     }
   933 
   934     /* Force capable? */
   935     if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
   936         result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
   937         if (FAILED(result)) {
   938             return SetDIerror("IDirectInputDevice8::Acquire", result);
   939         }
   940 
   941         /* reset all actuators. */
   942         result =
   943             IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->
   944             InputDevice,
   945             DISFFC_RESET);
   946 
   947         /* Not necessarily supported, ignore if not supported.
   948         if (FAILED(result)) {
   949         return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand", result);
   950         }
   951         */
   952 
   953         result = IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
   954 
   955         if (FAILED(result)) {
   956             return SetDIerror("IDirectInputDevice8::Unacquire", result);
   957         }
   958 
   959         /* Turn on auto-centering for a ForceFeedback device (until told
   960         * otherwise). */
   961         dipdw.diph.dwObj = 0;
   962         dipdw.diph.dwHow = DIPH_DEVICE;
   963         dipdw.dwData = DIPROPAUTOCENTER_ON;
   964 
   965         result =
   966             IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
   967             DIPROP_AUTOCENTER, &dipdw.diph);
   968 
   969         /* Not necessarily supported, ignore if not supported.
   970         if (FAILED(result)) {
   971         return SetDIerror("IDirectInputDevice8::SetProperty", result);
   972         }
   973         */
   974     }
   975 
   976     /* What buttons and axes does it have? */
   977     IDirectInputDevice8_EnumObjects(joystick->hwdata->InputDevice,
   978         EnumDevObjectsCallback, joystick,
   979         DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV);
   980 
   981     /* Reorder the input objects. Some devices do not report the X axis as
   982     * the first axis, for example. */
   983     SortDevObjects(joystick);
   984 
   985     dipdw.diph.dwObj = 0;
   986     dipdw.diph.dwHow = DIPH_DEVICE;
   987     dipdw.dwData = INPUT_QSIZE;
   988 
   989     /* Set the buffer size */
   990     result =
   991         IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
   992         DIPROP_BUFFERSIZE, &dipdw.diph);
   993 
   994     if (result == DI_POLLEDDEVICE) {
   995         /* This device doesn't support buffering, so we're forced
   996          * to use less reliable polling. */
   997         joystick->hwdata->buffered = SDL_FALSE;
   998     } else if (FAILED(result)) {
   999         return SetDIerror("IDirectInputDevice8::SetProperty", result);
  1000     }
  1001     return 0;
  1002 }
  1003 
  1004 static int
  1005 SDL_DINPUT_JoystickInitRumble(SDL_Joystick * joystick, Sint16 magnitude)
  1006 {
  1007     HRESULT result;
  1008 
  1009     /* Reset and then enable actuators */
  1010     result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_RESET);
  1011     if (result == DIERR_INPUTLOST || result == DIERR_NOTEXCLUSIVEACQUIRED) {
  1012         result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
  1013         if (SUCCEEDED(result)) {
  1014             result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_RESET);
  1015         }
  1016     }
  1017     if (FAILED(result)) {
  1018         return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand(DISFFC_RESET)", result);
  1019     }
  1020 
  1021     result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_SETACTUATORSON);
  1022     if (FAILED(result)) {
  1023         return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand(DISFFC_SETACTUATORSON)", result);
  1024     }
  1025 
  1026     /* Create the effect */
  1027     joystick->hwdata->ffeffect = CreateRumbleEffectData(magnitude);
  1028     if (!joystick->hwdata->ffeffect) {
  1029         return SDL_OutOfMemory();
  1030     }
  1031 
  1032     result = IDirectInputDevice8_CreateEffect(joystick->hwdata->InputDevice, &GUID_Sine,
  1033                                               joystick->hwdata->ffeffect, &joystick->hwdata->ffeffect_ref, NULL);
  1034     if (FAILED(result)) {
  1035         return SetDIerror("IDirectInputDevice8::CreateEffect", result);
  1036     }
  1037     return 0;
  1038 }
  1039 
  1040 int
  1041 SDL_DINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
  1042 {
  1043     HRESULT result;
  1044 
  1045     /* Scale and average the two rumble strengths */
  1046     Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
  1047 
  1048     if (!(joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK)) {
  1049         return SDL_Unsupported();
  1050     }
  1051 
  1052     if (joystick->hwdata->ff_initialized) {
  1053         DIPERIODIC *periodic = ((DIPERIODIC *)joystick->hwdata->ffeffect->lpvTypeSpecificParams);
  1054         periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude);
  1055 
  1056         result = IDirectInputEffect_SetParameters(joystick->hwdata->ffeffect_ref, joystick->hwdata->ffeffect, (DIEP_DURATION | DIEP_TYPESPECIFICPARAMS));
  1057         if (result == DIERR_INPUTLOST) {
  1058             result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
  1059             if (SUCCEEDED(result)) {
  1060                 result = IDirectInputEffect_SetParameters(joystick->hwdata->ffeffect_ref, joystick->hwdata->ffeffect, (DIEP_DURATION | DIEP_TYPESPECIFICPARAMS));
  1061             }
  1062         }
  1063         if (FAILED(result)) {
  1064             return SetDIerror("IDirectInputDevice8::SetParameters", result);
  1065         }
  1066     } else {
  1067         if (SDL_DINPUT_JoystickInitRumble(joystick, magnitude) < 0) {
  1068             return -1;
  1069         }
  1070         joystick->hwdata->ff_initialized = SDL_TRUE;
  1071     }
  1072 
  1073     result = IDirectInputEffect_Start(joystick->hwdata->ffeffect_ref, 1, 0);
  1074     if (result == DIERR_INPUTLOST || result == DIERR_NOTEXCLUSIVEACQUIRED) {
  1075         result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
  1076         if (SUCCEEDED(result)) {
  1077             result = IDirectInputEffect_Start(joystick->hwdata->ffeffect_ref, 1, 0);
  1078         }
  1079     }
  1080     if (FAILED(result)) {
  1081         return SetDIerror("IDirectInputDevice8::Start", result);
  1082     }
  1083     return 0;
  1084 }
  1085 
  1086 static Uint8
  1087 TranslatePOV(DWORD value)
  1088 {
  1089     const int HAT_VALS[] = {
  1090         SDL_HAT_UP,
  1091         SDL_HAT_UP | SDL_HAT_RIGHT,
  1092         SDL_HAT_RIGHT,
  1093         SDL_HAT_DOWN | SDL_HAT_RIGHT,
  1094         SDL_HAT_DOWN,
  1095         SDL_HAT_DOWN | SDL_HAT_LEFT,
  1096         SDL_HAT_LEFT,
  1097         SDL_HAT_UP | SDL_HAT_LEFT
  1098     };
  1099 
  1100     if (LOWORD(value) == 0xFFFF)
  1101         return SDL_HAT_CENTERED;
  1102 
  1103     /* Round the value up: */
  1104     value += 4500 / 2;
  1105     value %= 36000;
  1106     value /= 4500;
  1107 
  1108     if (value >= 8)
  1109         return SDL_HAT_CENTERED;        /* shouldn't happen */
  1110 
  1111     return HAT_VALS[value];
  1112 }
  1113 
  1114 static void
  1115 UpdateDINPUTJoystickState_Buffered(SDL_Joystick * joystick)
  1116 {
  1117     int i;
  1118     HRESULT result;
  1119     DWORD numevents;
  1120     DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
  1121 
  1122     numevents = INPUT_QSIZE;
  1123     result =
  1124         IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
  1125         sizeof(DIDEVICEOBJECTDATA), evtbuf,
  1126         &numevents, 0);
  1127     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
  1128         IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
  1129         result =
  1130             IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
  1131             sizeof(DIDEVICEOBJECTDATA),
  1132             evtbuf, &numevents, 0);
  1133     }
  1134 
  1135     /* Handle the events or punt */
  1136     if (FAILED(result)) {
  1137         return;
  1138     }
  1139 
  1140     for (i = 0; i < (int)numevents; ++i) {
  1141         int j;
  1142 
  1143         for (j = 0; j < joystick->hwdata->NumInputs; ++j) {
  1144             const input_t *in = &joystick->hwdata->Inputs[j];
  1145 
  1146             if (evtbuf[i].dwOfs != in->ofs)
  1147                 continue;
  1148 
  1149             switch (in->type) {
  1150             case AXIS:
  1151                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)evtbuf[i].dwData);
  1152                 break;
  1153             case BUTTON:
  1154                 SDL_PrivateJoystickButton(joystick, in->num,
  1155                     (Uint8)(evtbuf[i].dwData ? SDL_PRESSED : SDL_RELEASED));
  1156                 break;
  1157             case HAT:
  1158                 {
  1159                     Uint8 pos = TranslatePOV(evtbuf[i].dwData);
  1160                     SDL_PrivateJoystickHat(joystick, in->num, pos);
  1161                 }
  1162                 break;
  1163             }
  1164         }
  1165     }
  1166 }
  1167 
  1168 /* Function to update the state of a joystick - called as a device poll.
  1169  * This function shouldn't update the joystick structure directly,
  1170  * but instead should call SDL_PrivateJoystick*() to deliver events
  1171  * and update joystick device state.
  1172  */
  1173 static void
  1174 UpdateDINPUTJoystickState_Polled(SDL_Joystick * joystick)
  1175 {
  1176     DIJOYSTATE2 state;
  1177     HRESULT result;
  1178     int i;
  1179 
  1180     result =
  1181         IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
  1182         sizeof(DIJOYSTATE2), &state);
  1183     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
  1184         IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
  1185         result =
  1186             IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
  1187             sizeof(DIJOYSTATE2), &state);
  1188     }
  1189 
  1190     if (result != DI_OK) {
  1191         return;
  1192     }
  1193 
  1194     /* Set each known axis, button and POV. */
  1195     for (i = 0; i < joystick->hwdata->NumInputs; ++i) {
  1196         const input_t *in = &joystick->hwdata->Inputs[i];
  1197 
  1198         switch (in->type) {
  1199         case AXIS:
  1200             switch (in->ofs) {
  1201             case DIJOFS_X:
  1202                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lX);
  1203                 break;
  1204             case DIJOFS_Y:
  1205                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lY);
  1206                 break;
  1207             case DIJOFS_Z:
  1208                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lZ);
  1209                 break;
  1210             case DIJOFS_RX:
  1211                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRx);
  1212                 break;
  1213             case DIJOFS_RY:
  1214                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRy);
  1215                 break;
  1216             case DIJOFS_RZ:
  1217                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRz);
  1218                 break;
  1219             case DIJOFS_SLIDER(0):
  1220                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.rglSlider[0]);
  1221                 break;
  1222             case DIJOFS_SLIDER(1):
  1223                 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.rglSlider[1]);
  1224                 break;
  1225             }
  1226             break;
  1227 
  1228         case BUTTON:
  1229             SDL_PrivateJoystickButton(joystick, in->num,
  1230                 (Uint8)(state.rgbButtons[in->ofs - DIJOFS_BUTTON0] ? SDL_PRESSED : SDL_RELEASED));
  1231             break;
  1232         case HAT:
  1233         {
  1234             Uint8 pos = TranslatePOV(state.rgdwPOV[in->ofs - DIJOFS_POV(0)]);
  1235             SDL_PrivateJoystickHat(joystick, in->num, pos);
  1236             break;
  1237         }
  1238         }
  1239     }
  1240 }
  1241 
  1242 void
  1243 SDL_DINPUT_JoystickUpdate(SDL_Joystick * joystick)
  1244 {
  1245     HRESULT result;
  1246 
  1247     result = IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
  1248     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
  1249         IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
  1250         IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
  1251     }
  1252 
  1253     if (joystick->hwdata->buffered) {
  1254         UpdateDINPUTJoystickState_Buffered(joystick);
  1255     } else {
  1256         UpdateDINPUTJoystickState_Polled(joystick);
  1257     }
  1258 }
  1259 
  1260 void
  1261 SDL_DINPUT_JoystickClose(SDL_Joystick * joystick)
  1262 {
  1263     if (joystick->hwdata->ffeffect_ref) {
  1264         IDirectInputEffect_Unload(joystick->hwdata->ffeffect_ref);
  1265         joystick->hwdata->ffeffect_ref = NULL;
  1266     }
  1267     if (joystick->hwdata->ffeffect) {
  1268         FreeRumbleEffectData(joystick->hwdata->ffeffect);
  1269         joystick->hwdata->ffeffect = NULL;
  1270     }
  1271     IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
  1272     IDirectInputDevice8_Release(joystick->hwdata->InputDevice);
  1273     joystick->hwdata->ff_initialized = SDL_FALSE;
  1274 }
  1275 
  1276 void
  1277 SDL_DINPUT_JoystickQuit(void)
  1278 {
  1279     if (dinput != NULL) {
  1280         IDirectInput8_Release(dinput);
  1281         dinput = NULL;
  1282     }
  1283 
  1284     if (coinitialized) {
  1285         WIN_CoUninitialize();
  1286         coinitialized = SDL_FALSE;
  1287     }
  1288 }
  1289 
  1290 #else /* !SDL_JOYSTICK_DINPUT */
  1291 
  1292 typedef struct JoyStick_DeviceData JoyStick_DeviceData;
  1293 
  1294 int
  1295 SDL_DINPUT_JoystickInit(void)
  1296 {
  1297     return 0;
  1298 }
  1299 
  1300 void
  1301 SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext)
  1302 {
  1303 }
  1304 
  1305 SDL_bool
  1306 SDL_DINPUT_JoystickPresent(Uint16 vendor, Uint16 product, Uint16 version)
  1307 {
  1308     return SDL_FALSE;
  1309 }
  1310 
  1311 int
  1312 SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice)
  1313 {
  1314     return SDL_Unsupported();
  1315 }
  1316 
  1317 int
  1318 SDL_DINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
  1319 {
  1320     return SDL_Unsupported();
  1321 }
  1322 
  1323 void
  1324 SDL_DINPUT_JoystickUpdate(SDL_Joystick * joystick)
  1325 {
  1326 }
  1327 
  1328 void
  1329 SDL_DINPUT_JoystickClose(SDL_Joystick * joystick)
  1330 {
  1331 }
  1332 
  1333 void
  1334 SDL_DINPUT_JoystickQuit(void)
  1335 {
  1336 }
  1337 
  1338 #endif /* SDL_JOYSTICK_DINPUT */
  1339 
  1340 /* vi: set ts=4 sw=4 expandtab: */