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 | // This is the joystick API for Simple DirectMedia Layer |
24 | |
25 | #include "SDL_sysjoystick.h" |
26 | #include "../SDL_hints_c.h" |
27 | #include "SDL_gamepad_c.h" |
28 | #include "SDL_joystick_c.h" |
29 | #include "SDL_steam_virtual_gamepad.h" |
30 | |
31 | #include "../events/SDL_events_c.h" |
32 | #include "../video/SDL_sysvideo.h" |
33 | #include "../sensor/SDL_sensor_c.h" |
34 | #include "hidapi/SDL_hidapijoystick_c.h" |
35 | |
36 | // This is included in only one place because it has a large static list of controllers |
37 | #include "controller_type.h" |
38 | |
39 | #if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) |
40 | // Needed for checking for input remapping programs |
41 | #include "../core/windows/SDL_windows.h" |
42 | |
43 | #undef UNICODE // We want ASCII functions |
44 | #include <tlhelp32.h> |
45 | #endif |
46 | |
47 | #ifdef SDL_JOYSTICK_VIRTUAL |
48 | #include "./virtual/SDL_virtualjoystick_c.h" |
49 | #endif |
50 | |
51 | static SDL_JoystickDriver *SDL_joystick_drivers[] = { |
52 | #ifdef SDL_JOYSTICK_HIDAPI // Highest priority driver for supported devices |
53 | &SDL_HIDAPI_JoystickDriver, |
54 | #endif |
55 | #ifdef SDL_JOYSTICK_PRIVATE |
56 | &SDL_PRIVATE_JoystickDriver, |
57 | #endif |
58 | #ifdef SDL_JOYSTICK_GAMEINPUT // Higher priority than other Windows drivers |
59 | &SDL_GAMEINPUT_JoystickDriver, |
60 | #endif |
61 | #ifdef SDL_JOYSTICK_RAWINPUT // Before WINDOWS driver, as WINDOWS wants to check if this driver is handling things |
62 | &SDL_RAWINPUT_JoystickDriver, |
63 | #endif |
64 | #if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) // Before WGI driver, as WGI wants to check if this driver is handling things |
65 | &SDL_WINDOWS_JoystickDriver, |
66 | #endif |
67 | #ifdef SDL_JOYSTICK_WGI |
68 | &SDL_WGI_JoystickDriver, |
69 | #endif |
70 | #ifdef SDL_JOYSTICK_WINMM |
71 | &SDL_WINMM_JoystickDriver, |
72 | #endif |
73 | #ifdef SDL_JOYSTICK_LINUX |
74 | &SDL_LINUX_JoystickDriver, |
75 | #endif |
76 | #ifdef SDL_JOYSTICK_IOKIT |
77 | &SDL_DARWIN_JoystickDriver, |
78 | #endif |
79 | #if (defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS)) && !defined(SDL_JOYSTICK_DISABLED) |
80 | &SDL_IOS_JoystickDriver, |
81 | #endif |
82 | #ifdef SDL_JOYSTICK_ANDROID |
83 | &SDL_ANDROID_JoystickDriver, |
84 | #endif |
85 | #ifdef SDL_JOYSTICK_EMSCRIPTEN |
86 | &SDL_EMSCRIPTEN_JoystickDriver, |
87 | #endif |
88 | #ifdef SDL_JOYSTICK_HAIKU |
89 | &SDL_HAIKU_JoystickDriver, |
90 | #endif |
91 | #ifdef SDL_JOYSTICK_USBHID /* !!! FIXME: "USBHID" is a generic name, and doubly-confusing with HIDAPI next to it. This is the *BSD interface, rename this. */ |
92 | &SDL_BSD_JoystickDriver, |
93 | #endif |
94 | #ifdef SDL_JOYSTICK_PS2 |
95 | &SDL_PS2_JoystickDriver, |
96 | #endif |
97 | #ifdef SDL_JOYSTICK_PSP |
98 | &SDL_PSP_JoystickDriver, |
99 | #endif |
100 | #ifdef SDL_JOYSTICK_VIRTUAL |
101 | &SDL_VIRTUAL_JoystickDriver, |
102 | #endif |
103 | #ifdef SDL_JOYSTICK_VITA |
104 | &SDL_VITA_JoystickDriver, |
105 | #endif |
106 | #ifdef SDL_JOYSTICK_N3DS |
107 | &SDL_N3DS_JoystickDriver, |
108 | #endif |
109 | #if defined(SDL_JOYSTICK_DUMMY) || defined(SDL_JOYSTICK_DISABLED) |
110 | &SDL_DUMMY_JoystickDriver |
111 | #endif |
112 | }; |
113 | |
114 | #ifndef SDL_THREAD_SAFETY_ANALYSIS |
115 | static |
116 | #endif |
117 | SDL_Mutex *SDL_joystick_lock = NULL; // This needs to support recursive locks |
118 | static SDL_AtomicInt SDL_joystick_lock_pending; |
119 | static int SDL_joysticks_locked; |
120 | static bool SDL_joysticks_initialized; |
121 | static bool SDL_joysticks_quitting; |
122 | static bool SDL_joystick_being_added; |
123 | static SDL_Joystick *SDL_joysticks SDL_GUARDED_BY(SDL_joystick_lock) = NULL; |
124 | static int SDL_joystick_player_count SDL_GUARDED_BY(SDL_joystick_lock) = 0; |
125 | static SDL_JoystickID *SDL_joystick_players SDL_GUARDED_BY(SDL_joystick_lock) = NULL; |
126 | static bool SDL_joystick_allows_background_events = false; |
127 | |
128 | static Uint32 initial_arcadestick_devices[] = { |
129 | MAKE_VIDPID(0x0079, 0x181a), // Venom Arcade Stick |
130 | MAKE_VIDPID(0x0079, 0x181b), // Venom Arcade Stick |
131 | MAKE_VIDPID(0x0c12, 0x0ef6), // Hitbox Arcade Stick |
132 | MAKE_VIDPID(0x0e6f, 0x0109), // PDP Versus Fighting Pad |
133 | MAKE_VIDPID(0x0f0d, 0x0016), // Hori Real Arcade Pro.EX |
134 | MAKE_VIDPID(0x0f0d, 0x001b), // Hori Real Arcade Pro VX |
135 | MAKE_VIDPID(0x0f0d, 0x0063), // Hori Real Arcade Pro Hayabusa (USA) Xbox One |
136 | MAKE_VIDPID(0x0f0d, 0x006a), // Real Arcade Pro 4 |
137 | MAKE_VIDPID(0x0f0d, 0x0078), // Hori Real Arcade Pro V Kai Xbox One |
138 | MAKE_VIDPID(0x0f0d, 0x008a), // HORI Real Arcade Pro 4 |
139 | MAKE_VIDPID(0x0f0d, 0x008c), // Hori Real Arcade Pro 4 |
140 | MAKE_VIDPID(0x0f0d, 0x00aa), // HORI Real Arcade Pro V Hayabusa in Switch Mode |
141 | MAKE_VIDPID(0x0f0d, 0x00ed), // Hori Fighting Stick mini 4 kai |
142 | MAKE_VIDPID(0x0f0d, 0x011c), // Hori Fighting Stick Alpha in PS4 Mode |
143 | MAKE_VIDPID(0x0f0d, 0x011e), // Hori Fighting Stick Alpha in PC Mode |
144 | MAKE_VIDPID(0x0f0d, 0x0184), // Hori Fighting Stick Alpha in PS5 Mode |
145 | MAKE_VIDPID(0x146b, 0x0604), // NACON Daija Arcade Stick |
146 | MAKE_VIDPID(0x1532, 0x0a00), // Razer Atrox Arcade Stick |
147 | MAKE_VIDPID(0x1bad, 0xf03d), // Street Fighter IV Arcade Stick TE - Chun Li |
148 | MAKE_VIDPID(0x1bad, 0xf502), // Hori Real Arcade Pro.VX SA |
149 | MAKE_VIDPID(0x1bad, 0xf504), // Hori Real Arcade Pro. EX |
150 | MAKE_VIDPID(0x1bad, 0xf506), // Hori Real Arcade Pro.EX Premium VLX |
151 | MAKE_VIDPID(0x20d6, 0xa715), // PowerA Nintendo Switch Fusion Arcade Stick |
152 | MAKE_VIDPID(0x24c6, 0x5000), // Razer Atrox Arcade Stick |
153 | MAKE_VIDPID(0x24c6, 0x5501), // Hori Real Arcade Pro VX-SA |
154 | MAKE_VIDPID(0x24c6, 0x550e), // Hori Real Arcade Pro V Kai 360 |
155 | MAKE_VIDPID(0x2c22, 0x2300), // Qanba Obsidian Arcade Joystick in PS4 Mode |
156 | MAKE_VIDPID(0x2c22, 0x2302), // Qanba Obsidian Arcade Joystick in PS3 Mode |
157 | MAKE_VIDPID(0x2c22, 0x2303), // Qanba Obsidian Arcade Joystick in PC Mode |
158 | MAKE_VIDPID(0x2c22, 0x2500), // Qanba Dragon Arcade Joystick in PS4 Mode |
159 | MAKE_VIDPID(0x2c22, 0x2502), // Qanba Dragon Arcade Joystick in PS3 Mode |
160 | MAKE_VIDPID(0x2c22, 0x2503), // Qanba Dragon Arcade Joystick in PC Mode |
161 | }; |
162 | static SDL_vidpid_list arcadestick_devices = { |
163 | SDL_HINT_JOYSTICK_ARCADESTICK_DEVICES, 0, 0, NULL, |
164 | SDL_HINT_JOYSTICK_ARCADESTICK_DEVICES_EXCLUDED, 0, 0, NULL, |
165 | SDL_arraysize(initial_arcadestick_devices), initial_arcadestick_devices, |
166 | false |
167 | }; |
168 | |
169 | /* This list is taken from: |
170 | https://raw.githubusercontent.com/denilsonsa/udev-joystick-blacklist/master/generate_rules.py |
171 | */ |
172 | static Uint32 initial_blacklist_devices[] = { |
173 | // Microsoft Microsoft Wireless Optical Desktop 2.10 |
174 | // Microsoft Wireless Desktop - Comfort Edition |
175 | MAKE_VIDPID(0x045e, 0x009d), |
176 | |
177 | // Microsoft Microsoft Digital Media Pro Keyboard |
178 | // Microsoft Corp. Digital Media Pro Keyboard |
179 | MAKE_VIDPID(0x045e, 0x00b0), |
180 | |
181 | // Microsoft Microsoft Digital Media Keyboard |
182 | // Microsoft Corp. Digital Media Keyboard 1.0A |
183 | MAKE_VIDPID(0x045e, 0x00b4), |
184 | |
185 | // Microsoft Microsoft Digital Media Keyboard 3000 |
186 | MAKE_VIDPID(0x045e, 0x0730), |
187 | |
188 | // Microsoft Microsoft 2.4GHz Transceiver v6.0 |
189 | // Microsoft Microsoft 2.4GHz Transceiver v8.0 |
190 | // Microsoft Corp. Nano Transceiver v1.0 for Bluetooth |
191 | // Microsoft Wireless Mobile Mouse 1000 |
192 | // Microsoft Wireless Desktop 3000 |
193 | MAKE_VIDPID(0x045e, 0x0745), |
194 | |
195 | // Microsoft SideWinder(TM) 2.4GHz Transceiver |
196 | MAKE_VIDPID(0x045e, 0x0748), |
197 | |
198 | // Microsoft Corp. Wired Keyboard 600 |
199 | MAKE_VIDPID(0x045e, 0x0750), |
200 | |
201 | // Microsoft Corp. Sidewinder X4 keyboard |
202 | MAKE_VIDPID(0x045e, 0x0768), |
203 | |
204 | // Microsoft Corp. Arc Touch Mouse Transceiver |
205 | MAKE_VIDPID(0x045e, 0x0773), |
206 | |
207 | // Microsoft 2.4GHz Transceiver v9.0 |
208 | // Microsoft Nano Transceiver v2.1 |
209 | // Microsoft Sculpt Ergonomic Keyboard (5KV-00001) |
210 | MAKE_VIDPID(0x045e, 0x07a5), |
211 | |
212 | // Microsoft Nano Transceiver v1.0 |
213 | // Microsoft Wireless Keyboard 800 |
214 | MAKE_VIDPID(0x045e, 0x07b2), |
215 | |
216 | // Microsoft Nano Transceiver v2.0 |
217 | MAKE_VIDPID(0x045e, 0x0800), |
218 | |
219 | MAKE_VIDPID(0x046d, 0xc30a), // Logitech, Inc. iTouch Composite keyboard |
220 | |
221 | MAKE_VIDPID(0x04d9, 0xa0df), // Tek Syndicate Mouse (E-Signal USB Gaming Mouse) |
222 | |
223 | // List of Wacom devices at: http://linuxwacom.sourceforge.net/wiki/index.php/Device_IDs |
224 | MAKE_VIDPID(0x056a, 0x0010), // Wacom ET-0405 Graphire |
225 | MAKE_VIDPID(0x056a, 0x0011), // Wacom ET-0405A Graphire2 (4x5) |
226 | MAKE_VIDPID(0x056a, 0x0012), // Wacom ET-0507A Graphire2 (5x7) |
227 | MAKE_VIDPID(0x056a, 0x0013), // Wacom CTE-430 Graphire3 (4x5) |
228 | MAKE_VIDPID(0x056a, 0x0014), // Wacom CTE-630 Graphire3 (6x8) |
229 | MAKE_VIDPID(0x056a, 0x0015), // Wacom CTE-440 Graphire4 (4x5) |
230 | MAKE_VIDPID(0x056a, 0x0016), // Wacom CTE-640 Graphire4 (6x8) |
231 | MAKE_VIDPID(0x056a, 0x0017), // Wacom CTE-450 Bamboo Fun (4x5) |
232 | MAKE_VIDPID(0x056a, 0x0018), // Wacom CTE-650 Bamboo Fun 6x8 |
233 | MAKE_VIDPID(0x056a, 0x0019), // Wacom CTE-631 Bamboo One |
234 | MAKE_VIDPID(0x056a, 0x00d1), // Wacom Bamboo Pen and Touch CTH-460 |
235 | MAKE_VIDPID(0x056a, 0x030e), // Wacom Intuos Pen (S) CTL-480 |
236 | |
237 | MAKE_VIDPID(0x09da, 0x054f), // A4 Tech Co., G7 750 mouse |
238 | MAKE_VIDPID(0x09da, 0x1410), // A4 Tech Co., Ltd Bloody AL9 mouse |
239 | MAKE_VIDPID(0x09da, 0x3043), // A4 Tech Co., Ltd Bloody R8A Gaming Mouse |
240 | MAKE_VIDPID(0x09da, 0x31b5), // A4 Tech Co., Ltd Bloody TL80 Terminator Laser Gaming Mouse |
241 | MAKE_VIDPID(0x09da, 0x3997), // A4 Tech Co., Ltd Bloody RT7 Terminator Wireless |
242 | MAKE_VIDPID(0x09da, 0x3f8b), // A4 Tech Co., Ltd Bloody V8 mouse |
243 | MAKE_VIDPID(0x09da, 0x51f4), // Modecom MC-5006 Keyboard |
244 | MAKE_VIDPID(0x09da, 0x5589), // A4 Tech Co., Ltd Terminator TL9 Laser Gaming Mouse |
245 | MAKE_VIDPID(0x09da, 0x7b22), // A4 Tech Co., Ltd Bloody V5 |
246 | MAKE_VIDPID(0x09da, 0x7f2d), // A4 Tech Co., Ltd Bloody R3 mouse |
247 | MAKE_VIDPID(0x09da, 0x8090), // A4 Tech Co., Ltd X-718BK Oscar Optical Gaming Mouse |
248 | MAKE_VIDPID(0x09da, 0x9033), // A4 Tech Co., X7 X-705K |
249 | MAKE_VIDPID(0x09da, 0x9066), // A4 Tech Co., Sharkoon Fireglider Optical |
250 | MAKE_VIDPID(0x09da, 0x9090), // A4 Tech Co., Ltd XL-730K / XL-750BK / XL-755BK Laser Mouse |
251 | MAKE_VIDPID(0x09da, 0x90c0), // A4 Tech Co., Ltd X7 G800V keyboard |
252 | MAKE_VIDPID(0x09da, 0xf012), // A4 Tech Co., Ltd Bloody V7 mouse |
253 | MAKE_VIDPID(0x09da, 0xf32a), // A4 Tech Co., Ltd Bloody B540 keyboard |
254 | MAKE_VIDPID(0x09da, 0xf613), // A4 Tech Co., Ltd Bloody V2 mouse |
255 | MAKE_VIDPID(0x09da, 0xf624), // A4 Tech Co., Ltd Bloody B120 Keyboard |
256 | |
257 | MAKE_VIDPID(0x1b1c, 0x1b3c), // Corsair Harpoon RGB gaming mouse |
258 | |
259 | MAKE_VIDPID(0x1d57, 0xad03), // [T3] 2.4GHz and IR Air Mouse Remote Control |
260 | |
261 | MAKE_VIDPID(0x1e7d, 0x2e4a), // Roccat Tyon Mouse |
262 | |
263 | MAKE_VIDPID(0x20a0, 0x422d), // Winkeyless.kr Keyboards |
264 | |
265 | MAKE_VIDPID(0x2516, 0x001f), // Cooler Master Storm Mizar Mouse |
266 | MAKE_VIDPID(0x2516, 0x0028), // Cooler Master Storm Alcor Mouse |
267 | |
268 | /*****************************************************************/ |
269 | // Additional entries |
270 | /*****************************************************************/ |
271 | |
272 | MAKE_VIDPID(0x04d9, 0x8008), // OBINLB USB-HID Keyboard (Anne Pro II) |
273 | MAKE_VIDPID(0x04d9, 0x8009), // OBINLB USB-HID Keyboard (Anne Pro II) |
274 | MAKE_VIDPID(0x04d9, 0xa292), // OBINLB USB-HID Keyboard (Anne Pro II) |
275 | MAKE_VIDPID(0x04d9, 0xa293), // OBINLB USB-HID Keyboard (Anne Pro II) |
276 | MAKE_VIDPID(0x1532, 0x0266), // Razer Huntsman V2 Analog, non-functional DInput device |
277 | MAKE_VIDPID(0x1532, 0x0282), // Razer Huntsman Mini Analog, non-functional DInput device |
278 | MAKE_VIDPID(0x26ce, 0x01a2), // ASRock LED Controller |
279 | MAKE_VIDPID(0x20d6, 0x0002), // PowerA Enhanced Wireless Controller for Nintendo Switch (charging port only) |
280 | }; |
281 | static SDL_vidpid_list blacklist_devices = { |
282 | SDL_HINT_JOYSTICK_BLACKLIST_DEVICES, 0, 0, NULL, |
283 | SDL_HINT_JOYSTICK_BLACKLIST_DEVICES_EXCLUDED, 0, 0, NULL, |
284 | SDL_arraysize(initial_blacklist_devices), initial_blacklist_devices, |
285 | false |
286 | }; |
287 | |
288 | static Uint32 initial_flightstick_devices[] = { |
289 | MAKE_VIDPID(0x044f, 0x0402), // HOTAS Warthog Joystick |
290 | MAKE_VIDPID(0x044f, 0xb10a), // ThrustMaster, Inc. T.16000M Joystick |
291 | MAKE_VIDPID(0x046d, 0xc215), // Logitech Extreme 3D |
292 | MAKE_VIDPID(0x0738, 0x2221), // Saitek Pro Flight X-56 Rhino Stick |
293 | MAKE_VIDPID(0x231d, 0x0126), // Gunfighter Mk.III 'Space Combat Edition' (right) |
294 | MAKE_VIDPID(0x231d, 0x0127), // Gunfighter Mk.III 'Space Combat Edition' (left) |
295 | MAKE_VIDPID(0x362c, 0x0001), // Yawman Arrow |
296 | }; |
297 | static SDL_vidpid_list flightstick_devices = { |
298 | SDL_HINT_JOYSTICK_FLIGHTSTICK_DEVICES, 0, 0, NULL, |
299 | SDL_HINT_JOYSTICK_FLIGHTSTICK_DEVICES_EXCLUDED, 0, 0, NULL, |
300 | SDL_arraysize(initial_flightstick_devices), initial_flightstick_devices, |
301 | false |
302 | }; |
303 | |
304 | static Uint32 initial_gamecube_devices[] = { |
305 | MAKE_VIDPID(0x0e6f, 0x0185), // PDP Wired Fight Pad Pro for Nintendo Switch |
306 | MAKE_VIDPID(0x20d6, 0xa711), // PowerA Wired Controller Nintendo GameCube Style |
307 | }; |
308 | static SDL_vidpid_list gamecube_devices = { |
309 | SDL_HINT_JOYSTICK_GAMECUBE_DEVICES, 0, 0, NULL, |
310 | SDL_HINT_JOYSTICK_GAMECUBE_DEVICES_EXCLUDED, 0, 0, NULL, |
311 | SDL_arraysize(initial_gamecube_devices), initial_gamecube_devices, |
312 | false |
313 | }; |
314 | |
315 | static Uint32 initial_rog_gamepad_mice[] = { |
316 | MAKE_VIDPID(0x0b05, 0x18e3), // ROG Chakram (wired) Mouse |
317 | MAKE_VIDPID(0x0b05, 0x18e5), // ROG Chakram (wireless) Mouse |
318 | MAKE_VIDPID(0x0b05, 0x1906), // ROG Pugio II |
319 | MAKE_VIDPID(0x0b05, 0x1958), // ROG Chakram Core Mouse |
320 | MAKE_VIDPID(0x0b05, 0x1a18), // ROG Chakram X (wired) Mouse |
321 | MAKE_VIDPID(0x0b05, 0x1a1a), // ROG Chakram X (wireless) Mouse |
322 | MAKE_VIDPID(0x0b05, 0x1a1c), // ROG Chakram X (Bluetooth) Mouse |
323 | }; |
324 | static SDL_vidpid_list rog_gamepad_mice = { |
325 | SDL_HINT_ROG_GAMEPAD_MICE, 0, 0, NULL, |
326 | SDL_HINT_ROG_GAMEPAD_MICE_EXCLUDED, 0, 0, NULL, |
327 | SDL_arraysize(initial_rog_gamepad_mice), initial_rog_gamepad_mice, |
328 | false |
329 | }; |
330 | |
331 | static Uint32 initial_throttle_devices[] = { |
332 | MAKE_VIDPID(0x044f, 0x0404), // HOTAS Warthog Throttle |
333 | MAKE_VIDPID(0x0738, 0xa221), // Saitek Pro Flight X-56 Rhino Throttle |
334 | }; |
335 | static SDL_vidpid_list throttle_devices = { |
336 | SDL_HINT_JOYSTICK_THROTTLE_DEVICES, 0, 0, NULL, |
337 | SDL_HINT_JOYSTICK_THROTTLE_DEVICES_EXCLUDED, 0, 0, NULL, |
338 | SDL_arraysize(initial_throttle_devices), initial_throttle_devices, |
339 | false |
340 | }; |
341 | |
342 | static Uint32 initial_wheel_devices[] = { |
343 | MAKE_VIDPID(0x0079, 0x1864), // DragonRise Inc. Wired Wheel (active mode) (also known as PXN V900 (PS3), Superdrive SV-750, or a Genesis Seaborg 400) |
344 | MAKE_VIDPID(0x044f, 0xb65d), // Thrustmaster Wheel FFB |
345 | MAKE_VIDPID(0x044f, 0xb65e), // Thrustmaster T500RS |
346 | MAKE_VIDPID(0x044f, 0xb664), // Thrustmaster TX (initial mode) |
347 | MAKE_VIDPID(0x044f, 0xb669), // Thrustmaster TX (active mode) |
348 | MAKE_VIDPID(0x044f, 0xb66d), // Thrustmaster T300RS (PS4 mode) |
349 | MAKE_VIDPID(0x044f, 0xb66d), // Thrustmaster Wheel FFB |
350 | MAKE_VIDPID(0x044f, 0xb66e), // Thrustmaster T300RS (normal mode) |
351 | MAKE_VIDPID(0x044f, 0xb66f), // Thrustmaster T300RS (advanced mode) |
352 | MAKE_VIDPID(0x044f, 0xb677), // Thrustmaster T150 |
353 | MAKE_VIDPID(0x044f, 0xb67f), // Thrustmaster TMX |
354 | MAKE_VIDPID(0x044f, 0xb691), // Thrustmaster TS-XW (initial mode) |
355 | MAKE_VIDPID(0x044f, 0xb692), // Thrustmaster TS-XW (active mode) |
356 | MAKE_VIDPID(0x044f, 0xb696), // Thrustmaster T248 |
357 | MAKE_VIDPID(0x046d, 0xc24f), // Logitech G29 (PS3) |
358 | MAKE_VIDPID(0x046d, 0xc260), // Logitech G29 (PS4) |
359 | MAKE_VIDPID(0x046d, 0xc261), // Logitech G920 (initial mode) |
360 | MAKE_VIDPID(0x046d, 0xc262), // Logitech G920 (active mode) |
361 | MAKE_VIDPID(0x046d, 0xc266), // Logitech G923 for Playstation 4 and PC (PC mode) |
362 | MAKE_VIDPID(0x046d, 0xc267), // Logitech G923 for Playstation 4 and PC (PS4 mode) |
363 | MAKE_VIDPID(0x046d, 0xc268), // Logitech PRO Racing Wheel (PC mode) |
364 | MAKE_VIDPID(0x046d, 0xc269), // Logitech PRO Racing Wheel (PS4/PS5 mode) |
365 | MAKE_VIDPID(0x046d, 0xc26d), // Logitech G923 (Xbox) |
366 | MAKE_VIDPID(0x046d, 0xc26e), // Logitech G923 |
367 | MAKE_VIDPID(0x046d, 0xc272), // Logitech PRO Racing Wheel for Xbox (PC mode) |
368 | MAKE_VIDPID(0x046d, 0xc294), // Logitech generic wheel |
369 | MAKE_VIDPID(0x046d, 0xc295), // Logitech Momo Force |
370 | MAKE_VIDPID(0x046d, 0xc298), // Logitech Driving Force Pro |
371 | MAKE_VIDPID(0x046d, 0xc299), // Logitech G25 |
372 | MAKE_VIDPID(0x046d, 0xc29a), // Logitech Driving Force GT |
373 | MAKE_VIDPID(0x046d, 0xc29b), // Logitech G27 |
374 | MAKE_VIDPID(0x046d, 0xca03), // Logitech Momo Racing |
375 | MAKE_VIDPID(0x0483, 0x0522), // Simagic Wheelbase (including M10, Alpha Mini, Alpha, Alpha U) |
376 | MAKE_VIDPID(0x0483, 0xa355), // VRS DirectForce Pro Wheel Base |
377 | MAKE_VIDPID(0x0eb7, 0x0001), // Fanatec ClubSport Wheel Base V2 |
378 | MAKE_VIDPID(0x0eb7, 0x0004), // Fanatec ClubSport Wheel Base V2.5 |
379 | MAKE_VIDPID(0x0eb7, 0x0005), // Fanatec CSL Elite Wheel Base+ (PS4) |
380 | MAKE_VIDPID(0x0eb7, 0x0006), // Fanatec Podium Wheel Base DD1 |
381 | MAKE_VIDPID(0x0eb7, 0x0007), // Fanatec Podium Wheel Base DD2 |
382 | MAKE_VIDPID(0x0eb7, 0x0011), // Fanatec Forza Motorsport (CSR Wheel / CSR Elite Wheel) |
383 | MAKE_VIDPID(0x0eb7, 0x0020), // Fanatec generic wheel / CSL DD / GT DD Pro |
384 | MAKE_VIDPID(0x0eb7, 0x0197), // Fanatec Porsche Wheel (Turbo / GT3 RS / Turbo S / GT3 V2 / GT2) |
385 | MAKE_VIDPID(0x0eb7, 0x038e), // Fanatec ClubSport Wheel Base V1 |
386 | MAKE_VIDPID(0x0eb7, 0x0e03), // Fanatec CSL Elite Wheel Base |
387 | MAKE_VIDPID(0x11ff, 0x0511), // DragonRise Inc. Wired Wheel (initial mode) (also known as PXN V900 (PS3), Superdrive SV-750, or a Genesis Seaborg 400) |
388 | MAKE_VIDPID(0x1209, 0xffb0), // Generic FFBoard OpenFFBoard universal forcefeedback wheel |
389 | MAKE_VIDPID(0x16d0, 0x0d5a), // Simucube 1 Wheelbase |
390 | MAKE_VIDPID(0x16d0, 0x0d5f), // Simucube 2 Ultimate Wheelbase |
391 | MAKE_VIDPID(0x16d0, 0x0d60), // Simucube 2 Pro Wheelbase |
392 | MAKE_VIDPID(0x16d0, 0x0d61), // Simucube 2 Sport Wheelbase |
393 | MAKE_VIDPID(0x2433, 0xf300), // Asetek SimSports Invicta Wheelbase |
394 | MAKE_VIDPID(0x2433, 0xf301), // Asetek SimSports Forte Wheelbase |
395 | MAKE_VIDPID(0x2433, 0xf303), // Asetek SimSports La Prima Wheelbase |
396 | MAKE_VIDPID(0x2433, 0xf306), // Asetek SimSports Tony Kannan Wheelbase |
397 | MAKE_VIDPID(0x3416, 0x0301), // Cammus C5 Wheelbase |
398 | MAKE_VIDPID(0x3416, 0x0302), // Cammus C12 Wheelbase |
399 | MAKE_VIDPID(0x346e, 0x0000), // Moza R16/R21 Wheelbase |
400 | MAKE_VIDPID(0x346e, 0x0002), // Moza R9 Wheelbase |
401 | MAKE_VIDPID(0x346e, 0x0004), // Moza R5 Wheelbase |
402 | MAKE_VIDPID(0x346e, 0x0005), // Moza R3 Wheelbase |
403 | MAKE_VIDPID(0x346e, 0x0006), // Moza R12 Wheelbase |
404 | }; |
405 | static SDL_vidpid_list wheel_devices = { |
406 | SDL_HINT_JOYSTICK_WHEEL_DEVICES, 0, 0, NULL, |
407 | SDL_HINT_JOYSTICK_WHEEL_DEVICES_EXCLUDED, 0, 0, NULL, |
408 | SDL_arraysize(initial_wheel_devices), initial_wheel_devices, |
409 | false |
410 | }; |
411 | |
412 | static Uint32 initial_zero_centered_devices[] = { |
413 | MAKE_VIDPID(0x05a0, 0x3232), // 8Bitdo Zero Gamepad |
414 | MAKE_VIDPID(0x0e8f, 0x3013), // HuiJia SNES USB adapter |
415 | }; |
416 | static SDL_vidpid_list zero_centered_devices = { |
417 | SDL_HINT_JOYSTICK_ZERO_CENTERED_DEVICES, 0, 0, NULL, |
418 | NULL, 0, 0, NULL, |
419 | SDL_arraysize(initial_zero_centered_devices), initial_zero_centered_devices, |
420 | false |
421 | }; |
422 | |
423 | #define CHECK_JOYSTICK_MAGIC(joystick, result) \ |
424 | if (!SDL_ObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK)) { \ |
425 | SDL_InvalidParamError("joystick"); \ |
426 | SDL_UnlockJoysticks(); \ |
427 | return result; \ |
428 | } |
429 | |
430 | bool SDL_JoysticksInitialized(void) |
431 | { |
432 | return SDL_joysticks_initialized; |
433 | } |
434 | |
435 | bool SDL_JoysticksQuitting(void) |
436 | { |
437 | return SDL_joysticks_quitting; |
438 | } |
439 | |
440 | void SDL_LockJoysticks(void) |
441 | { |
442 | (void)SDL_AtomicIncRef(&SDL_joystick_lock_pending); |
443 | SDL_LockMutex(SDL_joystick_lock); |
444 | (void)SDL_AtomicDecRef(&SDL_joystick_lock_pending); |
445 | |
446 | ++SDL_joysticks_locked; |
447 | } |
448 | |
449 | void SDL_UnlockJoysticks(void) |
450 | { |
451 | bool last_unlock = false; |
452 | |
453 | --SDL_joysticks_locked; |
454 | |
455 | if (!SDL_joysticks_initialized) { |
456 | // NOTE: There's a small window here where another thread could lock the mutex after we've checked for pending locks |
457 | if (!SDL_joysticks_locked && SDL_GetAtomicInt(&SDL_joystick_lock_pending) == 0) { |
458 | last_unlock = true; |
459 | } |
460 | } |
461 | |
462 | /* The last unlock after joysticks are uninitialized will cleanup the mutex, |
463 | * allowing applications to lock joysticks while reinitializing the system. |
464 | */ |
465 | if (last_unlock) { |
466 | SDL_Mutex *joystick_lock = SDL_joystick_lock; |
467 | |
468 | SDL_LockMutex(joystick_lock); |
469 | { |
470 | SDL_UnlockMutex(SDL_joystick_lock); |
471 | |
472 | SDL_joystick_lock = NULL; |
473 | } |
474 | SDL_UnlockMutex(joystick_lock); |
475 | SDL_DestroyMutex(joystick_lock); |
476 | } else { |
477 | SDL_UnlockMutex(SDL_joystick_lock); |
478 | } |
479 | } |
480 | |
481 | bool SDL_JoysticksLocked(void) |
482 | { |
483 | return (SDL_joysticks_locked > 0); |
484 | } |
485 | |
486 | void SDL_AssertJoysticksLocked(void) |
487 | { |
488 | SDL_assert(SDL_JoysticksLocked()); |
489 | } |
490 | |
491 | /* |
492 | * Get the driver and device index for a joystick instance ID |
493 | * This should be called while the joystick lock is held, to prevent another thread from updating the list |
494 | */ |
495 | static bool SDL_GetDriverAndJoystickIndex(SDL_JoystickID instance_id, SDL_JoystickDriver **driver, int *driver_index) |
496 | { |
497 | int i, num_joysticks, device_index; |
498 | |
499 | SDL_AssertJoysticksLocked(); |
500 | |
501 | if (instance_id > 0) { |
502 | for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) { |
503 | num_joysticks = SDL_joystick_drivers[i]->GetCount(); |
504 | for (device_index = 0; device_index < num_joysticks; ++device_index) { |
505 | SDL_JoystickID joystick_id = SDL_joystick_drivers[i]->GetDeviceInstanceID(device_index); |
506 | if (joystick_id == instance_id) { |
507 | *driver = SDL_joystick_drivers[i]; |
508 | *driver_index = device_index; |
509 | return true; |
510 | } |
511 | } |
512 | } |
513 | } |
514 | |
515 | SDL_SetError("Joystick %" SDL_PRIu32 " not found" , instance_id); |
516 | return false; |
517 | } |
518 | |
519 | static int SDL_FindFreePlayerIndex(void) |
520 | { |
521 | int player_index; |
522 | |
523 | SDL_AssertJoysticksLocked(); |
524 | |
525 | for (player_index = 0; player_index < SDL_joystick_player_count; ++player_index) { |
526 | if (SDL_joystick_players[player_index] == 0) { |
527 | break; |
528 | } |
529 | } |
530 | return player_index; |
531 | } |
532 | |
533 | static int SDL_GetPlayerIndexForJoystickID(SDL_JoystickID instance_id) |
534 | { |
535 | int player_index; |
536 | |
537 | SDL_AssertJoysticksLocked(); |
538 | |
539 | for (player_index = 0; player_index < SDL_joystick_player_count; ++player_index) { |
540 | if (instance_id == SDL_joystick_players[player_index]) { |
541 | break; |
542 | } |
543 | } |
544 | if (player_index == SDL_joystick_player_count) { |
545 | player_index = -1; |
546 | } |
547 | return player_index; |
548 | } |
549 | |
550 | static SDL_JoystickID SDL_GetJoystickIDForPlayerIndex(int player_index) |
551 | { |
552 | SDL_AssertJoysticksLocked(); |
553 | |
554 | if (player_index < 0 || player_index >= SDL_joystick_player_count) { |
555 | return 0; |
556 | } |
557 | return SDL_joystick_players[player_index]; |
558 | } |
559 | |
560 | static bool SDL_SetJoystickIDForPlayerIndex(int player_index, SDL_JoystickID instance_id) |
561 | { |
562 | SDL_JoystickID existing_instance = SDL_GetJoystickIDForPlayerIndex(player_index); |
563 | SDL_JoystickDriver *driver; |
564 | int device_index; |
565 | int existing_player_index; |
566 | |
567 | SDL_AssertJoysticksLocked(); |
568 | |
569 | if (player_index >= SDL_joystick_player_count) { |
570 | SDL_JoystickID *new_players = (SDL_JoystickID *)SDL_realloc(SDL_joystick_players, (player_index + 1) * sizeof(*SDL_joystick_players)); |
571 | if (!new_players) { |
572 | return false; |
573 | } |
574 | |
575 | SDL_joystick_players = new_players; |
576 | SDL_memset(&SDL_joystick_players[SDL_joystick_player_count], 0, (player_index - SDL_joystick_player_count + 1) * sizeof(SDL_joystick_players[0])); |
577 | SDL_joystick_player_count = player_index + 1; |
578 | } else if (player_index >= 0 && SDL_joystick_players[player_index] == instance_id) { |
579 | // Joystick is already assigned the requested player index |
580 | return true; |
581 | } |
582 | |
583 | // Clear the old player index |
584 | existing_player_index = SDL_GetPlayerIndexForJoystickID(instance_id); |
585 | if (existing_player_index >= 0) { |
586 | SDL_joystick_players[existing_player_index] = 0; |
587 | } |
588 | |
589 | if (player_index >= 0) { |
590 | SDL_joystick_players[player_index] = instance_id; |
591 | } |
592 | |
593 | // Update the driver with the new index |
594 | if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) { |
595 | driver->SetDevicePlayerIndex(device_index, player_index); |
596 | } |
597 | |
598 | // Move any existing joystick to another slot |
599 | if (existing_instance > 0) { |
600 | SDL_SetJoystickIDForPlayerIndex(SDL_FindFreePlayerIndex(), existing_instance); |
601 | } |
602 | return true; |
603 | } |
604 | |
605 | static void SDLCALL SDL_JoystickAllowBackgroundEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint) |
606 | { |
607 | if (SDL_GetStringBoolean(hint, false)) { |
608 | SDL_joystick_allows_background_events = true; |
609 | } else { |
610 | SDL_joystick_allows_background_events = false; |
611 | } |
612 | } |
613 | |
614 | bool SDL_InitJoysticks(void) |
615 | { |
616 | int i; |
617 | bool result = false; |
618 | |
619 | // Create the joystick list lock |
620 | if (SDL_joystick_lock == NULL) { |
621 | SDL_joystick_lock = SDL_CreateMutex(); |
622 | } |
623 | |
624 | if (!SDL_InitSubSystem(SDL_INIT_EVENTS)) { |
625 | return false; |
626 | } |
627 | |
628 | SDL_LockJoysticks(); |
629 | |
630 | SDL_joysticks_initialized = true; |
631 | |
632 | SDL_InitGamepadMappings(); |
633 | |
634 | SDL_LoadVIDPIDList(&arcadestick_devices); |
635 | SDL_LoadVIDPIDList(&blacklist_devices); |
636 | SDL_LoadVIDPIDList(&flightstick_devices); |
637 | SDL_LoadVIDPIDList(&gamecube_devices); |
638 | SDL_LoadVIDPIDList(&rog_gamepad_mice); |
639 | SDL_LoadVIDPIDList(&throttle_devices); |
640 | SDL_LoadVIDPIDList(&wheel_devices); |
641 | SDL_LoadVIDPIDList(&zero_centered_devices); |
642 | |
643 | // See if we should allow joystick events while in the background |
644 | SDL_AddHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, |
645 | SDL_JoystickAllowBackgroundEventsChanged, NULL); |
646 | |
647 | SDL_InitSteamVirtualGamepadInfo(); |
648 | |
649 | for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) { |
650 | if (SDL_joystick_drivers[i]->Init()) { |
651 | result = true; |
652 | } |
653 | } |
654 | SDL_UnlockJoysticks(); |
655 | |
656 | if (!result) { |
657 | SDL_QuitJoysticks(); |
658 | } |
659 | |
660 | return result; |
661 | } |
662 | |
663 | bool SDL_JoysticksOpened(void) |
664 | { |
665 | bool opened; |
666 | |
667 | SDL_LockJoysticks(); |
668 | { |
669 | if (SDL_joysticks != NULL) { |
670 | opened = true; |
671 | } else { |
672 | opened = false; |
673 | } |
674 | } |
675 | SDL_UnlockJoysticks(); |
676 | |
677 | return opened; |
678 | } |
679 | |
680 | bool SDL_JoystickHandledByAnotherDriver(struct SDL_JoystickDriver *driver, Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name) |
681 | { |
682 | int i; |
683 | bool result = false; |
684 | |
685 | SDL_LockJoysticks(); |
686 | { |
687 | for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) { |
688 | if (driver == SDL_joystick_drivers[i]) { |
689 | // Higher priority drivers do not have this device |
690 | break; |
691 | } |
692 | if (SDL_joystick_drivers[i]->IsDevicePresent(vendor_id, product_id, version, name)) { |
693 | result = true; |
694 | break; |
695 | } |
696 | } |
697 | } |
698 | SDL_UnlockJoysticks(); |
699 | |
700 | return result; |
701 | } |
702 | |
703 | bool SDL_HasJoystick(void) |
704 | { |
705 | int i; |
706 | int total_joysticks = 0; |
707 | |
708 | SDL_LockJoysticks(); |
709 | { |
710 | for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) { |
711 | total_joysticks += SDL_joystick_drivers[i]->GetCount(); |
712 | } |
713 | } |
714 | SDL_UnlockJoysticks(); |
715 | |
716 | if (total_joysticks > 0) { |
717 | return true; |
718 | } |
719 | return false; |
720 | } |
721 | |
722 | SDL_JoystickID *SDL_GetJoysticks(int *count) |
723 | { |
724 | int i, num_joysticks, device_index; |
725 | int joystick_index = 0, total_joysticks = 0; |
726 | SDL_JoystickID *joysticks; |
727 | |
728 | SDL_LockJoysticks(); |
729 | { |
730 | for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) { |
731 | total_joysticks += SDL_joystick_drivers[i]->GetCount(); |
732 | } |
733 | |
734 | joysticks = (SDL_JoystickID *)SDL_malloc((total_joysticks + 1) * sizeof(*joysticks)); |
735 | if (joysticks) { |
736 | if (count) { |
737 | *count = total_joysticks; |
738 | } |
739 | |
740 | for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) { |
741 | num_joysticks = SDL_joystick_drivers[i]->GetCount(); |
742 | for (device_index = 0; device_index < num_joysticks; ++device_index) { |
743 | SDL_assert(joystick_index < total_joysticks); |
744 | joysticks[joystick_index] = SDL_joystick_drivers[i]->GetDeviceInstanceID(device_index); |
745 | SDL_assert(joysticks[joystick_index] > 0); |
746 | ++joystick_index; |
747 | } |
748 | } |
749 | SDL_assert(joystick_index == total_joysticks); |
750 | joysticks[joystick_index] = 0; |
751 | } else { |
752 | if (count) { |
753 | *count = 0; |
754 | } |
755 | } |
756 | } |
757 | SDL_UnlockJoysticks(); |
758 | |
759 | return joysticks; |
760 | } |
761 | |
762 | const SDL_SteamVirtualGamepadInfo *SDL_GetJoystickVirtualGamepadInfoForID(SDL_JoystickID instance_id) |
763 | { |
764 | SDL_JoystickDriver *driver; |
765 | int device_index; |
766 | const SDL_SteamVirtualGamepadInfo *info = NULL; |
767 | |
768 | if (SDL_SteamVirtualGamepadEnabled() && |
769 | SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) { |
770 | info = SDL_GetSteamVirtualGamepadInfo(driver->GetDeviceSteamVirtualGamepadSlot(device_index)); |
771 | } |
772 | return info; |
773 | } |
774 | |
775 | /* |
776 | * Get the implementation dependent name of a joystick |
777 | */ |
778 | const char *SDL_GetJoystickNameForID(SDL_JoystickID instance_id) |
779 | { |
780 | SDL_JoystickDriver *driver; |
781 | int device_index; |
782 | const char *name = NULL; |
783 | const SDL_SteamVirtualGamepadInfo *info; |
784 | |
785 | SDL_LockJoysticks(); |
786 | info = SDL_GetJoystickVirtualGamepadInfoForID(instance_id); |
787 | if (info) { |
788 | name = SDL_GetPersistentString(info->name); |
789 | } else if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) { |
790 | name = SDL_GetPersistentString(driver->GetDeviceName(device_index)); |
791 | } |
792 | SDL_UnlockJoysticks(); |
793 | |
794 | return name; |
795 | } |
796 | |
797 | /* |
798 | * Get the implementation dependent path of a joystick |
799 | */ |
800 | const char *SDL_GetJoystickPathForID(SDL_JoystickID instance_id) |
801 | { |
802 | SDL_JoystickDriver *driver; |
803 | int device_index; |
804 | const char *path = NULL; |
805 | |
806 | SDL_LockJoysticks(); |
807 | if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) { |
808 | path = SDL_GetPersistentString(driver->GetDevicePath(device_index)); |
809 | } |
810 | SDL_UnlockJoysticks(); |
811 | |
812 | if (!path) { |
813 | SDL_Unsupported(); |
814 | } |
815 | return path; |
816 | } |
817 | |
818 | /* |
819 | * Get the player index of a joystick, or -1 if it's not available |
820 | */ |
821 | int SDL_GetJoystickPlayerIndexForID(SDL_JoystickID instance_id) |
822 | { |
823 | int player_index; |
824 | |
825 | SDL_LockJoysticks(); |
826 | player_index = SDL_GetPlayerIndexForJoystickID(instance_id); |
827 | SDL_UnlockJoysticks(); |
828 | |
829 | return player_index; |
830 | } |
831 | |
832 | /* |
833 | * Return true if this joystick is known to have all axes centered at zero |
834 | * This isn't generally needed unless the joystick never generates an initial axis value near zero, |
835 | * e.g. it's emulating axes with digital buttons |
836 | */ |
837 | static bool SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick) |
838 | { |
839 | // printf("JOYSTICK '%s' VID/PID 0x%.4x/0x%.4x AXES: %d\n", joystick->name, vendor, product, joystick->naxes); |
840 | |
841 | if (joystick->naxes == 2) { |
842 | // Assume D-pad or thumbstick style axes are centered at 0 |
843 | return true; |
844 | } |
845 | |
846 | return SDL_VIDPIDInList(SDL_GetJoystickVendor(joystick), SDL_GetJoystickProduct(joystick), &zero_centered_devices); |
847 | } |
848 | |
849 | static bool IsROGAlly(SDL_Joystick *joystick) |
850 | { |
851 | Uint16 vendor, product; |
852 | SDL_GUID guid = SDL_GetJoystickGUID(joystick); |
853 | |
854 | // The ROG Ally controller spoofs an Xbox 360 controller |
855 | SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, NULL); |
856 | if (vendor == USB_VENDOR_MICROSOFT && product == USB_PRODUCT_XBOX360_WIRED_CONTROLLER) { |
857 | // Check to see if this system has the expected sensors |
858 | bool has_ally_accel = false; |
859 | bool has_ally_gyro = false; |
860 | |
861 | if (SDL_InitSubSystem(SDL_INIT_SENSOR)) { |
862 | SDL_SensorID *sensors = SDL_GetSensors(NULL); |
863 | if (sensors) { |
864 | int i; |
865 | for (i = 0; sensors[i]; ++i) { |
866 | SDL_SensorID sensor = sensors[i]; |
867 | |
868 | if (!has_ally_accel && SDL_GetSensorTypeForID(sensor) == SDL_SENSOR_ACCEL) { |
869 | const char *sensor_name = SDL_GetSensorNameForID(sensor); |
870 | if (sensor_name && SDL_strcmp(sensor_name, "Sensor BMI320 Acc" ) == 0) { |
871 | has_ally_accel = true; |
872 | } |
873 | } |
874 | if (!has_ally_gyro && SDL_GetSensorTypeForID(sensor) == SDL_SENSOR_GYRO) { |
875 | const char *sensor_name = SDL_GetSensorNameForID(sensor); |
876 | if (sensor_name && SDL_strcmp(sensor_name, "Sensor BMI320 Gyr" ) == 0) { |
877 | has_ally_gyro = true; |
878 | } |
879 | } |
880 | } |
881 | SDL_free(sensors); |
882 | } |
883 | SDL_QuitSubSystem(SDL_INIT_SENSOR); |
884 | } |
885 | if (has_ally_accel && has_ally_gyro) { |
886 | return true; |
887 | } |
888 | } |
889 | return false; |
890 | } |
891 | |
892 | static bool ShouldAttemptSensorFusion(SDL_Joystick *joystick, bool *invert_sensors) |
893 | { |
894 | SDL_AssertJoysticksLocked(); |
895 | |
896 | *invert_sensors = false; |
897 | |
898 | // The SDL controller sensor API is only available for gamepads (at the moment) |
899 | if (!SDL_IsGamepad(joystick->instance_id)) { |
900 | return false; |
901 | } |
902 | |
903 | // If the controller already has sensors, use those |
904 | if (joystick->nsensors > 0) { |
905 | return false; |
906 | } |
907 | |
908 | const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLER_SENSOR_FUSION); |
909 | if (hint && *hint) { |
910 | if (*hint == '@' || SDL_strncmp(hint, "0x" , 2) == 0) { |
911 | SDL_vidpid_list gamepads; |
912 | SDL_GUID guid; |
913 | Uint16 vendor, product; |
914 | bool enabled; |
915 | SDL_zero(gamepads); |
916 | |
917 | // See if the gamepad is in our list of devices to enable |
918 | guid = SDL_GetJoystickGUID(joystick); |
919 | SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, NULL); |
920 | SDL_LoadVIDPIDListFromHints(&gamepads, hint, NULL); |
921 | enabled = SDL_VIDPIDInList(vendor, product, &gamepads); |
922 | SDL_FreeVIDPIDList(&gamepads); |
923 | if (enabled) { |
924 | return true; |
925 | } |
926 | } else { |
927 | return SDL_GetStringBoolean(hint, false); |
928 | } |
929 | } |
930 | |
931 | // See if this is another known wraparound gamepad |
932 | if (joystick->name && |
933 | (SDL_strstr(joystick->name, "Backbone One" ) || |
934 | SDL_strstr(joystick->name, "Kishi" ))) { |
935 | return true; |
936 | } |
937 | if (IsROGAlly(joystick)) { |
938 | /* I'm not sure if this is a Windows thing, or a quirk for ROG Ally, |
939 | * but we need to invert the sensor data on all axes. |
940 | */ |
941 | *invert_sensors = true; |
942 | return true; |
943 | } |
944 | return false; |
945 | } |
946 | |
947 | static void AttemptSensorFusion(SDL_Joystick *joystick, bool invert_sensors) |
948 | { |
949 | SDL_SensorID *sensors; |
950 | unsigned int i, j; |
951 | |
952 | SDL_AssertJoysticksLocked(); |
953 | |
954 | if (!SDL_InitSubSystem(SDL_INIT_SENSOR)) { |
955 | return; |
956 | } |
957 | |
958 | sensors = SDL_GetSensors(NULL); |
959 | if (sensors) { |
960 | for (i = 0; sensors[i]; ++i) { |
961 | SDL_SensorID sensor = sensors[i]; |
962 | |
963 | if (!joystick->accel_sensor && SDL_GetSensorTypeForID(sensor) == SDL_SENSOR_ACCEL) { |
964 | // Increment the sensor subsystem reference count |
965 | SDL_InitSubSystem(SDL_INIT_SENSOR); |
966 | |
967 | joystick->accel_sensor = sensor; |
968 | SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 0.0f); |
969 | } |
970 | if (!joystick->gyro_sensor && SDL_GetSensorTypeForID(sensor) == SDL_SENSOR_GYRO) { |
971 | // Increment the sensor subsystem reference count |
972 | SDL_InitSubSystem(SDL_INIT_SENSOR); |
973 | |
974 | joystick->gyro_sensor = sensor; |
975 | SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 0.0f); |
976 | } |
977 | } |
978 | SDL_free(sensors); |
979 | } |
980 | SDL_QuitSubSystem(SDL_INIT_SENSOR); |
981 | |
982 | /* SDL defines sensor orientation for phones relative to the natural |
983 | orientation, and for gamepads relative to being held in front of you. |
984 | When a phone is being used as a gamepad, its orientation changes, |
985 | so adjust sensor axes to match. |
986 | */ |
987 | if (SDL_GetNaturalDisplayOrientation(SDL_GetPrimaryDisplay()) == SDL_ORIENTATION_LANDSCAPE) { |
988 | /* When a device in landscape orientation is laid flat, the axes change |
989 | orientation as follows: |
990 | -X to +X becomes -X to +X |
991 | -Y to +Y becomes +Z to -Z |
992 | -Z to +Z becomes -Y to +Y |
993 | */ |
994 | joystick->sensor_transform[0][0] = 1.0f; |
995 | joystick->sensor_transform[1][2] = 1.0f; |
996 | joystick->sensor_transform[2][1] = -1.0f; |
997 | } else { |
998 | /* When a device in portrait orientation is rotated left and laid flat, |
999 | the axes change orientation as follows: |
1000 | -X to +X becomes +Z to -Z |
1001 | -Y to +Y becomes +X to -X |
1002 | -Z to +Z becomes -Y to +Y |
1003 | */ |
1004 | joystick->sensor_transform[0][1] = -1.0f; |
1005 | joystick->sensor_transform[1][2] = 1.0f; |
1006 | joystick->sensor_transform[2][0] = -1.0f; |
1007 | } |
1008 | |
1009 | if (invert_sensors) { |
1010 | for (i = 0; i < SDL_arraysize(joystick->sensor_transform); ++i) { |
1011 | for (j = 0; j < SDL_arraysize(joystick->sensor_transform[i]); ++j) { |
1012 | joystick->sensor_transform[i][j] *= -1.0f; |
1013 | } |
1014 | } |
1015 | } |
1016 | } |
1017 | |
1018 | static void CleanupSensorFusion(SDL_Joystick *joystick) |
1019 | { |
1020 | SDL_AssertJoysticksLocked(); |
1021 | |
1022 | if (joystick->accel_sensor || joystick->gyro_sensor) { |
1023 | if (joystick->accel_sensor) { |
1024 | if (joystick->accel) { |
1025 | SDL_CloseSensor(joystick->accel); |
1026 | joystick->accel = NULL; |
1027 | } |
1028 | joystick->accel_sensor = 0; |
1029 | |
1030 | // Decrement the sensor subsystem reference count |
1031 | SDL_QuitSubSystem(SDL_INIT_SENSOR); |
1032 | } |
1033 | if (joystick->gyro_sensor) { |
1034 | if (joystick->gyro) { |
1035 | SDL_CloseSensor(joystick->gyro); |
1036 | joystick->gyro = NULL; |
1037 | } |
1038 | joystick->gyro_sensor = 0; |
1039 | |
1040 | // Decrement the sensor subsystem reference count |
1041 | SDL_QuitSubSystem(SDL_INIT_SENSOR); |
1042 | } |
1043 | } |
1044 | } |
1045 | |
1046 | static bool ShouldSwapFaceButtons(const SDL_SteamVirtualGamepadInfo *info) |
1047 | { |
1048 | // When "Use Nintendo Button Layout" is enabled under Steam (the default) |
1049 | // it will send button 0 for the A (east) button and button 1 for the |
1050 | // B (south) button. This is done so that games that interpret the |
1051 | // buttons as Xbox input will get button 0 for "A" as they expect. |
1052 | // |
1053 | // However, SDL reports positional buttons, so we need to swap |
1054 | // the buttons so they show up in the correct position. This provides |
1055 | // consistent behavior regardless of whether we're running under Steam, |
1056 | // under the default settings. |
1057 | if (info && |
1058 | (info->type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO || |
1059 | info->type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT || |
1060 | info->type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT || |
1061 | info->type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR)) { |
1062 | return true; |
1063 | } |
1064 | return false; |
1065 | } |
1066 | |
1067 | /* |
1068 | * Open a joystick for use - the index passed as an argument refers to |
1069 | * the N'th joystick on the system. This index is the value which will |
1070 | * identify this joystick in future joystick events. |
1071 | * |
1072 | * This function returns a joystick identifier, or NULL if an error occurred. |
1073 | */ |
1074 | SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id) |
1075 | { |
1076 | SDL_JoystickDriver *driver; |
1077 | int device_index; |
1078 | SDL_Joystick *joystick; |
1079 | SDL_Joystick *joysticklist; |
1080 | const char *joystickname = NULL; |
1081 | const char *joystickpath = NULL; |
1082 | bool invert_sensors = false; |
1083 | const SDL_SteamVirtualGamepadInfo *info; |
1084 | |
1085 | SDL_LockJoysticks(); |
1086 | |
1087 | if (!SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) { |
1088 | SDL_UnlockJoysticks(); |
1089 | return NULL; |
1090 | } |
1091 | |
1092 | joysticklist = SDL_joysticks; |
1093 | /* If the joystick is already open, return it |
1094 | * it is important that we have a single joystick for each instance id |
1095 | */ |
1096 | while (joysticklist) { |
1097 | if (instance_id == joysticklist->instance_id) { |
1098 | joystick = joysticklist; |
1099 | ++joystick->ref_count; |
1100 | SDL_UnlockJoysticks(); |
1101 | return joystick; |
1102 | } |
1103 | joysticklist = joysticklist->next; |
1104 | } |
1105 | |
1106 | // Create and initialize the joystick |
1107 | joystick = (SDL_Joystick *)SDL_calloc(1, sizeof(*joystick)); |
1108 | if (!joystick) { |
1109 | SDL_UnlockJoysticks(); |
1110 | return NULL; |
1111 | } |
1112 | SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, true); |
1113 | joystick->driver = driver; |
1114 | joystick->instance_id = instance_id; |
1115 | joystick->attached = true; |
1116 | joystick->led_expiration = SDL_GetTicks(); |
1117 | joystick->battery_percent = -1; |
1118 | |
1119 | if (!driver->Open(joystick, device_index)) { |
1120 | SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, false); |
1121 | SDL_free(joystick); |
1122 | SDL_UnlockJoysticks(); |
1123 | return NULL; |
1124 | } |
1125 | |
1126 | joystickname = driver->GetDeviceName(device_index); |
1127 | if (joystickname) { |
1128 | joystick->name = SDL_strdup(joystickname); |
1129 | } |
1130 | |
1131 | joystickpath = driver->GetDevicePath(device_index); |
1132 | if (joystickpath) { |
1133 | joystick->path = SDL_strdup(joystickpath); |
1134 | } |
1135 | |
1136 | joystick->guid = driver->GetDeviceGUID(device_index); |
1137 | |
1138 | if (joystick->naxes > 0) { |
1139 | joystick->axes = (SDL_JoystickAxisInfo *)SDL_calloc(joystick->naxes, sizeof(*joystick->axes)); |
1140 | } |
1141 | if (joystick->nballs > 0) { |
1142 | joystick->balls = (SDL_JoystickBallData *)SDL_calloc(joystick->nballs, sizeof(*joystick->balls)); |
1143 | } |
1144 | if (joystick->nhats > 0) { |
1145 | joystick->hats = (Uint8 *)SDL_calloc(joystick->nhats, sizeof(*joystick->hats)); |
1146 | } |
1147 | if (joystick->nbuttons > 0) { |
1148 | joystick->buttons = (bool *)SDL_calloc(joystick->nbuttons, sizeof(*joystick->buttons)); |
1149 | } |
1150 | if (((joystick->naxes > 0) && !joystick->axes) || |
1151 | ((joystick->nballs > 0) && !joystick->balls) || |
1152 | ((joystick->nhats > 0) && !joystick->hats) || |
1153 | ((joystick->nbuttons > 0) && !joystick->buttons)) { |
1154 | SDL_CloseJoystick(joystick); |
1155 | SDL_UnlockJoysticks(); |
1156 | return NULL; |
1157 | } |
1158 | |
1159 | // If this joystick is known to have all zero centered axes, skip the auto-centering code |
1160 | if (SDL_JoystickAxesCenteredAtZero(joystick)) { |
1161 | int i; |
1162 | |
1163 | for (i = 0; i < joystick->naxes; ++i) { |
1164 | joystick->axes[i].has_initial_value = true; |
1165 | } |
1166 | } |
1167 | |
1168 | // Get the Steam Input API handle |
1169 | info = SDL_GetJoystickVirtualGamepadInfoForID(instance_id); |
1170 | if (info) { |
1171 | joystick->steam_handle = info->handle; |
1172 | joystick->swap_face_buttons = ShouldSwapFaceButtons(info); |
1173 | } |
1174 | |
1175 | // Use system gyro and accelerometer if the gamepad doesn't have built-in sensors |
1176 | if (ShouldAttemptSensorFusion(joystick, &invert_sensors)) { |
1177 | AttemptSensorFusion(joystick, invert_sensors); |
1178 | } |
1179 | |
1180 | // Add joystick to list |
1181 | ++joystick->ref_count; |
1182 | // Link the joystick in the list |
1183 | joystick->next = SDL_joysticks; |
1184 | SDL_joysticks = joystick; |
1185 | |
1186 | driver->Update(joystick); |
1187 | |
1188 | SDL_UnlockJoysticks(); |
1189 | |
1190 | return joystick; |
1191 | } |
1192 | |
1193 | SDL_JoystickID SDL_AttachVirtualJoystick(const SDL_VirtualJoystickDesc *desc) |
1194 | { |
1195 | #ifdef SDL_JOYSTICK_VIRTUAL |
1196 | SDL_JoystickID result; |
1197 | |
1198 | SDL_LockJoysticks(); |
1199 | result = SDL_JoystickAttachVirtualInner(desc); |
1200 | SDL_UnlockJoysticks(); |
1201 | return result; |
1202 | #else |
1203 | SDL_SetError("SDL not built with virtual-joystick support" ); |
1204 | return 0; |
1205 | #endif |
1206 | } |
1207 | |
1208 | bool SDL_DetachVirtualJoystick(SDL_JoystickID instance_id) |
1209 | { |
1210 | #ifdef SDL_JOYSTICK_VIRTUAL |
1211 | bool result; |
1212 | |
1213 | SDL_LockJoysticks(); |
1214 | result = SDL_JoystickDetachVirtualInner(instance_id); |
1215 | SDL_UnlockJoysticks(); |
1216 | return result; |
1217 | #else |
1218 | return SDL_SetError("SDL not built with virtual-joystick support" ); |
1219 | #endif |
1220 | } |
1221 | |
1222 | bool SDL_IsJoystickVirtual(SDL_JoystickID instance_id) |
1223 | { |
1224 | #ifdef SDL_JOYSTICK_VIRTUAL |
1225 | SDL_JoystickDriver *driver; |
1226 | int device_index; |
1227 | bool is_virtual = false; |
1228 | |
1229 | SDL_LockJoysticks(); |
1230 | if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) { |
1231 | if (driver == &SDL_VIRTUAL_JoystickDriver) { |
1232 | is_virtual = true; |
1233 | } |
1234 | } |
1235 | SDL_UnlockJoysticks(); |
1236 | |
1237 | return is_virtual; |
1238 | #else |
1239 | return false; |
1240 | #endif |
1241 | } |
1242 | |
1243 | bool SDL_SetJoystickVirtualAxis(SDL_Joystick *joystick, int axis, Sint16 value) |
1244 | { |
1245 | bool result; |
1246 | |
1247 | SDL_LockJoysticks(); |
1248 | { |
1249 | CHECK_JOYSTICK_MAGIC(joystick, false); |
1250 | |
1251 | #ifdef SDL_JOYSTICK_VIRTUAL |
1252 | result = SDL_SetJoystickVirtualAxisInner(joystick, axis, value); |
1253 | #else |
1254 | result = SDL_SetError("SDL not built with virtual-joystick support" ); |
1255 | #endif |
1256 | } |
1257 | SDL_UnlockJoysticks(); |
1258 | |
1259 | return result; |
1260 | } |
1261 | |
1262 | bool SDL_SetJoystickVirtualBall(SDL_Joystick *joystick, int ball, Sint16 xrel, Sint16 yrel) |
1263 | { |
1264 | bool result; |
1265 | |
1266 | SDL_LockJoysticks(); |
1267 | { |
1268 | CHECK_JOYSTICK_MAGIC(joystick, false); |
1269 | |
1270 | #ifdef SDL_JOYSTICK_VIRTUAL |
1271 | result = SDL_SetJoystickVirtualBallInner(joystick, ball, xrel, yrel); |
1272 | #else |
1273 | result = SDL_SetError("SDL not built with virtual-joystick support" ); |
1274 | #endif |
1275 | } |
1276 | SDL_UnlockJoysticks(); |
1277 | |
1278 | return result; |
1279 | } |
1280 | |
1281 | bool SDL_SetJoystickVirtualButton(SDL_Joystick *joystick, int button, bool down) |
1282 | { |
1283 | bool result; |
1284 | |
1285 | SDL_LockJoysticks(); |
1286 | { |
1287 | CHECK_JOYSTICK_MAGIC(joystick, false); |
1288 | |
1289 | #ifdef SDL_JOYSTICK_VIRTUAL |
1290 | result = SDL_SetJoystickVirtualButtonInner(joystick, button, down); |
1291 | #else |
1292 | result = SDL_SetError("SDL not built with virtual-joystick support" ); |
1293 | #endif |
1294 | } |
1295 | SDL_UnlockJoysticks(); |
1296 | |
1297 | return result; |
1298 | } |
1299 | |
1300 | bool SDL_SetJoystickVirtualHat(SDL_Joystick *joystick, int hat, Uint8 value) |
1301 | { |
1302 | bool result; |
1303 | |
1304 | SDL_LockJoysticks(); |
1305 | { |
1306 | CHECK_JOYSTICK_MAGIC(joystick, false); |
1307 | |
1308 | #ifdef SDL_JOYSTICK_VIRTUAL |
1309 | result = SDL_SetJoystickVirtualHatInner(joystick, hat, value); |
1310 | #else |
1311 | result = SDL_SetError("SDL not built with virtual-joystick support" ); |
1312 | #endif |
1313 | } |
1314 | SDL_UnlockJoysticks(); |
1315 | |
1316 | return result; |
1317 | } |
1318 | |
1319 | bool SDL_SetJoystickVirtualTouchpad(SDL_Joystick *joystick, int touchpad, int finger, bool down, float x, float y, float pressure) |
1320 | { |
1321 | bool result; |
1322 | |
1323 | SDL_LockJoysticks(); |
1324 | { |
1325 | CHECK_JOYSTICK_MAGIC(joystick, false); |
1326 | |
1327 | #ifdef SDL_JOYSTICK_VIRTUAL |
1328 | result = SDL_SetJoystickVirtualTouchpadInner(joystick, touchpad, finger, down, x, y, pressure); |
1329 | #else |
1330 | result = SDL_SetError("SDL not built with virtual-joystick support" ); |
1331 | #endif |
1332 | } |
1333 | SDL_UnlockJoysticks(); |
1334 | |
1335 | return result; |
1336 | } |
1337 | |
1338 | bool SDL_SendJoystickVirtualSensorData(SDL_Joystick *joystick, SDL_SensorType type, Uint64 sensor_timestamp, const float *data, int num_values) |
1339 | { |
1340 | bool result; |
1341 | |
1342 | SDL_LockJoysticks(); |
1343 | { |
1344 | CHECK_JOYSTICK_MAGIC(joystick, false); |
1345 | |
1346 | #ifdef SDL_JOYSTICK_VIRTUAL |
1347 | result = SDL_SendJoystickVirtualSensorDataInner(joystick, type, sensor_timestamp, data, num_values); |
1348 | #else |
1349 | result = SDL_SetError("SDL not built with virtual-joystick support" ); |
1350 | #endif |
1351 | } |
1352 | SDL_UnlockJoysticks(); |
1353 | |
1354 | return result; |
1355 | } |
1356 | |
1357 | /* |
1358 | * Checks to make sure the joystick is valid. |
1359 | */ |
1360 | bool SDL_IsJoystickValid(SDL_Joystick *joystick) |
1361 | { |
1362 | SDL_AssertJoysticksLocked(); |
1363 | return SDL_ObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK); |
1364 | } |
1365 | |
1366 | bool SDL_PrivateJoystickGetAutoGamepadMapping(SDL_JoystickID instance_id, SDL_GamepadMapping *out) |
1367 | { |
1368 | SDL_JoystickDriver *driver; |
1369 | int device_index; |
1370 | bool is_ok = false; |
1371 | |
1372 | SDL_LockJoysticks(); |
1373 | if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) { |
1374 | is_ok = driver->GetGamepadMapping(device_index, out); |
1375 | } |
1376 | SDL_UnlockJoysticks(); |
1377 | |
1378 | return is_ok; |
1379 | } |
1380 | |
1381 | /* |
1382 | * Get the number of multi-dimensional axis controls on a joystick |
1383 | */ |
1384 | int SDL_GetNumJoystickAxes(SDL_Joystick *joystick) |
1385 | { |
1386 | int result; |
1387 | |
1388 | SDL_LockJoysticks(); |
1389 | { |
1390 | CHECK_JOYSTICK_MAGIC(joystick, -1); |
1391 | |
1392 | result = joystick->naxes; |
1393 | } |
1394 | SDL_UnlockJoysticks(); |
1395 | |
1396 | return result; |
1397 | } |
1398 | |
1399 | /* |
1400 | * Get the number of hats on a joystick |
1401 | */ |
1402 | int SDL_GetNumJoystickHats(SDL_Joystick *joystick) |
1403 | { |
1404 | int result; |
1405 | |
1406 | SDL_LockJoysticks(); |
1407 | { |
1408 | CHECK_JOYSTICK_MAGIC(joystick, -1); |
1409 | |
1410 | result = joystick->nhats; |
1411 | } |
1412 | SDL_UnlockJoysticks(); |
1413 | |
1414 | return result; |
1415 | } |
1416 | |
1417 | /* |
1418 | * Get the number of trackballs on a joystick |
1419 | */ |
1420 | int SDL_GetNumJoystickBalls(SDL_Joystick *joystick) |
1421 | { |
1422 | CHECK_JOYSTICK_MAGIC(joystick, -1); |
1423 | |
1424 | return joystick->nballs; |
1425 | } |
1426 | |
1427 | /* |
1428 | * Get the number of buttons on a joystick |
1429 | */ |
1430 | int SDL_GetNumJoystickButtons(SDL_Joystick *joystick) |
1431 | { |
1432 | int result; |
1433 | |
1434 | SDL_LockJoysticks(); |
1435 | { |
1436 | CHECK_JOYSTICK_MAGIC(joystick, -1); |
1437 | |
1438 | result = joystick->nbuttons; |
1439 | } |
1440 | SDL_UnlockJoysticks(); |
1441 | |
1442 | return result; |
1443 | } |
1444 | |
1445 | /* |
1446 | * Get the current state of an axis control on a joystick |
1447 | */ |
1448 | Sint16 SDL_GetJoystickAxis(SDL_Joystick *joystick, int axis) |
1449 | { |
1450 | Sint16 state; |
1451 | |
1452 | SDL_LockJoysticks(); |
1453 | { |
1454 | CHECK_JOYSTICK_MAGIC(joystick, 0); |
1455 | |
1456 | if (axis < joystick->naxes) { |
1457 | state = joystick->axes[axis].value; |
1458 | } else { |
1459 | SDL_SetError("Joystick only has %d axes" , joystick->naxes); |
1460 | state = 0; |
1461 | } |
1462 | } |
1463 | SDL_UnlockJoysticks(); |
1464 | |
1465 | return state; |
1466 | } |
1467 | |
1468 | /* |
1469 | * Get the initial state of an axis control on a joystick |
1470 | */ |
1471 | bool SDL_GetJoystickAxisInitialState(SDL_Joystick *joystick, int axis, Sint16 *state) |
1472 | { |
1473 | bool result; |
1474 | |
1475 | SDL_LockJoysticks(); |
1476 | { |
1477 | CHECK_JOYSTICK_MAGIC(joystick, false); |
1478 | |
1479 | if (axis >= joystick->naxes) { |
1480 | SDL_SetError("Joystick only has %d axes" , joystick->naxes); |
1481 | result = false; |
1482 | } else { |
1483 | if (state) { |
1484 | *state = joystick->axes[axis].initial_value; |
1485 | } |
1486 | result = joystick->axes[axis].has_initial_value; |
1487 | } |
1488 | } |
1489 | SDL_UnlockJoysticks(); |
1490 | |
1491 | return result; |
1492 | } |
1493 | |
1494 | /* |
1495 | * Get the current state of a hat on a joystick |
1496 | */ |
1497 | Uint8 SDL_GetJoystickHat(SDL_Joystick *joystick, int hat) |
1498 | { |
1499 | Uint8 state; |
1500 | |
1501 | SDL_LockJoysticks(); |
1502 | { |
1503 | CHECK_JOYSTICK_MAGIC(joystick, 0); |
1504 | |
1505 | if (hat < joystick->nhats) { |
1506 | state = joystick->hats[hat]; |
1507 | } else { |
1508 | SDL_SetError("Joystick only has %d hats" , joystick->nhats); |
1509 | state = 0; |
1510 | } |
1511 | } |
1512 | SDL_UnlockJoysticks(); |
1513 | |
1514 | return state; |
1515 | } |
1516 | |
1517 | /* |
1518 | * Get the ball axis change since the last poll |
1519 | */ |
1520 | bool SDL_GetJoystickBall(SDL_Joystick *joystick, int ball, int *dx, int *dy) |
1521 | { |
1522 | bool result; |
1523 | |
1524 | SDL_LockJoysticks(); |
1525 | { |
1526 | CHECK_JOYSTICK_MAGIC(joystick, false); |
1527 | |
1528 | if (ball < joystick->nballs) { |
1529 | if (dx) { |
1530 | *dx = joystick->balls[ball].dx; |
1531 | } |
1532 | if (dy) { |
1533 | *dy = joystick->balls[ball].dy; |
1534 | } |
1535 | joystick->balls[ball].dx = 0; |
1536 | joystick->balls[ball].dy = 0; |
1537 | result = true; |
1538 | } else { |
1539 | result = SDL_SetError("Joystick only has %d balls" , joystick->nballs); |
1540 | } |
1541 | } |
1542 | SDL_UnlockJoysticks(); |
1543 | |
1544 | return result; |
1545 | } |
1546 | |
1547 | /* |
1548 | * Get the current state of a button on a joystick |
1549 | */ |
1550 | bool SDL_GetJoystickButton(SDL_Joystick *joystick, int button) |
1551 | { |
1552 | bool down = false; |
1553 | |
1554 | SDL_LockJoysticks(); |
1555 | { |
1556 | CHECK_JOYSTICK_MAGIC(joystick, false); |
1557 | |
1558 | if (button < joystick->nbuttons) { |
1559 | down = joystick->buttons[button]; |
1560 | } else { |
1561 | SDL_SetError("Joystick only has %d buttons" , joystick->nbuttons); |
1562 | } |
1563 | } |
1564 | SDL_UnlockJoysticks(); |
1565 | |
1566 | return down; |
1567 | } |
1568 | |
1569 | /* |
1570 | * Return if the joystick in question is currently attached to the system, |
1571 | * \return false if not plugged in, true if still present. |
1572 | */ |
1573 | bool SDL_JoystickConnected(SDL_Joystick *joystick) |
1574 | { |
1575 | bool result; |
1576 | |
1577 | SDL_LockJoysticks(); |
1578 | { |
1579 | CHECK_JOYSTICK_MAGIC(joystick, false); |
1580 | |
1581 | result = joystick->attached; |
1582 | } |
1583 | SDL_UnlockJoysticks(); |
1584 | |
1585 | return result; |
1586 | } |
1587 | |
1588 | /* |
1589 | * Get the instance id for this opened joystick |
1590 | */ |
1591 | SDL_JoystickID SDL_GetJoystickID(SDL_Joystick *joystick) |
1592 | { |
1593 | SDL_JoystickID result; |
1594 | |
1595 | SDL_LockJoysticks(); |
1596 | { |
1597 | CHECK_JOYSTICK_MAGIC(joystick, 0); |
1598 | |
1599 | result = joystick->instance_id; |
1600 | } |
1601 | SDL_UnlockJoysticks(); |
1602 | |
1603 | return result; |
1604 | } |
1605 | |
1606 | /* |
1607 | * Return the SDL_Joystick associated with an instance id. |
1608 | */ |
1609 | SDL_Joystick *SDL_GetJoystickFromID(SDL_JoystickID instance_id) |
1610 | { |
1611 | SDL_Joystick *joystick; |
1612 | |
1613 | SDL_LockJoysticks(); |
1614 | for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { |
1615 | if (joystick->instance_id == instance_id) { |
1616 | break; |
1617 | } |
1618 | } |
1619 | SDL_UnlockJoysticks(); |
1620 | return joystick; |
1621 | } |
1622 | |
1623 | /** |
1624 | * Return the SDL_Joystick associated with a player index. |
1625 | */ |
1626 | SDL_Joystick *SDL_GetJoystickFromPlayerIndex(int player_index) |
1627 | { |
1628 | SDL_JoystickID instance_id; |
1629 | SDL_Joystick *joystick; |
1630 | |
1631 | SDL_LockJoysticks(); |
1632 | instance_id = SDL_GetJoystickIDForPlayerIndex(player_index); |
1633 | for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { |
1634 | if (joystick->instance_id == instance_id) { |
1635 | break; |
1636 | } |
1637 | } |
1638 | SDL_UnlockJoysticks(); |
1639 | return joystick; |
1640 | } |
1641 | |
1642 | /* |
1643 | * Get the properties associated with a joystick |
1644 | */ |
1645 | SDL_PropertiesID SDL_GetJoystickProperties(SDL_Joystick *joystick) |
1646 | { |
1647 | SDL_PropertiesID result; |
1648 | |
1649 | SDL_LockJoysticks(); |
1650 | { |
1651 | CHECK_JOYSTICK_MAGIC(joystick, 0); |
1652 | |
1653 | if (joystick->props == 0) { |
1654 | joystick->props = SDL_CreateProperties(); |
1655 | } |
1656 | result = joystick->props; |
1657 | } |
1658 | SDL_UnlockJoysticks(); |
1659 | |
1660 | return result; |
1661 | } |
1662 | |
1663 | /* |
1664 | * Get the friendly name of this joystick |
1665 | */ |
1666 | const char *SDL_GetJoystickName(SDL_Joystick *joystick) |
1667 | { |
1668 | const char *result; |
1669 | const SDL_SteamVirtualGamepadInfo *info; |
1670 | |
1671 | SDL_LockJoysticks(); |
1672 | { |
1673 | CHECK_JOYSTICK_MAGIC(joystick, NULL); |
1674 | |
1675 | info = SDL_GetJoystickVirtualGamepadInfoForID(joystick->instance_id); |
1676 | if (info) { |
1677 | result = SDL_GetPersistentString(info->name); |
1678 | } else { |
1679 | result = SDL_GetPersistentString(joystick->name); |
1680 | } |
1681 | } |
1682 | SDL_UnlockJoysticks(); |
1683 | |
1684 | return result; |
1685 | } |
1686 | |
1687 | /* |
1688 | * Get the implementation dependent path of this joystick |
1689 | */ |
1690 | const char *SDL_GetJoystickPath(SDL_Joystick *joystick) |
1691 | { |
1692 | const char *result; |
1693 | |
1694 | SDL_LockJoysticks(); |
1695 | { |
1696 | CHECK_JOYSTICK_MAGIC(joystick, NULL); |
1697 | |
1698 | if (joystick->path) { |
1699 | result = SDL_GetPersistentString(joystick->path); |
1700 | } else { |
1701 | SDL_Unsupported(); |
1702 | result = NULL; |
1703 | } |
1704 | } |
1705 | SDL_UnlockJoysticks(); |
1706 | |
1707 | return result; |
1708 | } |
1709 | |
1710 | /** |
1711 | * Get the player index of an opened joystick, or -1 if it's not available |
1712 | */ |
1713 | int SDL_GetJoystickPlayerIndex(SDL_Joystick *joystick) |
1714 | { |
1715 | int result; |
1716 | |
1717 | SDL_LockJoysticks(); |
1718 | { |
1719 | CHECK_JOYSTICK_MAGIC(joystick, -1); |
1720 | |
1721 | result = SDL_GetPlayerIndexForJoystickID(joystick->instance_id); |
1722 | } |
1723 | SDL_UnlockJoysticks(); |
1724 | |
1725 | return result; |
1726 | } |
1727 | |
1728 | /** |
1729 | * Set the player index of an opened joystick |
1730 | */ |
1731 | bool SDL_SetJoystickPlayerIndex(SDL_Joystick *joystick, int player_index) |
1732 | { |
1733 | bool result; |
1734 | |
1735 | SDL_LockJoysticks(); |
1736 | { |
1737 | CHECK_JOYSTICK_MAGIC(joystick, false); |
1738 | |
1739 | result = SDL_SetJoystickIDForPlayerIndex(player_index, joystick->instance_id); |
1740 | } |
1741 | SDL_UnlockJoysticks(); |
1742 | |
1743 | return result; |
1744 | } |
1745 | |
1746 | bool SDL_RumbleJoystick(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms) |
1747 | { |
1748 | bool result; |
1749 | |
1750 | SDL_LockJoysticks(); |
1751 | { |
1752 | CHECK_JOYSTICK_MAGIC(joystick, false); |
1753 | |
1754 | if (low_frequency_rumble == joystick->low_frequency_rumble && |
1755 | high_frequency_rumble == joystick->high_frequency_rumble) { |
1756 | // Just update the expiration |
1757 | result = true; |
1758 | } else { |
1759 | result = joystick->driver->Rumble(joystick, low_frequency_rumble, high_frequency_rumble); |
1760 | if (result) { |
1761 | joystick->rumble_resend = SDL_GetTicks() + SDL_RUMBLE_RESEND_MS; |
1762 | if (joystick->rumble_resend == 0) { |
1763 | joystick->rumble_resend = 1; |
1764 | } |
1765 | } else { |
1766 | joystick->rumble_resend = 0; |
1767 | } |
1768 | } |
1769 | |
1770 | if (result) { |
1771 | joystick->low_frequency_rumble = low_frequency_rumble; |
1772 | joystick->high_frequency_rumble = high_frequency_rumble; |
1773 | |
1774 | if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) { |
1775 | joystick->rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS); |
1776 | if (!joystick->rumble_expiration) { |
1777 | joystick->rumble_expiration = 1; |
1778 | } |
1779 | } else { |
1780 | joystick->rumble_expiration = 0; |
1781 | joystick->rumble_resend = 0; |
1782 | } |
1783 | } |
1784 | } |
1785 | SDL_UnlockJoysticks(); |
1786 | |
1787 | return result; |
1788 | } |
1789 | |
1790 | bool SDL_RumbleJoystickTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble, Uint32 duration_ms) |
1791 | { |
1792 | bool result; |
1793 | |
1794 | SDL_LockJoysticks(); |
1795 | { |
1796 | CHECK_JOYSTICK_MAGIC(joystick, false); |
1797 | |
1798 | if (left_rumble == joystick->left_trigger_rumble && right_rumble == joystick->right_trigger_rumble) { |
1799 | // Just update the expiration |
1800 | result = true; |
1801 | } else { |
1802 | result = joystick->driver->RumbleTriggers(joystick, left_rumble, right_rumble); |
1803 | } |
1804 | |
1805 | if (result) { |
1806 | joystick->left_trigger_rumble = left_rumble; |
1807 | joystick->right_trigger_rumble = right_rumble; |
1808 | |
1809 | if ((left_rumble || right_rumble) && duration_ms) { |
1810 | joystick->trigger_rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS); |
1811 | } else { |
1812 | joystick->trigger_rumble_expiration = 0; |
1813 | } |
1814 | } |
1815 | } |
1816 | SDL_UnlockJoysticks(); |
1817 | |
1818 | return result; |
1819 | } |
1820 | |
1821 | bool SDL_SetJoystickLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) |
1822 | { |
1823 | bool result; |
1824 | bool isfreshvalue; |
1825 | |
1826 | SDL_LockJoysticks(); |
1827 | { |
1828 | CHECK_JOYSTICK_MAGIC(joystick, false); |
1829 | |
1830 | isfreshvalue = red != joystick->led_red || |
1831 | green != joystick->led_green || |
1832 | blue != joystick->led_blue; |
1833 | |
1834 | if (isfreshvalue || SDL_GetTicks() >= joystick->led_expiration) { |
1835 | result = joystick->driver->SetLED(joystick, red, green, blue); |
1836 | joystick->led_expiration = SDL_GetTicks() + SDL_LED_MIN_REPEAT_MS; |
1837 | } else { |
1838 | // Avoid spamming the driver |
1839 | result = true; |
1840 | } |
1841 | |
1842 | // Save the LED value regardless of success, so we don't spam the driver |
1843 | joystick->led_red = red; |
1844 | joystick->led_green = green; |
1845 | joystick->led_blue = blue; |
1846 | } |
1847 | SDL_UnlockJoysticks(); |
1848 | |
1849 | return result; |
1850 | } |
1851 | |
1852 | bool SDL_SendJoystickEffect(SDL_Joystick *joystick, const void *data, int size) |
1853 | { |
1854 | bool result; |
1855 | |
1856 | SDL_LockJoysticks(); |
1857 | { |
1858 | CHECK_JOYSTICK_MAGIC(joystick, false); |
1859 | |
1860 | result = joystick->driver->SendEffect(joystick, data, size); |
1861 | } |
1862 | SDL_UnlockJoysticks(); |
1863 | |
1864 | return result; |
1865 | } |
1866 | |
1867 | /* |
1868 | * Close a joystick previously opened with SDL_OpenJoystick() |
1869 | */ |
1870 | void SDL_CloseJoystick(SDL_Joystick *joystick) |
1871 | { |
1872 | SDL_Joystick *joysticklist; |
1873 | SDL_Joystick *joysticklistprev; |
1874 | int i; |
1875 | |
1876 | SDL_LockJoysticks(); |
1877 | { |
1878 | CHECK_JOYSTICK_MAGIC(joystick,); |
1879 | |
1880 | // First decrement ref count |
1881 | if (--joystick->ref_count > 0) { |
1882 | SDL_UnlockJoysticks(); |
1883 | return; |
1884 | } |
1885 | |
1886 | SDL_DestroyProperties(joystick->props); |
1887 | |
1888 | if (joystick->rumble_expiration) { |
1889 | SDL_RumbleJoystick(joystick, 0, 0, 0); |
1890 | } |
1891 | if (joystick->trigger_rumble_expiration) { |
1892 | SDL_RumbleJoystickTriggers(joystick, 0, 0, 0); |
1893 | } |
1894 | |
1895 | CleanupSensorFusion(joystick); |
1896 | |
1897 | joystick->driver->Close(joystick); |
1898 | joystick->hwdata = NULL; |
1899 | SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, false); |
1900 | |
1901 | joysticklist = SDL_joysticks; |
1902 | joysticklistprev = NULL; |
1903 | while (joysticklist) { |
1904 | if (joystick == joysticklist) { |
1905 | if (joysticklistprev) { |
1906 | // unlink this entry |
1907 | joysticklistprev->next = joysticklist->next; |
1908 | } else { |
1909 | SDL_joysticks = joystick->next; |
1910 | } |
1911 | break; |
1912 | } |
1913 | joysticklistprev = joysticklist; |
1914 | joysticklist = joysticklist->next; |
1915 | } |
1916 | |
1917 | // Free the data associated with this joystick |
1918 | SDL_free(joystick->name); |
1919 | SDL_free(joystick->path); |
1920 | SDL_free(joystick->serial); |
1921 | SDL_free(joystick->axes); |
1922 | SDL_free(joystick->balls); |
1923 | SDL_free(joystick->hats); |
1924 | SDL_free(joystick->buttons); |
1925 | for (i = 0; i < joystick->ntouchpads; i++) { |
1926 | SDL_JoystickTouchpadInfo *touchpad = &joystick->touchpads[i]; |
1927 | SDL_free(touchpad->fingers); |
1928 | } |
1929 | SDL_free(joystick->touchpads); |
1930 | SDL_free(joystick->sensors); |
1931 | SDL_free(joystick); |
1932 | } |
1933 | SDL_UnlockJoysticks(); |
1934 | } |
1935 | |
1936 | void SDL_QuitJoysticks(void) |
1937 | { |
1938 | int i; |
1939 | SDL_JoystickID *joysticks; |
1940 | |
1941 | SDL_LockJoysticks(); |
1942 | |
1943 | SDL_joysticks_quitting = true; |
1944 | |
1945 | joysticks = SDL_GetJoysticks(NULL); |
1946 | if (joysticks) { |
1947 | for (i = 0; joysticks[i]; ++i) { |
1948 | SDL_PrivateJoystickRemoved(joysticks[i]); |
1949 | } |
1950 | SDL_free(joysticks); |
1951 | } |
1952 | |
1953 | while (SDL_joysticks) { |
1954 | SDL_joysticks->ref_count = 1; |
1955 | SDL_CloseJoystick(SDL_joysticks); |
1956 | } |
1957 | |
1958 | // Quit drivers in reverse order to avoid breaking dependencies between drivers |
1959 | for (i = SDL_arraysize(SDL_joystick_drivers) - 1; i >= 0; --i) { |
1960 | SDL_joystick_drivers[i]->Quit(); |
1961 | } |
1962 | |
1963 | if (SDL_joystick_players) { |
1964 | SDL_free(SDL_joystick_players); |
1965 | SDL_joystick_players = NULL; |
1966 | SDL_joystick_player_count = 0; |
1967 | } |
1968 | |
1969 | SDL_QuitSubSystem(SDL_INIT_EVENTS); |
1970 | |
1971 | SDL_QuitSteamVirtualGamepadInfo(); |
1972 | |
1973 | SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, |
1974 | SDL_JoystickAllowBackgroundEventsChanged, NULL); |
1975 | |
1976 | SDL_FreeVIDPIDList(&arcadestick_devices); |
1977 | SDL_FreeVIDPIDList(&blacklist_devices); |
1978 | SDL_FreeVIDPIDList(&flightstick_devices); |
1979 | SDL_FreeVIDPIDList(&gamecube_devices); |
1980 | SDL_FreeVIDPIDList(&rog_gamepad_mice); |
1981 | SDL_FreeVIDPIDList(&throttle_devices); |
1982 | SDL_FreeVIDPIDList(&wheel_devices); |
1983 | SDL_FreeVIDPIDList(&zero_centered_devices); |
1984 | |
1985 | SDL_QuitGamepadMappings(); |
1986 | |
1987 | SDL_joysticks_quitting = false; |
1988 | SDL_joysticks_initialized = false; |
1989 | |
1990 | SDL_UnlockJoysticks(); |
1991 | } |
1992 | |
1993 | static bool SDL_PrivateJoystickShouldIgnoreEvent(void) |
1994 | { |
1995 | if (SDL_joystick_allows_background_events) { |
1996 | return false; |
1997 | } |
1998 | |
1999 | if (SDL_HasWindows() && SDL_GetKeyboardFocus() == NULL) { |
2000 | // We have windows but we don't have focus, ignore the event. |
2001 | return true; |
2002 | } |
2003 | return false; |
2004 | } |
2005 | |
2006 | // These are global for SDL_sysjoystick.c and SDL_events.c |
2007 | |
2008 | void SDL_PrivateJoystickAddTouchpad(SDL_Joystick *joystick, int nfingers) |
2009 | { |
2010 | int ntouchpads; |
2011 | SDL_JoystickTouchpadInfo *touchpads; |
2012 | |
2013 | SDL_AssertJoysticksLocked(); |
2014 | |
2015 | ntouchpads = joystick->ntouchpads + 1; |
2016 | touchpads = (SDL_JoystickTouchpadInfo *)SDL_realloc(joystick->touchpads, (ntouchpads * sizeof(SDL_JoystickTouchpadInfo))); |
2017 | if (touchpads) { |
2018 | SDL_JoystickTouchpadInfo *touchpad = &touchpads[ntouchpads - 1]; |
2019 | SDL_JoystickTouchpadFingerInfo *fingers = (SDL_JoystickTouchpadFingerInfo *)SDL_calloc(nfingers, sizeof(SDL_JoystickTouchpadFingerInfo)); |
2020 | |
2021 | if (fingers) { |
2022 | touchpad->nfingers = nfingers; |
2023 | touchpad->fingers = fingers; |
2024 | } else { |
2025 | // Out of memory, this touchpad won't be active |
2026 | touchpad->nfingers = 0; |
2027 | touchpad->fingers = NULL; |
2028 | } |
2029 | |
2030 | joystick->ntouchpads = ntouchpads; |
2031 | joystick->touchpads = touchpads; |
2032 | } |
2033 | } |
2034 | |
2035 | void SDL_PrivateJoystickAddSensor(SDL_Joystick *joystick, SDL_SensorType type, float rate) |
2036 | { |
2037 | int nsensors; |
2038 | SDL_JoystickSensorInfo *sensors; |
2039 | |
2040 | SDL_AssertJoysticksLocked(); |
2041 | |
2042 | nsensors = joystick->nsensors + 1; |
2043 | sensors = (SDL_JoystickSensorInfo *)SDL_realloc(joystick->sensors, (nsensors * sizeof(SDL_JoystickSensorInfo))); |
2044 | if (sensors) { |
2045 | SDL_JoystickSensorInfo *sensor = &sensors[nsensors - 1]; |
2046 | |
2047 | SDL_zerop(sensor); |
2048 | sensor->type = type; |
2049 | sensor->rate = rate; |
2050 | |
2051 | joystick->nsensors = nsensors; |
2052 | joystick->sensors = sensors; |
2053 | } |
2054 | } |
2055 | |
2056 | void SDL_PrivateJoystickSensorRate(SDL_Joystick *joystick, SDL_SensorType type, float rate) |
2057 | { |
2058 | int i; |
2059 | SDL_AssertJoysticksLocked(); |
2060 | |
2061 | for (i = 0; i < joystick->nsensors; ++i) { |
2062 | if (joystick->sensors[i].type == type) { |
2063 | joystick->sensors[i].rate = rate; |
2064 | } |
2065 | } |
2066 | } |
2067 | |
2068 | void SDL_PrivateJoystickAdded(SDL_JoystickID instance_id) |
2069 | { |
2070 | SDL_JoystickDriver *driver; |
2071 | int device_index; |
2072 | int player_index = -1; |
2073 | |
2074 | SDL_AssertJoysticksLocked(); |
2075 | |
2076 | if (SDL_JoysticksQuitting()) { |
2077 | return; |
2078 | } |
2079 | |
2080 | SDL_joystick_being_added = true; |
2081 | |
2082 | if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) { |
2083 | player_index = driver->GetDeviceSteamVirtualGamepadSlot(device_index); |
2084 | if (player_index < 0) { |
2085 | player_index = driver->GetDevicePlayerIndex(device_index); |
2086 | } |
2087 | } |
2088 | if (player_index < 0 && SDL_IsGamepad(instance_id)) { |
2089 | player_index = SDL_FindFreePlayerIndex(); |
2090 | } |
2091 | if (player_index >= 0) { |
2092 | SDL_SetJoystickIDForPlayerIndex(player_index, instance_id); |
2093 | } |
2094 | |
2095 | { |
2096 | SDL_Event event; |
2097 | |
2098 | event.type = SDL_EVENT_JOYSTICK_ADDED; |
2099 | event.common.timestamp = 0; |
2100 | |
2101 | if (SDL_EventEnabled(event.type)) { |
2102 | event.jdevice.which = instance_id; |
2103 | SDL_PushEvent(&event); |
2104 | } |
2105 | } |
2106 | |
2107 | SDL_joystick_being_added = false; |
2108 | |
2109 | if (SDL_IsGamepad(instance_id)) { |
2110 | SDL_PrivateGamepadAdded(instance_id); |
2111 | } |
2112 | } |
2113 | |
2114 | bool SDL_IsJoystickBeingAdded(void) |
2115 | { |
2116 | return SDL_joystick_being_added; |
2117 | } |
2118 | |
2119 | void SDL_PrivateJoystickForceRecentering(SDL_Joystick *joystick) |
2120 | { |
2121 | Uint8 i, j; |
2122 | Uint64 timestamp = SDL_GetTicksNS(); |
2123 | |
2124 | SDL_AssertJoysticksLocked(); |
2125 | |
2126 | // Tell the app that everything is centered/unpressed... |
2127 | for (i = 0; i < joystick->naxes; i++) { |
2128 | if (joystick->axes[i].has_initial_value) { |
2129 | SDL_SendJoystickAxis(timestamp, joystick, i, joystick->axes[i].zero); |
2130 | } |
2131 | } |
2132 | |
2133 | for (i = 0; i < joystick->nbuttons; i++) { |
2134 | SDL_SendJoystickButton(timestamp, joystick, i, false); |
2135 | } |
2136 | |
2137 | for (i = 0; i < joystick->nhats; i++) { |
2138 | SDL_SendJoystickHat(timestamp, joystick, i, SDL_HAT_CENTERED); |
2139 | } |
2140 | |
2141 | for (i = 0; i < joystick->ntouchpads; i++) { |
2142 | SDL_JoystickTouchpadInfo *touchpad = &joystick->touchpads[i]; |
2143 | |
2144 | for (j = 0; j < touchpad->nfingers; ++j) { |
2145 | SDL_SendJoystickTouchpad(timestamp, joystick, i, j, false, 0.0f, 0.0f, 0.0f); |
2146 | } |
2147 | } |
2148 | } |
2149 | |
2150 | void SDL_PrivateJoystickRemoved(SDL_JoystickID instance_id) |
2151 | { |
2152 | SDL_Joystick *joystick = NULL; |
2153 | int player_index; |
2154 | SDL_Event event; |
2155 | |
2156 | SDL_AssertJoysticksLocked(); |
2157 | |
2158 | // Find this joystick... |
2159 | for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { |
2160 | if (joystick->instance_id == instance_id) { |
2161 | SDL_PrivateJoystickForceRecentering(joystick); |
2162 | joystick->attached = false; |
2163 | break; |
2164 | } |
2165 | } |
2166 | |
2167 | if (SDL_IsGamepad(instance_id)) { |
2168 | SDL_PrivateGamepadRemoved(instance_id); |
2169 | } |
2170 | |
2171 | event.type = SDL_EVENT_JOYSTICK_REMOVED; |
2172 | event.common.timestamp = 0; |
2173 | |
2174 | if (SDL_EventEnabled(event.type)) { |
2175 | event.jdevice.which = instance_id; |
2176 | SDL_PushEvent(&event); |
2177 | } |
2178 | |
2179 | player_index = SDL_GetPlayerIndexForJoystickID(instance_id); |
2180 | if (player_index >= 0) { |
2181 | SDL_joystick_players[player_index] = 0; |
2182 | } |
2183 | } |
2184 | |
2185 | void SDL_SendJoystickAxis(Uint64 timestamp, SDL_Joystick *joystick, Uint8 axis, Sint16 value) |
2186 | { |
2187 | SDL_JoystickAxisInfo *info; |
2188 | |
2189 | SDL_AssertJoysticksLocked(); |
2190 | |
2191 | // Make sure we're not getting garbage or duplicate events |
2192 | if (axis >= joystick->naxes) { |
2193 | return; |
2194 | } |
2195 | |
2196 | info = &joystick->axes[axis]; |
2197 | if (!info->has_initial_value || |
2198 | (!info->has_second_value && (info->initial_value <= -32767 || info->initial_value == 32767) && SDL_abs(value) < (SDL_JOYSTICK_AXIS_MAX / 4))) { |
2199 | info->initial_value = value; |
2200 | info->value = value; |
2201 | info->zero = value; |
2202 | info->has_initial_value = true; |
2203 | } else if (value == info->value && !info->sending_initial_value) { |
2204 | return; |
2205 | } else { |
2206 | info->has_second_value = true; |
2207 | } |
2208 | if (!info->sent_initial_value) { |
2209 | // Make sure we don't send motion until there's real activity on this axis |
2210 | const int MAX_ALLOWED_JITTER = SDL_JOYSTICK_AXIS_MAX / 80; // ShanWan PS3 controller needed 96 |
2211 | if (SDL_abs(value - info->value) <= MAX_ALLOWED_JITTER && |
2212 | !SDL_IsJoystickVIRTUAL(joystick->guid)) { |
2213 | return; |
2214 | } |
2215 | info->sent_initial_value = true; |
2216 | info->sending_initial_value = true; |
2217 | SDL_SendJoystickAxis(timestamp, joystick, axis, info->initial_value); |
2218 | info->sending_initial_value = false; |
2219 | } |
2220 | |
2221 | /* We ignore events if we don't have keyboard focus, except for centering |
2222 | * events. |
2223 | */ |
2224 | if (SDL_PrivateJoystickShouldIgnoreEvent()) { |
2225 | if (info->sending_initial_value || |
2226 | (value > info->zero && value >= info->value) || |
2227 | (value < info->zero && value <= info->value)) { |
2228 | return; |
2229 | } |
2230 | } |
2231 | |
2232 | // Update internal joystick state |
2233 | SDL_assert(timestamp != 0); |
2234 | info->value = value; |
2235 | joystick->update_complete = timestamp; |
2236 | |
2237 | // Post the event, if desired |
2238 | if (SDL_EventEnabled(SDL_EVENT_JOYSTICK_AXIS_MOTION)) { |
2239 | SDL_Event event; |
2240 | event.type = SDL_EVENT_JOYSTICK_AXIS_MOTION; |
2241 | event.common.timestamp = timestamp; |
2242 | event.jaxis.which = joystick->instance_id; |
2243 | event.jaxis.axis = axis; |
2244 | event.jaxis.value = value; |
2245 | SDL_PushEvent(&event); |
2246 | } |
2247 | } |
2248 | |
2249 | void SDL_SendJoystickBall(Uint64 timestamp, SDL_Joystick *joystick, Uint8 ball, Sint16 xrel, Sint16 yrel) |
2250 | { |
2251 | SDL_AssertJoysticksLocked(); |
2252 | |
2253 | // Make sure we're not getting garbage events |
2254 | if (ball >= joystick->nballs) { |
2255 | return; |
2256 | } |
2257 | |
2258 | // We ignore events if we don't have keyboard focus. |
2259 | if (SDL_PrivateJoystickShouldIgnoreEvent()) { |
2260 | return; |
2261 | } |
2262 | |
2263 | // Update internal mouse state |
2264 | joystick->balls[ball].dx += xrel; |
2265 | joystick->balls[ball].dy += yrel; |
2266 | |
2267 | // Post the event, if desired |
2268 | if (SDL_EventEnabled(SDL_EVENT_JOYSTICK_BALL_MOTION)) { |
2269 | SDL_Event event; |
2270 | event.type = SDL_EVENT_JOYSTICK_BALL_MOTION; |
2271 | event.common.timestamp = timestamp; |
2272 | event.jball.which = joystick->instance_id; |
2273 | event.jball.ball = ball; |
2274 | event.jball.xrel = xrel; |
2275 | event.jball.yrel = yrel; |
2276 | SDL_PushEvent(&event); |
2277 | } |
2278 | } |
2279 | |
2280 | void SDL_SendJoystickHat(Uint64 timestamp, SDL_Joystick *joystick, Uint8 hat, Uint8 value) |
2281 | { |
2282 | SDL_AssertJoysticksLocked(); |
2283 | |
2284 | // Make sure we're not getting garbage or duplicate events |
2285 | if (hat >= joystick->nhats) { |
2286 | return; |
2287 | } |
2288 | if (value == joystick->hats[hat]) { |
2289 | return; |
2290 | } |
2291 | |
2292 | /* We ignore events if we don't have keyboard focus, except for centering |
2293 | * events. |
2294 | */ |
2295 | if (SDL_PrivateJoystickShouldIgnoreEvent()) { |
2296 | if (value != SDL_HAT_CENTERED) { |
2297 | return; |
2298 | } |
2299 | } |
2300 | |
2301 | // Update internal joystick state |
2302 | SDL_assert(timestamp != 0); |
2303 | joystick->hats[hat] = value; |
2304 | joystick->update_complete = timestamp; |
2305 | |
2306 | // Post the event, if desired |
2307 | if (SDL_EventEnabled(SDL_EVENT_JOYSTICK_HAT_MOTION)) { |
2308 | SDL_Event event; |
2309 | event.type = SDL_EVENT_JOYSTICK_HAT_MOTION; |
2310 | event.common.timestamp = timestamp; |
2311 | event.jhat.which = joystick->instance_id; |
2312 | event.jhat.hat = hat; |
2313 | event.jhat.value = value; |
2314 | SDL_PushEvent(&event); |
2315 | } |
2316 | } |
2317 | |
2318 | void SDL_SendJoystickButton(Uint64 timestamp, SDL_Joystick *joystick, Uint8 button, bool down) |
2319 | { |
2320 | SDL_Event event; |
2321 | |
2322 | SDL_AssertJoysticksLocked(); |
2323 | |
2324 | if (down) { |
2325 | event.type = SDL_EVENT_JOYSTICK_BUTTON_DOWN; |
2326 | } else { |
2327 | event.type = SDL_EVENT_JOYSTICK_BUTTON_UP; |
2328 | } |
2329 | |
2330 | if (joystick->swap_face_buttons) { |
2331 | switch (button) { |
2332 | case 0: |
2333 | button = 1; |
2334 | break; |
2335 | case 1: |
2336 | button = 0; |
2337 | break; |
2338 | case 2: |
2339 | button = 3; |
2340 | break; |
2341 | case 3: |
2342 | button = 2; |
2343 | break; |
2344 | default: |
2345 | break; |
2346 | } |
2347 | } |
2348 | |
2349 | // Make sure we're not getting garbage or duplicate events |
2350 | if (button >= joystick->nbuttons) { |
2351 | return; |
2352 | } |
2353 | if (down == joystick->buttons[button]) { |
2354 | return; |
2355 | } |
2356 | |
2357 | /* We ignore events if we don't have keyboard focus, except for button |
2358 | * release. */ |
2359 | if (SDL_PrivateJoystickShouldIgnoreEvent()) { |
2360 | if (down) { |
2361 | return; |
2362 | } |
2363 | } |
2364 | |
2365 | // Update internal joystick state |
2366 | SDL_assert(timestamp != 0); |
2367 | joystick->buttons[button] = down; |
2368 | joystick->update_complete = timestamp; |
2369 | |
2370 | // Post the event, if desired |
2371 | if (SDL_EventEnabled(event.type)) { |
2372 | event.common.timestamp = timestamp; |
2373 | event.jbutton.which = joystick->instance_id; |
2374 | event.jbutton.button = button; |
2375 | event.jbutton.down = down; |
2376 | SDL_PushEvent(&event); |
2377 | } |
2378 | } |
2379 | |
2380 | static void SendSteamHandleUpdateEvents(void) |
2381 | { |
2382 | SDL_Joystick *joystick; |
2383 | const SDL_SteamVirtualGamepadInfo *info; |
2384 | |
2385 | // Check to see if any Steam handles changed |
2386 | for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { |
2387 | bool changed = false; |
2388 | |
2389 | if (!SDL_IsGamepad(joystick->instance_id)) { |
2390 | continue; |
2391 | } |
2392 | |
2393 | info = SDL_GetJoystickVirtualGamepadInfoForID(joystick->instance_id); |
2394 | if (info) { |
2395 | if (joystick->steam_handle != info->handle) { |
2396 | joystick->steam_handle = info->handle; |
2397 | joystick->swap_face_buttons = ShouldSwapFaceButtons(info); |
2398 | changed = true; |
2399 | } |
2400 | } else { |
2401 | if (joystick->steam_handle != 0) { |
2402 | joystick->steam_handle = 0; |
2403 | joystick->swap_face_buttons = false; |
2404 | changed = true; |
2405 | } |
2406 | } |
2407 | if (changed) { |
2408 | SDL_Event event; |
2409 | |
2410 | SDL_zero(event); |
2411 | event.type = SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED; |
2412 | event.common.timestamp = 0; |
2413 | event.gdevice.which = joystick->instance_id; |
2414 | SDL_PushEvent(&event); |
2415 | } |
2416 | } |
2417 | } |
2418 | |
2419 | void SDL_UpdateJoysticks(void) |
2420 | { |
2421 | int i; |
2422 | Uint64 now; |
2423 | SDL_Joystick *joystick; |
2424 | |
2425 | if (!SDL_WasInit(SDL_INIT_JOYSTICK)) { |
2426 | return; |
2427 | } |
2428 | |
2429 | SDL_LockJoysticks(); |
2430 | |
2431 | if (SDL_UpdateSteamVirtualGamepadInfo()) { |
2432 | SendSteamHandleUpdateEvents(); |
2433 | } |
2434 | |
2435 | #ifdef SDL_JOYSTICK_HIDAPI |
2436 | // Special function for HIDAPI devices, as a single device can provide multiple SDL_Joysticks |
2437 | HIDAPI_UpdateDevices(); |
2438 | #endif // SDL_JOYSTICK_HIDAPI |
2439 | |
2440 | for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { |
2441 | if (!joystick->attached) { |
2442 | continue; |
2443 | } |
2444 | |
2445 | joystick->driver->Update(joystick); |
2446 | |
2447 | if (joystick->delayed_guide_button) { |
2448 | SDL_GamepadHandleDelayedGuideButton(joystick); |
2449 | } |
2450 | |
2451 | now = SDL_GetTicks(); |
2452 | if (joystick->rumble_expiration && now >= joystick->rumble_expiration) { |
2453 | SDL_RumbleJoystick(joystick, 0, 0, 0); |
2454 | joystick->rumble_resend = 0; |
2455 | } |
2456 | |
2457 | if (joystick->rumble_resend && now >= joystick->rumble_resend) { |
2458 | joystick->driver->Rumble(joystick, joystick->low_frequency_rumble, joystick->high_frequency_rumble); |
2459 | joystick->rumble_resend = now + SDL_RUMBLE_RESEND_MS; |
2460 | if (joystick->rumble_resend == 0) { |
2461 | joystick->rumble_resend = 1; |
2462 | } |
2463 | } |
2464 | |
2465 | if (joystick->trigger_rumble_expiration && now >= joystick->trigger_rumble_expiration) { |
2466 | SDL_RumbleJoystickTriggers(joystick, 0, 0, 0); |
2467 | } |
2468 | } |
2469 | |
2470 | if (SDL_EventEnabled(SDL_EVENT_JOYSTICK_UPDATE_COMPLETE)) { |
2471 | for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { |
2472 | if (joystick->update_complete) { |
2473 | SDL_Event event; |
2474 | |
2475 | event.type = SDL_EVENT_JOYSTICK_UPDATE_COMPLETE; |
2476 | event.common.timestamp = joystick->update_complete; |
2477 | event.jdevice.which = joystick->instance_id; |
2478 | SDL_PushEvent(&event); |
2479 | |
2480 | joystick->update_complete = 0; |
2481 | } |
2482 | } |
2483 | } |
2484 | |
2485 | /* this needs to happen AFTER walking the joystick list above, so that any |
2486 | dangling hardware data from removed devices can be free'd |
2487 | */ |
2488 | for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) { |
2489 | SDL_joystick_drivers[i]->Detect(); |
2490 | } |
2491 | |
2492 | SDL_UnlockJoysticks(); |
2493 | } |
2494 | |
2495 | static const Uint32 SDL_joystick_event_list[] = { |
2496 | SDL_EVENT_JOYSTICK_AXIS_MOTION, |
2497 | SDL_EVENT_JOYSTICK_BALL_MOTION, |
2498 | SDL_EVENT_JOYSTICK_HAT_MOTION, |
2499 | SDL_EVENT_JOYSTICK_BUTTON_DOWN, |
2500 | SDL_EVENT_JOYSTICK_BUTTON_UP, |
2501 | SDL_EVENT_JOYSTICK_ADDED, |
2502 | SDL_EVENT_JOYSTICK_REMOVED, |
2503 | SDL_EVENT_JOYSTICK_BATTERY_UPDATED |
2504 | }; |
2505 | |
2506 | void SDL_SetJoystickEventsEnabled(bool enabled) |
2507 | { |
2508 | unsigned int i; |
2509 | |
2510 | for (i = 0; i < SDL_arraysize(SDL_joystick_event_list); ++i) { |
2511 | SDL_SetEventEnabled(SDL_joystick_event_list[i], enabled); |
2512 | } |
2513 | } |
2514 | |
2515 | bool SDL_JoystickEventsEnabled(void) |
2516 | { |
2517 | bool enabled = false; |
2518 | unsigned int i; |
2519 | |
2520 | for (i = 0; i < SDL_arraysize(SDL_joystick_event_list); ++i) { |
2521 | enabled = SDL_EventEnabled(SDL_joystick_event_list[i]); |
2522 | if (enabled) { |
2523 | break; |
2524 | } |
2525 | } |
2526 | return enabled; |
2527 | } |
2528 | |
2529 | void SDL_GetJoystickGUIDInfo(SDL_GUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version, Uint16 *crc16) |
2530 | { |
2531 | Uint16 *guid16 = (Uint16 *)guid.data; |
2532 | Uint16 bus = SDL_Swap16LE(guid16[0]); |
2533 | |
2534 | if ((bus < ' ' || bus == SDL_HARDWARE_BUS_VIRTUAL) && guid16[3] == 0x0000 && guid16[5] == 0x0000) { |
2535 | /* This GUID fits the standard form: |
2536 | * 16-bit bus |
2537 | * 16-bit CRC16 of the joystick name (can be zero) |
2538 | * 16-bit vendor ID |
2539 | * 16-bit zero |
2540 | * 16-bit product ID |
2541 | * 16-bit zero |
2542 | * 16-bit version |
2543 | * 8-bit driver identifier ('h' for HIDAPI, 'x' for XInput, etc.) |
2544 | * 8-bit driver-dependent type info |
2545 | */ |
2546 | if (vendor) { |
2547 | *vendor = SDL_Swap16LE(guid16[2]); |
2548 | } |
2549 | if (product) { |
2550 | *product = SDL_Swap16LE(guid16[4]); |
2551 | } |
2552 | if (version) { |
2553 | *version = SDL_Swap16LE(guid16[6]); |
2554 | } |
2555 | if (crc16) { |
2556 | *crc16 = SDL_Swap16LE(guid16[1]); |
2557 | } |
2558 | } else if (bus < ' ' || bus == SDL_HARDWARE_BUS_VIRTUAL) { |
2559 | /* This GUID fits the unknown VID/PID form: |
2560 | * 16-bit bus |
2561 | * 16-bit CRC16 of the joystick name (can be zero) |
2562 | * 11 characters of the joystick name, null terminated |
2563 | */ |
2564 | if (vendor) { |
2565 | *vendor = 0; |
2566 | } |
2567 | if (product) { |
2568 | *product = 0; |
2569 | } |
2570 | if (version) { |
2571 | *version = 0; |
2572 | } |
2573 | if (crc16) { |
2574 | *crc16 = SDL_Swap16LE(guid16[1]); |
2575 | } |
2576 | } else { |
2577 | if (vendor) { |
2578 | *vendor = 0; |
2579 | } |
2580 | if (product) { |
2581 | *product = 0; |
2582 | } |
2583 | if (version) { |
2584 | *version = 0; |
2585 | } |
2586 | if (crc16) { |
2587 | *crc16 = 0; |
2588 | } |
2589 | } |
2590 | } |
2591 | |
2592 | char *SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name) |
2593 | { |
2594 | const char *custom_name = GuessControllerName(vendor, product); |
2595 | if (custom_name) { |
2596 | return SDL_strdup(custom_name); |
2597 | } |
2598 | |
2599 | return SDL_CreateDeviceName(vendor, product, vendor_name, product_name, "Controller" ); |
2600 | } |
2601 | |
2602 | SDL_GUID SDL_CreateJoystickGUID(Uint16 bus, Uint16 vendor, Uint16 product, Uint16 version, const char *vendor_name, const char *product_name, Uint8 driver_signature, Uint8 driver_data) |
2603 | { |
2604 | SDL_GUID guid; |
2605 | Uint16 *guid16 = (Uint16 *)guid.data; |
2606 | Uint16 crc = 0; |
2607 | |
2608 | SDL_zero(guid); |
2609 | |
2610 | if (vendor_name && *vendor_name && product_name && *product_name) { |
2611 | crc = SDL_crc16(crc, vendor_name, SDL_strlen(vendor_name)); |
2612 | crc = SDL_crc16(crc, " " , 1); |
2613 | crc = SDL_crc16(crc, product_name, SDL_strlen(product_name)); |
2614 | } else if (product_name) { |
2615 | crc = SDL_crc16(crc, product_name, SDL_strlen(product_name)); |
2616 | } |
2617 | |
2618 | // We only need 16 bits for each of these; space them out to fill 128. |
2619 | // Byteswap so devices get same GUID on little/big endian platforms. |
2620 | *guid16++ = SDL_Swap16LE(bus); |
2621 | *guid16++ = SDL_Swap16LE(crc); |
2622 | |
2623 | if (vendor) { |
2624 | *guid16++ = SDL_Swap16LE(vendor); |
2625 | *guid16++ = 0; |
2626 | *guid16++ = SDL_Swap16LE(product); |
2627 | *guid16++ = 0; |
2628 | *guid16++ = SDL_Swap16LE(version); |
2629 | guid.data[14] = driver_signature; |
2630 | guid.data[15] = driver_data; |
2631 | } else { |
2632 | size_t available_space = sizeof(guid.data) - 4; |
2633 | |
2634 | if (driver_signature) { |
2635 | available_space -= 2; |
2636 | guid.data[14] = driver_signature; |
2637 | guid.data[15] = driver_data; |
2638 | } |
2639 | if (product_name) { |
2640 | SDL_strlcpy((char *)guid16, product_name, available_space); |
2641 | } |
2642 | } |
2643 | return guid; |
2644 | } |
2645 | |
2646 | SDL_GUID SDL_CreateJoystickGUIDForName(const char *name) |
2647 | { |
2648 | return SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_UNKNOWN, 0, 0, 0, NULL, name, 0, 0); |
2649 | } |
2650 | |
2651 | void SDL_SetJoystickGUIDVendor(SDL_GUID *guid, Uint16 vendor) |
2652 | { |
2653 | Uint16 *guid16 = (Uint16 *)guid->data; |
2654 | |
2655 | guid16[2] = SDL_Swap16LE(vendor); |
2656 | } |
2657 | |
2658 | void SDL_SetJoystickGUIDProduct(SDL_GUID *guid, Uint16 product) |
2659 | { |
2660 | Uint16 *guid16 = (Uint16 *)guid->data; |
2661 | |
2662 | guid16[4] = SDL_Swap16LE(product); |
2663 | } |
2664 | |
2665 | void SDL_SetJoystickGUIDVersion(SDL_GUID *guid, Uint16 version) |
2666 | { |
2667 | Uint16 *guid16 = (Uint16 *)guid->data; |
2668 | |
2669 | guid16[6] = SDL_Swap16LE(version); |
2670 | } |
2671 | |
2672 | void SDL_SetJoystickGUIDCRC(SDL_GUID *guid, Uint16 crc) |
2673 | { |
2674 | Uint16 *guid16 = (Uint16 *)guid->data; |
2675 | |
2676 | guid16[1] = SDL_Swap16LE(crc); |
2677 | } |
2678 | |
2679 | SDL_GamepadType SDL_GetGamepadTypeFromVIDPID(Uint16 vendor, Uint16 product, const char *name, bool forUI) |
2680 | { |
2681 | SDL_GamepadType type = SDL_GAMEPAD_TYPE_STANDARD; |
2682 | |
2683 | if (vendor == 0x0000 && product == 0x0000) { |
2684 | // Some devices are only identifiable by their name |
2685 | if (name && |
2686 | (SDL_strcmp(name, "Lic Pro Controller" ) == 0 || |
2687 | SDL_strcmp(name, "Nintendo Wireless Gamepad" ) == 0 || |
2688 | SDL_strcmp(name, "Wireless Gamepad" ) == 0)) { |
2689 | // HORI or PowerA Switch Pro Controller clone |
2690 | type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO; |
2691 | } |
2692 | |
2693 | } else if (vendor == 0x0001 && product == 0x0001) { |
2694 | type = SDL_GAMEPAD_TYPE_STANDARD; |
2695 | |
2696 | } else if (vendor == USB_VENDOR_NINTENDO && product == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT) { |
2697 | type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT; |
2698 | |
2699 | } else if (vendor == USB_VENDOR_NINTENDO && product == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT) { |
2700 | if (name && SDL_strstr(name, "NES Controller" ) != NULL) { |
2701 | // We don't have a type for the Nintendo Online NES Controller |
2702 | type = SDL_GAMEPAD_TYPE_STANDARD; |
2703 | } else { |
2704 | type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT; |
2705 | } |
2706 | |
2707 | } else if (vendor == USB_VENDOR_NINTENDO && product == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_GRIP) { |
2708 | if (name && SDL_strstr(name, "(L)" ) != NULL) { |
2709 | type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT; |
2710 | } else { |
2711 | type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT; |
2712 | } |
2713 | |
2714 | } else if (vendor == USB_VENDOR_NINTENDO && product == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR) { |
2715 | type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR; |
2716 | |
2717 | } else if (forUI && SDL_IsJoystickGameCube(vendor, product)) { |
2718 | // We don't have a type for the Nintendo GameCube controller |
2719 | type = SDL_GAMEPAD_TYPE_STANDARD; |
2720 | |
2721 | } else { |
2722 | switch (GuessControllerType(vendor, product)) { |
2723 | case k_eControllerType_XBox360Controller: |
2724 | type = SDL_GAMEPAD_TYPE_XBOX360; |
2725 | break; |
2726 | case k_eControllerType_XBoxOneController: |
2727 | type = SDL_GAMEPAD_TYPE_XBOXONE; |
2728 | break; |
2729 | case k_eControllerType_PS3Controller: |
2730 | type = SDL_GAMEPAD_TYPE_PS3; |
2731 | break; |
2732 | case k_eControllerType_PS4Controller: |
2733 | type = SDL_GAMEPAD_TYPE_PS4; |
2734 | break; |
2735 | case k_eControllerType_PS5Controller: |
2736 | type = SDL_GAMEPAD_TYPE_PS5; |
2737 | break; |
2738 | case k_eControllerType_XInputPS4Controller: |
2739 | if (forUI) { |
2740 | type = SDL_GAMEPAD_TYPE_PS4; |
2741 | } else { |
2742 | type = SDL_GAMEPAD_TYPE_STANDARD; |
2743 | } |
2744 | break; |
2745 | case k_eControllerType_SwitchProController: |
2746 | case k_eControllerType_SwitchInputOnlyController: |
2747 | type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO; |
2748 | break; |
2749 | case k_eControllerType_XInputSwitchController: |
2750 | if (forUI) { |
2751 | type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO; |
2752 | } else { |
2753 | type = SDL_GAMEPAD_TYPE_STANDARD; |
2754 | } |
2755 | break; |
2756 | default: |
2757 | break; |
2758 | } |
2759 | } |
2760 | return type; |
2761 | } |
2762 | |
2763 | SDL_GamepadType SDL_GetGamepadTypeFromGUID(SDL_GUID guid, const char *name) |
2764 | { |
2765 | SDL_GamepadType type; |
2766 | Uint16 vendor, product; |
2767 | |
2768 | SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, NULL); |
2769 | type = SDL_GetGamepadTypeFromVIDPID(vendor, product, name, true); |
2770 | if (type == SDL_GAMEPAD_TYPE_STANDARD) { |
2771 | if (SDL_IsJoystickXInput(guid)) { |
2772 | // This is probably an Xbox One controller |
2773 | return SDL_GAMEPAD_TYPE_XBOXONE; |
2774 | } |
2775 | #ifdef SDL_JOYSTICK_HIDAPI |
2776 | if (SDL_IsJoystickHIDAPI(guid)) { |
2777 | return HIDAPI_GetGamepadTypeFromGUID(guid); |
2778 | } |
2779 | #endif // SDL_JOYSTICK_HIDAPI |
2780 | } |
2781 | return type; |
2782 | } |
2783 | |
2784 | bool SDL_JoystickGUIDUsesVersion(SDL_GUID guid) |
2785 | { |
2786 | Uint16 vendor, product; |
2787 | |
2788 | if (SDL_IsJoystickMFI(guid)) { |
2789 | // The version bits are used as button capability mask |
2790 | return false; |
2791 | } |
2792 | |
2793 | SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, NULL); |
2794 | if (vendor && product) { |
2795 | return true; |
2796 | } |
2797 | return false; |
2798 | } |
2799 | |
2800 | bool SDL_IsJoystickXboxOne(Uint16 vendor_id, Uint16 product_id) |
2801 | { |
2802 | EControllerType eType = GuessControllerType(vendor_id, product_id); |
2803 | return eType == k_eControllerType_XBoxOneController; |
2804 | } |
2805 | |
2806 | bool SDL_IsJoystickXboxOneElite(Uint16 vendor_id, Uint16 product_id) |
2807 | { |
2808 | if (vendor_id == USB_VENDOR_MICROSOFT) { |
2809 | if (product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_1 || |
2810 | product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2 || |
2811 | product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH || |
2812 | product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLE) { |
2813 | return true; |
2814 | } |
2815 | } |
2816 | return false; |
2817 | } |
2818 | |
2819 | bool SDL_IsJoystickXboxSeriesX(Uint16 vendor_id, Uint16 product_id) |
2820 | { |
2821 | if (vendor_id == USB_VENDOR_MICROSOFT) { |
2822 | if (product_id == USB_PRODUCT_XBOX_SERIES_X || |
2823 | product_id == USB_PRODUCT_XBOX_SERIES_X_BLE) { |
2824 | return true; |
2825 | } |
2826 | } |
2827 | if (vendor_id == USB_VENDOR_PDP) { |
2828 | if (product_id == USB_PRODUCT_XBOX_SERIES_X_VICTRIX_GAMBIT || |
2829 | product_id == USB_PRODUCT_XBOX_SERIES_X_PDP_BLUE || |
2830 | product_id == USB_PRODUCT_XBOX_SERIES_X_PDP_AFTERGLOW) { |
2831 | return true; |
2832 | } |
2833 | } |
2834 | if (vendor_id == USB_VENDOR_POWERA_ALT) { |
2835 | if ((product_id >= 0x2001 && product_id <= 0x201a) || |
2836 | product_id == USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO2 || |
2837 | product_id == USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO4 || |
2838 | product_id == USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO_WIRELESS_USB || |
2839 | product_id == USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO_WIRELESS_DONGLE || |
2840 | product_id == USB_PRODUCT_XBOX_SERIES_X_POWERA_MOGA_XP_ULTRA || |
2841 | product_id == USB_PRODUCT_XBOX_SERIES_X_POWERA_SPECTRA) { |
2842 | return true; |
2843 | } |
2844 | } |
2845 | if (vendor_id == USB_VENDOR_HORI) { |
2846 | if (product_id == USB_PRODUCT_HORI_FIGHTING_COMMANDER_OCTA_SERIES_X || |
2847 | product_id == USB_PRODUCT_HORI_HORIPAD_PRO_SERIES_X) { |
2848 | return true; |
2849 | } |
2850 | } |
2851 | if (vendor_id == USB_VENDOR_HP) { |
2852 | if (product_id == USB_PRODUCT_XBOX_SERIES_X_HP_HYPERX || |
2853 | product_id == USB_PRODUCT_XBOX_SERIES_X_HP_HYPERX_RGB) { |
2854 | return true; |
2855 | } |
2856 | } |
2857 | if (vendor_id == USB_VENDOR_RAZER) { |
2858 | if (product_id == USB_PRODUCT_RAZER_WOLVERINE_V2 || |
2859 | product_id == USB_PRODUCT_RAZER_WOLVERINE_V2_CHROMA || |
2860 | product_id == USB_PRODUCT_RAZER_WOLVERINE_V3_PRO) { |
2861 | return true; |
2862 | } |
2863 | } |
2864 | if (vendor_id == USB_VENDOR_THRUSTMASTER) { |
2865 | if (product_id == USB_PRODUCT_THRUSTMASTER_ESWAPX_PRO_SERIES_X) { |
2866 | return true; |
2867 | } |
2868 | } |
2869 | if (vendor_id == USB_VENDOR_TURTLE_BEACH) { |
2870 | if (product_id == USB_PRODUCT_TURTLE_BEACH_SERIES_X_REACT_R || |
2871 | product_id == USB_PRODUCT_TURTLE_BEACH_SERIES_X_RECON) { |
2872 | return true; |
2873 | } |
2874 | } |
2875 | if (vendor_id == USB_VENDOR_8BITDO) { |
2876 | if (product_id == USB_PRODUCT_8BITDO_XBOX_CONTROLLER1 || |
2877 | product_id == USB_PRODUCT_8BITDO_XBOX_CONTROLLER2) { |
2878 | return true; |
2879 | } |
2880 | } |
2881 | if (vendor_id == USB_VENDOR_GAMESIR) { |
2882 | if (product_id == USB_PRODUCT_GAMESIR_G7) { |
2883 | return true; |
2884 | } |
2885 | } |
2886 | if (vendor_id == USB_VENDOR_ASUS) { |
2887 | if (product_id == USB_PRODUCT_ROG_RAIKIRI) { |
2888 | return true; |
2889 | } |
2890 | } |
2891 | return false; |
2892 | } |
2893 | |
2894 | bool SDL_IsJoystickBluetoothXboxOne(Uint16 vendor_id, Uint16 product_id) |
2895 | { |
2896 | if (vendor_id == USB_VENDOR_MICROSOFT) { |
2897 | if (product_id == USB_PRODUCT_XBOX_ONE_ADAPTIVE_BLUETOOTH || |
2898 | product_id == USB_PRODUCT_XBOX_ONE_ADAPTIVE_BLE || |
2899 | product_id == USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH || |
2900 | product_id == USB_PRODUCT_XBOX_ONE_S_REV2_BLUETOOTH || |
2901 | product_id == USB_PRODUCT_XBOX_ONE_S_REV2_BLE || |
2902 | product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH || |
2903 | product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLE || |
2904 | product_id == USB_PRODUCT_XBOX_SERIES_X_BLE) { |
2905 | return true; |
2906 | } |
2907 | } |
2908 | return false; |
2909 | } |
2910 | |
2911 | bool SDL_IsJoystickPS4(Uint16 vendor_id, Uint16 product_id) |
2912 | { |
2913 | EControllerType eType = GuessControllerType(vendor_id, product_id); |
2914 | return eType == k_eControllerType_PS4Controller; |
2915 | } |
2916 | |
2917 | bool SDL_IsJoystickPS5(Uint16 vendor_id, Uint16 product_id) |
2918 | { |
2919 | EControllerType eType = GuessControllerType(vendor_id, product_id); |
2920 | return eType == k_eControllerType_PS5Controller; |
2921 | } |
2922 | |
2923 | bool SDL_IsJoystickDualSenseEdge(Uint16 vendor_id, Uint16 product_id) |
2924 | { |
2925 | if (vendor_id == USB_VENDOR_SONY) { |
2926 | if (product_id == USB_PRODUCT_SONY_DS5_EDGE) { |
2927 | return true; |
2928 | } |
2929 | } |
2930 | return false; |
2931 | } |
2932 | |
2933 | bool SDL_IsJoystickNintendoSwitchPro(Uint16 vendor_id, Uint16 product_id) |
2934 | { |
2935 | EControllerType eType = GuessControllerType(vendor_id, product_id); |
2936 | return eType == k_eControllerType_SwitchProController || eType == k_eControllerType_SwitchInputOnlyController; |
2937 | } |
2938 | |
2939 | bool SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor_id, Uint16 product_id) |
2940 | { |
2941 | EControllerType eType = GuessControllerType(vendor_id, product_id); |
2942 | return eType == k_eControllerType_SwitchInputOnlyController; |
2943 | } |
2944 | |
2945 | bool SDL_IsJoystickNintendoSwitchJoyCon(Uint16 vendor_id, Uint16 product_id) |
2946 | { |
2947 | EControllerType eType = GuessControllerType(vendor_id, product_id); |
2948 | return eType == k_eControllerType_SwitchJoyConLeft || eType == k_eControllerType_SwitchJoyConRight; |
2949 | } |
2950 | |
2951 | bool SDL_IsJoystickNintendoSwitchJoyConLeft(Uint16 vendor_id, Uint16 product_id) |
2952 | { |
2953 | EControllerType eType = GuessControllerType(vendor_id, product_id); |
2954 | return eType == k_eControllerType_SwitchJoyConLeft; |
2955 | } |
2956 | |
2957 | bool SDL_IsJoystickNintendoSwitchJoyConRight(Uint16 vendor_id, Uint16 product_id) |
2958 | { |
2959 | EControllerType eType = GuessControllerType(vendor_id, product_id); |
2960 | return eType == k_eControllerType_SwitchJoyConRight; |
2961 | } |
2962 | |
2963 | bool SDL_IsJoystickNintendoSwitchJoyConGrip(Uint16 vendor_id, Uint16 product_id) |
2964 | { |
2965 | return vendor_id == USB_VENDOR_NINTENDO && product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_GRIP; |
2966 | } |
2967 | |
2968 | bool SDL_IsJoystickNintendoSwitchJoyConPair(Uint16 vendor_id, Uint16 product_id) |
2969 | { |
2970 | return vendor_id == USB_VENDOR_NINTENDO && product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR; |
2971 | } |
2972 | |
2973 | bool SDL_IsJoystickGameCube(Uint16 vendor_id, Uint16 product_id) |
2974 | { |
2975 | return SDL_VIDPIDInList(vendor_id, product_id, &gamecube_devices); |
2976 | } |
2977 | |
2978 | bool SDL_IsJoystickAmazonLunaController(Uint16 vendor_id, Uint16 product_id) |
2979 | { |
2980 | return ((vendor_id == USB_VENDOR_AMAZON && product_id == USB_PRODUCT_AMAZON_LUNA_CONTROLLER) || |
2981 | (vendor_id == BLUETOOTH_VENDOR_AMAZON && product_id == BLUETOOTH_PRODUCT_LUNA_CONTROLLER)); |
2982 | } |
2983 | |
2984 | bool SDL_IsJoystickGoogleStadiaController(Uint16 vendor_id, Uint16 product_id) |
2985 | { |
2986 | return vendor_id == USB_VENDOR_GOOGLE && product_id == USB_PRODUCT_GOOGLE_STADIA_CONTROLLER; |
2987 | } |
2988 | |
2989 | bool SDL_IsJoystickNVIDIASHIELDController(Uint16 vendor_id, Uint16 product_id) |
2990 | { |
2991 | return (vendor_id == USB_VENDOR_NVIDIA && |
2992 | (product_id == USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V103 || |
2993 | product_id == USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V104)); |
2994 | } |
2995 | |
2996 | bool SDL_IsJoystickSteamVirtualGamepad(Uint16 vendor_id, Uint16 product_id, Uint16 version) |
2997 | { |
2998 | #ifdef SDL_PLATFORM_MACOS |
2999 | return (vendor_id == USB_VENDOR_MICROSOFT && product_id == USB_PRODUCT_XBOX360_WIRED_CONTROLLER && version == 0); |
3000 | #else |
3001 | return (vendor_id == USB_VENDOR_VALVE && product_id == USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD); |
3002 | #endif |
3003 | } |
3004 | |
3005 | bool SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id) |
3006 | { |
3007 | EControllerType eType = GuessControllerType(vendor_id, product_id); |
3008 | return eType == k_eControllerType_SteamController || eType == k_eControllerType_SteamControllerV2; |
3009 | } |
3010 | |
3011 | bool SDL_IsJoystickHoriSteamController(Uint16 vendor_id, Uint16 product_id) |
3012 | { |
3013 | return vendor_id == USB_VENDOR_HORI && (product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER || product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER_BT); |
3014 | } |
3015 | |
3016 | bool SDL_IsJoystickSteamDeck(Uint16 vendor_id, Uint16 product_id) |
3017 | { |
3018 | EControllerType eType = GuessControllerType(vendor_id, product_id); |
3019 | return eType == k_eControllerType_SteamControllerNeptune; |
3020 | } |
3021 | |
3022 | bool SDL_IsJoystickXInput(SDL_GUID guid) |
3023 | { |
3024 | return (guid.data[14] == 'x') ? true : false; |
3025 | } |
3026 | |
3027 | bool SDL_IsJoystickWGI(SDL_GUID guid) |
3028 | { |
3029 | return (guid.data[14] == 'w') ? true : false; |
3030 | } |
3031 | |
3032 | bool SDL_IsJoystickHIDAPI(SDL_GUID guid) |
3033 | { |
3034 | return (guid.data[14] == 'h') ? true : false; |
3035 | } |
3036 | |
3037 | bool SDL_IsJoystickMFI(SDL_GUID guid) |
3038 | { |
3039 | return (guid.data[14] == 'm') ? true : false; |
3040 | } |
3041 | |
3042 | bool SDL_IsJoystickRAWINPUT(SDL_GUID guid) |
3043 | { |
3044 | return (guid.data[14] == 'r') ? true : false; |
3045 | } |
3046 | |
3047 | bool SDL_IsJoystickVIRTUAL(SDL_GUID guid) |
3048 | { |
3049 | return (guid.data[14] == 'v') ? true : false; |
3050 | } |
3051 | |
3052 | bool SDL_IsJoystickWheel(Uint16 vendor_id, Uint16 product_id) |
3053 | { |
3054 | return SDL_VIDPIDInList(vendor_id, product_id, &wheel_devices); |
3055 | } |
3056 | |
3057 | static bool SDL_IsJoystickArcadeStick(Uint16 vendor_id, Uint16 product_id) |
3058 | { |
3059 | return SDL_VIDPIDInList(vendor_id, product_id, &arcadestick_devices); |
3060 | } |
3061 | |
3062 | static bool SDL_IsJoystickFlightStick(Uint16 vendor_id, Uint16 product_id) |
3063 | { |
3064 | return SDL_VIDPIDInList(vendor_id, product_id, &flightstick_devices); |
3065 | } |
3066 | |
3067 | static bool SDL_IsJoystickThrottle(Uint16 vendor_id, Uint16 product_id) |
3068 | { |
3069 | return SDL_VIDPIDInList(vendor_id, product_id, &throttle_devices); |
3070 | } |
3071 | |
3072 | static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_GUID guid) |
3073 | { |
3074 | Uint16 vendor; |
3075 | Uint16 product; |
3076 | |
3077 | SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, NULL); |
3078 | |
3079 | if (SDL_IsJoystickWheel(vendor, product)) { |
3080 | return SDL_JOYSTICK_TYPE_WHEEL; |
3081 | } |
3082 | |
3083 | if (SDL_IsJoystickArcadeStick(vendor, product)) { |
3084 | return SDL_JOYSTICK_TYPE_ARCADE_STICK; |
3085 | } |
3086 | |
3087 | if (SDL_IsJoystickFlightStick(vendor, product)) { |
3088 | return SDL_JOYSTICK_TYPE_FLIGHT_STICK; |
3089 | } |
3090 | |
3091 | if (SDL_IsJoystickThrottle(vendor, product)) { |
3092 | return SDL_JOYSTICK_TYPE_THROTTLE; |
3093 | } |
3094 | |
3095 | if (SDL_IsJoystickXInput(guid)) { |
3096 | // XInput GUID, get the type based on the XInput device subtype |
3097 | switch (guid.data[15]) { |
3098 | case 0x01: // XINPUT_DEVSUBTYPE_GAMEPAD |
3099 | return SDL_JOYSTICK_TYPE_GAMEPAD; |
3100 | case 0x02: // XINPUT_DEVSUBTYPE_WHEEL |
3101 | return SDL_JOYSTICK_TYPE_WHEEL; |
3102 | case 0x03: // XINPUT_DEVSUBTYPE_ARCADE_STICK |
3103 | return SDL_JOYSTICK_TYPE_ARCADE_STICK; |
3104 | case 0x04: // XINPUT_DEVSUBTYPE_FLIGHT_STICK |
3105 | return SDL_JOYSTICK_TYPE_FLIGHT_STICK; |
3106 | case 0x05: // XINPUT_DEVSUBTYPE_DANCE_PAD |
3107 | return SDL_JOYSTICK_TYPE_DANCE_PAD; |
3108 | case 0x06: // XINPUT_DEVSUBTYPE_GUITAR |
3109 | case 0x07: // XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE |
3110 | case 0x0B: // XINPUT_DEVSUBTYPE_GUITAR_BASS |
3111 | return SDL_JOYSTICK_TYPE_GUITAR; |
3112 | case 0x08: // XINPUT_DEVSUBTYPE_DRUM_KIT |
3113 | return SDL_JOYSTICK_TYPE_DRUM_KIT; |
3114 | case 0x13: // XINPUT_DEVSUBTYPE_ARCADE_PAD |
3115 | return SDL_JOYSTICK_TYPE_ARCADE_PAD; |
3116 | default: |
3117 | return SDL_JOYSTICK_TYPE_UNKNOWN; |
3118 | } |
3119 | } |
3120 | |
3121 | if (SDL_IsJoystickWGI(guid)) { |
3122 | return (SDL_JoystickType)guid.data[15]; |
3123 | } |
3124 | |
3125 | if (SDL_IsJoystickVIRTUAL(guid)) { |
3126 | return (SDL_JoystickType)guid.data[15]; |
3127 | } |
3128 | |
3129 | #ifdef SDL_JOYSTICK_HIDAPI |
3130 | if (SDL_IsJoystickHIDAPI(guid)) { |
3131 | return HIDAPI_GetJoystickTypeFromGUID(guid); |
3132 | } |
3133 | #endif // SDL_JOYSTICK_HIDAPI |
3134 | |
3135 | if (GuessControllerType(vendor, product) != k_eControllerType_UnknownNonSteamController) { |
3136 | return SDL_JOYSTICK_TYPE_GAMEPAD; |
3137 | } |
3138 | |
3139 | return SDL_JOYSTICK_TYPE_UNKNOWN; |
3140 | } |
3141 | |
3142 | bool SDL_ShouldIgnoreJoystick(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name) |
3143 | { |
3144 | // Check the joystick blacklist |
3145 | if (SDL_VIDPIDInList(vendor_id, product_id, &blacklist_devices)) { |
3146 | return true; |
3147 | } |
3148 | if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_ROG_CHAKRAM, false)) { |
3149 | if (SDL_VIDPIDInList(vendor_id, product_id, &rog_gamepad_mice)) { |
3150 | return true; |
3151 | } |
3152 | } |
3153 | |
3154 | if (SDL_ShouldIgnoreGamepad(vendor_id, product_id, version, name)) { |
3155 | return true; |
3156 | } |
3157 | |
3158 | return false; |
3159 | } |
3160 | |
3161 | // return the guid for this index |
3162 | SDL_GUID SDL_GetJoystickGUIDForID(SDL_JoystickID instance_id) |
3163 | { |
3164 | SDL_JoystickDriver *driver; |
3165 | int device_index; |
3166 | SDL_GUID guid; |
3167 | |
3168 | SDL_LockJoysticks(); |
3169 | if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) { |
3170 | guid = driver->GetDeviceGUID(device_index); |
3171 | } else { |
3172 | SDL_zero(guid); |
3173 | } |
3174 | SDL_UnlockJoysticks(); |
3175 | |
3176 | return guid; |
3177 | } |
3178 | |
3179 | Uint16 SDL_GetJoystickVendorForID(SDL_JoystickID instance_id) |
3180 | { |
3181 | Uint16 vendor; |
3182 | const SDL_SteamVirtualGamepadInfo *info; |
3183 | |
3184 | SDL_LockJoysticks(); |
3185 | info = SDL_GetJoystickVirtualGamepadInfoForID(instance_id); |
3186 | if (info) { |
3187 | vendor = info->vendor_id; |
3188 | } else { |
3189 | SDL_GUID guid = SDL_GetJoystickGUIDForID(instance_id); |
3190 | |
3191 | SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL, NULL); |
3192 | } |
3193 | SDL_UnlockJoysticks(); |
3194 | |
3195 | return vendor; |
3196 | } |
3197 | |
3198 | Uint16 SDL_GetJoystickProductForID(SDL_JoystickID instance_id) |
3199 | { |
3200 | Uint16 product; |
3201 | const SDL_SteamVirtualGamepadInfo *info; |
3202 | |
3203 | SDL_LockJoysticks(); |
3204 | info = SDL_GetJoystickVirtualGamepadInfoForID(instance_id); |
3205 | if (info) { |
3206 | product = info->product_id; |
3207 | } else { |
3208 | SDL_GUID guid = SDL_GetJoystickGUIDForID(instance_id); |
3209 | |
3210 | SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL, NULL); |
3211 | } |
3212 | SDL_UnlockJoysticks(); |
3213 | |
3214 | return product; |
3215 | } |
3216 | |
3217 | Uint16 SDL_GetJoystickProductVersionForID(SDL_JoystickID instance_id) |
3218 | { |
3219 | Uint16 version; |
3220 | SDL_GUID guid = SDL_GetJoystickGUIDForID(instance_id); |
3221 | |
3222 | SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version, NULL); |
3223 | return version; |
3224 | } |
3225 | |
3226 | SDL_JoystickType SDL_GetJoystickTypeForID(SDL_JoystickID instance_id) |
3227 | { |
3228 | SDL_JoystickType type; |
3229 | SDL_GUID guid = SDL_GetJoystickGUIDForID(instance_id); |
3230 | |
3231 | type = SDL_GetJoystickGUIDType(guid); |
3232 | if (type == SDL_JOYSTICK_TYPE_UNKNOWN) { |
3233 | if (SDL_IsGamepad(instance_id)) { |
3234 | type = SDL_JOYSTICK_TYPE_GAMEPAD; |
3235 | } |
3236 | } |
3237 | return type; |
3238 | } |
3239 | |
3240 | SDL_GUID SDL_GetJoystickGUID(SDL_Joystick *joystick) |
3241 | { |
3242 | SDL_GUID result; |
3243 | |
3244 | SDL_LockJoysticks(); |
3245 | { |
3246 | static SDL_GUID emptyGUID; |
3247 | |
3248 | CHECK_JOYSTICK_MAGIC(joystick, emptyGUID); |
3249 | |
3250 | result = joystick->guid; |
3251 | } |
3252 | SDL_UnlockJoysticks(); |
3253 | |
3254 | return result; |
3255 | } |
3256 | |
3257 | Uint16 SDL_GetJoystickVendor(SDL_Joystick *joystick) |
3258 | { |
3259 | Uint16 vendor; |
3260 | const SDL_SteamVirtualGamepadInfo *info; |
3261 | |
3262 | SDL_LockJoysticks(); |
3263 | { |
3264 | CHECK_JOYSTICK_MAGIC(joystick, 0); |
3265 | |
3266 | info = SDL_GetJoystickVirtualGamepadInfoForID(joystick->instance_id); |
3267 | if (info) { |
3268 | vendor = info->vendor_id; |
3269 | } else { |
3270 | SDL_GUID guid = SDL_GetJoystickGUID(joystick); |
3271 | |
3272 | SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL, NULL); |
3273 | } |
3274 | } |
3275 | SDL_UnlockJoysticks(); |
3276 | |
3277 | return vendor; |
3278 | } |
3279 | |
3280 | Uint16 SDL_GetJoystickProduct(SDL_Joystick *joystick) |
3281 | { |
3282 | Uint16 product; |
3283 | const SDL_SteamVirtualGamepadInfo *info; |
3284 | |
3285 | SDL_LockJoysticks(); |
3286 | { |
3287 | CHECK_JOYSTICK_MAGIC(joystick, 0); |
3288 | |
3289 | info = SDL_GetJoystickVirtualGamepadInfoForID(joystick->instance_id); |
3290 | if (info) { |
3291 | product = info->product_id; |
3292 | } else { |
3293 | SDL_GUID guid = SDL_GetJoystickGUID(joystick); |
3294 | |
3295 | SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL, NULL); |
3296 | } |
3297 | } |
3298 | SDL_UnlockJoysticks(); |
3299 | |
3300 | return product; |
3301 | } |
3302 | |
3303 | Uint16 SDL_GetJoystickProductVersion(SDL_Joystick *joystick) |
3304 | { |
3305 | Uint16 version; |
3306 | SDL_GUID guid = SDL_GetJoystickGUID(joystick); |
3307 | |
3308 | SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version, NULL); |
3309 | return version; |
3310 | } |
3311 | |
3312 | Uint16 SDL_GetJoystickFirmwareVersion(SDL_Joystick *joystick) |
3313 | { |
3314 | Uint16 result; |
3315 | |
3316 | SDL_LockJoysticks(); |
3317 | { |
3318 | CHECK_JOYSTICK_MAGIC(joystick, 0); |
3319 | |
3320 | result = joystick->firmware_version; |
3321 | } |
3322 | SDL_UnlockJoysticks(); |
3323 | |
3324 | return result; |
3325 | } |
3326 | |
3327 | const char *SDL_GetJoystickSerial(SDL_Joystick *joystick) |
3328 | { |
3329 | const char *result; |
3330 | |
3331 | SDL_LockJoysticks(); |
3332 | { |
3333 | CHECK_JOYSTICK_MAGIC(joystick, NULL); |
3334 | |
3335 | result = SDL_GetPersistentString(joystick->serial); |
3336 | } |
3337 | SDL_UnlockJoysticks(); |
3338 | |
3339 | return result; |
3340 | } |
3341 | |
3342 | SDL_JoystickType SDL_GetJoystickType(SDL_Joystick *joystick) |
3343 | { |
3344 | SDL_JoystickType type; |
3345 | SDL_GUID guid = SDL_GetJoystickGUID(joystick); |
3346 | |
3347 | type = SDL_GetJoystickGUIDType(guid); |
3348 | if (type == SDL_JOYSTICK_TYPE_UNKNOWN) { |
3349 | SDL_LockJoysticks(); |
3350 | { |
3351 | CHECK_JOYSTICK_MAGIC(joystick, SDL_JOYSTICK_TYPE_UNKNOWN); |
3352 | |
3353 | if (SDL_IsGamepad(joystick->instance_id)) { |
3354 | type = SDL_JOYSTICK_TYPE_GAMEPAD; |
3355 | } |
3356 | } |
3357 | SDL_UnlockJoysticks(); |
3358 | } |
3359 | return type; |
3360 | } |
3361 | |
3362 | void SDL_SendJoystickPowerInfo(SDL_Joystick *joystick, SDL_PowerState state, int percent) |
3363 | { |
3364 | SDL_AssertJoysticksLocked(); |
3365 | |
3366 | if (state != joystick->battery_state || percent != joystick->battery_percent) { |
3367 | joystick->battery_state = state; |
3368 | joystick->battery_percent = percent; |
3369 | |
3370 | if (SDL_EventEnabled(SDL_EVENT_JOYSTICK_BATTERY_UPDATED)) { |
3371 | SDL_Event event; |
3372 | event.type = SDL_EVENT_JOYSTICK_BATTERY_UPDATED; |
3373 | event.common.timestamp = 0; |
3374 | event.jbattery.which = joystick->instance_id; |
3375 | event.jbattery.state = state; |
3376 | event.jbattery.percent = percent; |
3377 | SDL_PushEvent(&event); |
3378 | } |
3379 | } |
3380 | } |
3381 | |
3382 | SDL_JoystickConnectionState SDL_GetJoystickConnectionState(SDL_Joystick *joystick) |
3383 | { |
3384 | SDL_JoystickConnectionState result; |
3385 | |
3386 | SDL_LockJoysticks(); |
3387 | { |
3388 | CHECK_JOYSTICK_MAGIC(joystick, SDL_JOYSTICK_CONNECTION_INVALID); |
3389 | |
3390 | result = joystick->connection_state; |
3391 | } |
3392 | SDL_UnlockJoysticks(); |
3393 | |
3394 | return result; |
3395 | } |
3396 | |
3397 | SDL_PowerState SDL_GetJoystickPowerInfo(SDL_Joystick *joystick, int *percent) |
3398 | { |
3399 | SDL_PowerState result; |
3400 | |
3401 | if (percent) { |
3402 | *percent = -1; |
3403 | } |
3404 | |
3405 | SDL_LockJoysticks(); |
3406 | { |
3407 | CHECK_JOYSTICK_MAGIC(joystick, SDL_POWERSTATE_ERROR); |
3408 | |
3409 | result = joystick->battery_state; |
3410 | |
3411 | if (percent) { |
3412 | *percent = joystick->battery_percent; |
3413 | } |
3414 | } |
3415 | SDL_UnlockJoysticks(); |
3416 | |
3417 | return result; |
3418 | } |
3419 | |
3420 | void SDL_SendJoystickTouchpad(Uint64 timestamp, SDL_Joystick *joystick, int touchpad, int finger, bool down, float x, float y, float pressure) |
3421 | { |
3422 | SDL_JoystickTouchpadInfo *touchpad_info; |
3423 | SDL_JoystickTouchpadFingerInfo *finger_info; |
3424 | Uint32 event_type; |
3425 | |
3426 | SDL_AssertJoysticksLocked(); |
3427 | |
3428 | if (touchpad < 0 || touchpad >= joystick->ntouchpads) { |
3429 | return; |
3430 | } |
3431 | |
3432 | touchpad_info = &joystick->touchpads[touchpad]; |
3433 | if (finger < 0 || finger >= touchpad_info->nfingers) { |
3434 | return; |
3435 | } |
3436 | |
3437 | finger_info = &touchpad_info->fingers[finger]; |
3438 | |
3439 | if (!down) { |
3440 | if (x == 0.0f && y == 0.0f) { |
3441 | x = finger_info->x; |
3442 | y = finger_info->y; |
3443 | } |
3444 | pressure = 0.0f; |
3445 | } |
3446 | |
3447 | if (x < 0.0f) { |
3448 | x = 0.0f; |
3449 | } else if (x > 1.0f) { |
3450 | x = 1.0f; |
3451 | } |
3452 | if (y < 0.0f) { |
3453 | y = 0.0f; |
3454 | } else if (y > 1.0f) { |
3455 | y = 1.0f; |
3456 | } |
3457 | if (pressure < 0.0f) { |
3458 | pressure = 0.0f; |
3459 | } else if (pressure > 1.0f) { |
3460 | pressure = 1.0f; |
3461 | } |
3462 | |
3463 | if (down == finger_info->down) { |
3464 | if (!down || |
3465 | (x == finger_info->x && y == finger_info->y && pressure == finger_info->pressure)) { |
3466 | return; |
3467 | } |
3468 | } |
3469 | |
3470 | if (down == finger_info->down) { |
3471 | event_type = SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION; |
3472 | } else if (down) { |
3473 | event_type = SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN; |
3474 | } else { |
3475 | event_type = SDL_EVENT_GAMEPAD_TOUCHPAD_UP; |
3476 | } |
3477 | |
3478 | // We ignore events if we don't have keyboard focus, except for touch release |
3479 | if (SDL_PrivateJoystickShouldIgnoreEvent()) { |
3480 | if (event_type != SDL_EVENT_GAMEPAD_TOUCHPAD_UP) { |
3481 | return; |
3482 | } |
3483 | } |
3484 | |
3485 | // Update internal joystick state |
3486 | SDL_assert(timestamp != 0); |
3487 | finger_info->down = down; |
3488 | finger_info->x = x; |
3489 | finger_info->y = y; |
3490 | finger_info->pressure = pressure; |
3491 | joystick->update_complete = timestamp; |
3492 | |
3493 | // Post the event, if desired |
3494 | if (SDL_EventEnabled(event_type)) { |
3495 | SDL_Event event; |
3496 | event.type = event_type; |
3497 | event.common.timestamp = timestamp; |
3498 | event.gtouchpad.which = joystick->instance_id; |
3499 | event.gtouchpad.touchpad = touchpad; |
3500 | event.gtouchpad.finger = finger; |
3501 | event.gtouchpad.x = x; |
3502 | event.gtouchpad.y = y; |
3503 | event.gtouchpad.pressure = pressure; |
3504 | SDL_PushEvent(&event); |
3505 | } |
3506 | } |
3507 | |
3508 | void SDL_SendJoystickSensor(Uint64 timestamp, SDL_Joystick *joystick, SDL_SensorType type, Uint64 sensor_timestamp, const float *data, int num_values) |
3509 | { |
3510 | SDL_AssertJoysticksLocked(); |
3511 | |
3512 | // We ignore events if we don't have keyboard focus |
3513 | if (SDL_PrivateJoystickShouldIgnoreEvent()) { |
3514 | return; |
3515 | } |
3516 | |
3517 | for (int i = 0; i < joystick->nsensors; ++i) { |
3518 | SDL_JoystickSensorInfo *sensor = &joystick->sensors[i]; |
3519 | |
3520 | if (sensor->type == type) { |
3521 | if (sensor->enabled) { |
3522 | num_values = SDL_min(num_values, SDL_arraysize(sensor->data)); |
3523 | |
3524 | // Update internal sensor state |
3525 | SDL_memcpy(sensor->data, data, num_values * sizeof(*data)); |
3526 | joystick->update_complete = timestamp; |
3527 | |
3528 | // Post the event, if desired |
3529 | if (SDL_EventEnabled(SDL_EVENT_GAMEPAD_SENSOR_UPDATE)) { |
3530 | SDL_Event event; |
3531 | event.type = SDL_EVENT_GAMEPAD_SENSOR_UPDATE; |
3532 | event.common.timestamp = timestamp; |
3533 | event.gsensor.which = joystick->instance_id; |
3534 | event.gsensor.sensor = type; |
3535 | num_values = SDL_min(num_values, |
3536 | SDL_arraysize(event.gsensor.data)); |
3537 | SDL_memset(event.gsensor.data, 0, |
3538 | sizeof(event.gsensor.data)); |
3539 | SDL_memcpy(event.gsensor.data, data, |
3540 | num_values * sizeof(*data)); |
3541 | event.gsensor.sensor_timestamp = sensor_timestamp; |
3542 | SDL_PushEvent(&event); |
3543 | } |
3544 | } |
3545 | break; |
3546 | } |
3547 | } |
3548 | } |
3549 | |
3550 | static void SDL_LoadVIDPIDListFromHint(const char *hint, int *num_entries, int *max_entries, Uint32 **entries) |
3551 | { |
3552 | Uint32 entry; |
3553 | char *spot; |
3554 | char *file = NULL; |
3555 | |
3556 | if (hint && *hint == '@') { |
3557 | spot = file = (char *)SDL_LoadFile(hint + 1, NULL); |
3558 | } else { |
3559 | spot = (char *)hint; |
3560 | } |
3561 | |
3562 | if (!spot) { |
3563 | return; |
3564 | } |
3565 | |
3566 | while ((spot = SDL_strstr(spot, "0x" )) != NULL) { |
3567 | entry = (Uint16)SDL_strtol(spot, &spot, 0); |
3568 | entry <<= 16; |
3569 | spot = SDL_strstr(spot, "0x" ); |
3570 | if (!spot) { |
3571 | break; |
3572 | } |
3573 | entry |= (Uint16)SDL_strtol(spot, &spot, 0); |
3574 | |
3575 | if (*num_entries == *max_entries) { |
3576 | int new_max_entries = *max_entries + 16; |
3577 | Uint32 *new_entries = (Uint32 *)SDL_realloc(*entries, new_max_entries * sizeof(**entries)); |
3578 | if (!new_entries) { |
3579 | // Out of memory, go with what we have already |
3580 | break; |
3581 | } |
3582 | *entries = new_entries; |
3583 | *max_entries = new_max_entries; |
3584 | } |
3585 | (*entries)[(*num_entries)++] = entry; |
3586 | } |
3587 | |
3588 | if (file) { |
3589 | SDL_free(file); |
3590 | } |
3591 | } |
3592 | |
3593 | void SDL_LoadVIDPIDListFromHints(SDL_vidpid_list *list, const char *included_list, const char *excluded_list) |
3594 | { |
3595 | // Empty the list |
3596 | list->num_included_entries = 0; |
3597 | list->num_excluded_entries = 0; |
3598 | |
3599 | // Add the initial entries |
3600 | if (list->num_initial_entries > 0) { |
3601 | if (list->num_included_entries < list->num_initial_entries) { |
3602 | Uint32 *entries = (Uint32 *)SDL_malloc(list->num_initial_entries * sizeof(*entries)); |
3603 | if (entries) { |
3604 | SDL_memcpy(entries, list->initial_entries, list->num_initial_entries * sizeof(*entries)); |
3605 | list->included_entries = entries; |
3606 | list->num_included_entries = list->num_initial_entries; |
3607 | list->max_included_entries = list->num_initial_entries; |
3608 | } |
3609 | } |
3610 | } |
3611 | |
3612 | // Add the included entries from the hint |
3613 | SDL_LoadVIDPIDListFromHint(included_list, &list->num_included_entries, &list->max_included_entries, &list->included_entries); |
3614 | |
3615 | // Add the excluded entries from the hint |
3616 | SDL_LoadVIDPIDListFromHint(excluded_list, &list->num_excluded_entries, &list->max_excluded_entries, &list->excluded_entries); |
3617 | } |
3618 | |
3619 | static void SDLCALL SDL_VIDPIDIncludedHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint) |
3620 | { |
3621 | SDL_vidpid_list *list = (SDL_vidpid_list *)userdata; |
3622 | const char *included_list = hint; |
3623 | const char *excluded_list = NULL; |
3624 | |
3625 | if (!list->initialized) { |
3626 | return; |
3627 | } |
3628 | |
3629 | if (list->excluded_hint_name) { |
3630 | excluded_list = SDL_GetHint(list->excluded_hint_name); |
3631 | } |
3632 | SDL_LoadVIDPIDListFromHints(list, included_list, excluded_list); |
3633 | } |
3634 | |
3635 | static void SDLCALL SDL_VIDPIDExcludedHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint) |
3636 | { |
3637 | SDL_vidpid_list *list = (SDL_vidpid_list *)userdata; |
3638 | const char *included_list = NULL; |
3639 | const char *excluded_list = hint; |
3640 | |
3641 | if (!list->initialized) { |
3642 | return; |
3643 | } |
3644 | |
3645 | if (list->included_hint_name) { |
3646 | included_list = SDL_GetHint(list->included_hint_name); |
3647 | } |
3648 | SDL_LoadVIDPIDListFromHints(list, included_list, excluded_list); |
3649 | } |
3650 | |
3651 | void SDL_LoadVIDPIDList(SDL_vidpid_list *list) |
3652 | { |
3653 | const char *included_list = NULL; |
3654 | const char *excluded_list = NULL; |
3655 | |
3656 | if (list->included_hint_name) { |
3657 | SDL_AddHintCallback(list->included_hint_name, SDL_VIDPIDIncludedHintChanged, list); |
3658 | } |
3659 | |
3660 | if (list->excluded_hint_name) { |
3661 | SDL_AddHintCallback(list->excluded_hint_name, SDL_VIDPIDExcludedHintChanged, list); |
3662 | } |
3663 | |
3664 | list->initialized = true; |
3665 | |
3666 | if (list->included_hint_name) { |
3667 | included_list = SDL_GetHint(list->included_hint_name); |
3668 | } |
3669 | if (list->excluded_hint_name) { |
3670 | excluded_list = SDL_GetHint(list->excluded_hint_name); |
3671 | } |
3672 | SDL_LoadVIDPIDListFromHints(list, included_list, excluded_list); |
3673 | } |
3674 | |
3675 | bool SDL_VIDPIDInList(Uint16 vendor_id, Uint16 product_id, const SDL_vidpid_list *list) |
3676 | { |
3677 | int i; |
3678 | Uint32 vidpid = MAKE_VIDPID(vendor_id, product_id); |
3679 | |
3680 | for (i = 0; i < list->num_excluded_entries; ++i) { |
3681 | if (vidpid == list->excluded_entries[i]) { |
3682 | return false; |
3683 | } |
3684 | } |
3685 | for (i = 0; i < list->num_included_entries; ++i) { |
3686 | if (vidpid == list->included_entries[i]) { |
3687 | return true; |
3688 | } |
3689 | } |
3690 | return false; |
3691 | } |
3692 | |
3693 | void SDL_FreeVIDPIDList(SDL_vidpid_list *list) |
3694 | { |
3695 | if (list->included_hint_name) { |
3696 | SDL_RemoveHintCallback(list->included_hint_name, SDL_VIDPIDIncludedHintChanged, list); |
3697 | } |
3698 | |
3699 | if (list->excluded_hint_name) { |
3700 | SDL_RemoveHintCallback(list->excluded_hint_name, SDL_VIDPIDExcludedHintChanged, list); |
3701 | } |
3702 | |
3703 | if (list->included_entries) { |
3704 | SDL_free(list->included_entries); |
3705 | list->included_entries = NULL; |
3706 | list->num_included_entries = 0; |
3707 | list->max_included_entries = 0; |
3708 | } |
3709 | |
3710 | if (list->excluded_entries) { |
3711 | SDL_free(list->excluded_entries); |
3712 | list->excluded_entries = NULL; |
3713 | list->num_excluded_entries = 0; |
3714 | list->max_excluded_entries = 0; |
3715 | } |
3716 | |
3717 | list->initialized = false; |
3718 | } |
3719 | |