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