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