Atlas - SDL_dinputjoystick.c
Home / ext / SDL / src / joystick / windows Lines: 1 | Size: 50171 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 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#ifdef SDL_JOYSTICK_DINPUT 26 27#include "SDL_windowsjoystick_c.h" 28#include "SDL_dinputjoystick_c.h" 29#include "SDL_rawinputjoystick_c.h" 30#include "SDL_xinputjoystick_c.h" 31#include "../hidapi/SDL_hidapijoystick_c.h" 32 33#ifndef DIDFT_OPTIONAL 34#define DIDFT_OPTIONAL 0x80000000 35#endif 36 37#define INPUT_QSIZE 128 // Buffer up to 128 input messages 38#define JOY_AXIS_THRESHOLD (((SDL_JOYSTICK_AXIS_MAX) - (SDL_JOYSTICK_AXIS_MIN)) / 100) // 1% motion 39 40#define CONVERT_MAGNITUDE(x) (((x)*10000) / 0x7FFF) 41 42// external variables referenced. 43extern HWND SDL_HelperWindow; 44 45// local variables 46static bool coinitialized = false; 47static LPDIRECTINPUT8 dinput = NULL; 48static bool has_broken_EZFRD64DLL = false; 49 50// Taken from Wine - Thanks! 51static DIOBJECTDATAFORMAT dfDIJoystick2[] = { 52 { &GUID_XAxis, DIJOFS_X, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, 53 { &GUID_YAxis, DIJOFS_Y, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, 54 { &GUID_ZAxis, DIJOFS_Z, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, 55 { &GUID_RxAxis, DIJOFS_RX, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, 56 { &GUID_RyAxis, DIJOFS_RY, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, 57 { &GUID_RzAxis, DIJOFS_RZ, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, 58 { &GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, 59 { &GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, 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, DIDOI_ASPECTVELOCITY }, 193 { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lVY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY }, 194 { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lVZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY }, 195 { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lVRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY }, 196 { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lVRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY }, 197 { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lVRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY }, 198 // note: dwOfs value matches Windows 199 { &GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY }, 200 { &GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY }, 201 { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lAX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL }, 202 { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lAY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL }, 203 { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lAZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL }, 204 { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lARx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL }, 205 { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lARy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL }, 206 { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lARz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL }, 207 // note: dwOfs value matches Windows 208 { &GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL }, 209 { &GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL }, 210 { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lFX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE }, 211 { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lFY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE }, 212 { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lFZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE }, 213 { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lFRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE }, 214 { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lFRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE }, 215 { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lFRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE }, 216 // note: dwOfs value matches Windows 217 { &GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE }, 218 { &GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE }, 219}; 220 221const DIDATAFORMAT SDL_c_dfDIJoystick2 = { 222 sizeof(DIDATAFORMAT), 223 sizeof(DIOBJECTDATAFORMAT), 224 DIDF_ABSAXIS, 225 sizeof(DIJOYSTATE2), 226 SDL_arraysize(dfDIJoystick2), 227 dfDIJoystick2 228}; 229 230// Convert a DirectInput return code to a text message 231static bool SetDIerror(const char *function, HRESULT code) 232{ 233 return SDL_SetError("%s() DirectX error 0x%8.8lx", function, code); 234} 235 236static bool SDL_IsXInputDevice(Uint16 vendor_id, Uint16 product_id, const char *hidPath) 237{ 238#if defined(SDL_JOYSTICK_XINPUT) || defined(SDL_JOYSTICK_RAWINPUT) 239 SDL_GamepadType type; 240 241 // XInput and RawInput backends will pick up XInput-compatible devices 242 if (!SDL_XINPUT_Enabled() 243#ifdef SDL_JOYSTICK_RAWINPUT 244 && !RAWINPUT_IsEnabled() 245#endif 246 ) { 247 return false; 248 } 249 250 // If device path contains "IG_" then its an XInput device 251 // See: https://docs.microsoft.com/windows/win32/xinput/xinput-and-directinput 252 if (SDL_strstr(hidPath, "IG_") != NULL) { 253 return true; 254 } 255 256 type = SDL_GetGamepadTypeFromVIDPID(vendor_id, product_id, NULL, false); 257 if (type == SDL_GAMEPAD_TYPE_XBOX360 || 258 type == SDL_GAMEPAD_TYPE_XBOXONE || 259 (vendor_id == USB_VENDOR_VALVE && product_id == USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD)) { 260 return true; 261 } 262#endif // SDL_JOYSTICK_XINPUT || SDL_JOYSTICK_RAWINPUT 263 264 return false; 265} 266 267static bool QueryDeviceName(LPDIRECTINPUTDEVICE8 device, Uint16 vendor_id, Uint16 product_id, char **manufacturer_string, char **product_string) 268{ 269 DIPROPSTRING dipstr; 270 271 if (!device || !manufacturer_string || !product_string) { 272 return false; 273 } 274 275#ifdef SDL_JOYSTICK_HIDAPI 276 *manufacturer_string = HIDAPI_GetDeviceManufacturerName(vendor_id, product_id); 277 *product_string = HIDAPI_GetDeviceProductName(vendor_id, product_id); 278 if (*product_string) { 279 return true; 280 } 281#endif 282 283 dipstr.diph.dwSize = sizeof(dipstr); 284 dipstr.diph.dwHeaderSize = sizeof(dipstr.diph); 285 dipstr.diph.dwObj = 0; 286 dipstr.diph.dwHow = DIPH_DEVICE; 287 288 if (FAILED(IDirectInputDevice8_GetProperty(device, DIPROP_PRODUCTNAME, &dipstr.diph))) { 289 return false; 290 } 291 292 *manufacturer_string = NULL; 293 *product_string = WIN_StringToUTF8W(dipstr.wsz); 294 295 return true; 296} 297 298static bool QueryDevicePath(LPDIRECTINPUTDEVICE8 device, char **device_path) 299{ 300 DIPROPGUIDANDPATH dippath; 301 302 if (!device || !device_path) { 303 return false; 304 } 305 306 dippath.diph.dwSize = sizeof(dippath); 307 dippath.diph.dwHeaderSize = sizeof(dippath.diph); 308 dippath.diph.dwObj = 0; 309 dippath.diph.dwHow = DIPH_DEVICE; 310 311 if (FAILED(IDirectInputDevice8_GetProperty(device, DIPROP_GUIDANDPATH, &dippath.diph))) { 312 return false; 313 } 314 315 *device_path = WIN_StringToUTF8W(dippath.wszPath); 316 317 // Normalize path to upper case. 318 SDL_strupr(*device_path); 319 320 return true; 321} 322 323static bool QueryDeviceInfo(LPDIRECTINPUTDEVICE8 device, Uint16 *vendor_id, Uint16 *product_id) 324{ 325 DIPROPDWORD dipdw; 326 327 if (!device || !vendor_id || !product_id) { 328 return false; 329 } 330 331 dipdw.diph.dwSize = sizeof(dipdw); 332 dipdw.diph.dwHeaderSize = sizeof(dipdw.diph); 333 dipdw.diph.dwObj = 0; 334 dipdw.diph.dwHow = DIPH_DEVICE; 335 dipdw.dwData = 0; 336 337 if (FAILED(IDirectInputDevice8_GetProperty(device, DIPROP_VIDPID, &dipdw.diph))) { 338 return false; 339 } 340 341 *vendor_id = LOWORD(dipdw.dwData); 342 *product_id = HIWORD(dipdw.dwData); 343 344 return true; 345} 346 347void FreeRumbleEffectData(DIEFFECT *effect) 348{ 349 if (!effect) { 350 return; 351 } 352 SDL_free(effect->rgdwAxes); 353 SDL_free(effect->rglDirection); 354 SDL_free(effect->lpvTypeSpecificParams); 355 SDL_free(effect); 356} 357 358DIEFFECT *CreateRumbleEffectData(Sint16 magnitude) 359{ 360 DIEFFECT *effect; 361 DIPERIODIC *periodic; 362 363 // Create the effect 364 effect = (DIEFFECT *)SDL_calloc(1, sizeof(*effect)); 365 if (!effect) { 366 return NULL; 367 } 368 effect->dwSize = sizeof(*effect); 369 effect->dwGain = 10000; 370 effect->dwFlags = DIEFF_OBJECTOFFSETS; 371 effect->dwDuration = SDL_MAX_RUMBLE_DURATION_MS * 1000; // In microseconds. 372 effect->dwTriggerButton = DIEB_NOTRIGGER; 373 374 effect->cAxes = 2; 375 effect->rgdwAxes = (DWORD *)SDL_calloc(effect->cAxes, sizeof(DWORD)); 376 if (!effect->rgdwAxes) { 377 FreeRumbleEffectData(effect); 378 return NULL; 379 } 380 381 effect->rglDirection = (LONG *)SDL_calloc(effect->cAxes, sizeof(LONG)); 382 if (!effect->rglDirection) { 383 FreeRumbleEffectData(effect); 384 return NULL; 385 } 386 effect->dwFlags |= DIEFF_CARTESIAN; 387 388 periodic = (DIPERIODIC *)SDL_calloc(1, sizeof(*periodic)); 389 if (!periodic) { 390 FreeRumbleEffectData(effect); 391 return NULL; 392 } 393 periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude); 394 periodic->dwPeriod = 1000000; 395 396 effect->cbTypeSpecificParams = sizeof(*periodic); 397 effect->lpvTypeSpecificParams = periodic; 398 399 return effect; 400} 401 402bool SDL_DINPUT_JoystickInit(void) 403{ 404 HRESULT result; 405 HINSTANCE instance; 406 407 if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_DIRECTINPUT, true)) { 408 // In some environments, IDirectInput8_Initialize / _EnumDevices can take a minute even with no controllers. 409 dinput = NULL; 410 return true; 411 } 412 413 result = WIN_CoInitialize(); 414 if (FAILED(result)) { 415 return SetDIerror("CoInitialize", result); 416 } 417 418 coinitialized = true; 419 420 result = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER, 421 &IID_IDirectInput8, (LPVOID *)&dinput); 422 423 if (FAILED(result)) { 424 return SetDIerror("CoCreateInstance", result); 425 } 426 427 // Because we used CoCreateInstance, we need to Initialize it, first. 428 instance = GetModuleHandle(NULL); 429 if (!instance) { 430 IDirectInput8_Release(dinput); 431 dinput = NULL; 432 return SDL_SetError("GetModuleHandle() failed with error code %lu.", GetLastError()); 433 } 434 result = IDirectInput8_Initialize(dinput, instance, DIRECTINPUT_VERSION); 435 436 if (FAILED(result)) { 437 IDirectInput8_Release(dinput); 438 dinput = NULL; 439 return SetDIerror("IDirectInput::Initialize", result); 440 } 441 442#ifdef _WIN64 443 if (SDL_GetHintBoolean("SDL_JOYSTICK_CHECK_EZFRD64", true)) { 444 // The 64-bit version of EZFRD64.DLL crashes after being loaded, 445 // which happens implicitly when querying the device capabilities, 446 // so make sure we don't do that if there's a possibility of crashing 447 static const char *directories[] = { 448 "C:/Windows/USB_Vibration", 449 "C:/Windows/USB Vibration" 450 }; 451 for (int i = 0; i < SDL_arraysize(directories) && !has_broken_EZFRD64DLL; ++i) { 452 int count = 0; 453 char **files = SDL_GlobDirectory(directories[i], "*/EZFRD64.DLL", SDL_GLOB_CASEINSENSITIVE, &count); 454 if (count > 0) { 455 has_broken_EZFRD64DLL = true; 456 } 457 SDL_free(files); 458 } 459 if (has_broken_EZFRD64DLL) { 460 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Broken EZFRD64.DLL detected, disabling DirectInput force feedback"); 461 } 462 } 463#endif 464 return true; 465} 466 467static int GetSteamVirtualGamepadSlot(Uint16 vendor_id, Uint16 product_id, const char *device_path) 468{ 469 int slot = -1; 470 471 if (vendor_id == USB_VENDOR_VALVE && 472 product_id == USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD) { 473 (void)SDL_sscanf(device_path, "\\\\?\\HID#VID_28DE&PID_11FF&IG_0%d", &slot); 474 } 475 return slot; 476} 477 478// helper function for direct input, gets called for each connected joystick 479static BOOL CALLBACK EnumJoystickDetectCallback(LPCDIDEVICEINSTANCE pDeviceInstance, LPVOID pContext) 480{ 481#define CHECK(expression) \ 482 { \ 483 if (!(expression)) \ 484 goto err; \ 485 } 486 JoyStick_DeviceData *pNewJoystick = NULL; 487 JoyStick_DeviceData *pPrevJoystick = NULL; 488 Uint16 vendor = 0; 489 Uint16 product = 0; 490 Uint16 version = 0; 491 char *hidPath = NULL; 492 char *manufacturer_string = NULL; 493 char *product_string = NULL; 494 LPDIRECTINPUTDEVICE8 device = NULL; 495 496 // We are only supporting HID devices. 497 CHECK(pDeviceInstance->dwDevType & DIDEVTYPE_HID); 498 499 CHECK(SUCCEEDED(IDirectInput8_CreateDevice(dinput, &pDeviceInstance->guidInstance, &device, NULL))); 500 CHECK(QueryDevicePath(device, &hidPath)); 501 CHECK(QueryDeviceInfo(device, &vendor, &product)); 502 CHECK(QueryDeviceName(device, vendor, product, &manufacturer_string, &product_string)); 503 504 CHECK(!SDL_IsXInputDevice(vendor, product, hidPath)); 505 CHECK(!SDL_ShouldIgnoreJoystick(vendor, product, version, product_string)); 506 CHECK(!SDL_JoystickHandledByAnotherDriver(&SDL_WINDOWS_JoystickDriver, vendor, product, version, product_string)); 507 508 pNewJoystick = *(JoyStick_DeviceData **)pContext; 509 while (pNewJoystick) { 510 // update GUIDs of joysticks with matching paths, in case they're not open yet 511 if (SDL_strcmp(pNewJoystick->path, hidPath) == 0) { 512 // if we are replacing the front of the list then update it 513 if (pNewJoystick == *(JoyStick_DeviceData **)pContext) { 514 *(JoyStick_DeviceData **)pContext = pNewJoystick->pNext; 515 } else if (pPrevJoystick) { 516 pPrevJoystick->pNext = pNewJoystick->pNext; 517 } 518 519 // Update with new guid/etc, if it has changed 520 SDL_memcpy(&pNewJoystick->dxdevice, pDeviceInstance, sizeof(DIDEVICEINSTANCE)); 521 522 pNewJoystick->pNext = SYS_Joystick; 523 SYS_Joystick = pNewJoystick; 524 525 pNewJoystick = NULL; 526 CHECK(FALSE); 527 } 528 529 pPrevJoystick = pNewJoystick; 530 pNewJoystick = pNewJoystick->pNext; 531 } 532 533 pNewJoystick = (JoyStick_DeviceData *)SDL_calloc(1, sizeof(JoyStick_DeviceData)); 534 CHECK(pNewJoystick); 535 536 pNewJoystick->steam_virtual_gamepad_slot = GetSteamVirtualGamepadSlot(vendor, product, hidPath); 537 SDL_strlcpy(pNewJoystick->path, hidPath, SDL_arraysize(pNewJoystick->path)); 538 SDL_memcpy(&pNewJoystick->dxdevice, pDeviceInstance, sizeof(DIDEVICEINSTANCE)); 539 540 pNewJoystick->joystickname = SDL_CreateJoystickName(vendor, product, manufacturer_string, product_string); 541 CHECK(pNewJoystick->joystickname); 542 543 if (vendor && product) { 544 pNewJoystick->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, vendor, product, version, manufacturer_string, product_string, 0, 0); 545 } else { 546 pNewJoystick->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_BLUETOOTH, vendor, product, version, manufacturer_string, product_string, 0, 0); 547 } 548 549 WINDOWS_AddJoystickDevice(pNewJoystick); 550 pNewJoystick = NULL; 551 552err: 553 if (pNewJoystick) { 554 SDL_free(pNewJoystick->joystickname); 555 SDL_free(pNewJoystick); 556 } 557 558 SDL_free(hidPath); 559 SDL_free(manufacturer_string); 560 SDL_free(product_string); 561 562 if (device) { 563 IDirectInputDevice8_Release(device); 564 } 565 566 return DIENUM_CONTINUE; // get next device, please 567#undef CHECK 568} 569 570void SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext) 571{ 572 if (!dinput) { 573 return; 574 } 575 576 IDirectInput8_EnumDevices(dinput, DI8DEVCLASS_GAMECTRL, EnumJoystickDetectCallback, pContext, DIEDFL_ATTACHEDONLY); 577} 578 579// helper function for direct input, gets called for each connected joystick 580typedef struct 581{ 582 Uint16 vendor; 583 Uint16 product; 584 bool present; 585} Joystick_PresentData; 586 587static BOOL CALLBACK EnumJoystickPresentCallback(LPCDIDEVICEINSTANCE pDeviceInstance, LPVOID pContext) 588{ 589#define CHECK(expression) \ 590 { \ 591 if (!(expression)) \ 592 goto err; \ 593 } 594 Joystick_PresentData *pData = (Joystick_PresentData *)pContext; 595 Uint16 vendor = 0; 596 Uint16 product = 0; 597 LPDIRECTINPUTDEVICE8 device = NULL; 598 BOOL result = DIENUM_CONTINUE; 599 600 // We are only supporting HID devices. 601 CHECK(pDeviceInstance->dwDevType & DIDEVTYPE_HID); 602 603 CHECK(SUCCEEDED(IDirectInput8_CreateDevice(dinput, &pDeviceInstance->guidInstance, &device, NULL))); 604 CHECK(QueryDeviceInfo(device, &vendor, &product)); 605 606 if (vendor == pData->vendor && product == pData->product) { 607 pData->present = true; 608 result = DIENUM_STOP; // found it 609 } 610 611err: 612 if (device) { 613 IDirectInputDevice8_Release(device); 614 } 615 616 return result; 617#undef CHECK 618} 619 620bool SDL_DINPUT_JoystickPresent(Uint16 vendor_id, Uint16 product_id, Uint16 version_number) 621{ 622 Joystick_PresentData data; 623 624 if (!dinput) { 625 return false; 626 } 627 628 data.vendor = vendor_id; 629 data.product = product_id; 630 data.present = false; 631 IDirectInput8_EnumDevices(dinput, DI8DEVCLASS_GAMECTRL, EnumJoystickPresentCallback, &data, DIEDFL_ATTACHEDONLY); 632 return data.present; 633} 634 635static BOOL CALLBACK EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE pDeviceObject, LPVOID pContext) 636{ 637 SDL_Joystick *joystick = (SDL_Joystick *)pContext; 638 HRESULT result; 639 input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs]; 640 641 if (pDeviceObject->dwType & DIDFT_BUTTON) { 642 in->type = BUTTON; 643 in->num = (Uint8)joystick->nbuttons; 644 in->ofs = DIJOFS_BUTTON(in->num); 645 joystick->nbuttons++; 646 } else if (pDeviceObject->dwType & DIDFT_POV) { 647 in->type = HAT; 648 in->num = (Uint8)joystick->nhats; 649 in->ofs = DIJOFS_POV(in->num); 650 joystick->nhats++; 651 } else if (pDeviceObject->dwType & DIDFT_AXIS) { 652 DIPROPRANGE diprg; 653 DIPROPDWORD dilong; 654 655 in->type = AXIS; 656 in->num = (Uint8)joystick->naxes; 657 if (SDL_memcmp(&pDeviceObject->guidType, &GUID_XAxis, sizeof(pDeviceObject->guidType)) == 0) { 658 in->ofs = DIJOFS_X; 659 } else if (SDL_memcmp(&pDeviceObject->guidType, &GUID_YAxis, sizeof(pDeviceObject->guidType)) == 0) { 660 in->ofs = DIJOFS_Y; 661 } else if (SDL_memcmp(&pDeviceObject->guidType, &GUID_ZAxis, sizeof(pDeviceObject->guidType)) == 0) { 662 in->ofs = DIJOFS_Z; 663 } else if (SDL_memcmp(&pDeviceObject->guidType, &GUID_RxAxis, sizeof(pDeviceObject->guidType)) == 0) { 664 in->ofs = DIJOFS_RX; 665 } else if (SDL_memcmp(&pDeviceObject->guidType, &GUID_RyAxis, sizeof(pDeviceObject->guidType)) == 0) { 666 in->ofs = DIJOFS_RY; 667 } else if (SDL_memcmp(&pDeviceObject->guidType, &GUID_RzAxis, sizeof(pDeviceObject->guidType)) == 0) { 668 in->ofs = DIJOFS_RZ; 669 } else if (SDL_memcmp(&pDeviceObject->guidType, &GUID_Slider, sizeof(pDeviceObject->guidType)) == 0) { 670 in->ofs = DIJOFS_SLIDER(joystick->hwdata->NumSliders); 671 ++joystick->hwdata->NumSliders; 672 } else { 673 return DIENUM_CONTINUE; // not an axis we can grok 674 } 675 676 diprg.diph.dwSize = sizeof(diprg); 677 diprg.diph.dwHeaderSize = sizeof(diprg.diph); 678 diprg.diph.dwObj = pDeviceObject->dwType; 679 diprg.diph.dwHow = DIPH_BYID; 680 diprg.lMin = SDL_JOYSTICK_AXIS_MIN; 681 diprg.lMax = SDL_JOYSTICK_AXIS_MAX; 682 683 result = 684 IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice, 685 DIPROP_RANGE, &diprg.diph); 686 if (FAILED(result)) { 687 return DIENUM_CONTINUE; // don't use this axis 688 } 689 690 // Set dead zone to 0. 691 dilong.diph.dwSize = sizeof(dilong); 692 dilong.diph.dwHeaderSize = sizeof(dilong.diph); 693 dilong.diph.dwObj = pDeviceObject->dwType; 694 dilong.diph.dwHow = DIPH_BYID; 695 dilong.dwData = 0; 696 result = 697 IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice, 698 DIPROP_DEADZONE, &dilong.diph); 699 if (FAILED(result)) { 700 return DIENUM_CONTINUE; // don't use this axis 701 } 702 703 joystick->naxes++; 704 } else { 705 // not supported at this time 706 return DIENUM_CONTINUE; 707 } 708 709 joystick->hwdata->NumInputs++; 710 711 if (joystick->hwdata->NumInputs == MAX_INPUTS) { 712 return DIENUM_STOP; // too many 713 } 714 715 return DIENUM_CONTINUE; 716} 717 718/* Sort using the data offset into the DInput struct. 719 * This gives a reasonable ordering for the inputs. 720 */ 721static int SDLCALL SortDevFunc(const void *a, const void *b) 722{ 723 const input_t *inputA = (const input_t *)a; 724 const input_t *inputB = (const input_t *)b; 725 726 if (inputA->ofs < inputB->ofs) { 727 return -1; 728 } 729 if (inputA->ofs > inputB->ofs) { 730 return 1; 731 } 732 return 0; 733} 734 735// Sort the input objects and recalculate the indices for each input. 736static void SortDevObjects(SDL_Joystick *joystick) 737{ 738 input_t *inputs = joystick->hwdata->Inputs; 739 Uint8 nButtons = 0; 740 Uint8 nHats = 0; 741 Uint8 nAxis = 0; 742 int n; 743 744 SDL_qsort(inputs, joystick->hwdata->NumInputs, sizeof(input_t), SortDevFunc); 745 746 for (n = 0; n < joystick->hwdata->NumInputs; n++) { 747 switch (inputs[n].type) { 748 case BUTTON: 749 inputs[n].num = nButtons; 750 nButtons++; 751 break; 752 753 case HAT: 754 inputs[n].num = nHats; 755 nHats++; 756 break; 757 758 case AXIS: 759 inputs[n].num = nAxis; 760 nAxis++; 761 break; 762 } 763 } 764} 765 766bool SDL_DINPUT_JoystickOpen(SDL_Joystick *joystick, JoyStick_DeviceData *joystickdevice) 767{ 768 HRESULT result; 769 DIPROPDWORD dipdw; 770 771 joystick->hwdata->buffered = true; 772 joystick->hwdata->Capabilities.dwSize = sizeof(DIDEVCAPS); 773 774 SDL_zero(dipdw); 775 dipdw.diph.dwSize = sizeof(DIPROPDWORD); 776 dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); 777 778 result = 779 IDirectInput8_CreateDevice(dinput, 780 &joystickdevice->dxdevice.guidInstance, 781 &joystick->hwdata->InputDevice, 782 NULL); 783 if (FAILED(result)) { 784 return SetDIerror("IDirectInput::CreateDevice", result); 785 } 786 787 /* Acquire shared access. Exclusive access is required for forces, 788 * though. */ 789 result = 790 IDirectInputDevice8_SetCooperativeLevel(joystick->hwdata->InputDevice, SDL_HelperWindow, 791 DISCL_EXCLUSIVE | 792 DISCL_BACKGROUND); 793 if (FAILED(result)) { 794 return SetDIerror("IDirectInputDevice8::SetCooperativeLevel", result); 795 } 796 797 // Use the extended data structure: DIJOYSTATE2. 798 result = 799 IDirectInputDevice8_SetDataFormat(joystick->hwdata->InputDevice, 800 &SDL_c_dfDIJoystick2); 801 if (FAILED(result)) { 802 return SetDIerror("IDirectInputDevice8::SetDataFormat", result); 803 } 804 805 if (!has_broken_EZFRD64DLL) { 806 // Get device capabilities to see if we are force feedback capable 807 result = 808 IDirectInputDevice8_GetCapabilities(joystick->hwdata->InputDevice, 809 &joystick->hwdata->Capabilities); 810 if (FAILED(result)) { 811 return SetDIerror("IDirectInputDevice8::GetCapabilities", result); 812 } 813 } 814 815 // Force capable? 816 if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) { 817 result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); 818 if (FAILED(result)) { 819 return SetDIerror("IDirectInputDevice8::Acquire", result); 820 } 821 822 // reset all actuators. 823 result = 824 IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, 825 DISFFC_RESET); 826 827 /* Not necessarily supported, ignore if not supported. 828 if (FAILED(result)) { 829 return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand", result); 830 } 831 */ 832 833 result = IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice); 834 835 if (FAILED(result)) { 836 return SetDIerror("IDirectInputDevice8::Unacquire", result); 837 } 838 839 /* Turn on auto-centering for a ForceFeedback device (until told 840 * otherwise). */ 841 dipdw.diph.dwObj = 0; 842 dipdw.diph.dwHow = DIPH_DEVICE; 843 dipdw.dwData = DIPROPAUTOCENTER_ON; 844 845 result = 846 IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice, 847 DIPROP_AUTOCENTER, &dipdw.diph); 848 849 /* Not necessarily supported, ignore if not supported. 850 if (FAILED(result)) { 851 return SetDIerror("IDirectInputDevice8::SetProperty", result); 852 } 853 */ 854 855 SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true); 856 } 857 858 // What buttons and axes does it have? 859 IDirectInputDevice8_EnumObjects(joystick->hwdata->InputDevice, 860 EnumDevObjectsCallback, joystick, 861 DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV); 862 863 /* Reorder the input objects. Some devices do not report the X axis as 864 * the first axis, for example. */ 865 SortDevObjects(joystick); 866 867 dipdw.diph.dwObj = 0; 868 dipdw.diph.dwHow = DIPH_DEVICE; 869 dipdw.dwData = INPUT_QSIZE; 870 871 // Set the buffer size 872 result = 873 IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice, 874 DIPROP_BUFFERSIZE, &dipdw.diph); 875 876 if (result == DI_POLLEDDEVICE) { 877 /* This device doesn't support buffering, so we're forced 878 * to use less reliable polling. */ 879 joystick->hwdata->buffered = false; 880 } else if (FAILED(result)) { 881 return SetDIerror("IDirectInputDevice8::SetProperty", result); 882 } 883 joystick->hwdata->first_update = true; 884 885 // Poll and wait for initial device state to be populated 886 result = IDirectInputDevice8_Poll(joystick->hwdata->InputDevice); 887 if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) { 888 IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); 889 IDirectInputDevice8_Poll(joystick->hwdata->InputDevice); 890 } 891 SDL_Delay(50); 892 893 return true; 894} 895 896static bool SDL_DINPUT_JoystickInitRumble(SDL_Joystick *joystick, Sint16 magnitude) 897{ 898 HRESULT result; 899 900 // Reset and then enable actuators 901 result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_RESET); 902 if (result == DIERR_INPUTLOST || result == DIERR_NOTEXCLUSIVEACQUIRED) { 903 result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); 904 if (SUCCEEDED(result)) { 905 result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_RESET); 906 } 907 } 908 if (FAILED(result)) { 909 return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand(DISFFC_RESET)", result); 910 } 911 912 result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_SETACTUATORSON); 913 if (FAILED(result)) { 914 return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand(DISFFC_SETACTUATORSON)", result); 915 } 916 917 // Create the effect 918 joystick->hwdata->ffeffect = CreateRumbleEffectData(magnitude); 919 if (!joystick->hwdata->ffeffect) { 920 return false; 921 } 922 923 result = IDirectInputDevice8_CreateEffect(joystick->hwdata->InputDevice, &GUID_Sine, 924 joystick->hwdata->ffeffect, &joystick->hwdata->ffeffect_ref, NULL); 925 if (FAILED(result)) { 926 return SetDIerror("IDirectInputDevice8::CreateEffect", result); 927 } 928 return true; 929} 930 931bool SDL_DINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 932{ 933 HRESULT result; 934 935 // Scale and average the two rumble strengths 936 Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2); 937 938 if (!(joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK)) { 939 return SDL_Unsupported(); 940 } 941 942 if (joystick->hwdata->ff_initialized) { 943 DIPERIODIC *periodic = ((DIPERIODIC *)joystick->hwdata->ffeffect->lpvTypeSpecificParams); 944 periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude); 945 946 result = IDirectInputEffect_SetParameters(joystick->hwdata->ffeffect_ref, joystick->hwdata->ffeffect, (DIEP_DURATION | DIEP_TYPESPECIFICPARAMS)); 947 if (result == DIERR_INPUTLOST) { 948 result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); 949 if (SUCCEEDED(result)) { 950 result = IDirectInputEffect_SetParameters(joystick->hwdata->ffeffect_ref, joystick->hwdata->ffeffect, (DIEP_DURATION | DIEP_TYPESPECIFICPARAMS)); 951 } 952 } 953 if (FAILED(result)) { 954 return SetDIerror("IDirectInputDevice8::SetParameters", result); 955 } 956 } else { 957 if (!SDL_DINPUT_JoystickInitRumble(joystick, magnitude)) { 958 return false; 959 } 960 joystick->hwdata->ff_initialized = true; 961 } 962 963 result = IDirectInputEffect_Start(joystick->hwdata->ffeffect_ref, 1, 0); 964 if (result == DIERR_INPUTLOST || result == DIERR_NOTEXCLUSIVEACQUIRED) { 965 result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); 966 if (SUCCEEDED(result)) { 967 result = IDirectInputEffect_Start(joystick->hwdata->ffeffect_ref, 1, 0); 968 } 969 } 970 if (FAILED(result)) { 971 return SetDIerror("IDirectInputDevice8::Start", result); 972 } 973 return true; 974} 975 976static Uint8 TranslatePOV(DWORD value) 977{ 978 const Uint8 HAT_VALS[] = { 979 SDL_HAT_UP, 980 SDL_HAT_UP | SDL_HAT_RIGHT, 981 SDL_HAT_RIGHT, 982 SDL_HAT_DOWN | SDL_HAT_RIGHT, 983 SDL_HAT_DOWN, 984 SDL_HAT_DOWN | SDL_HAT_LEFT, 985 SDL_HAT_LEFT, 986 SDL_HAT_UP | SDL_HAT_LEFT 987 }; 988 989 if (LOWORD(value) == 0xFFFF) { 990 return SDL_HAT_CENTERED; 991 } 992 993 // Round the value up: 994 value += 4500 / 2; 995 value %= 36000; 996 value /= 4500; 997 998 if (value >= 8) { 999 return SDL_HAT_CENTERED; // shouldn't happen 1000 } 1001 1002 return HAT_VALS[value]; 1003} 1004 1005/* Function to update the state of a joystick - called as a device poll. 1006 * This function shouldn't update the joystick structure directly, 1007 * but instead should call SDL_PrivateJoystick*() to deliver events 1008 * and update joystick device state. 1009 */ 1010static void UpdateDINPUTJoystickState_Polled(SDL_Joystick *joystick) 1011{ 1012 DIJOYSTATE2 state; 1013 HRESULT result; 1014 int i; 1015 Uint64 timestamp = SDL_GetTicksNS(); 1016 1017 result = 1018 IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice, 1019 sizeof(DIJOYSTATE2), &state); 1020 if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) { 1021 IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); 1022 result = 1023 IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice, 1024 sizeof(DIJOYSTATE2), &state); 1025 } 1026 1027 if (result != DI_OK) { 1028 return; 1029 } 1030 1031 // Set each known axis, button and POV. 1032 for (i = 0; i < joystick->hwdata->NumInputs; ++i) { 1033 const input_t *in = &joystick->hwdata->Inputs[i]; 1034 1035 switch (in->type) { 1036 case AXIS: 1037 switch (in->ofs) { 1038 case DIJOFS_X: 1039 SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.lX); 1040 break; 1041 case DIJOFS_Y: 1042 SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.lY); 1043 break; 1044 case DIJOFS_Z: 1045 SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.lZ); 1046 break; 1047 case DIJOFS_RX: 1048 SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.lRx); 1049 break; 1050 case DIJOFS_RY: 1051 SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.lRy); 1052 break; 1053 case DIJOFS_RZ: 1054 SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.lRz); 1055 break; 1056 case DIJOFS_SLIDER(0): 1057 SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.rglSlider[0]); 1058 break; 1059 case DIJOFS_SLIDER(1): 1060 SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.rglSlider[1]); 1061 break; 1062 } 1063 break; 1064 1065 case BUTTON: 1066 SDL_SendJoystickButton(timestamp, joystick, in->num, 1067 (state.rgbButtons[in->ofs - DIJOFS_BUTTON0] != 0)); 1068 break; 1069 case HAT: 1070 { 1071 Uint8 pos = TranslatePOV(state.rgdwPOV[in->ofs - DIJOFS_POV(0)]); 1072 SDL_SendJoystickHat(timestamp, joystick, in->num, pos); 1073 break; 1074 } 1075 } 1076 } 1077} 1078 1079static void UpdateDINPUTJoystickState_Buffered(SDL_Joystick *joystick) 1080{ 1081 int i; 1082 HRESULT result; 1083 DWORD numevents; 1084 DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE]; 1085 Uint64 timestamp = SDL_GetTicksNS(); 1086 1087 numevents = INPUT_QSIZE; 1088 result = 1089 IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice, 1090 sizeof(DIDEVICEOBJECTDATA), evtbuf, 1091 &numevents, 0); 1092 if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) { 1093 IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); 1094 result = 1095 IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice, 1096 sizeof(DIDEVICEOBJECTDATA), 1097 evtbuf, &numevents, 0); 1098 } 1099 1100 // Handle the events or punt 1101 if (FAILED(result)) { 1102 return; 1103 } 1104 1105 for (i = 0; i < (int)numevents; ++i) { 1106 int j; 1107 1108 for (j = 0; j < joystick->hwdata->NumInputs; ++j) { 1109 const input_t *in = &joystick->hwdata->Inputs[j]; 1110 1111 if (evtbuf[i].dwOfs != in->ofs) { 1112 continue; 1113 } 1114 1115 switch (in->type) { 1116 case AXIS: 1117 SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)evtbuf[i].dwData); 1118 break; 1119 case BUTTON: 1120 SDL_SendJoystickButton(timestamp, joystick, in->num, 1121 (evtbuf[i].dwData != 0)); 1122 break; 1123 case HAT: 1124 { 1125 Uint8 pos = TranslatePOV(evtbuf[i].dwData); 1126 SDL_SendJoystickHat(timestamp, joystick, in->num, pos); 1127 } break; 1128 } 1129 } 1130 } 1131 1132 if (result == DI_BUFFEROVERFLOW) { 1133 /* Our buffer wasn't big enough to hold all the queued events, 1134 * so poll the device to make sure we have the complete state. 1135 */ 1136 UpdateDINPUTJoystickState_Polled(joystick); 1137 } 1138} 1139 1140void SDL_DINPUT_JoystickUpdate(SDL_Joystick *joystick) 1141{ 1142 HRESULT result; 1143 1144 result = IDirectInputDevice8_Poll(joystick->hwdata->InputDevice); 1145 if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) { 1146 IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); 1147 IDirectInputDevice8_Poll(joystick->hwdata->InputDevice); 1148 } 1149 1150 if (joystick->hwdata->first_update) { 1151 // Poll to get the initial state of the joystick 1152 UpdateDINPUTJoystickState_Polled(joystick); 1153 joystick->hwdata->first_update = false; 1154 return; 1155 } 1156 1157 if (joystick->hwdata->buffered ) { 1158 UpdateDINPUTJoystickState_Buffered(joystick); 1159 } else { 1160 UpdateDINPUTJoystickState_Polled(joystick); 1161 } 1162} 1163 1164void SDL_DINPUT_JoystickClose(SDL_Joystick *joystick) 1165{ 1166 if (joystick->hwdata->ffeffect_ref) { 1167 IDirectInputEffect_Unload(joystick->hwdata->ffeffect_ref); 1168 joystick->hwdata->ffeffect_ref = NULL; 1169 } 1170 if (joystick->hwdata->ffeffect) { 1171 FreeRumbleEffectData(joystick->hwdata->ffeffect); 1172 joystick->hwdata->ffeffect = NULL; 1173 } 1174 IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice); 1175 IDirectInputDevice8_Release(joystick->hwdata->InputDevice); 1176 joystick->hwdata->ff_initialized = false; 1177} 1178 1179void SDL_DINPUT_JoystickQuit(void) 1180{ 1181 if (dinput != NULL) { 1182 IDirectInput8_Release(dinput); 1183 dinput = NULL; 1184 } 1185 1186 if (coinitialized) { 1187 WIN_CoUninitialize(); 1188 coinitialized = false; 1189 } 1190} 1191 1192#else // !SDL_JOYSTICK_DINPUT 1193 1194typedef struct JoyStick_DeviceData JoyStick_DeviceData; 1195 1196bool SDL_DINPUT_JoystickInit(void) 1197{ 1198 return true; 1199} 1200 1201void SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext) 1202{ 1203} 1204 1205bool SDL_DINPUT_JoystickPresent(Uint16 vendor, Uint16 product, Uint16 version) 1206{ 1207 return false; 1208} 1209 1210bool SDL_DINPUT_JoystickOpen(SDL_Joystick *joystick, JoyStick_DeviceData *joystickdevice) 1211{ 1212 return SDL_Unsupported(); 1213} 1214 1215bool SDL_DINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 1216{ 1217 return SDL_Unsupported(); 1218} 1219 1220void SDL_DINPUT_JoystickUpdate(SDL_Joystick *joystick) 1221{ 1222} 1223 1224void SDL_DINPUT_JoystickClose(SDL_Joystick *joystick) 1225{ 1226} 1227 1228void SDL_DINPUT_JoystickQuit(void) 1229{ 1230} 1231 1232#endif // SDL_JOYSTICK_DINPUT 1233[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.