1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "SDL_internal.h"
22
23#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
135typedef enum
136{
137 ENUMERATION_UNSET,
138 ENUMERATION_LIBUDEV,
139 ENUMERATION_FALLBACK
140} EnumerationMethod;
141
142static EnumerationMethod enumeration_method = ENUMERATION_UNSET;
143
144static bool IsJoystickJSNode(const char *node);
145static void MaybeAddDevice(const char *path);
146static void MaybeRemoveDevice(const char *path);
147
148// A linked list of available joysticks
149typedef 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
165typedef 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
173static bool SDL_classic_joysticks = false;
174static SDL_joylist_item *SDL_joylist SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
175static SDL_joylist_item *SDL_joylist_tail SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
176static int numjoysticks SDL_GUARDED_BY(SDL_joystick_lock) = 0;
177static SDL_sensorlist_item *SDL_sensorlist SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
178static int inotify_fd = -1;
179
180static Uint64 last_joy_detect_time;
181static time_t last_input_dir_mtime;
182
183static 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
206static 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
216static bool IsVirtualJoystick(Uint16 vendor, Uint16 product, Uint16 version, const char *name)
217{
218 return false;
219}
220#endif // SDL_JOYSTICK_HIDAPI
221
222static 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
239static 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
261static bool GuessIsJoystick(int fd)
262{
263 if (GuessDeviceClass(fd) & SDL_UDEV_DEVICE_JOYSTICK) {
264 return true;
265 }
266 return false;
267}
268
269static bool GuessIsSensor(int fd)
270{
271 if (GuessDeviceClass(fd) & SDL_UDEV_DEVICE_ACCELEROMETER) {
272 return true;
273 }
274 return false;
275}
276
277static 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
344static 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
383static 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
420static 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
428static void FreeSensorlistItem(SDL_sensorlist_item *item)
429{
430 SDL_free(item->path);
431 SDL_free(item);
432}
433
434static 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
538done:
539 close(fd);
540 SDL_UnlockJoysticks();
541}
542
543static 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
569static 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
589static 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 }
617done:
618 SDL_UnlockJoysticks();
619}
620
621static 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
663static 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
680static 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
689static 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
698static 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
709static int SDL_inotify_init1(void)
710{
711 return inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
712}
713#else
714static 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
726static 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
768static 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). */
792static int filter_entries(const struct dirent *entry)
793{
794 return IsJoystickDeviceNode(entry->d_name);
795}
796static 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
829typedef struct
830{
831 char *path;
832 int slot;
833} VirtualGamepadEntry;
834
835static 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
842static 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
906static 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
925static 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
947static 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
966static 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
972static 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
1075static int LINUX_JoystickGetCount(void)
1076{
1077 SDL_AssertJoysticksLocked();
1078
1079 return numjoysticks;
1080}
1081
1082static 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
1102static const char *LINUX_JoystickGetDeviceName(int device_index)
1103{
1104 return GetJoystickByDevIndex(device_index)->name;
1105}
1106
1107static const char *LINUX_JoystickGetDevicePath(int device_index)
1108{
1109 return GetJoystickByDevIndex(device_index)->path;
1110}
1111
1112static int LINUX_JoystickGetDeviceSteamVirtualGamepadSlot(int device_index)
1113{
1114 return GetJoystickByDevIndex(device_index)->steam_virtual_gamepad_slot;
1115}
1116
1117static int LINUX_JoystickGetDevicePlayerIndex(int device_index)
1118{
1119 return -1;
1120}
1121
1122static void LINUX_JoystickSetDevicePlayerIndex(int device_index, int player_index)
1123{
1124}
1125
1126static 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
1132static SDL_JoystickID LINUX_JoystickGetDeviceInstanceID(int device_index)
1133{
1134 return GetJoystickByDevIndex(device_index)->device_instance;
1135}
1136
1137static 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
1147static 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
1166static 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
1198static 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. */
1455static 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
1503static 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
1558static 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
1611static 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
1654static bool LINUX_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
1655{
1656 return SDL_Unsupported();
1657}
1658
1659static bool LINUX_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
1660{
1661 return SDL_Unsupported();
1662}
1663
1664static bool LINUX_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
1665{
1666 return SDL_Unsupported();
1667}
1668
1669static 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
1699static 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
1748static void HandleBall(SDL_Joystick *stick, Uint8 ball, int axis, int value)
1749{
1750 stick->hwdata->balls[ball].axis[axis] += value;
1751}
1752
1753static 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
1788static 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
1847static 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
1882static 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
2086static 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
2133static 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
2160static 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
2191static 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 */
2233static 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
2698done:
2699 LINUX_JoystickClose(joystick);
2700 SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, false);
2701 SDL_free(joystick);
2702
2703 return result;
2704}
2705
2706SDL_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