Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/sdl/joystick/linux/SDL_sysjoystick.c
21635 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
#ifdef SDL_JOYSTICK_LINUX
24
25
#ifndef SDL_INPUT_LINUXEV
26
#error SDL now requires a Linux 2.4+ kernel with /dev/input/event support.
27
#endif
28
29
// This is the Linux implementation of the SDL joystick API
30
31
#include <sys/stat.h>
32
#include <errno.h> // errno, strerror
33
#include <fcntl.h>
34
#include <limits.h> // For the definition of PATH_MAX
35
#ifdef HAVE_INOTIFY
36
#include <sys/inotify.h>
37
#include <string.h> // strerror
38
#endif
39
#include <sys/ioctl.h>
40
#include <unistd.h>
41
#include <dirent.h>
42
#include <linux/joystick.h>
43
44
#include "../../events/SDL_events_c.h"
45
#include "../../core/linux/SDL_evdev.h"
46
#include "../SDL_sysjoystick.h"
47
#include "../SDL_joystick_c.h"
48
#include "../usb_ids.h"
49
#include "SDL_sysjoystick_c.h"
50
#include "../hidapi/SDL_hidapijoystick_c.h"
51
52
// This isn't defined in older Linux kernel headers
53
#ifndef MSC_TIMESTAMP
54
#define MSC_TIMESTAMP 0x05
55
#endif
56
57
#ifndef SYN_DROPPED
58
#define SYN_DROPPED 3
59
#endif
60
#ifndef BTN_NORTH
61
#define BTN_NORTH 0x133
62
#endif
63
#ifndef BTN_WEST
64
#define BTN_WEST 0x134
65
#endif
66
#ifndef BTN_DPAD_UP
67
#define BTN_DPAD_UP 0x220
68
#endif
69
#ifndef BTN_DPAD_DOWN
70
#define BTN_DPAD_DOWN 0x221
71
#endif
72
#ifndef BTN_DPAD_LEFT
73
#define BTN_DPAD_LEFT 0x222
74
#endif
75
#ifndef BTN_DPAD_RIGHT
76
#define BTN_DPAD_RIGHT 0x223
77
#endif
78
79
#ifndef BTN_TRIGGER_HAPPY
80
#define BTN_TRIGGER_HAPPY 0x2c0
81
#define BTN_TRIGGER_HAPPY1 0x2c0
82
#define BTN_TRIGGER_HAPPY2 0x2c1
83
#define BTN_TRIGGER_HAPPY3 0x2c2
84
#define BTN_TRIGGER_HAPPY4 0x2c3
85
#define BTN_TRIGGER_HAPPY5 0x2c4
86
#define BTN_TRIGGER_HAPPY6 0x2c5
87
#define BTN_TRIGGER_HAPPY7 0x2c6
88
#define BTN_TRIGGER_HAPPY8 0x2c7
89
#define BTN_TRIGGER_HAPPY9 0x2c8
90
#define BTN_TRIGGER_HAPPY10 0x2c9
91
#define BTN_TRIGGER_HAPPY11 0x2ca
92
#define BTN_TRIGGER_HAPPY12 0x2cb
93
#define BTN_TRIGGER_HAPPY13 0x2cc
94
#define BTN_TRIGGER_HAPPY14 0x2cd
95
#define BTN_TRIGGER_HAPPY15 0x2ce
96
#define BTN_TRIGGER_HAPPY16 0x2cf
97
#define BTN_TRIGGER_HAPPY17 0x2d0
98
#define BTN_TRIGGER_HAPPY18 0x2d1
99
#define BTN_TRIGGER_HAPPY19 0x2d2
100
#define BTN_TRIGGER_HAPPY20 0x2d3
101
#define BTN_TRIGGER_HAPPY21 0x2d4
102
#define BTN_TRIGGER_HAPPY22 0x2d5
103
#define BTN_TRIGGER_HAPPY23 0x2d6
104
#define BTN_TRIGGER_HAPPY24 0x2d7
105
#define BTN_TRIGGER_HAPPY25 0x2d8
106
#define BTN_TRIGGER_HAPPY26 0x2d9
107
#define BTN_TRIGGER_HAPPY27 0x2da
108
#define BTN_TRIGGER_HAPPY28 0x2db
109
#define BTN_TRIGGER_HAPPY29 0x2dc
110
#define BTN_TRIGGER_HAPPY30 0x2dd
111
#define BTN_TRIGGER_HAPPY31 0x2de
112
#define BTN_TRIGGER_HAPPY32 0x2df
113
#define BTN_TRIGGER_HAPPY33 0x2e0
114
#define BTN_TRIGGER_HAPPY34 0x2e1
115
#define BTN_TRIGGER_HAPPY35 0x2e2
116
#define BTN_TRIGGER_HAPPY36 0x2e3
117
#define BTN_TRIGGER_HAPPY37 0x2e4
118
#define BTN_TRIGGER_HAPPY38 0x2e5
119
#define BTN_TRIGGER_HAPPY39 0x2e6
120
#define BTN_TRIGGER_HAPPY40 0x2e7
121
#endif
122
123
124
#include "../../core/linux/SDL_evdev_capabilities.h"
125
#include "../../core/linux/SDL_udev.h"
126
127
#if 0
128
#define DEBUG_INPUT_EVENTS 1
129
#endif
130
131
#if 0
132
#define DEBUG_GAMEPAD_MAPPING 1
133
#endif
134
135
typedef enum
136
{
137
ENUMERATION_UNSET,
138
ENUMERATION_LIBUDEV,
139
ENUMERATION_FALLBACK
140
} EnumerationMethod;
141
142
static EnumerationMethod enumeration_method = ENUMERATION_UNSET;
143
144
static bool IsJoystickJSNode(const char *node);
145
static void MaybeAddDevice(const char *path);
146
static void MaybeRemoveDevice(const char *path);
147
148
// A linked list of available joysticks
149
typedef struct SDL_joylist_item
150
{
151
SDL_JoystickID device_instance;
152
char *path; // "/dev/input/event2" or whatever
153
Uint16 vendor;
154
Uint16 product;
155
char *name; // "SideWinder 3D Pro" or whatever
156
SDL_GUID guid;
157
dev_t devnum;
158
int steam_virtual_gamepad_slot;
159
struct joystick_hwdata *hwdata;
160
struct SDL_joylist_item *next;
161
162
bool checked_mapping;
163
SDL_GamepadMapping *mapping;
164
} SDL_joylist_item;
165
166
// A linked list of available gamepad sensors
167
typedef struct SDL_sensorlist_item
168
{
169
char *path; // "/dev/input/event2" or whatever
170
dev_t devnum;
171
struct joystick_hwdata *hwdata;
172
struct SDL_sensorlist_item *next;
173
} SDL_sensorlist_item;
174
175
static bool SDL_classic_joysticks = false;
176
static SDL_joylist_item *SDL_joylist SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
177
static SDL_joylist_item *SDL_joylist_tail SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
178
static int numjoysticks SDL_GUARDED_BY(SDL_joystick_lock) = 0;
179
static SDL_sensorlist_item *SDL_sensorlist SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
180
static int inotify_fd = -1;
181
182
static Uint64 last_joy_detect_time;
183
static time_t last_input_dir_mtime;
184
185
static void FixupDeviceInfoForMapping(int fd, struct input_id *inpid)
186
{
187
if (inpid->vendor == 0x045e && inpid->product == 0x0b05 && inpid->version == 0x0903) {
188
// This is a Microsoft Xbox One Elite Series 2 controller
189
unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
190
191
// The first version of the firmware duplicated all the inputs
192
if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
193
test_bit(0x2c0, keybit)) {
194
// Change the version to 0x0902, so we can map it differently
195
inpid->version = 0x0902;
196
}
197
}
198
199
/* For Atari vcs modern and classic controllers have the version reflecting
200
* firmware version, but the mapping stays stable so ignore
201
* version information */
202
if (inpid->vendor == 0x3250 && (inpid->product == 0x1001 || inpid->product == 0x1002)) {
203
inpid->version = 0;
204
}
205
}
206
207
#ifdef SDL_JOYSTICK_HIDAPI
208
static bool IsVirtualJoystick(Uint16 vendor, Uint16 product, Uint16 version, const char *name)
209
{
210
if (vendor == USB_VENDOR_MICROSOFT && product == USB_PRODUCT_XBOX_ONE_S && version == 0 &&
211
SDL_strcmp(name, "Xbox One S Controller") == 0) {
212
// This is the virtual device created by the xow driver
213
return true;
214
}
215
return false;
216
}
217
#else
218
static bool IsVirtualJoystick(Uint16 vendor, Uint16 product, Uint16 version, const char *name)
219
{
220
return false;
221
}
222
#endif // SDL_JOYSTICK_HIDAPI
223
224
static bool GetSteamVirtualGamepadSlot(int fd, int *slot)
225
{
226
char name[128];
227
228
if (ioctl(fd, EVIOCGNAME(sizeof(name)), name) > 0) {
229
const char *digits = SDL_strstr(name, "pad ");
230
if (digits) {
231
digits += 4;
232
if (SDL_isdigit(*digits)) {
233
*slot = SDL_atoi(digits);
234
return true;
235
}
236
}
237
}
238
return false;
239
}
240
241
static int GuessDeviceClass(int fd)
242
{
243
unsigned long propbit[NBITS(INPUT_PROP_MAX)] = { 0 };
244
unsigned long evbit[NBITS(EV_MAX)] = { 0 };
245
unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
246
unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
247
unsigned long relbit[NBITS(REL_MAX)] = { 0 };
248
249
if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
250
(ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
251
(ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) < 0) ||
252
(ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
253
return 0;
254
}
255
256
/* This is a newer feature, so it's allowed to fail - if so, then the
257
* device just doesn't have any properties. */
258
(void) ioctl(fd, EVIOCGPROP(sizeof(propbit)), propbit);
259
260
return SDL_EVDEV_GuessDeviceClass(propbit, evbit, absbit, keybit, relbit);
261
}
262
263
static bool GuessIsJoystick(int fd)
264
{
265
if (GuessDeviceClass(fd) & SDL_UDEV_DEVICE_JOYSTICK) {
266
return true;
267
}
268
return false;
269
}
270
271
static bool GuessIsSensor(int fd)
272
{
273
if (GuessDeviceClass(fd) & SDL_UDEV_DEVICE_ACCELEROMETER) {
274
return true;
275
}
276
return false;
277
}
278
279
static bool IsJoystick(const char *path, int *fd, char **name_return, Uint16 *vendor_return, Uint16 *product_return, SDL_GUID *guid)
280
{
281
struct input_id inpid;
282
char *name;
283
char product_string[128];
284
int class = 0;
285
286
SDL_zero(inpid);
287
#ifdef SDL_USE_LIBUDEV
288
// Opening input devices can generate synchronous device I/O, so avoid it if we can
289
if (SDL_UDEV_GetProductInfo(path, &inpid.vendor, &inpid.product, &inpid.version, &class) &&
290
!(class & SDL_UDEV_DEVICE_JOYSTICK)) {
291
return false;
292
}
293
#endif
294
295
if (fd && *fd < 0) {
296
*fd = open(path, O_RDONLY | O_CLOEXEC, 0);
297
}
298
if (!fd || *fd < 0) {
299
return false;
300
}
301
302
if (ioctl(*fd, JSIOCGNAME(sizeof(product_string)), product_string) <= 0) {
303
// When udev enumeration or classification, we only got joysticks here, so no need to test
304
if (enumeration_method != ENUMERATION_LIBUDEV && !class && !GuessIsJoystick(*fd)) {
305
return false;
306
}
307
308
// Could have vendor and product already from udev, but should agree with evdev
309
if (ioctl(*fd, EVIOCGID, &inpid) < 0) {
310
return false;
311
}
312
313
if (ioctl(*fd, EVIOCGNAME(sizeof(product_string)), product_string) < 0) {
314
return false;
315
}
316
}
317
318
name = SDL_CreateJoystickName(inpid.vendor, inpid.product, NULL, product_string);
319
if (!name) {
320
return false;
321
}
322
323
if (!IsVirtualJoystick(inpid.vendor, inpid.product, inpid.version, name) &&
324
SDL_JoystickHandledByAnotherDriver(&SDL_LINUX_JoystickDriver, inpid.vendor, inpid.product, inpid.version, name)) {
325
SDL_free(name);
326
return false;
327
}
328
329
FixupDeviceInfoForMapping(*fd, &inpid);
330
331
#ifdef DEBUG_JOYSTICK
332
SDL_Log("Joystick: %s, bustype = %d, vendor = 0x%.4x, product = 0x%.4x, version = %d", name, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
333
#endif
334
335
if (SDL_ShouldIgnoreJoystick(inpid.vendor, inpid.product, inpid.version, name)) {
336
SDL_free(name);
337
return false;
338
}
339
*name_return = name;
340
*vendor_return = inpid.vendor;
341
*product_return = inpid.product;
342
*guid = SDL_CreateJoystickGUID(inpid.bustype, inpid.vendor, inpid.product, inpid.version, NULL, product_string, 0, 0);
343
return true;
344
}
345
346
static bool IsSensor(const char *path, int *fd)
347
{
348
struct input_id inpid;
349
int class = 0;
350
351
SDL_zero(inpid);
352
#ifdef SDL_USE_LIBUDEV
353
// Opening input devices can generate synchronous device I/O, so avoid it if we can
354
if (SDL_UDEV_GetProductInfo(path, &inpid.vendor, &inpid.product, &inpid.version, &class) &&
355
!(class & SDL_UDEV_DEVICE_ACCELEROMETER)) {
356
return false;
357
}
358
#endif
359
360
if (fd && *fd < 0) {
361
*fd = open(path, O_RDONLY | O_CLOEXEC, 0);
362
}
363
if (!fd || *fd < 0) {
364
return false;
365
}
366
367
if (!class && !GuessIsSensor(*fd)) {
368
return false;
369
}
370
371
if (ioctl(*fd, EVIOCGID, &inpid) < 0) {
372
return false;
373
}
374
375
if (inpid.vendor == USB_VENDOR_NINTENDO && inpid.product == USB_PRODUCT_NINTENDO_WII_REMOTE) {
376
// Wii extension controls
377
// These may create 3 sensor devices but we only support reading from 1: ignore them
378
return false;
379
}
380
381
return true;
382
}
383
384
#ifdef SDL_USE_LIBUDEV
385
static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
386
{
387
if (!devpath) {
388
return;
389
}
390
391
switch (udev_type) {
392
case SDL_UDEV_DEVICEADDED:
393
if (!(udev_class & (SDL_UDEV_DEVICE_JOYSTICK | SDL_UDEV_DEVICE_ACCELEROMETER))) {
394
return;
395
}
396
if (SDL_classic_joysticks) {
397
if (!IsJoystickJSNode(devpath)) {
398
return;
399
}
400
} else {
401
if (IsJoystickJSNode(devpath)) {
402
return;
403
}
404
}
405
406
// Wait a bit for the hidraw udev node to initialize
407
SDL_Delay(10);
408
409
MaybeAddDevice(devpath);
410
break;
411
412
case SDL_UDEV_DEVICEREMOVED:
413
MaybeRemoveDevice(devpath);
414
break;
415
416
default:
417
break;
418
}
419
}
420
#endif // SDL_USE_LIBUDEV
421
422
static void FreeJoylistItem(SDL_joylist_item *item)
423
{
424
SDL_free(item->mapping);
425
SDL_free(item->path);
426
SDL_free(item->name);
427
SDL_free(item);
428
}
429
430
static void FreeSensorlistItem(SDL_sensorlist_item *item)
431
{
432
SDL_free(item->path);
433
SDL_free(item);
434
}
435
436
static void MaybeAddDevice(const char *path)
437
{
438
struct stat sb;
439
int fd = -1;
440
char *name = NULL;
441
Uint16 vendor, product;
442
SDL_GUID guid;
443
SDL_joylist_item *item;
444
SDL_sensorlist_item *item_sensor;
445
446
if (!path) {
447
return;
448
}
449
450
fd = open(path, O_RDONLY | O_CLOEXEC, 0);
451
if (fd < 0) {
452
return;
453
}
454
455
if (fstat(fd, &sb) == -1) {
456
close(fd);
457
return;
458
}
459
460
SDL_LockJoysticks();
461
462
// Check to make sure it's not already in list.
463
for (item = SDL_joylist; item; item = item->next) {
464
if (sb.st_rdev == item->devnum) {
465
goto done; // already have this one
466
}
467
}
468
for (item_sensor = SDL_sensorlist; item_sensor; item_sensor = item_sensor->next) {
469
if (sb.st_rdev == item_sensor->devnum) {
470
goto done; // already have this one
471
}
472
}
473
474
#ifdef DEBUG_INPUT_EVENTS
475
SDL_Log("Checking %s", path);
476
#endif
477
478
if (IsJoystick(path, &fd, &name, &vendor, &product, &guid)) {
479
#ifdef DEBUG_INPUT_EVENTS
480
SDL_Log("found joystick: %s", path);
481
#endif
482
item = (SDL_joylist_item *)SDL_calloc(1, sizeof(SDL_joylist_item));
483
if (!item) {
484
SDL_free(name);
485
goto done;
486
}
487
488
item->devnum = sb.st_rdev;
489
item->steam_virtual_gamepad_slot = -1;
490
item->path = SDL_strdup(path);
491
item->vendor = vendor;
492
item->product = product;
493
item->name = name;
494
item->guid = guid;
495
496
if (vendor == USB_VENDOR_VALVE &&
497
product == USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD) {
498
GetSteamVirtualGamepadSlot(fd, &item->steam_virtual_gamepad_slot);
499
}
500
501
if ((!item->path) || (!item->name)) {
502
FreeJoylistItem(item);
503
goto done;
504
}
505
506
item->device_instance = SDL_GetNextObjectID();
507
if (!SDL_joylist_tail) {
508
SDL_joylist = SDL_joylist_tail = item;
509
} else {
510
SDL_joylist_tail->next = item;
511
SDL_joylist_tail = item;
512
}
513
514
// Need to increment the joystick count before we post the event
515
++numjoysticks;
516
517
SDL_PrivateJoystickAdded(item->device_instance);
518
goto done;
519
}
520
521
if (IsSensor(path, &fd)) {
522
#ifdef DEBUG_INPUT_EVENTS
523
SDL_Log("found sensor: %s", path);
524
#endif
525
item_sensor = (SDL_sensorlist_item *)SDL_calloc(1, sizeof(SDL_sensorlist_item));
526
if (!item_sensor) {
527
goto done;
528
}
529
item_sensor->devnum = sb.st_rdev;
530
item_sensor->path = SDL_strdup(path);
531
532
if (!item_sensor->path) {
533
FreeSensorlistItem(item_sensor);
534
goto done;
535
}
536
537
item_sensor->next = SDL_sensorlist;
538
SDL_sensorlist = item_sensor;
539
goto done;
540
}
541
542
done:
543
close(fd);
544
SDL_UnlockJoysticks();
545
}
546
547
static void RemoveJoylistItem(SDL_joylist_item *item, SDL_joylist_item *prev)
548
{
549
SDL_AssertJoysticksLocked();
550
551
if (item->hwdata) {
552
item->hwdata->item = NULL;
553
}
554
555
if (prev) {
556
prev->next = item->next;
557
} else {
558
SDL_assert(SDL_joylist == item);
559
SDL_joylist = item->next;
560
}
561
562
if (item == SDL_joylist_tail) {
563
SDL_joylist_tail = prev;
564
}
565
566
// Need to decrement the joystick count before we post the event
567
--numjoysticks;
568
569
SDL_PrivateJoystickRemoved(item->device_instance);
570
FreeJoylistItem(item);
571
}
572
573
static void RemoveSensorlistItem(SDL_sensorlist_item *item, SDL_sensorlist_item *prev)
574
{
575
SDL_AssertJoysticksLocked();
576
577
if (item->hwdata) {
578
item->hwdata->item_sensor = NULL;
579
}
580
581
if (prev) {
582
prev->next = item->next;
583
} else {
584
SDL_assert(SDL_sensorlist == item);
585
SDL_sensorlist = item->next;
586
}
587
588
/* Do not call SDL_PrivateJoystickRemoved here as RemoveJoylistItem will do it,
589
* assuming both sensor and joy item are removed at the same time */
590
FreeSensorlistItem(item);
591
}
592
593
static void MaybeRemoveDevice(const char *path)
594
{
595
SDL_joylist_item *item;
596
SDL_joylist_item *prev = NULL;
597
SDL_sensorlist_item *item_sensor;
598
SDL_sensorlist_item *prev_sensor = NULL;
599
600
if (!path) {
601
return;
602
}
603
604
SDL_LockJoysticks();
605
for (item = SDL_joylist; item; item = item->next) {
606
// found it, remove it.
607
if (SDL_strcmp(path, item->path) == 0) {
608
RemoveJoylistItem(item, prev);
609
goto done;
610
}
611
prev = item;
612
}
613
for (item_sensor = SDL_sensorlist; item_sensor; item_sensor = item_sensor->next) {
614
// found it, remove it.
615
if (SDL_strcmp(path, item_sensor->path) == 0) {
616
RemoveSensorlistItem(item_sensor, prev_sensor);
617
goto done;
618
}
619
prev_sensor = item_sensor;
620
}
621
done:
622
SDL_UnlockJoysticks();
623
}
624
625
static void HandlePendingRemovals(void)
626
{
627
SDL_joylist_item *prev = NULL;
628
SDL_joylist_item *item = NULL;
629
SDL_sensorlist_item *prev_sensor = NULL;
630
SDL_sensorlist_item *item_sensor = NULL;
631
632
SDL_AssertJoysticksLocked();
633
634
item = SDL_joylist;
635
while (item) {
636
if (item->hwdata && item->hwdata->gone) {
637
RemoveJoylistItem(item, prev);
638
639
if (prev) {
640
item = prev->next;
641
} else {
642
item = SDL_joylist;
643
}
644
} else {
645
prev = item;
646
item = item->next;
647
}
648
}
649
650
item_sensor = SDL_sensorlist;
651
while (item_sensor) {
652
if (item_sensor->hwdata && item_sensor->hwdata->sensor_gone) {
653
RemoveSensorlistItem(item_sensor, prev_sensor);
654
655
if (prev_sensor) {
656
item_sensor = prev_sensor->next;
657
} else {
658
item_sensor = SDL_sensorlist;
659
}
660
} else {
661
prev_sensor = item_sensor;
662
item_sensor = item_sensor->next;
663
}
664
}
665
}
666
667
static bool StrIsInteger(const char *string)
668
{
669
const char *p;
670
671
if (*string == '\0') {
672
return false;
673
}
674
675
for (p = string; *p != '\0'; p++) {
676
if (*p < '0' || *p > '9') {
677
return false;
678
}
679
}
680
681
return true;
682
}
683
684
static bool IsJoystickJSNode(const char *node)
685
{
686
const char *last_slash = SDL_strrchr(node, '/');
687
if (last_slash) {
688
node = last_slash + 1;
689
}
690
return SDL_startswith(node, "js") && StrIsInteger(node + 2);
691
}
692
693
static bool IsJoystickEventNode(const char *node)
694
{
695
const char *last_slash = SDL_strrchr(node, '/');
696
if (last_slash) {
697
node = last_slash + 1;
698
}
699
return SDL_startswith(node, "event") && StrIsInteger(node + 5);
700
}
701
702
static bool IsJoystickDeviceNode(const char *node)
703
{
704
if (SDL_classic_joysticks) {
705
return IsJoystickJSNode(node);
706
} else {
707
return IsJoystickEventNode(node);
708
}
709
}
710
711
#ifdef HAVE_INOTIFY
712
#ifdef HAVE_INOTIFY_INIT1
713
static int SDL_inotify_init1(void)
714
{
715
return inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
716
}
717
#else
718
static int SDL_inotify_init1(void)
719
{
720
int fd = inotify_init();
721
if (fd < 0) {
722
return -1;
723
}
724
fcntl(fd, F_SETFL, O_NONBLOCK);
725
fcntl(fd, F_SETFD, FD_CLOEXEC);
726
return fd;
727
}
728
#endif
729
730
static void LINUX_InotifyJoystickDetect(void)
731
{
732
union
733
{
734
struct inotify_event event;
735
char storage[4096];
736
char enough_for_inotify[sizeof(struct inotify_event) + NAME_MAX + 1];
737
} buf;
738
ssize_t bytes;
739
size_t remain = 0;
740
size_t len;
741
char path[PATH_MAX];
742
743
bytes = read(inotify_fd, &buf, sizeof(buf));
744
745
if (bytes > 0) {
746
remain = (size_t)bytes;
747
}
748
749
while (remain > 0) {
750
if (buf.event.len > 0) {
751
if (IsJoystickDeviceNode(buf.event.name)) {
752
(void)SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", buf.event.name);
753
754
if (buf.event.mask & (IN_CREATE | IN_MOVED_TO | IN_ATTRIB)) {
755
MaybeAddDevice(path);
756
} else if (buf.event.mask & (IN_DELETE | IN_MOVED_FROM)) {
757
MaybeRemoveDevice(path);
758
}
759
}
760
}
761
762
len = sizeof(struct inotify_event) + buf.event.len;
763
remain -= len;
764
765
if (remain != 0) {
766
SDL_memmove(&buf.storage[0], &buf.storage[len], remain);
767
}
768
}
769
}
770
#endif // HAVE_INOTIFY
771
772
static int get_event_joystick_index(int event)
773
{
774
int joystick_index = -1;
775
int i, count;
776
struct dirent **entries = NULL;
777
char path[PATH_MAX];
778
779
(void)SDL_snprintf(path, SDL_arraysize(path), "/sys/class/input/event%d/device", event);
780
count = scandir(path, &entries, NULL, alphasort);
781
for (i = 0; i < count; ++i) {
782
if (SDL_strncmp(entries[i]->d_name, "js", 2) == 0) {
783
joystick_index = SDL_atoi(entries[i]->d_name + 2);
784
}
785
free(entries[i]); // This should NOT be SDL_free()
786
}
787
free(entries); // This should NOT be SDL_free()
788
789
return joystick_index;
790
}
791
792
/* Detect devices by reading /dev/input. In the inotify code path we
793
* have to do this the first time, to detect devices that already existed
794
* before we started; in the non-inotify code path we do this repeatedly
795
* (polling). */
796
static int filter_entries(const struct dirent *entry)
797
{
798
return IsJoystickDeviceNode(entry->d_name);
799
}
800
static int SDLCALL sort_entries(const void *_a, const void *_b)
801
{
802
const struct dirent **a = (const struct dirent **)_a;
803
const struct dirent **b = (const struct dirent **)_b;
804
int numA, numB;
805
int offset;
806
807
if (SDL_classic_joysticks) {
808
offset = 2; // strlen("js")
809
numA = SDL_atoi((*a)->d_name + offset);
810
numB = SDL_atoi((*b)->d_name + offset);
811
} else {
812
offset = 5; // strlen("event")
813
numA = SDL_atoi((*a)->d_name + offset);
814
numB = SDL_atoi((*b)->d_name + offset);
815
816
// See if we can get the joystick ordering
817
{
818
int jsA = get_event_joystick_index(numA);
819
int jsB = get_event_joystick_index(numB);
820
if (jsA >= 0 && jsB >= 0) {
821
numA = jsA;
822
numB = jsB;
823
} else if (jsA >= 0) {
824
return -1;
825
} else if (jsB >= 0) {
826
return 1;
827
}
828
}
829
}
830
return numA - numB;
831
}
832
833
typedef struct
834
{
835
char *path;
836
int slot;
837
} VirtualGamepadEntry;
838
839
static int SDLCALL sort_virtual_gamepads(const void *_a, const void *_b)
840
{
841
const VirtualGamepadEntry *a = (const VirtualGamepadEntry *)_a;
842
const VirtualGamepadEntry *b = (const VirtualGamepadEntry *)_b;
843
return a->slot - b->slot;
844
}
845
846
static void LINUX_ScanSteamVirtualGamepads(void)
847
{
848
int i, count;
849
int fd;
850
struct dirent **entries = NULL;
851
char path[PATH_MAX];
852
struct input_id inpid;
853
int num_virtual_gamepads = 0;
854
int virtual_gamepad_slot;
855
VirtualGamepadEntry *virtual_gamepads = NULL;
856
#ifdef SDL_USE_LIBUDEV
857
int class;
858
#endif
859
860
count = scandir("/dev/input", &entries, filter_entries, NULL);
861
for (i = 0; i < count; ++i) {
862
(void)SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", entries[i]->d_name);
863
864
#ifdef SDL_USE_LIBUDEV
865
// Opening input devices can generate synchronous device I/O, so avoid it if we can
866
class = 0;
867
SDL_zero(inpid);
868
if (SDL_UDEV_GetProductInfo(path, &inpid.vendor, &inpid.product, &inpid.version, &class) &&
869
(inpid.vendor != USB_VENDOR_VALVE || inpid.product != USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD)) {
870
free(entries[i]); // This should NOT be SDL_free()
871
continue;
872
}
873
#endif
874
fd = open(path, O_RDONLY | O_CLOEXEC, 0);
875
if (fd >= 0) {
876
if (ioctl(fd, EVIOCGID, &inpid) == 0 &&
877
inpid.vendor == USB_VENDOR_VALVE &&
878
inpid.product == USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD &&
879
GetSteamVirtualGamepadSlot(fd, &virtual_gamepad_slot)) {
880
VirtualGamepadEntry *new_virtual_gamepads = (VirtualGamepadEntry *)SDL_realloc(virtual_gamepads, (num_virtual_gamepads + 1) * sizeof(*virtual_gamepads));
881
if (new_virtual_gamepads) {
882
VirtualGamepadEntry *entry = &new_virtual_gamepads[num_virtual_gamepads];
883
entry->path = SDL_strdup(path);
884
entry->slot = virtual_gamepad_slot;
885
if (entry->path) {
886
virtual_gamepads = new_virtual_gamepads;
887
++num_virtual_gamepads;
888
} else {
889
SDL_free(entry->path);
890
SDL_free(new_virtual_gamepads);
891
}
892
}
893
}
894
close(fd);
895
}
896
free(entries[i]); // This should NOT be SDL_free()
897
}
898
free(entries); // This should NOT be SDL_free()
899
900
if (num_virtual_gamepads > 1) {
901
SDL_qsort(virtual_gamepads, num_virtual_gamepads, sizeof(*virtual_gamepads), sort_virtual_gamepads);
902
}
903
for (i = 0; i < num_virtual_gamepads; ++i) {
904
MaybeAddDevice(virtual_gamepads[i].path);
905
SDL_free(virtual_gamepads[i].path);
906
}
907
SDL_free(virtual_gamepads);
908
}
909
910
static void LINUX_ScanInputDevices(void)
911
{
912
int i, count;
913
struct dirent **entries = NULL;
914
char path[PATH_MAX];
915
916
count = scandir("/dev/input", &entries, filter_entries, NULL);
917
if (count > 1) {
918
SDL_qsort(entries, count, sizeof(*entries), sort_entries);
919
}
920
for (i = 0; i < count; ++i) {
921
(void)SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", entries[i]->d_name);
922
MaybeAddDevice(path);
923
924
free(entries[i]); // This should NOT be SDL_free()
925
}
926
free(entries); // This should NOT be SDL_free()
927
}
928
929
static void LINUX_FallbackJoystickDetect(void)
930
{
931
const Uint32 SDL_JOY_DETECT_INTERVAL_MS = 3000; // Update every 3 seconds
932
Uint64 now = SDL_GetTicks();
933
934
if (!last_joy_detect_time || now >= (last_joy_detect_time + SDL_JOY_DETECT_INTERVAL_MS)) {
935
struct stat sb;
936
937
// Opening input devices can generate synchronous device I/O, so avoid it if we can
938
if (stat("/dev/input", &sb) == 0 && sb.st_mtime != last_input_dir_mtime) {
939
// Look for Steam virtual gamepads first, and sort by Steam controller slot
940
LINUX_ScanSteamVirtualGamepads();
941
942
LINUX_ScanInputDevices();
943
944
last_input_dir_mtime = sb.st_mtime;
945
}
946
947
last_joy_detect_time = now;
948
}
949
}
950
951
static void LINUX_JoystickDetect(void)
952
{
953
#ifdef SDL_USE_LIBUDEV
954
if (enumeration_method == ENUMERATION_LIBUDEV) {
955
SDL_UDEV_Poll();
956
} else
957
#endif
958
#ifdef HAVE_INOTIFY
959
if (inotify_fd >= 0 && last_joy_detect_time != 0) {
960
LINUX_InotifyJoystickDetect();
961
} else
962
#endif
963
{
964
LINUX_FallbackJoystickDetect();
965
}
966
967
HandlePendingRemovals();
968
}
969
970
static bool LINUX_JoystickIsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name)
971
{
972
// We don't override any other drivers
973
return false;
974
}
975
976
static bool LINUX_JoystickInit(void)
977
{
978
const char *devices = SDL_GetHint(SDL_HINT_JOYSTICK_DEVICE);
979
#ifdef SDL_USE_LIBUDEV
980
bool udev_initialized = SDL_UDEV_Init();
981
#endif
982
983
SDL_classic_joysticks = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_LINUX_CLASSIC, false);
984
985
enumeration_method = ENUMERATION_UNSET;
986
987
// First see if the user specified one or more joysticks to use
988
if (devices) {
989
char *envcopy, *envpath, *delim;
990
envcopy = SDL_strdup(devices);
991
envpath = envcopy;
992
while (envpath) {
993
delim = SDL_strchr(envpath, ':');
994
if (delim) {
995
*delim++ = '\0';
996
}
997
MaybeAddDevice(envpath);
998
envpath = delim;
999
}
1000
SDL_free(envcopy);
1001
}
1002
1003
// Force immediate joystick detection if using fallback
1004
last_joy_detect_time = 0;
1005
last_input_dir_mtime = 0;
1006
1007
// Manually scan first, since we sort by device number and udev doesn't
1008
LINUX_JoystickDetect();
1009
1010
#ifdef SDL_USE_LIBUDEV
1011
if (enumeration_method == ENUMERATION_UNSET) {
1012
if (SDL_GetHintBoolean("SDL_JOYSTICK_DISABLE_UDEV", false)) {
1013
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
1014
"udev disabled by SDL_JOYSTICK_DISABLE_UDEV");
1015
enumeration_method = ENUMERATION_FALLBACK;
1016
} else if (SDL_GetSandbox() != SDL_SANDBOX_NONE) {
1017
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
1018
"Container detected, disabling udev integration");
1019
enumeration_method = ENUMERATION_FALLBACK;
1020
1021
} else {
1022
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
1023
"Using udev for joystick device discovery");
1024
enumeration_method = ENUMERATION_LIBUDEV;
1025
}
1026
}
1027
1028
if (enumeration_method == ENUMERATION_LIBUDEV) {
1029
if (udev_initialized) {
1030
// Set up the udev callback
1031
if (!SDL_UDEV_AddCallback(joystick_udev_callback)) {
1032
SDL_UDEV_Quit();
1033
return SDL_SetError("Could not set up joystick <-> udev callback");
1034
}
1035
1036
// Force a scan to build the initial device list
1037
SDL_UDEV_Scan();
1038
} else {
1039
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
1040
"udev init failed, disabling udev integration");
1041
enumeration_method = ENUMERATION_FALLBACK;
1042
}
1043
} else {
1044
if (udev_initialized) {
1045
SDL_UDEV_Quit();
1046
}
1047
}
1048
#endif
1049
1050
if (enumeration_method != ENUMERATION_LIBUDEV) {
1051
#ifdef HAVE_INOTIFY
1052
inotify_fd = SDL_inotify_init1();
1053
1054
if (inotify_fd < 0) {
1055
SDL_LogWarn(SDL_LOG_CATEGORY_INPUT,
1056
"Unable to initialize inotify, falling back to polling: %s",
1057
strerror(errno));
1058
} else {
1059
/* We need to watch for attribute changes in addition to
1060
* creation, because when a device is first created, it has
1061
* permissions that we can't read. When udev chmods it to
1062
* something that we maybe *can* read, we'll get an
1063
* IN_ATTRIB event to tell us. */
1064
if (inotify_add_watch(inotify_fd, "/dev/input",
1065
IN_CREATE | IN_DELETE | IN_MOVE | IN_ATTRIB) < 0) {
1066
close(inotify_fd);
1067
inotify_fd = -1;
1068
SDL_LogWarn(SDL_LOG_CATEGORY_INPUT,
1069
"Unable to add inotify watch, falling back to polling: %s",
1070
strerror(errno));
1071
}
1072
}
1073
#endif // HAVE_INOTIFY
1074
}
1075
1076
return true;
1077
}
1078
1079
static int LINUX_JoystickGetCount(void)
1080
{
1081
SDL_AssertJoysticksLocked();
1082
1083
return numjoysticks;
1084
}
1085
1086
static SDL_joylist_item *GetJoystickByDevIndex(int device_index)
1087
{
1088
SDL_joylist_item *item;
1089
1090
SDL_AssertJoysticksLocked();
1091
1092
if ((device_index < 0) || (device_index >= numjoysticks)) {
1093
return NULL;
1094
}
1095
1096
item = SDL_joylist;
1097
while (device_index > 0) {
1098
SDL_assert(item != NULL);
1099
device_index--;
1100
item = item->next;
1101
}
1102
1103
return item;
1104
}
1105
1106
static const char *LINUX_JoystickGetDeviceName(int device_index)
1107
{
1108
return GetJoystickByDevIndex(device_index)->name;
1109
}
1110
1111
static const char *LINUX_JoystickGetDevicePath(int device_index)
1112
{
1113
return GetJoystickByDevIndex(device_index)->path;
1114
}
1115
1116
static int LINUX_JoystickGetDeviceSteamVirtualGamepadSlot(int device_index)
1117
{
1118
return GetJoystickByDevIndex(device_index)->steam_virtual_gamepad_slot;
1119
}
1120
1121
static int LINUX_JoystickGetDevicePlayerIndex(int device_index)
1122
{
1123
return -1;
1124
}
1125
1126
static void LINUX_JoystickSetDevicePlayerIndex(int device_index, int player_index)
1127
{
1128
}
1129
1130
static SDL_GUID LINUX_JoystickGetDeviceGUID(int device_index)
1131
{
1132
return GetJoystickByDevIndex(device_index)->guid;
1133
}
1134
1135
// Function to perform the mapping from device index to the instance id for this index
1136
static SDL_JoystickID LINUX_JoystickGetDeviceInstanceID(int device_index)
1137
{
1138
return GetJoystickByDevIndex(device_index)->device_instance;
1139
}
1140
1141
static bool allocate_balldata(SDL_Joystick *joystick)
1142
{
1143
joystick->hwdata->balls =
1144
(struct hwdata_ball *)SDL_calloc(joystick->nballs, sizeof(struct hwdata_ball));
1145
if (joystick->hwdata->balls == NULL) {
1146
return false;
1147
}
1148
return true;
1149
}
1150
1151
static bool allocate_hatdata(SDL_Joystick *joystick)
1152
{
1153
int i;
1154
1155
SDL_AssertJoysticksLocked();
1156
1157
joystick->hwdata->hats =
1158
(struct hwdata_hat *)SDL_malloc(joystick->nhats *
1159
sizeof(struct hwdata_hat));
1160
if (!joystick->hwdata->hats) {
1161
return false;
1162
}
1163
for (i = 0; i < joystick->nhats; ++i) {
1164
joystick->hwdata->hats[i].axis[0] = 1;
1165
joystick->hwdata->hats[i].axis[1] = 1;
1166
}
1167
return true;
1168
}
1169
1170
static bool GuessIfAxesAreDigitalHat(struct input_absinfo *absinfo_x, struct input_absinfo *absinfo_y)
1171
{
1172
/* A "hat" is assumed to be a digital input with at most 9 possible states
1173
* (3 per axis: negative/zero/positive), as opposed to a true "axis" which
1174
* can report a continuous range of possible values. Unfortunately the Linux
1175
* joystick interface makes no distinction between digital hat axes and any
1176
* other continuous analog axis, so we have to guess. */
1177
1178
// If both axes are missing, they're not anything.
1179
if (!absinfo_x && !absinfo_y) {
1180
return false;
1181
}
1182
1183
// If the hint says so, treat all hats as digital.
1184
if (SDL_GetHintBoolean(SDL_HINT_JOYSTICK_LINUX_DIGITAL_HATS, false)) {
1185
return true;
1186
}
1187
1188
// If both axes have ranges constrained between -1 and 1, they're definitely digital.
1189
if ((!absinfo_x || (absinfo_x->minimum == -1 && absinfo_x->maximum == 1)) && (!absinfo_y || (absinfo_y->minimum == -1 && absinfo_y->maximum == 1))) {
1190
return true;
1191
}
1192
1193
// If both axes lack fuzz, flat, and resolution values, they're probably digital.
1194
if ((!absinfo_x || (!absinfo_x->fuzz && !absinfo_x->flat && !absinfo_x->resolution)) && (!absinfo_y || (!absinfo_y->fuzz && !absinfo_y->flat && !absinfo_y->resolution))) {
1195
return true;
1196
}
1197
1198
// Otherwise, treat them as analog.
1199
return false;
1200
}
1201
1202
static void ConfigJoystick(SDL_Joystick *joystick, int fd, int fd_sensor)
1203
{
1204
int i, t;
1205
unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
1206
unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
1207
unsigned long relbit[NBITS(REL_MAX)] = { 0 };
1208
unsigned long ffbit[NBITS(FF_MAX)] = { 0 };
1209
Uint8 key_pam_size, abs_pam_size;
1210
bool use_deadzones = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_LINUX_DEADZONES, false);
1211
bool use_hat_deadzones = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_LINUX_HAT_DEADZONES, true);
1212
1213
SDL_AssertJoysticksLocked();
1214
1215
// See if this device uses the new unified event API
1216
if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
1217
(ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
1218
(ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) {
1219
1220
// Get the number of buttons, axes, and other thingamajigs
1221
for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
1222
if (test_bit(i, keybit)) {
1223
#ifdef DEBUG_INPUT_EVENTS
1224
SDL_Log("Joystick has button: 0x%x", i);
1225
#endif
1226
joystick->hwdata->key_map[i] = joystick->nbuttons;
1227
joystick->hwdata->has_key[i] = true;
1228
++joystick->nbuttons;
1229
}
1230
}
1231
for (i = 0; i < BTN_JOYSTICK; ++i) {
1232
if (test_bit(i, keybit)) {
1233
#ifdef DEBUG_INPUT_EVENTS
1234
SDL_Log("Joystick has button: 0x%x", i);
1235
#endif
1236
joystick->hwdata->key_map[i] = joystick->nbuttons;
1237
joystick->hwdata->has_key[i] = true;
1238
++joystick->nbuttons;
1239
}
1240
}
1241
for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
1242
int hat_x = -1;
1243
int hat_y = -1;
1244
struct input_absinfo absinfo_x;
1245
struct input_absinfo absinfo_y;
1246
if (test_bit(i, absbit)) {
1247
hat_x = ioctl(fd, EVIOCGABS(i), &absinfo_x);
1248
}
1249
if (test_bit(i + 1, absbit)) {
1250
hat_y = ioctl(fd, EVIOCGABS(i + 1), &absinfo_y);
1251
}
1252
if (GuessIfAxesAreDigitalHat((hat_x < 0 ? (void *)0 : &absinfo_x),
1253
(hat_y < 0 ? (void *)0 : &absinfo_y))) {
1254
const int hat_index = (i - ABS_HAT0X) / 2;
1255
struct hat_axis_correct *correct = &joystick->hwdata->hat_correct[hat_index];
1256
#ifdef DEBUG_INPUT_EVENTS
1257
SDL_Log("Joystick has digital hat: #%d", hat_index);
1258
if (hat_x >= 0) {
1259
SDL_Log("X Values = { val:%d, min:%d, max:%d, fuzz:%d, flat:%d, res:%d }",
1260
absinfo_x.value, absinfo_x.minimum, absinfo_x.maximum,
1261
absinfo_x.fuzz, absinfo_x.flat, absinfo_x.resolution);
1262
}
1263
if (hat_y >= 0) {
1264
SDL_Log("Y Values = { val:%d, min:%d, max:%d, fuzz:%d, flat:%d, res:%d }",
1265
absinfo_y.value, absinfo_y.minimum, absinfo_y.maximum,
1266
absinfo_y.fuzz, absinfo_y.flat, absinfo_y.resolution);
1267
}
1268
#endif // DEBUG_INPUT_EVENTS
1269
joystick->hwdata->hats_indices[hat_index] = joystick->nhats;
1270
joystick->hwdata->has_hat[hat_index] = true;
1271
correct->use_deadzones = use_hat_deadzones;
1272
correct->minimum[0] = (hat_x < 0) ? -1 : absinfo_x.minimum;
1273
correct->maximum[0] = (hat_x < 0) ? 1 : absinfo_x.maximum;
1274
correct->minimum[1] = (hat_y < 0) ? -1 : absinfo_y.minimum;
1275
correct->maximum[1] = (hat_y < 0) ? 1 : absinfo_y.maximum;
1276
++joystick->nhats;
1277
}
1278
}
1279
for (i = 0; i < ABS_MAX; ++i) {
1280
// Skip digital hats
1281
if (i >= ABS_HAT0X && i <= ABS_HAT3Y && joystick->hwdata->has_hat[(i - ABS_HAT0X) / 2]) {
1282
continue;
1283
}
1284
if (test_bit(i, absbit)) {
1285
struct input_absinfo absinfo;
1286
struct axis_correct *correct = &joystick->hwdata->abs_correct[i];
1287
1288
if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
1289
continue;
1290
}
1291
#ifdef DEBUG_INPUT_EVENTS
1292
SDL_Log("Joystick has absolute axis: 0x%.2x", i);
1293
SDL_Log("Values = { val:%d, min:%d, max:%d, fuzz:%d, flat:%d, res:%d }",
1294
absinfo.value, absinfo.minimum, absinfo.maximum,
1295
absinfo.fuzz, absinfo.flat, absinfo.resolution);
1296
#endif // DEBUG_INPUT_EVENTS
1297
joystick->hwdata->abs_map[i] = joystick->naxes;
1298
joystick->hwdata->has_abs[i] = true;
1299
1300
correct->minimum = absinfo.minimum;
1301
correct->maximum = absinfo.maximum;
1302
if (correct->minimum != correct->maximum) {
1303
if (use_deadzones) {
1304
correct->use_deadzones = true;
1305
correct->coef[0] = (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
1306
correct->coef[1] = (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
1307
t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
1308
if (t != 0) {
1309
correct->coef[2] = (1 << 28) / t;
1310
} else {
1311
correct->coef[2] = 0;
1312
}
1313
} else {
1314
float value_range = (correct->maximum - correct->minimum);
1315
float output_range = (SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN);
1316
1317
correct->scale = (output_range / value_range);
1318
}
1319
}
1320
++joystick->naxes;
1321
}
1322
}
1323
if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
1324
++joystick->nballs;
1325
}
1326
1327
} else if ((ioctl(fd, JSIOCGBUTTONS, &key_pam_size, sizeof(key_pam_size)) >= 0) &&
1328
(ioctl(fd, JSIOCGAXES, &abs_pam_size, sizeof(abs_pam_size)) >= 0)) {
1329
size_t len;
1330
1331
joystick->hwdata->classic = true;
1332
1333
len = (KEY_MAX - BTN_MISC + 1) * sizeof(*joystick->hwdata->key_pam);
1334
joystick->hwdata->key_pam = (Uint16 *)SDL_calloc(1, len);
1335
if (joystick->hwdata->key_pam) {
1336
if (ioctl(fd, JSIOCGBTNMAP, joystick->hwdata->key_pam, len) < 0) {
1337
SDL_free(joystick->hwdata->key_pam);
1338
joystick->hwdata->key_pam = NULL;
1339
key_pam_size = 0;
1340
}
1341
} else {
1342
key_pam_size = 0;
1343
}
1344
for (i = 0; i < key_pam_size; ++i) {
1345
Uint16 code = joystick->hwdata->key_pam[i];
1346
#ifdef DEBUG_INPUT_EVENTS
1347
SDL_Log("Joystick has button: 0x%x", code);
1348
#endif
1349
joystick->hwdata->key_map[code] = joystick->nbuttons;
1350
joystick->hwdata->has_key[code] = true;
1351
++joystick->nbuttons;
1352
}
1353
1354
len = ABS_CNT * sizeof(*joystick->hwdata->abs_pam);
1355
joystick->hwdata->abs_pam = (Uint8 *)SDL_calloc(1, len);
1356
if (joystick->hwdata->abs_pam) {
1357
if (ioctl(fd, JSIOCGAXMAP, joystick->hwdata->abs_pam, len) < 0) {
1358
SDL_free(joystick->hwdata->abs_pam);
1359
joystick->hwdata->abs_pam = NULL;
1360
abs_pam_size = 0;
1361
}
1362
} else {
1363
abs_pam_size = 0;
1364
}
1365
for (i = 0; i < abs_pam_size; ++i) {
1366
Uint8 code = joystick->hwdata->abs_pam[i];
1367
1368
// TODO: is there any way to detect analog hats in advance via this API?
1369
if (code >= ABS_HAT0X && code <= ABS_HAT3Y) {
1370
int hat_index = (code - ABS_HAT0X) / 2;
1371
if (!joystick->hwdata->has_hat[hat_index]) {
1372
#ifdef DEBUG_INPUT_EVENTS
1373
SDL_Log("Joystick has digital hat: #%d", hat_index);
1374
#endif
1375
joystick->hwdata->hats_indices[hat_index] = joystick->nhats++;
1376
joystick->hwdata->has_hat[hat_index] = true;
1377
joystick->hwdata->hat_correct[hat_index].minimum[0] = -1;
1378
joystick->hwdata->hat_correct[hat_index].maximum[0] = 1;
1379
joystick->hwdata->hat_correct[hat_index].minimum[1] = -1;
1380
joystick->hwdata->hat_correct[hat_index].maximum[1] = 1;
1381
}
1382
} else {
1383
#ifdef DEBUG_INPUT_EVENTS
1384
SDL_Log("Joystick has absolute axis: 0x%.2x", code);
1385
#endif
1386
joystick->hwdata->abs_map[code] = joystick->naxes;
1387
joystick->hwdata->has_abs[code] = true;
1388
++joystick->naxes;
1389
}
1390
}
1391
}
1392
1393
// Sensors are only available through the new unified event API
1394
if (fd_sensor >= 0 && (ioctl(fd_sensor, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0)) {
1395
if (test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit) && test_bit(ABS_Z, absbit)) {
1396
joystick->hwdata->has_accelerometer = true;
1397
for (i = 0; i < 3; ++i) {
1398
struct input_absinfo absinfo;
1399
if (ioctl(fd_sensor, EVIOCGABS(ABS_X + i), &absinfo) < 0) {
1400
joystick->hwdata->has_accelerometer = false;
1401
break; // do not report an accelerometer if we can't read all axes
1402
}
1403
joystick->hwdata->accelerometer_scale[i] = absinfo.resolution;
1404
#ifdef DEBUG_INPUT_EVENTS
1405
SDL_Log("Joystick has accelerometer axis: 0x%.2x", ABS_X + i);
1406
SDL_Log("Values = { val:%d, min:%d, max:%d, fuzz:%d, flat:%d, res:%d }",
1407
absinfo.value, absinfo.minimum, absinfo.maximum,
1408
absinfo.fuzz, absinfo.flat, absinfo.resolution);
1409
#endif // DEBUG_INPUT_EVENTS
1410
}
1411
}
1412
1413
if (test_bit(ABS_RX, absbit) && test_bit(ABS_RY, absbit) && test_bit(ABS_RZ, absbit)) {
1414
joystick->hwdata->has_gyro = true;
1415
for (i = 0; i < 3; ++i) {
1416
struct input_absinfo absinfo;
1417
if (ioctl(fd_sensor, EVIOCGABS(ABS_RX + i), &absinfo) < 0) {
1418
joystick->hwdata->has_gyro = false;
1419
break; // do not report a gyro if we can't read all axes
1420
}
1421
joystick->hwdata->gyro_scale[i] = absinfo.resolution;
1422
#ifdef DEBUG_INPUT_EVENTS
1423
SDL_Log("Joystick has gyro axis: 0x%.2x", ABS_RX + i);
1424
SDL_Log("Values = { val:%d, min:%d, max:%d, fuzz:%d, flat:%d, res:%d }",
1425
absinfo.value, absinfo.minimum, absinfo.maximum,
1426
absinfo.fuzz, absinfo.flat, absinfo.resolution);
1427
#endif // DEBUG_INPUT_EVENTS
1428
}
1429
}
1430
}
1431
1432
// Allocate data to keep track of these thingamajigs
1433
if (joystick->nballs > 0) {
1434
if (!allocate_balldata(joystick)) {
1435
joystick->nballs = 0;
1436
}
1437
}
1438
if (joystick->nhats > 0) {
1439
if (!allocate_hatdata(joystick)) {
1440
joystick->nhats = 0;
1441
}
1442
}
1443
1444
if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) >= 0) {
1445
if (test_bit(FF_RUMBLE, ffbit)) {
1446
joystick->hwdata->ff_rumble = true;
1447
}
1448
if (test_bit(FF_SINE, ffbit)) {
1449
joystick->hwdata->ff_sine = true;
1450
}
1451
}
1452
}
1453
1454
/* This is used to do the heavy lifting for LINUX_JoystickOpen and
1455
also LINUX_JoystickGetGamepadMapping, so we can query the hardware
1456
without adding an opened SDL_Joystick object to the system.
1457
This expects `joystick->hwdata` to be allocated and will not free it
1458
on error. Returns -1 on error, 0 on success. */
1459
static bool PrepareJoystickHwdata(SDL_Joystick *joystick, SDL_joylist_item *item, SDL_sensorlist_item *item_sensor)
1460
{
1461
SDL_AssertJoysticksLocked();
1462
1463
joystick->hwdata->item = item;
1464
joystick->hwdata->item_sensor = item_sensor;
1465
joystick->hwdata->guid = item->guid;
1466
joystick->hwdata->effect.id = -1;
1467
SDL_memset(joystick->hwdata->key_map, 0xFF, sizeof(joystick->hwdata->key_map));
1468
SDL_memset(joystick->hwdata->abs_map, 0xFF, sizeof(joystick->hwdata->abs_map));
1469
1470
int fd = -1, fd_sensor = -1;
1471
// Try read-write first, so we can do rumble
1472
fd = open(item->path, O_RDWR | O_CLOEXEC, 0);
1473
if (fd < 0) {
1474
// Try read-only again, at least we'll get events in this case
1475
fd = open(item->path, O_RDONLY | O_CLOEXEC, 0);
1476
}
1477
if (fd < 0) {
1478
return SDL_SetError("Unable to open %s", item->path);
1479
}
1480
// If opening sensor fail, continue with buttons and axes only
1481
if (item_sensor) {
1482
fd_sensor = open(item_sensor->path, O_RDONLY | O_CLOEXEC, 0);
1483
}
1484
1485
joystick->hwdata->fd = fd;
1486
joystick->hwdata->fd_sensor = fd_sensor;
1487
joystick->hwdata->fname = SDL_strdup(item->path);
1488
if (!joystick->hwdata->fname) {
1489
close(fd);
1490
if (fd_sensor >= 0) {
1491
close(fd_sensor);
1492
}
1493
return false;
1494
}
1495
1496
// Set the joystick to non-blocking read mode
1497
fcntl(fd, F_SETFL, O_NONBLOCK);
1498
if (fd_sensor >= 0) {
1499
fcntl(fd_sensor, F_SETFL, O_NONBLOCK);
1500
}
1501
1502
// Get the number of buttons and axes on the joystick
1503
ConfigJoystick(joystick, fd, fd_sensor);
1504
return true;
1505
}
1506
1507
static SDL_sensorlist_item *GetSensor(SDL_joylist_item *item)
1508
{
1509
SDL_sensorlist_item *item_sensor;
1510
char uniq_item[128];
1511
int fd_item = -1;
1512
1513
SDL_AssertJoysticksLocked();
1514
1515
if (!item || !SDL_sensorlist) {
1516
return NULL;
1517
}
1518
1519
SDL_memset(uniq_item, 0, sizeof(uniq_item));
1520
fd_item = open(item->path, O_RDONLY | O_CLOEXEC, 0);
1521
if (fd_item < 0) {
1522
return NULL;
1523
}
1524
if (ioctl(fd_item, EVIOCGUNIQ(sizeof(uniq_item) - 1), &uniq_item) < 0) {
1525
close(fd_item);
1526
return NULL;
1527
}
1528
close(fd_item);
1529
#ifdef DEBUG_INPUT_EVENTS
1530
SDL_Log("Joystick UNIQ: %s", uniq_item);
1531
#endif // DEBUG_INPUT_EVENTS
1532
1533
for (item_sensor = SDL_sensorlist; item_sensor; item_sensor = item_sensor->next) {
1534
char uniq_sensor[128];
1535
int fd_sensor = -1;
1536
if (item_sensor->hwdata) {
1537
// already associated with another joystick
1538
continue;
1539
}
1540
1541
SDL_memset(uniq_sensor, 0, sizeof(uniq_sensor));
1542
fd_sensor = open(item_sensor->path, O_RDONLY | O_CLOEXEC, 0);
1543
if (fd_sensor < 0) {
1544
continue;
1545
}
1546
if (ioctl(fd_sensor, EVIOCGUNIQ(sizeof(uniq_sensor) - 1), &uniq_sensor) < 0) {
1547
close(fd_sensor);
1548
continue;
1549
}
1550
close(fd_sensor);
1551
#ifdef DEBUG_INPUT_EVENTS
1552
SDL_Log("Sensor UNIQ: %s", uniq_sensor);
1553
#endif // DEBUG_INPUT_EVENTS
1554
1555
if (SDL_strcmp(uniq_item, uniq_sensor) == 0) {
1556
return item_sensor;
1557
}
1558
}
1559
return NULL;
1560
}
1561
1562
static bool LINUX_JoystickOpen(SDL_Joystick *joystick, int device_index)
1563
{
1564
SDL_joylist_item *item;
1565
SDL_sensorlist_item *item_sensor;
1566
1567
SDL_AssertJoysticksLocked();
1568
1569
item = GetJoystickByDevIndex(device_index);
1570
if (!item) {
1571
return SDL_SetError("No such device");
1572
}
1573
1574
joystick->hwdata = (struct joystick_hwdata *)
1575
SDL_calloc(1, sizeof(*joystick->hwdata));
1576
if (!joystick->hwdata) {
1577
return false;
1578
}
1579
1580
item_sensor = GetSensor(item);
1581
if (!PrepareJoystickHwdata(joystick, item, item_sensor)) {
1582
SDL_free(joystick->hwdata);
1583
joystick->hwdata = NULL;
1584
return false; // SDL_SetError will already have been called
1585
}
1586
1587
SDL_assert(item->hwdata == NULL);
1588
SDL_assert(!item_sensor || item_sensor->hwdata == NULL);
1589
item->hwdata = joystick->hwdata;
1590
if (item_sensor) {
1591
item_sensor->hwdata = joystick->hwdata;
1592
}
1593
1594
#ifdef SDL_USE_LIBUDEV
1595
const char *serial = NULL;
1596
if (SDL_UDEV_GetProductSerial(item->path, &serial)) {
1597
joystick->serial = SDL_strdup(serial);
1598
}
1599
#endif
1600
1601
// mark joystick as fresh and ready
1602
joystick->hwdata->fresh = true;
1603
1604
if (joystick->hwdata->has_gyro) {
1605
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 0.0f);
1606
}
1607
if (joystick->hwdata->has_accelerometer) {
1608
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 0.0f);
1609
}
1610
if (joystick->hwdata->fd_sensor >= 0) {
1611
// Don't keep fd_sensor opened while sensor is disabled
1612
close(joystick->hwdata->fd_sensor);
1613
joystick->hwdata->fd_sensor = -1;
1614
}
1615
1616
if (joystick->hwdata->ff_rumble || joystick->hwdata->ff_sine) {
1617
SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true);
1618
}
1619
return true;
1620
}
1621
1622
static bool LINUX_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
1623
{
1624
struct input_event event;
1625
1626
SDL_AssertJoysticksLocked();
1627
1628
if (joystick->hwdata->ff_rumble) {
1629
struct ff_effect *effect = &joystick->hwdata->effect;
1630
1631
effect->type = FF_RUMBLE;
1632
effect->replay.length = SDL_MAX_RUMBLE_DURATION_MS;
1633
effect->u.rumble.strong_magnitude = low_frequency_rumble;
1634
effect->u.rumble.weak_magnitude = high_frequency_rumble;
1635
} else if (joystick->hwdata->ff_sine) {
1636
// Scale and average the two rumble strengths
1637
Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
1638
struct ff_effect *effect = &joystick->hwdata->effect;
1639
1640
effect->type = FF_PERIODIC;
1641
effect->replay.length = SDL_MAX_RUMBLE_DURATION_MS;
1642
effect->u.periodic.waveform = FF_SINE;
1643
effect->u.periodic.magnitude = magnitude;
1644
} else {
1645
return SDL_Unsupported();
1646
}
1647
1648
if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
1649
// The kernel may have lost this effect, try to allocate a new one
1650
joystick->hwdata->effect.id = -1;
1651
if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
1652
return SDL_SetError("Couldn't update rumble effect: %s", strerror(errno));
1653
}
1654
}
1655
1656
event.type = EV_FF;
1657
event.code = joystick->hwdata->effect.id;
1658
event.value = 1;
1659
if (write(joystick->hwdata->fd, &event, sizeof(event)) < 0) {
1660
return SDL_SetError("Couldn't start rumble effect: %s", strerror(errno));
1661
}
1662
return true;
1663
}
1664
1665
static bool LINUX_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
1666
{
1667
return SDL_Unsupported();
1668
}
1669
1670
static bool LINUX_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
1671
{
1672
return SDL_Unsupported();
1673
}
1674
1675
static bool LINUX_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
1676
{
1677
return SDL_Unsupported();
1678
}
1679
1680
static bool LINUX_JoystickSetSensorsEnabled(SDL_Joystick *joystick, bool enabled)
1681
{
1682
SDL_AssertJoysticksLocked();
1683
1684
if (!joystick->hwdata->has_accelerometer && !joystick->hwdata->has_gyro) {
1685
return SDL_Unsupported();
1686
}
1687
if (enabled == joystick->hwdata->report_sensor) {
1688
return true;
1689
}
1690
1691
if (enabled) {
1692
if (!joystick->hwdata->item_sensor) {
1693
return SDL_SetError("Sensors unplugged.");
1694
}
1695
joystick->hwdata->fd_sensor = open(joystick->hwdata->item_sensor->path, O_RDONLY | O_CLOEXEC, 0);
1696
if (joystick->hwdata->fd_sensor < 0) {
1697
return SDL_SetError("Couldn't open sensor file %s.", joystick->hwdata->item_sensor->path);
1698
}
1699
fcntl(joystick->hwdata->fd_sensor, F_SETFL, O_NONBLOCK);
1700
} else {
1701
SDL_assert(joystick->hwdata->fd_sensor >= 0);
1702
close(joystick->hwdata->fd_sensor);
1703
joystick->hwdata->fd_sensor = -1;
1704
}
1705
1706
joystick->hwdata->report_sensor = enabled;
1707
return true;
1708
}
1709
1710
static void HandleHat(Uint64 timestamp, SDL_Joystick *stick, int hatidx, int axis, int value)
1711
{
1712
int hatnum;
1713
struct hwdata_hat *the_hat;
1714
struct hat_axis_correct *correct;
1715
const Uint8 position_map[3][3] = {
1716
{ SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP },
1717
{ SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT },
1718
{ SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN }
1719
};
1720
1721
SDL_AssertJoysticksLocked();
1722
1723
hatnum = stick->hwdata->hats_indices[hatidx];
1724
the_hat = &stick->hwdata->hats[hatnum];
1725
correct = &stick->hwdata->hat_correct[hatidx];
1726
/* Hopefully we detected any analog axes and left them as is rather than trying
1727
* to use them as digital hats, but just in case, the deadzones here will
1728
* prevent the slightest of twitches on an analog axis from registering as a hat
1729
* movement. If the axes really are digital, this won't hurt since they should
1730
* only ever be sending min, 0, or max anyway. */
1731
if (value < 0) {
1732
if (value <= correct->minimum[axis]) {
1733
correct->minimum[axis] = value;
1734
value = 0;
1735
} else if (!correct->use_deadzones || value < correct->minimum[axis] / 3) {
1736
value = 0;
1737
} else {
1738
value = 1;
1739
}
1740
} else if (value > 0) {
1741
if (value >= correct->maximum[axis]) {
1742
correct->maximum[axis] = value;
1743
value = 2;
1744
} else if (!correct->use_deadzones || value > correct->maximum[axis] / 3) {
1745
value = 2;
1746
} else {
1747
value = 1;
1748
}
1749
} else { // value == 0
1750
value = 1;
1751
}
1752
if (value != the_hat->axis[axis]) {
1753
the_hat->axis[axis] = value;
1754
SDL_SendJoystickHat(timestamp, stick, hatnum,
1755
position_map[the_hat->axis[1]][the_hat->axis[0]]);
1756
}
1757
}
1758
1759
static void HandleBall(SDL_Joystick *stick, Uint8 ball, int axis, int value)
1760
{
1761
stick->hwdata->balls[ball].axis[axis] += value;
1762
}
1763
1764
static int AxisCorrect(SDL_Joystick *joystick, int which, int value)
1765
{
1766
struct axis_correct *correct;
1767
1768
SDL_AssertJoysticksLocked();
1769
1770
correct = &joystick->hwdata->abs_correct[which];
1771
if (correct->minimum != correct->maximum) {
1772
if (correct->use_deadzones) {
1773
value *= 2;
1774
if (value > correct->coef[0]) {
1775
if (value < correct->coef[1]) {
1776
return 0;
1777
}
1778
value -= correct->coef[1];
1779
} else {
1780
value -= correct->coef[0];
1781
}
1782
value *= correct->coef[2];
1783
value >>= 13;
1784
} else {
1785
value = (int)SDL_floorf((value - correct->minimum) * correct->scale + SDL_JOYSTICK_AXIS_MIN + 0.5f);
1786
}
1787
}
1788
1789
// Clamp and return
1790
if (value < SDL_JOYSTICK_AXIS_MIN) {
1791
return SDL_JOYSTICK_AXIS_MIN;
1792
}
1793
if (value > SDL_JOYSTICK_AXIS_MAX) {
1794
return SDL_JOYSTICK_AXIS_MAX;
1795
}
1796
return value;
1797
}
1798
1799
static void PollAllValues(Uint64 timestamp, SDL_Joystick *joystick)
1800
{
1801
struct input_absinfo absinfo;
1802
unsigned long keyinfo[NBITS(KEY_MAX)];
1803
int i;
1804
1805
SDL_AssertJoysticksLocked();
1806
1807
// Poll all axis
1808
for (i = ABS_X; i < ABS_MAX; i++) {
1809
// We don't need to test for digital hats here, they won't have has_abs[] set
1810
if (joystick->hwdata->has_abs[i]) {
1811
if (ioctl(joystick->hwdata->fd, EVIOCGABS(i), &absinfo) >= 0) {
1812
absinfo.value = AxisCorrect(joystick, i, absinfo.value);
1813
1814
#ifdef DEBUG_INPUT_EVENTS
1815
SDL_Log("Joystick : Re-read Axis %d (%d) val= %d",
1816
joystick->hwdata->abs_map[i], i, absinfo.value);
1817
#endif
1818
SDL_SendJoystickAxis(timestamp, joystick,
1819
joystick->hwdata->abs_map[i],
1820
absinfo.value);
1821
}
1822
}
1823
}
1824
1825
// Poll all digital hats
1826
for (i = ABS_HAT0X; i <= ABS_HAT3Y; i++) {
1827
const int baseaxis = i - ABS_HAT0X;
1828
const int hatidx = baseaxis / 2;
1829
SDL_assert(hatidx < SDL_arraysize(joystick->hwdata->has_hat));
1830
// We don't need to test for analog axes here, they won't have has_hat[] set
1831
if (joystick->hwdata->has_hat[hatidx]) {
1832
if (ioctl(joystick->hwdata->fd, EVIOCGABS(i), &absinfo) >= 0) {
1833
const int hataxis = baseaxis % 2;
1834
HandleHat(timestamp, joystick, hatidx, hataxis, absinfo.value);
1835
}
1836
}
1837
}
1838
1839
// Poll all buttons
1840
SDL_zeroa(keyinfo);
1841
if (ioctl(joystick->hwdata->fd, EVIOCGKEY(sizeof(keyinfo)), keyinfo) >= 0) {
1842
for (i = 0; i < KEY_MAX; i++) {
1843
if (joystick->hwdata->has_key[i]) {
1844
bool down = test_bit(i, keyinfo);
1845
#ifdef DEBUG_INPUT_EVENTS
1846
SDL_Log("Joystick : Re-read Button %d (%d) val= %d",
1847
joystick->hwdata->key_map[i], i, down);
1848
#endif
1849
SDL_SendJoystickButton(timestamp, joystick,
1850
joystick->hwdata->key_map[i], down);
1851
}
1852
}
1853
}
1854
1855
// Joyballs are relative input, so there's no poll state. Events only!
1856
}
1857
1858
static void CorrectSensorData(struct joystick_hwdata *hwdata, float *values, float *data)
1859
{
1860
if (hwdata->item->vendor == USB_VENDOR_NINTENDO) {
1861
// The Nintendo driver uses a different axis order than SDL
1862
data[0] = -values[1];
1863
data[1] = values[2];
1864
data[2] = -values[0];
1865
} else {
1866
data[0] = values[0];
1867
data[1] = values[1];
1868
data[2] = values[2];
1869
}
1870
}
1871
1872
static void PollAllSensors(Uint64 timestamp, SDL_Joystick *joystick)
1873
{
1874
struct input_absinfo absinfo;
1875
int i;
1876
1877
SDL_AssertJoysticksLocked();
1878
1879
SDL_assert(joystick->hwdata->fd_sensor >= 0);
1880
1881
if (joystick->hwdata->has_gyro) {
1882
float values[3] = {0.0f, 0.0f, 0.0f};
1883
for (i = 0; i < 3; i++) {
1884
if (ioctl(joystick->hwdata->fd_sensor, EVIOCGABS(ABS_RX + i), &absinfo) >= 0) {
1885
values[i] = absinfo.value * (SDL_PI_F / 180.f) / joystick->hwdata->gyro_scale[i];
1886
#ifdef DEBUG_INPUT_EVENTS
1887
SDL_Log("Joystick : Re-read Gyro (axis %d) val= %f", i, data[i]);
1888
#endif
1889
}
1890
}
1891
float data[3];
1892
CorrectSensorData(joystick->hwdata, values, data);
1893
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, SDL_US_TO_NS(joystick->hwdata->sensor_tick), data, 3);
1894
}
1895
if (joystick->hwdata->has_accelerometer) {
1896
float values[3] = {0.0f, 0.0f, 0.0f};
1897
for (i = 0; i < 3; i++) {
1898
if (ioctl(joystick->hwdata->fd_sensor, EVIOCGABS(ABS_X + i), &absinfo) >= 0) {
1899
values[i] = absinfo.value * SDL_STANDARD_GRAVITY / joystick->hwdata->accelerometer_scale[i];
1900
#ifdef DEBUG_INPUT_EVENTS
1901
SDL_Log("Joystick : Re-read Accelerometer (axis %d) val= %f", i, data[i]);
1902
#endif
1903
}
1904
}
1905
float data[3];
1906
CorrectSensorData(joystick->hwdata, values, data);
1907
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, SDL_US_TO_NS(joystick->hwdata->sensor_tick), data, 3);
1908
}
1909
}
1910
1911
static void HandleInputEvents(SDL_Joystick *joystick)
1912
{
1913
struct input_event events[32];
1914
int i, len, code, hat_index;
1915
1916
SDL_AssertJoysticksLocked();
1917
1918
if (joystick->hwdata->fresh) {
1919
Uint64 ticks = SDL_GetTicksNS();
1920
PollAllValues(ticks, joystick);
1921
if (joystick->hwdata->report_sensor) {
1922
PollAllSensors(ticks, joystick);
1923
}
1924
joystick->hwdata->fresh = false;
1925
}
1926
1927
errno = 0;
1928
1929
while ((len = read(joystick->hwdata->fd, events, sizeof(events))) > 0) {
1930
len /= sizeof(events[0]);
1931
for (i = 0; i < len; ++i) {
1932
struct input_event *event = &events[i];
1933
1934
code = event->code;
1935
1936
/* If the kernel sent a SYN_DROPPED, we are supposed to ignore the
1937
rest of the packet (the end of it signified by a SYN_REPORT) */
1938
if (joystick->hwdata->recovering_from_dropped &&
1939
((event->type != EV_SYN) || (code != SYN_REPORT))) {
1940
continue;
1941
}
1942
1943
switch (event->type) {
1944
case EV_KEY:
1945
#ifdef DEBUG_INPUT_EVENTS
1946
SDL_Log("Key 0x%.2x %s", code, event->value ? "PRESSED" : "RELEASED");
1947
#endif
1948
SDL_SendJoystickButton(SDL_EVDEV_GetEventTimestamp(event), joystick,
1949
joystick->hwdata->key_map[code],
1950
(event->value != 0));
1951
break;
1952
case EV_ABS:
1953
switch (code) {
1954
case ABS_HAT0X:
1955
case ABS_HAT0Y:
1956
case ABS_HAT1X:
1957
case ABS_HAT1Y:
1958
case ABS_HAT2X:
1959
case ABS_HAT2Y:
1960
case ABS_HAT3X:
1961
case ABS_HAT3Y:
1962
hat_index = (code - ABS_HAT0X) / 2;
1963
if (joystick->hwdata->has_hat[hat_index]) {
1964
#ifdef DEBUG_INPUT_EVENTS
1965
SDL_Log("Axis 0x%.2x = %d", code, event->value);
1966
#endif
1967
HandleHat(SDL_EVDEV_GetEventTimestamp(event), joystick, hat_index, code % 2, event->value);
1968
break;
1969
}
1970
SDL_FALLTHROUGH;
1971
default:
1972
#ifdef DEBUG_INPUT_EVENTS
1973
SDL_Log("Axis 0x%.2x = %d", code, event->value);
1974
#endif
1975
event->value = AxisCorrect(joystick, code, event->value);
1976
SDL_SendJoystickAxis(SDL_EVDEV_GetEventTimestamp(event), joystick,
1977
joystick->hwdata->abs_map[code],
1978
event->value);
1979
break;
1980
}
1981
break;
1982
case EV_REL:
1983
switch (code) {
1984
case REL_X:
1985
case REL_Y:
1986
code -= REL_X;
1987
HandleBall(joystick, code / 2, code % 2, event->value);
1988
break;
1989
default:
1990
break;
1991
}
1992
break;
1993
case EV_SYN:
1994
switch (code) {
1995
case SYN_DROPPED:
1996
#ifdef DEBUG_INPUT_EVENTS
1997
SDL_Log("Event SYN_DROPPED detected");
1998
#endif
1999
joystick->hwdata->recovering_from_dropped = true;
2000
break;
2001
case SYN_REPORT:
2002
if (joystick->hwdata->recovering_from_dropped) {
2003
joystick->hwdata->recovering_from_dropped = false;
2004
PollAllValues(SDL_GetTicksNS(), joystick); // try to sync up to current state now
2005
}
2006
break;
2007
default:
2008
break;
2009
}
2010
break;
2011
default:
2012
break;
2013
}
2014
}
2015
}
2016
2017
if (errno == ENODEV) {
2018
// We have to wait until the JoystickDetect callback to remove this
2019
joystick->hwdata->gone = true;
2020
errno = 0;
2021
}
2022
2023
if (joystick->hwdata->report_sensor) {
2024
SDL_assert(joystick->hwdata->fd_sensor >= 0);
2025
2026
while ((len = read(joystick->hwdata->fd_sensor, events, sizeof(events))) > 0) {
2027
len /= sizeof(events[0]);
2028
for (i = 0; i < len; ++i) {
2029
unsigned int j;
2030
struct input_event *event = &events[i];
2031
2032
code = event->code;
2033
2034
/* If the kernel sent a SYN_DROPPED, we are supposed to ignore the
2035
rest of the packet (the end of it signified by a SYN_REPORT) */
2036
if (joystick->hwdata->recovering_from_dropped_sensor &&
2037
((event->type != EV_SYN) || (code != SYN_REPORT))) {
2038
continue;
2039
}
2040
2041
switch (event->type) {
2042
case EV_KEY:
2043
SDL_assert(0);
2044
break;
2045
case EV_ABS:
2046
switch (code) {
2047
case ABS_X:
2048
case ABS_Y:
2049
case ABS_Z:
2050
j = code - ABS_X;
2051
joystick->hwdata->accel_data[j] = event->value * SDL_STANDARD_GRAVITY
2052
/ joystick->hwdata->accelerometer_scale[j];
2053
break;
2054
case ABS_RX:
2055
case ABS_RY:
2056
case ABS_RZ:
2057
j = code - ABS_RX;
2058
joystick->hwdata->gyro_data[j] = event->value * (SDL_PI_F / 180.f)
2059
/ joystick->hwdata->gyro_scale[j];
2060
break;
2061
}
2062
break;
2063
case EV_MSC:
2064
if (code == MSC_TIMESTAMP) {
2065
Sint32 tick = event->value;
2066
Sint32 delta;
2067
if (joystick->hwdata->last_tick < tick) {
2068
delta = (tick - joystick->hwdata->last_tick);
2069
} else {
2070
delta = (SDL_MAX_SINT32 - joystick->hwdata->last_tick + tick + 1);
2071
}
2072
joystick->hwdata->sensor_tick += delta;
2073
joystick->hwdata->last_tick = tick;
2074
}
2075
break;
2076
case EV_SYN:
2077
switch (code) {
2078
case SYN_DROPPED:
2079
#ifdef DEBUG_INPUT_EVENTS
2080
SDL_Log("Event SYN_DROPPED detected");
2081
#endif
2082
joystick->hwdata->recovering_from_dropped_sensor = true;
2083
break;
2084
case SYN_REPORT:
2085
if (joystick->hwdata->recovering_from_dropped_sensor) {
2086
joystick->hwdata->recovering_from_dropped_sensor = false;
2087
PollAllSensors(SDL_GetTicksNS(), joystick); // try to sync up to current state now
2088
} else {
2089
Uint64 timestamp = SDL_EVDEV_GetEventTimestamp(event);
2090
float data[3];
2091
CorrectSensorData(joystick->hwdata, joystick->hwdata->gyro_data, data);
2092
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO,
2093
SDL_US_TO_NS(joystick->hwdata->sensor_tick),
2094
data, 3);
2095
CorrectSensorData(joystick->hwdata, joystick->hwdata->accel_data, data);
2096
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL,
2097
SDL_US_TO_NS(joystick->hwdata->sensor_tick),
2098
data, 3);
2099
}
2100
break;
2101
default:
2102
break;
2103
}
2104
break;
2105
default:
2106
break;
2107
}
2108
}
2109
}
2110
}
2111
2112
if (errno == ENODEV) {
2113
// We have to wait until the JoystickDetect callback to remove this
2114
joystick->hwdata->sensor_gone = true;
2115
}
2116
}
2117
2118
static void HandleClassicEvents(SDL_Joystick *joystick)
2119
{
2120
struct js_event events[32];
2121
int i, len, code, hat_index;
2122
Uint64 timestamp = SDL_GetTicksNS();
2123
2124
SDL_AssertJoysticksLocked();
2125
2126
joystick->hwdata->fresh = false;
2127
while ((len = read(joystick->hwdata->fd, events, sizeof(events))) > 0) {
2128
len /= sizeof(events[0]);
2129
for (i = 0; i < len; ++i) {
2130
switch (events[i].type) {
2131
case JS_EVENT_BUTTON:
2132
code = joystick->hwdata->key_pam[events[i].number];
2133
SDL_SendJoystickButton(timestamp, joystick,
2134
joystick->hwdata->key_map[code],
2135
(events[i].value != 0));
2136
break;
2137
case JS_EVENT_AXIS:
2138
code = joystick->hwdata->abs_pam[events[i].number];
2139
switch (code) {
2140
case ABS_HAT0X:
2141
case ABS_HAT0Y:
2142
case ABS_HAT1X:
2143
case ABS_HAT1Y:
2144
case ABS_HAT2X:
2145
case ABS_HAT2Y:
2146
case ABS_HAT3X:
2147
case ABS_HAT3Y:
2148
hat_index = (code - ABS_HAT0X) / 2;
2149
if (joystick->hwdata->has_hat[hat_index]) {
2150
HandleHat(timestamp, joystick, hat_index, code % 2, events[i].value);
2151
break;
2152
}
2153
SDL_FALLTHROUGH;
2154
default:
2155
SDL_SendJoystickAxis(timestamp, joystick,
2156
joystick->hwdata->abs_map[code],
2157
events[i].value);
2158
break;
2159
}
2160
}
2161
}
2162
}
2163
}
2164
2165
static void LINUX_JoystickUpdate(SDL_Joystick *joystick)
2166
{
2167
int i;
2168
2169
SDL_AssertJoysticksLocked();
2170
2171
if (joystick->hwdata->classic) {
2172
HandleClassicEvents(joystick);
2173
} else {
2174
HandleInputEvents(joystick);
2175
}
2176
2177
// Deliver ball motion updates
2178
for (i = 0; i < joystick->nballs; ++i) {
2179
int xrel, yrel;
2180
2181
xrel = joystick->hwdata->balls[i].axis[0];
2182
yrel = joystick->hwdata->balls[i].axis[1];
2183
if (xrel || yrel) {
2184
joystick->hwdata->balls[i].axis[0] = 0;
2185
joystick->hwdata->balls[i].axis[1] = 0;
2186
SDL_SendJoystickBall(0, joystick, (Uint8)i, xrel, yrel);
2187
}
2188
}
2189
}
2190
2191
// Function to close a joystick after use
2192
static void LINUX_JoystickClose(SDL_Joystick *joystick)
2193
{
2194
SDL_AssertJoysticksLocked();
2195
2196
if (joystick->hwdata) {
2197
if (joystick->hwdata->effect.id >= 0) {
2198
ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id);
2199
joystick->hwdata->effect.id = -1;
2200
}
2201
if (joystick->hwdata->fd >= 0) {
2202
close(joystick->hwdata->fd);
2203
}
2204
if (joystick->hwdata->fd_sensor >= 0) {
2205
close(joystick->hwdata->fd_sensor);
2206
}
2207
if (joystick->hwdata->item) {
2208
joystick->hwdata->item->hwdata = NULL;
2209
}
2210
if (joystick->hwdata->item_sensor) {
2211
joystick->hwdata->item_sensor->hwdata = NULL;
2212
}
2213
SDL_free(joystick->hwdata->key_pam);
2214
SDL_free(joystick->hwdata->abs_pam);
2215
SDL_free(joystick->hwdata->hats);
2216
SDL_free(joystick->hwdata->balls);
2217
SDL_free(joystick->hwdata->fname);
2218
SDL_free(joystick->hwdata);
2219
}
2220
}
2221
2222
// Function to perform any system-specific joystick related cleanup
2223
static void LINUX_JoystickQuit(void)
2224
{
2225
SDL_joylist_item *item = NULL;
2226
SDL_joylist_item *next = NULL;
2227
SDL_sensorlist_item *item_sensor = NULL;
2228
SDL_sensorlist_item *next_sensor = NULL;
2229
2230
SDL_AssertJoysticksLocked();
2231
2232
if (inotify_fd >= 0) {
2233
close(inotify_fd);
2234
inotify_fd = -1;
2235
}
2236
2237
for (item = SDL_joylist; item; item = next) {
2238
next = item->next;
2239
FreeJoylistItem(item);
2240
}
2241
for (item_sensor = SDL_sensorlist; item_sensor; item_sensor = next_sensor) {
2242
next_sensor = item_sensor->next;
2243
FreeSensorlistItem(item_sensor);
2244
}
2245
2246
SDL_joylist = SDL_joylist_tail = NULL;
2247
SDL_sensorlist = NULL;
2248
2249
numjoysticks = 0;
2250
2251
#ifdef SDL_USE_LIBUDEV
2252
if (enumeration_method == ENUMERATION_LIBUDEV) {
2253
SDL_UDEV_DelCallback(joystick_udev_callback);
2254
SDL_UDEV_Quit();
2255
}
2256
#endif
2257
}
2258
2259
/*
2260
This is based on the Linux Gamepad Specification
2261
available at: https://www.kernel.org/doc/html/v4.15/input/gamepad.html
2262
and the Android gamepad documentation,
2263
https://developer.android.com/develop/ui/views/touch-and-input/game-controllers/controller-input
2264
*/
2265
static bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
2266
{
2267
SDL_Joystick *joystick;
2268
SDL_joylist_item *item = GetJoystickByDevIndex(device_index);
2269
enum {
2270
MAPPED_TRIGGER_LEFT = 0x1,
2271
MAPPED_TRIGGER_RIGHT = 0x2,
2272
MAPPED_TRIGGER_BOTH = 0x3,
2273
2274
MAPPED_DPAD_UP = 0x1,
2275
MAPPED_DPAD_DOWN = 0x2,
2276
MAPPED_DPAD_LEFT = 0x4,
2277
MAPPED_DPAD_RIGHT = 0x8,
2278
MAPPED_DPAD_ALL = 0xF,
2279
};
2280
unsigned int mapped;
2281
bool result = false;
2282
2283
SDL_AssertJoysticksLocked();
2284
2285
if (item->checked_mapping) {
2286
if (item->mapping) {
2287
SDL_memcpy(out, item->mapping, sizeof(*out));
2288
#ifdef DEBUG_GAMEPAD_MAPPING
2289
SDL_Log("Prior mapping for device %d", device_index);
2290
#endif
2291
return true;
2292
} else {
2293
return false;
2294
}
2295
}
2296
2297
/* We temporarily open the device to check how it's configured. Make
2298
a fake SDL_Joystick object to do so. */
2299
joystick = (SDL_Joystick *)SDL_calloc(1, sizeof(*joystick));
2300
if (!joystick) {
2301
return false;
2302
}
2303
SDL_memcpy(&joystick->guid, &item->guid, sizeof(item->guid));
2304
2305
joystick->hwdata = (struct joystick_hwdata *)SDL_calloc(1, sizeof(*joystick->hwdata));
2306
if (!joystick->hwdata) {
2307
SDL_free(joystick);
2308
return false;
2309
}
2310
SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, true);
2311
2312
item->checked_mapping = true;
2313
2314
if (!PrepareJoystickHwdata(joystick, item, NULL)) {
2315
goto done; // SDL_SetError will already have been called
2316
}
2317
2318
// don't assign `item->hwdata` so it's not in any global state.
2319
2320
// it is now safe to call LINUX_JoystickClose on this fake joystick.
2321
2322
if (!joystick->hwdata->has_key[BTN_GAMEPAD]) {
2323
// Not a gamepad according to the specs.
2324
goto done;
2325
}
2326
2327
// We have a gamepad, start filling out the mappings
2328
2329
#ifdef DEBUG_GAMEPAD_MAPPING
2330
SDL_Log("Mapping %s (VID/PID 0x%.4x/0x%.4x)", item->name, SDL_GetJoystickVendor(joystick), SDL_GetJoystickProduct(joystick));
2331
#endif
2332
2333
if (joystick->hwdata->has_key[BTN_A]) {
2334
out->a.kind = EMappingKind_Button;
2335
out->a.target = joystick->hwdata->key_map[BTN_A];
2336
#ifdef DEBUG_GAMEPAD_MAPPING
2337
SDL_Log("Mapped A to button %d (BTN_A)", out->a.target);
2338
#endif
2339
}
2340
2341
if (joystick->hwdata->has_key[BTN_B]) {
2342
out->b.kind = EMappingKind_Button;
2343
out->b.target = joystick->hwdata->key_map[BTN_B];
2344
#ifdef DEBUG_GAMEPAD_MAPPING
2345
SDL_Log("Mapped B to button %d (BTN_B)", out->b.target);
2346
#endif
2347
}
2348
2349
// Xbox controllers use BTN_X and BTN_Y, and PS4 controllers use BTN_WEST and BTN_NORTH
2350
if (SDL_GetJoystickVendor(joystick) == USB_VENDOR_SONY) {
2351
if (joystick->hwdata->has_key[BTN_WEST]) {
2352
out->x.kind = EMappingKind_Button;
2353
out->x.target = joystick->hwdata->key_map[BTN_WEST];
2354
#ifdef DEBUG_GAMEPAD_MAPPING
2355
SDL_Log("Mapped X to button %d (BTN_WEST)", out->x.target);
2356
#endif
2357
}
2358
2359
if (joystick->hwdata->has_key[BTN_NORTH]) {
2360
out->y.kind = EMappingKind_Button;
2361
out->y.target = joystick->hwdata->key_map[BTN_NORTH];
2362
#ifdef DEBUG_GAMEPAD_MAPPING
2363
SDL_Log("Mapped Y to button %d (BTN_NORTH)", out->y.target);
2364
#endif
2365
}
2366
} else {
2367
if (joystick->hwdata->has_key[BTN_X]) {
2368
out->x.kind = EMappingKind_Button;
2369
out->x.target = joystick->hwdata->key_map[BTN_X];
2370
#ifdef DEBUG_GAMEPAD_MAPPING
2371
SDL_Log("Mapped X to button %d (BTN_X)", out->x.target);
2372
#endif
2373
}
2374
2375
if (joystick->hwdata->has_key[BTN_Y]) {
2376
out->y.kind = EMappingKind_Button;
2377
out->y.target = joystick->hwdata->key_map[BTN_Y];
2378
#ifdef DEBUG_GAMEPAD_MAPPING
2379
SDL_Log("Mapped Y to button %d (BTN_Y)", out->y.target);
2380
#endif
2381
}
2382
}
2383
2384
if (joystick->hwdata->has_key[BTN_SELECT]) {
2385
out->back.kind = EMappingKind_Button;
2386
out->back.target = joystick->hwdata->key_map[BTN_SELECT];
2387
#ifdef DEBUG_GAMEPAD_MAPPING
2388
SDL_Log("Mapped BACK to button %d (BTN_SELECT)", out->back.target);
2389
#endif
2390
}
2391
2392
if (joystick->hwdata->has_key[BTN_START]) {
2393
out->start.kind = EMappingKind_Button;
2394
out->start.target = joystick->hwdata->key_map[BTN_START];
2395
#ifdef DEBUG_GAMEPAD_MAPPING
2396
SDL_Log("Mapped START to button %d (BTN_START)", out->start.target);
2397
#endif
2398
}
2399
2400
if (joystick->hwdata->has_key[BTN_THUMBL]) {
2401
out->leftstick.kind = EMappingKind_Button;
2402
out->leftstick.target = joystick->hwdata->key_map[BTN_THUMBL];
2403
#ifdef DEBUG_GAMEPAD_MAPPING
2404
SDL_Log("Mapped LEFTSTICK to button %d (BTN_THUMBL)", out->leftstick.target);
2405
#endif
2406
}
2407
2408
if (joystick->hwdata->has_key[BTN_THUMBR]) {
2409
out->rightstick.kind = EMappingKind_Button;
2410
out->rightstick.target = joystick->hwdata->key_map[BTN_THUMBR];
2411
#ifdef DEBUG_GAMEPAD_MAPPING
2412
SDL_Log("Mapped RIGHTSTICK to button %d (BTN_THUMBR)", out->rightstick.target);
2413
#endif
2414
}
2415
2416
if (joystick->hwdata->has_key[BTN_MODE]) {
2417
out->guide.kind = EMappingKind_Button;
2418
out->guide.target = joystick->hwdata->key_map[BTN_MODE];
2419
#ifdef DEBUG_GAMEPAD_MAPPING
2420
SDL_Log("Mapped GUIDE to button %d (BTN_MODE)", out->guide.target);
2421
#endif
2422
}
2423
2424
/*
2425
According to the specs the D-Pad, the shoulder buttons and the triggers
2426
can be digital, or analog, or both at the same time.
2427
*/
2428
2429
// Prefer digital shoulder buttons, but settle for digital or analog hat.
2430
mapped = 0;
2431
2432
if (joystick->hwdata->has_key[BTN_TL]) {
2433
out->leftshoulder.kind = EMappingKind_Button;
2434
out->leftshoulder.target = joystick->hwdata->key_map[BTN_TL];
2435
mapped |= 0x1;
2436
#ifdef DEBUG_GAMEPAD_MAPPING
2437
SDL_Log("Mapped LEFTSHOULDER to button %d (BTN_TL)", out->leftshoulder.target);
2438
#endif
2439
}
2440
2441
if (joystick->hwdata->has_key[BTN_TR]) {
2442
out->rightshoulder.kind = EMappingKind_Button;
2443
out->rightshoulder.target = joystick->hwdata->key_map[BTN_TR];
2444
mapped |= 0x2;
2445
#ifdef DEBUG_GAMEPAD_MAPPING
2446
SDL_Log("Mapped RIGHTSHOULDER to button %d (BTN_TR)", out->rightshoulder.target);
2447
#endif
2448
}
2449
2450
if (mapped != 0x3 && joystick->hwdata->has_hat[1]) {
2451
int hat = joystick->hwdata->hats_indices[1] << 4;
2452
out->leftshoulder.kind = EMappingKind_Hat;
2453
out->rightshoulder.kind = EMappingKind_Hat;
2454
out->leftshoulder.target = hat | 0x4;
2455
out->rightshoulder.target = hat | 0x2;
2456
mapped |= 0x3;
2457
#ifdef DEBUG_GAMEPAD_MAPPING
2458
SDL_Log("Mapped LEFT+RIGHTSHOULDER to hat 1 (ABS_HAT1X, ABS_HAT1Y)");
2459
#endif
2460
}
2461
2462
if (!(mapped & 0x1) && joystick->hwdata->has_abs[ABS_HAT1Y]) {
2463
out->leftshoulder.kind = EMappingKind_Axis;
2464
out->leftshoulder.target = joystick->hwdata->abs_map[ABS_HAT1Y];
2465
mapped |= 0x1;
2466
#ifdef DEBUG_GAMEPAD_MAPPING
2467
SDL_Log("Mapped LEFTSHOULDER to axis %d (ABS_HAT1Y)", out->leftshoulder.target);
2468
#endif
2469
}
2470
2471
if (!(mapped & 0x2) && joystick->hwdata->has_abs[ABS_HAT1X]) {
2472
out->rightshoulder.kind = EMappingKind_Axis;
2473
out->rightshoulder.target = joystick->hwdata->abs_map[ABS_HAT1X];
2474
mapped |= 0x2;
2475
#ifdef DEBUG_GAMEPAD_MAPPING
2476
SDL_Log("Mapped RIGHTSHOULDER to axis %d (ABS_HAT1X)", out->rightshoulder.target);
2477
#endif
2478
}
2479
2480
// Prefer analog triggers, but settle for digital hat or buttons.
2481
mapped = 0;
2482
2483
/* Unfortunately there are several conventions for how analog triggers
2484
* are represented as absolute axes:
2485
*
2486
* - Linux Gamepad Specification:
2487
* LT = ABS_HAT2Y, RT = ABS_HAT2X
2488
* - Android (and therefore many Bluetooth controllers):
2489
* LT = ABS_BRAKE, RT = ABS_GAS
2490
* - De facto standard for older Xbox and Playstation controllers:
2491
* LT = ABS_Z, RT = ABS_RZ
2492
*
2493
* We try each one in turn. */
2494
if (joystick->hwdata->has_abs[ABS_HAT2Y]) {
2495
// Linux Gamepad Specification
2496
out->lefttrigger.kind = EMappingKind_Axis;
2497
out->lefttrigger.target = joystick->hwdata->abs_map[ABS_HAT2Y];
2498
mapped |= MAPPED_TRIGGER_LEFT;
2499
#ifdef DEBUG_GAMEPAD_MAPPING
2500
SDL_Log("Mapped LEFTTRIGGER to axis %d (ABS_HAT2Y)", out->lefttrigger.target);
2501
#endif
2502
} else if (joystick->hwdata->has_abs[ABS_BRAKE]) {
2503
// Android convention
2504
out->lefttrigger.kind = EMappingKind_Axis;
2505
out->lefttrigger.target = joystick->hwdata->abs_map[ABS_BRAKE];
2506
mapped |= MAPPED_TRIGGER_LEFT;
2507
#ifdef DEBUG_GAMEPAD_MAPPING
2508
SDL_Log("Mapped LEFTTRIGGER to axis %d (ABS_BRAKE)", out->lefttrigger.target);
2509
#endif
2510
} else if (joystick->hwdata->has_abs[ABS_Z]) {
2511
// De facto standard for Xbox 360 and Playstation gamepads
2512
out->lefttrigger.kind = EMappingKind_Axis;
2513
out->lefttrigger.target = joystick->hwdata->abs_map[ABS_Z];
2514
mapped |= MAPPED_TRIGGER_LEFT;
2515
#ifdef DEBUG_GAMEPAD_MAPPING
2516
SDL_Log("Mapped LEFTTRIGGER to axis %d (ABS_Z)", out->lefttrigger.target);
2517
#endif
2518
}
2519
2520
if (joystick->hwdata->has_abs[ABS_HAT2X]) {
2521
// Linux Gamepad Specification
2522
out->righttrigger.kind = EMappingKind_Axis;
2523
out->righttrigger.target = joystick->hwdata->abs_map[ABS_HAT2X];
2524
mapped |= MAPPED_TRIGGER_RIGHT;
2525
#ifdef DEBUG_GAMEPAD_MAPPING
2526
SDL_Log("Mapped RIGHTTRIGGER to axis %d (ABS_HAT2X)", out->righttrigger.target);
2527
#endif
2528
} else if (joystick->hwdata->has_abs[ABS_GAS]) {
2529
// Android convention
2530
out->righttrigger.kind = EMappingKind_Axis;
2531
out->righttrigger.target = joystick->hwdata->abs_map[ABS_GAS];
2532
mapped |= MAPPED_TRIGGER_RIGHT;
2533
#ifdef DEBUG_GAMEPAD_MAPPING
2534
SDL_Log("Mapped RIGHTTRIGGER to axis %d (ABS_GAS)", out->righttrigger.target);
2535
#endif
2536
} else if (joystick->hwdata->has_abs[ABS_RZ]) {
2537
// De facto standard for Xbox 360 and Playstation gamepads
2538
out->righttrigger.kind = EMappingKind_Axis;
2539
out->righttrigger.target = joystick->hwdata->abs_map[ABS_RZ];
2540
mapped |= MAPPED_TRIGGER_RIGHT;
2541
#ifdef DEBUG_GAMEPAD_MAPPING
2542
SDL_Log("Mapped RIGHTTRIGGER to axis %d (ABS_RZ)", out->righttrigger.target);
2543
#endif
2544
}
2545
2546
if (mapped != MAPPED_TRIGGER_BOTH && joystick->hwdata->has_hat[2]) {
2547
int hat = joystick->hwdata->hats_indices[2] << 4;
2548
out->lefttrigger.kind = EMappingKind_Hat;
2549
out->righttrigger.kind = EMappingKind_Hat;
2550
out->lefttrigger.target = hat | 0x4;
2551
out->righttrigger.target = hat | 0x2;
2552
mapped |= MAPPED_TRIGGER_BOTH;
2553
#ifdef DEBUG_GAMEPAD_MAPPING
2554
SDL_Log("Mapped LEFT+RIGHTTRIGGER to hat 2 (ABS_HAT2X, ABS_HAT2Y)");
2555
#endif
2556
}
2557
2558
if (!(mapped & MAPPED_TRIGGER_LEFT) && joystick->hwdata->has_key[BTN_TL2]) {
2559
out->lefttrigger.kind = EMappingKind_Button;
2560
out->lefttrigger.target = joystick->hwdata->key_map[BTN_TL2];
2561
mapped |= MAPPED_TRIGGER_LEFT;
2562
#ifdef DEBUG_GAMEPAD_MAPPING
2563
SDL_Log("Mapped LEFTTRIGGER to button %d (BTN_TL2)", out->lefttrigger.target);
2564
#endif
2565
}
2566
2567
if (!(mapped & MAPPED_TRIGGER_RIGHT) && joystick->hwdata->has_key[BTN_TR2]) {
2568
out->righttrigger.kind = EMappingKind_Button;
2569
out->righttrigger.target = joystick->hwdata->key_map[BTN_TR2];
2570
mapped |= MAPPED_TRIGGER_RIGHT;
2571
#ifdef DEBUG_GAMEPAD_MAPPING
2572
SDL_Log("Mapped RIGHTTRIGGER to button %d (BTN_TR2)", out->righttrigger.target);
2573
#endif
2574
}
2575
2576
// Prefer digital D-Pad buttons, but settle for digital or analog hat.
2577
mapped = 0;
2578
2579
if (joystick->hwdata->has_key[BTN_DPAD_UP]) {
2580
out->dpup.kind = EMappingKind_Button;
2581
out->dpup.target = joystick->hwdata->key_map[BTN_DPAD_UP];
2582
mapped |= MAPPED_DPAD_UP;
2583
#ifdef DEBUG_GAMEPAD_MAPPING
2584
SDL_Log("Mapped DPUP to button %d (BTN_DPAD_UP)", out->dpup.target);
2585
#endif
2586
}
2587
2588
if (joystick->hwdata->has_key[BTN_DPAD_DOWN]) {
2589
out->dpdown.kind = EMappingKind_Button;
2590
out->dpdown.target = joystick->hwdata->key_map[BTN_DPAD_DOWN];
2591
mapped |= MAPPED_DPAD_DOWN;
2592
#ifdef DEBUG_GAMEPAD_MAPPING
2593
SDL_Log("Mapped DPDOWN to button %d (BTN_DPAD_DOWN)", out->dpdown.target);
2594
#endif
2595
}
2596
2597
if (joystick->hwdata->has_key[BTN_DPAD_LEFT]) {
2598
out->dpleft.kind = EMappingKind_Button;
2599
out->dpleft.target = joystick->hwdata->key_map[BTN_DPAD_LEFT];
2600
mapped |= MAPPED_DPAD_LEFT;
2601
#ifdef DEBUG_GAMEPAD_MAPPING
2602
SDL_Log("Mapped DPLEFT to button %d (BTN_DPAD_LEFT)", out->dpleft.target);
2603
#endif
2604
}
2605
2606
if (joystick->hwdata->has_key[BTN_DPAD_RIGHT]) {
2607
out->dpright.kind = EMappingKind_Button;
2608
out->dpright.target = joystick->hwdata->key_map[BTN_DPAD_RIGHT];
2609
mapped |= MAPPED_DPAD_RIGHT;
2610
#ifdef DEBUG_GAMEPAD_MAPPING
2611
SDL_Log("Mapped DPRIGHT to button %d (BTN_DPAD_RIGHT)", out->dpright.target);
2612
#endif
2613
}
2614
2615
if (mapped != MAPPED_DPAD_ALL) {
2616
if (joystick->hwdata->has_hat[0]) {
2617
int hat = joystick->hwdata->hats_indices[0] << 4;
2618
out->dpleft.kind = EMappingKind_Hat;
2619
out->dpright.kind = EMappingKind_Hat;
2620
out->dpup.kind = EMappingKind_Hat;
2621
out->dpdown.kind = EMappingKind_Hat;
2622
out->dpleft.target = hat | 0x8;
2623
out->dpright.target = hat | 0x2;
2624
out->dpup.target = hat | 0x1;
2625
out->dpdown.target = hat | 0x4;
2626
mapped |= MAPPED_DPAD_ALL;
2627
#ifdef DEBUG_GAMEPAD_MAPPING
2628
SDL_Log("Mapped DPUP+DOWN+LEFT+RIGHT to hat 0 (ABS_HAT0X, ABS_HAT0Y)");
2629
#endif
2630
} else if (joystick->hwdata->has_abs[ABS_HAT0X] && joystick->hwdata->has_abs[ABS_HAT0Y]) {
2631
out->dpleft.kind = EMappingKind_Axis;
2632
out->dpright.kind = EMappingKind_Axis;
2633
out->dpup.kind = EMappingKind_Axis;
2634
out->dpdown.kind = EMappingKind_Axis;
2635
out->dpleft.target = joystick->hwdata->abs_map[ABS_HAT0X];
2636
out->dpright.target = joystick->hwdata->abs_map[ABS_HAT0X];
2637
out->dpup.target = joystick->hwdata->abs_map[ABS_HAT0Y];
2638
out->dpdown.target = joystick->hwdata->abs_map[ABS_HAT0Y];
2639
mapped |= MAPPED_DPAD_ALL;
2640
#ifdef DEBUG_GAMEPAD_MAPPING
2641
SDL_Log("Mapped DPUP+DOWN to axis %d (ABS_HAT0Y)", out->dpup.target);
2642
SDL_Log("Mapped DPLEFT+RIGHT to axis %d (ABS_HAT0X)", out->dpleft.target);
2643
#endif
2644
}
2645
}
2646
2647
if (joystick->hwdata->has_abs[ABS_X] && joystick->hwdata->has_abs[ABS_Y]) {
2648
out->leftx.kind = EMappingKind_Axis;
2649
out->lefty.kind = EMappingKind_Axis;
2650
out->leftx.target = joystick->hwdata->abs_map[ABS_X];
2651
out->lefty.target = joystick->hwdata->abs_map[ABS_Y];
2652
#ifdef DEBUG_GAMEPAD_MAPPING
2653
SDL_Log("Mapped LEFTX to axis %d (ABS_X)", out->leftx.target);
2654
SDL_Log("Mapped LEFTY to axis %d (ABS_Y)", out->lefty.target);
2655
#endif
2656
}
2657
2658
/* The Linux Gamepad Specification uses the RX and RY axes,
2659
* originally intended to represent X and Y rotation, as a second
2660
* joystick. This is common for USB gamepads, and also many Bluetooth
2661
* gamepads, particularly older ones.
2662
*
2663
* The Android mapping convention used by many Bluetooth controllers
2664
* instead uses the Z axis as a secondary X axis, and the RZ axis as
2665
* a secondary Y axis. */
2666
if (joystick->hwdata->has_abs[ABS_RX] && joystick->hwdata->has_abs[ABS_RY]) {
2667
// Linux Gamepad Specification, Xbox 360, Playstation etc.
2668
out->rightx.kind = EMappingKind_Axis;
2669
out->righty.kind = EMappingKind_Axis;
2670
out->rightx.target = joystick->hwdata->abs_map[ABS_RX];
2671
out->righty.target = joystick->hwdata->abs_map[ABS_RY];
2672
#ifdef DEBUG_GAMEPAD_MAPPING
2673
SDL_Log("Mapped RIGHTX to axis %d (ABS_RX)", out->rightx.target);
2674
SDL_Log("Mapped RIGHTY to axis %d (ABS_RY)", out->righty.target);
2675
#endif
2676
} else if (joystick->hwdata->has_abs[ABS_Z] && joystick->hwdata->has_abs[ABS_RZ]) {
2677
// Android convention
2678
out->rightx.kind = EMappingKind_Axis;
2679
out->righty.kind = EMappingKind_Axis;
2680
out->rightx.target = joystick->hwdata->abs_map[ABS_Z];
2681
out->righty.target = joystick->hwdata->abs_map[ABS_RZ];
2682
#ifdef DEBUG_GAMEPAD_MAPPING
2683
SDL_Log("Mapped RIGHTX to axis %d (ABS_Z)", out->rightx.target);
2684
SDL_Log("Mapped RIGHTY to axis %d (ABS_RZ)", out->righty.target);
2685
#endif
2686
}
2687
2688
if (SDL_GetJoystickVendor(joystick) == USB_VENDOR_MICROSOFT) {
2689
// The Xbox Elite controllers have the paddles as BTN_TRIGGER_HAPPY5 - BTN_TRIGGER_HAPPY8
2690
if (joystick->hwdata->has_key[BTN_TRIGGER_HAPPY5] &&
2691
joystick->hwdata->has_key[BTN_TRIGGER_HAPPY6] &&
2692
joystick->hwdata->has_key[BTN_TRIGGER_HAPPY7] &&
2693
joystick->hwdata->has_key[BTN_TRIGGER_HAPPY8]) {
2694
out->right_paddle1.kind = EMappingKind_Button;
2695
out->right_paddle1.target = joystick->hwdata->key_map[BTN_TRIGGER_HAPPY5];
2696
out->left_paddle1.kind = EMappingKind_Button;
2697
out->left_paddle1.target = joystick->hwdata->key_map[BTN_TRIGGER_HAPPY7];
2698
out->right_paddle2.kind = EMappingKind_Button;
2699
out->right_paddle2.target = joystick->hwdata->key_map[BTN_TRIGGER_HAPPY6];
2700
out->left_paddle2.kind = EMappingKind_Button;
2701
out->left_paddle2.target = joystick->hwdata->key_map[BTN_TRIGGER_HAPPY8];
2702
#ifdef DEBUG_GAMEPAD_MAPPING
2703
SDL_Log("Mapped RIGHT_PADDLE1 to button %d (BTN_TRIGGER_HAPPY5)", out->right_paddle1.target);
2704
SDL_Log("Mapped LEFT_PADDLE1 to button %d (BTN_TRIGGER_HAPPY7)", out->left_paddle1.target);
2705
SDL_Log("Mapped RIGHT_PADDLE2 to button %d (BTN_TRIGGER_HAPPY6)", out->right_paddle2.target);
2706
SDL_Log("Mapped LEFT_PADDLE2 to button %d (BTN_TRIGGER_HAPPY8)", out->left_paddle2.target);
2707
#endif
2708
}
2709
2710
// The Xbox Series X controllers have the Share button as KEY_RECORD
2711
if (joystick->hwdata->has_key[KEY_RECORD]) {
2712
out->misc1.kind = EMappingKind_Button;
2713
out->misc1.target = joystick->hwdata->key_map[KEY_RECORD];
2714
#ifdef DEBUG_GAMEPAD_MAPPING
2715
SDL_Log("Mapped MISC1 to button %d (KEY_RECORD)", out->misc1.target);
2716
#endif
2717
}
2718
}
2719
2720
// Cache the mapping for later
2721
item->mapping = (SDL_GamepadMapping *)SDL_malloc(sizeof(*item->mapping));
2722
if (item->mapping) {
2723
SDL_memcpy(item->mapping, out, sizeof(*out));
2724
}
2725
#ifdef DEBUG_GAMEPAD_MAPPING
2726
SDL_Log("Generated mapping for device %d", device_index);
2727
#endif
2728
result = true;
2729
2730
done:
2731
LINUX_JoystickClose(joystick);
2732
SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, false);
2733
SDL_free(joystick);
2734
2735
return result;
2736
}
2737
2738
SDL_JoystickDriver SDL_LINUX_JoystickDriver = {
2739
LINUX_JoystickInit,
2740
LINUX_JoystickGetCount,
2741
LINUX_JoystickDetect,
2742
LINUX_JoystickIsDevicePresent,
2743
LINUX_JoystickGetDeviceName,
2744
LINUX_JoystickGetDevicePath,
2745
LINUX_JoystickGetDeviceSteamVirtualGamepadSlot,
2746
LINUX_JoystickGetDevicePlayerIndex,
2747
LINUX_JoystickSetDevicePlayerIndex,
2748
LINUX_JoystickGetDeviceGUID,
2749
LINUX_JoystickGetDeviceInstanceID,
2750
LINUX_JoystickOpen,
2751
LINUX_JoystickRumble,
2752
LINUX_JoystickRumbleTriggers,
2753
LINUX_JoystickSetLED,
2754
LINUX_JoystickSendEffect,
2755
LINUX_JoystickSetSensorsEnabled,
2756
LINUX_JoystickUpdate,
2757
LINUX_JoystickClose,
2758
LINUX_JoystickQuit,
2759
LINUX_JoystickGetGamepadMapping
2760
};
2761
2762
#endif // SDL_JOYSTICK_LINUX
2763
2764