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