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