Atlas - SDL_sysjoystick.c
Home / ext / SDL / src / joystick / android Lines: 1 | Size: 19594 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_ANDROID 24 25#include <stdio.h> // For the definition of NULL 26 27#include "SDL_sysjoystick_c.h" 28#include "../SDL_joystick_c.h" 29#include "../../events/SDL_keyboard_c.h" 30#include "../../core/android/SDL_android.h" 31#include "../hidapi/SDL_hidapijoystick_c.h" 32 33#include "android/keycodes.h" 34 35// As of platform android-14, android/keycodes.h is missing these defines 36#ifndef AKEYCODE_BUTTON_1 37#define AKEYCODE_BUTTON_1 188 38#define AKEYCODE_BUTTON_2 189 39#define AKEYCODE_BUTTON_3 190 40#define AKEYCODE_BUTTON_4 191 41#define AKEYCODE_BUTTON_5 192 42#define AKEYCODE_BUTTON_6 193 43#define AKEYCODE_BUTTON_7 194 44#define AKEYCODE_BUTTON_8 195 45#define AKEYCODE_BUTTON_9 196 46#define AKEYCODE_BUTTON_10 197 47#define AKEYCODE_BUTTON_11 198 48#define AKEYCODE_BUTTON_12 199 49#define AKEYCODE_BUTTON_13 200 50#define AKEYCODE_BUTTON_14 201 51#define AKEYCODE_BUTTON_15 202 52#define AKEYCODE_BUTTON_16 203 53#endif 54 55#define ANDROID_MAX_NBUTTONS 36 56 57static SDL_joylist_item *JoystickByDeviceId(int device_id); 58 59static SDL_joylist_item *SDL_joylist = NULL; 60static SDL_joylist_item *SDL_joylist_tail = NULL; 61static int numjoysticks = 0; 62 63/* Function to convert Android keyCodes into SDL ones. 64 * This code manipulation is done to get a sequential list of codes. 65 * FIXME: This is only suited for the case where we use a fixed number of buttons determined by ANDROID_MAX_NBUTTONS 66 */ 67static int keycode_to_SDL(int keycode) 68{ 69 // FIXME: If this function gets too unwieldy in the future, replace with a lookup table 70 int button = 0; 71 switch (keycode) { 72 // Some gamepad buttons (API 9) 73 case AKEYCODE_BUTTON_A: 74 button = SDL_GAMEPAD_BUTTON_SOUTH; 75 break; 76 case AKEYCODE_BUTTON_B: 77 button = SDL_GAMEPAD_BUTTON_EAST; 78 break; 79 case AKEYCODE_BUTTON_X: 80 button = SDL_GAMEPAD_BUTTON_WEST; 81 break; 82 case AKEYCODE_BUTTON_Y: 83 button = SDL_GAMEPAD_BUTTON_NORTH; 84 break; 85 case AKEYCODE_BUTTON_L1: 86 button = SDL_GAMEPAD_BUTTON_LEFT_SHOULDER; 87 break; 88 case AKEYCODE_BUTTON_R1: 89 button = SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER; 90 break; 91 case AKEYCODE_BUTTON_THUMBL: 92 button = SDL_GAMEPAD_BUTTON_LEFT_STICK; 93 break; 94 case AKEYCODE_BUTTON_THUMBR: 95 button = SDL_GAMEPAD_BUTTON_RIGHT_STICK; 96 break; 97 case AKEYCODE_MENU: 98 case AKEYCODE_BUTTON_START: 99 button = SDL_GAMEPAD_BUTTON_START; 100 break; 101 case AKEYCODE_BACK: 102 case AKEYCODE_BUTTON_SELECT: 103 button = SDL_GAMEPAD_BUTTON_BACK; 104 break; 105 case AKEYCODE_BUTTON_MODE: 106 button = SDL_GAMEPAD_BUTTON_GUIDE; 107 break; 108 case AKEYCODE_BUTTON_L2: 109 button = 15; 110 break; 111 case AKEYCODE_BUTTON_R2: 112 button = 16; 113 break; 114 case AKEYCODE_BUTTON_C: 115 button = 17; 116 break; 117 case AKEYCODE_BUTTON_Z: 118 button = 18; 119 break; 120 121 // D-Pad key codes (API 1) 122 case AKEYCODE_DPAD_UP: 123 button = SDL_GAMEPAD_BUTTON_DPAD_UP; 124 break; 125 case AKEYCODE_DPAD_DOWN: 126 button = SDL_GAMEPAD_BUTTON_DPAD_DOWN; 127 break; 128 case AKEYCODE_DPAD_LEFT: 129 button = SDL_GAMEPAD_BUTTON_DPAD_LEFT; 130 break; 131 case AKEYCODE_DPAD_RIGHT: 132 button = SDL_GAMEPAD_BUTTON_DPAD_RIGHT; 133 break; 134 case AKEYCODE_DPAD_CENTER: 135 // This is handled better by applications as the A button 136 // button = 19; 137 button = SDL_GAMEPAD_BUTTON_SOUTH; 138 break; 139 140 // More gamepad buttons (API 12), these get mapped to 20...35 141 case AKEYCODE_BUTTON_1: 142 case AKEYCODE_BUTTON_2: 143 case AKEYCODE_BUTTON_3: 144 case AKEYCODE_BUTTON_4: 145 case AKEYCODE_BUTTON_5: 146 case AKEYCODE_BUTTON_6: 147 case AKEYCODE_BUTTON_7: 148 case AKEYCODE_BUTTON_8: 149 case AKEYCODE_BUTTON_9: 150 case AKEYCODE_BUTTON_10: 151 case AKEYCODE_BUTTON_11: 152 case AKEYCODE_BUTTON_12: 153 case AKEYCODE_BUTTON_13: 154 case AKEYCODE_BUTTON_14: 155 case AKEYCODE_BUTTON_15: 156 case AKEYCODE_BUTTON_16: 157 button = 20 + (keycode - AKEYCODE_BUTTON_1); 158 break; 159 160 default: 161 return -1; 162 // break; -Wunreachable-code-break 163 } 164 165 /* This is here in case future generations, probably with six fingers per hand, 166 * happily add new cases up above and forget to update the max number of buttons. 167 */ 168 SDL_assert(button < ANDROID_MAX_NBUTTONS); 169 return button; 170} 171 172static SDL_Scancode button_to_scancode(int button) 173{ 174 switch (button) { 175 case SDL_GAMEPAD_BUTTON_SOUTH: 176 return SDL_SCANCODE_RETURN; 177 case SDL_GAMEPAD_BUTTON_EAST: 178 return SDL_SCANCODE_ESCAPE; 179 case SDL_GAMEPAD_BUTTON_BACK: 180 return SDL_SCANCODE_ESCAPE; 181 case SDL_GAMEPAD_BUTTON_START: 182 return SDL_SCANCODE_MENU; 183 case SDL_GAMEPAD_BUTTON_DPAD_UP: 184 return SDL_SCANCODE_UP; 185 case SDL_GAMEPAD_BUTTON_DPAD_DOWN: 186 return SDL_SCANCODE_DOWN; 187 case SDL_GAMEPAD_BUTTON_DPAD_LEFT: 188 return SDL_SCANCODE_LEFT; 189 case SDL_GAMEPAD_BUTTON_DPAD_RIGHT: 190 return SDL_SCANCODE_RIGHT; 191 } 192 193 // Unsupported button 194 return SDL_SCANCODE_UNKNOWN; 195} 196 197bool Android_OnPadDown(int device_id, int keycode) 198{ 199 Uint64 timestamp = SDL_GetTicksNS(); 200 SDL_joylist_item *item; 201 int button = keycode_to_SDL(keycode); 202 if (button >= 0) { 203 SDL_LockJoysticks(); 204 item = JoystickByDeviceId(device_id); 205 if (item && item->joystick) { 206 SDL_SendJoystickButton(timestamp, item->joystick, button, true); 207 } else { 208 SDL_SendKeyboardKey(timestamp, SDL_GLOBAL_KEYBOARD_ID, keycode, button_to_scancode(button), true); 209 } 210 SDL_UnlockJoysticks(); 211 return true; 212 } 213 214 return false; 215} 216 217bool Android_OnPadUp(int device_id, int keycode) 218{ 219 Uint64 timestamp = SDL_GetTicksNS(); 220 SDL_joylist_item *item; 221 int button = keycode_to_SDL(keycode); 222 if (button >= 0) { 223 SDL_LockJoysticks(); 224 item = JoystickByDeviceId(device_id); 225 if (item && item->joystick) { 226 SDL_SendJoystickButton(timestamp, item->joystick, button, false); 227 } else { 228 SDL_SendKeyboardKey(timestamp, SDL_GLOBAL_KEYBOARD_ID, keycode, button_to_scancode(button), false); 229 } 230 SDL_UnlockJoysticks(); 231 return true; 232 } 233 234 return false; 235} 236 237bool Android_OnJoy(int device_id, int axis, float value) 238{ 239 Uint64 timestamp = SDL_GetTicksNS(); 240 // Android gives joy info normalized as [-1.0, 1.0] or [0.0, 1.0] 241 SDL_joylist_item *item; 242 243 SDL_LockJoysticks(); 244 item = JoystickByDeviceId(device_id); 245 if (item && item->joystick) { 246 SDL_SendJoystickAxis(timestamp, item->joystick, axis, (Sint16)(32767. * value)); 247 } 248 SDL_UnlockJoysticks(); 249 250 return true; 251} 252 253bool Android_OnHat(int device_id, int hat_id, int x, int y) 254{ 255 Uint64 timestamp = SDL_GetTicksNS(); 256 const int DPAD_UP_MASK = (1 << SDL_GAMEPAD_BUTTON_DPAD_UP); 257 const int DPAD_DOWN_MASK = (1 << SDL_GAMEPAD_BUTTON_DPAD_DOWN); 258 const int DPAD_LEFT_MASK = (1 << SDL_GAMEPAD_BUTTON_DPAD_LEFT); 259 const int DPAD_RIGHT_MASK = (1 << SDL_GAMEPAD_BUTTON_DPAD_RIGHT); 260 261 if (x >= -1 && x <= 1 && y >= -1 && y <= 1) { 262 SDL_joylist_item *item; 263 264 SDL_LockJoysticks(); 265 item = JoystickByDeviceId(device_id); 266 if (item && item->joystick) { 267 int dpad_state = 0; 268 int dpad_delta; 269 if (x < 0) { 270 dpad_state |= DPAD_LEFT_MASK; 271 } else if (x > 0) { 272 dpad_state |= DPAD_RIGHT_MASK; 273 } 274 if (y < 0) { 275 dpad_state |= DPAD_UP_MASK; 276 } else if (y > 0) { 277 dpad_state |= DPAD_DOWN_MASK; 278 } 279 280 dpad_delta = (dpad_state ^ item->dpad_state); 281 if (dpad_delta) { 282 if (dpad_delta & DPAD_UP_MASK) { 283 bool down = ((dpad_state & DPAD_UP_MASK) != 0); 284 SDL_SendJoystickButton(timestamp, item->joystick, SDL_GAMEPAD_BUTTON_DPAD_UP, down); 285 } 286 if (dpad_delta & DPAD_DOWN_MASK) { 287 bool down = ((dpad_state & DPAD_DOWN_MASK) != 0); 288 SDL_SendJoystickButton(timestamp, item->joystick, SDL_GAMEPAD_BUTTON_DPAD_DOWN, down); 289 } 290 if (dpad_delta & DPAD_LEFT_MASK) { 291 bool down = ((dpad_state & DPAD_LEFT_MASK) != 0); 292 SDL_SendJoystickButton(timestamp, item->joystick, SDL_GAMEPAD_BUTTON_DPAD_LEFT, down); 293 } 294 if (dpad_delta & DPAD_RIGHT_MASK) { 295 bool down = ((dpad_state & DPAD_RIGHT_MASK) != 0); 296 SDL_SendJoystickButton(timestamp, item->joystick, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, down); 297 } 298 item->dpad_state = dpad_state; 299 } 300 } 301 SDL_UnlockJoysticks(); 302 return true; 303 } 304 305 return false; 306} 307 308void Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, int button_mask, int naxes, int axis_mask, int nhats, bool can_rumble) 309{ 310 SDL_joylist_item *item; 311 SDL_GUID guid; 312 int i; 313 314 SDL_LockJoysticks(); 315 316 if (!SDL_GetHintBoolean(SDL_HINT_TV_REMOTE_AS_JOYSTICK, true)) { 317 // Ignore devices that aren't actually controllers (e.g. remotes), they'll be handled as keyboard input 318 if (naxes < 2 && nhats < 1) { 319 goto done; 320 } 321 } 322 323 if (JoystickByDeviceId(device_id) != NULL || !name) { 324 goto done; 325 } 326 327 if (SDL_JoystickHandledByAnotherDriver(&SDL_ANDROID_JoystickDriver, vendor_id, product_id, 0, name)) { 328 goto done; 329 } 330 331 if (SDL_ShouldIgnoreJoystick(vendor_id, product_id, 0, name)) { 332 goto done; 333 } 334 335#ifdef DEBUG_JOYSTICK 336 SDL_Log("Joystick: %s, descriptor %s, vendor = 0x%.4x, product = 0x%.4x, %d axes, %d hats", name, desc, vendor_id, product_id, naxes, nhats); 337#endif 338 339 if (nhats > 0) { 340 // Hat is translated into DPAD buttons 341 button_mask |= ((1 << SDL_GAMEPAD_BUTTON_DPAD_UP) | 342 (1 << SDL_GAMEPAD_BUTTON_DPAD_DOWN) | 343 (1 << SDL_GAMEPAD_BUTTON_DPAD_LEFT) | 344 (1 << SDL_GAMEPAD_BUTTON_DPAD_RIGHT)); 345 nhats = 0; 346 } 347 348 guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_BLUETOOTH, vendor_id, product_id, 0, NULL, desc, 0, 0); 349 350 // Update the GUID with capability bits 351 { 352 Uint16 *guid16 = (Uint16 *)guid.data; 353 guid16[6] = SDL_Swap16LE(button_mask); 354 guid16[7] = SDL_Swap16LE(axis_mask); 355 } 356 357 item = (SDL_joylist_item *)SDL_malloc(sizeof(SDL_joylist_item)); 358 if (!item) { 359 goto done; 360 } 361 362 SDL_zerop(item); 363 item->guid = guid; 364 item->device_id = device_id; 365 item->name = SDL_CreateJoystickName(vendor_id, product_id, NULL, name); 366 if (!item->name) { 367 SDL_free(item); 368 goto done; 369 } 370 371 if (button_mask == 0xFFFFFFFF) { 372 item->nbuttons = ANDROID_MAX_NBUTTONS; 373 } else { 374 for (i = 0; i < sizeof(button_mask) * 8; ++i) { 375 if (button_mask & (1 << i)) { 376 item->nbuttons = i + 1; 377 } 378 } 379 } 380 item->naxes = naxes; 381 item->nhats = nhats; 382 item->can_rumble = can_rumble; 383 item->device_instance = SDL_GetNextObjectID(); 384 if (!SDL_joylist_tail) { 385 SDL_joylist = SDL_joylist_tail = item; 386 } else { 387 SDL_joylist_tail->next = item; 388 SDL_joylist_tail = item; 389 } 390 391 // Need to increment the joystick count before we post the event 392 ++numjoysticks; 393 394 SDL_PrivateJoystickAdded(item->device_instance); 395 396#ifdef DEBUG_JOYSTICK 397 SDL_Log("Added joystick %s with device_id %d", item->name, device_id); 398#endif 399 400done: 401 SDL_UnlockJoysticks(); 402} 403 404void Android_RemoveJoystick(int device_id) 405{ 406 SDL_joylist_item *item = SDL_joylist; 407 SDL_joylist_item *prev = NULL; 408 409 SDL_LockJoysticks(); 410 411 // Don't call JoystickByDeviceId here or there'll be an infinite loop! 412 while (item) { 413 if (item->device_id == device_id) { 414 break; 415 } 416 prev = item; 417 item = item->next; 418 } 419 420 if (!item) { 421 goto done; 422 } 423 424 if (item->joystick) { 425 item->joystick->hwdata = NULL; 426 } 427 428 if (prev) { 429 prev->next = item->next; 430 } else { 431 SDL_assert(SDL_joylist == item); 432 SDL_joylist = item->next; 433 } 434 if (item == SDL_joylist_tail) { 435 SDL_joylist_tail = prev; 436 } 437 438 // Need to decrement the joystick count before we post the event 439 --numjoysticks; 440 441 SDL_PrivateJoystickRemoved(item->device_instance); 442 443#ifdef DEBUG_JOYSTICK 444 SDL_Log("Removed joystick with device_id %d", device_id); 445#endif 446 447 SDL_free(item->name); 448 SDL_free(item); 449 450done: 451 SDL_UnlockJoysticks(); 452} 453 454static void ANDROID_JoystickDetect(void); 455 456static bool ANDROID_JoystickInit(void) 457{ 458 ANDROID_JoystickDetect(); 459 return true; 460} 461 462static int ANDROID_JoystickGetCount(void) 463{ 464 return numjoysticks; 465} 466 467static void ANDROID_JoystickDetect(void) 468{ 469 /* Support for device connect/disconnect is API >= 16 only, 470 * so we poll every three seconds 471 * Ref: http://developer.android.com/reference/android/hardware/input/InputManager.InputDeviceListener.html 472 */ 473 static Uint64 timeout = 0; 474 Uint64 now = SDL_GetTicks(); 475 if (!timeout || now >= timeout) { 476 timeout = now + 3000; 477 Android_JNI_PollInputDevices(); 478 } 479} 480 481static bool ANDROID_JoystickIsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name) 482{ 483 // We don't override any other drivers 484 return false; 485} 486 487static SDL_joylist_item *GetJoystickByDevIndex(int device_index) 488{ 489 SDL_joylist_item *item = SDL_joylist; 490 491 if ((device_index < 0) || (device_index >= numjoysticks)) { 492 return NULL; 493 } 494 495 while (device_index > 0) { 496 SDL_assert(item != NULL); 497 device_index--; 498 item = item->next; 499 } 500 501 return item; 502} 503 504static SDL_joylist_item *JoystickByDeviceId(int device_id) 505{ 506 SDL_joylist_item *item = SDL_joylist; 507 508 while (item) { 509 if (item->device_id == device_id) { 510 return item; 511 } 512 item = item->next; 513 } 514 515 // Joystick not found, try adding it 516 ANDROID_JoystickDetect(); 517 518 while (item) { 519 if (item->device_id == device_id) { 520 return item; 521 } 522 item = item->next; 523 } 524 525 return NULL; 526} 527 528static const char *ANDROID_JoystickGetDeviceName(int device_index) 529{ 530 return GetJoystickByDevIndex(device_index)->name; 531} 532 533static const char *ANDROID_JoystickGetDevicePath(int device_index) 534{ 535 return NULL; 536} 537 538static int ANDROID_JoystickGetDeviceSteamVirtualGamepadSlot(int device_index) 539{ 540 return -1; 541} 542 543static int ANDROID_JoystickGetDevicePlayerIndex(int device_index) 544{ 545 return -1; 546} 547 548static void ANDROID_JoystickSetDevicePlayerIndex(int device_index, int player_index) 549{ 550} 551 552static SDL_GUID ANDROID_JoystickGetDeviceGUID(int device_index) 553{ 554 return GetJoystickByDevIndex(device_index)->guid; 555} 556 557static SDL_JoystickID ANDROID_JoystickGetDeviceInstanceID(int device_index) 558{ 559 return GetJoystickByDevIndex(device_index)->device_instance; 560} 561 562static bool ANDROID_JoystickOpen(SDL_Joystick *joystick, int device_index) 563{ 564 SDL_joylist_item *item = GetJoystickByDevIndex(device_index); 565 566 if (!item) { 567 return SDL_SetError("No such device"); 568 } 569 570 if (item->joystick) { 571 return SDL_SetError("Joystick already opened"); 572 } 573 574 joystick->hwdata = (struct joystick_hwdata *)item; 575 item->joystick = joystick; 576 joystick->nhats = item->nhats; 577 joystick->nbuttons = item->nbuttons; 578 joystick->naxes = item->naxes; 579 580 if (item->can_rumble) { 581 SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true); 582 } 583 584 return true; 585} 586 587static bool ANDROID_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 588{ 589 SDL_joylist_item *item = (SDL_joylist_item *)joystick->hwdata; 590 if (!item) { 591 return SDL_SetError("Rumble failed, device disconnected"); 592 } 593 if (!item->can_rumble) { 594 return SDL_Unsupported(); 595 } 596 597 float low_frequency_intensity = (float)low_frequency_rumble / SDL_MAX_UINT16; 598 float high_frequency_intensity = (float)high_frequency_rumble / SDL_MAX_UINT16; 599 Android_JNI_HapticRumble(item->device_id, low_frequency_intensity, high_frequency_intensity, 5000); 600 return true; 601} 602 603static bool ANDROID_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) 604{ 605 return SDL_Unsupported(); 606} 607 608static bool ANDROID_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) 609{ 610 return SDL_Unsupported(); 611} 612 613static bool ANDROID_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) 614{ 615 return SDL_Unsupported(); 616} 617 618static bool ANDROID_JoystickSetSensorsEnabled(SDL_Joystick *joystick, bool enabled) 619{ 620 return SDL_Unsupported(); 621} 622 623static void ANDROID_JoystickUpdate(SDL_Joystick *joystick) 624{ 625} 626 627static void ANDROID_JoystickClose(SDL_Joystick *joystick) 628{ 629 SDL_joylist_item *item = (SDL_joylist_item *)joystick->hwdata; 630 if (item) { 631 item->joystick = NULL; 632 } 633} 634 635static void ANDROID_JoystickQuit(void) 636{ 637/* We don't have any way to scan for joysticks at init, so don't wipe the list 638 * of joysticks here in case this is a reinit. 639 */ 640#if 0 641 SDL_joylist_item *item = NULL; 642 SDL_joylist_item *next = NULL; 643 644 for (item = SDL_joylist; item; item = next) { 645 next = item->next; 646 SDL_free(item->name); 647 SDL_free(item); 648 } 649 650 SDL_joylist = SDL_joylist_tail = NULL; 651 652 numjoysticks = 0; 653#endif // 0 654} 655 656static bool ANDROID_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) 657{ 658 return false; 659} 660 661SDL_JoystickDriver SDL_ANDROID_JoystickDriver = { 662 ANDROID_JoystickInit, 663 ANDROID_JoystickGetCount, 664 ANDROID_JoystickDetect, 665 ANDROID_JoystickIsDevicePresent, 666 ANDROID_JoystickGetDeviceName, 667 ANDROID_JoystickGetDevicePath, 668 ANDROID_JoystickGetDeviceSteamVirtualGamepadSlot, 669 ANDROID_JoystickGetDevicePlayerIndex, 670 ANDROID_JoystickSetDevicePlayerIndex, 671 ANDROID_JoystickGetDeviceGUID, 672 ANDROID_JoystickGetDeviceInstanceID, 673 ANDROID_JoystickOpen, 674 ANDROID_JoystickRumble, 675 ANDROID_JoystickRumbleTriggers, 676 ANDROID_JoystickSetLED, 677 ANDROID_JoystickSendEffect, 678 ANDROID_JoystickSetSensorsEnabled, 679 ANDROID_JoystickUpdate, 680 ANDROID_JoystickClose, 681 ANDROID_JoystickQuit, 682 ANDROID_JoystickGetGamepadMapping 683}; 684 685#endif // SDL_JOYSTICK_ANDROID 686[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.