Atlas - SDL_sysjoystick.c

Home / ext / SDL / src / joystick / emscripten Lines: 1 | Size: 23409 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 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 22#include "SDL_internal.h" 23 24#ifdef SDL_JOYSTICK_EMSCRIPTEN 25 26#include <stdio.h> // For the definition of NULL 27 28#include "SDL_sysjoystick_c.h" 29#include "../SDL_joystick_c.h" 30#include "../usb_ids.h" 31 32static SDL_joylist_item *JoystickByIndex(int index); 33 34static SDL_joylist_item *SDL_joylist = NULL; 35static SDL_joylist_item *SDL_joylist_tail = NULL; 36static int numjoysticks = 0; 37 38static int SDL_GetEmscriptenJoystickVendor(int device_index) 39{ 40 return MAIN_THREAD_EM_ASM_INT({ 41 let gamepad = navigator['getGamepads']()[$0]; 42 if (!gamepad) { 43 return 0; 44 } 45 46 // Chrome, Edge, Opera: Wireless Controller (STANDARD GAMEPAD Vendor: 054c Product: 09cc) 47 let vendor_str = 'Vendor: '; 48 if (gamepad['id']['indexOf'](vendor_str) > 0) { 49 let vendor_str_index = gamepad['id']['indexOf'](vendor_str) + vendor_str['length']; 50 return parseInt(gamepad['id']['substr'](vendor_str_index, 4), 16); 51 } 52 53 // Firefox, Safari: 046d-c216-Logitech Dual Action (or 46d-c216-Logicool Dual Action) 54 let id_split = gamepad['id']['split']('-'); 55 if (id_split['length'] > 1 && !isNaN(parseInt(id_split[0], 16))) { 56 return parseInt(id_split[0], 16); 57 } 58 59 return 0; 60 }, device_index); 61} 62 63static int SDL_GetEmscriptenJoystickProduct(int device_index) 64{ 65 return MAIN_THREAD_EM_ASM_INT({ 66 let gamepad = navigator['getGamepads']()[$0]; 67 if (!gamepad) { 68 return 0; 69 } 70 71 // Chrome, Edge, Opera: Wireless Controller (STANDARD GAMEPAD Vendor: 054c Product: 09cc) 72 let product_str = 'Product: '; 73 if (gamepad['id']['indexOf'](product_str) > 0) { 74 let product_str_index = gamepad['id']['indexOf'](product_str) + product_str['length']; 75 return parseInt(gamepad['id']['substr'](product_str_index, 4), 16); 76 } 77 78 // Firefox, Safari: 046d-c216-Logitech Dual Action (or 46d-c216-Logicool Dual Action) 79 let id_split = gamepad['id']['split']('-'); 80 if (id_split['length'] > 1 && !isNaN(parseInt(id_split[1], 16))) { 81 return parseInt(id_split[1], 16); 82 } 83 84 return 0; 85 }, device_index); 86} 87 88static int SDL_IsEmscriptenJoystickXInput(int device_index) 89{ 90 return MAIN_THREAD_EM_ASM_INT({ 91 let gamepad = navigator['getGamepads']()[$0]; 92 if (!gamepad) { 93 return 0; 94 } 95 96 // Chrome, Edge, Opera: Xbox 360 Controller (XInput STANDARD GAMEPAD) 97 // Firefox: xinput 98 // TODO: Safari 99 return gamepad['id']['toLowerCase']()['indexOf']('xinput') >= 0; 100 }, device_index); 101} 102 103static int SDL_GetEmscriptenOSID() 104{ 105 return MAIN_THREAD_EM_ASM_INT({ 106 const os = ([ 107 'Android', 108 'Linux', 109 'iPhone', 110 'Macintosh', 111 'Windows', 112 ]); 113 const ua = navigator['userAgent']; 114 for (let i = 0; i < os.length; i++) { 115 if (ua['indexOf'](os[i]) >= 0) { 116 return i + 1; 117 } 118 } 119 return 0; 120 }); 121} 122 123static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) 124{ 125 SDL_joylist_item *item; 126 int i; 127 Uint16 bus; 128 Uint16 vendor, product; 129 Uint8 os_id; 130 bool is_xinput; 131 132 SDL_LockJoysticks(); 133 134 if (JoystickByIndex(gamepadEvent->index) != NULL) { 135 goto done; 136 } 137 138 item = (SDL_joylist_item *)SDL_malloc(sizeof(SDL_joylist_item)); 139 if (!item) { 140 goto done; 141 } 142 143 SDL_zerop(item); 144 item->index = gamepadEvent->index; 145 146 bus = SDL_HARDWARE_BUS_UNKNOWN; 147 vendor = SDL_GetEmscriptenJoystickVendor(gamepadEvent->index); 148 product = SDL_GetEmscriptenJoystickProduct(gamepadEvent->index); 149 is_xinput = SDL_IsEmscriptenJoystickXInput(gamepadEvent->index); 150 151 // Use a generic VID/PID representing an XInput controller 152 if (!vendor && !product && is_xinput) { 153 vendor = USB_VENDOR_MICROSOFT; 154 product = USB_PRODUCT_XBOX360_XUSB_CONTROLLER; 155 } 156 157 os_id = SDL_GetEmscriptenOSID(); 158 159 if (os_id != 0) { 160 if (os_id == 1 || os_id == 3) { // Android or iOS (mobile) 161 bus = SDL_HARDWARE_BUS_BLUETOOTH; 162 } else { // Desktop 163 bus = SDL_HARDWARE_BUS_USB; 164 } 165 } 166 167 if (SDL_strcmp(gamepadEvent->mapping, "standard") == 0) { 168 // We should differentiate between devices that are mapped or unmapped by the browser. 169 os_id += 0x80; 170 } 171 172 item->name = SDL_CreateJoystickName(vendor, product, NULL, gamepadEvent->id); 173 if (!item->name) { 174 SDL_free(item); 175 goto done; 176 } 177 178 if (vendor && product) { 179 item->guid = SDL_CreateJoystickGUID(bus, vendor, product, 0, NULL, gamepadEvent->id, 0, os_id); 180 } else { 181 item->guid = SDL_CreateJoystickGUIDForName(item->name); 182 item->guid.data[15] = os_id; 183 } 184 185 if (is_xinput) { 186 item->guid.data[14] = 'x'; // See SDL_IsJoystickXInput 187 } 188 189 item->mapping = SDL_strdup(gamepadEvent->mapping); 190 if (!item->mapping) { 191 SDL_free(item->name); 192 SDL_free(item); 193 goto done; 194 } 195 196 const int real_button_count = gamepadEvent->numButtons; 197 const int real_axis_count = gamepadEvent->numAxes; 198 int first_trigger_button = -1; 199 int first_hat_button = -1; 200 int num_buttons = gamepadEvent->numButtons; 201 int num_axes = gamepadEvent->numAxes; 202 bool triggers_are_buttons = false; 203 if ((SDL_strcmp(gamepadEvent->mapping, "standard") == 0) && (num_buttons >= 16)) { // maps to a game console gamepad layout, turn the d-pad into a hat, treat triggers as analog. 204 num_buttons -= 4; // 4 dpad buttons become a hat. 205 first_hat_button = 12; 206 207 if (num_axes == 4) { // Chrome gives the triggers analog button values, Firefox exposes them as extra axes. Both have the digital buttons. 208 num_axes += 2; // the two trigger "buttons" 209 triggers_are_buttons = true; 210 } 211 212 // dump the digital trigger buttons in any case. 213 first_trigger_button = 6; 214 num_buttons -= 2; 215 } 216 217 item->first_hat_button = first_hat_button; 218 item->first_trigger_button = first_trigger_button; 219 item->triggers_are_buttons = triggers_are_buttons; 220 item->nhats = (first_hat_button >= 0) ? 1 : 0; 221 item->naxes = num_axes; 222 item->nbuttons = num_buttons; 223 item->device_instance = SDL_GetNextObjectID(); 224 225 item->timestamp = gamepadEvent->timestamp; 226 227 int buttonidx = 0; 228 for (i = 0; i < real_button_count; i++, buttonidx++) { 229 if (buttonidx == first_hat_button) { 230 buttonidx += 4; // skip these buttons, we're treating them as hat input. 231 } else if (buttonidx == first_trigger_button) { 232 buttonidx += 2; // skip these buttons, we're treating them as axes. 233 } 234 item->analogButton[i] = gamepadEvent->analogButton[buttonidx]; 235 item->digitalButton[i] = gamepadEvent->digitalButton[buttonidx]; 236 } 237 238 for (i = 0; i < real_axis_count; i++) { 239 item->axis[i] = gamepadEvent->axis[i]; 240 } 241 242 if (item->triggers_are_buttons) { 243 item->axis[real_axis_count] = (gamepadEvent->analogButton[first_trigger_button] * 2.0f) - 1.0f; 244 item->axis[real_axis_count+1] = (gamepadEvent->analogButton[first_trigger_button+1] * 2.0f) - 1.0f; 245 } 246 247 SDL_assert(item->nhats <= 1); // there is (currently) only ever one of these, faked from the d-pad buttons. 248 if (first_hat_button != -1) { 249 Uint8 value = SDL_HAT_CENTERED; 250 // this currently expects the first button to be up, then down, then left, then right. 251 if (gamepadEvent->digitalButton[first_hat_button + 0]) { 252 value |= SDL_HAT_UP; 253 } 254 if (gamepadEvent->digitalButton[first_hat_button + 1]) { 255 value |= SDL_HAT_DOWN; 256 } 257 if (gamepadEvent->digitalButton[first_hat_button + 2]) { 258 value |= SDL_HAT_LEFT; 259 } 260 if (gamepadEvent->digitalButton[first_hat_button + 3]) { 261 value |= SDL_HAT_RIGHT; 262 } 263 item->hat = value; 264 } 265 266 if (!SDL_joylist_tail) { 267 SDL_joylist = SDL_joylist_tail = item; 268 } else { 269 SDL_joylist_tail->next = item; 270 SDL_joylist_tail = item; 271 } 272 273 ++numjoysticks; 274 275 SDL_PrivateJoystickAdded(item->device_instance); 276 277#ifdef DEBUG_JOYSTICK 278 SDL_Log("Number of joysticks is %d", numjoysticks); 279#endif 280#ifdef DEBUG_JOYSTICK 281 SDL_Log("Added joystick with index %d", item->index); 282#endif 283 284done: 285 SDL_UnlockJoysticks(); 286 287 return 1; 288} 289 290static EM_BOOL Emscripten_JoyStickDisconnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) 291{ 292 SDL_joylist_item *item = SDL_joylist; 293 SDL_joylist_item *prev = NULL; 294 295 SDL_LockJoysticks(); 296 297 while (item) { 298 if (item->index == gamepadEvent->index) { 299 break; 300 } 301 prev = item; 302 item = item->next; 303 } 304 305 if (!item) { 306 goto done; 307 } 308 309 if (item->joystick) { 310 item->joystick->hwdata = NULL; 311 } 312 313 if (prev) { 314 prev->next = item->next; 315 } else { 316 SDL_assert(SDL_joylist == item); 317 SDL_joylist = item->next; 318 } 319 if (item == SDL_joylist_tail) { 320 SDL_joylist_tail = prev; 321 } 322 323 // Need to decrement the joystick count before we post the event 324 --numjoysticks; 325 326 SDL_PrivateJoystickRemoved(item->device_instance); 327 328#ifdef DEBUG_JOYSTICK 329 SDL_Log("Removed joystick with id %d", item->device_instance); 330#endif 331 SDL_free(item->name); 332 SDL_free(item->mapping); 333 SDL_free(item); 334 335done: 336 SDL_UnlockJoysticks(); 337 338 return 1; 339} 340 341// Function to perform any system-specific joystick related cleanup 342static void EMSCRIPTEN_JoystickQuit(void) 343{ 344 SDL_joylist_item *item = NULL; 345 SDL_joylist_item *next = NULL; 346 347 for (item = SDL_joylist; item; item = next) { 348 next = item->next; 349 SDL_free(item->mapping); 350 SDL_free(item->name); 351 SDL_free(item); 352 } 353 354 SDL_joylist = SDL_joylist_tail = NULL; 355 356 numjoysticks = 0; 357 358 emscripten_set_gamepadconnected_callback(NULL, 0, NULL); 359 emscripten_set_gamepaddisconnected_callback(NULL, 0, NULL); 360} 361 362// Function to scan the system for joysticks. 363static bool EMSCRIPTEN_JoystickInit(void) 364{ 365 int rc, i, numjs; 366 EmscriptenGamepadEvent gamepadState; 367 368 numjoysticks = 0; 369 370 rc = emscripten_sample_gamepad_data(); 371 372 // Check if gamepad is supported by browser 373 if (rc == EMSCRIPTEN_RESULT_NOT_SUPPORTED) { 374 return SDL_SetError("Gamepads not supported"); 375 } 376 377 numjs = emscripten_get_num_gamepads(); 378 379 // handle already connected gamepads 380 if (numjs > 0) { 381 for (i = 0; i < numjs; i++) { 382 rc = emscripten_get_gamepad_status(i, &gamepadState); 383 if (rc == EMSCRIPTEN_RESULT_SUCCESS) { 384 Emscripten_JoyStickConnected(EMSCRIPTEN_EVENT_GAMEPADCONNECTED, 385 &gamepadState, 386 NULL); 387 } 388 } 389 } 390 391 rc = emscripten_set_gamepadconnected_callback(NULL, 392 0, 393 Emscripten_JoyStickConnected); 394 395 if (rc != EMSCRIPTEN_RESULT_SUCCESS) { 396 EMSCRIPTEN_JoystickQuit(); 397 return SDL_SetError("Could not set gamepad connect callback"); 398 } 399 400 rc = emscripten_set_gamepaddisconnected_callback(NULL, 401 0, 402 Emscripten_JoyStickDisconnected); 403 if (rc != EMSCRIPTEN_RESULT_SUCCESS) { 404 EMSCRIPTEN_JoystickQuit(); 405 return SDL_SetError("Could not set gamepad disconnect callback"); 406 } 407 408 return true; 409} 410 411// Returns item matching given SDL device index. 412static SDL_joylist_item *JoystickByDeviceIndex(int device_index) 413{ 414 SDL_joylist_item *item = SDL_joylist; 415 416 while (0 < device_index) { 417 --device_index; 418 item = item->next; 419 } 420 421 return item; 422} 423 424// Returns item matching given HTML gamepad index. 425static SDL_joylist_item *JoystickByIndex(int index) 426{ 427 SDL_joylist_item *item = SDL_joylist; 428 429 if (index < 0) { 430 return NULL; 431 } 432 433 while (item) { 434 if (item->index == index) { 435 break; 436 } 437 item = item->next; 438 } 439 440 return item; 441} 442 443static int EMSCRIPTEN_JoystickGetCount(void) 444{ 445 return numjoysticks; 446} 447 448static void EMSCRIPTEN_JoystickDetect(void) 449{ 450} 451 452static bool EMSCRIPTEN_JoystickIsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name) 453{ 454 // We don't override any other drivers 455 return false; 456} 457 458static const char *EMSCRIPTEN_JoystickGetDeviceName(int device_index) 459{ 460 return JoystickByDeviceIndex(device_index)->name; 461} 462 463static const char *EMSCRIPTEN_JoystickGetDevicePath(int device_index) 464{ 465 return NULL; 466} 467 468static int EMSCRIPTEN_JoystickGetDeviceSteamVirtualGamepadSlot(int device_index) 469{ 470 return -1; 471} 472 473static int EMSCRIPTEN_JoystickGetDevicePlayerIndex(int device_index) 474{ 475 return -1; 476} 477 478static void EMSCRIPTEN_JoystickSetDevicePlayerIndex(int device_index, int player_index) 479{ 480} 481 482static SDL_JoystickID EMSCRIPTEN_JoystickGetDeviceInstanceID(int device_index) 483{ 484 return JoystickByDeviceIndex(device_index)->device_instance; 485} 486 487static bool EMSCRIPTEN_JoystickOpen(SDL_Joystick *joystick, int device_index) 488{ 489 SDL_joylist_item *item = JoystickByDeviceIndex(device_index); 490 491 if (!item) { 492 return SDL_SetError("No such device"); 493 } 494 495 if (item->joystick) { 496 return SDL_SetError("Joystick already opened"); 497 } 498 499 joystick->hwdata = (struct joystick_hwdata *)item; 500 item->joystick = joystick; 501 502 // HTML5 Gamepad API doesn't offer hats, but we can fake it from the d-pad buttons on the "standard" mapping. 503 joystick->nhats = item->nhats; 504 joystick->nbuttons = item->nbuttons; 505 joystick->naxes = item->naxes; 506 507 item->rumble_available = MAIN_THREAD_EM_ASM_INT({ 508 let gamepad = navigator['getGamepads']()[$0]; 509 return gamepad && gamepad['vibrationActuator'] && gamepad['vibrationActuator']['effects']['includes']('dual-rumble'); 510 }, item->index); 511 512 if (item->rumble_available) { 513 SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true); 514 } 515 516 item->trigger_rumble_available = MAIN_THREAD_EM_ASM_INT({ 517 let gamepad = navigator['getGamepads']()[$0]; 518 return gamepad && gamepad['vibrationActuator'] && gamepad['vibrationActuator']['effects']['includes']('trigger-rumble'); 519 }, item->index); 520 521 if (item->trigger_rumble_available) { 522 SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_TRIGGER_RUMBLE_BOOLEAN, true); 523 } 524 525 return true; 526} 527 528/* Function to update the state of a joystick - called as a device poll. 529 * This function shouldn't update the joystick structure directly, 530 * but instead should call SDL_PrivateJoystick*() to deliver events 531 * and update joystick device state. 532 */ 533static void EMSCRIPTEN_JoystickUpdate(SDL_Joystick *joystick) 534{ 535 EmscriptenGamepadEvent gamepadState; 536 SDL_joylist_item *item = (SDL_joylist_item *)joystick->hwdata; 537 int i, result; 538 Uint64 timestamp = SDL_GetTicksNS(); 539 540 emscripten_sample_gamepad_data(); 541 542 if (item) { 543 result = emscripten_get_gamepad_status(item->index, &gamepadState); 544 if (result == EMSCRIPTEN_RESULT_SUCCESS) { 545 if (gamepadState.timestamp == 0 || gamepadState.timestamp != item->timestamp) { 546 const int first_hat_button = item->first_hat_button; 547 const int first_trigger_button = item->first_trigger_button; 548 const int real_button_count = gamepadState.numButtons; 549 const int real_axis_count = gamepadState.numAxes; 550 551 int buttonidx = 0; 552 for (i = 0; i < real_button_count; i++, buttonidx++) { 553 if (buttonidx == first_hat_button) { 554 buttonidx += 4; // skip these buttons, we're treating them as hat input. 555 } else if (buttonidx == first_trigger_button) { 556 buttonidx += 2; // skip these buttons, we're treating them as axes. 557 } 558 if (item->digitalButton[i] != gamepadState.digitalButton[buttonidx]) { 559 const bool down = (gamepadState.digitalButton[buttonidx] != 0); 560 SDL_SendJoystickButton(timestamp, item->joystick, i, down); 561 } 562 563 // store values to compare them in the next update 564 item->analogButton[i] = gamepadState.analogButton[buttonidx]; 565 item->digitalButton[i] = gamepadState.digitalButton[buttonidx]; 566 } 567 568 for (i = 0; i < real_axis_count; i++) { 569 if (item->axis[i] != gamepadState.axis[i]) { 570 SDL_SendJoystickAxis(timestamp, item->joystick, i, (Sint16)(32767.0f * gamepadState.axis[i])); 571 item->axis[i] = gamepadState.axis[i]; 572 } 573 } 574 575 if (item->triggers_are_buttons) { 576 for (i = 0; i < 2; i++) { 577 if (item->axis[real_axis_count+i] != gamepadState.analogButton[first_trigger_button+i]) { 578 SDL_SendJoystickAxis(timestamp, item->joystick, real_axis_count+i, (Sint16)(32767.0f * ((gamepadState.analogButton[first_trigger_button+i] * 2.0f) - 1.0f))); 579 item->axis[real_axis_count+i] = gamepadState.analogButton[first_trigger_button+i]; 580 } 581 } 582 } 583 584 SDL_assert(item->nhats <= 1); // there is (currently) only ever one of these, faked from the d-pad buttons. 585 if (item->nhats) { 586 Uint8 value = SDL_HAT_CENTERED; 587 // this currently expects the first button to be up, then down, then left, then right. 588 if (gamepadState.digitalButton[first_hat_button + 0]) { 589 value |= SDL_HAT_UP; 590 } else if (gamepadState.digitalButton[first_hat_button + 1]) { 591 value |= SDL_HAT_DOWN; 592 } 593 if (gamepadState.digitalButton[first_hat_button + 2]) { 594 value |= SDL_HAT_LEFT; 595 } else if (gamepadState.digitalButton[first_hat_button + 3]) { 596 value |= SDL_HAT_RIGHT; 597 } 598 if (item->hat != value) { 599 item->hat = value; 600 SDL_SendJoystickHat(timestamp, item->joystick, 0, value); 601 } 602 } 603 604 605 item->timestamp = gamepadState.timestamp; 606 } 607 } 608 } 609} 610 611// Function to close a joystick after use 612static void EMSCRIPTEN_JoystickClose(SDL_Joystick *joystick) 613{ 614 SDL_joylist_item *item = (SDL_joylist_item *)joystick->hwdata; 615 if (item) { 616 item->joystick = NULL; 617 } 618} 619 620static SDL_GUID EMSCRIPTEN_JoystickGetDeviceGUID(int device_index) 621{ 622 return JoystickByDeviceIndex(device_index)->guid; 623} 624 625static bool Emscripten_UpdateRumble(SDL_joylist_item *item) 626{ 627 bool result = MAIN_THREAD_EM_ASM_INT({ 628 let gamepad = navigator['getGamepads']()[$0]; 629 if (!gamepad) { 630 return false; 631 } 632 // We check if rumble is available in EMSCRIPTEN_JoystickRumble() and EMSCRIPTEN_JoystickRumbleTriggers(). 633 // From my testing using "dual-rumble" here covers both main rumble and trigger rumble. 634 gamepad['vibrationActuator']['playEffect']('dual-rumble', { 635 'startDelay': 0, 636 'duration': 3000, 637 'weakMagnitude': $1 / 0xFFFF, 638 'strongMagnitude': $2 / 0xFFFF, 639 'leftTrigger': $3 / 0xFFFF, 640 'rightTrigger': $4 / 0xFFFF, 641 }); 642 643 return true; 644 }, item->index, item->weak_magnitude_rumble, item->strong_magnitude_rumble, item->left_trigger_rumble, item->right_trigger_rumble); 645 return result; 646} 647 648static bool EMSCRIPTEN_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 649{ 650 SDL_joylist_item *item = (SDL_joylist_item *)joystick->hwdata; 651 if (!item || !item->rumble_available) { 652 return SDL_Unsupported(); 653 } 654 item->strong_magnitude_rumble = low_frequency_rumble; 655 item->weak_magnitude_rumble = high_frequency_rumble; 656 return Emscripten_UpdateRumble(item); 657} 658 659static bool EMSCRIPTEN_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) 660{ 661 SDL_joylist_item *item = (SDL_joylist_item *)joystick->hwdata; 662 if (!item || !item->trigger_rumble_available) { 663 return SDL_Unsupported(); 664 } 665 item->left_trigger_rumble = left_rumble; 666 item->right_trigger_rumble = right_rumble; 667 return Emscripten_UpdateRumble(item); 668} 669 670static bool EMSCRIPTEN_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) 671{ 672 return false; 673} 674 675static bool EMSCRIPTEN_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) 676{ 677 return SDL_Unsupported(); 678} 679 680static bool EMSCRIPTEN_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) 681{ 682 return SDL_Unsupported(); 683} 684 685static bool EMSCRIPTEN_JoystickSetSensorsEnabled(SDL_Joystick *joystick, bool enabled) 686{ 687 return SDL_Unsupported(); 688} 689 690SDL_JoystickDriver SDL_EMSCRIPTEN_JoystickDriver = { 691 EMSCRIPTEN_JoystickInit, 692 EMSCRIPTEN_JoystickGetCount, 693 EMSCRIPTEN_JoystickDetect, 694 EMSCRIPTEN_JoystickIsDevicePresent, 695 EMSCRIPTEN_JoystickGetDeviceName, 696 EMSCRIPTEN_JoystickGetDevicePath, 697 EMSCRIPTEN_JoystickGetDeviceSteamVirtualGamepadSlot, 698 EMSCRIPTEN_JoystickGetDevicePlayerIndex, 699 EMSCRIPTEN_JoystickSetDevicePlayerIndex, 700 EMSCRIPTEN_JoystickGetDeviceGUID, 701 EMSCRIPTEN_JoystickGetDeviceInstanceID, 702 EMSCRIPTEN_JoystickOpen, 703 EMSCRIPTEN_JoystickRumble, 704 EMSCRIPTEN_JoystickRumbleTriggers, 705 EMSCRIPTEN_JoystickSetLED, 706 EMSCRIPTEN_JoystickSendEffect, 707 EMSCRIPTEN_JoystickSetSensorsEnabled, 708 EMSCRIPTEN_JoystickUpdate, 709 EMSCRIPTEN_JoystickClose, 710 EMSCRIPTEN_JoystickQuit, 711 EMSCRIPTEN_JoystickGetGamepadMapping 712}; 713 714#endif // SDL_JOYSTICK_EMSCRIPTEN 715
[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.