SDL  2.0
SDL_sysjoystick.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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 #endif
38 #include <sys/ioctl.h>
39 #include <unistd.h>
40 #include <dirent.h>
41 #include <linux/joystick.h>
42 
43 #include "SDL_hints.h"
44 #include "SDL_joystick.h"
45 #include "SDL_log.h"
46 #include "SDL_endian.h"
47 #include "SDL_timer.h"
48 #include "../../events/SDL_events_c.h"
49 #include "../SDL_sysjoystick.h"
50 #include "../SDL_joystick_c.h"
51 #include "../steam/SDL_steamcontroller.h"
52 #include "SDL_sysjoystick_c.h"
53 #include "../hidapi/SDL_hidapijoystick_c.h"
54 
55 /* This isn't defined in older Linux kernel headers */
56 #ifndef SYN_DROPPED
57 #define SYN_DROPPED 3
58 #endif
59 #ifndef BTN_SOUTH
60 #define BTN_SOUTH 0x130
61 #endif
62 #ifndef BTN_EAST
63 #define BTN_EAST 0x131
64 #endif
65 #ifndef BTN_NORTH
66 #define BTN_NORTH 0x133
67 #endif
68 #ifndef BTN_WEST
69 #define BTN_WEST 0x134
70 #endif
71 #ifndef BTN_DPAD_UP
72 #define BTN_DPAD_UP 0x220
73 #endif
74 #ifndef BTN_DPAD_DOWN
75 #define BTN_DPAD_DOWN 0x221
76 #endif
77 #ifndef BTN_DPAD_LEFT
78 #define BTN_DPAD_LEFT 0x222
79 #endif
80 #ifndef BTN_DPAD_RIGHT
81 #define BTN_DPAD_RIGHT 0x223
82 #endif
83 
84 #include "../../core/linux/SDL_evdev_capabilities.h"
85 #include "../../core/linux/SDL_udev.h"
86 
87 #if 0
88 #define DEBUG_INPUT_EVENTS 1
89 #endif
90 
91 typedef enum
92 {
93  ENUMERATION_UNSET,
94  ENUMERATION_LIBUDEV,
95  ENUMERATION_FALLBACK
96 } EnumerationMethod;
97 
98 static EnumerationMethod enumeration_method = ENUMERATION_UNSET;
99 
100 static int MaybeAddDevice(const char *path);
101 static int MaybeRemoveDevice(const char *path);
102 
103 /* A linked list of available joysticks */
104 typedef struct SDL_joylist_item
105 {
106  int device_instance;
107  char *path; /* "/dev/input/event2" or whatever */
108  char *name; /* "SideWinder 3D Pro" or whatever */
109  SDL_JoystickGUID guid;
110  dev_t devnum;
111  struct joystick_hwdata *hwdata;
112  struct SDL_joylist_item *next;
113 
114  /* Steam Controller support */
115  SDL_bool m_bSteamController;
116 } SDL_joylist_item;
117 
118 static SDL_joylist_item *SDL_joylist = NULL;
119 static SDL_joylist_item *SDL_joylist_tail = NULL;
120 static int numjoysticks = 0;
121 static int inotify_fd = -1;
122 
123 static Uint32 last_joy_detect_time;
124 static time_t last_input_dir_mtime;
125 
126 static void
127 FixupDeviceInfoForMapping(int fd, struct input_id *inpid)
128 {
129  if (inpid->vendor == 0x045e && inpid->product == 0x0b05 && inpid->version == 0x0903) {
130  /* This is a Microsoft Xbox One Elite Series 2 controller */
131  unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
132 
133  /* The first version of the firmware duplicated all the inputs */
134  if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
135  test_bit(0x2c0, keybit)) {
136  /* Change the version to 0x0902, so we can map it differently */
137  inpid->version = 0x0902;
138  }
139  }
140 }
141 
142 #ifdef SDL_JOYSTICK_HIDAPI
143 static SDL_bool
144 IsVirtualJoystick(Uint16 vendor, Uint16 product, Uint16 version, const char *name)
145 {
146  if (vendor == USB_VENDOR_MICROSOFT && product == USB_PRODUCT_XBOX_ONE_S && version == 0 &&
147  SDL_strcmp(name, "Xbox One S Controller") == 0) {
148  /* This is the virtual device created by the xow driver */
149  return SDL_TRUE;
150  }
151  return SDL_FALSE;
152 }
153 #endif /* SDL_JOYSTICK_HIDAPI */
154 
155 static int
156 GuessIsJoystick(int fd)
157 {
158  unsigned long evbit[NBITS(EV_MAX)] = { 0 };
159  unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
160  unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
161  unsigned long relbit[NBITS(REL_MAX)] = { 0 };
162  int devclass;
163 
164  if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
165  (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
166  (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) < 0) ||
167  (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
168  return (0);
169  }
170 
171  devclass = SDL_EVDEV_GuessDeviceClass(evbit, absbit, keybit, relbit);
172 
173  if (devclass & SDL_UDEV_DEVICE_JOYSTICK) {
174  return 1;
175  }
176 
177  return 0;
178 }
179 
180 static int
181 IsJoystick(int fd, char **name_return, SDL_JoystickGUID *guid)
182 {
183  struct input_id inpid;
184  Uint16 *guid16 = (Uint16 *)guid->data;
185  char *name;
186  char product_string[128];
187 
188  /* When udev is enabled we only get joystick devices here, so there's no need to test them */
189  if (enumeration_method != ENUMERATION_LIBUDEV && !GuessIsJoystick(fd)) {
190  return 0;
191  }
192 
193  if (ioctl(fd, EVIOCGID, &inpid) < 0) {
194  return 0;
195  }
196 
197  if (ioctl(fd, EVIOCGNAME(sizeof(product_string)), product_string) < 0) {
198  return 0;
199  }
200 
201  name = SDL_CreateJoystickName(inpid.vendor, inpid.product, NULL, product_string);
202  if (!name) {
203  return 0;
204  }
205 
206 #ifdef SDL_JOYSTICK_HIDAPI
207  if (!IsVirtualJoystick(inpid.vendor, inpid.product, inpid.version, name) &&
208  HIDAPI_IsDevicePresent(inpid.vendor, inpid.product, inpid.version, name)) {
209  /* The HIDAPI driver is taking care of this device */
210  SDL_free(name);
211  return 0;
212  }
213 #endif
214 
215  FixupDeviceInfoForMapping(fd, &inpid);
216 
217 #ifdef DEBUG_JOYSTICK
218  printf("Joystick: %s, bustype = %d, vendor = 0x%.4x, product = 0x%.4x, version = %d\n", name, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
219 #endif
220 
221  SDL_memset(guid->data, 0, sizeof(guid->data));
222 
223  /* We only need 16 bits for each of these; space them out to fill 128. */
224  /* Byteswap so devices get same GUID on little/big endian platforms. */
225  *guid16++ = SDL_SwapLE16(inpid.bustype);
226  *guid16++ = 0;
227 
228  if (inpid.vendor && inpid.product) {
229  *guid16++ = SDL_SwapLE16(inpid.vendor);
230  *guid16++ = 0;
231  *guid16++ = SDL_SwapLE16(inpid.product);
232  *guid16++ = 0;
233  *guid16++ = SDL_SwapLE16(inpid.version);
234  *guid16++ = 0;
235  } else {
236  SDL_strlcpy((char*)guid16, name, sizeof(guid->data) - 4);
237  }
238 
239  if (SDL_ShouldIgnoreJoystick(name, *guid)) {
240  SDL_free(name);
241  return 0;
242  }
243  *name_return = name;
244  return 1;
245 }
246 
247 #if SDL_USE_LIBUDEV
248 static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
249 {
250  if (devpath == NULL) {
251  return;
252  }
253 
254  switch (udev_type) {
255  case SDL_UDEV_DEVICEADDED:
256  if (!(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
257  return;
258  }
259  MaybeAddDevice(devpath);
260  break;
261 
262  case SDL_UDEV_DEVICEREMOVED:
263  MaybeRemoveDevice(devpath);
264  break;
265 
266  default:
267  break;
268  }
269 
270 }
271 #endif /* SDL_USE_LIBUDEV */
272 
273 static int
274 MaybeAddDevice(const char *path)
275 {
276  struct stat sb;
277  int fd = -1;
278  int isstick = 0;
279  char *name = NULL;
280  SDL_JoystickGUID guid;
281  SDL_joylist_item *item;
282 
283  if (path == NULL) {
284  return -1;
285  }
286 
287  if (stat(path, &sb) == -1) {
288  return -1;
289  }
290 
291  /* Check to make sure it's not already in list. */
292  for (item = SDL_joylist; item != NULL; item = item->next) {
293  if (sb.st_rdev == item->devnum) {
294  return -1; /* already have this one */
295  }
296  }
297 
298  fd = open(path, O_RDONLY, 0);
299  if (fd < 0) {
300  return -1;
301  }
302 
303 #ifdef DEBUG_INPUT_EVENTS
304  printf("Checking %s\n", path);
305 #endif
306 
307  isstick = IsJoystick(fd, &name, &guid);
308  close(fd);
309  if (!isstick) {
310  return -1;
311  }
312 
313  item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
314  if (item == NULL) {
315  return -1;
316  }
317 
318  SDL_zerop(item);
319  item->devnum = sb.st_rdev;
320  item->path = SDL_strdup(path);
321  item->name = name;
322  item->guid = guid;
323 
324  if ((item->path == NULL) || (item->name == NULL)) {
325  SDL_free(item->path);
326  SDL_free(item->name);
327  SDL_free(item);
328  return -1;
329  }
330 
331  item->device_instance = SDL_GetNextJoystickInstanceID();
332  if (SDL_joylist_tail == NULL) {
333  SDL_joylist = SDL_joylist_tail = item;
334  } else {
335  SDL_joylist_tail->next = item;
336  SDL_joylist_tail = item;
337  }
338 
339  /* Need to increment the joystick count before we post the event */
340  ++numjoysticks;
341 
342  SDL_PrivateJoystickAdded(item->device_instance);
343 
344  return numjoysticks;
345 }
346 
347 static int
348 MaybeRemoveDevice(const char *path)
349 {
350  SDL_joylist_item *item;
351  SDL_joylist_item *prev = NULL;
352 
353  if (path == NULL) {
354  return -1;
355  }
356 
357  for (item = SDL_joylist; item != NULL; item = item->next) {
358  /* found it, remove it. */
359  if (SDL_strcmp(path, item->path) == 0) {
360  const int retval = item->device_instance;
361  if (item->hwdata) {
362  item->hwdata->item = NULL;
363  }
364  if (prev != NULL) {
365  prev->next = item->next;
366  } else {
367  SDL_assert(SDL_joylist == item);
368  SDL_joylist = item->next;
369  }
370  if (item == SDL_joylist_tail) {
371  SDL_joylist_tail = prev;
372  }
373 
374  /* Need to decrement the joystick count before we post the event */
375  --numjoysticks;
376 
377  SDL_PrivateJoystickRemoved(item->device_instance);
378 
379  SDL_free(item->path);
380  SDL_free(item->name);
381  SDL_free(item);
382  return retval;
383  }
384  prev = item;
385  }
386 
387  return -1;
388 }
389 
390 static void
391 HandlePendingRemovals(void)
392 {
393  SDL_joylist_item *prev = NULL;
394  SDL_joylist_item *item = SDL_joylist;
395 
396  while (item != NULL) {
397  if (item->hwdata && item->hwdata->gone) {
398  item->hwdata->item = NULL;
399 
400  if (prev != NULL) {
401  prev->next = item->next;
402  } else {
403  SDL_assert(SDL_joylist == item);
404  SDL_joylist = item->next;
405  }
406  if (item == SDL_joylist_tail) {
407  SDL_joylist_tail = prev;
408  }
409 
410  /* Need to decrement the joystick count before we post the event */
411  --numjoysticks;
412 
413  SDL_PrivateJoystickRemoved(item->device_instance);
414 
415  SDL_free(item->path);
416  SDL_free(item->name);
417  SDL_free(item);
418 
419  if (prev != NULL) {
420  item = prev->next;
421  } else {
422  item = SDL_joylist;
423  }
424  } else {
425  prev = item;
426  item = item->next;
427  }
428  }
429 }
430 
431 static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickGUID guid, int *device_instance)
432 {
433  SDL_joylist_item *item;
434 
435  item = (SDL_joylist_item *) SDL_calloc(1, sizeof (SDL_joylist_item));
436  if (item == NULL) {
437  return SDL_FALSE;
438  }
439 
440  item->path = SDL_strdup("");
441  item->name = SDL_strdup(name);
442  item->guid = guid;
443  item->m_bSteamController = SDL_TRUE;
444 
445  if ((item->path == NULL) || (item->name == NULL)) {
446  SDL_free(item->path);
447  SDL_free(item->name);
448  SDL_free(item);
449  return SDL_FALSE;
450  }
451 
452  *device_instance = item->device_instance = SDL_GetNextJoystickInstanceID();
453  if (SDL_joylist_tail == NULL) {
454  SDL_joylist = SDL_joylist_tail = item;
455  } else {
456  SDL_joylist_tail->next = item;
457  SDL_joylist_tail = item;
458  }
459 
460  /* Need to increment the joystick count before we post the event */
461  ++numjoysticks;
462 
463  SDL_PrivateJoystickAdded(item->device_instance);
464 
465  return SDL_TRUE;
466 }
467 
468 static void SteamControllerDisconnectedCallback(int device_instance)
469 {
470  SDL_joylist_item *item;
471  SDL_joylist_item *prev = NULL;
472 
473  for (item = SDL_joylist; item != NULL; item = item->next) {
474  /* found it, remove it. */
475  if (item->device_instance == device_instance) {
476  if (item->hwdata) {
477  item->hwdata->item = NULL;
478  }
479  if (prev != NULL) {
480  prev->next = item->next;
481  } else {
482  SDL_assert(SDL_joylist == item);
483  SDL_joylist = item->next;
484  }
485  if (item == SDL_joylist_tail) {
486  SDL_joylist_tail = prev;
487  }
488 
489  /* Need to decrement the joystick count before we post the event */
490  --numjoysticks;
491 
492  SDL_PrivateJoystickRemoved(item->device_instance);
493 
494  SDL_free(item->name);
495  SDL_free(item);
496  return;
497  }
498  prev = item;
499  }
500 }
501 
502 #ifdef HAVE_INOTIFY
503 #ifdef HAVE_INOTIFY_INIT1
504 static int SDL_inotify_init1(void) {
505  return inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
506 }
507 #else
508 static int SDL_inotify_init1(void) {
509  int fd = inotify_init();
510  if (fd < 0) return -1;
511  fcntl(fd, F_SETFL, O_NONBLOCK);
512  fcntl(fd, F_SETFD, FD_CLOEXEC);
513  return fd;
514 }
515 #endif
516 
517 static int
518 StrHasPrefix(const char *string, const char *prefix)
519 {
520  return (SDL_strncmp(string, prefix, SDL_strlen(prefix)) == 0);
521 }
522 
523 static int
524 StrIsInteger(const char *string)
525 {
526  const char *p;
527 
528  if (*string == '\0') {
529  return 0;
530  }
531 
532  for (p = string; *p != '\0'; p++) {
533  if (*p < '0' || *p > '9') {
534  return 0;
535  }
536  }
537 
538  return 1;
539 }
540 
541 static void
542 LINUX_InotifyJoystickDetect(void)
543 {
544  union
545  {
546  struct inotify_event event;
547  char storage[4096];
548  char enough_for_inotify[sizeof (struct inotify_event) + NAME_MAX + 1];
549  } buf;
550  ssize_t bytes;
551  size_t remain = 0;
552  size_t len;
553 
554  bytes = read(inotify_fd, &buf, sizeof (buf));
555 
556  if (bytes > 0) {
557  remain = (size_t) bytes;
558  }
559 
560  while (remain > 0) {
561  if (buf.event.len > 0) {
562  if (StrHasPrefix(buf.event.name, "event") &&
563  StrIsInteger(buf.event.name + strlen ("event"))) {
564  char path[PATH_MAX];
565 
566  SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", buf.event.name);
567 
568  if (buf.event.mask & (IN_CREATE | IN_MOVED_TO | IN_ATTRIB)) {
569  MaybeAddDevice(path);
570  }
571  else if (buf.event.mask & (IN_DELETE | IN_MOVED_FROM)) {
572  MaybeRemoveDevice(path);
573  }
574  }
575  }
576 
577  len = sizeof (struct inotify_event) + buf.event.len;
578  remain -= len;
579 
580  if (remain != 0) {
581  memmove (&buf.storage[0], &buf.storage[len], remain);
582  }
583  }
584 }
585 #endif /* HAVE_INOTIFY */
586 
587 /* Detect devices by reading /dev/input. In the inotify code path we
588  * have to do this the first time, to detect devices that already existed
589  * before we started; in the non-inotify code path we do this repeatedly
590  * (polling). */
591 static void
592 LINUX_FallbackJoystickDetect(void)
593 {
594  const Uint32 SDL_JOY_DETECT_INTERVAL_MS = 3000; /* Update every 3 seconds */
595  Uint32 now = SDL_GetTicks();
596 
597  if (!last_joy_detect_time || SDL_TICKS_PASSED(now, last_joy_detect_time + SDL_JOY_DETECT_INTERVAL_MS)) {
598  struct stat sb;
599 
600  /* Opening input devices can generate synchronous device I/O, so avoid it if we can */
601  if (stat("/dev/input", &sb) == 0 && sb.st_mtime != last_input_dir_mtime) {
602  DIR *folder;
603  struct dirent *dent;
604 
605  folder = opendir("/dev/input");
606  if (folder) {
607  while ((dent = readdir(folder))) {
608  int len = SDL_strlen(dent->d_name);
609  if (len > 5 && SDL_strncmp(dent->d_name, "event", 5) == 0) {
610  char path[PATH_MAX];
611  SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", dent->d_name);
612  MaybeAddDevice(path);
613  }
614  }
615 
616  closedir(folder);
617  }
618 
619  last_input_dir_mtime = sb.st_mtime;
620  }
621 
622  last_joy_detect_time = now;
623  }
624 }
625 
626 static void
627 LINUX_JoystickDetect(void)
628 {
629 #if SDL_USE_LIBUDEV
630  if (enumeration_method == ENUMERATION_LIBUDEV) {
631  SDL_UDEV_Poll();
632  }
633  else
634 #endif
635 #ifdef HAVE_INOTIFY
636  if (inotify_fd >= 0 && last_joy_detect_time != 0) {
637  LINUX_InotifyJoystickDetect();
638  }
639  else
640 #endif
641  {
642  LINUX_FallbackJoystickDetect();
643  }
644 
645  HandlePendingRemovals();
646 
648 }
649 
650 static int
651 LINUX_JoystickInit(void)
652 {
653 #if SDL_USE_LIBUDEV
654  if (enumeration_method == ENUMERATION_UNSET) {
655  if (SDL_getenv("SDL_JOYSTICK_DISABLE_UDEV") != NULL) {
657  "udev disabled by SDL_JOYSTICK_DISABLE_UDEV");
658  enumeration_method = ENUMERATION_FALLBACK;
659  }
660  else if (access("/.flatpak-info", F_OK) == 0
661  || access("/run/pressure-vessel", F_OK) == 0) {
663  "Container detected, disabling udev integration");
664  enumeration_method = ENUMERATION_FALLBACK;
665  }
666  else {
668  "Using udev for joystick device discovery");
669  enumeration_method = ENUMERATION_LIBUDEV;
670  }
671  }
672 #endif
673 
674  /* First see if the user specified one or more joysticks to use */
675  if (SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL) {
676  char *envcopy, *envpath, *delim;
677  envcopy = SDL_strdup(SDL_getenv("SDL_JOYSTICK_DEVICE"));
678  envpath = envcopy;
679  while (envpath != NULL) {
680  delim = SDL_strchr(envpath, ':');
681  if (delim != NULL) {
682  *delim++ = '\0';
683  }
684  MaybeAddDevice(envpath);
685  envpath = delim;
686  }
687  SDL_free(envcopy);
688  }
689 
690  SDL_InitSteamControllers(SteamControllerConnectedCallback,
691  SteamControllerDisconnectedCallback);
692 
693  /* Force immediate joystick detection if using fallback */
694  last_joy_detect_time = 0;
695  last_input_dir_mtime = 0;
696 
697 #if SDL_USE_LIBUDEV
698  if (enumeration_method == ENUMERATION_LIBUDEV) {
699  if (SDL_UDEV_Init() < 0) {
700  return SDL_SetError("Could not initialize UDEV");
701  }
702 
703  /* Set up the udev callback */
704  if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
705  SDL_UDEV_Quit();
706  return SDL_SetError("Could not set up joystick <-> udev callback");
707  }
708 
709  /* Force a scan to build the initial device list */
710  SDL_UDEV_Scan();
711  }
712  else
713 #endif
714  {
715 #if defined(HAVE_INOTIFY)
716  inotify_fd = SDL_inotify_init1();
717 
718  if (inotify_fd < 0) {
720  "Unable to initialize inotify, falling back to polling: %s",
721  strerror (errno));
722  } else {
723  /* We need to watch for attribute changes in addition to
724  * creation, because when a device is first created, it has
725  * permissions that we can't read. When udev chmods it to
726  * something that we maybe *can* read, we'll get an
727  * IN_ATTRIB event to tell us. */
728  if (inotify_add_watch(inotify_fd, "/dev/input",
729  IN_CREATE | IN_DELETE | IN_MOVE | IN_ATTRIB) < 0) {
730  close(inotify_fd);
731  inotify_fd = -1;
733  "Unable to add inotify watch, falling back to polling: %s",
734  strerror (errno));
735  }
736  }
737 #endif /* HAVE_INOTIFY */
738 
739  /* Report all devices currently present */
740  LINUX_JoystickDetect();
741  }
742 
743  return 0;
744 }
745 
746 static int
747 LINUX_JoystickGetCount(void)
748 {
749  return numjoysticks;
750 }
751 
752 static SDL_joylist_item *
753 JoystickByDevIndex(int device_index)
754 {
755  SDL_joylist_item *item = SDL_joylist;
756 
757  if ((device_index < 0) || (device_index >= numjoysticks)) {
758  return NULL;
759  }
760 
761  while (device_index > 0) {
762  SDL_assert(item != NULL);
763  device_index--;
764  item = item->next;
765  }
766 
767  return item;
768 }
769 
770 /* Function to get the device-dependent name of a joystick */
771 static const char *
772 LINUX_JoystickGetDeviceName(int device_index)
773 {
774  return JoystickByDevIndex(device_index)->name;
775 }
776 
777 static int
778 LINUX_JoystickGetDevicePlayerIndex(int device_index)
779 {
780  return -1;
781 }
782 
783 static void
784 LINUX_JoystickSetDevicePlayerIndex(int device_index, int player_index)
785 {
786 }
787 
788 static SDL_JoystickGUID
789 LINUX_JoystickGetDeviceGUID( int device_index )
790 {
791  return JoystickByDevIndex(device_index)->guid;
792 }
793 
794 /* Function to perform the mapping from device index to the instance id for this index */
795 static SDL_JoystickID
796 LINUX_JoystickGetDeviceInstanceID(int device_index)
797 {
798  return JoystickByDevIndex(device_index)->device_instance;
799 }
800 
801 static int
802 allocate_hatdata(SDL_Joystick *joystick)
803 {
804  int i;
805 
806  joystick->hwdata->hats =
807  (struct hwdata_hat *) SDL_malloc(joystick->nhats *
808  sizeof(struct hwdata_hat));
809  if (joystick->hwdata->hats == NULL) {
810  return (-1);
811  }
812  for (i = 0; i < joystick->nhats; ++i) {
813  joystick->hwdata->hats[i].axis[0] = 1;
814  joystick->hwdata->hats[i].axis[1] = 1;
815  }
816  return (0);
817 }
818 
819 static int
820 allocate_balldata(SDL_Joystick *joystick)
821 {
822  int i;
823 
824  joystick->hwdata->balls =
825  (struct hwdata_ball *) SDL_malloc(joystick->nballs *
826  sizeof(struct hwdata_ball));
827  if (joystick->hwdata->balls == NULL) {
828  return (-1);
829  }
830  for (i = 0; i < joystick->nballs; ++i) {
831  joystick->hwdata->balls[i].axis[0] = 0;
832  joystick->hwdata->balls[i].axis[1] = 0;
833  }
834  return (0);
835 }
836 
837 static void
838 ConfigJoystick(SDL_Joystick *joystick, int fd)
839 {
840  int i, t;
841  unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
842  unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
843  unsigned long relbit[NBITS(REL_MAX)] = { 0 };
844  unsigned long ffbit[NBITS(FF_MAX)] = { 0 };
846 
847  /* See if this device uses the new unified event API */
848  if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
849  (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
850  (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) {
851 
852  /* Get the number of buttons, axes, and other thingamajigs */
853  for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
854  if (test_bit(i, keybit)) {
855 #ifdef DEBUG_INPUT_EVENTS
856  printf("Joystick has button: 0x%x\n", i);
857 #endif
858  joystick->hwdata->key_map[i] = joystick->nbuttons;
859  joystick->hwdata->has_key[i] = SDL_TRUE;
860  ++joystick->nbuttons;
861  }
862  }
863  for (i = 0; i < BTN_JOYSTICK; ++i) {
864  if (test_bit(i, keybit)) {
865 #ifdef DEBUG_INPUT_EVENTS
866  printf("Joystick has button: 0x%x\n", i);
867 #endif
868  joystick->hwdata->key_map[i] = joystick->nbuttons;
869  joystick->hwdata->has_key[i] = SDL_TRUE;
870  ++joystick->nbuttons;
871  }
872  }
873  for (i = 0; i < ABS_MAX; ++i) {
874  /* Skip hats */
875  if (i == ABS_HAT0X) {
876  i = ABS_HAT3Y;
877  continue;
878  }
879  if (test_bit(i, absbit)) {
880  struct input_absinfo absinfo;
881  struct axis_correct *correct = &joystick->hwdata->abs_correct[i];
882 
883  if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
884  continue;
885  }
886 #ifdef DEBUG_INPUT_EVENTS
887  printf("Joystick has absolute axis: 0x%.2x\n", i);
888  printf("Values = { %d, %d, %d, %d, %d }\n",
889  absinfo.value, absinfo.minimum, absinfo.maximum,
890  absinfo.fuzz, absinfo.flat);
891 #endif /* DEBUG_INPUT_EVENTS */
892  joystick->hwdata->abs_map[i] = joystick->naxes;
893  joystick->hwdata->has_abs[i] = SDL_TRUE;
894 
895  correct->minimum = absinfo.minimum;
896  correct->maximum = absinfo.maximum;
897  if (correct->minimum != correct->maximum) {
898  if (use_deadzones) {
899  correct->use_deadzones = SDL_TRUE;
900  correct->coef[0] = (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
901  correct->coef[1] = (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
902  t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
903  if (t != 0) {
904  correct->coef[2] = (1 << 28) / t;
905  } else {
906  correct->coef[2] = 0;
907  }
908  } else {
909  float value_range = (correct->maximum - correct->minimum);
910  float output_range = (SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN);
911 
912  correct->scale = (output_range / value_range);
913  }
914  }
915  ++joystick->naxes;
916  }
917  }
918  for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
919  if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
920  struct input_absinfo absinfo;
921  int hat_index = (i - ABS_HAT0X) / 2;
922 
923  if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
924  continue;
925  }
926 #ifdef DEBUG_INPUT_EVENTS
927  printf("Joystick has hat %d\n", hat_index);
928  printf("Values = { %d, %d, %d, %d, %d }\n",
929  absinfo.value, absinfo.minimum, absinfo.maximum,
930  absinfo.fuzz, absinfo.flat);
931 #endif /* DEBUG_INPUT_EVENTS */
932  joystick->hwdata->hats_indices[hat_index] = joystick->nhats++;
933  joystick->hwdata->has_hat[hat_index] = SDL_TRUE;
934  }
935  }
936  if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
937  ++joystick->nballs;
938  }
939 
940  /* Allocate data to keep track of these thingamajigs */
941  if (joystick->nhats > 0) {
942  if (allocate_hatdata(joystick) < 0) {
943  joystick->nhats = 0;
944  }
945  }
946  if (joystick->nballs > 0) {
947  if (allocate_balldata(joystick) < 0) {
948  joystick->nballs = 0;
949  }
950  }
951  }
952 
953  if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) >= 0) {
954  if (test_bit(FF_RUMBLE, ffbit)) {
955  joystick->hwdata->ff_rumble = SDL_TRUE;
956  }
957  if (test_bit(FF_SINE, ffbit)) {
958  joystick->hwdata->ff_sine = SDL_TRUE;
959  }
960  }
961 }
962 
963 
964 /* Function to open a joystick for use.
965  The joystick to open is specified by the device index.
966  This should fill the nbuttons and naxes fields of the joystick structure.
967  It returns 0, or -1 if there is an error.
968  */
969 static int
970 LINUX_JoystickOpen(SDL_Joystick *joystick, int device_index)
971 {
972  SDL_joylist_item *item = JoystickByDevIndex(device_index);
973 
974  if (item == NULL) {
975  return SDL_SetError("No such device");
976  }
977 
978  joystick->instance_id = item->device_instance;
979  joystick->hwdata = (struct joystick_hwdata *)
980  SDL_calloc(1, sizeof(*joystick->hwdata));
981  if (joystick->hwdata == NULL) {
982  return SDL_OutOfMemory();
983  }
984  joystick->hwdata->item = item;
985  joystick->hwdata->guid = item->guid;
986  joystick->hwdata->effect.id = -1;
987  joystick->hwdata->m_bSteamController = item->m_bSteamController;
988  SDL_memset(joystick->hwdata->abs_map, 0xFF, sizeof(joystick->hwdata->abs_map));
989 
990  if (item->m_bSteamController) {
991  joystick->hwdata->fd = -1;
993  &joystick->naxes,
994  &joystick->nhats);
995  } else {
996  int fd = open(item->path, O_RDWR, 0);
997  if (fd < 0) {
998  SDL_free(joystick->hwdata);
999  joystick->hwdata = NULL;
1000  return SDL_SetError("Unable to open %s", item->path);
1001  }
1002 
1003  joystick->hwdata->fd = fd;
1004  joystick->hwdata->fname = SDL_strdup(item->path);
1005  if (joystick->hwdata->fname == NULL) {
1006  SDL_free(joystick->hwdata);
1007  joystick->hwdata = NULL;
1008  close(fd);
1009  return SDL_OutOfMemory();
1010  }
1011 
1012  /* Set the joystick to non-blocking read mode */
1013  fcntl(fd, F_SETFL, O_NONBLOCK);
1014 
1015  /* Get the number of buttons and axes on the joystick */
1016  ConfigJoystick(joystick, fd);
1017  }
1018 
1019  SDL_assert(item->hwdata == NULL);
1020  item->hwdata = joystick->hwdata;
1021 
1022  /* mark joystick as fresh and ready */
1023  joystick->hwdata->fresh = SDL_TRUE;
1024 
1025  return (0);
1026 }
1027 
1028 static int
1029 LINUX_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
1030 {
1031  struct input_event event;
1032 
1033  if (joystick->hwdata->ff_rumble) {
1034  struct ff_effect *effect = &joystick->hwdata->effect;
1035 
1036  effect->type = FF_RUMBLE;
1037  effect->replay.length = SDL_MAX_RUMBLE_DURATION_MS;
1038  effect->u.rumble.strong_magnitude = low_frequency_rumble;
1039  effect->u.rumble.weak_magnitude = high_frequency_rumble;
1040  } else if (joystick->hwdata->ff_sine) {
1041  /* Scale and average the two rumble strengths */
1042  Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
1043  struct ff_effect *effect = &joystick->hwdata->effect;
1044 
1045  effect->type = FF_PERIODIC;
1046  effect->replay.length = SDL_MAX_RUMBLE_DURATION_MS;
1047  effect->u.periodic.waveform = FF_SINE;
1048  effect->u.periodic.magnitude = magnitude;
1049  } else {
1050  return SDL_Unsupported();
1051  }
1052 
1053  if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
1054  /* The kernel may have lost this effect, try to allocate a new one */
1055  joystick->hwdata->effect.id = -1;
1056  if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
1057  return SDL_SetError("Couldn't update rumble effect: %s", strerror(errno));
1058  }
1059  }
1060 
1061  event.type = EV_FF;
1062  event.code = joystick->hwdata->effect.id;
1063  event.value = 1;
1064  if (write(joystick->hwdata->fd, &event, sizeof(event)) < 0) {
1065  return SDL_SetError("Couldn't start rumble effect: %s", strerror(errno));
1066  }
1067  return 0;
1068 }
1069 
1070 static int
1071 LINUX_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
1072 {
1073  return SDL_Unsupported();
1074 }
1075 
1076 static SDL_bool
1077 LINUX_JoystickHasLED(SDL_Joystick *joystick)
1078 {
1079  return SDL_FALSE;
1080 }
1081 
1082 static int
1083 LINUX_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
1084 {
1085  return SDL_Unsupported();
1086 }
1087 
1088 static int
1089 LINUX_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
1090 {
1091  return SDL_Unsupported();
1092 }
1093 
1094 static SDL_INLINE void
1095 HandleHat(SDL_Joystick *stick, Uint8 hat, int axis, int value)
1096 {
1097  struct hwdata_hat *the_hat;
1098  const Uint8 position_map[3][3] = {
1102  };
1103 
1104  the_hat = &stick->hwdata->hats[hat];
1105  if (value < 0) {
1106  value = 0;
1107  } else if (value == 0) {
1108  value = 1;
1109  } else if (value > 0) {
1110  value = 2;
1111  }
1112  if (value != the_hat->axis[axis]) {
1113  the_hat->axis[axis] = value;
1114  SDL_PrivateJoystickHat(stick, hat,
1115  position_map[the_hat->axis[1]][the_hat->axis[0]]);
1116  }
1117 }
1118 
1119 static SDL_INLINE void
1120 HandleBall(SDL_Joystick *stick, Uint8 ball, int axis, int value)
1121 {
1122  stick->hwdata->balls[ball].axis[axis] += value;
1123 }
1124 
1125 
1126 static SDL_INLINE int
1127 AxisCorrect(SDL_Joystick *joystick, int which, int value)
1128 {
1129  struct axis_correct *correct;
1130 
1131  correct = &joystick->hwdata->abs_correct[which];
1132  if (correct->minimum != correct->maximum) {
1133  if (correct->use_deadzones) {
1134  value *= 2;
1135  if (value > correct->coef[0]) {
1136  if (value < correct->coef[1]) {
1137  return 0;
1138  }
1139  value -= correct->coef[1];
1140  } else {
1141  value -= correct->coef[0];
1142  }
1143  value *= correct->coef[2];
1144  value >>= 13;
1145  } else {
1146  value = (int)SDL_floorf((value - correct->minimum) * correct->scale + SDL_JOYSTICK_AXIS_MIN + 0.5f);
1147  }
1148  }
1149 
1150  /* Clamp and return */
1151  if (value < SDL_JOYSTICK_AXIS_MIN) {
1152  return SDL_JOYSTICK_AXIS_MIN;
1153  }
1154  if (value > SDL_JOYSTICK_AXIS_MAX) {
1155  return SDL_JOYSTICK_AXIS_MAX;
1156  }
1157  return value;
1158 }
1159 
1160 static SDL_INLINE void
1161 PollAllValues(SDL_Joystick *joystick)
1162 {
1163  struct input_absinfo absinfo;
1164  unsigned long keyinfo[NBITS(KEY_MAX)];
1165  int i;
1166 
1167  /* Poll all axis */
1168  for (i = ABS_X; i < ABS_MAX; i++) {
1169  if (i == ABS_HAT0X) { /* we handle hats in the next loop, skip them for now. */
1170  i = ABS_HAT3Y;
1171  continue;
1172  }
1173  if (joystick->hwdata->has_abs[i]) {
1174  if (ioctl(joystick->hwdata->fd, EVIOCGABS(i), &absinfo) >= 0) {
1175  absinfo.value = AxisCorrect(joystick, i, absinfo.value);
1176 
1177 #ifdef DEBUG_INPUT_EVENTS
1178  printf("Joystick : Re-read Axis %d (%d) val= %d\n",
1179  joystick->hwdata->abs_map[i], i, absinfo.value);
1180 #endif
1182  joystick->hwdata->abs_map[i],
1183  absinfo.value);
1184  }
1185  }
1186  }
1187 
1188  /* Poll all hats */
1189  for (i = ABS_HAT0X; i <= ABS_HAT3Y; i++) {
1190  const int baseaxis = i - ABS_HAT0X;
1191  const int hatidx = baseaxis / 2;
1192  SDL_assert(hatidx < SDL_arraysize(joystick->hwdata->has_hat));
1193  if (joystick->hwdata->has_hat[hatidx]) {
1194  if (ioctl(joystick->hwdata->fd, EVIOCGABS(i), &absinfo) >= 0) {
1195  const int hataxis = baseaxis % 2;
1196  HandleHat(joystick, joystick->hwdata->hats_indices[hatidx], hataxis, absinfo.value);
1197  }
1198  }
1199  }
1200 
1201  /* Poll all buttons */
1202  SDL_zeroa(keyinfo);
1203  if (ioctl(joystick->hwdata->fd, EVIOCGKEY(sizeof (keyinfo)), keyinfo) >= 0) {
1204  for (i = 0; i < KEY_MAX; i++) {
1205  if (joystick->hwdata->has_key[i]) {
1206  const Uint8 value = test_bit(i, keyinfo) ? SDL_PRESSED : SDL_RELEASED;
1207 #ifdef DEBUG_INPUT_EVENTS
1208  printf("Joystick : Re-read Button %d (%d) val= %d\n",
1209  joystick->hwdata->key_map[i], i, value);
1210 #endif
1212  joystick->hwdata->key_map[i], value);
1213  }
1214  }
1215  }
1216 
1217  /* Joyballs are relative input, so there's no poll state. Events only! */
1218 }
1219 
1220 static SDL_INLINE void
1221 HandleInputEvents(SDL_Joystick *joystick)
1222 {
1223  struct input_event events[32];
1224  int i, len;
1225  int code;
1226 
1227  if (joystick->hwdata->fresh) {
1228  PollAllValues(joystick);
1229  joystick->hwdata->fresh = SDL_FALSE;
1230  }
1231 
1232  while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
1233  len /= sizeof(events[0]);
1234  for (i = 0; i < len; ++i) {
1235  code = events[i].code;
1236 
1237  /* If the kernel sent a SYN_DROPPED, we are supposed to ignore the
1238  rest of the packet (the end of it signified by a SYN_REPORT) */
1239  if ( joystick->hwdata->recovering_from_dropped &&
1240  ((events[i].type != EV_SYN) || (code != SYN_REPORT)) ) {
1241  continue;
1242  }
1243 
1244  switch (events[i].type) {
1245  case EV_KEY:
1247  joystick->hwdata->key_map[code],
1248  events[i].value);
1249  break;
1250  case EV_ABS:
1251  switch (code) {
1252  case ABS_HAT0X:
1253  case ABS_HAT0Y:
1254  case ABS_HAT1X:
1255  case ABS_HAT1Y:
1256  case ABS_HAT2X:
1257  case ABS_HAT2Y:
1258  case ABS_HAT3X:
1259  case ABS_HAT3Y:
1260  code -= ABS_HAT0X;
1261  HandleHat(joystick, joystick->hwdata->hats_indices[code / 2], code % 2, events[i].value);
1262  break;
1263  default:
1264  if (joystick->hwdata->abs_map[code] != 0xFF) {
1265  events[i].value =
1266  AxisCorrect(joystick, code, events[i].value);
1268  joystick->hwdata->abs_map[code],
1269  events[i].value);
1270  }
1271  break;
1272  }
1273  break;
1274  case EV_REL:
1275  switch (code) {
1276  case REL_X:
1277  case REL_Y:
1278  code -= REL_X;
1279  HandleBall(joystick, code / 2, code % 2, events[i].value);
1280  break;
1281  default:
1282  break;
1283  }
1284  break;
1285  case EV_SYN:
1286  switch (code) {
1287  case SYN_DROPPED :
1288 #ifdef DEBUG_INPUT_EVENTS
1289  printf("Event SYN_DROPPED detected\n");
1290 #endif
1291  joystick->hwdata->recovering_from_dropped = SDL_TRUE;
1292  break;
1293  case SYN_REPORT :
1294  if (joystick->hwdata->recovering_from_dropped) {
1295  joystick->hwdata->recovering_from_dropped = SDL_FALSE;
1296  PollAllValues(joystick); /* try to sync up to current state now */
1297  }
1298  break;
1299  default:
1300  break;
1301  }
1302  default:
1303  break;
1304  }
1305  }
1306  }
1307 
1308  if (errno == ENODEV) {
1309  /* We have to wait until the JoystickDetect callback to remove this */
1310  joystick->hwdata->gone = SDL_TRUE;
1311  }
1312 }
1313 
1314 static void
1315 LINUX_JoystickUpdate(SDL_Joystick *joystick)
1316 {
1317  int i;
1318 
1319  if (joystick->hwdata->m_bSteamController) {
1321  return;
1322  }
1323 
1324  HandleInputEvents(joystick);
1325 
1326  /* Deliver ball motion updates */
1327  for (i = 0; i < joystick->nballs; ++i) {
1328  int xrel, yrel;
1329 
1330  xrel = joystick->hwdata->balls[i].axis[0];
1331  yrel = joystick->hwdata->balls[i].axis[1];
1332  if (xrel || yrel) {
1333  joystick->hwdata->balls[i].axis[0] = 0;
1334  joystick->hwdata->balls[i].axis[1] = 0;
1335  SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
1336  }
1337  }
1338 }
1339 
1340 /* Function to close a joystick after use */
1341 static void
1342 LINUX_JoystickClose(SDL_Joystick *joystick)
1343 {
1344  if (joystick->hwdata) {
1345  if (joystick->hwdata->effect.id >= 0) {
1346  ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id);
1347  joystick->hwdata->effect.id = -1;
1348  }
1349  if (joystick->hwdata->fd >= 0) {
1350  close(joystick->hwdata->fd);
1351  }
1352  if (joystick->hwdata->item) {
1353  joystick->hwdata->item->hwdata = NULL;
1354  }
1355  SDL_free(joystick->hwdata->hats);
1356  SDL_free(joystick->hwdata->balls);
1357  SDL_free(joystick->hwdata->fname);
1358  SDL_free(joystick->hwdata);
1359  }
1360 }
1361 
1362 /* Function to perform any system-specific joystick related cleanup */
1363 static void
1364 LINUX_JoystickQuit(void)
1365 {
1366  SDL_joylist_item *item = NULL;
1367  SDL_joylist_item *next = NULL;
1368 
1369  if (inotify_fd >= 0) {
1370  close(inotify_fd);
1371  inotify_fd = -1;
1372  }
1373 
1374  for (item = SDL_joylist; item; item = next) {
1375  next = item->next;
1376  SDL_free(item->path);
1377  SDL_free(item->name);
1378  SDL_free(item);
1379  }
1380 
1381  SDL_joylist = SDL_joylist_tail = NULL;
1382 
1383  numjoysticks = 0;
1384 
1385 #if SDL_USE_LIBUDEV
1386  if (enumeration_method == ENUMERATION_LIBUDEV) {
1387  SDL_UDEV_DelCallback(joystick_udev_callback);
1388  SDL_UDEV_Quit();
1389  }
1390 #endif
1391 
1393 }
1394 
1395 /*
1396  This is based on the Linux Gamepad Specification
1397  available at: https://www.kernel.org/doc/html/v4.15/input/gamepad.html
1398  */
1399 static SDL_bool
1400 LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
1401 {
1402  SDL_Joystick *joystick;
1403 
1404  joystick = (SDL_Joystick *) SDL_calloc(sizeof(*joystick), 1);
1405  if (joystick == NULL) {
1406  SDL_OutOfMemory();
1407  return SDL_FALSE;
1408  }
1409 
1410  /* We temporarily open the device to check how it's configured. */
1411  if (LINUX_JoystickOpen(joystick, device_index) < 0) {
1412  SDL_free(joystick);
1413  return SDL_FALSE;
1414  }
1415 
1416  if (!joystick->hwdata->has_key[BTN_GAMEPAD]) {
1417  /* Not a gamepad according to the specs. */
1418  LINUX_JoystickClose(joystick);
1419  SDL_free(joystick);
1420  return SDL_FALSE;
1421  }
1422 
1423  /* We have a gamepad, start filling out the mappings */
1424 
1425  if (joystick->hwdata->has_key[BTN_SOUTH]) {
1426  out->a.kind = EMappingKind_Button;
1427  out->a.target = joystick->hwdata->key_map[BTN_SOUTH];
1428  }
1429 
1430  if (joystick->hwdata->has_key[BTN_EAST]) {
1431  out->b.kind = EMappingKind_Button;
1432  out->b.target = joystick->hwdata->key_map[BTN_EAST];
1433  }
1434 
1435  if (joystick->hwdata->has_key[BTN_NORTH]) {
1436  out->y.kind = EMappingKind_Button;
1437  out->y.target = joystick->hwdata->key_map[BTN_NORTH];
1438  }
1439 
1440  if (joystick->hwdata->has_key[BTN_WEST]) {
1441  out->x.kind = EMappingKind_Button;
1442  out->x.target = joystick->hwdata->key_map[BTN_WEST];
1443  }
1444 
1445  if (joystick->hwdata->has_key[BTN_SELECT]) {
1446  out->back.kind = EMappingKind_Button;
1447  out->back.target = joystick->hwdata->key_map[BTN_SELECT];
1448  }
1449 
1450  if (joystick->hwdata->has_key[BTN_START]) {
1452  out->start.target = joystick->hwdata->key_map[BTN_START];
1453  }
1454 
1455  if (joystick->hwdata->has_key[BTN_THUMBL]) {
1457  out->leftstick.target = joystick->hwdata->key_map[BTN_THUMBL];
1458  }
1459 
1460  if (joystick->hwdata->has_key[BTN_THUMBR]) {
1462  out->rightstick.target = joystick->hwdata->key_map[BTN_THUMBR];
1463  }
1464 
1465  if (joystick->hwdata->has_key[BTN_MODE]) {
1467  out->guide.target = joystick->hwdata->key_map[BTN_MODE];
1468  }
1469 
1470  /*
1471  According to the specs the D-Pad, the shoulder buttons and the triggers
1472  can be digital, or analog, or both at the same time.
1473  */
1474 
1475  /* Prefer digital shoulder buttons, but settle for analog if missing. */
1476  if (joystick->hwdata->has_key[BTN_TL]) {
1478  out->leftshoulder.target = joystick->hwdata->key_map[BTN_TL];
1479  }
1480 
1481  if (joystick->hwdata->has_key[BTN_TR]) {
1483  out->rightshoulder.target = joystick->hwdata->key_map[BTN_TR];
1484  }
1485 
1486  if (joystick->hwdata->has_hat[1] && /* Check if ABS_HAT1{X, Y} is available. */
1487  (!joystick->hwdata->has_key[BTN_TL] || !joystick->hwdata->has_key[BTN_TR])) {
1488  int hat = joystick->hwdata->hats_indices[1] << 4;
1491  out->leftshoulder.target = hat | 0x4;
1492  out->rightshoulder.target = hat | 0x2;
1493  }
1494 
1495  /* Prefer analog triggers, but settle for digital if missing. */
1496  if (joystick->hwdata->has_hat[2]) { /* Check if ABS_HAT2{X,Y} is available. */
1497  int hat = joystick->hwdata->hats_indices[2] << 4;
1500  out->lefttrigger.target = hat | 0x4;
1501  out->righttrigger.target = hat | 0x2;
1502  } else {
1503  if (joystick->hwdata->has_key[BTN_TL2]) {
1505  out->lefttrigger.target = joystick->hwdata->key_map[BTN_TL2];
1506  }
1507 
1508  if (joystick->hwdata->has_key[BTN_TR2]) {
1510  out->righttrigger.target = joystick->hwdata->key_map[BTN_TR2];
1511  }
1512  }
1513 
1514  /* Prefer digital D-Pad, but settle for analog if missing. */
1515  if (joystick->hwdata->has_key[BTN_DPAD_UP]) {
1516  out->dpup.kind = EMappingKind_Button;
1517  out->dpup.target = joystick->hwdata->key_map[BTN_DPAD_UP];
1518  }
1519 
1520  if (joystick->hwdata->has_key[BTN_DPAD_DOWN]) {
1522  out->dpdown.target = joystick->hwdata->key_map[BTN_DPAD_DOWN];
1523  }
1524 
1525  if (joystick->hwdata->has_key[BTN_DPAD_LEFT]) {
1527  out->dpleft.target = joystick->hwdata->key_map[BTN_DPAD_LEFT];
1528  }
1529 
1530  if (joystick->hwdata->has_key[BTN_DPAD_RIGHT]) {
1532  out->dpright.target = joystick->hwdata->key_map[BTN_DPAD_RIGHT];
1533  }
1534 
1535  if (joystick->hwdata->has_hat[0] && /* Check if ABS_HAT0{X,Y} is available. */
1536  (!joystick->hwdata->has_key[BTN_DPAD_LEFT] || !joystick->hwdata->has_key[BTN_DPAD_RIGHT] ||
1537  !joystick->hwdata->has_key[BTN_DPAD_UP] || !joystick->hwdata->has_key[BTN_DPAD_DOWN])) {
1538  int hat = joystick->hwdata->hats_indices[0] << 4;
1539  out->dpleft.kind = EMappingKind_Hat;
1540  out->dpright.kind = EMappingKind_Hat;
1541  out->dpup.kind = EMappingKind_Hat;
1542  out->dpdown.kind = EMappingKind_Hat;
1543  out->dpleft.target = hat | 0x8;
1544  out->dpright.target = hat | 0x2;
1545  out->dpup.target = hat | 0x1;
1546  out->dpdown.target = hat | 0x4;
1547  }
1548 
1549  if (joystick->hwdata->has_abs[ABS_X] && joystick->hwdata->has_abs[ABS_Y]) {
1550  out->leftx.kind = EMappingKind_Axis;
1551  out->lefty.kind = EMappingKind_Axis;
1552  out->leftx.target = joystick->hwdata->abs_map[ABS_X];
1553  out->lefty.target = joystick->hwdata->abs_map[ABS_Y];
1554  }
1555 
1556  if (joystick->hwdata->has_abs[ABS_RX] && joystick->hwdata->has_abs[ABS_RY]) {
1557  out->rightx.kind = EMappingKind_Axis;
1558  out->righty.kind = EMappingKind_Axis;
1559  out->rightx.target = joystick->hwdata->abs_map[ABS_RX];
1560  out->righty.target = joystick->hwdata->abs_map[ABS_RY];
1561  }
1562 
1563  LINUX_JoystickClose(joystick);
1564  SDL_free(joystick);
1565 
1566  return SDL_TRUE;
1567 }
1568 
1570 {
1571  LINUX_JoystickInit,
1572  LINUX_JoystickGetCount,
1573  LINUX_JoystickDetect,
1574  LINUX_JoystickGetDeviceName,
1575  LINUX_JoystickGetDevicePlayerIndex,
1576  LINUX_JoystickSetDevicePlayerIndex,
1577  LINUX_JoystickGetDeviceGUID,
1578  LINUX_JoystickGetDeviceInstanceID,
1579  LINUX_JoystickOpen,
1580  LINUX_JoystickRumble,
1581  LINUX_JoystickRumbleTriggers,
1582  LINUX_JoystickHasLED,
1583  LINUX_JoystickSetLED,
1584  LINUX_JoystickSetSensorsEnabled,
1585  LINUX_JoystickUpdate,
1586  LINUX_JoystickClose,
1587  LINUX_JoystickQuit,
1588  LINUX_JoystickGetGamepadMapping
1589 };
1590 
1591 #endif /* SDL_JOYSTICK_LINUX */
1592 
1593 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_assert(condition)
Definition: SDL_assert.h:171
unsigned int size_t
#define SDL_SetError
#define SDL_memset
#define SDL_strchr
#define SDL_strncmp
#define SDL_floorf
#define SDL_getenv
#define SDL_malloc
#define SDL_strlen
#define SDL_strlcpy
#define SDL_free
#define SDL_strdup
#define SDL_strcmp
#define SDL_GetHintBoolean
#define SDL_LogDebug
#define SDL_LogWarn
#define SDL_snprintf
#define SDL_calloc
#define SDL_SwapLE16(X)
Definition: SDL_endian.h:235
#define SDL_OutOfMemory()
Definition: SDL_error.h:88
#define SDL_Unsupported()
Definition: SDL_error.h:89
#define SDL_RELEASED
Definition: SDL_events.h:49
#define SDL_PRESSED
Definition: SDL_events.h:50
const GLubyte GLuint red
Definition: SDL_glfuncs.h:80
SDL_bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name)
#define SDL_HINT_LINUX_JOYSTICK_DEADZONES
A variable controlling whether joysticks on Linux adhere to their HID-defined deadzones or return unf...
Definition: SDL_hints.h:729
int SDL_PrivateJoystickBall(SDL_Joystick *joystick, Uint8 ball, Sint16 xrel, Sint16 yrel)
int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid)
void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance)
SDL_JoystickID SDL_GetNextJoystickInstanceID()
Definition: SDL_joystick.c:262
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
char * SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name)
#define SDL_HAT_LEFTDOWN
Definition: SDL_joystick.h:394
#define SDL_HAT_LEFT
Definition: SDL_joystick.h:390
#define SDL_JOYSTICK_AXIS_MIN
Definition: SDL_joystick.h:359
#define SDL_HAT_RIGHT
Definition: SDL_joystick.h:388
#define SDL_HAT_RIGHTUP
Definition: SDL_joystick.h:391
#define SDL_HAT_LEFTUP
Definition: SDL_joystick.h:393
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:81
#define SDL_HAT_DOWN
Definition: SDL_joystick.h:389
#define SDL_HAT_RIGHTDOWN
Definition: SDL_joystick.h:392
#define SDL_HAT_UP
Definition: SDL_joystick.h:387
#define SDL_HAT_CENTERED
Definition: SDL_joystick.h:386
#define SDL_JOYSTICK_AXIS_MAX
Definition: SDL_joystick.h:358
@ EMappingKind_Hat
@ EMappingKind_Button
@ EMappingKind_Axis
@ SDL_LOG_CATEGORY_INPUT
Definition: SDL_log.h:73
static int numjoysticks
GLdouble GLdouble t
Definition: SDL_opengl.h:2071
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
struct _cl_event * event
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLbyte GLbyte blue
GLenum GLsizei len
GLuint const GLchar * name
GLuint GLint GLboolean GLint GLenum access
GLenum GLuint GLenum GLsizei const GLchar * buf
GLfloat GLfloat p
GLsizei const GLchar *const * path
GLbyte green
GLsizei const GLfloat * value
#define memmove
Definition: SDL_qsort.c:58
uint16_t Uint16
Definition: SDL_stdinc.h:197
int16_t Sint16
Definition: SDL_stdinc.h:191
#define SDL_zeroa(x)
Definition: SDL_stdinc.h:428
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_TRUE
Definition: SDL_stdinc.h:170
@ SDL_FALSE
Definition: SDL_stdinc.h:169
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:121
uint8_t Uint8
Definition: SDL_stdinc.h:185
#define SDL_zerop(x)
Definition: SDL_stdinc.h:427
uint32_t Uint32
Definition: SDL_stdinc.h:209
void SDL_InitSteamControllers(SteamControllerConnectedCallback_t connectedCallback, SteamControllerDisconnectedCallback_t disconnectedCallback)
void SDL_GetSteamControllerInputs(int *nbuttons, int *naxes, int *nhats)
void SDL_UpdateSteamControllers(void)
void SDL_UpdateSteamController(SDL_Joystick *joystick)
void SDL_QuitSteamControllers(void)
#define SDL_MAX_RUMBLE_DURATION_MS
SDL_JoystickDriver SDL_LINUX_JoystickDriver
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
#define SDL_TICKS_PASSED(A, B)
Compare SDL ticks values, and return true if A has passed B.
Definition: SDL_timer.h:56
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:163
#define SDL_INLINE
Definition: begin_code.h:130
GLuint64 GLenum GLint fd
Definition: gl2ext.h:1508
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
SDL_InputMapping rightshoulder
SDL_InputMapping leftx
SDL_InputMapping guide
SDL_InputMapping righttrigger
SDL_InputMapping dpup
SDL_InputMapping a
SDL_InputMapping rightx
SDL_InputMapping rightstick
SDL_InputMapping righty
SDL_InputMapping b
SDL_InputMapping leftshoulder
SDL_InputMapping lefttrigger
SDL_InputMapping start
SDL_InputMapping lefty
SDL_InputMapping leftstick
SDL_InputMapping dpdown
SDL_InputMapping x
SDL_InputMapping dpright
SDL_InputMapping back
SDL_InputMapping dpleft
SDL_InputMapping y
EMappingKind kind
Uint8 data[16]
Definition: SDL_joystick.h:71
struct SDL_joylist_item * item
SDL_Texture * axis
SDL_bool retval
static SDL_Event events[EVENT_BUF_SIZE]
Definition: testgesture.c:39
static SDL_Joystick * joystick
Definition: testjoystick.c:37
Uint32 type
Definition: SDL_events.h:593
#define USB_PRODUCT_XBOX_ONE_S
Definition: usb_ids.h:50
#define USB_VENDOR_MICROSOFT
Definition: usb_ids.h:29
typedef int(__stdcall *FARPROC)()