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