Atlas - SDL_dinputjoystick.c

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