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