Atlas - SDL_sysjoystick.c

Home / ext / SDL / src / joystick / linux Lines: 1 | Size: 97258 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 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#include <string.h> // strerror 38#endif 39#include <sys/ioctl.h> 40#include <unistd.h> 41#include <dirent.h> 42#include <linux/joystick.h> 43 44#include "../../events/SDL_events_c.h" 45#include "../../core/linux/SDL_evdev.h" 46#include "../SDL_sysjoystick.h" 47#include "../SDL_joystick_c.h" 48#include "../usb_ids.h" 49#include "SDL_sysjoystick_c.h" 50#include "../hidapi/SDL_hidapijoystick_c.h" 51 52// This isn't defined in older Linux kernel headers 53#ifndef MSC_TIMESTAMP 54#define MSC_TIMESTAMP 0x05 55#endif 56 57#ifndef SYN_DROPPED 58#define SYN_DROPPED 3 59#endif 60#ifndef BTN_NORTH 61#define BTN_NORTH 0x133 62#endif 63#ifndef BTN_WEST 64#define BTN_WEST 0x134 65#endif 66#ifndef BTN_DPAD_UP 67#define BTN_DPAD_UP 0x220 68#endif 69#ifndef BTN_DPAD_DOWN 70#define BTN_DPAD_DOWN 0x221 71#endif 72#ifndef BTN_DPAD_LEFT 73#define BTN_DPAD_LEFT 0x222 74#endif 75#ifndef BTN_DPAD_RIGHT 76#define BTN_DPAD_RIGHT 0x223 77#endif 78#ifndef BTN_GRIPL 79#define BTN_GRIPL 0x224 80#endif 81#ifndef BTN_GRIPR 82#define BTN_GRIPR 0x225 83#endif 84#ifndef BTN_GRIPL2 85#define BTN_GRIPL2 0x226 86#endif 87#ifndef BTN_GRIPR2 88#define BTN_GRIPR2 0x227 89#endif 90 91#ifndef BTN_TRIGGER_HAPPY 92#define BTN_TRIGGER_HAPPY 0x2c0 93#define BTN_TRIGGER_HAPPY1 0x2c0 94#define BTN_TRIGGER_HAPPY2 0x2c1 95#define BTN_TRIGGER_HAPPY3 0x2c2 96#define BTN_TRIGGER_HAPPY4 0x2c3 97#define BTN_TRIGGER_HAPPY5 0x2c4 98#define BTN_TRIGGER_HAPPY6 0x2c5 99#define BTN_TRIGGER_HAPPY7 0x2c6 100#define BTN_TRIGGER_HAPPY8 0x2c7 101#define BTN_TRIGGER_HAPPY9 0x2c8 102#define BTN_TRIGGER_HAPPY10 0x2c9 103#define BTN_TRIGGER_HAPPY11 0x2ca 104#define BTN_TRIGGER_HAPPY12 0x2cb 105#define BTN_TRIGGER_HAPPY13 0x2cc 106#define BTN_TRIGGER_HAPPY14 0x2cd 107#define BTN_TRIGGER_HAPPY15 0x2ce 108#define BTN_TRIGGER_HAPPY16 0x2cf 109#define BTN_TRIGGER_HAPPY17 0x2d0 110#define BTN_TRIGGER_HAPPY18 0x2d1 111#define BTN_TRIGGER_HAPPY19 0x2d2 112#define BTN_TRIGGER_HAPPY20 0x2d3 113#define BTN_TRIGGER_HAPPY21 0x2d4 114#define BTN_TRIGGER_HAPPY22 0x2d5 115#define BTN_TRIGGER_HAPPY23 0x2d6 116#define BTN_TRIGGER_HAPPY24 0x2d7 117#define BTN_TRIGGER_HAPPY25 0x2d8 118#define BTN_TRIGGER_HAPPY26 0x2d9 119#define BTN_TRIGGER_HAPPY27 0x2da 120#define BTN_TRIGGER_HAPPY28 0x2db 121#define BTN_TRIGGER_HAPPY29 0x2dc 122#define BTN_TRIGGER_HAPPY30 0x2dd 123#define BTN_TRIGGER_HAPPY31 0x2de 124#define BTN_TRIGGER_HAPPY32 0x2df 125#define BTN_TRIGGER_HAPPY33 0x2e0 126#define BTN_TRIGGER_HAPPY34 0x2e1 127#define BTN_TRIGGER_HAPPY35 0x2e2 128#define BTN_TRIGGER_HAPPY36 0x2e3 129#define BTN_TRIGGER_HAPPY37 0x2e4 130#define BTN_TRIGGER_HAPPY38 0x2e5 131#define BTN_TRIGGER_HAPPY39 0x2e6 132#define BTN_TRIGGER_HAPPY40 0x2e7 133#endif 134 135 136#include "../../core/linux/SDL_evdev_capabilities.h" 137#include "../../core/linux/SDL_udev.h" 138 139#if 0 140#define DEBUG_INPUT_EVENTS 1 141#endif 142 143#if 0 144#define DEBUG_GAMEPAD_MAPPING 1 145#endif 146 147typedef enum 148{ 149 ENUMERATION_UNSET, 150 ENUMERATION_LIBUDEV, 151 ENUMERATION_FALLBACK 152} EnumerationMethod; 153 154static EnumerationMethod enumeration_method = ENUMERATION_UNSET; 155 156static bool IsJoystickJSNode(const char *node); 157static void MaybeAddDevice(const char *path); 158static void MaybeRemoveDevice(const char *path); 159 160// A linked list of available joysticks 161typedef struct SDL_joylist_item 162{ 163 SDL_JoystickID device_instance; 164 char *path; // "/dev/input/event2" or whatever 165 Uint16 vendor; 166 Uint16 product; 167 char *name; // "SideWinder 3D Pro" or whatever 168 char *driver; // "xpad" or whatever 169 SDL_GUID guid; 170 dev_t devnum; 171 int steam_virtual_gamepad_slot; 172 struct joystick_hwdata *hwdata; 173 struct SDL_joylist_item *next; 174 175 bool checked_mapping; 176 SDL_GamepadMapping *mapping; 177} SDL_joylist_item; 178 179// A linked list of available gamepad sensors 180typedef struct SDL_sensorlist_item 181{ 182 char *path; // "/dev/input/event2" or whatever 183 dev_t devnum; 184 struct joystick_hwdata *hwdata; 185 struct SDL_sensorlist_item *next; 186} SDL_sensorlist_item; 187 188static bool SDL_classic_joysticks = false; 189static SDL_joylist_item *SDL_joylist SDL_GUARDED_BY(SDL_joystick_lock) = NULL; 190static SDL_joylist_item *SDL_joylist_tail SDL_GUARDED_BY(SDL_joystick_lock) = NULL; 191static int numjoysticks SDL_GUARDED_BY(SDL_joystick_lock) = 0; 192static SDL_sensorlist_item *SDL_sensorlist SDL_GUARDED_BY(SDL_joystick_lock) = NULL; 193static int inotify_fd = -1; 194 195static Uint64 last_joy_detect_time; 196static time_t last_input_dir_mtime; 197 198static void FixupDeviceInfoForMapping(int fd, struct input_id *inpid) 199{ 200 if (inpid->vendor == 0x045e && inpid->product == 0x0b05 && inpid->version == 0x0903) { 201 // This is a Microsoft Xbox One Elite Series 2 controller 202 unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; 203 204 // The first version of the firmware duplicated all the inputs 205 if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) && 206 test_bit(0x2c0, keybit)) { 207 // Change the version to 0x0902, so we can map it differently 208 inpid->version = 0x0902; 209 } 210 } 211 212 /* For Atari vcs modern and classic controllers have the version reflecting 213 * firmware version, but the mapping stays stable so ignore 214 * version information */ 215 if (inpid->vendor == 0x3250 && (inpid->product == 0x1001 || inpid->product == 0x1002)) { 216 inpid->version = 0; 217 } 218} 219 220#ifdef SDL_JOYSTICK_HIDAPI 221static bool IsVirtualJoystick(Uint16 vendor, Uint16 product, Uint16 version, const char *name) 222{ 223 if (vendor == USB_VENDOR_MICROSOFT && product == USB_PRODUCT_XBOX_ONE_S && version == 0 && 224 SDL_strcmp(name, "Xbox One S Controller") == 0) { 225 // This is the virtual device created by the xow driver 226 return true; 227 } 228 return false; 229} 230#else 231static bool IsVirtualJoystick(Uint16 vendor, Uint16 product, Uint16 version, const char *name) 232{ 233 return false; 234} 235#endif // SDL_JOYSTICK_HIDAPI 236 237static bool GetSteamVirtualGamepadSlot(int fd, int *slot) 238{ 239 char name[128]; 240 241 if (ioctl(fd, EVIOCGNAME(sizeof(name)), name) > 0) { 242 const char *digits = SDL_strstr(name, "pad "); 243 if (digits) { 244 digits += 4; 245 if (SDL_isdigit(*digits)) { 246 *slot = SDL_atoi(digits); 247 return true; 248 } 249 } 250 } 251 return false; 252} 253 254static int GuessDeviceClass(int fd) 255{ 256 unsigned long propbit[NBITS(INPUT_PROP_MAX)] = { 0 }; 257 unsigned long evbit[NBITS(EV_MAX)] = { 0 }; 258 unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; 259 unsigned long absbit[NBITS(ABS_MAX)] = { 0 }; 260 unsigned long relbit[NBITS(REL_MAX)] = { 0 }; 261 262 if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) || 263 (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) || 264 (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) < 0) || 265 (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) { 266 return 0; 267 } 268 269 /* This is a newer feature, so it's allowed to fail - if so, then the 270 * device just doesn't have any properties. */ 271 (void) ioctl(fd, EVIOCGPROP(sizeof(propbit)), propbit); 272 273 return SDL_EVDEV_GuessDeviceClass(propbit, evbit, absbit, keybit, relbit); 274} 275 276static bool GuessIsJoystick(int fd) 277{ 278 if (GuessDeviceClass(fd) & SDL_UDEV_DEVICE_JOYSTICK) { 279 return true; 280 } 281 return false; 282} 283 284static bool GuessIsSensor(int fd) 285{ 286 if (GuessDeviceClass(fd) & SDL_UDEV_DEVICE_ACCELEROMETER) { 287 return true; 288 } 289 return false; 290} 291 292static bool IsJoystick(const char *path, int *fd, char **name_return, Uint16 *vendor_return, Uint16 *product_return, SDL_GUID *guid, char **driver_return) 293{ 294 struct input_id inpid; 295 char *name = NULL; 296 char *driver = NULL; 297 char product_string[128]; 298 int class = 0; 299 300 SDL_zero(inpid); 301#ifdef SDL_USE_LIBUDEV 302 // Opening input devices can generate synchronous device I/O, so avoid it if we can 303 if (SDL_UDEV_GetProductInfo(path, &inpid, &class, &driver) && 304 !(class & SDL_UDEV_DEVICE_JOYSTICK)) { 305 goto error; 306 } 307#endif 308 309 if (fd && *fd < 0) { 310 *fd = open(path, O_RDONLY | O_CLOEXEC, 0); 311 } 312 if (!fd || *fd < 0) { 313 goto error; 314 } 315 316 if (ioctl(*fd, JSIOCGNAME(sizeof(product_string)), product_string) <= 0) { 317 // When udev enumeration or classification, we only got joysticks here, so no need to test 318 if (enumeration_method != ENUMERATION_LIBUDEV && !class && !GuessIsJoystick(*fd)) { 319 goto error; 320 } 321 322 // Could have vendor and product already from udev, but should agree with evdev 323 if (ioctl(*fd, EVIOCGID, &inpid) < 0) { 324 goto error; 325 } 326 327 if (ioctl(*fd, EVIOCGNAME(sizeof(product_string)), product_string) < 0) { 328 goto error; 329 } 330 } 331 332 name = SDL_CreateJoystickName(inpid.vendor, inpid.product, NULL, product_string); 333 if (!name) { 334 goto error; 335 } 336 337 if (!IsVirtualJoystick(inpid.vendor, inpid.product, inpid.version, name) && 338 SDL_JoystickHandledByAnotherDriver(&SDL_LINUX_JoystickDriver, inpid.vendor, inpid.product, inpid.version, name)) { 339 goto error; 340 } 341 342 FixupDeviceInfoForMapping(*fd, &inpid); 343 344#ifdef DEBUG_JOYSTICK 345 SDL_Log("Joystick: %s, bustype = %d, vendor = 0x%.4x, product = 0x%.4x, version = %d", name, inpid.bustype, inpid.vendor, inpid.product, inpid.version); 346#endif 347 348 if (SDL_ShouldIgnoreJoystick(inpid.vendor, inpid.product, inpid.version, name)) { 349 goto error; 350 } 351 *name_return = name; 352 *driver_return = driver; 353 *vendor_return = inpid.vendor; 354 *product_return = inpid.product; 355 *guid = SDL_CreateJoystickGUID(inpid.bustype, inpid.vendor, inpid.product, inpid.version, NULL, product_string, 0, 0); 356 return true; 357 358error: 359 SDL_free(driver); 360 SDL_free(name); 361 return false; 362} 363 364static bool IsSensor(const char *path, int *fd) 365{ 366 struct input_id inpid; 367 int class = 0; 368 369 SDL_zero(inpid); 370#ifdef SDL_USE_LIBUDEV 371 // Opening input devices can generate synchronous device I/O, so avoid it if we can 372 if (SDL_UDEV_GetProductInfo(path, &inpid, &class, NULL) && 373 !(class & SDL_UDEV_DEVICE_ACCELEROMETER)) { 374 return false; 375 } 376#endif 377 378 if (fd && *fd < 0) { 379 *fd = open(path, O_RDONLY | O_CLOEXEC, 0); 380 } 381 if (!fd || *fd < 0) { 382 return false; 383 } 384 385 if (!class && !GuessIsSensor(*fd)) { 386 return false; 387 } 388 389 if (ioctl(*fd, EVIOCGID, &inpid) < 0) { 390 return false; 391 } 392 393 if (inpid.vendor == USB_VENDOR_NINTENDO && inpid.product == USB_PRODUCT_NINTENDO_WII_REMOTE) { 394 // Wii extension controls 395 // These may create 3 sensor devices but we only support reading from 1: ignore them 396 return false; 397 } 398 399 return true; 400} 401 402#ifdef SDL_USE_LIBUDEV 403static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath) 404{ 405 if (!devpath) { 406 return; 407 } 408 409 switch (udev_type) { 410 case SDL_UDEV_DEVICEADDED: 411 if (!(udev_class & (SDL_UDEV_DEVICE_JOYSTICK | SDL_UDEV_DEVICE_ACCELEROMETER))) { 412 return; 413 } 414 if (SDL_classic_joysticks) { 415 if (!IsJoystickJSNode(devpath)) { 416 return; 417 } 418 } else { 419 if (IsJoystickJSNode(devpath)) { 420 return; 421 } 422 } 423 424 // Wait a bit for the hidraw udev node to initialize 425 SDL_Delay(10); 426 427 MaybeAddDevice(devpath); 428 break; 429 430 case SDL_UDEV_DEVICEREMOVED: 431 MaybeRemoveDevice(devpath); 432 break; 433 434 default: 435 break; 436 } 437} 438#endif // SDL_USE_LIBUDEV 439 440static void FreeJoylistItem(SDL_joylist_item *item) 441{ 442 SDL_free(item->mapping); 443 SDL_free(item->path); 444 SDL_free(item->name); 445 SDL_free(item->driver); 446 SDL_free(item); 447} 448 449static void FreeSensorlistItem(SDL_sensorlist_item *item) 450{ 451 SDL_free(item->path); 452 SDL_free(item); 453} 454 455static void MaybeAddDevice(const char *path) 456{ 457 struct stat sb; 458 int fd = -1; 459 char *name = NULL; 460 char *driver = NULL; 461 Uint16 vendor, product; 462 SDL_GUID guid; 463 SDL_joylist_item *item; 464 SDL_sensorlist_item *item_sensor; 465 466 if (!path) { 467 return; 468 } 469 470 fd = open(path, O_RDONLY | O_CLOEXEC, 0); 471 if (fd < 0) { 472 return; 473 } 474 475 if (fstat(fd, &sb) == -1) { 476 close(fd); 477 return; 478 } 479 480 SDL_LockJoysticks(); 481 482 // Check to make sure it's not already in list. 483 for (item = SDL_joylist; item; item = item->next) { 484 if (sb.st_rdev == item->devnum) { 485 goto done; // already have this one 486 } 487 } 488 for (item_sensor = SDL_sensorlist; item_sensor; item_sensor = item_sensor->next) { 489 if (sb.st_rdev == item_sensor->devnum) { 490 goto done; // already have this one 491 } 492 } 493 494#ifdef DEBUG_INPUT_EVENTS 495 SDL_Log("Checking %s", path); 496#endif 497 498 if (IsJoystick(path, &fd, &name, &vendor, &product, &guid, &driver)) { 499#ifdef DEBUG_INPUT_EVENTS 500 SDL_Log("found joystick: %s", path); 501#endif 502 item = (SDL_joylist_item *)SDL_calloc(1, sizeof(SDL_joylist_item)); 503 if (!item) { 504 SDL_free(name); 505 goto done; 506 } 507 508 item->devnum = sb.st_rdev; 509 item->steam_virtual_gamepad_slot = -1; 510 item->path = SDL_strdup(path); 511 item->vendor = vendor; 512 item->product = product; 513 item->name = name; 514 item->guid = guid; 515 item->driver = driver; 516 517 if (vendor == USB_VENDOR_VALVE && 518 product == USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD) { 519 GetSteamVirtualGamepadSlot(fd, &item->steam_virtual_gamepad_slot); 520 } 521 522 if ((!item->path) || (!item->name)) { 523 FreeJoylistItem(item); 524 goto done; 525 } 526 527 item->device_instance = SDL_GetNextObjectID(); 528 if (!SDL_joylist_tail) { 529 SDL_joylist = SDL_joylist_tail = item; 530 } else { 531 SDL_joylist_tail->next = item; 532 SDL_joylist_tail = item; 533 } 534 535 // Need to increment the joystick count before we post the event 536 ++numjoysticks; 537 538 SDL_PrivateJoystickAdded(item->device_instance); 539 goto done; 540 } 541 542 if (IsSensor(path, &fd)) { 543#ifdef DEBUG_INPUT_EVENTS 544 SDL_Log("found sensor: %s", path); 545#endif 546 item_sensor = (SDL_sensorlist_item *)SDL_calloc(1, sizeof(SDL_sensorlist_item)); 547 if (!item_sensor) { 548 goto done; 549 } 550 item_sensor->devnum = sb.st_rdev; 551 item_sensor->path = SDL_strdup(path); 552 553 if (!item_sensor->path) { 554 FreeSensorlistItem(item_sensor); 555 goto done; 556 } 557 558 item_sensor->next = SDL_sensorlist; 559 SDL_sensorlist = item_sensor; 560 goto done; 561 } 562 563done: 564 close(fd); 565 SDL_UnlockJoysticks(); 566} 567 568static void RemoveJoylistItem(SDL_joylist_item *item, SDL_joylist_item *prev) 569{ 570 SDL_AssertJoysticksLocked(); 571 572 if (item->hwdata) { 573 item->hwdata->item = NULL; 574 } 575 576 if (prev) { 577 prev->next = item->next; 578 } else { 579 SDL_assert(SDL_joylist == item); 580 SDL_joylist = item->next; 581 } 582 583 if (item == SDL_joylist_tail) { 584 SDL_joylist_tail = prev; 585 } 586 587 // Need to decrement the joystick count before we post the event 588 --numjoysticks; 589 590 SDL_PrivateJoystickRemoved(item->device_instance); 591 FreeJoylistItem(item); 592} 593 594static void RemoveSensorlistItem(SDL_sensorlist_item *item, SDL_sensorlist_item *prev) 595{ 596 SDL_AssertJoysticksLocked(); 597 598 if (item->hwdata) { 599 item->hwdata->item_sensor = NULL; 600 } 601 602 if (prev) { 603 prev->next = item->next; 604 } else { 605 SDL_assert(SDL_sensorlist == item); 606 SDL_sensorlist = item->next; 607 } 608 609 /* Do not call SDL_PrivateJoystickRemoved here as RemoveJoylistItem will do it, 610 * assuming both sensor and joy item are removed at the same time */ 611 FreeSensorlistItem(item); 612} 613 614static void MaybeRemoveDevice(const char *path) 615{ 616 SDL_joylist_item *item; 617 SDL_joylist_item *prev = NULL; 618 SDL_sensorlist_item *item_sensor; 619 SDL_sensorlist_item *prev_sensor = NULL; 620 621 if (!path) { 622 return; 623 } 624 625 SDL_LockJoysticks(); 626 for (item = SDL_joylist; item; item = item->next) { 627 // found it, remove it. 628 if (SDL_strcmp(path, item->path) == 0) { 629 RemoveJoylistItem(item, prev); 630 goto done; 631 } 632 prev = item; 633 } 634 for (item_sensor = SDL_sensorlist; item_sensor; item_sensor = item_sensor->next) { 635 // found it, remove it. 636 if (SDL_strcmp(path, item_sensor->path) == 0) { 637 RemoveSensorlistItem(item_sensor, prev_sensor); 638 goto done; 639 } 640 prev_sensor = item_sensor; 641 } 642done: 643 SDL_UnlockJoysticks(); 644} 645 646static void HandlePendingRemovals(void) 647{ 648 SDL_joylist_item *prev = NULL; 649 SDL_joylist_item *item = NULL; 650 SDL_sensorlist_item *prev_sensor = NULL; 651 SDL_sensorlist_item *item_sensor = NULL; 652 653 SDL_AssertJoysticksLocked(); 654 655 item = SDL_joylist; 656 while (item) { 657 if (item->hwdata && item->hwdata->gone) { 658 RemoveJoylistItem(item, prev); 659 660 if (prev) { 661 item = prev->next; 662 } else { 663 item = SDL_joylist; 664 } 665 } else { 666 prev = item; 667 item = item->next; 668 } 669 } 670 671 item_sensor = SDL_sensorlist; 672 while (item_sensor) { 673 if (item_sensor->hwdata && item_sensor->hwdata->sensor_gone) { 674 RemoveSensorlistItem(item_sensor, prev_sensor); 675 676 if (prev_sensor) { 677 item_sensor = prev_sensor->next; 678 } else { 679 item_sensor = SDL_sensorlist; 680 } 681 } else { 682 prev_sensor = item_sensor; 683 item_sensor = item_sensor->next; 684 } 685 } 686} 687 688static bool StrIsInteger(const char *string) 689{ 690 const char *p; 691 692 if (*string == '\0') { 693 return false; 694 } 695 696 for (p = string; *p != '\0'; p++) { 697 if (*p < '0' || *p > '9') { 698 return false; 699 } 700 } 701 702 return true; 703} 704 705static bool IsJoystickJSNode(const char *node) 706{ 707 const char *last_slash = SDL_strrchr(node, '/'); 708 if (last_slash) { 709 node = last_slash + 1; 710 } 711 return SDL_startswith(node, "js") && StrIsInteger(node + 2); 712} 713 714static bool IsJoystickEventNode(const char *node) 715{ 716 const char *last_slash = SDL_strrchr(node, '/'); 717 if (last_slash) { 718 node = last_slash + 1; 719 } 720 return SDL_startswith(node, "event") && StrIsInteger(node + 5); 721} 722 723static bool IsJoystickDeviceNode(const char *node) 724{ 725 if (SDL_classic_joysticks) { 726 return IsJoystickJSNode(node); 727 } else { 728 return IsJoystickEventNode(node); 729 } 730} 731 732#ifdef HAVE_INOTIFY 733#ifdef HAVE_INOTIFY_INIT1 734static int SDL_inotify_init1(void) 735{ 736 return inotify_init1(IN_NONBLOCK | IN_CLOEXEC); 737} 738#else 739static int SDL_inotify_init1(void) 740{ 741 int fd = inotify_init(); 742 if (fd < 0) { 743 return -1; 744 } 745 fcntl(fd, F_SETFL, O_NONBLOCK); 746 fcntl(fd, F_SETFD, FD_CLOEXEC); 747 return fd; 748} 749#endif 750 751static void LINUX_InotifyJoystickDetect(void) 752{ 753 union 754 { 755 struct inotify_event event; 756 char storage[4096]; 757 char enough_for_inotify[sizeof(struct inotify_event) + NAME_MAX + 1]; 758 } buf; 759 ssize_t bytes; 760 size_t remain = 0; 761 size_t len; 762 char path[PATH_MAX]; 763 764 bytes = read(inotify_fd, &buf, sizeof(buf)); 765 766 if (bytes > 0) { 767 remain = (size_t)bytes; 768 } 769 770 while (remain > 0) { 771 if (buf.event.len > 0) { 772 if (IsJoystickDeviceNode(buf.event.name)) { 773 (void)SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", buf.event.name); 774 775 if (buf.event.mask & (IN_CREATE | IN_MOVED_TO | IN_ATTRIB)) { 776 MaybeAddDevice(path); 777 } else if (buf.event.mask & (IN_DELETE | IN_MOVED_FROM)) { 778 MaybeRemoveDevice(path); 779 } 780 } 781 } 782 783 len = sizeof(struct inotify_event) + buf.event.len; 784 remain -= len; 785 786 if (remain != 0) { 787 SDL_memmove(&buf.storage[0], &buf.storage[len], remain); 788 } 789 } 790} 791#endif // HAVE_INOTIFY 792 793static int get_event_joystick_index(int event) 794{ 795 int joystick_index = -1; 796 int i, count; 797 struct dirent **entries = NULL; 798 char path[PATH_MAX]; 799 800 (void)SDL_snprintf(path, SDL_arraysize(path), "/sys/class/input/event%d/device", event); 801 count = scandir(path, &entries, NULL, alphasort); 802 for (i = 0; i < count; ++i) { 803 if (SDL_strncmp(entries[i]->d_name, "js", 2) == 0) { 804 joystick_index = SDL_atoi(entries[i]->d_name + 2); 805 } 806 free(entries[i]); // This should NOT be SDL_free() 807 } 808 free(entries); // This should NOT be SDL_free() 809 810 return joystick_index; 811} 812 813/* Detect devices by reading /dev/input. In the inotify code path we 814 * have to do this the first time, to detect devices that already existed 815 * before we started; in the non-inotify code path we do this repeatedly 816 * (polling). */ 817static int filter_entries(const struct dirent *entry) 818{ 819 return IsJoystickDeviceNode(entry->d_name); 820} 821static int SDLCALL sort_entries(const void *_a, const void *_b) 822{ 823 const struct dirent **a = (const struct dirent **)_a; 824 const struct dirent **b = (const struct dirent **)_b; 825 int numA, numB; 826 int offset; 827 828 if (SDL_classic_joysticks) { 829 offset = 2; // strlen("js") 830 numA = SDL_atoi((*a)->d_name + offset); 831 numB = SDL_atoi((*b)->d_name + offset); 832 } else { 833 offset = 5; // strlen("event") 834 numA = SDL_atoi((*a)->d_name + offset); 835 numB = SDL_atoi((*b)->d_name + offset); 836 837 // See if we can get the joystick ordering 838 { 839 int jsA = get_event_joystick_index(numA); 840 int jsB = get_event_joystick_index(numB); 841 if (jsA >= 0 && jsB >= 0) { 842 numA = jsA; 843 numB = jsB; 844 } else if (jsA >= 0) { 845 return -1; 846 } else if (jsB >= 0) { 847 return 1; 848 } 849 } 850 } 851 return numA - numB; 852} 853 854typedef struct 855{ 856 char *path; 857 int slot; 858} VirtualGamepadEntry; 859 860static int SDLCALL sort_virtual_gamepads(const void *_a, const void *_b) 861{ 862 const VirtualGamepadEntry *a = (const VirtualGamepadEntry *)_a; 863 const VirtualGamepadEntry *b = (const VirtualGamepadEntry *)_b; 864 return a->slot - b->slot; 865} 866 867static void LINUX_ScanSteamVirtualGamepads(void) 868{ 869 int i, count; 870 int fd; 871 struct dirent **entries = NULL; 872 char path[PATH_MAX]; 873 struct input_id inpid; 874 int num_virtual_gamepads = 0; 875 int virtual_gamepad_slot; 876 VirtualGamepadEntry *virtual_gamepads = NULL; 877#ifdef SDL_USE_LIBUDEV 878 int class; 879#endif 880 881 count = scandir("/dev/input", &entries, filter_entries, NULL); 882 for (i = 0; i < count; ++i) { 883 (void)SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", entries[i]->d_name); 884 885#ifdef SDL_USE_LIBUDEV 886 // Opening input devices can generate synchronous device I/O, so avoid it if we can 887 class = 0; 888 SDL_zero(inpid); 889 if (SDL_UDEV_GetProductInfo(path, &inpid, &class, NULL) && 890 (inpid.vendor != USB_VENDOR_VALVE || inpid.product != USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD)) { 891 free(entries[i]); // This should NOT be SDL_free() 892 continue; 893 } 894#endif 895 fd = open(path, O_RDONLY | O_CLOEXEC, 0); 896 if (fd >= 0) { 897 if (ioctl(fd, EVIOCGID, &inpid) == 0 && 898 inpid.vendor == USB_VENDOR_VALVE && 899 inpid.product == USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD && 900 GetSteamVirtualGamepadSlot(fd, &virtual_gamepad_slot)) { 901 VirtualGamepadEntry *new_virtual_gamepads = (VirtualGamepadEntry *)SDL_realloc(virtual_gamepads, (num_virtual_gamepads + 1) * sizeof(*virtual_gamepads)); 902 if (new_virtual_gamepads) { 903 VirtualGamepadEntry *entry = &new_virtual_gamepads[num_virtual_gamepads]; 904 entry->path = SDL_strdup(path); 905 entry->slot = virtual_gamepad_slot; 906 if (entry->path) { 907 virtual_gamepads = new_virtual_gamepads; 908 ++num_virtual_gamepads; 909 } else { 910 SDL_free(entry->path); 911 SDL_free(new_virtual_gamepads); 912 } 913 } 914 } 915 close(fd); 916 } 917 free(entries[i]); // This should NOT be SDL_free() 918 } 919 free(entries); // This should NOT be SDL_free() 920 921 if (num_virtual_gamepads > 1) { 922 SDL_qsort(virtual_gamepads, num_virtual_gamepads, sizeof(*virtual_gamepads), sort_virtual_gamepads); 923 } 924 for (i = 0; i < num_virtual_gamepads; ++i) { 925 MaybeAddDevice(virtual_gamepads[i].path); 926 SDL_free(virtual_gamepads[i].path); 927 } 928 SDL_free(virtual_gamepads); 929} 930 931static void LINUX_ScanInputDevices(void) 932{ 933 int i, count; 934 struct dirent **entries = NULL; 935 char path[PATH_MAX]; 936 937 count = scandir("/dev/input", &entries, filter_entries, NULL); 938 if (count > 1) { 939 SDL_qsort(entries, count, sizeof(*entries), sort_entries); 940 } 941 for (i = 0; i < count; ++i) { 942 (void)SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", entries[i]->d_name); 943 MaybeAddDevice(path); 944 945 free(entries[i]); // This should NOT be SDL_free() 946 } 947 free(entries); // This should NOT be SDL_free() 948} 949 950static void LINUX_FallbackJoystickDetect(void) 951{ 952 const Uint32 SDL_JOY_DETECT_INTERVAL_MS = 3000; // Update every 3 seconds 953 Uint64 now = SDL_GetTicks(); 954 955 if (!last_joy_detect_time || now >= (last_joy_detect_time + SDL_JOY_DETECT_INTERVAL_MS)) { 956 struct stat sb; 957 958 // Opening input devices can generate synchronous device I/O, so avoid it if we can 959 if (stat("/dev/input", &sb) == 0 && sb.st_mtime != last_input_dir_mtime) { 960 // Look for Steam virtual gamepads first, and sort by Steam controller slot 961 LINUX_ScanSteamVirtualGamepads(); 962 963 LINUX_ScanInputDevices(); 964 965 last_input_dir_mtime = sb.st_mtime; 966 } 967 968 last_joy_detect_time = now; 969 } 970} 971 972static void LINUX_JoystickDetect(void) 973{ 974#ifdef SDL_USE_LIBUDEV 975 if (enumeration_method == ENUMERATION_LIBUDEV) { 976 // Polling will happen in the main event loop 977 } else 978#endif 979#ifdef HAVE_INOTIFY 980 if (inotify_fd >= 0 && last_joy_detect_time != 0) { 981 LINUX_InotifyJoystickDetect(); 982 } else 983#endif 984 { 985 LINUX_FallbackJoystickDetect(); 986 } 987 988 HandlePendingRemovals(); 989} 990 991static bool LINUX_JoystickIsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name) 992{ 993 // We don't override any other drivers 994 return false; 995} 996 997static bool LINUX_JoystickInit(void) 998{ 999 const char *devices = SDL_GetHint(SDL_HINT_JOYSTICK_DEVICE); 1000#ifdef SDL_USE_LIBUDEV 1001 bool udev_initialized = SDL_UDEV_Init(); 1002#endif 1003 1004 SDL_classic_joysticks = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_LINUX_CLASSIC, false); 1005 1006 enumeration_method = ENUMERATION_UNSET; 1007 1008 // First see if the user specified one or more joysticks to use 1009 if (devices) { 1010 char *envcopy, *envpath, *delim; 1011 envcopy = SDL_strdup(devices); 1012 envpath = envcopy; 1013 while (envpath) { 1014 delim = SDL_strchr(envpath, ':'); 1015 if (delim) { 1016 *delim++ = '\0'; 1017 } 1018 MaybeAddDevice(envpath); 1019 envpath = delim; 1020 } 1021 SDL_free(envcopy); 1022 } 1023 1024 // Force immediate joystick detection if using fallback 1025 last_joy_detect_time = 0; 1026 last_input_dir_mtime = 0; 1027 1028 // Manually scan first, since we sort by device number and udev doesn't 1029 LINUX_JoystickDetect(); 1030 1031#ifdef SDL_USE_LIBUDEV 1032 if (enumeration_method == ENUMERATION_UNSET) { 1033 if (SDL_GetHintBoolean("SDL_JOYSTICK_DISABLE_UDEV", false)) { 1034 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, 1035 "udev disabled by SDL_JOYSTICK_DISABLE_UDEV"); 1036 enumeration_method = ENUMERATION_FALLBACK; 1037 } else if (SDL_GetSandbox() != SDL_SANDBOX_NONE) { 1038 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, 1039 "Container detected, disabling udev integration"); 1040 enumeration_method = ENUMERATION_FALLBACK; 1041 1042 } else { 1043 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, 1044 "Using udev for joystick device discovery"); 1045 enumeration_method = ENUMERATION_LIBUDEV; 1046 } 1047 } 1048 1049 if (enumeration_method == ENUMERATION_LIBUDEV) { 1050 if (udev_initialized) { 1051 // Set up the udev callback 1052 if (!SDL_UDEV_AddCallback(joystick_udev_callback)) { 1053 SDL_UDEV_Quit(); 1054 return SDL_SetError("Could not set up joystick <-> udev callback"); 1055 } 1056 1057 // Force a scan to build the initial device list 1058 SDL_UDEV_Scan(); 1059 } else { 1060 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, 1061 "udev init failed, disabling udev integration"); 1062 enumeration_method = ENUMERATION_FALLBACK; 1063 } 1064 } else { 1065 if (udev_initialized) { 1066 SDL_UDEV_Quit(); 1067 } 1068 } 1069#endif 1070 1071 if (enumeration_method != ENUMERATION_LIBUDEV) { 1072#ifdef HAVE_INOTIFY 1073 inotify_fd = SDL_inotify_init1(); 1074 1075 if (inotify_fd < 0) { 1076 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, 1077 "Unable to initialize inotify, falling back to polling: %s", 1078 strerror(errno)); 1079 } else { 1080 /* We need to watch for attribute changes in addition to 1081 * creation, because when a device is first created, it has 1082 * permissions that we can't read. When udev chmods it to 1083 * something that we maybe *can* read, we'll get an 1084 * IN_ATTRIB event to tell us. */ 1085 if (inotify_add_watch(inotify_fd, "/dev/input", 1086 IN_CREATE | IN_DELETE | IN_MOVE | IN_ATTRIB) < 0) { 1087 close(inotify_fd); 1088 inotify_fd = -1; 1089 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, 1090 "Unable to add inotify watch, falling back to polling: %s", 1091 strerror(errno)); 1092 } 1093 } 1094#endif // HAVE_INOTIFY 1095 } 1096 1097 return true; 1098} 1099 1100static int LINUX_JoystickGetCount(void) 1101{ 1102 SDL_AssertJoysticksLocked(); 1103 1104 return numjoysticks; 1105} 1106 1107static SDL_joylist_item *GetJoystickByDevIndex(int device_index) 1108{ 1109 SDL_joylist_item *item; 1110 1111 SDL_AssertJoysticksLocked(); 1112 1113 if ((device_index < 0) || (device_index >= numjoysticks)) { 1114 return NULL; 1115 } 1116 1117 item = SDL_joylist; 1118 while (device_index > 0) { 1119 SDL_assert(item != NULL); 1120 device_index--; 1121 item = item->next; 1122 } 1123 1124 return item; 1125} 1126 1127static const char *LINUX_JoystickGetDeviceName(int device_index) 1128{ 1129 return GetJoystickByDevIndex(device_index)->name; 1130} 1131 1132static const char *LINUX_JoystickGetDevicePath(int device_index) 1133{ 1134 return GetJoystickByDevIndex(device_index)->path; 1135} 1136 1137static int LINUX_JoystickGetDeviceSteamVirtualGamepadSlot(int device_index) 1138{ 1139 return GetJoystickByDevIndex(device_index)->steam_virtual_gamepad_slot; 1140} 1141 1142static int LINUX_JoystickGetDevicePlayerIndex(int device_index) 1143{ 1144 return -1; 1145} 1146 1147static void LINUX_JoystickSetDevicePlayerIndex(int device_index, int player_index) 1148{ 1149} 1150 1151static SDL_GUID LINUX_JoystickGetDeviceGUID(int device_index) 1152{ 1153 return GetJoystickByDevIndex(device_index)->guid; 1154} 1155 1156// Function to perform the mapping from device index to the instance id for this index 1157static SDL_JoystickID LINUX_JoystickGetDeviceInstanceID(int device_index) 1158{ 1159 return GetJoystickByDevIndex(device_index)->device_instance; 1160} 1161 1162static bool allocate_balldata(SDL_Joystick *joystick) 1163{ 1164 SDL_AssertJoysticksLocked(); 1165 1166 joystick->hwdata->balls = 1167 (struct hwdata_ball *)SDL_calloc(joystick->nballs, sizeof(struct hwdata_ball)); 1168 if (joystick->hwdata->balls == NULL) { 1169 return false; 1170 } 1171 return true; 1172} 1173 1174static bool allocate_hatdata(SDL_Joystick *joystick) 1175{ 1176 int i; 1177 1178 SDL_AssertJoysticksLocked(); 1179 1180 joystick->hwdata->hats = 1181 (struct hwdata_hat *)SDL_malloc(joystick->nhats * 1182 sizeof(struct hwdata_hat)); 1183 if (!joystick->hwdata->hats) { 1184 return false; 1185 } 1186 for (i = 0; i < joystick->nhats; ++i) { 1187 joystick->hwdata->hats[i].axis[0] = 1; 1188 joystick->hwdata->hats[i].axis[1] = 1; 1189 } 1190 return true; 1191} 1192 1193static bool GuessIfAxesAreDigitalHat(struct input_absinfo *absinfo_x, struct input_absinfo *absinfo_y) 1194{ 1195 /* A "hat" is assumed to be a digital input with at most 9 possible states 1196 * (3 per axis: negative/zero/positive), as opposed to a true "axis" which 1197 * can report a continuous range of possible values. Unfortunately the Linux 1198 * joystick interface makes no distinction between digital hat axes and any 1199 * other continuous analog axis, so we have to guess. */ 1200 1201 // If both axes are missing, they're not anything. 1202 if (!absinfo_x && !absinfo_y) { 1203 return false; 1204 } 1205 1206 // If the hint says so, treat all hats as digital. 1207 if (SDL_GetHintBoolean(SDL_HINT_JOYSTICK_LINUX_DIGITAL_HATS, false)) { 1208 return true; 1209 } 1210 1211 // If both axes have ranges constrained between -1 and 1, they're definitely digital. 1212 if ((!absinfo_x || (absinfo_x->minimum == -1 && absinfo_x->maximum == 1)) && (!absinfo_y || (absinfo_y->minimum == -1 && absinfo_y->maximum == 1))) { 1213 return true; 1214 } 1215 1216 // If both axes lack fuzz, flat, and resolution values, they're probably digital. 1217 if ((!absinfo_x || (!absinfo_x->fuzz && !absinfo_x->flat && !absinfo_x->resolution)) && (!absinfo_y || (!absinfo_y->fuzz && !absinfo_y->flat && !absinfo_y->resolution))) { 1218 return true; 1219 } 1220 1221 // Otherwise, treat them as analog. 1222 return false; 1223} 1224 1225static void ConfigJoystick(SDL_Joystick *joystick, int fd, int fd_sensor) 1226{ 1227 int i, t; 1228 unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; 1229 unsigned long absbit[NBITS(ABS_MAX)] = { 0 }; 1230 unsigned long relbit[NBITS(REL_MAX)] = { 0 }; 1231 unsigned long ffbit[NBITS(FF_MAX)] = { 0 }; 1232 Uint8 key_pam_size, abs_pam_size; 1233 bool use_deadzones = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_LINUX_DEADZONES, false); 1234 bool use_hat_deadzones = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_LINUX_HAT_DEADZONES, true); 1235 1236 SDL_AssertJoysticksLocked(); 1237 1238 // See if this device uses the new unified event API 1239 if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) && 1240 (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) && 1241 (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) { 1242 1243 // Get the number of buttons, axes, and other thingamajigs 1244 for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) { 1245 if (test_bit(i, keybit)) { 1246#ifdef DEBUG_INPUT_EVENTS 1247 SDL_Log("Joystick has button: 0x%x", i); 1248#endif 1249 joystick->hwdata->key_map[i] = joystick->nbuttons; 1250 joystick->hwdata->has_key[i] = true; 1251 ++joystick->nbuttons; 1252 } 1253 } 1254 for (i = 0; i < BTN_JOYSTICK; ++i) { 1255 if (test_bit(i, keybit)) { 1256#ifdef DEBUG_INPUT_EVENTS 1257 SDL_Log("Joystick has button: 0x%x", i); 1258#endif 1259 joystick->hwdata->key_map[i] = joystick->nbuttons; 1260 joystick->hwdata->has_key[i] = true; 1261 ++joystick->nbuttons; 1262 } 1263 } 1264 for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) { 1265 int hat_x = -1; 1266 int hat_y = -1; 1267 struct input_absinfo absinfo_x; 1268 struct input_absinfo absinfo_y; 1269 if (test_bit(i, absbit)) { 1270 hat_x = ioctl(fd, EVIOCGABS(i), &absinfo_x); 1271 } 1272 if (test_bit(i + 1, absbit)) { 1273 hat_y = ioctl(fd, EVIOCGABS(i + 1), &absinfo_y); 1274 } 1275 if (GuessIfAxesAreDigitalHat((hat_x < 0 ? (void *)0 : &absinfo_x), 1276 (hat_y < 0 ? (void *)0 : &absinfo_y))) { 1277 const int hat_index = (i - ABS_HAT0X) / 2; 1278 struct hat_axis_correct *correct = &joystick->hwdata->hat_correct[hat_index]; 1279#ifdef DEBUG_INPUT_EVENTS 1280 SDL_Log("Joystick has digital hat: #%d", hat_index); 1281 if (hat_x >= 0) { 1282 SDL_Log("X Values = { val:%d, min:%d, max:%d, fuzz:%d, flat:%d, res:%d }", 1283 absinfo_x.value, absinfo_x.minimum, absinfo_x.maximum, 1284 absinfo_x.fuzz, absinfo_x.flat, absinfo_x.resolution); 1285 } 1286 if (hat_y >= 0) { 1287 SDL_Log("Y Values = { val:%d, min:%d, max:%d, fuzz:%d, flat:%d, res:%d }", 1288 absinfo_y.value, absinfo_y.minimum, absinfo_y.maximum, 1289 absinfo_y.fuzz, absinfo_y.flat, absinfo_y.resolution); 1290 } 1291#endif // DEBUG_INPUT_EVENTS 1292 joystick->hwdata->hats_indices[hat_index] = joystick->nhats; 1293 joystick->hwdata->has_hat[hat_index] = true; 1294 correct->use_deadzones = use_hat_deadzones; 1295 correct->minimum[0] = (hat_x < 0) ? -1 : absinfo_x.minimum; 1296 correct->maximum[0] = (hat_x < 0) ? 1 : absinfo_x.maximum; 1297 correct->minimum[1] = (hat_y < 0) ? -1 : absinfo_y.minimum; 1298 correct->maximum[1] = (hat_y < 0) ? 1 : absinfo_y.maximum; 1299 ++joystick->nhats; 1300 } 1301 } 1302 for (i = 0; i < ABS_MAX; ++i) { 1303 // Skip digital hats 1304 if (i >= ABS_HAT0X && i <= ABS_HAT3Y && joystick->hwdata->has_hat[(i - ABS_HAT0X) / 2]) { 1305 continue; 1306 } 1307 if (test_bit(i, absbit)) { 1308 struct input_absinfo absinfo; 1309 struct axis_correct *correct = &joystick->hwdata->abs_correct[i]; 1310 1311 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) { 1312 continue; 1313 } 1314#ifdef DEBUG_INPUT_EVENTS 1315 SDL_Log("Joystick has absolute axis: 0x%.2x", i); 1316 SDL_Log("Values = { val:%d, min:%d, max:%d, fuzz:%d, flat:%d, res:%d }", 1317 absinfo.value, absinfo.minimum, absinfo.maximum, 1318 absinfo.fuzz, absinfo.flat, absinfo.resolution); 1319#endif // DEBUG_INPUT_EVENTS 1320 joystick->hwdata->abs_map[i] = joystick->naxes; 1321 joystick->hwdata->has_abs[i] = true; 1322 1323 correct->minimum = absinfo.minimum; 1324 correct->maximum = absinfo.maximum; 1325 if (correct->minimum != correct->maximum) { 1326 if (use_deadzones) { 1327 correct->use_deadzones = true; 1328 correct->coef[0] = (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat; 1329 correct->coef[1] = (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat; 1330 t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat); 1331 if (t != 0) { 1332 correct->coef[2] = (1 << 28) / t; 1333 } else { 1334 correct->coef[2] = 0; 1335 } 1336 } else { 1337 float value_range = (correct->maximum - correct->minimum); 1338 float output_range = (SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN); 1339 1340 correct->scale = (output_range / value_range); 1341 } 1342 } 1343 ++joystick->naxes; 1344 } 1345 } 1346 if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) { 1347 ++joystick->nballs; 1348 } 1349 1350 } else if ((ioctl(fd, JSIOCGBUTTONS, &key_pam_size, sizeof(key_pam_size)) >= 0) && 1351 (ioctl(fd, JSIOCGAXES, &abs_pam_size, sizeof(abs_pam_size)) >= 0)) { 1352 size_t len; 1353 1354 joystick->hwdata->classic = true; 1355 1356 len = (KEY_MAX - BTN_MISC + 1) * sizeof(*joystick->hwdata->key_pam); 1357 joystick->hwdata->key_pam = (Uint16 *)SDL_calloc(1, len); 1358 if (joystick->hwdata->key_pam) { 1359 if (ioctl(fd, JSIOCGBTNMAP, joystick->hwdata->key_pam, len) < 0) { 1360 SDL_free(joystick->hwdata->key_pam); 1361 joystick->hwdata->key_pam = NULL; 1362 key_pam_size = 0; 1363 } 1364 } else { 1365 key_pam_size = 0; 1366 } 1367 for (i = 0; i < key_pam_size; ++i) { 1368 Uint16 code = joystick->hwdata->key_pam[i]; 1369#ifdef DEBUG_INPUT_EVENTS 1370 SDL_Log("Joystick has button: 0x%x", code); 1371#endif 1372 joystick->hwdata->key_map[code] = joystick->nbuttons; 1373 joystick->hwdata->has_key[code] = true; 1374 ++joystick->nbuttons; 1375 } 1376 1377 len = ABS_CNT * sizeof(*joystick->hwdata->abs_pam); 1378 joystick->hwdata->abs_pam = (Uint8 *)SDL_calloc(1, len); 1379 if (joystick->hwdata->abs_pam) { 1380 if (ioctl(fd, JSIOCGAXMAP, joystick->hwdata->abs_pam, len) < 0) { 1381 SDL_free(joystick->hwdata->abs_pam); 1382 joystick->hwdata->abs_pam = NULL; 1383 abs_pam_size = 0; 1384 } 1385 } else { 1386 abs_pam_size = 0; 1387 } 1388 for (i = 0; i < abs_pam_size; ++i) { 1389 Uint8 code = joystick->hwdata->abs_pam[i]; 1390 1391 // TODO: is there any way to detect analog hats in advance via this API? 1392 if (code >= ABS_HAT0X && code <= ABS_HAT3Y) { 1393 int hat_index = (code - ABS_HAT0X) / 2; 1394 if (!joystick->hwdata->has_hat[hat_index]) { 1395#ifdef DEBUG_INPUT_EVENTS 1396 SDL_Log("Joystick has digital hat: #%d", hat_index); 1397#endif 1398 joystick->hwdata->hats_indices[hat_index] = joystick->nhats++; 1399 joystick->hwdata->has_hat[hat_index] = true; 1400 joystick->hwdata->hat_correct[hat_index].minimum[0] = -1; 1401 joystick->hwdata->hat_correct[hat_index].maximum[0] = 1; 1402 joystick->hwdata->hat_correct[hat_index].minimum[1] = -1; 1403 joystick->hwdata->hat_correct[hat_index].maximum[1] = 1; 1404 } 1405 } else { 1406#ifdef DEBUG_INPUT_EVENTS 1407 SDL_Log("Joystick has absolute axis: 0x%.2x", code); 1408#endif 1409 joystick->hwdata->abs_map[code] = joystick->naxes; 1410 joystick->hwdata->has_abs[code] = true; 1411 ++joystick->naxes; 1412 } 1413 } 1414 } 1415 1416 // Sensors are only available through the new unified event API 1417 if (fd_sensor >= 0 && (ioctl(fd_sensor, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0)) { 1418 if (test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit) && test_bit(ABS_Z, absbit)) { 1419 joystick->hwdata->has_accelerometer = true; 1420 for (i = 0; i < 3; ++i) { 1421 struct input_absinfo absinfo; 1422 if (ioctl(fd_sensor, EVIOCGABS(ABS_X + i), &absinfo) < 0) { 1423 joystick->hwdata->has_accelerometer = false; 1424 break; // do not report an accelerometer if we can't read all axes 1425 } 1426 joystick->hwdata->accelerometer_scale[i] = absinfo.resolution; 1427#ifdef DEBUG_INPUT_EVENTS 1428 SDL_Log("Joystick has accelerometer axis: 0x%.2x", ABS_X + i); 1429 SDL_Log("Values = { val:%d, min:%d, max:%d, fuzz:%d, flat:%d, res:%d }", 1430 absinfo.value, absinfo.minimum, absinfo.maximum, 1431 absinfo.fuzz, absinfo.flat, absinfo.resolution); 1432#endif // DEBUG_INPUT_EVENTS 1433 } 1434 } 1435 1436 if (test_bit(ABS_RX, absbit) && test_bit(ABS_RY, absbit) && test_bit(ABS_RZ, absbit)) { 1437 joystick->hwdata->has_gyro = true; 1438 for (i = 0; i < 3; ++i) { 1439 struct input_absinfo absinfo; 1440 if (ioctl(fd_sensor, EVIOCGABS(ABS_RX + i), &absinfo) < 0) { 1441 joystick->hwdata->has_gyro = false; 1442 break; // do not report a gyro if we can't read all axes 1443 } 1444 joystick->hwdata->gyro_scale[i] = absinfo.resolution; 1445#ifdef DEBUG_INPUT_EVENTS 1446 SDL_Log("Joystick has gyro axis: 0x%.2x", ABS_RX + i); 1447 SDL_Log("Values = { val:%d, min:%d, max:%d, fuzz:%d, flat:%d, res:%d }", 1448 absinfo.value, absinfo.minimum, absinfo.maximum, 1449 absinfo.fuzz, absinfo.flat, absinfo.resolution); 1450#endif // DEBUG_INPUT_EVENTS 1451 } 1452 } 1453 } 1454 1455 // Allocate data to keep track of these thingamajigs 1456 if (joystick->nballs > 0) { 1457 if (!allocate_balldata(joystick)) { 1458 joystick->nballs = 0; 1459 } 1460 } 1461 if (joystick->nhats > 0) { 1462 if (!allocate_hatdata(joystick)) { 1463 joystick->nhats = 0; 1464 } 1465 } 1466 1467 if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) >= 0) { 1468 if (test_bit(FF_RUMBLE, ffbit)) { 1469 joystick->hwdata->ff_rumble = true; 1470 } 1471 if (test_bit(FF_SINE, ffbit)) { 1472 joystick->hwdata->ff_sine = true; 1473 } 1474 } 1475} 1476 1477/* This is used to do the heavy lifting for LINUX_JoystickOpen and 1478 also LINUX_JoystickGetGamepadMapping, so we can query the hardware 1479 without adding an opened SDL_Joystick object to the system. 1480 This expects `joystick->hwdata` to be allocated and will not free it 1481 on error. Returns -1 on error, 0 on success. */ 1482static bool PrepareJoystickHwdata(SDL_Joystick *joystick, SDL_joylist_item *item, SDL_sensorlist_item *item_sensor) 1483{ 1484 SDL_AssertJoysticksLocked(); 1485 1486 joystick->hwdata->item = item; 1487 joystick->hwdata->item_sensor = item_sensor; 1488 joystick->hwdata->guid = item->guid; 1489 joystick->hwdata->effect.id = -1; 1490 SDL_memset(joystick->hwdata->key_map, 0xFF, sizeof(joystick->hwdata->key_map)); 1491 SDL_memset(joystick->hwdata->abs_map, 0xFF, sizeof(joystick->hwdata->abs_map)); 1492 1493 int fd = -1, fd_sensor = -1; 1494 // Try read-write first, so we can do rumble 1495 fd = open(item->path, O_RDWR | O_CLOEXEC, 0); 1496 if (fd < 0) { 1497 // Try read-only again, at least we'll get events in this case 1498 fd = open(item->path, O_RDONLY | O_CLOEXEC, 0); 1499 } 1500 if (fd < 0) { 1501 return SDL_SetError("Unable to open %s", item->path); 1502 } 1503 // If opening sensor fail, continue with buttons and axes only 1504 if (item_sensor) { 1505 fd_sensor = open(item_sensor->path, O_RDONLY | O_CLOEXEC, 0); 1506 } 1507 1508 joystick->hwdata->fd = fd; 1509 joystick->hwdata->fd_sensor = fd_sensor; 1510 joystick->hwdata->fname = SDL_strdup(item->path); 1511 if (!joystick->hwdata->fname) { 1512 close(fd); 1513 if (fd_sensor >= 0) { 1514 close(fd_sensor); 1515 } 1516 return false; 1517 } 1518 1519 // Set the joystick to non-blocking read mode 1520 fcntl(fd, F_SETFL, O_NONBLOCK); 1521 if (fd_sensor >= 0) { 1522 fcntl(fd_sensor, F_SETFL, O_NONBLOCK); 1523 } 1524 1525 // Get the number of buttons and axes on the joystick 1526 ConfigJoystick(joystick, fd, fd_sensor); 1527 return true; 1528} 1529 1530static SDL_sensorlist_item *GetSensor(SDL_joylist_item *item) 1531{ 1532 SDL_sensorlist_item *item_sensor; 1533 char uniq_item[128]; 1534 int fd_item = -1; 1535 1536 SDL_AssertJoysticksLocked(); 1537 1538 if (!item || !SDL_sensorlist) { 1539 return NULL; 1540 } 1541 1542 SDL_memset(uniq_item, 0, sizeof(uniq_item)); 1543 fd_item = open(item->path, O_RDONLY | O_CLOEXEC, 0); 1544 if (fd_item < 0) { 1545 return NULL; 1546 } 1547 if (ioctl(fd_item, EVIOCGUNIQ(sizeof(uniq_item) - 1), &uniq_item) < 0) { 1548 close(fd_item); 1549 return NULL; 1550 } 1551 close(fd_item); 1552#ifdef DEBUG_INPUT_EVENTS 1553 SDL_Log("Joystick UNIQ: %s", uniq_item); 1554#endif // DEBUG_INPUT_EVENTS 1555 1556 for (item_sensor = SDL_sensorlist; item_sensor; item_sensor = item_sensor->next) { 1557 char uniq_sensor[128]; 1558 int fd_sensor = -1; 1559 if (item_sensor->hwdata) { 1560 // already associated with another joystick 1561 continue; 1562 } 1563 1564 SDL_memset(uniq_sensor, 0, sizeof(uniq_sensor)); 1565 fd_sensor = open(item_sensor->path, O_RDONLY | O_CLOEXEC, 0); 1566 if (fd_sensor < 0) { 1567 continue; 1568 } 1569 if (ioctl(fd_sensor, EVIOCGUNIQ(sizeof(uniq_sensor) - 1), &uniq_sensor) < 0) { 1570 close(fd_sensor); 1571 continue; 1572 } 1573 close(fd_sensor); 1574#ifdef DEBUG_INPUT_EVENTS 1575 SDL_Log("Sensor UNIQ: %s", uniq_sensor); 1576#endif // DEBUG_INPUT_EVENTS 1577 1578 if (SDL_strcmp(uniq_item, uniq_sensor) == 0) { 1579 return item_sensor; 1580 } 1581 } 1582 return NULL; 1583} 1584 1585static bool LINUX_JoystickOpen(SDL_Joystick *joystick, int device_index) 1586{ 1587 SDL_joylist_item *item; 1588 SDL_sensorlist_item *item_sensor; 1589 1590 SDL_AssertJoysticksLocked(); 1591 1592 item = GetJoystickByDevIndex(device_index); 1593 if (!item) { 1594 return SDL_SetError("No such device"); 1595 } 1596 1597 joystick->hwdata = (struct joystick_hwdata *) 1598 SDL_calloc(1, sizeof(*joystick->hwdata)); 1599 if (!joystick->hwdata) { 1600 return false; 1601 } 1602 1603 item_sensor = GetSensor(item); 1604 if (!PrepareJoystickHwdata(joystick, item, item_sensor)) { 1605 SDL_free(joystick->hwdata); 1606 joystick->hwdata = NULL; 1607 return false; // SDL_SetError will already have been called 1608 } 1609 1610 SDL_assert(item->hwdata == NULL); 1611 SDL_assert(!item_sensor || item_sensor->hwdata == NULL); 1612 item->hwdata = joystick->hwdata; 1613 if (item_sensor) { 1614 item_sensor->hwdata = joystick->hwdata; 1615 } 1616 1617#ifdef SDL_USE_LIBUDEV 1618 joystick->serial = SDL_UDEV_GetProductSerial(item->path); 1619#endif 1620 1621 // mark joystick as fresh and ready 1622 joystick->hwdata->fresh = true; 1623 1624 if (joystick->hwdata->has_gyro) { 1625 SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 0.0f); 1626 } 1627 if (joystick->hwdata->has_accelerometer) { 1628 SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 0.0f); 1629 } 1630 if (joystick->hwdata->fd_sensor >= 0) { 1631 // Don't keep fd_sensor opened while sensor is disabled 1632 close(joystick->hwdata->fd_sensor); 1633 joystick->hwdata->fd_sensor = -1; 1634 } 1635 1636 if (joystick->hwdata->ff_rumble || joystick->hwdata->ff_sine) { 1637 SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true); 1638 } 1639 return true; 1640} 1641 1642static bool LINUX_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 1643{ 1644 struct input_event event; 1645 1646 SDL_AssertJoysticksLocked(); 1647 1648 if (joystick->hwdata->ff_rumble) { 1649 struct ff_effect *effect = &joystick->hwdata->effect; 1650 1651 effect->type = FF_RUMBLE; 1652 effect->replay.length = SDL_MAX_RUMBLE_DURATION_MS; 1653 effect->u.rumble.strong_magnitude = low_frequency_rumble; 1654 effect->u.rumble.weak_magnitude = high_frequency_rumble; 1655 } else if (joystick->hwdata->ff_sine) { 1656 // Scale and average the two rumble strengths 1657 Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2); 1658 struct ff_effect *effect = &joystick->hwdata->effect; 1659 1660 effect->type = FF_PERIODIC; 1661 effect->replay.length = SDL_MAX_RUMBLE_DURATION_MS; 1662 effect->u.periodic.waveform = FF_SINE; 1663 effect->u.periodic.magnitude = magnitude; 1664 } else { 1665 return SDL_Unsupported(); 1666 } 1667 1668 if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) { 1669 // The kernel may have lost this effect, try to allocate a new one 1670 joystick->hwdata->effect.id = -1; 1671 if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) { 1672 return SDL_SetError("Couldn't update rumble effect: %s", strerror(errno)); 1673 } 1674 } 1675 1676 event.type = EV_FF; 1677 event.code = joystick->hwdata->effect.id; 1678 event.value = 1; 1679 if (write(joystick->hwdata->fd, &event, sizeof(event)) < 0) { 1680 return SDL_SetError("Couldn't start rumble effect: %s", strerror(errno)); 1681 } 1682 return true; 1683} 1684 1685static bool LINUX_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) 1686{ 1687 return SDL_Unsupported(); 1688} 1689 1690static bool LINUX_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) 1691{ 1692 return SDL_Unsupported(); 1693} 1694 1695static bool LINUX_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) 1696{ 1697 return SDL_Unsupported(); 1698} 1699 1700static bool LINUX_JoystickSetSensorsEnabled(SDL_Joystick *joystick, bool enabled) 1701{ 1702 SDL_AssertJoysticksLocked(); 1703 1704 if (!joystick->hwdata->has_accelerometer && !joystick->hwdata->has_gyro) { 1705 return SDL_Unsupported(); 1706 } 1707 if (enabled == joystick->hwdata->report_sensor) { 1708 return true; 1709 } 1710 1711 if (enabled) { 1712 if (!joystick->hwdata->item_sensor) { 1713 return SDL_SetError("Sensors unplugged."); 1714 } 1715 joystick->hwdata->fd_sensor = open(joystick->hwdata->item_sensor->path, O_RDONLY | O_CLOEXEC, 0); 1716 if (joystick->hwdata->fd_sensor < 0) { 1717 return SDL_SetError("Couldn't open sensor file %s.", joystick->hwdata->item_sensor->path); 1718 } 1719 fcntl(joystick->hwdata->fd_sensor, F_SETFL, O_NONBLOCK); 1720 } else { 1721 SDL_assert(joystick->hwdata->fd_sensor >= 0); 1722 close(joystick->hwdata->fd_sensor); 1723 joystick->hwdata->fd_sensor = -1; 1724 } 1725 1726 joystick->hwdata->report_sensor = enabled; 1727 return true; 1728} 1729 1730static void HandleHat(Uint64 timestamp, SDL_Joystick *stick, int hatidx, int axis, int value) 1731{ 1732 int hatnum; 1733 struct hwdata_hat *the_hat; 1734 struct hat_axis_correct *correct; 1735 const Uint8 position_map[3][3] = { 1736 { SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP }, 1737 { SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT }, 1738 { SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN } 1739 }; 1740 1741 SDL_AssertJoysticksLocked(); 1742 1743 hatnum = stick->hwdata->hats_indices[hatidx]; 1744 the_hat = &stick->hwdata->hats[hatnum]; 1745 correct = &stick->hwdata->hat_correct[hatidx]; 1746 /* Hopefully we detected any analog axes and left them as is rather than trying 1747 * to use them as digital hats, but just in case, the deadzones here will 1748 * prevent the slightest of twitches on an analog axis from registering as a hat 1749 * movement. If the axes really are digital, this won't hurt since they should 1750 * only ever be sending min, 0, or max anyway. */ 1751 if (value < 0) { 1752 if (value <= correct->minimum[axis]) { 1753 correct->minimum[axis] = value; 1754 value = 0; 1755 } else if (!correct->use_deadzones || value < correct->minimum[axis] / 3) { 1756 value = 0; 1757 } else { 1758 value = 1; 1759 } 1760 } else if (value > 0) { 1761 if (value >= correct->maximum[axis]) { 1762 correct->maximum[axis] = value; 1763 value = 2; 1764 } else if (!correct->use_deadzones || value > correct->maximum[axis] / 3) { 1765 value = 2; 1766 } else { 1767 value = 1; 1768 } 1769 } else { // value == 0 1770 value = 1; 1771 } 1772 if (value != the_hat->axis[axis]) { 1773 the_hat->axis[axis] = value; 1774 SDL_SendJoystickHat(timestamp, stick, hatnum, 1775 position_map[the_hat->axis[1]][the_hat->axis[0]]); 1776 } 1777} 1778 1779static void HandleBall(SDL_Joystick *stick, Uint8 ball, int axis, int value) 1780{ 1781 SDL_AssertJoysticksLocked(); 1782 1783 stick->hwdata->balls[ball].axis[axis] += value; 1784} 1785 1786static int AxisCorrect(SDL_Joystick *joystick, int which, int value) 1787{ 1788 struct axis_correct *correct; 1789 1790 SDL_AssertJoysticksLocked(); 1791 1792 correct = &joystick->hwdata->abs_correct[which]; 1793 if (correct->minimum != correct->maximum) { 1794 if (correct->use_deadzones) { 1795 value *= 2; 1796 if (value > correct->coef[0]) { 1797 if (value < correct->coef[1]) { 1798 return 0; 1799 } 1800 value -= correct->coef[1]; 1801 } else { 1802 value -= correct->coef[0]; 1803 } 1804 value *= correct->coef[2]; 1805 value >>= 13; 1806 } else { 1807 value = (int)SDL_floorf((value - correct->minimum) * correct->scale + SDL_JOYSTICK_AXIS_MIN + 0.5f); 1808 } 1809 } 1810 1811 // Clamp and return 1812 if (value < SDL_JOYSTICK_AXIS_MIN) { 1813 return SDL_JOYSTICK_AXIS_MIN; 1814 } 1815 if (value > SDL_JOYSTICK_AXIS_MAX) { 1816 return SDL_JOYSTICK_AXIS_MAX; 1817 } 1818 return value; 1819} 1820 1821static void PollAllValues(Uint64 timestamp, SDL_Joystick *joystick) 1822{ 1823 struct input_absinfo absinfo; 1824 unsigned long keyinfo[NBITS(KEY_MAX)]; 1825 int i; 1826 1827 SDL_AssertJoysticksLocked(); 1828 1829 // Poll all axis 1830 for (i = ABS_X; i < ABS_MAX; i++) { 1831 // We don't need to test for digital hats here, they won't have has_abs[] set 1832 if (joystick->hwdata->has_abs[i]) { 1833 if (ioctl(joystick->hwdata->fd, EVIOCGABS(i), &absinfo) >= 0) { 1834 absinfo.value = AxisCorrect(joystick, i, absinfo.value); 1835 1836#ifdef DEBUG_INPUT_EVENTS 1837 SDL_Log("Joystick : Re-read Axis %d (%d) val= %d", 1838 joystick->hwdata->abs_map[i], i, absinfo.value); 1839#endif 1840 SDL_SendJoystickAxis(timestamp, joystick, 1841 joystick->hwdata->abs_map[i], 1842 absinfo.value); 1843 } 1844 } 1845 } 1846 1847 // Poll all digital hats 1848 for (i = ABS_HAT0X; i <= ABS_HAT3Y; i++) { 1849 const int baseaxis = i - ABS_HAT0X; 1850 const int hatidx = baseaxis / 2; 1851 SDL_assert(hatidx < SDL_arraysize(joystick->hwdata->has_hat)); 1852 // We don't need to test for analog axes here, they won't have has_hat[] set 1853 if (joystick->hwdata->has_hat[hatidx]) { 1854 if (ioctl(joystick->hwdata->fd, EVIOCGABS(i), &absinfo) >= 0) { 1855 const int hataxis = baseaxis % 2; 1856 HandleHat(timestamp, joystick, hatidx, hataxis, absinfo.value); 1857 } 1858 } 1859 } 1860 1861 // Poll all buttons 1862 SDL_zeroa(keyinfo); 1863 if (ioctl(joystick->hwdata->fd, EVIOCGKEY(sizeof(keyinfo)), keyinfo) >= 0) { 1864 for (i = 0; i < KEY_MAX; i++) { 1865 if (joystick->hwdata->has_key[i]) { 1866 bool down = test_bit(i, keyinfo); 1867#ifdef DEBUG_INPUT_EVENTS 1868 SDL_Log("Joystick : Re-read Button %d (%d) val= %d", 1869 joystick->hwdata->key_map[i], i, down); 1870#endif 1871 SDL_SendJoystickButton(timestamp, joystick, 1872 joystick->hwdata->key_map[i], down); 1873 } 1874 } 1875 } 1876 1877 // Joyballs are relative input, so there's no poll state. Events only! 1878} 1879 1880static void CorrectSensorData(struct joystick_hwdata *hwdata, float *values, float *data) 1881{ 1882 if (hwdata->item->vendor == USB_VENDOR_NINTENDO) { 1883 // The Nintendo driver uses a different axis order than SDL 1884 data[0] = -values[1]; 1885 data[1] = values[2]; 1886 data[2] = -values[0]; 1887 } else { 1888 data[0] = values[0]; 1889 data[1] = values[1]; 1890 data[2] = values[2]; 1891 } 1892} 1893 1894static void PollAllSensors(Uint64 timestamp, SDL_Joystick *joystick) 1895{ 1896 struct input_absinfo absinfo; 1897 int i; 1898 1899 SDL_AssertJoysticksLocked(); 1900 1901 SDL_assert(joystick->hwdata->fd_sensor >= 0); 1902 1903 if (joystick->hwdata->has_gyro) { 1904 float values[3] = {0.0f, 0.0f, 0.0f}; 1905 for (i = 0; i < 3; i++) { 1906 if (ioctl(joystick->hwdata->fd_sensor, EVIOCGABS(ABS_RX + i), &absinfo) >= 0) { 1907 values[i] = absinfo.value * (SDL_PI_F / 180.f) / joystick->hwdata->gyro_scale[i]; 1908#ifdef DEBUG_INPUT_EVENTS 1909 SDL_Log("Joystick : Re-read Gyro (axis %d) val= %f", i, data[i]); 1910#endif 1911 } 1912 } 1913 float data[3]; 1914 CorrectSensorData(joystick->hwdata, values, data); 1915 SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, SDL_US_TO_NS(joystick->hwdata->sensor_tick), data, 3); 1916 } 1917 if (joystick->hwdata->has_accelerometer) { 1918 float values[3] = {0.0f, 0.0f, 0.0f}; 1919 for (i = 0; i < 3; i++) { 1920 if (ioctl(joystick->hwdata->fd_sensor, EVIOCGABS(ABS_X + i), &absinfo) >= 0) { 1921 values[i] = absinfo.value * SDL_STANDARD_GRAVITY / joystick->hwdata->accelerometer_scale[i]; 1922#ifdef DEBUG_INPUT_EVENTS 1923 SDL_Log("Joystick : Re-read Accelerometer (axis %d) val= %f", i, data[i]); 1924#endif 1925 } 1926 } 1927 float data[3]; 1928 CorrectSensorData(joystick->hwdata, values, data); 1929 SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, SDL_US_TO_NS(joystick->hwdata->sensor_tick), data, 3); 1930 } 1931} 1932 1933static void HandleInputEvents(SDL_Joystick *joystick) 1934{ 1935 struct input_event events[32]; 1936 int i, len, code, hat_index; 1937 1938 SDL_AssertJoysticksLocked(); 1939 1940 if (joystick->hwdata->fresh) { 1941 Uint64 ticks = SDL_GetTicksNS(); 1942 PollAllValues(ticks, joystick); 1943 if (joystick->hwdata->report_sensor) { 1944 PollAllSensors(ticks, joystick); 1945 } 1946 joystick->hwdata->fresh = false; 1947 } 1948 1949 errno = 0; 1950 1951 while ((len = read(joystick->hwdata->fd, events, sizeof(events))) > 0) { 1952 len /= sizeof(events[0]); 1953 for (i = 0; i < len; ++i) { 1954 struct input_event *event = &events[i]; 1955 1956 code = event->code; 1957 1958 /* If the kernel sent a SYN_DROPPED, we are supposed to ignore the 1959 rest of the packet (the end of it signified by a SYN_REPORT) */ 1960 if (joystick->hwdata->recovering_from_dropped && 1961 ((event->type != EV_SYN) || (code != SYN_REPORT))) { 1962 continue; 1963 } 1964 1965 switch (event->type) { 1966 case EV_KEY: 1967#ifdef DEBUG_INPUT_EVENTS 1968 SDL_Log("Key 0x%.2x %s", code, event->value ? "PRESSED" : "RELEASED"); 1969#endif 1970 SDL_SendJoystickButton(SDL_EVDEV_GetEventTimestamp(event), joystick, 1971 joystick->hwdata->key_map[code], 1972 (event->value != 0)); 1973 break; 1974 case EV_ABS: 1975 switch (code) { 1976 case ABS_HAT0X: 1977 case ABS_HAT0Y: 1978 case ABS_HAT1X: 1979 case ABS_HAT1Y: 1980 case ABS_HAT2X: 1981 case ABS_HAT2Y: 1982 case ABS_HAT3X: 1983 case ABS_HAT3Y: 1984 hat_index = (code - ABS_HAT0X) / 2; 1985 if (joystick->hwdata->has_hat[hat_index]) { 1986#ifdef DEBUG_INPUT_EVENTS 1987 SDL_Log("Axis 0x%.2x = %d", code, event->value); 1988#endif 1989 HandleHat(SDL_EVDEV_GetEventTimestamp(event), joystick, hat_index, code % 2, event->value); 1990 break; 1991 } 1992 SDL_FALLTHROUGH; 1993 default: 1994#ifdef DEBUG_INPUT_EVENTS 1995 SDL_Log("Axis 0x%.2x = %d", code, event->value); 1996#endif 1997 event->value = AxisCorrect(joystick, code, event->value); 1998 SDL_SendJoystickAxis(SDL_EVDEV_GetEventTimestamp(event), joystick, 1999 joystick->hwdata->abs_map[code], 2000 event->value); 2001 break; 2002 } 2003 break; 2004 case EV_REL: 2005 switch (code) { 2006 case REL_X: 2007 case REL_Y: 2008 code -= REL_X; 2009 HandleBall(joystick, code / 2, code % 2, event->value); 2010 break; 2011 default: 2012 break; 2013 } 2014 break; 2015 case EV_SYN: 2016 switch (code) { 2017 case SYN_DROPPED: 2018#ifdef DEBUG_INPUT_EVENTS 2019 SDL_Log("Event SYN_DROPPED detected"); 2020#endif 2021 joystick->hwdata->recovering_from_dropped = true; 2022 break; 2023 case SYN_REPORT: 2024 if (joystick->hwdata->recovering_from_dropped) { 2025 joystick->hwdata->recovering_from_dropped = false; 2026 PollAllValues(SDL_GetTicksNS(), joystick); // try to sync up to current state now 2027 } 2028 break; 2029 default: 2030 break; 2031 } 2032 break; 2033 default: 2034 break; 2035 } 2036 } 2037 } 2038 2039 if (errno == ENODEV) { 2040 // We have to wait until the JoystickDetect callback to remove this 2041 joystick->hwdata->gone = true; 2042 errno = 0; 2043 } 2044 2045 if (joystick->hwdata->report_sensor) { 2046 SDL_assert(joystick->hwdata->fd_sensor >= 0); 2047 2048 while ((len = read(joystick->hwdata->fd_sensor, events, sizeof(events))) > 0) { 2049 len /= sizeof(events[0]); 2050 for (i = 0; i < len; ++i) { 2051 unsigned int j; 2052 struct input_event *event = &events[i]; 2053 2054 code = event->code; 2055 2056 /* If the kernel sent a SYN_DROPPED, we are supposed to ignore the 2057 rest of the packet (the end of it signified by a SYN_REPORT) */ 2058 if (joystick->hwdata->recovering_from_dropped_sensor && 2059 ((event->type != EV_SYN) || (code != SYN_REPORT))) { 2060 continue; 2061 } 2062 2063 switch (event->type) { 2064 case EV_KEY: 2065 SDL_assert(0); 2066 break; 2067 case EV_ABS: 2068 switch (code) { 2069 case ABS_X: 2070 case ABS_Y: 2071 case ABS_Z: 2072 j = code - ABS_X; 2073 joystick->hwdata->accel_data[j] = event->value * SDL_STANDARD_GRAVITY 2074 / joystick->hwdata->accelerometer_scale[j]; 2075 break; 2076 case ABS_RX: 2077 case ABS_RY: 2078 case ABS_RZ: 2079 j = code - ABS_RX; 2080 joystick->hwdata->gyro_data[j] = event->value * (SDL_PI_F / 180.f) 2081 / joystick->hwdata->gyro_scale[j]; 2082 break; 2083 } 2084 break; 2085 case EV_MSC: 2086 if (code == MSC_TIMESTAMP) { 2087 Sint32 tick = event->value; 2088 Sint32 delta; 2089 if (joystick->hwdata->last_tick < tick) { 2090 delta = (tick - joystick->hwdata->last_tick); 2091 } else { 2092 delta = (SDL_MAX_SINT32 - joystick->hwdata->last_tick + tick + 1); 2093 } 2094 joystick->hwdata->sensor_tick += delta; 2095 joystick->hwdata->last_tick = tick; 2096 } 2097 break; 2098 case EV_SYN: 2099 switch (code) { 2100 case SYN_DROPPED: 2101 #ifdef DEBUG_INPUT_EVENTS 2102 SDL_Log("Event SYN_DROPPED detected"); 2103 #endif 2104 joystick->hwdata->recovering_from_dropped_sensor = true; 2105 break; 2106 case SYN_REPORT: 2107 if (joystick->hwdata->recovering_from_dropped_sensor) { 2108 joystick->hwdata->recovering_from_dropped_sensor = false; 2109 PollAllSensors(SDL_GetTicksNS(), joystick); // try to sync up to current state now 2110 } else { 2111 Uint64 timestamp = SDL_EVDEV_GetEventTimestamp(event); 2112 float data[3]; 2113 CorrectSensorData(joystick->hwdata, joystick->hwdata->gyro_data, data); 2114 SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, 2115 SDL_US_TO_NS(joystick->hwdata->sensor_tick), 2116 data, 3); 2117 CorrectSensorData(joystick->hwdata, joystick->hwdata->accel_data, data); 2118 SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, 2119 SDL_US_TO_NS(joystick->hwdata->sensor_tick), 2120 data, 3); 2121 } 2122 break; 2123 default: 2124 break; 2125 } 2126 break; 2127 default: 2128 break; 2129 } 2130 } 2131 } 2132 } 2133 2134 if (errno == ENODEV) { 2135 // We have to wait until the JoystickDetect callback to remove this 2136 joystick->hwdata->sensor_gone = true; 2137 } 2138} 2139 2140static void HandleClassicEvents(SDL_Joystick *joystick) 2141{ 2142 struct js_event events[32]; 2143 int i, len, code, hat_index; 2144 Uint64 timestamp = SDL_GetTicksNS(); 2145 2146 SDL_AssertJoysticksLocked(); 2147 2148 joystick->hwdata->fresh = false; 2149 while ((len = read(joystick->hwdata->fd, events, sizeof(events))) > 0) { 2150 len /= sizeof(events[0]); 2151 for (i = 0; i < len; ++i) { 2152 switch (events[i].type) { 2153 case JS_EVENT_BUTTON: 2154 code = joystick->hwdata->key_pam[events[i].number]; 2155 SDL_SendJoystickButton(timestamp, joystick, 2156 joystick->hwdata->key_map[code], 2157 (events[i].value != 0)); 2158 break; 2159 case JS_EVENT_AXIS: 2160 code = joystick->hwdata->abs_pam[events[i].number]; 2161 switch (code) { 2162 case ABS_HAT0X: 2163 case ABS_HAT0Y: 2164 case ABS_HAT1X: 2165 case ABS_HAT1Y: 2166 case ABS_HAT2X: 2167 case ABS_HAT2Y: 2168 case ABS_HAT3X: 2169 case ABS_HAT3Y: 2170 hat_index = (code - ABS_HAT0X) / 2; 2171 if (joystick->hwdata->has_hat[hat_index]) { 2172 HandleHat(timestamp, joystick, hat_index, code % 2, events[i].value); 2173 break; 2174 } 2175 SDL_FALLTHROUGH; 2176 default: 2177 SDL_SendJoystickAxis(timestamp, joystick, 2178 joystick->hwdata->abs_map[code], 2179 events[i].value); 2180 break; 2181 } 2182 } 2183 } 2184 } 2185} 2186 2187static void LINUX_JoystickUpdate(SDL_Joystick *joystick) 2188{ 2189 int i; 2190 2191 SDL_AssertJoysticksLocked(); 2192 2193 if (joystick->hwdata->classic) { 2194 HandleClassicEvents(joystick); 2195 } else { 2196 HandleInputEvents(joystick); 2197 } 2198 2199 // Deliver ball motion updates 2200 for (i = 0; i < joystick->nballs; ++i) { 2201 int xrel, yrel; 2202 2203 xrel = joystick->hwdata->balls[i].axis[0]; 2204 yrel = joystick->hwdata->balls[i].axis[1]; 2205 if (xrel || yrel) { 2206 joystick->hwdata->balls[i].axis[0] = 0; 2207 joystick->hwdata->balls[i].axis[1] = 0; 2208 SDL_SendJoystickBall(0, joystick, (Uint8)i, xrel, yrel); 2209 } 2210 } 2211} 2212 2213// Function to close a joystick after use 2214static void LINUX_JoystickClose(SDL_Joystick *joystick) 2215{ 2216 SDL_AssertJoysticksLocked(); 2217 2218 if (joystick->hwdata) { 2219 if (joystick->hwdata->effect.id >= 0) { 2220 ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id); 2221 joystick->hwdata->effect.id = -1; 2222 } 2223 if (joystick->hwdata->fd >= 0) { 2224 close(joystick->hwdata->fd); 2225 } 2226 if (joystick->hwdata->fd_sensor >= 0) { 2227 close(joystick->hwdata->fd_sensor); 2228 } 2229 if (joystick->hwdata->item) { 2230 joystick->hwdata->item->hwdata = NULL; 2231 } 2232 if (joystick->hwdata->item_sensor) { 2233 joystick->hwdata->item_sensor->hwdata = NULL; 2234 } 2235 SDL_free(joystick->hwdata->key_pam); 2236 SDL_free(joystick->hwdata->abs_pam); 2237 SDL_free(joystick->hwdata->hats); 2238 SDL_free(joystick->hwdata->balls); 2239 SDL_free(joystick->hwdata->fname); 2240 SDL_free(joystick->hwdata); 2241 } 2242} 2243 2244// Function to perform any system-specific joystick related cleanup 2245static void LINUX_JoystickQuit(void) 2246{ 2247 SDL_joylist_item *item = NULL; 2248 SDL_joylist_item *next = NULL; 2249 SDL_sensorlist_item *item_sensor = NULL; 2250 SDL_sensorlist_item *next_sensor = NULL; 2251 2252 SDL_AssertJoysticksLocked(); 2253 2254 if (inotify_fd >= 0) { 2255 close(inotify_fd); 2256 inotify_fd = -1; 2257 } 2258 2259 for (item = SDL_joylist; item; item = next) { 2260 next = item->next; 2261 FreeJoylistItem(item); 2262 } 2263 for (item_sensor = SDL_sensorlist; item_sensor; item_sensor = next_sensor) { 2264 next_sensor = item_sensor->next; 2265 FreeSensorlistItem(item_sensor); 2266 } 2267 2268 SDL_joylist = SDL_joylist_tail = NULL; 2269 SDL_sensorlist = NULL; 2270 2271 numjoysticks = 0; 2272 2273#ifdef SDL_USE_LIBUDEV 2274 if (enumeration_method == ENUMERATION_LIBUDEV) { 2275 SDL_UDEV_DelCallback(joystick_udev_callback); 2276 SDL_UDEV_Quit(); 2277 } 2278#endif 2279} 2280 2281/* 2282 This is based on the Linux Gamepad Specification 2283 available at: https://www.kernel.org/doc/html/v4.15/input/gamepad.html 2284 and the Android gamepad documentation, 2285 https://developer.android.com/develop/ui/views/touch-and-input/game-controllers/controller-input 2286 */ 2287static bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) 2288{ 2289 SDL_Joystick *joystick; 2290 SDL_joylist_item *item = GetJoystickByDevIndex(device_index); 2291 enum { 2292 MAPPED_TRIGGER_LEFT = 0x1, 2293 MAPPED_TRIGGER_RIGHT = 0x2, 2294 MAPPED_TRIGGER_BOTH = 0x3, 2295 2296 MAPPED_DPAD_UP = 0x1, 2297 MAPPED_DPAD_DOWN = 0x2, 2298 MAPPED_DPAD_LEFT = 0x4, 2299 MAPPED_DPAD_RIGHT = 0x8, 2300 MAPPED_DPAD_ALL = 0xF, 2301 2302 MAPPED_LEFT_PADDLE1 = 0x1, 2303 MAPPED_RIGHT_PADDLE1 = 0x2, 2304 MAPPED_LEFT_PADDLE2 = 0x4, 2305 MAPPED_RIGHT_PADDLE2 = 0x8, 2306 MAPPED_PADDLE_ALL = 0xF, 2307 }; 2308 unsigned int mapped; 2309 bool result = false; 2310 2311 SDL_AssertJoysticksLocked(); 2312 2313 if (item->checked_mapping) { 2314 if (item->mapping) { 2315 SDL_memcpy(out, item->mapping, sizeof(*out)); 2316#ifdef DEBUG_GAMEPAD_MAPPING 2317 SDL_Log("Prior mapping for device %d", device_index); 2318#endif 2319 return true; 2320 } else { 2321 return false; 2322 } 2323 } 2324 2325 /* We temporarily open the device to check how it's configured. Make 2326 a fake SDL_Joystick object to do so. */ 2327 joystick = (SDL_Joystick *)SDL_calloc(1, sizeof(*joystick)); 2328 if (!joystick) { 2329 return false; 2330 } 2331 SDL_memcpy(&joystick->guid, &item->guid, sizeof(item->guid)); 2332 2333 joystick->hwdata = (struct joystick_hwdata *)SDL_calloc(1, sizeof(*joystick->hwdata)); 2334 if (!joystick->hwdata) { 2335 SDL_free(joystick); 2336 return false; 2337 } 2338 SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, true); 2339 2340 item->checked_mapping = true; 2341 2342 if (!PrepareJoystickHwdata(joystick, item, NULL)) { 2343 goto done; // SDL_SetError will already have been called 2344 } 2345 2346 // don't assign `item->hwdata` so it's not in any global state. 2347 2348 // it is now safe to call LINUX_JoystickClose on this fake joystick. 2349 2350 if (!joystick->hwdata->has_key[BTN_GAMEPAD]) { 2351 // Not a gamepad according to the specs. 2352 goto done; 2353 } 2354 2355 // We have a gamepad, start filling out the mappings 2356 2357#ifdef DEBUG_GAMEPAD_MAPPING 2358 SDL_Log("Mapping %s (VID/PID 0x%.4x/0x%.4x)", item->name, SDL_GetJoystickVendor(joystick), SDL_GetJoystickProduct(joystick)); 2359#endif 2360 2361 if (joystick->hwdata->has_key[BTN_A]) { 2362 out->a.kind = EMappingKind_Button; 2363 out->a.target = joystick->hwdata->key_map[BTN_A]; 2364#ifdef DEBUG_GAMEPAD_MAPPING 2365 SDL_Log("Mapped A to button %d (BTN_A)", out->a.target); 2366#endif 2367 } 2368 2369 if (joystick->hwdata->has_key[BTN_B]) { 2370 out->b.kind = EMappingKind_Button; 2371 out->b.target = joystick->hwdata->key_map[BTN_B]; 2372#ifdef DEBUG_GAMEPAD_MAPPING 2373 SDL_Log("Mapped B to button %d (BTN_B)", out->b.target); 2374#endif 2375 } 2376 2377 // Xbox controllers use BTN_X and BTN_Y, and PS4 controllers use BTN_WEST and BTN_NORTH 2378 if (SDL_GetJoystickVendor(joystick) == USB_VENDOR_SONY) { 2379 if (joystick->hwdata->has_key[BTN_WEST]) { 2380 out->x.kind = EMappingKind_Button; 2381 out->x.target = joystick->hwdata->key_map[BTN_WEST]; 2382#ifdef DEBUG_GAMEPAD_MAPPING 2383 SDL_Log("Mapped X to button %d (BTN_WEST)", out->x.target); 2384#endif 2385 } 2386 2387 if (joystick->hwdata->has_key[BTN_NORTH]) { 2388 out->y.kind = EMappingKind_Button; 2389 out->y.target = joystick->hwdata->key_map[BTN_NORTH]; 2390#ifdef DEBUG_GAMEPAD_MAPPING 2391 SDL_Log("Mapped Y to button %d (BTN_NORTH)", out->y.target); 2392#endif 2393 } 2394 } else { 2395 if (joystick->hwdata->has_key[BTN_X]) { 2396 out->x.kind = EMappingKind_Button; 2397 out->x.target = joystick->hwdata->key_map[BTN_X]; 2398#ifdef DEBUG_GAMEPAD_MAPPING 2399 SDL_Log("Mapped X to button %d (BTN_X)", out->x.target); 2400#endif 2401 } 2402 2403 if (joystick->hwdata->has_key[BTN_Y]) { 2404 out->y.kind = EMappingKind_Button; 2405 out->y.target = joystick->hwdata->key_map[BTN_Y]; 2406#ifdef DEBUG_GAMEPAD_MAPPING 2407 SDL_Log("Mapped Y to button %d (BTN_Y)", out->y.target); 2408#endif 2409 } 2410 } 2411 2412 if (joystick->hwdata->has_key[BTN_SELECT]) { 2413 out->back.kind = EMappingKind_Button; 2414 out->back.target = joystick->hwdata->key_map[BTN_SELECT]; 2415#ifdef DEBUG_GAMEPAD_MAPPING 2416 SDL_Log("Mapped BACK to button %d (BTN_SELECT)", out->back.target); 2417#endif 2418 } 2419 2420 if (joystick->hwdata->has_key[BTN_START]) { 2421 out->start.kind = EMappingKind_Button; 2422 out->start.target = joystick->hwdata->key_map[BTN_START]; 2423#ifdef DEBUG_GAMEPAD_MAPPING 2424 SDL_Log("Mapped START to button %d (BTN_START)", out->start.target); 2425#endif 2426 } 2427 2428 if (joystick->hwdata->has_key[BTN_THUMBL]) { 2429 out->leftstick.kind = EMappingKind_Button; 2430 out->leftstick.target = joystick->hwdata->key_map[BTN_THUMBL]; 2431#ifdef DEBUG_GAMEPAD_MAPPING 2432 SDL_Log("Mapped LEFTSTICK to button %d (BTN_THUMBL)", out->leftstick.target); 2433#endif 2434 } 2435 2436 if (joystick->hwdata->has_key[BTN_THUMBR]) { 2437 out->rightstick.kind = EMappingKind_Button; 2438 out->rightstick.target = joystick->hwdata->key_map[BTN_THUMBR]; 2439#ifdef DEBUG_GAMEPAD_MAPPING 2440 SDL_Log("Mapped RIGHTSTICK to button %d (BTN_THUMBR)", out->rightstick.target); 2441#endif 2442 } 2443 2444 if (joystick->hwdata->has_key[BTN_MODE]) { 2445 out->guide.kind = EMappingKind_Button; 2446 out->guide.target = joystick->hwdata->key_map[BTN_MODE]; 2447#ifdef DEBUG_GAMEPAD_MAPPING 2448 SDL_Log("Mapped GUIDE to button %d (BTN_MODE)", out->guide.target); 2449#endif 2450 } 2451 2452 /* 2453 According to the specs the D-Pad, the shoulder buttons and the triggers 2454 can be digital, or analog, or both at the same time. 2455 */ 2456 2457 // Prefer digital shoulder buttons, but settle for digital or analog hat. 2458 mapped = 0; 2459 2460 if (joystick->hwdata->has_key[BTN_TL]) { 2461 out->leftshoulder.kind = EMappingKind_Button; 2462 out->leftshoulder.target = joystick->hwdata->key_map[BTN_TL]; 2463 mapped |= 0x1; 2464#ifdef DEBUG_GAMEPAD_MAPPING 2465 SDL_Log("Mapped LEFTSHOULDER to button %d (BTN_TL)", out->leftshoulder.target); 2466#endif 2467 } 2468 2469 if (joystick->hwdata->has_key[BTN_TR]) { 2470 out->rightshoulder.kind = EMappingKind_Button; 2471 out->rightshoulder.target = joystick->hwdata->key_map[BTN_TR]; 2472 mapped |= 0x2; 2473#ifdef DEBUG_GAMEPAD_MAPPING 2474 SDL_Log("Mapped RIGHTSHOULDER to button %d (BTN_TR)", out->rightshoulder.target); 2475#endif 2476 } 2477 2478 if (mapped != 0x3 && joystick->hwdata->has_hat[1]) { 2479 int hat = joystick->hwdata->hats_indices[1] << 4; 2480 out->leftshoulder.kind = EMappingKind_Hat; 2481 out->rightshoulder.kind = EMappingKind_Hat; 2482 out->leftshoulder.target = hat | 0x4; 2483 out->rightshoulder.target = hat | 0x2; 2484 mapped |= 0x3; 2485#ifdef DEBUG_GAMEPAD_MAPPING 2486 SDL_Log("Mapped LEFT+RIGHTSHOULDER to hat 1 (ABS_HAT1X, ABS_HAT1Y)"); 2487#endif 2488 } 2489 2490 if (!(mapped & 0x1) && joystick->hwdata->has_abs[ABS_HAT1Y]) { 2491 out->leftshoulder.kind = EMappingKind_Axis; 2492 out->leftshoulder.target = joystick->hwdata->abs_map[ABS_HAT1Y]; 2493 mapped |= 0x1; 2494#ifdef DEBUG_GAMEPAD_MAPPING 2495 SDL_Log("Mapped LEFTSHOULDER to axis %d (ABS_HAT1Y)", out->leftshoulder.target); 2496#endif 2497 } 2498 2499 if (!(mapped & 0x2) && joystick->hwdata->has_abs[ABS_HAT1X]) { 2500 out->rightshoulder.kind = EMappingKind_Axis; 2501 out->rightshoulder.target = joystick->hwdata->abs_map[ABS_HAT1X]; 2502 mapped |= 0x2; 2503#ifdef DEBUG_GAMEPAD_MAPPING 2504 SDL_Log("Mapped RIGHTSHOULDER to axis %d (ABS_HAT1X)", out->rightshoulder.target); 2505#endif 2506 } 2507 2508 // Prefer analog triggers, but settle for digital hat or buttons. 2509 mapped = 0; 2510 2511 /* Unfortunately there are several conventions for how analog triggers 2512 * are represented as absolute axes: 2513 * 2514 * - Linux Gamepad Specification: 2515 * LT = ABS_HAT2Y, RT = ABS_HAT2X 2516 * - Android (and therefore many Bluetooth controllers): 2517 * LT = ABS_BRAKE, RT = ABS_GAS 2518 * - De facto standard for older Xbox and Playstation controllers: 2519 * LT = ABS_Z, RT = ABS_RZ 2520 * 2521 * We try each one in turn. */ 2522 if (joystick->hwdata->has_abs[ABS_HAT2Y]) { 2523 // Linux Gamepad Specification 2524 out->lefttrigger.kind = EMappingKind_Axis; 2525 out->lefttrigger.target = joystick->hwdata->abs_map[ABS_HAT2Y]; 2526 mapped |= MAPPED_TRIGGER_LEFT; 2527#ifdef DEBUG_GAMEPAD_MAPPING 2528 SDL_Log("Mapped LEFTTRIGGER to axis %d (ABS_HAT2Y)", out->lefttrigger.target); 2529#endif 2530 } else if (joystick->hwdata->has_abs[ABS_BRAKE]) { 2531 // Android convention 2532 out->lefttrigger.kind = EMappingKind_Axis; 2533 out->lefttrigger.target = joystick->hwdata->abs_map[ABS_BRAKE]; 2534 mapped |= MAPPED_TRIGGER_LEFT; 2535#ifdef DEBUG_GAMEPAD_MAPPING 2536 SDL_Log("Mapped LEFTTRIGGER to axis %d (ABS_BRAKE)", out->lefttrigger.target); 2537#endif 2538 } else if (joystick->hwdata->has_abs[ABS_Z]) { 2539 // De facto standard for Xbox 360 and Playstation gamepads 2540 out->lefttrigger.kind = EMappingKind_Axis; 2541 out->lefttrigger.target = joystick->hwdata->abs_map[ABS_Z]; 2542 mapped |= MAPPED_TRIGGER_LEFT; 2543#ifdef DEBUG_GAMEPAD_MAPPING 2544 SDL_Log("Mapped LEFTTRIGGER to axis %d (ABS_Z)", out->lefttrigger.target); 2545#endif 2546 } 2547 2548 if (joystick->hwdata->has_abs[ABS_HAT2X]) { 2549 // Linux Gamepad Specification 2550 out->righttrigger.kind = EMappingKind_Axis; 2551 out->righttrigger.target = joystick->hwdata->abs_map[ABS_HAT2X]; 2552 mapped |= MAPPED_TRIGGER_RIGHT; 2553#ifdef DEBUG_GAMEPAD_MAPPING 2554 SDL_Log("Mapped RIGHTTRIGGER to axis %d (ABS_HAT2X)", out->righttrigger.target); 2555#endif 2556 } else if (joystick->hwdata->has_abs[ABS_GAS]) { 2557 // Android convention 2558 out->righttrigger.kind = EMappingKind_Axis; 2559 out->righttrigger.target = joystick->hwdata->abs_map[ABS_GAS]; 2560 mapped |= MAPPED_TRIGGER_RIGHT; 2561#ifdef DEBUG_GAMEPAD_MAPPING 2562 SDL_Log("Mapped RIGHTTRIGGER to axis %d (ABS_GAS)", out->righttrigger.target); 2563#endif 2564 } else if (joystick->hwdata->has_abs[ABS_RZ]) { 2565 // De facto standard for Xbox 360 and Playstation gamepads 2566 out->righttrigger.kind = EMappingKind_Axis; 2567 out->righttrigger.target = joystick->hwdata->abs_map[ABS_RZ]; 2568 mapped |= MAPPED_TRIGGER_RIGHT; 2569#ifdef DEBUG_GAMEPAD_MAPPING 2570 SDL_Log("Mapped RIGHTTRIGGER to axis %d (ABS_RZ)", out->righttrigger.target); 2571#endif 2572 } 2573 2574 if (mapped != MAPPED_TRIGGER_BOTH && joystick->hwdata->has_hat[2]) { 2575 int hat = joystick->hwdata->hats_indices[2] << 4; 2576 out->lefttrigger.kind = EMappingKind_Hat; 2577 out->righttrigger.kind = EMappingKind_Hat; 2578 out->lefttrigger.target = hat | 0x4; 2579 out->righttrigger.target = hat | 0x2; 2580 mapped |= MAPPED_TRIGGER_BOTH; 2581#ifdef DEBUG_GAMEPAD_MAPPING 2582 SDL_Log("Mapped LEFT+RIGHTTRIGGER to hat 2 (ABS_HAT2X, ABS_HAT2Y)"); 2583#endif 2584 } 2585 2586 if (!(mapped & MAPPED_TRIGGER_LEFT) && joystick->hwdata->has_key[BTN_TL2]) { 2587 out->lefttrigger.kind = EMappingKind_Button; 2588 out->lefttrigger.target = joystick->hwdata->key_map[BTN_TL2]; 2589 mapped |= MAPPED_TRIGGER_LEFT; 2590#ifdef DEBUG_GAMEPAD_MAPPING 2591 SDL_Log("Mapped LEFTTRIGGER to button %d (BTN_TL2)", out->lefttrigger.target); 2592#endif 2593 } 2594 2595 if (!(mapped & MAPPED_TRIGGER_RIGHT) && joystick->hwdata->has_key[BTN_TR2]) { 2596 out->righttrigger.kind = EMappingKind_Button; 2597 out->righttrigger.target = joystick->hwdata->key_map[BTN_TR2]; 2598 mapped |= MAPPED_TRIGGER_RIGHT; 2599#ifdef DEBUG_GAMEPAD_MAPPING 2600 SDL_Log("Mapped RIGHTTRIGGER to button %d (BTN_TR2)", out->righttrigger.target); 2601#endif 2602 } 2603 2604 // Prefer digital D-Pad buttons, but settle for digital or analog hat. 2605 mapped = 0; 2606 2607 if (joystick->hwdata->has_key[BTN_DPAD_UP]) { 2608 out->dpup.kind = EMappingKind_Button; 2609 out->dpup.target = joystick->hwdata->key_map[BTN_DPAD_UP]; 2610 mapped |= MAPPED_DPAD_UP; 2611#ifdef DEBUG_GAMEPAD_MAPPING 2612 SDL_Log("Mapped DPUP to button %d (BTN_DPAD_UP)", out->dpup.target); 2613#endif 2614 } 2615 2616 if (joystick->hwdata->has_key[BTN_DPAD_DOWN]) { 2617 out->dpdown.kind = EMappingKind_Button; 2618 out->dpdown.target = joystick->hwdata->key_map[BTN_DPAD_DOWN]; 2619 mapped |= MAPPED_DPAD_DOWN; 2620#ifdef DEBUG_GAMEPAD_MAPPING 2621 SDL_Log("Mapped DPDOWN to button %d (BTN_DPAD_DOWN)", out->dpdown.target); 2622#endif 2623 } 2624 2625 if (joystick->hwdata->has_key[BTN_DPAD_LEFT]) { 2626 out->dpleft.kind = EMappingKind_Button; 2627 out->dpleft.target = joystick->hwdata->key_map[BTN_DPAD_LEFT]; 2628 mapped |= MAPPED_DPAD_LEFT; 2629#ifdef DEBUG_GAMEPAD_MAPPING 2630 SDL_Log("Mapped DPLEFT to button %d (BTN_DPAD_LEFT)", out->dpleft.target); 2631#endif 2632 } 2633 2634 if (joystick->hwdata->has_key[BTN_DPAD_RIGHT]) { 2635 out->dpright.kind = EMappingKind_Button; 2636 out->dpright.target = joystick->hwdata->key_map[BTN_DPAD_RIGHT]; 2637 mapped |= MAPPED_DPAD_RIGHT; 2638#ifdef DEBUG_GAMEPAD_MAPPING 2639 SDL_Log("Mapped DPRIGHT to button %d (BTN_DPAD_RIGHT)", out->dpright.target); 2640#endif 2641 } 2642 2643 if (mapped != MAPPED_DPAD_ALL) { 2644 if (joystick->hwdata->has_hat[0]) { 2645 int hat = joystick->hwdata->hats_indices[0] << 4; 2646 out->dpleft.kind = EMappingKind_Hat; 2647 out->dpright.kind = EMappingKind_Hat; 2648 out->dpup.kind = EMappingKind_Hat; 2649 out->dpdown.kind = EMappingKind_Hat; 2650 out->dpleft.target = hat | 0x8; 2651 out->dpright.target = hat | 0x2; 2652 out->dpup.target = hat | 0x1; 2653 out->dpdown.target = hat | 0x4; 2654 mapped |= MAPPED_DPAD_ALL; 2655#ifdef DEBUG_GAMEPAD_MAPPING 2656 SDL_Log("Mapped DPUP+DOWN+LEFT+RIGHT to hat 0 (ABS_HAT0X, ABS_HAT0Y)"); 2657#endif 2658 } else if (joystick->hwdata->has_abs[ABS_HAT0X] && joystick->hwdata->has_abs[ABS_HAT0Y]) { 2659 out->dpleft.kind = EMappingKind_Axis; 2660 out->dpright.kind = EMappingKind_Axis; 2661 out->dpup.kind = EMappingKind_Axis; 2662 out->dpdown.kind = EMappingKind_Axis; 2663 out->dpleft.target = joystick->hwdata->abs_map[ABS_HAT0X]; 2664 out->dpright.target = joystick->hwdata->abs_map[ABS_HAT0X]; 2665 out->dpup.target = joystick->hwdata->abs_map[ABS_HAT0Y]; 2666 out->dpdown.target = joystick->hwdata->abs_map[ABS_HAT0Y]; 2667 mapped |= MAPPED_DPAD_ALL; 2668#ifdef DEBUG_GAMEPAD_MAPPING 2669 SDL_Log("Mapped DPUP+DOWN to axis %d (ABS_HAT0Y)", out->dpup.target); 2670 SDL_Log("Mapped DPLEFT+RIGHT to axis %d (ABS_HAT0X)", out->dpleft.target); 2671#endif 2672 } else if (item->driver && SDL_strcmp(item->driver, "xpad") == 0) { 2673 // xpad will sometimes map the D-Pad as BTN_TRIGGER_HAPPY1 - BTN_TRIGGER_HAPPY4 2674 if (joystick->hwdata->has_key[BTN_TRIGGER_HAPPY1] && 2675 joystick->hwdata->has_key[BTN_TRIGGER_HAPPY2] && 2676 joystick->hwdata->has_key[BTN_TRIGGER_HAPPY3] && 2677 joystick->hwdata->has_key[BTN_TRIGGER_HAPPY4]) { 2678 out->dpleft.kind = EMappingKind_Button; 2679 out->dpright.kind = EMappingKind_Button; 2680 out->dpup.kind = EMappingKind_Button; 2681 out->dpdown.kind = EMappingKind_Button; 2682 out->dpleft.target = joystick->hwdata->key_map[BTN_TRIGGER_HAPPY1]; 2683 out->dpright.target = joystick->hwdata->key_map[BTN_TRIGGER_HAPPY2]; 2684 out->dpup.target = joystick->hwdata->key_map[BTN_TRIGGER_HAPPY3]; 2685 out->dpdown.target = joystick->hwdata->key_map[BTN_TRIGGER_HAPPY4]; 2686#ifdef DEBUG_GAMEPAD_MAPPING 2687 SDL_Log("Mapped DPLEFT to button %d (BTN_TRIGGER_HAPPY1)", out->dpleft.target); 2688 SDL_Log("Mapped DPRIGHT to button %d (BTN_TRIGGER_HAPPY2)", out->dpright.target); 2689 SDL_Log("Mapped DPUP to button %d (BTN_TRIGGER_HAPPY3)", out->dpup.target); 2690 SDL_Log("Mapped DPDOWN to button %d (BTN_TRIGGER_HAPPY4)", out->dpdown.target); 2691#endif 2692 } 2693 } 2694 } 2695 2696 if (joystick->hwdata->has_abs[ABS_X] && joystick->hwdata->has_abs[ABS_Y]) { 2697 out->leftx.kind = EMappingKind_Axis; 2698 out->lefty.kind = EMappingKind_Axis; 2699 out->leftx.target = joystick->hwdata->abs_map[ABS_X]; 2700 out->lefty.target = joystick->hwdata->abs_map[ABS_Y]; 2701#ifdef DEBUG_GAMEPAD_MAPPING 2702 SDL_Log("Mapped LEFTX to axis %d (ABS_X)", out->leftx.target); 2703 SDL_Log("Mapped LEFTY to axis %d (ABS_Y)", out->lefty.target); 2704#endif 2705 } 2706 2707 /* The Linux Gamepad Specification uses the RX and RY axes, 2708 * originally intended to represent X and Y rotation, as a second 2709 * joystick. This is common for USB gamepads, and also many Bluetooth 2710 * gamepads, particularly older ones. 2711 * 2712 * The Android mapping convention used by many Bluetooth controllers 2713 * instead uses the Z axis as a secondary X axis, and the RZ axis as 2714 * a secondary Y axis. */ 2715 if (joystick->hwdata->has_abs[ABS_RX] && joystick->hwdata->has_abs[ABS_RY]) { 2716 // Linux Gamepad Specification, Xbox 360, Playstation etc. 2717 out->rightx.kind = EMappingKind_Axis; 2718 out->righty.kind = EMappingKind_Axis; 2719 out->rightx.target = joystick->hwdata->abs_map[ABS_RX]; 2720 out->righty.target = joystick->hwdata->abs_map[ABS_RY]; 2721#ifdef DEBUG_GAMEPAD_MAPPING 2722 SDL_Log("Mapped RIGHTX to axis %d (ABS_RX)", out->rightx.target); 2723 SDL_Log("Mapped RIGHTY to axis %d (ABS_RY)", out->righty.target); 2724#endif 2725 } else if (joystick->hwdata->has_abs[ABS_Z] && joystick->hwdata->has_abs[ABS_RZ]) { 2726 // Android convention 2727 out->rightx.kind = EMappingKind_Axis; 2728 out->righty.kind = EMappingKind_Axis; 2729 out->rightx.target = joystick->hwdata->abs_map[ABS_Z]; 2730 out->righty.target = joystick->hwdata->abs_map[ABS_RZ]; 2731#ifdef DEBUG_GAMEPAD_MAPPING 2732 SDL_Log("Mapped RIGHTX to axis %d (ABS_Z)", out->rightx.target); 2733 SDL_Log("Mapped RIGHTY to axis %d (ABS_RZ)", out->righty.target); 2734#endif 2735 } 2736 2737 mapped = 0; 2738 2739 if (joystick->hwdata->has_key[BTN_GRIPR]) { 2740 out->right_paddle1.kind = EMappingKind_Button; 2741 out->right_paddle1.target = joystick->hwdata->key_map[BTN_GRIPR]; 2742 mapped |= MAPPED_RIGHT_PADDLE1; 2743#ifdef DEBUG_GAMEPAD_MAPPING 2744 SDL_Log("Mapped RIGHT_PADDLE1 to button %d (BTN_GRIPR)", out->right_paddle1.target); 2745#endif 2746 } 2747 if (joystick->hwdata->has_key[BTN_GRIPL]) { 2748 out->left_paddle1.kind = EMappingKind_Button; 2749 out->left_paddle1.target = joystick->hwdata->key_map[BTN_GRIPL]; 2750 mapped |= MAPPED_LEFT_PADDLE1; 2751#ifdef DEBUG_GAMEPAD_MAPPING 2752 SDL_Log("Mapped LEFT_PADDLE1 to button %d (BTN_GRIPL)", out->left_paddle1.target); 2753#endif 2754 } 2755 if (joystick->hwdata->has_key[BTN_GRIPR2]) { 2756 out->right_paddle2.kind = EMappingKind_Button; 2757 out->right_paddle2.target = joystick->hwdata->key_map[BTN_GRIPR2]; 2758 mapped |= MAPPED_RIGHT_PADDLE2; 2759#ifdef DEBUG_GAMEPAD_MAPPING 2760 SDL_Log("Mapped RIGHT_PADDLE2 to button %d (BTN_GRIPR)", out->right_paddle2.target); 2761#endif 2762 } 2763 if (joystick->hwdata->has_key[BTN_GRIPL2]) { 2764 out->left_paddle2.kind = EMappingKind_Button; 2765 out->left_paddle2.target = joystick->hwdata->key_map[BTN_GRIPL2]; 2766 mapped |= MAPPED_LEFT_PADDLE2; 2767#ifdef DEBUG_GAMEPAD_MAPPING 2768 SDL_Log("Mapped LEFT_PADDLE2 to button %d (BTN_GRIPL2)", out->left_paddle2.target); 2769#endif 2770 } 2771 2772 if (mapped != MAPPED_PADDLE_ALL && SDL_GetJoystickVendor(joystick) == USB_VENDOR_MICROSOFT) { 2773 // The Xbox Elite controllers have the paddles as BTN_TRIGGER_HAPPY5 - BTN_TRIGGER_HAPPY8 2774 // in older drivers 2775 if (joystick->hwdata->has_key[BTN_TRIGGER_HAPPY5] && 2776 joystick->hwdata->has_key[BTN_TRIGGER_HAPPY6] && 2777 joystick->hwdata->has_key[BTN_TRIGGER_HAPPY7] && 2778 joystick->hwdata->has_key[BTN_TRIGGER_HAPPY8]) { 2779 out->right_paddle1.kind = EMappingKind_Button; 2780 out->right_paddle1.target = joystick->hwdata->key_map[BTN_TRIGGER_HAPPY5]; 2781 out->left_paddle1.kind = EMappingKind_Button; 2782 out->left_paddle1.target = joystick->hwdata->key_map[BTN_TRIGGER_HAPPY7]; 2783 out->right_paddle2.kind = EMappingKind_Button; 2784 out->right_paddle2.target = joystick->hwdata->key_map[BTN_TRIGGER_HAPPY6]; 2785 out->left_paddle2.kind = EMappingKind_Button; 2786 out->left_paddle2.target = joystick->hwdata->key_map[BTN_TRIGGER_HAPPY8]; 2787 mapped = MAPPED_PADDLE_ALL; 2788#ifdef DEBUG_GAMEPAD_MAPPING 2789 SDL_Log("Mapped RIGHT_PADDLE1 to button %d (BTN_TRIGGER_HAPPY5)", out->right_paddle1.target); 2790 SDL_Log("Mapped LEFT_PADDLE1 to button %d (BTN_TRIGGER_HAPPY7)", out->left_paddle1.target); 2791 SDL_Log("Mapped RIGHT_PADDLE2 to button %d (BTN_TRIGGER_HAPPY6)", out->right_paddle2.target); 2792 SDL_Log("Mapped LEFT_PADDLE2 to button %d (BTN_TRIGGER_HAPPY8)", out->left_paddle2.target); 2793#endif 2794 } 2795 } 2796 2797 // Xbox Series controllers have the Share button as KEY_RECORD 2798 if (joystick->hwdata->has_key[KEY_RECORD]) { 2799 out->misc1.kind = EMappingKind_Button; 2800 out->misc1.target = joystick->hwdata->key_map[KEY_RECORD]; 2801#ifdef DEBUG_GAMEPAD_MAPPING 2802 SDL_Log("Mapped MISC1 to button %d (KEY_RECORD)", out->misc1.target); 2803#endif 2804 } 2805 2806 // Cache the mapping for later 2807 item->mapping = (SDL_GamepadMapping *)SDL_malloc(sizeof(*item->mapping)); 2808 if (item->mapping) { 2809 SDL_memcpy(item->mapping, out, sizeof(*out)); 2810 } 2811#ifdef DEBUG_GAMEPAD_MAPPING 2812 SDL_Log("Generated mapping for device %d", device_index); 2813#endif 2814 result = true; 2815 2816done: 2817 LINUX_JoystickClose(joystick); 2818 SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, false); 2819 SDL_free(joystick); 2820 2821 return result; 2822} 2823 2824SDL_JoystickDriver SDL_LINUX_JoystickDriver = { 2825 LINUX_JoystickInit, 2826 LINUX_JoystickGetCount, 2827 LINUX_JoystickDetect, 2828 LINUX_JoystickIsDevicePresent, 2829 LINUX_JoystickGetDeviceName, 2830 LINUX_JoystickGetDevicePath, 2831 LINUX_JoystickGetDeviceSteamVirtualGamepadSlot, 2832 LINUX_JoystickGetDevicePlayerIndex, 2833 LINUX_JoystickSetDevicePlayerIndex, 2834 LINUX_JoystickGetDeviceGUID, 2835 LINUX_JoystickGetDeviceInstanceID, 2836 LINUX_JoystickOpen, 2837 LINUX_JoystickRumble, 2838 LINUX_JoystickRumbleTriggers, 2839 LINUX_JoystickSetLED, 2840 LINUX_JoystickSendEffect, 2841 LINUX_JoystickSetSensorsEnabled, 2842 LINUX_JoystickUpdate, 2843 LINUX_JoystickClose, 2844 LINUX_JoystickQuit, 2845 LINUX_JoystickGetGamepadMapping 2846}; 2847 2848#endif // SDL_JOYSTICK_LINUX 2849
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.