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