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