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