cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_dinputjoystick.c (38655B)


      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. */
     41extern HWND SDL_HelperWindow;
     42
     43/* local variables */
     44static SDL_bool coinitialized = SDL_FALSE;
     45static LPDIRECTINPUT8 dinput = NULL;
     46static PRAWINPUTDEVICELIST SDL_RawDevList = NULL;
     47static UINT SDL_RawDevListCount = 0;
     48
     49/* Taken from Wine - Thanks! */
     50static 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
    217const 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 */
    227static int
    228SetDIerror(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
    237static SDL_bool
    238SDL_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
    304int
    305SDL_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 */
    338static BOOL CALLBACK
    339EnumJoysticksCallback(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
    389void
    390SDL_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
    401static BOOL CALLBACK
    402EnumDevObjectsCallback(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 */
    488static int
    489SortDevFunc(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. */
    502static void
    503SortDevObjects(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
    533int
    534SDL_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
    664static Uint8
    665TranslatePOV(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
    692static void
    693UpdateDINPUTJoystickState_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 */
    753static void
    754UpdateDINPUTJoystickState_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
    824void
    825SDL_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
    842void
    843SDL_DINPUT_JoystickClose(SDL_Joystick * joystick)
    844{
    845    IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
    846    IDirectInputDevice8_Release(joystick->hwdata->InputDevice);
    847}
    848
    849void
    850SDL_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
    866int
    867SDL_DINPUT_JoystickInit(void)
    868{
    869    return 0;
    870}
    871
    872void
    873SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext)
    874{
    875}
    876
    877int
    878SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice)
    879{
    880    return SDL_Unsupported();
    881}
    882
    883void
    884SDL_DINPUT_JoystickUpdate(SDL_Joystick * joystick)
    885{
    886}
    887
    888void
    889SDL_DINPUT_JoystickClose(SDL_Joystick * joystick)
    890{
    891}
    892
    893void
    894SDL_DINPUT_JoystickQuit(void)
    895{
    896}
    897
    898#endif /* SDL_JOYSTICK_DINPUT */
    899
    900/* vi: set ts=4 sw=4 expandtab: */