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