SDL  2.0
SDL_sysjoystick.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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 #include <sys/ioctl.h>
36 #include <unistd.h>
37 #include <linux/joystick.h>
38 
39 #include "SDL_assert.h"
40 #include "SDL_joystick.h"
41 #include "SDL_endian.h"
42 #include "../../events/SDL_events_c.h"
43 #include "../SDL_sysjoystick.h"
44 #include "../SDL_joystick_c.h"
45 #include "../steam/SDL_steamcontroller.h"
46 #include "SDL_sysjoystick_c.h"
47 #include "../hidapi/SDL_hidapijoystick_c.h"
48 
49 /* This isn't defined in older Linux kernel headers */
50 #ifndef SYN_DROPPED
51 #define SYN_DROPPED 3
52 #endif
53 
54 #include "../../core/linux/SDL_udev.h"
55 
56 static int MaybeAddDevice(const char *path);
57 #if SDL_USE_LIBUDEV
58 static int MaybeRemoveDevice(const char *path);
59 static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);
60 #endif /* SDL_USE_LIBUDEV */
61 
62 
63 /* A linked list of available joysticks */
64 typedef struct SDL_joylist_item
65 {
66  int device_instance;
67  char *path; /* "/dev/input/event2" or whatever */
68  char *name; /* "SideWinder 3D Pro" or whatever */
69  SDL_JoystickGUID guid;
70  dev_t devnum;
71  struct joystick_hwdata *hwdata;
72  struct SDL_joylist_item *next;
73 
74  /* Steam Controller support */
75  SDL_bool m_bSteamController;
76 } SDL_joylist_item;
77 
78 static SDL_joylist_item *SDL_joylist = NULL;
79 static SDL_joylist_item *SDL_joylist_tail = NULL;
80 static int numjoysticks = 0;
81 
82 
83 #define test_bit(nr, addr) \
84  (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
85 #define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1)
86 
87 static int
88 IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *guid)
89 {
90  /* This list is taken from:
91  https://raw.githubusercontent.com/denilsonsa/udev-joystick-blacklist/master/generate_rules.py
92  */
93  static Uint32 joystick_blacklist[] = {
94  /* Microsoft Microsoft Wireless Optical Desktop® 2.10 */
95  /* Microsoft Wireless Desktop - Comfort Edition */
96  MAKE_VIDPID(0x045e, 0x009d),
97 
98  /* Microsoft Microsoft® Digital Media Pro Keyboard */
99  /* Microsoft Corp. Digital Media Pro Keyboard */
100  MAKE_VIDPID(0x045e, 0x00b0),
101 
102  /* Microsoft Microsoft® Digital Media Keyboard */
103  /* Microsoft Corp. Digital Media Keyboard 1.0A */
104  MAKE_VIDPID(0x045e, 0x00b4),
105 
106  /* Microsoft Microsoft® Digital Media Keyboard 3000 */
107  MAKE_VIDPID(0x045e, 0x0730),
108 
109  /* Microsoft Microsoft® 2.4GHz Transceiver v6.0 */
110  /* Microsoft Microsoft® 2.4GHz Transceiver v8.0 */
111  /* Microsoft Corp. Nano Transceiver v1.0 for Bluetooth */
112  /* Microsoft Wireless Mobile Mouse 1000 */
113  /* Microsoft Wireless Desktop 3000 */
114  MAKE_VIDPID(0x045e, 0x0745),
115 
116  /* Microsoft® SideWinder(TM) 2.4GHz Transceiver */
117  MAKE_VIDPID(0x045e, 0x0748),
118 
119  /* Microsoft Corp. Wired Keyboard 600 */
120  MAKE_VIDPID(0x045e, 0x0750),
121 
122  /* Microsoft Corp. Sidewinder X4 keyboard */
123  MAKE_VIDPID(0x045e, 0x0768),
124 
125  /* Microsoft Corp. Arc Touch Mouse Transceiver */
126  MAKE_VIDPID(0x045e, 0x0773),
127 
128  /* Microsoft® 2.4GHz Transceiver v9.0 */
129  /* Microsoft® Nano Transceiver v2.1 */
130  /* Microsoft Sculpt Ergonomic Keyboard (5KV-00001) */
131  MAKE_VIDPID(0x045e, 0x07a5),
132 
133  /* Microsoft® Nano Transceiver v1.0 */
134  /* Microsoft Wireless Keyboard 800 */
135  MAKE_VIDPID(0x045e, 0x07b2),
136 
137  /* Microsoft® Nano Transceiver v2.0 */
138  MAKE_VIDPID(0x045e, 0x0800),
139 
140  /* List of Wacom devices at: http://linuxwacom.sourceforge.net/wiki/index.php/Device_IDs */
141  MAKE_VIDPID(0x056a, 0x0010), /* Wacom ET-0405 Graphire */
142  MAKE_VIDPID(0x056a, 0x0011), /* Wacom ET-0405A Graphire2 (4x5) */
143  MAKE_VIDPID(0x056a, 0x0012), /* Wacom ET-0507A Graphire2 (5x7) */
144  MAKE_VIDPID(0x056a, 0x0013), /* Wacom CTE-430 Graphire3 (4x5) */
145  MAKE_VIDPID(0x056a, 0x0014), /* Wacom CTE-630 Graphire3 (6x8) */
146  MAKE_VIDPID(0x056a, 0x0015), /* Wacom CTE-440 Graphire4 (4x5) */
147  MAKE_VIDPID(0x056a, 0x0016), /* Wacom CTE-640 Graphire4 (6x8) */
148  MAKE_VIDPID(0x056a, 0x0017), /* Wacom CTE-450 Bamboo Fun (4x5) */
149  MAKE_VIDPID(0x056a, 0x0016), /* Wacom CTE-640 Graphire 4 6x8 */
150  MAKE_VIDPID(0x056a, 0x0017), /* Wacom CTE-450 Bamboo Fun 4x5 */
151  MAKE_VIDPID(0x056a, 0x0018), /* Wacom CTE-650 Bamboo Fun 6x8 */
152  MAKE_VIDPID(0x056a, 0x0019), /* Wacom CTE-631 Bamboo One */
153  MAKE_VIDPID(0x056a, 0x00d1), /* Wacom Bamboo Pen and Touch CTH-460 */
154 
155  MAKE_VIDPID(0x09da, 0x054f), /* A4 Tech Co., G7 750 mouse */
156  MAKE_VIDPID(0x09da, 0x3043), /* A4 Tech Co., Ltd Bloody R8A Gaming Mouse */
157  MAKE_VIDPID(0x09da, 0x31b5), /* A4 Tech Co., Ltd Bloody TL80 Terminator Laser Gaming Mouse */
158  MAKE_VIDPID(0x09da, 0x3997), /* A4 Tech Co., Ltd Bloody RT7 Terminator Wireless */
159  MAKE_VIDPID(0x09da, 0x3f8b), /* A4 Tech Co., Ltd Bloody V8 mouse */
160  MAKE_VIDPID(0x09da, 0x51f4), /* Modecom MC-5006 Keyboard */
161  MAKE_VIDPID(0x09da, 0x5589), /* A4 Tech Co., Ltd Terminator TL9 Laser Gaming Mouse */
162  MAKE_VIDPID(0x09da, 0x7b22), /* A4 Tech Co., Ltd Bloody V5 */
163  MAKE_VIDPID(0x09da, 0x7f2d), /* A4 Tech Co., Ltd Bloody R3 mouse */
164  MAKE_VIDPID(0x09da, 0x8090), /* A4 Tech Co., Ltd X-718BK Oscar Optical Gaming Mouse */
165  MAKE_VIDPID(0x09da, 0x9066), /* A4 Tech Co., Sharkoon Fireglider Optical */
166  MAKE_VIDPID(0x09da, 0x9090), /* A4 Tech Co., Ltd XL-730K / XL-750BK / XL-755BK Laser Mouse */
167  MAKE_VIDPID(0x09da, 0x90c0), /* A4 Tech Co., Ltd X7 G800V keyboard */
168  MAKE_VIDPID(0x09da, 0xf012), /* A4 Tech Co., Ltd Bloody V7 mouse */
169  MAKE_VIDPID(0x09da, 0xf32a), /* A4 Tech Co., Ltd Bloody B540 keyboard */
170  MAKE_VIDPID(0x09da, 0xf613), /* A4 Tech Co., Ltd Bloody V2 mouse */
171  MAKE_VIDPID(0x09da, 0xf624), /* A4 Tech Co., Ltd Bloody B120 Keyboard */
172 
173  MAKE_VIDPID(0x1d57, 0xad03), /* [T3] 2.4GHz and IR Air Mouse Remote Control */
174 
175  MAKE_VIDPID(0x1e7d, 0x2e4a), /* Roccat Tyon Mouse */
176 
177  MAKE_VIDPID(0x20a0, 0x422d), /* Winkeyless.kr Keyboards */
178 
179  MAKE_VIDPID(0x2516, 0x001f), /* Cooler Master Storm Mizar Mouse */
180  MAKE_VIDPID(0x2516, 0x0028), /* Cooler Master Storm Alcor Mouse */
181  };
182  struct input_id inpid;
183  int i;
184  Uint32 id;
185  Uint16 *guid16 = (Uint16 *)guid->data;
186 
187 #if !SDL_USE_LIBUDEV
188  /* When udev is enabled we only get joystick devices here, so there's no need to test them */
189  unsigned long evbit[NBITS(EV_MAX)] = { 0 };
190  unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
191  unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
192 
193  if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
194  (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
195  (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
196  return (0);
197  }
198 
199  if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
200  test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
201  return 0;
202  }
203 #endif
204 
205  if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) {
206  return 0;
207  }
208 
209  if (ioctl(fd, EVIOCGID, &inpid) < 0) {
210  return 0;
211  }
212 
213 #ifdef SDL_JOYSTICK_HIDAPI
214  if (HIDAPI_IsDevicePresent(inpid.vendor, inpid.product, inpid.version)) {
215  /* The HIDAPI driver is taking care of this device */
216  return 0;
217  }
218 #endif
219 
220  /* Check the joystick blacklist */
221  id = MAKE_VIDPID(inpid.vendor, inpid.product);
222  for (i = 0; i < SDL_arraysize(joystick_blacklist); ++i) {
223  if (id == joystick_blacklist[i]) {
224  return 0;
225  }
226  }
227 
228 #ifdef DEBUG_JOYSTICK
229  printf("Joystick: %s, bustype = %d, vendor = 0x%.4x, product = 0x%.4x, version = %d\n", namebuf, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
230 #endif
231 
232  SDL_memset(guid->data, 0, sizeof(guid->data));
233 
234  /* We only need 16 bits for each of these; space them out to fill 128. */
235  /* Byteswap so devices get same GUID on little/big endian platforms. */
236  *guid16++ = SDL_SwapLE16(inpid.bustype);
237  *guid16++ = 0;
238 
239  if (inpid.vendor && inpid.product) {
240  *guid16++ = SDL_SwapLE16(inpid.vendor);
241  *guid16++ = 0;
242  *guid16++ = SDL_SwapLE16(inpid.product);
243  *guid16++ = 0;
244  *guid16++ = SDL_SwapLE16(inpid.version);
245  *guid16++ = 0;
246  } else {
247  SDL_strlcpy((char*)guid16, namebuf, sizeof(guid->data) - 4);
248  }
249 
250  if (SDL_ShouldIgnoreJoystick(namebuf, *guid)) {
251  return 0;
252  }
253  return 1;
254 }
255 
256 #if SDL_USE_LIBUDEV
257 static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
258 {
259  if (devpath == NULL) {
260  return;
261  }
262 
263  switch (udev_type) {
264  case SDL_UDEV_DEVICEADDED:
265  if (!(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
266  return;
267  }
268  MaybeAddDevice(devpath);
269  break;
270 
271  case SDL_UDEV_DEVICEREMOVED:
272  MaybeRemoveDevice(devpath);
273  break;
274 
275  default:
276  break;
277  }
278 
279 }
280 #endif /* SDL_USE_LIBUDEV */
281 
282 
283 /* !!! FIXME: I would love to dump this code and use libudev instead. */
284 static int
285 MaybeAddDevice(const char *path)
286 {
287  struct stat sb;
288  int fd = -1;
289  int isstick = 0;
290  char namebuf[128];
291  SDL_JoystickGUID guid;
292  SDL_joylist_item *item;
293 
294  if (path == NULL) {
295  return -1;
296  }
297 
298  if (stat(path, &sb) == -1) {
299  return -1;
300  }
301 
302  /* Check to make sure it's not already in list. */
303  for (item = SDL_joylist; item != NULL; item = item->next) {
304  if (sb.st_rdev == item->devnum) {
305  return -1; /* already have this one */
306  }
307  }
308 
309  fd = open(path, O_RDONLY, 0);
310  if (fd < 0) {
311  return -1;
312  }
313 
314 #ifdef DEBUG_INPUT_EVENTS
315  printf("Checking %s\n", path);
316 #endif
317 
318  isstick = IsJoystick(fd, namebuf, sizeof (namebuf), &guid);
319  close(fd);
320  if (!isstick) {
321  return -1;
322  }
323 
324  item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
325  if (item == NULL) {
326  return -1;
327  }
328 
329  SDL_zerop(item);
330  item->devnum = sb.st_rdev;
331  item->path = SDL_strdup(path);
332  item->name = SDL_strdup(namebuf);
333  item->guid = guid;
334 
335  if ((item->path == NULL) || (item->name == NULL)) {
336  SDL_free(item->path);
337  SDL_free(item->name);
338  SDL_free(item);
339  return -1;
340  }
341 
342  item->device_instance = SDL_GetNextJoystickInstanceID();
343  if (SDL_joylist_tail == NULL) {
344  SDL_joylist = SDL_joylist_tail = item;
345  } else {
346  SDL_joylist_tail->next = item;
347  SDL_joylist_tail = item;
348  }
349 
350  /* Need to increment the joystick count before we post the event */
351  ++numjoysticks;
352 
353  SDL_PrivateJoystickAdded(item->device_instance);
354 
355  return numjoysticks;
356 }
357 
358 #if SDL_USE_LIBUDEV
359 /* !!! FIXME: I would love to dump this code and use libudev instead. */
360 static int
361 MaybeRemoveDevice(const char *path)
362 {
363  SDL_joylist_item *item;
364  SDL_joylist_item *prev = NULL;
365 
366  if (path == NULL) {
367  return -1;
368  }
369 
370  for (item = SDL_joylist; item != NULL; item = item->next) {
371  /* found it, remove it. */
372  if (SDL_strcmp(path, item->path) == 0) {
373  const int retval = item->device_instance;
374  if (item->hwdata) {
375  item->hwdata->item = NULL;
376  }
377  if (prev != NULL) {
378  prev->next = item->next;
379  } else {
380  SDL_assert(SDL_joylist == item);
381  SDL_joylist = item->next;
382  }
383  if (item == SDL_joylist_tail) {
384  SDL_joylist_tail = prev;
385  }
386 
387  /* Need to decrement the joystick count before we post the event */
388  --numjoysticks;
389 
390  SDL_PrivateJoystickRemoved(item->device_instance);
391 
392  SDL_free(item->path);
393  SDL_free(item->name);
394  SDL_free(item);
395  return retval;
396  }
397  prev = item;
398  }
399 
400  return -1;
401 }
402 #endif
403 
404 #if ! SDL_USE_LIBUDEV
405 static int
406 JoystickInitWithoutUdev(void)
407 {
408  int i;
409  char path[PATH_MAX];
410 
411  /* !!! FIXME: only finds sticks if they're called /dev/input/event[0..31] */
412  /* !!! FIXME: we could at least readdir() through /dev/input...? */
413  /* !!! FIXME: (or delete this and rely on libudev?) */
414  for (i = 0; i < 32; i++) {
415  SDL_snprintf(path, SDL_arraysize(path), "/dev/input/event%d", i);
416  MaybeAddDevice(path);
417  }
418 
419  return 0;
420 }
421 #endif
422 
423 #if SDL_USE_LIBUDEV
424 static int
425 JoystickInitWithUdev(void)
426 {
427  if (SDL_UDEV_Init() < 0) {
428  return SDL_SetError("Could not initialize UDEV");
429  }
430 
431  /* Set up the udev callback */
432  if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
433  SDL_UDEV_Quit();
434  return SDL_SetError("Could not set up joystick <-> udev callback");
435  }
436 
437  /* Force a scan to build the initial device list */
438  SDL_UDEV_Scan();
439 
440  return 0;
441 }
442 #endif
443 
444 static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickGUID guid, int *device_instance)
445 {
446  SDL_joylist_item *item;
447 
448  item = (SDL_joylist_item *) SDL_calloc(1, sizeof (SDL_joylist_item));
449  if (item == NULL) {
450  return SDL_FALSE;
451  }
452 
453  item->path = SDL_strdup("");
454  item->name = SDL_strdup(name);
455  item->guid = guid;
456  item->m_bSteamController = SDL_TRUE;
457 
458  if ((item->path == NULL) || (item->name == NULL)) {
459  SDL_free(item->path);
460  SDL_free(item->name);
461  SDL_free(item);
462  return SDL_FALSE;
463  }
464 
465  *device_instance = item->device_instance = SDL_GetNextJoystickInstanceID();
466  if (SDL_joylist_tail == NULL) {
467  SDL_joylist = SDL_joylist_tail = item;
468  } else {
469  SDL_joylist_tail->next = item;
470  SDL_joylist_tail = item;
471  }
472 
473  /* Need to increment the joystick count before we post the event */
474  ++numjoysticks;
475 
476  SDL_PrivateJoystickAdded(item->device_instance);
477 
478  return SDL_TRUE;
479 }
480 
481 static void SteamControllerDisconnectedCallback(int device_instance)
482 {
483  SDL_joylist_item *item;
484  SDL_joylist_item *prev = NULL;
485 
486  for (item = SDL_joylist; item != NULL; item = item->next) {
487  /* found it, remove it. */
488  if (item->device_instance == device_instance) {
489  if (item->hwdata) {
490  item->hwdata->item = NULL;
491  }
492  if (prev != NULL) {
493  prev->next = item->next;
494  } else {
495  SDL_assert(SDL_joylist == item);
496  SDL_joylist = item->next;
497  }
498  if (item == SDL_joylist_tail) {
499  SDL_joylist_tail = prev;
500  }
501 
502  /* Need to decrement the joystick count before we post the event */
503  --numjoysticks;
504 
505  SDL_PrivateJoystickRemoved(item->device_instance);
506 
507  SDL_free(item->name);
508  SDL_free(item);
509  return;
510  }
511  prev = item;
512  }
513 }
514 
515 static int
516 LINUX_JoystickInit(void)
517 {
518  /* First see if the user specified one or more joysticks to use */
519  if (SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL) {
520  char *envcopy, *envpath, *delim;
521  envcopy = SDL_strdup(SDL_getenv("SDL_JOYSTICK_DEVICE"));
522  envpath = envcopy;
523  while (envpath != NULL) {
524  delim = SDL_strchr(envpath, ':');
525  if (delim != NULL) {
526  *delim++ = '\0';
527  }
528  MaybeAddDevice(envpath);
529  envpath = delim;
530  }
531  SDL_free(envcopy);
532  }
533 
534  SDL_InitSteamControllers(SteamControllerConnectedCallback,
535  SteamControllerDisconnectedCallback);
536 
537 #if SDL_USE_LIBUDEV
538  return JoystickInitWithUdev();
539 #else
540  return JoystickInitWithoutUdev();
541 #endif
542 }
543 
544 static int
545 LINUX_JoystickGetCount(void)
546 {
547  return numjoysticks;
548 }
549 
550 static void
551 LINUX_JoystickDetect(void)
552 {
553 #if SDL_USE_LIBUDEV
554  SDL_UDEV_Poll();
555 #endif
556 
558 }
559 
560 static SDL_joylist_item *
561 JoystickByDevIndex(int device_index)
562 {
563  SDL_joylist_item *item = SDL_joylist;
564 
565  if ((device_index < 0) || (device_index >= numjoysticks)) {
566  return NULL;
567  }
568 
569  while (device_index > 0) {
570  SDL_assert(item != NULL);
571  device_index--;
572  item = item->next;
573  }
574 
575  return item;
576 }
577 
578 /* Function to get the device-dependent name of a joystick */
579 static const char *
580 LINUX_JoystickGetDeviceName(int device_index)
581 {
582  return JoystickByDevIndex(device_index)->name;
583 }
584 
585 static int
586 LINUX_JoystickGetDevicePlayerIndex(int device_index)
587 {
588  return -1;
589 }
590 
591 static SDL_JoystickGUID
592 LINUX_JoystickGetDeviceGUID( int device_index )
593 {
594  return JoystickByDevIndex(device_index)->guid;
595 }
596 
597 /* Function to perform the mapping from device index to the instance id for this index */
598 static SDL_JoystickID
599 LINUX_JoystickGetDeviceInstanceID(int device_index)
600 {
601  return JoystickByDevIndex(device_index)->device_instance;
602 }
603 
604 static int
605 allocate_hatdata(SDL_Joystick * joystick)
606 {
607  int i;
608 
609  joystick->hwdata->hats =
610  (struct hwdata_hat *) SDL_malloc(joystick->nhats *
611  sizeof(struct hwdata_hat));
612  if (joystick->hwdata->hats == NULL) {
613  return (-1);
614  }
615  for (i = 0; i < joystick->nhats; ++i) {
616  joystick->hwdata->hats[i].axis[0] = 1;
617  joystick->hwdata->hats[i].axis[1] = 1;
618  }
619  return (0);
620 }
621 
622 static int
623 allocate_balldata(SDL_Joystick * joystick)
624 {
625  int i;
626 
627  joystick->hwdata->balls =
628  (struct hwdata_ball *) SDL_malloc(joystick->nballs *
629  sizeof(struct hwdata_ball));
630  if (joystick->hwdata->balls == NULL) {
631  return (-1);
632  }
633  for (i = 0; i < joystick->nballs; ++i) {
634  joystick->hwdata->balls[i].axis[0] = 0;
635  joystick->hwdata->balls[i].axis[1] = 0;
636  }
637  return (0);
638 }
639 
640 static void
641 ConfigJoystick(SDL_Joystick * joystick, int fd)
642 {
643  int i, t;
644  unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
645  unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
646  unsigned long relbit[NBITS(REL_MAX)] = { 0 };
647  unsigned long ffbit[NBITS(FF_MAX)] = { 0 };
648 
649  /* See if this device uses the new unified event API */
650  if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
651  (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
652  (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) {
653 
654  /* Get the number of buttons, axes, and other thingamajigs */
655  for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
656  if (test_bit(i, keybit)) {
657 #ifdef DEBUG_INPUT_EVENTS
658  printf("Joystick has button: 0x%x\n", i);
659 #endif
660  joystick->hwdata->key_map[i] = joystick->nbuttons;
661  ++joystick->nbuttons;
662  }
663  }
664  for (i = 0; i < BTN_JOYSTICK; ++i) {
665  if (test_bit(i, keybit)) {
666 #ifdef DEBUG_INPUT_EVENTS
667  printf("Joystick has button: 0x%x\n", i);
668 #endif
669  joystick->hwdata->key_map[i] = joystick->nbuttons;
670  ++joystick->nbuttons;
671  }
672  }
673  for (i = 0; i < ABS_MAX; ++i) {
674  /* Skip hats */
675  if (i == ABS_HAT0X) {
676  i = ABS_HAT3Y;
677  continue;
678  }
679  if (test_bit(i, absbit)) {
680  struct input_absinfo absinfo;
681 
682  if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
683  continue;
684  }
685 #ifdef DEBUG_INPUT_EVENTS
686  printf("Joystick has absolute axis: 0x%.2x\n", i);
687  printf("Values = { %d, %d, %d, %d, %d }\n",
688  absinfo.value, absinfo.minimum, absinfo.maximum,
689  absinfo.fuzz, absinfo.flat);
690 #endif /* DEBUG_INPUT_EVENTS */
691  joystick->hwdata->abs_map[i] = joystick->naxes;
692  if (absinfo.minimum == absinfo.maximum) {
693  joystick->hwdata->abs_correct[i].used = 0;
694  } else {
695  joystick->hwdata->abs_correct[i].used = 1;
696  joystick->hwdata->abs_correct[i].coef[0] =
697  (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
698  joystick->hwdata->abs_correct[i].coef[1] =
699  (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
700  t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
701  if (t != 0) {
702  joystick->hwdata->abs_correct[i].coef[2] =
703  (1 << 28) / t;
704  } else {
705  joystick->hwdata->abs_correct[i].coef[2] = 0;
706  }
707  }
708  ++joystick->naxes;
709  }
710  }
711  for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
712  if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
713  struct input_absinfo absinfo;
714 
715  if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
716  continue;
717  }
718 #ifdef DEBUG_INPUT_EVENTS
719  printf("Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
720  printf("Values = { %d, %d, %d, %d, %d }\n",
721  absinfo.value, absinfo.minimum, absinfo.maximum,
722  absinfo.fuzz, absinfo.flat);
723 #endif /* DEBUG_INPUT_EVENTS */
724  ++joystick->nhats;
725  }
726  }
727  if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
728  ++joystick->nballs;
729  }
730 
731  /* Allocate data to keep track of these thingamajigs */
732  if (joystick->nhats > 0) {
733  if (allocate_hatdata(joystick) < 0) {
734  joystick->nhats = 0;
735  }
736  }
737  if (joystick->nballs > 0) {
738  if (allocate_balldata(joystick) < 0) {
739  joystick->nballs = 0;
740  }
741  }
742  }
743 
744  if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) >= 0) {
745  if (test_bit(FF_RUMBLE, ffbit)) {
746  joystick->hwdata->ff_rumble = SDL_TRUE;
747  }
748  if (test_bit(FF_SINE, ffbit)) {
749  joystick->hwdata->ff_sine = SDL_TRUE;
750  }
751  }
752 }
753 
754 
755 /* Function to open a joystick for use.
756  The joystick to open is specified by the device index.
757  This should fill the nbuttons and naxes fields of the joystick structure.
758  It returns 0, or -1 if there is an error.
759  */
760 static int
761 LINUX_JoystickOpen(SDL_Joystick * joystick, int device_index)
762 {
763  SDL_joylist_item *item = JoystickByDevIndex(device_index);
764 
765  if (item == NULL) {
766  return SDL_SetError("No such device");
767  }
768 
769  joystick->instance_id = item->device_instance;
770  joystick->hwdata = (struct joystick_hwdata *)
771  SDL_calloc(1, sizeof(*joystick->hwdata));
772  if (joystick->hwdata == NULL) {
773  return SDL_OutOfMemory();
774  }
775  joystick->hwdata->item = item;
776  joystick->hwdata->guid = item->guid;
777  joystick->hwdata->effect.id = -1;
778  joystick->hwdata->m_bSteamController = item->m_bSteamController;
779 
780  if (item->m_bSteamController) {
781  joystick->hwdata->fd = -1;
783  &joystick->naxes,
784  &joystick->nhats);
785  } else {
786  int fd = open(item->path, O_RDWR, 0);
787  if (fd < 0) {
788  SDL_free(joystick->hwdata);
789  joystick->hwdata = NULL;
790  return SDL_SetError("Unable to open %s", item->path);
791  }
792 
793  joystick->hwdata->fd = fd;
794  joystick->hwdata->fname = SDL_strdup(item->path);
795  if (joystick->hwdata->fname == NULL) {
796  SDL_free(joystick->hwdata);
797  joystick->hwdata = NULL;
798  close(fd);
799  return SDL_OutOfMemory();
800  }
801 
802  /* Set the joystick to non-blocking read mode */
803  fcntl(fd, F_SETFL, O_NONBLOCK);
804 
805  /* Get the number of buttons and axes on the joystick */
806  ConfigJoystick(joystick, fd);
807  }
808 
809  SDL_assert(item->hwdata == NULL);
810  item->hwdata = joystick->hwdata;
811 
812  /* mark joystick as fresh and ready */
813  joystick->hwdata->fresh = 1;
814 
815  return (0);
816 }
817 
818 static int
819 LINUX_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
820 {
821  struct input_event event;
822 
823  if (joystick->hwdata->ff_rumble) {
824  struct ff_effect *effect = &joystick->hwdata->effect;
825 
826  effect->type = FF_RUMBLE;
827  effect->replay.length = SDL_min(duration_ms, 32767);
828  effect->u.rumble.strong_magnitude = low_frequency_rumble;
829  effect->u.rumble.weak_magnitude = high_frequency_rumble;
830  } else if (joystick->hwdata->ff_sine) {
831  /* Scale and average the two rumble strengths */
832  Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
833  struct ff_effect *effect = &joystick->hwdata->effect;
834 
835  effect->type = FF_PERIODIC;
836  effect->replay.length = SDL_min(duration_ms, 32767);
837  effect->u.periodic.waveform = FF_SINE;
838  effect->u.periodic.magnitude = magnitude;
839  } else {
840  return SDL_Unsupported();
841  }
842 
843  if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
844  return SDL_SetError("Couldn't update rumble effect: %s", strerror(errno));
845  }
846 
847  event.type = EV_FF;
848  event.code = joystick->hwdata->effect.id;
849  event.value = 1;
850  if (write(joystick->hwdata->fd, &event, sizeof(event)) < 0) {
851  return SDL_SetError("Couldn't start rumble effect: %s", strerror(errno));
852  }
853  return 0;
854 }
855 
856 static SDL_INLINE void
857 HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value)
858 {
859  struct hwdata_hat *the_hat;
860  const Uint8 position_map[3][3] = {
864  };
865 
866  the_hat = &stick->hwdata->hats[hat];
867  if (value < 0) {
868  value = 0;
869  } else if (value == 0) {
870  value = 1;
871  } else if (value > 0) {
872  value = 2;
873  }
874  if (value != the_hat->axis[axis]) {
875  the_hat->axis[axis] = value;
876  SDL_PrivateJoystickHat(stick, hat,
877  position_map[the_hat->
878  axis[1]][the_hat->axis[0]]);
879  }
880 }
881 
882 static SDL_INLINE void
883 HandleBall(SDL_Joystick * stick, Uint8 ball, int axis, int value)
884 {
885  stick->hwdata->balls[ball].axis[axis] += value;
886 }
887 
888 
889 static SDL_INLINE int
890 AxisCorrect(SDL_Joystick * joystick, int which, int value)
891 {
892  struct axis_correct *correct;
893 
894  correct = &joystick->hwdata->abs_correct[which];
895  if (correct->used) {
896  value *= 2;
897  if (value > correct->coef[0]) {
898  if (value < correct->coef[1]) {
899  return 0;
900  }
901  value -= correct->coef[1];
902  } else {
903  value -= correct->coef[0];
904  }
905  value *= correct->coef[2];
906  value >>= 13;
907  }
908 
909  /* Clamp and return */
910  if (value < -32768)
911  return -32768;
912  if (value > 32767)
913  return 32767;
914 
915  return value;
916 }
917 
918 static SDL_INLINE void
919 PollAllValues(SDL_Joystick * joystick)
920 {
921  struct input_absinfo absinfo;
922  int a, b = 0;
923 
924  /* Poll all axis */
925  for (a = ABS_X; b < ABS_MAX; a++) {
926  switch (a) {
927  case ABS_HAT0X:
928  case ABS_HAT0Y:
929  case ABS_HAT1X:
930  case ABS_HAT1Y:
931  case ABS_HAT2X:
932  case ABS_HAT2Y:
933  case ABS_HAT3X:
934  case ABS_HAT3Y:
935  /* ingore hats */
936  break;
937  default:
938  if (joystick->hwdata->abs_correct[b].used) {
939  if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) {
940  absinfo.value = AxisCorrect(joystick, b, absinfo.value);
941 
942 #ifdef DEBUG_INPUT_EVENTS
943  printf("Joystick : Re-read Axis %d (%d) val= %d\n",
944  joystick->hwdata->abs_map[b], a, absinfo.value);
945 #endif
946  SDL_PrivateJoystickAxis(joystick,
947  joystick->hwdata->abs_map[b],
948  absinfo.value);
949  }
950  }
951  b++;
952  }
953  }
954 }
955 
956 static SDL_INLINE void
957 HandleInputEvents(SDL_Joystick * joystick)
958 {
959  struct input_event events[32];
960  int i, len;
961  int code;
962 
963  if (joystick->hwdata->fresh) {
964  PollAllValues(joystick);
965  joystick->hwdata->fresh = 0;
966  }
967 
968  while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
969  len /= sizeof(events[0]);
970  for (i = 0; i < len; ++i) {
971  code = events[i].code;
972  switch (events[i].type) {
973  case EV_KEY:
974  SDL_PrivateJoystickButton(joystick,
975  joystick->hwdata->key_map[code],
976  events[i].value);
977  break;
978  case EV_ABS:
979  switch (code) {
980  case ABS_HAT0X:
981  case ABS_HAT0Y:
982  case ABS_HAT1X:
983  case ABS_HAT1Y:
984  case ABS_HAT2X:
985  case ABS_HAT2Y:
986  case ABS_HAT3X:
987  case ABS_HAT3Y:
988  code -= ABS_HAT0X;
989  HandleHat(joystick, code / 2, code % 2, events[i].value);
990  break;
991  default:
992  events[i].value =
993  AxisCorrect(joystick, code, events[i].value);
994  SDL_PrivateJoystickAxis(joystick,
995  joystick->hwdata->abs_map[code],
996  events[i].value);
997  break;
998  }
999  break;
1000  case EV_REL:
1001  switch (code) {
1002  case REL_X:
1003  case REL_Y:
1004  code -= REL_X;
1005  HandleBall(joystick, code / 2, code % 2, events[i].value);
1006  break;
1007  default:
1008  break;
1009  }
1010  break;
1011  case EV_SYN:
1012  switch (code) {
1013  case SYN_DROPPED :
1014 #ifdef DEBUG_INPUT_EVENTS
1015  printf("Event SYN_DROPPED detected\n");
1016 #endif
1017  PollAllValues(joystick);
1018  break;
1019  default:
1020  break;
1021  }
1022  default:
1023  break;
1024  }
1025  }
1026  }
1027 }
1028 
1029 static void
1030 LINUX_JoystickUpdate(SDL_Joystick * joystick)
1031 {
1032  int i;
1033 
1034  if (joystick->hwdata->m_bSteamController) {
1035  SDL_UpdateSteamController(joystick);
1036  return;
1037  }
1038 
1039  HandleInputEvents(joystick);
1040 
1041  /* Deliver ball motion updates */
1042  for (i = 0; i < joystick->nballs; ++i) {
1043  int xrel, yrel;
1044 
1045  xrel = joystick->hwdata->balls[i].axis[0];
1046  yrel = joystick->hwdata->balls[i].axis[1];
1047  if (xrel || yrel) {
1048  joystick->hwdata->balls[i].axis[0] = 0;
1049  joystick->hwdata->balls[i].axis[1] = 0;
1050  SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
1051  }
1052  }
1053 }
1054 
1055 /* Function to close a joystick after use */
1056 static void
1057 LINUX_JoystickClose(SDL_Joystick * joystick)
1058 {
1059  if (joystick->hwdata) {
1060  if (joystick->hwdata->effect.id >= 0) {
1061  ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id);
1062  joystick->hwdata->effect.id = -1;
1063  }
1064  if (joystick->hwdata->fd >= 0) {
1065  close(joystick->hwdata->fd);
1066  }
1067  if (joystick->hwdata->item) {
1068  joystick->hwdata->item->hwdata = NULL;
1069  }
1070  SDL_free(joystick->hwdata->hats);
1071  SDL_free(joystick->hwdata->balls);
1072  SDL_free(joystick->hwdata->fname);
1073  SDL_free(joystick->hwdata);
1074  }
1075 }
1076 
1077 /* Function to perform any system-specific joystick related cleanup */
1078 static void
1079 LINUX_JoystickQuit(void)
1080 {
1081  SDL_joylist_item *item = NULL;
1082  SDL_joylist_item *next = NULL;
1083 
1084  for (item = SDL_joylist; item; item = next) {
1085  next = item->next;
1086  SDL_free(item->path);
1087  SDL_free(item->name);
1088  SDL_free(item);
1089  }
1090 
1091  SDL_joylist = SDL_joylist_tail = NULL;
1092 
1093  numjoysticks = 0;
1094 
1095 #if SDL_USE_LIBUDEV
1096  SDL_UDEV_DelCallback(joystick_udev_callback);
1097  SDL_UDEV_Quit();
1098 #endif
1099 
1101 }
1102 
1104 {
1105  LINUX_JoystickInit,
1106  LINUX_JoystickGetCount,
1107  LINUX_JoystickDetect,
1108  LINUX_JoystickGetDeviceName,
1109  LINUX_JoystickGetDevicePlayerIndex,
1110  LINUX_JoystickGetDeviceGUID,
1111  LINUX_JoystickGetDeviceInstanceID,
1112  LINUX_JoystickOpen,
1113  LINUX_JoystickRumble,
1114  LINUX_JoystickUpdate,
1115  LINUX_JoystickClose,
1116  LINUX_JoystickQuit,
1117 };
1118 
1119 #endif /* SDL_JOYSTICK_LINUX */
1120 
1121 /* vi: set ts=4 sw=4 expandtab: */
SDL_ShouldIgnoreJoystick
SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid)
Definition: SDL_joystick.c:1343
Uint8
uint8_t Uint8
Definition: SDL_stdinc.h:179
SDL_memset
#define SDL_memset
Definition: SDL_dynapi_overrides.h:386
SDL_strlcpy
#define SDL_strlcpy
Definition: SDL_dynapi_overrides.h:394
Uint16
uint16_t Uint16
Definition: SDL_stdinc.h:191
numjoysticks
static int numjoysticks
Definition: SDL_sysjoystick.m:60
SDL_HAT_CENTERED
#define SDL_HAT_CENTERED
Definition: SDL_joystick.h:329
NULL
#define NULL
Definition: begin_code.h:164
SDL_HAT_DOWN
#define SDL_HAT_DOWN
Definition: SDL_joystick.h:332
b
GLboolean GLboolean GLboolean b
Definition: SDL_opengl_glext.h:1109
SDL_joystick.h
SDL_JoystickID
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:81
SDL_zerop
#define SDL_zerop(x)
Definition: SDL_stdinc.h:417
SDL_InitSteamControllers
void SDL_InitSteamControllers(SteamControllerConnectedCallback_t connectedCallback, SteamControllerDisconnectedCallback_t disconnectedCallback)
Definition: SDL_steamcontroller.c:28
SDL_PrivateJoystickAdded
void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance)
Definition: SDL_joystick.c:751
joystick_hwdata::joystick
SDL_Joystick * joystick
Definition: SDL_sysjoystick_c.h:41
Uint32
uint32_t Uint32
Definition: SDL_stdinc.h:203
SDL_GetNextJoystickInstanceID
SDL_JoystickID SDL_GetNextJoystickInstanceID()
Definition: SDL_joystick.c:163
SDL_endian.h
SDL_JoystickGUID::data
Uint8 data[16]
Definition: SDL_joystick.h:71
path
GLsizei const GLchar *const * path
Definition: SDL_opengl_glext.h:3730
a
GLboolean GLboolean GLboolean GLboolean a
Definition: SDL_opengl_glext.h:1109
SDL_SwapLE16
#define SDL_SwapLE16(X)
Definition: SDL_endian.h:232
SDL_HAT_LEFTDOWN
#define SDL_HAT_LEFTDOWN
Definition: SDL_joystick.h:337
SDL_PrivateJoystickRemoved
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
Definition: SDL_joystick.c:800
SDL_PrivateJoystickAxis
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
Definition: SDL_joystick.c:828
Sint16
int16_t Sint16
Definition: SDL_stdinc.h:185
len
GLenum GLsizei len
Definition: SDL_opengl_glext.h:2926
event
struct _cl_event * event
Definition: SDL_opengl_glext.h:2649
SDL_strchr
#define SDL_strchr
Definition: SDL_dynapi_overrides.h:401
retval
SDL_bool retval
Definition: testgamecontroller.c:65
SDL_INLINE
#define SDL_INLINE
Definition: begin_code.h:131
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
t
GLdouble GLdouble t
Definition: SDL_opengl.h:2071
name
GLuint const GLchar * name
Definition: SDL_opengl_glext.h:660
SDL_PrivateJoystickButton
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
Definition: SDL_joystick.c:961
SDL_QuitSteamControllers
void SDL_QuitSteamControllers(void)
Definition: SDL_steamcontroller.c:48
SDL_HAT_LEFT
#define SDL_HAT_LEFT
Definition: SDL_joystick.h:333
SDL_assert.h
SDL_min
#define SDL_min(x, y)
Definition: SDL_stdinc.h:406
MAKE_VIDPID
#define MAKE_VIDPID(VID, PID)
Definition: SDL_sysjoystick.h:90
SDL_PrivateJoystickBall
int SDL_PrivateJoystickBall(SDL_Joystick *joystick, Uint8 ball, Sint16 xrel, Sint16 yrel)
Definition: SDL_joystick.c:925
SDL_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
SDL_HAT_LEFTUP
#define SDL_HAT_LEFTUP
Definition: SDL_joystick.h:336
SDL_assert
#define SDL_assert(condition)
Definition: SDL_assert.h:169
axis
SDL_Texture * axis
Definition: testgamecontroller.c:67
SDL_JoystickDriver
Definition: SDL_sysjoystick.h:93
SDL_OutOfMemory
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_PrivateJoystickHat
int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
Definition: SDL_joystick.c:885
id
GLuint id
Definition: SDL_opengl_glext.h:528
SDL_arraysize
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:115
SDL_calloc
#define SDL_calloc
Definition: SDL_dynapi_overrides.h:375
events
static SDL_Event events[EVENT_BUF_SIZE]
Definition: testgesture.c:35
SDL_getenv
#define SDL_getenv
Definition: SDL_dynapi_overrides.h:378
SDL_HAT_RIGHT
#define SDL_HAT_RIGHT
Definition: SDL_joystick.h:331
value
GLsizei const GLfloat * value
Definition: SDL_opengl_glext.h:698
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
SDL_UpdateSteamControllers
void SDL_UpdateSteamControllers(void)
Definition: SDL_steamcontroller.c:40
SDL_snprintf
#define SDL_snprintf
Definition: SDL_dynapi_overrides.h:40
joystick_hwdata::item
struct SDL_joylist_item * item
Definition: SDL_sysjoystick_c.h:33
SDL_strdup
#define SDL_strdup
Definition: SDL_dynapi_overrides.h:397
SDL_GetSteamControllerInputs
void SDL_GetSteamControllerInputs(int *nbuttons, int *naxes, int *nhats)
Definition: SDL_steamcontroller.c:33
SDL_LINUX_JoystickDriver
SDL_JoystickDriver SDL_LINUX_JoystickDriver
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:162
SDL_HAT_UP
#define SDL_HAT_UP
Definition: SDL_joystick.h:330
HIDAPI_IsDevicePresent
SDL_bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version)
SDL_FALSE
@ SDL_FALSE
Definition: SDL_stdinc.h:163
SDL_Unsupported
#define SDL_Unsupported()
Definition: SDL_error.h:53
SDL_malloc
#define SDL_malloc
Definition: SDL_dynapi_overrides.h:374
SDL_strcmp
#define SDL_strcmp
Definition: SDL_dynapi_overrides.h:417
fd
GLuint64 GLenum GLint fd
Definition: gl2ext.h:1508
SDL_JoystickGUID
Definition: SDL_joystick.h:70
type
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
SDL_HAT_RIGHTDOWN
#define SDL_HAT_RIGHTDOWN
Definition: SDL_joystick.h:335
i
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
SDL_HAT_RIGHTUP
#define SDL_HAT_RIGHTUP
Definition: SDL_joystick.h:334
SDL_UpdateSteamController
void SDL_UpdateSteamController(SDL_Joystick *joystick)
Definition: SDL_steamcontroller.c:44
joystick_hwdata
Definition: SDL_sysjoystick_c.h:47