Atlas - SDL_dinputjoystick.c
Home / ext / SDL2 / src / joystick / windows Lines: 1 | Size: 48228 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "../../SDL_internal.h" 22 23#include "../SDL_sysjoystick.h" 24 25#if SDL_JOYSTICK_DINPUT 26 27#include "SDL_windowsjoystick_c.h" 28#include "SDL_dinputjoystick_c.h" 29#include "SDL_xinputjoystick_c.h" 30#include "../hidapi/SDL_hidapijoystick_c.h" 31 32#ifndef DIDFT_OPTIONAL 33#define DIDFT_OPTIONAL 0x80000000 34#endif 35 36#define INPUT_QSIZE 32 /* Buffer up to 32 input messages */ 37#define JOY_AXIS_THRESHOLD (((SDL_JOYSTICK_AXIS_MAX)-(SDL_JOYSTICK_AXIS_MIN))/100) /* 1% motion */ 38 39#define CONVERT_MAGNITUDE(x) (((x)*10000) / 0x7FFF) 40 41/* external variables referenced. */ 42extern HWND SDL_HelperWindow; 43 44/* local variables */ 45static SDL_bool coinitialized = SDL_FALSE; 46static LPDIRECTINPUT8 dinput = NULL; 47static PRAWINPUTDEVICELIST SDL_RawDevList = NULL; 48static UINT SDL_RawDevListCount = 0; 49 50/* Taken from Wine - Thanks! */ 51static DIOBJECTDATAFORMAT dfDIJoystick2[] = { 52 { &GUID_XAxis, DIJOFS_X, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 53 { &GUID_YAxis, DIJOFS_Y, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 54 { &GUID_ZAxis, DIJOFS_Z, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 55 { &GUID_RxAxis, DIJOFS_RX, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 56 { &GUID_RyAxis, DIJOFS_RY, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 57 { &GUID_RzAxis, DIJOFS_RZ, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 58 { &GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 59 { &GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 60 { &GUID_POV, DIJOFS_POV(0), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 }, 61 { &GUID_POV, DIJOFS_POV(1), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 }, 62 { &GUID_POV, DIJOFS_POV(2), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 }, 63 { &GUID_POV, DIJOFS_POV(3), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 }, 64 { NULL, DIJOFS_BUTTON(0), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 65 { NULL, DIJOFS_BUTTON(1), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 66 { NULL, DIJOFS_BUTTON(2), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 67 { NULL, DIJOFS_BUTTON(3), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 68 { NULL, DIJOFS_BUTTON(4), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 69 { NULL, DIJOFS_BUTTON(5), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 70 { NULL, DIJOFS_BUTTON(6), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 71 { NULL, DIJOFS_BUTTON(7), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 72 { NULL, DIJOFS_BUTTON(8), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 73 { NULL, DIJOFS_BUTTON(9), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 74 { NULL, DIJOFS_BUTTON(10), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 75 { NULL, DIJOFS_BUTTON(11), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 76 { NULL, DIJOFS_BUTTON(12), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 77 { NULL, DIJOFS_BUTTON(13), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 78 { NULL, DIJOFS_BUTTON(14), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 79 { NULL, DIJOFS_BUTTON(15), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 80 { NULL, DIJOFS_BUTTON(16), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 81 { NULL, DIJOFS_BUTTON(17), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 82 { NULL, DIJOFS_BUTTON(18), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 83 { NULL, DIJOFS_BUTTON(19), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 84 { NULL, DIJOFS_BUTTON(20), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 85 { NULL, DIJOFS_BUTTON(21), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 86 { NULL, DIJOFS_BUTTON(22), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 87 { NULL, DIJOFS_BUTTON(23), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 88 { NULL, DIJOFS_BUTTON(24), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 89 { NULL, DIJOFS_BUTTON(25), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 90 { NULL, DIJOFS_BUTTON(26), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 91 { NULL, DIJOFS_BUTTON(27), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 92 { NULL, DIJOFS_BUTTON(28), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 93 { NULL, DIJOFS_BUTTON(29), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 94 { NULL, DIJOFS_BUTTON(30), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 95 { NULL, DIJOFS_BUTTON(31), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 96 { NULL, DIJOFS_BUTTON(32), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 97 { NULL, DIJOFS_BUTTON(33), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 98 { NULL, DIJOFS_BUTTON(34), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 99 { NULL, DIJOFS_BUTTON(35), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 100 { NULL, DIJOFS_BUTTON(36), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 101 { NULL, DIJOFS_BUTTON(37), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 102 { NULL, DIJOFS_BUTTON(38), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 103 { NULL, DIJOFS_BUTTON(39), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 104 { NULL, DIJOFS_BUTTON(40), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 105 { NULL, DIJOFS_BUTTON(41), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 106 { NULL, DIJOFS_BUTTON(42), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 107 { NULL, DIJOFS_BUTTON(43), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 108 { NULL, DIJOFS_BUTTON(44), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 109 { NULL, DIJOFS_BUTTON(45), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 110 { NULL, DIJOFS_BUTTON(46), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 111 { NULL, DIJOFS_BUTTON(47), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 112 { NULL, DIJOFS_BUTTON(48), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 113 { NULL, DIJOFS_BUTTON(49), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 114 { NULL, DIJOFS_BUTTON(50), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 115 { NULL, DIJOFS_BUTTON(51), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 116 { NULL, DIJOFS_BUTTON(52), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 117 { NULL, DIJOFS_BUTTON(53), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 118 { NULL, DIJOFS_BUTTON(54), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 119 { NULL, DIJOFS_BUTTON(55), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 120 { NULL, DIJOFS_BUTTON(56), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 121 { NULL, DIJOFS_BUTTON(57), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 122 { NULL, DIJOFS_BUTTON(58), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 123 { NULL, DIJOFS_BUTTON(59), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 124 { NULL, DIJOFS_BUTTON(60), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 125 { NULL, DIJOFS_BUTTON(61), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 126 { NULL, DIJOFS_BUTTON(62), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 127 { NULL, DIJOFS_BUTTON(63), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 128 { NULL, DIJOFS_BUTTON(64), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 129 { NULL, DIJOFS_BUTTON(65), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 130 { NULL, DIJOFS_BUTTON(66), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 131 { NULL, DIJOFS_BUTTON(67), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 132 { NULL, DIJOFS_BUTTON(68), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 133 { NULL, DIJOFS_BUTTON(69), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 134 { NULL, DIJOFS_BUTTON(70), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 135 { NULL, DIJOFS_BUTTON(71), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 136 { NULL, DIJOFS_BUTTON(72), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 137 { NULL, DIJOFS_BUTTON(73), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 138 { NULL, DIJOFS_BUTTON(74), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 139 { NULL, DIJOFS_BUTTON(75), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 140 { NULL, DIJOFS_BUTTON(76), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 141 { NULL, DIJOFS_BUTTON(77), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 142 { NULL, DIJOFS_BUTTON(78), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 143 { NULL, DIJOFS_BUTTON(79), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 144 { NULL, DIJOFS_BUTTON(80), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 145 { NULL, DIJOFS_BUTTON(81), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 146 { NULL, DIJOFS_BUTTON(82), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 147 { NULL, DIJOFS_BUTTON(83), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 148 { NULL, DIJOFS_BUTTON(84), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 149 { NULL, DIJOFS_BUTTON(85), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 150 { NULL, DIJOFS_BUTTON(86), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 151 { NULL, DIJOFS_BUTTON(87), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 152 { NULL, DIJOFS_BUTTON(88), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 153 { NULL, DIJOFS_BUTTON(89), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 154 { NULL, DIJOFS_BUTTON(90), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 155 { NULL, DIJOFS_BUTTON(91), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 156 { NULL, DIJOFS_BUTTON(92), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 157 { NULL, DIJOFS_BUTTON(93), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 158 { NULL, DIJOFS_BUTTON(94), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 159 { NULL, DIJOFS_BUTTON(95), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 160 { NULL, DIJOFS_BUTTON(96), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 161 { NULL, DIJOFS_BUTTON(97), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 162 { NULL, DIJOFS_BUTTON(98), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 163 { NULL, DIJOFS_BUTTON(99), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 164 { NULL, DIJOFS_BUTTON(100), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 165 { NULL, DIJOFS_BUTTON(101), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 166 { NULL, DIJOFS_BUTTON(102), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 167 { NULL, DIJOFS_BUTTON(103), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 168 { NULL, DIJOFS_BUTTON(104), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 169 { NULL, DIJOFS_BUTTON(105), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 170 { NULL, DIJOFS_BUTTON(106), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 171 { NULL, DIJOFS_BUTTON(107), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 172 { NULL, DIJOFS_BUTTON(108), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 173 { NULL, DIJOFS_BUTTON(109), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 174 { NULL, DIJOFS_BUTTON(110), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 175 { NULL, DIJOFS_BUTTON(111), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 176 { NULL, DIJOFS_BUTTON(112), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 177 { NULL, DIJOFS_BUTTON(113), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 178 { NULL, DIJOFS_BUTTON(114), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 179 { NULL, DIJOFS_BUTTON(115), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 180 { NULL, DIJOFS_BUTTON(116), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 181 { NULL, DIJOFS_BUTTON(117), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 182 { NULL, DIJOFS_BUTTON(118), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 183 { NULL, DIJOFS_BUTTON(119), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 184 { NULL, DIJOFS_BUTTON(120), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 185 { NULL, DIJOFS_BUTTON(121), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 186 { NULL, DIJOFS_BUTTON(122), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 187 { NULL, DIJOFS_BUTTON(123), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 188 { NULL, DIJOFS_BUTTON(124), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 189 { NULL, DIJOFS_BUTTON(125), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 190 { NULL, DIJOFS_BUTTON(126), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 191 { NULL, DIJOFS_BUTTON(127), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, 192 { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lVX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 193 { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lVY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 194 { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lVZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 195 { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lVRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 196 { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lVRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 197 { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lVRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 198 { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglVSlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 199 { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglVSlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 200 { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lAX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 201 { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lAY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 202 { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lAZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 203 { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lARx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 204 { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lARy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 205 { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lARz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 206 { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglASlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 207 { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglASlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 208 { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lFX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 209 { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lFY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 210 { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lFZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 211 { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lFRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 212 { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lFRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 213 { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lFRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 214 { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglFSlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 215 { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglFSlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, 216}; 217 218const DIDATAFORMAT SDL_c_dfDIJoystick2 = { 219 sizeof(DIDATAFORMAT), 220 sizeof(DIOBJECTDATAFORMAT), 221 DIDF_ABSAXIS, 222 sizeof(DIJOYSTATE2), 223 SDL_arraysize(dfDIJoystick2), 224 dfDIJoystick2 225}; 226 227/* Convert a DirectInput return code to a text message */ 228static int 229SetDIerror(const char *function, HRESULT code) 230{ 231 /* 232 return SDL_SetError("%s() [%s]: %s", function, 233 DXGetErrorString9A(code), DXGetErrorDescription9A(code)); 234 */ 235 return SDL_SetError("%s() DirectX error 0x%8.8lx", function, code); 236} 237 238static SDL_bool 239SDL_IsXInputDevice(const GUID* pGuidProductFromDirectInput) 240{ 241 static GUID IID_ValveStreamingGamepad = { MAKELONG(0x28DE, 0x11FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; 242 static GUID IID_X360WiredGamepad = { MAKELONG(0x045E, 0x02A1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; 243 static GUID IID_X360WirelessGamepad = { MAKELONG(0x045E, 0x028E), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; 244 static GUID IID_XOneWiredGamepad = { MAKELONG(0x045E, 0x02FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; 245 static GUID IID_XOneWirelessGamepad = { MAKELONG(0x045E, 0x02DD), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; 246 static GUID IID_XOneNewWirelessGamepad = { MAKELONG(0x045E, 0x02D1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; 247 static GUID IID_XOneSWirelessGamepad = { MAKELONG(0x045E, 0x02EA), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; 248 static GUID IID_XOneSBluetoothGamepad = { MAKELONG(0x045E, 0x02E0), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; 249 static GUID IID_XOneEliteWirelessGamepad = { MAKELONG(0x045E, 0x02E3), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; 250 251 static const GUID *s_XInputProductGUID[] = { 252 &IID_ValveStreamingGamepad, 253 &IID_X360WiredGamepad, /* Microsoft's wired X360 controller for Windows. */ 254 &IID_X360WirelessGamepad, /* Microsoft's wireless X360 controller for Windows. */ 255 &IID_XOneWiredGamepad, /* Microsoft's wired Xbox One controller for Windows. */ 256 &IID_XOneWirelessGamepad, /* Microsoft's wireless Xbox One controller for Windows. */ 257 &IID_XOneNewWirelessGamepad, /* Microsoft's updated wireless Xbox One controller (w/ 3.5 mm jack) for Windows. */ 258 &IID_XOneSWirelessGamepad, /* Microsoft's wireless Xbox One S controller for Windows. */ 259 &IID_XOneSBluetoothGamepad, /* Microsoft's Bluetooth Xbox One S controller for Windows. */ 260 &IID_XOneEliteWirelessGamepad /* Microsoft's wireless Xbox One Elite controller for Windows. */ 261 }; 262 263 size_t iDevice; 264 UINT i; 265 266 if (!SDL_XINPUT_Enabled()) { 267 return SDL_FALSE; 268 } 269 270 /* Check for well known XInput device GUIDs */ 271 /* 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. */ 272 for (iDevice = 0; iDevice < SDL_arraysize(s_XInputProductGUID); ++iDevice) { 273 if (SDL_memcmp(pGuidProductFromDirectInput, s_XInputProductGUID[iDevice], sizeof(GUID)) == 0) { 274 return SDL_TRUE; 275 } 276 } 277 278 /* Go through RAWINPUT (WinXP and later) to find HID devices. */ 279 /* Cache this if we end up using it. */ 280 if (SDL_RawDevList == NULL) { 281 if ((GetRawInputDeviceList(NULL, &SDL_RawDevListCount, sizeof(RAWINPUTDEVICELIST)) == -1) || (!SDL_RawDevListCount)) { 282 return SDL_FALSE; /* oh well. */ 283 } 284 285 SDL_RawDevList = (PRAWINPUTDEVICELIST)SDL_malloc(sizeof(RAWINPUTDEVICELIST) * SDL_RawDevListCount); 286 if (SDL_RawDevList == NULL) { 287 SDL_OutOfMemory(); 288 return SDL_FALSE; 289 } 290 291 if (GetRawInputDeviceList(SDL_RawDevList, &SDL_RawDevListCount, sizeof(RAWINPUTDEVICELIST)) == -1) { 292 SDL_free(SDL_RawDevList); 293 SDL_RawDevList = NULL; 294 return SDL_FALSE; /* oh well. */ 295 } 296 } 297 298 for (i = 0; i < SDL_RawDevListCount; i++) { 299 RID_DEVICE_INFO rdi; 300 char devName[128]; 301 UINT rdiSize = sizeof(rdi); 302 UINT nameSize = SDL_arraysize(devName); 303 304 rdi.cbSize = sizeof(rdi); 305 if ((SDL_RawDevList[i].dwType == RIM_TYPEHID) && 306 (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != ((UINT)-1)) && 307 (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == ((LONG)pGuidProductFromDirectInput->Data1)) && 308 (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != ((UINT)-1)) && 309 (SDL_strstr(devName, "IG_") != NULL)) { 310 return SDL_TRUE; 311 } 312 } 313 314 return SDL_FALSE; 315} 316 317void FreeRumbleEffectData(DIEFFECT *effect) 318{ 319 if (!effect) { 320 return; 321 } 322 SDL_free(effect->rgdwAxes); 323 SDL_free(effect->rglDirection); 324 SDL_free(effect->lpvTypeSpecificParams); 325 SDL_free(effect); 326} 327 328DIEFFECT *CreateRumbleEffectData(Sint16 magnitude, Uint32 duration_ms) 329{ 330 DIEFFECT *effect; 331 DIPERIODIC *periodic; 332 333 /* Create the effect */ 334 effect = (DIEFFECT *)SDL_calloc(1, sizeof(*effect)); 335 if (!effect) { 336 return NULL; 337 } 338 effect->dwSize = sizeof(*effect); 339 effect->dwGain = 10000; 340 effect->dwFlags = DIEFF_OBJECTOFFSETS; 341 effect->dwDuration = duration_ms * 1000; /* In microseconds. */ 342 effect->dwTriggerButton = DIEB_NOTRIGGER; 343 344 effect->cAxes = 2; 345 effect->rgdwAxes = (DWORD *)SDL_calloc(effect->cAxes, sizeof(DWORD)); 346 if (!effect->rgdwAxes) { 347 FreeRumbleEffectData(effect); 348 return NULL; 349 } 350 351 effect->rglDirection = (LONG *)SDL_calloc(effect->cAxes, sizeof(LONG)); 352 if (!effect->rglDirection) { 353 FreeRumbleEffectData(effect); 354 return NULL; 355 } 356 effect->dwFlags |= DIEFF_CARTESIAN; 357 358 periodic = (DIPERIODIC *)SDL_calloc(1, sizeof(*periodic)); 359 if (!periodic) { 360 FreeRumbleEffectData(effect); 361 return NULL; 362 } 363 periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude); 364 periodic->dwPeriod = 1000000; 365 366 effect->cbTypeSpecificParams = sizeof(*periodic); 367 effect->lpvTypeSpecificParams = periodic; 368 369 return effect; 370} 371 372int 373SDL_DINPUT_JoystickInit(void) 374{ 375 HRESULT result; 376 HINSTANCE instance; 377 378 result = WIN_CoInitialize(); 379 if (FAILED(result)) { 380 return SetDIerror("CoInitialize", result); 381 } 382 383 coinitialized = SDL_TRUE; 384 385 result = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER, 386 &IID_IDirectInput8, (LPVOID)&dinput); 387 388 if (FAILED(result)) { 389 return SetDIerror("CoCreateInstance", result); 390 } 391 392 /* Because we used CoCreateInstance, we need to Initialize it, first. */ 393 instance = GetModuleHandle(NULL); 394 if (instance == NULL) { 395 return SDL_SetError("GetModuleHandle() failed with error code %lu.", GetLastError()); 396 } 397 result = IDirectInput8_Initialize(dinput, instance, DIRECTINPUT_VERSION); 398 399 if (FAILED(result)) { 400 return SetDIerror("IDirectInput::Initialize", result); 401 } 402 return 0; 403} 404 405/* helper function for direct input, gets called for each connected joystick */ 406static BOOL CALLBACK 407EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext) 408{ 409 JoyStick_DeviceData *pNewJoystick; 410 JoyStick_DeviceData *pPrevJoystick = NULL; 411 const DWORD devtype = (pdidInstance->dwDevType & 0xFF); 412 Uint16 *guid16; 413 Uint16 vendor = 0; 414 Uint16 product = 0; 415 Uint16 version = 0; 416 WCHAR hidPath[MAX_PATH]; 417 418 if (devtype == DI8DEVTYPE_SUPPLEMENTAL) { 419 /* Add any supplemental devices that should be ignored here */ 420#define MAKE_TABLE_ENTRY(VID, PID) ((((DWORD)PID)<<16)|VID) 421 static DWORD ignored_devices[] = { 422 MAKE_TABLE_ENTRY(0, 0) 423 }; 424#undef MAKE_TABLE_ENTRY 425 unsigned int i; 426 427 for (i = 0; i < SDL_arraysize(ignored_devices); ++i) { 428 if (pdidInstance->guidProduct.Data1 == ignored_devices[i]) { 429 return DIENUM_CONTINUE; 430 } 431 } 432 } 433 434 if (SDL_IsXInputDevice(&pdidInstance->guidProduct)) { 435 return DIENUM_CONTINUE; /* ignore XInput devices here, keep going. */ 436 } 437 438 { 439 HRESULT result; 440 LPDIRECTINPUTDEVICE8 device; 441 LPDIRECTINPUTDEVICE8 InputDevice; 442 DIPROPGUIDANDPATH dipdw2; 443 444 result = IDirectInput8_CreateDevice(dinput, &(pdidInstance->guidInstance), &device, NULL); 445 if (FAILED(result)) { 446 return DIENUM_CONTINUE; /* better luck next time? */ 447 } 448 449 /* Now get the IDirectInputDevice8 interface, instead. */ 450 result = IDirectInputDevice8_QueryInterface(device, &IID_IDirectInputDevice8, (LPVOID *)&InputDevice); 451 /* We are done with this object. Use the stored one from now on. */ 452 IDirectInputDevice8_Release(device); 453 if (FAILED(result)) { 454 return DIENUM_CONTINUE; /* better luck next time? */ 455 } 456 dipdw2.diph.dwSize = sizeof(dipdw2); 457 dipdw2.diph.dwHeaderSize = sizeof(dipdw2.diph); 458 dipdw2.diph.dwObj = 0; // device property 459 dipdw2.diph.dwHow = DIPH_DEVICE; 460 461 result = IDirectInputDevice8_GetProperty(InputDevice, DIPROP_GUIDANDPATH, &dipdw2.diph); 462 IDirectInputDevice8_Release(InputDevice); 463 if (FAILED(result)) { 464 return DIENUM_CONTINUE; /* better luck next time? */ 465 } 466 467 /* Get device path, compare that instead of GUID, additionally update GUIDs of joysticks with matching paths, in case they're not open yet. */ 468 SDL_wcslcpy(hidPath, dipdw2.wszPath, SDL_arraysize(hidPath)); 469 } 470 471 pNewJoystick = *(JoyStick_DeviceData **)pContext; 472 while (pNewJoystick) { 473 if (SDL_wcscmp(pNewJoystick->hidPath, hidPath) == 0) { 474 /* if we are replacing the front of the list then update it */ 475 if (pNewJoystick == *(JoyStick_DeviceData **)pContext) { 476 *(JoyStick_DeviceData **)pContext = pNewJoystick->pNext; 477 } else if (pPrevJoystick) { 478 pPrevJoystick->pNext = pNewJoystick->pNext; 479 } 480 481 // Update with new guid/etc, if it has changed 482 pNewJoystick->dxdevice = *pdidInstance; 483 484 pNewJoystick->pNext = SYS_Joystick; 485 SYS_Joystick = pNewJoystick; 486 487 return DIENUM_CONTINUE; /* already have this joystick loaded, just keep going */ 488 } 489 490 pPrevJoystick = pNewJoystick; 491 pNewJoystick = pNewJoystick->pNext; 492 } 493 494 pNewJoystick = (JoyStick_DeviceData *)SDL_malloc(sizeof(JoyStick_DeviceData)); 495 if (!pNewJoystick) { 496 return DIENUM_CONTINUE; /* better luck next time? */ 497 } 498 499 SDL_zerop(pNewJoystick); 500 SDL_wcslcpy(pNewJoystick->hidPath, hidPath, SDL_arraysize(pNewJoystick->hidPath)); 501 pNewJoystick->joystickname = WIN_StringToUTF8(pdidInstance->tszProductName); 502 if (!pNewJoystick->joystickname) { 503 SDL_free(pNewJoystick); 504 return DIENUM_CONTINUE; /* better luck next time? */ 505 } 506 507 SDL_memcpy(&(pNewJoystick->dxdevice), pdidInstance, 508 sizeof(DIDEVICEINSTANCE)); 509 510 SDL_memset(pNewJoystick->guid.data, 0, sizeof(pNewJoystick->guid.data)); 511 512 guid16 = (Uint16 *)pNewJoystick->guid.data; 513 if (SDL_memcmp(&pdidInstance->guidProduct.Data4[2], "PIDVID", 6) == 0) { 514 vendor = (Uint16)LOWORD(pdidInstance->guidProduct.Data1); 515 product = (Uint16)HIWORD(pdidInstance->guidProduct.Data1); 516 version = 0; 517 518 *guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_USB); 519 *guid16++ = 0; 520 *guid16++ = SDL_SwapLE16(vendor); 521 *guid16++ = 0; 522 *guid16++ = SDL_SwapLE16(product); 523 *guid16++ = 0; 524 *guid16++ = SDL_SwapLE16(version); 525 *guid16++ = 0; 526 } else { 527 *guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_BLUETOOTH); 528 *guid16++ = 0; 529 SDL_strlcpy((char*)guid16, pNewJoystick->joystickname, sizeof(pNewJoystick->guid.data) - 4); 530 } 531 532 if (SDL_ShouldIgnoreJoystick(pNewJoystick->joystickname, pNewJoystick->guid)) { 533 SDL_free(pNewJoystick); 534 return DIENUM_CONTINUE; 535 } 536 537#ifdef SDL_JOYSTICK_HIDAPI 538 if (HIDAPI_IsDevicePresent(vendor, product, 0)) { 539 /* The HIDAPI driver is taking care of this device */ 540 SDL_free(pNewJoystick); 541 return DIENUM_CONTINUE; 542 } 543#endif 544 545 WINDOWS_AddJoystickDevice(pNewJoystick); 546 547 return DIENUM_CONTINUE; /* get next device, please */ 548} 549 550void 551SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext) 552{ 553 IDirectInput8_EnumDevices(dinput, DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, pContext, DIEDFL_ATTACHEDONLY); 554 555 if (SDL_RawDevList) { 556 SDL_free(SDL_RawDevList); /* in case we used this in DirectInput detection */ 557 SDL_RawDevList = NULL; 558 } 559 SDL_RawDevListCount = 0; 560} 561 562static BOOL CALLBACK 563EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef) 564{ 565 SDL_Joystick *joystick = (SDL_Joystick *)pvRef; 566 HRESULT result; 567 input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs]; 568 569 if (dev->dwType & DIDFT_BUTTON) { 570 in->type = BUTTON; 571 in->num = joystick->nbuttons; 572 in->ofs = DIJOFS_BUTTON(in->num); 573 joystick->nbuttons++; 574 } else if (dev->dwType & DIDFT_POV) { 575 in->type = HAT; 576 in->num = joystick->nhats; 577 in->ofs = DIJOFS_POV(in->num); 578 joystick->nhats++; 579 } else if (dev->dwType & DIDFT_AXIS) { 580 DIPROPRANGE diprg; 581 DIPROPDWORD dilong; 582 583 in->type = AXIS; 584 in->num = joystick->naxes; 585 if (!SDL_memcmp(&dev->guidType, &GUID_XAxis, sizeof(dev->guidType))) 586 in->ofs = DIJOFS_X; 587 else if (!SDL_memcmp(&dev->guidType, &GUID_YAxis, sizeof(dev->guidType))) 588 in->ofs = DIJOFS_Y; 589 else if (!SDL_memcmp(&dev->guidType, &GUID_ZAxis, sizeof(dev->guidType))) 590 in->ofs = DIJOFS_Z; 591 else if (!SDL_memcmp(&dev->guidType, &GUID_RxAxis, sizeof(dev->guidType))) 592 in->ofs = DIJOFS_RX; 593 else if (!SDL_memcmp(&dev->guidType, &GUID_RyAxis, sizeof(dev->guidType))) 594 in->ofs = DIJOFS_RY; 595 else if (!SDL_memcmp(&dev->guidType, &GUID_RzAxis, sizeof(dev->guidType))) 596 in->ofs = DIJOFS_RZ; 597 else if (!SDL_memcmp(&dev->guidType, &GUID_Slider, sizeof(dev->guidType))) { 598 in->ofs = DIJOFS_SLIDER(joystick->hwdata->NumSliders); 599 ++joystick->hwdata->NumSliders; 600 } else { 601 return DIENUM_CONTINUE; /* not an axis we can grok */ 602 } 603 604 diprg.diph.dwSize = sizeof(diprg); 605 diprg.diph.dwHeaderSize = sizeof(diprg.diph); 606 diprg.diph.dwObj = dev->dwType; 607 diprg.diph.dwHow = DIPH_BYID; 608 diprg.lMin = SDL_JOYSTICK_AXIS_MIN; 609 diprg.lMax = SDL_JOYSTICK_AXIS_MAX; 610 611 result = 612 IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice, 613 DIPROP_RANGE, &diprg.diph); 614 if (FAILED(result)) { 615 return DIENUM_CONTINUE; /* don't use this axis */ 616 } 617 618 /* Set dead zone to 0. */ 619 dilong.diph.dwSize = sizeof(dilong); 620 dilong.diph.dwHeaderSize = sizeof(dilong.diph); 621 dilong.diph.dwObj = dev->dwType; 622 dilong.diph.dwHow = DIPH_BYID; 623 dilong.dwData = 0; 624 result = 625 IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice, 626 DIPROP_DEADZONE, &dilong.diph); 627 if (FAILED(result)) { 628 return DIENUM_CONTINUE; /* don't use this axis */ 629 } 630 631 joystick->naxes++; 632 } else { 633 /* not supported at this time */ 634 return DIENUM_CONTINUE; 635 } 636 637 joystick->hwdata->NumInputs++; 638 639 if (joystick->hwdata->NumInputs == MAX_INPUTS) { 640 return DIENUM_STOP; /* too many */ 641 } 642 643 return DIENUM_CONTINUE; 644} 645 646/* Sort using the data offset into the DInput struct. 647 * This gives a reasonable ordering for the inputs. 648 */ 649static int 650SortDevFunc(const void *a, const void *b) 651{ 652 const input_t *inputA = (const input_t*)a; 653 const input_t *inputB = (const input_t*)b; 654 655 if (inputA->ofs < inputB->ofs) 656 return -1; 657 if (inputA->ofs > inputB->ofs) 658 return 1; 659 return 0; 660} 661 662/* Sort the input objects and recalculate the indices for each input. */ 663static void 664SortDevObjects(SDL_Joystick *joystick) 665{ 666 input_t *inputs = joystick->hwdata->Inputs; 667 int nButtons = 0; 668 int nHats = 0; 669 int nAxis = 0; 670 int n; 671 672 SDL_qsort(inputs, joystick->hwdata->NumInputs, sizeof(input_t), SortDevFunc); 673 674 for (n = 0; n < joystick->hwdata->NumInputs; n++) { 675 switch (inputs[n].type) { 676 case BUTTON: 677 inputs[n].num = nButtons; 678 nButtons++; 679 break; 680 681 case HAT: 682 inputs[n].num = nHats; 683 nHats++; 684 break; 685 686 case AXIS: 687 inputs[n].num = nAxis; 688 nAxis++; 689 break; 690 } 691 } 692} 693 694int 695SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice) 696{ 697 HRESULT result; 698 LPDIRECTINPUTDEVICE8 device; 699 DIPROPDWORD dipdw; 700 701 joystick->hwdata->buffered = SDL_TRUE; 702 joystick->hwdata->Capabilities.dwSize = sizeof(DIDEVCAPS); 703 704 SDL_zero(dipdw); 705 dipdw.diph.dwSize = sizeof(DIPROPDWORD); 706 dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); 707 708 result = 709 IDirectInput8_CreateDevice(dinput, 710 &(joystickdevice->dxdevice.guidInstance), &device, NULL); 711 if (FAILED(result)) { 712 return SetDIerror("IDirectInput::CreateDevice", result); 713 } 714 715 /* Now get the IDirectInputDevice8 interface, instead. */ 716 result = IDirectInputDevice8_QueryInterface(device, 717 &IID_IDirectInputDevice8, 718 (LPVOID *)& joystick-> 719 hwdata->InputDevice); 720 /* We are done with this object. Use the stored one from now on. */ 721 IDirectInputDevice8_Release(device); 722 723 if (FAILED(result)) { 724 return SetDIerror("IDirectInputDevice8::QueryInterface", result); 725 } 726 727 /* Acquire shared access. Exclusive access is required for forces, 728 * though. */ 729 result = 730 IDirectInputDevice8_SetCooperativeLevel(joystick->hwdata-> 731 InputDevice, SDL_HelperWindow, 732 DISCL_EXCLUSIVE | 733 DISCL_BACKGROUND); 734 if (FAILED(result)) { 735 return SetDIerror("IDirectInputDevice8::SetCooperativeLevel", result); 736 } 737 738 /* Use the extended data structure: DIJOYSTATE2. */ 739 result = 740 IDirectInputDevice8_SetDataFormat(joystick->hwdata->InputDevice, 741 &SDL_c_dfDIJoystick2); 742 if (FAILED(result)) { 743 return SetDIerror("IDirectInputDevice8::SetDataFormat", result); 744 } 745 746 /* Get device capabilities */ 747 result = 748 IDirectInputDevice8_GetCapabilities(joystick->hwdata->InputDevice, 749 &joystick->hwdata->Capabilities); 750 if (FAILED(result)) { 751 return SetDIerror("IDirectInputDevice8::GetCapabilities", result); 752 } 753 754 /* Force capable? */ 755 if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) { 756 result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); 757 if (FAILED(result)) { 758 return SetDIerror("IDirectInputDevice8::Acquire", result); 759 } 760 761 /* reset all actuators. */ 762 result = 763 IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata-> 764 InputDevice, 765 DISFFC_RESET); 766 767 /* Not necessarily supported, ignore if not supported. 768 if (FAILED(result)) { 769 return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand", result); 770 } 771 */ 772 773 result = IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice); 774 775 if (FAILED(result)) { 776 return SetDIerror("IDirectInputDevice8::Unacquire", result); 777 } 778 779 /* Turn on auto-centering for a ForceFeedback device (until told 780 * otherwise). */ 781 dipdw.diph.dwObj = 0; 782 dipdw.diph.dwHow = DIPH_DEVICE; 783 dipdw.dwData = DIPROPAUTOCENTER_ON; 784 785 result = 786 IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice, 787 DIPROP_AUTOCENTER, &dipdw.diph); 788 789 /* Not necessarily supported, ignore if not supported. 790 if (FAILED(result)) { 791 return SetDIerror("IDirectInputDevice8::SetProperty", result); 792 } 793 */ 794 } 795 796 /* What buttons and axes does it have? */ 797 IDirectInputDevice8_EnumObjects(joystick->hwdata->InputDevice, 798 EnumDevObjectsCallback, joystick, 799 DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV); 800 801 /* Reorder the input objects. Some devices do not report the X axis as 802 * the first axis, for example. */ 803 SortDevObjects(joystick); 804 805 dipdw.diph.dwObj = 0; 806 dipdw.diph.dwHow = DIPH_DEVICE; 807 dipdw.dwData = INPUT_QSIZE; 808 809 /* Set the buffer size */ 810 result = 811 IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice, 812 DIPROP_BUFFERSIZE, &dipdw.diph); 813 814 if (result == DI_POLLEDDEVICE) { 815 /* This device doesn't support buffering, so we're forced 816 * to use less reliable polling. */ 817 joystick->hwdata->buffered = SDL_FALSE; 818 } else if (FAILED(result)) { 819 return SetDIerror("IDirectInputDevice8::SetProperty", result); 820 } 821 return 0; 822} 823 824static int 825SDL_DINPUT_JoystickInitRumble(SDL_Joystick * joystick, Sint16 magnitude, Uint32 duration_ms) 826{ 827 HRESULT result; 828 829 /* Reset and then enable actuators */ 830 result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_RESET); 831 if (result == DIERR_INPUTLOST || result == DIERR_NOTEXCLUSIVEACQUIRED) { 832 result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); 833 if (SUCCEEDED(result)) { 834 result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_RESET); 835 } 836 } 837 if (FAILED(result)) { 838 return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand(DISFFC_RESET)", result); 839 } 840 841 result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_SETACTUATORSON); 842 if (FAILED(result)) { 843 return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand(DISFFC_SETACTUATORSON)", result); 844 } 845 846 /* Create the effect */ 847 joystick->hwdata->ffeffect = CreateRumbleEffectData(magnitude, duration_ms); 848 if (!joystick->hwdata->ffeffect) { 849 return SDL_OutOfMemory(); 850 } 851 852 result = IDirectInputDevice8_CreateEffect(joystick->hwdata->InputDevice, &GUID_Sine, 853 joystick->hwdata->ffeffect, &joystick->hwdata->ffeffect_ref, NULL); 854 if (FAILED(result)) { 855 return SetDIerror("IDirectInputDevice8::CreateEffect", result); 856 } 857 return 0; 858} 859 860int 861SDL_DINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms) 862{ 863 HRESULT result; 864 865 /* Scale and average the two rumble strengths */ 866 Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2); 867 868 if (!(joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK)) { 869 return SDL_Unsupported(); 870 } 871 872 if (joystick->hwdata->ff_initialized) { 873 DIPERIODIC *periodic = ((DIPERIODIC *)joystick->hwdata->ffeffect->lpvTypeSpecificParams); 874 joystick->hwdata->ffeffect->dwDuration = duration_ms * 1000; /* In microseconds. */ 875 periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude); 876 877 result = IDirectInputEffect_SetParameters(joystick->hwdata->ffeffect_ref, joystick->hwdata->ffeffect, (DIEP_DURATION | DIEP_TYPESPECIFICPARAMS)); 878 if (result == DIERR_INPUTLOST) { 879 result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); 880 if (SUCCEEDED(result)) { 881 result = IDirectInputEffect_SetParameters(joystick->hwdata->ffeffect_ref, joystick->hwdata->ffeffect, (DIEP_DURATION | DIEP_TYPESPECIFICPARAMS)); 882 } 883 } 884 if (FAILED(result)) { 885 return SetDIerror("IDirectInputDevice8::SetParameters", result); 886 } 887 } else { 888 if (SDL_DINPUT_JoystickInitRumble(joystick, magnitude, duration_ms) < 0) { 889 return -1; 890 } 891 joystick->hwdata->ff_initialized = SDL_TRUE; 892 } 893 894 result = IDirectInputEffect_Start(joystick->hwdata->ffeffect_ref, 1, 0); 895 if (result == DIERR_INPUTLOST || result == DIERR_NOTEXCLUSIVEACQUIRED) { 896 result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); 897 if (SUCCEEDED(result)) { 898 result = IDirectInputEffect_Start(joystick->hwdata->ffeffect_ref, 1, 0); 899 } 900 } 901 if (FAILED(result)) { 902 return SetDIerror("IDirectInputDevice8::Start", result); 903 } 904 return 0; 905} 906 907static Uint8 908TranslatePOV(DWORD value) 909{ 910 const int HAT_VALS[] = { 911 SDL_HAT_UP, 912 SDL_HAT_UP | SDL_HAT_RIGHT, 913 SDL_HAT_RIGHT, 914 SDL_HAT_DOWN | SDL_HAT_RIGHT, 915 SDL_HAT_DOWN, 916 SDL_HAT_DOWN | SDL_HAT_LEFT, 917 SDL_HAT_LEFT, 918 SDL_HAT_UP | SDL_HAT_LEFT 919 }; 920 921 if (LOWORD(value) == 0xFFFF) 922 return SDL_HAT_CENTERED; 923 924 /* Round the value up: */ 925 value += 4500 / 2; 926 value %= 36000; 927 value /= 4500; 928 929 if (value >= 8) 930 return SDL_HAT_CENTERED; /* shouldn't happen */ 931 932 return HAT_VALS[value]; 933} 934 935static void 936UpdateDINPUTJoystickState_Buffered(SDL_Joystick * joystick) 937{ 938 int i; 939 HRESULT result; 940 DWORD numevents; 941 DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE]; 942 943 numevents = INPUT_QSIZE; 944 result = 945 IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice, 946 sizeof(DIDEVICEOBJECTDATA), evtbuf, 947 &numevents, 0); 948 if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) { 949 IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); 950 result = 951 IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice, 952 sizeof(DIDEVICEOBJECTDATA), 953 evtbuf, &numevents, 0); 954 } 955 956 /* Handle the events or punt */ 957 if (FAILED(result)) { 958 return; 959 } 960 961 for (i = 0; i < (int)numevents; ++i) { 962 int j; 963 964 for (j = 0; j < joystick->hwdata->NumInputs; ++j) { 965 const input_t *in = &joystick->hwdata->Inputs[j]; 966 967 if (evtbuf[i].dwOfs != in->ofs) 968 continue; 969 970 switch (in->type) { 971 case AXIS: 972 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)evtbuf[i].dwData); 973 break; 974 case BUTTON: 975 SDL_PrivateJoystickButton(joystick, in->num, 976 (Uint8)(evtbuf[i].dwData ? SDL_PRESSED : SDL_RELEASED)); 977 break; 978 case HAT: 979 { 980 Uint8 pos = TranslatePOV(evtbuf[i].dwData); 981 SDL_PrivateJoystickHat(joystick, in->num, pos); 982 } 983 break; 984 } 985 } 986 } 987} 988 989/* Function to update the state of a joystick - called as a device poll. 990 * This function shouldn't update the joystick structure directly, 991 * but instead should call SDL_PrivateJoystick*() to deliver events 992 * and update joystick device state. 993 */ 994static void 995UpdateDINPUTJoystickState_Polled(SDL_Joystick * joystick) 996{ 997 DIJOYSTATE2 state; 998 HRESULT result; 999 int i; 1000 1001 result = 1002 IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice, 1003 sizeof(DIJOYSTATE2), &state); 1004 if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) { 1005 IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); 1006 result = 1007 IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice, 1008 sizeof(DIJOYSTATE2), &state); 1009 } 1010 1011 if (result != DI_OK) { 1012 return; 1013 } 1014 1015 /* Set each known axis, button and POV. */ 1016 for (i = 0; i < joystick->hwdata->NumInputs; ++i) { 1017 const input_t *in = &joystick->hwdata->Inputs[i]; 1018 1019 switch (in->type) { 1020 case AXIS: 1021 switch (in->ofs) { 1022 case DIJOFS_X: 1023 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lX); 1024 break; 1025 case DIJOFS_Y: 1026 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lY); 1027 break; 1028 case DIJOFS_Z: 1029 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lZ); 1030 break; 1031 case DIJOFS_RX: 1032 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRx); 1033 break; 1034 case DIJOFS_RY: 1035 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRy); 1036 break; 1037 case DIJOFS_RZ: 1038 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRz); 1039 break; 1040 case DIJOFS_SLIDER(0): 1041 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.rglSlider[0]); 1042 break; 1043 case DIJOFS_SLIDER(1): 1044 SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.rglSlider[1]); 1045 break; 1046 } 1047 break; 1048 1049 case BUTTON: 1050 SDL_PrivateJoystickButton(joystick, in->num, 1051 (Uint8)(state.rgbButtons[in->ofs - DIJOFS_BUTTON0] ? SDL_PRESSED : SDL_RELEASED)); 1052 break; 1053 case HAT: 1054 { 1055 Uint8 pos = TranslatePOV(state.rgdwPOV[in->ofs - DIJOFS_POV(0)]); 1056 SDL_PrivateJoystickHat(joystick, in->num, pos); 1057 break; 1058 } 1059 } 1060 } 1061} 1062 1063void 1064SDL_DINPUT_JoystickUpdate(SDL_Joystick * joystick) 1065{ 1066 HRESULT result; 1067 1068 result = IDirectInputDevice8_Poll(joystick->hwdata->InputDevice); 1069 if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) { 1070 IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); 1071 IDirectInputDevice8_Poll(joystick->hwdata->InputDevice); 1072 } 1073 1074 if (joystick->hwdata->buffered) { 1075 UpdateDINPUTJoystickState_Buffered(joystick); 1076 } else { 1077 UpdateDINPUTJoystickState_Polled(joystick); 1078 } 1079} 1080 1081void 1082SDL_DINPUT_JoystickClose(SDL_Joystick * joystick) 1083{ 1084 if (joystick->hwdata->ffeffect_ref) { 1085 IDirectInputEffect_Unload(joystick->hwdata->ffeffect_ref); 1086 joystick->hwdata->ffeffect_ref = NULL; 1087 } 1088 if (joystick->hwdata->ffeffect) { 1089 FreeRumbleEffectData(joystick->hwdata->ffeffect); 1090 joystick->hwdata->ffeffect = NULL; 1091 } 1092 IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice); 1093 IDirectInputDevice8_Release(joystick->hwdata->InputDevice); 1094 joystick->hwdata->ff_initialized = SDL_FALSE; 1095} 1096 1097void 1098SDL_DINPUT_JoystickQuit(void) 1099{ 1100 if (dinput != NULL) { 1101 IDirectInput8_Release(dinput); 1102 dinput = NULL; 1103 } 1104 1105 if (coinitialized) { 1106 WIN_CoUninitialize(); 1107 coinitialized = SDL_FALSE; 1108 } 1109} 1110 1111#else /* !SDL_JOYSTICK_DINPUT */ 1112 1113typedef struct JoyStick_DeviceData JoyStick_DeviceData; 1114 1115int 1116SDL_DINPUT_JoystickInit(void) 1117{ 1118 return 0; 1119} 1120 1121void 1122SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext) 1123{ 1124} 1125 1126int 1127SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice) 1128{ 1129 return SDL_Unsupported(); 1130} 1131 1132int 1133SDL_DINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms) 1134{ 1135 return SDL_Unsupported(); 1136} 1137 1138void 1139SDL_DINPUT_JoystickUpdate(SDL_Joystick * joystick) 1140{ 1141} 1142 1143void 1144SDL_DINPUT_JoystickClose(SDL_Joystick * joystick) 1145{ 1146} 1147 1148void 1149SDL_DINPUT_JoystickQuit(void) 1150{ 1151} 1152 1153#endif /* SDL_JOYSTICK_DINPUT */ 1154 1155/* vi: set ts=4 sw=4 expandtab: */ 1156[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.