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