Atlas - SDL_virtualjoystick.c
Home / ext / SDL / src / joystick / virtual Lines: 1 | Size: 31680 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_VIRTUAL 24 25// This is the virtual implementation of the SDL joystick API 26 27#include "SDL_virtualjoystick_c.h" 28#include "../SDL_sysjoystick.h" 29#include "../SDL_joystick_c.h" 30 31static joystick_hwdata *g_VJoys SDL_GUARDED_BY(SDL_joystick_lock) = NULL; 32 33static joystick_hwdata *VIRTUAL_HWDataForInstance(SDL_JoystickID instance_id) 34{ 35 joystick_hwdata *vjoy; 36 37 SDL_AssertJoysticksLocked(); 38 39 for (vjoy = g_VJoys; vjoy; vjoy = vjoy->next) { 40 if (instance_id == vjoy->instance_id) { 41 return vjoy; 42 } 43 } 44 return NULL; 45} 46 47static joystick_hwdata *VIRTUAL_HWDataForIndex(int device_index) 48{ 49 joystick_hwdata *vjoy; 50 51 SDL_AssertJoysticksLocked(); 52 53 for (vjoy = g_VJoys; vjoy; vjoy = vjoy->next) { 54 if (device_index == 0) { 55 break; 56 } 57 --device_index; 58 } 59 return vjoy; 60} 61 62static void VIRTUAL_FreeHWData(joystick_hwdata *hwdata) 63{ 64 joystick_hwdata *cur; 65 joystick_hwdata *prev = NULL; 66 67 SDL_AssertJoysticksLocked(); 68 69 if (!hwdata) { 70 return; 71 } 72 73 if (hwdata->desc.Cleanup) { 74 hwdata->desc.Cleanup(hwdata->desc.userdata); 75 } 76 77 // Remove hwdata from SDL-global list 78 for (cur = g_VJoys; cur; prev = cur, cur = cur->next) { 79 if (hwdata == cur) { 80 if (prev) { 81 prev->next = cur->next; 82 } else { 83 g_VJoys = cur->next; 84 } 85 break; 86 } 87 } 88 89 if (hwdata->joystick) { 90 hwdata->joystick->hwdata = NULL; 91 hwdata->joystick = NULL; 92 } 93 if (hwdata->name) { 94 SDL_free(hwdata->name); 95 hwdata->name = NULL; 96 } 97 if (hwdata->axes) { 98 SDL_free((void *)hwdata->axes); 99 hwdata->axes = NULL; 100 } 101 if (hwdata->buttons) { 102 SDL_free(hwdata->buttons); 103 hwdata->buttons = NULL; 104 } 105 if (hwdata->hats) { 106 SDL_free(hwdata->hats); 107 hwdata->hats = NULL; 108 } 109 if (hwdata->balls) { 110 SDL_free(hwdata->balls); 111 hwdata->balls = NULL; 112 } 113 if (hwdata->touchpads) { 114 for (Uint16 i = 0; i < hwdata->desc.ntouchpads; ++i) { 115 SDL_free(hwdata->touchpads[i].fingers); 116 hwdata->touchpads[i].fingers = NULL; 117 } 118 SDL_free(hwdata->touchpads); 119 hwdata->touchpads = NULL; 120 } 121 if (hwdata->sensors) { 122 SDL_free(hwdata->sensors); 123 hwdata->sensors = NULL; 124 } 125 if (hwdata->sensor_events) { 126 SDL_free(hwdata->sensor_events); 127 hwdata->sensor_events = NULL; 128 } 129 SDL_free(hwdata); 130} 131 132SDL_JoystickID SDL_JoystickAttachVirtualInner(const SDL_VirtualJoystickDesc *desc) 133{ 134 joystick_hwdata *hwdata = NULL; 135 const char *name = NULL; 136 int axis_triggerleft = -1; 137 int axis_triggerright = -1; 138 139 SDL_AssertJoysticksLocked(); 140 141 CHECK_PARAM(!desc) { 142 SDL_InvalidParamError("desc"); 143 return 0; 144 } 145 CHECK_PARAM(desc->version < sizeof(*desc)) { 146 // Update this to handle older versions of this interface 147 SDL_SetError("Invalid desc, should be initialized with SDL_INIT_INTERFACE()"); 148 return 0; 149 } 150 151 hwdata = (joystick_hwdata *)SDL_calloc(1, sizeof(joystick_hwdata)); 152 if (!hwdata) { 153 VIRTUAL_FreeHWData(hwdata); 154 return 0; 155 } 156 SDL_copyp(&hwdata->desc, desc); 157 hwdata->desc.touchpads = NULL; 158 hwdata->desc.sensors = NULL; 159 160 if (hwdata->desc.name) { 161 name = hwdata->desc.name; 162 } else { 163 switch (hwdata->desc.type) { 164 case SDL_JOYSTICK_TYPE_GAMEPAD: 165 name = "Virtual Controller"; 166 break; 167 case SDL_JOYSTICK_TYPE_WHEEL: 168 name = "Virtual Wheel"; 169 break; 170 case SDL_JOYSTICK_TYPE_ARCADE_STICK: 171 name = "Virtual Arcade Stick"; 172 break; 173 case SDL_JOYSTICK_TYPE_FLIGHT_STICK: 174 name = "Virtual Flight Stick"; 175 break; 176 case SDL_JOYSTICK_TYPE_DANCE_PAD: 177 name = "Virtual Dance Pad"; 178 break; 179 case SDL_JOYSTICK_TYPE_GUITAR: 180 name = "Virtual Guitar"; 181 break; 182 case SDL_JOYSTICK_TYPE_DRUM_KIT: 183 name = "Virtual Drum Kit"; 184 break; 185 case SDL_JOYSTICK_TYPE_ARCADE_PAD: 186 name = "Virtual Arcade Pad"; 187 break; 188 case SDL_JOYSTICK_TYPE_THROTTLE: 189 name = "Virtual Throttle"; 190 break; 191 default: 192 name = "Virtual Joystick"; 193 break; 194 } 195 } 196 hwdata->name = SDL_strdup(name); 197 198 if (hwdata->desc.type == SDL_JOYSTICK_TYPE_GAMEPAD) { 199 int i, axis; 200 201 if (hwdata->desc.button_mask == 0) { 202 for (i = 0; i < hwdata->desc.nbuttons && i < sizeof(hwdata->desc.button_mask) * 8; ++i) { 203 hwdata->desc.button_mask |= (1 << i); 204 } 205 } 206 207 if (hwdata->desc.axis_mask == 0) { 208 if (hwdata->desc.naxes >= 2) { 209 hwdata->desc.axis_mask |= ((1 << SDL_GAMEPAD_AXIS_LEFTX) | (1 << SDL_GAMEPAD_AXIS_LEFTY)); 210 } 211 if (hwdata->desc.naxes >= 4) { 212 hwdata->desc.axis_mask |= ((1 << SDL_GAMEPAD_AXIS_RIGHTX) | (1 << SDL_GAMEPAD_AXIS_RIGHTY)); 213 } 214 if (hwdata->desc.naxes >= 6) { 215 hwdata->desc.axis_mask |= ((1 << SDL_GAMEPAD_AXIS_LEFT_TRIGGER) | (1 << SDL_GAMEPAD_AXIS_RIGHT_TRIGGER)); 216 } 217 } 218 219 // Find the trigger axes 220 axis = 0; 221 for (i = 0; axis < hwdata->desc.naxes && i < SDL_GAMEPAD_AXIS_COUNT; ++i) { 222 if (hwdata->desc.axis_mask & (1 << i)) { 223 if (i == SDL_GAMEPAD_AXIS_LEFT_TRIGGER) { 224 axis_triggerleft = axis; 225 } 226 if (i == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) { 227 axis_triggerright = axis; 228 } 229 ++axis; 230 } 231 } 232 } 233 234 hwdata->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_VIRTUAL, hwdata->desc.vendor_id, hwdata->desc.product_id, 0, NULL, name, 'v', (Uint8)hwdata->desc.type); 235 236 // Allocate fields for different control-types 237 if (hwdata->desc.naxes > 0) { 238 hwdata->axes = (Sint16 *)SDL_calloc(hwdata->desc.naxes, sizeof(*hwdata->axes)); 239 if (!hwdata->axes) { 240 VIRTUAL_FreeHWData(hwdata); 241 return 0; 242 } 243 244 // Trigger axes are at minimum value at rest 245 if (axis_triggerleft >= 0) { 246 hwdata->axes[axis_triggerleft] = SDL_JOYSTICK_AXIS_MIN; 247 } 248 if (axis_triggerright >= 0) { 249 hwdata->axes[axis_triggerright] = SDL_JOYSTICK_AXIS_MIN; 250 } 251 } 252 if (hwdata->desc.nbuttons > 0) { 253 hwdata->buttons = (bool *)SDL_calloc(hwdata->desc.nbuttons, sizeof(*hwdata->buttons)); 254 if (!hwdata->buttons) { 255 VIRTUAL_FreeHWData(hwdata); 256 return 0; 257 } 258 } 259 if (hwdata->desc.nhats > 0) { 260 hwdata->hats = (Uint8 *)SDL_calloc(hwdata->desc.nhats, sizeof(*hwdata->hats)); 261 if (!hwdata->hats) { 262 VIRTUAL_FreeHWData(hwdata); 263 return 0; 264 } 265 } 266 if (hwdata->desc.nballs > 0) { 267 hwdata->balls = (SDL_JoystickBallData *)SDL_calloc(hwdata->desc.nballs, sizeof(*hwdata->balls)); 268 if (!hwdata->balls) { 269 VIRTUAL_FreeHWData(hwdata); 270 return 0; 271 } 272 } 273 if (hwdata->desc.ntouchpads > 0) { 274 if (!desc->touchpads) { 275 VIRTUAL_FreeHWData(hwdata); 276 SDL_SetError("desc missing touchpad descriptions"); 277 return 0; 278 } 279 hwdata->touchpads = (SDL_JoystickTouchpadInfo *)SDL_calloc(hwdata->desc.ntouchpads, sizeof(*hwdata->touchpads)); 280 if (!hwdata->touchpads) { 281 VIRTUAL_FreeHWData(hwdata); 282 return 0; 283 } 284 for (Uint16 i = 0; i < hwdata->desc.ntouchpads; ++i) { 285 const SDL_VirtualJoystickTouchpadDesc *touchpad_desc = &desc->touchpads[i]; 286 hwdata->touchpads[i].nfingers = touchpad_desc->nfingers; 287 hwdata->touchpads[i].fingers = (SDL_JoystickTouchpadFingerInfo *)SDL_calloc(touchpad_desc->nfingers, sizeof(*hwdata->touchpads[i].fingers)); 288 if (!hwdata->touchpads[i].fingers) { 289 VIRTUAL_FreeHWData(hwdata); 290 return 0; 291 } 292 } 293 } 294 if (hwdata->desc.nsensors > 0) { 295 if (!desc->sensors) { 296 VIRTUAL_FreeHWData(hwdata); 297 SDL_SetError("desc missing sensor descriptions"); 298 return 0; 299 } 300 hwdata->sensors = (SDL_JoystickSensorInfo *)SDL_calloc(hwdata->desc.nsensors, sizeof(*hwdata->sensors)); 301 if (!hwdata->sensors) { 302 VIRTUAL_FreeHWData(hwdata); 303 return 0; 304 } 305 for (Uint16 i = 0; i < hwdata->desc.nsensors; ++i) { 306 const SDL_VirtualJoystickSensorDesc *sensor_desc = &desc->sensors[i]; 307 hwdata->sensors[i].type = sensor_desc->type; 308 hwdata->sensors[i].rate = sensor_desc->rate; 309 } 310 } 311 312 // Allocate an instance ID for this device 313 hwdata->instance_id = SDL_GetNextObjectID(); 314 315 // Add virtual joystick to SDL-global lists 316 if (g_VJoys) { 317 joystick_hwdata *last; 318 319 for (last = g_VJoys; last->next; last = last->next) { 320 } 321 last->next = hwdata; 322 } else { 323 g_VJoys = hwdata; 324 } 325 SDL_PrivateJoystickAdded(hwdata->instance_id); 326 327 return hwdata->instance_id; 328} 329 330bool SDL_JoystickDetachVirtualInner(SDL_JoystickID instance_id) 331{ 332 joystick_hwdata *hwdata = VIRTUAL_HWDataForInstance(instance_id); 333 if (!hwdata) { 334 return SDL_SetError("Virtual joystick data not found"); 335 } 336 VIRTUAL_FreeHWData(hwdata); 337 SDL_PrivateJoystickRemoved(instance_id); 338 return true; 339} 340 341bool SDL_SetJoystickVirtualAxisInner(SDL_Joystick *joystick, int axis, Sint16 value) 342{ 343 joystick_hwdata *hwdata; 344 345 SDL_AssertJoysticksLocked(); 346 347 if (!joystick || !joystick->hwdata) { 348 return SDL_SetError("Invalid joystick"); 349 } 350 351 hwdata = (joystick_hwdata *)joystick->hwdata; 352 if (axis < 0 || axis >= hwdata->desc.naxes) { 353 return SDL_SetError("Invalid axis index"); 354 } 355 356 hwdata->axes[axis] = value; 357 hwdata->changes |= AXES_CHANGED; 358 359 return true; 360} 361 362bool SDL_SetJoystickVirtualBallInner(SDL_Joystick *joystick, int ball, Sint16 xrel, Sint16 yrel) 363{ 364 joystick_hwdata *hwdata; 365 366 SDL_AssertJoysticksLocked(); 367 368 if (!joystick || !joystick->hwdata) { 369 return SDL_SetError("Invalid joystick"); 370 } 371 372 hwdata = (joystick_hwdata *)joystick->hwdata; 373 if (ball < 0 || ball >= hwdata->desc.nballs) { 374 return SDL_SetError("Invalid ball index"); 375 } 376 377 hwdata->balls[ball].dx += xrel; 378 hwdata->balls[ball].dx = SDL_clamp(hwdata->balls[ball].dx, SDL_MIN_SINT16, SDL_MAX_SINT16); 379 hwdata->balls[ball].dy += yrel; 380 hwdata->balls[ball].dy = SDL_clamp(hwdata->balls[ball].dy, SDL_MIN_SINT16, SDL_MAX_SINT16); 381 hwdata->changes |= BALLS_CHANGED; 382 383 return true; 384} 385 386bool SDL_SetJoystickVirtualButtonInner(SDL_Joystick *joystick, int button, bool down) 387{ 388 joystick_hwdata *hwdata; 389 390 SDL_AssertJoysticksLocked(); 391 392 if (!joystick || !joystick->hwdata) { 393 return SDL_SetError("Invalid joystick"); 394 } 395 396 hwdata = (joystick_hwdata *)joystick->hwdata; 397 if (button < 0 || button >= hwdata->desc.nbuttons) { 398 return SDL_SetError("Invalid button index"); 399 } 400 401 hwdata->buttons[button] = down; 402 hwdata->changes |= BUTTONS_CHANGED; 403 404 return true; 405} 406 407bool SDL_SetJoystickVirtualHatInner(SDL_Joystick *joystick, int hat, Uint8 value) 408{ 409 joystick_hwdata *hwdata; 410 411 SDL_AssertJoysticksLocked(); 412 413 if (!joystick || !joystick->hwdata) { 414 return SDL_SetError("Invalid joystick"); 415 } 416 417 hwdata = (joystick_hwdata *)joystick->hwdata; 418 if (hat < 0 || hat >= hwdata->desc.nhats) { 419 return SDL_SetError("Invalid hat index"); 420 } 421 422 hwdata->hats[hat] = value; 423 hwdata->changes |= HATS_CHANGED; 424 425 return true; 426} 427 428bool SDL_SetJoystickVirtualTouchpadInner(SDL_Joystick *joystick, int touchpad, int finger, bool down, float x, float y, float pressure) 429{ 430 joystick_hwdata *hwdata; 431 432 SDL_AssertJoysticksLocked(); 433 434 if (!joystick || !joystick->hwdata) { 435 return SDL_SetError("Invalid joystick"); 436 } 437 438 hwdata = (joystick_hwdata *)joystick->hwdata; 439 if (touchpad < 0 || touchpad >= hwdata->desc.ntouchpads) { 440 return SDL_SetError("Invalid touchpad index"); 441 } 442 if (finger < 0 || finger >= hwdata->touchpads[touchpad].nfingers) { 443 return SDL_SetError("Invalid finger index"); 444 } 445 446 SDL_JoystickTouchpadFingerInfo *info = &hwdata->touchpads[touchpad].fingers[finger]; 447 info->down = down; 448 info->x = x; 449 info->y = y; 450 info->pressure = pressure; 451 hwdata->changes |= TOUCHPADS_CHANGED; 452 453 return true; 454} 455 456bool SDL_SendJoystickVirtualSensorDataInner(SDL_Joystick *joystick, SDL_SensorType type, Uint64 sensor_timestamp, const float *data, int num_values) 457{ 458 joystick_hwdata *hwdata; 459 460 SDL_AssertJoysticksLocked(); 461 462 if (!joystick || !joystick->hwdata) { 463 return SDL_SetError("Invalid joystick"); 464 } 465 466 hwdata = (joystick_hwdata *)joystick->hwdata; 467 if (hwdata->num_sensor_events == hwdata->max_sensor_events) { 468 int new_max_sensor_events = (hwdata->max_sensor_events + 1); 469 VirtualSensorEvent *sensor_events = (VirtualSensorEvent *)SDL_realloc(hwdata->sensor_events, new_max_sensor_events * sizeof(*sensor_events)); 470 if (!sensor_events) { 471 return false; 472 } 473 hwdata->sensor_events = sensor_events; 474 hwdata->max_sensor_events = new_max_sensor_events; 475 } 476 477 VirtualSensorEvent *event = &hwdata->sensor_events[hwdata->num_sensor_events++]; 478 event->type = type; 479 event->sensor_timestamp = sensor_timestamp; 480 event->num_values = SDL_min(num_values, SDL_arraysize(event->data)); 481 SDL_memcpy(event->data, data, (event->num_values * sizeof(*event->data))); 482 483 return true; 484} 485 486static bool VIRTUAL_JoystickInit(void) 487{ 488 return true; 489} 490 491static int VIRTUAL_JoystickGetCount(void) 492{ 493 joystick_hwdata *cur; 494 int count = 0; 495 496 SDL_AssertJoysticksLocked(); 497 498 for (cur = g_VJoys; cur; cur = cur->next) { 499 ++count; 500 } 501 return count; 502} 503 504static void VIRTUAL_JoystickDetect(void) 505{ 506} 507 508static bool VIRTUAL_JoystickIsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name) 509{ 510 // We don't override any other drivers... or do we? 511 return false; 512} 513 514static const char *VIRTUAL_JoystickGetDeviceName(int device_index) 515{ 516 joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index); 517 if (!hwdata) { 518 return NULL; 519 } 520 return hwdata->name; 521} 522 523static const char *VIRTUAL_JoystickGetDevicePath(int device_index) 524{ 525 return NULL; 526} 527 528static int VIRTUAL_JoystickGetDeviceSteamVirtualGamepadSlot(int device_index) 529{ 530 return -1; 531} 532 533static int VIRTUAL_JoystickGetDevicePlayerIndex(int device_index) 534{ 535 return -1; 536} 537 538static void VIRTUAL_JoystickSetDevicePlayerIndex(int device_index, int player_index) 539{ 540 joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index); 541 542 if (hwdata && hwdata->desc.SetPlayerIndex) { 543 hwdata->desc.SetPlayerIndex(hwdata->desc.userdata, player_index); 544 } 545} 546 547static SDL_GUID VIRTUAL_JoystickGetDeviceGUID(int device_index) 548{ 549 joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index); 550 if (!hwdata) { 551 SDL_GUID guid; 552 SDL_zero(guid); 553 return guid; 554 } 555 return hwdata->guid; 556} 557 558static SDL_JoystickID VIRTUAL_JoystickGetDeviceInstanceID(int device_index) 559{ 560 joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index); 561 if (!hwdata) { 562 return true; 563 } 564 return hwdata->instance_id; 565} 566 567static bool VIRTUAL_JoystickOpen(SDL_Joystick *joystick, int device_index) 568{ 569 joystick_hwdata *hwdata; 570 571 SDL_AssertJoysticksLocked(); 572 573 hwdata = VIRTUAL_HWDataForIndex(device_index); 574 if (!hwdata) { 575 return SDL_SetError("No such device"); 576 } 577 joystick->hwdata = hwdata; 578 joystick->naxes = hwdata->desc.naxes; 579 joystick->nbuttons = hwdata->desc.nbuttons; 580 joystick->nhats = hwdata->desc.nhats; 581 hwdata->joystick = joystick; 582 583 for (Uint16 i = 0; i < hwdata->desc.ntouchpads; ++i) { 584 const SDL_JoystickTouchpadInfo *touchpad = &hwdata->touchpads[i]; 585 SDL_PrivateJoystickAddTouchpad(joystick, touchpad->nfingers); 586 } 587 for (Uint16 i = 0; i < hwdata->desc.nsensors; ++i) { 588 const SDL_JoystickSensorInfo *sensor = &hwdata->sensors[i]; 589 SDL_PrivateJoystickAddSensor(joystick, sensor->type, sensor->rate); 590 } 591 592 if (hwdata->desc.SetLED) { 593 SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RGB_LED_BOOLEAN, true); 594 } 595 if (hwdata->desc.Rumble) { 596 SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true); 597 } 598 if (hwdata->desc.RumbleTriggers) { 599 SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_TRIGGER_RUMBLE_BOOLEAN, true); 600 } 601 return true; 602} 603 604static bool VIRTUAL_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 605{ 606 bool result; 607 608 SDL_AssertJoysticksLocked(); 609 610 if (joystick->hwdata) { 611 joystick_hwdata *hwdata = joystick->hwdata; 612 if (hwdata->desc.Rumble) { 613 result = hwdata->desc.Rumble(hwdata->desc.userdata, low_frequency_rumble, high_frequency_rumble); 614 } else { 615 result = SDL_Unsupported(); 616 } 617 } else { 618 result = SDL_SetError("Rumble failed, device disconnected"); 619 } 620 621 return result; 622} 623 624static bool VIRTUAL_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) 625{ 626 bool result; 627 628 SDL_AssertJoysticksLocked(); 629 630 if (joystick->hwdata) { 631 joystick_hwdata *hwdata = joystick->hwdata; 632 if (hwdata->desc.RumbleTriggers) { 633 result = hwdata->desc.RumbleTriggers(hwdata->desc.userdata, left_rumble, right_rumble); 634 } else { 635 result = SDL_Unsupported(); 636 } 637 } else { 638 result = SDL_SetError("Rumble failed, device disconnected"); 639 } 640 641 return result; 642} 643 644static bool VIRTUAL_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) 645{ 646 bool result; 647 648 SDL_AssertJoysticksLocked(); 649 650 if (joystick->hwdata) { 651 joystick_hwdata *hwdata = joystick->hwdata; 652 if (hwdata->desc.SetLED) { 653 result = hwdata->desc.SetLED(hwdata->desc.userdata, red, green, blue); 654 } else { 655 result = SDL_Unsupported(); 656 } 657 } else { 658 result = SDL_SetError("SetLED failed, device disconnected"); 659 } 660 661 return result; 662} 663 664static bool VIRTUAL_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) 665{ 666 bool result; 667 668 SDL_AssertJoysticksLocked(); 669 670 if (joystick->hwdata) { 671 joystick_hwdata *hwdata = joystick->hwdata; 672 if (hwdata->desc.SendEffect) { 673 result = hwdata->desc.SendEffect(hwdata->desc.userdata, data, size); 674 } else { 675 result = SDL_Unsupported(); 676 } 677 } else { 678 result = SDL_SetError("SendEffect failed, device disconnected"); 679 } 680 681 return result; 682} 683 684static bool VIRTUAL_JoystickSetSensorsEnabled(SDL_Joystick *joystick, bool enabled) 685{ 686 bool result; 687 688 SDL_AssertJoysticksLocked(); 689 690 if (joystick->hwdata) { 691 joystick_hwdata *hwdata = joystick->hwdata; 692 if (hwdata->desc.SetSensorsEnabled) { 693 result = hwdata->desc.SetSensorsEnabled(hwdata->desc.userdata, enabled); 694 } else { 695 result = true; 696 } 697 if (result) { 698 hwdata->sensors_enabled = enabled; 699 } 700 } else { 701 result = SDL_SetError("SetSensorsEnabled failed, device disconnected"); 702 } 703 704 return result; 705} 706 707static void VIRTUAL_JoystickUpdate(SDL_Joystick *joystick) 708{ 709 joystick_hwdata *hwdata; 710 Uint64 timestamp = SDL_GetTicksNS(); 711 712 SDL_AssertJoysticksLocked(); 713 714 if (!joystick) { 715 return; 716 } 717 if (!joystick->hwdata) { 718 return; 719 } 720 721 hwdata = (joystick_hwdata *)joystick->hwdata; 722 723 if (hwdata->desc.Update) { 724 hwdata->desc.Update(hwdata->desc.userdata); 725 } 726 727 if (hwdata->changes & AXES_CHANGED) { 728 for (Uint8 i = 0; i < hwdata->desc.naxes; ++i) { 729 SDL_SendJoystickAxis(timestamp, joystick, i, hwdata->axes[i]); 730 } 731 } 732 if (hwdata->changes & BALLS_CHANGED) { 733 for (Uint8 i = 0; i < hwdata->desc.nballs; ++i) { 734 SDL_JoystickBallData *ball = &hwdata->balls[i]; 735 if (ball->dx || ball->dy) { 736 SDL_SendJoystickBall(timestamp, joystick, i, (Sint16)ball->dx, (Sint16)ball->dy); 737 ball->dx = 0; 738 ball->dy = 0; 739 } 740 } 741 } 742 if (hwdata->changes & BUTTONS_CHANGED) { 743 for (Uint8 i = 0; i < hwdata->desc.nbuttons; ++i) { 744 SDL_SendJoystickButton(timestamp, joystick, i, hwdata->buttons[i]); 745 } 746 } 747 if (hwdata->changes & HATS_CHANGED) { 748 for (Uint8 i = 0; i < hwdata->desc.nhats; ++i) { 749 SDL_SendJoystickHat(timestamp, joystick, i, hwdata->hats[i]); 750 } 751 } 752 if (hwdata->changes & TOUCHPADS_CHANGED) { 753 for (Uint16 i = 0; i < hwdata->desc.ntouchpads; ++i) { 754 const SDL_JoystickTouchpadInfo *touchpad = &hwdata->touchpads[i]; 755 for (int j = 0; j < touchpad->nfingers; ++j) { 756 const SDL_JoystickTouchpadFingerInfo *finger = &touchpad->fingers[j]; 757 SDL_SendJoystickTouchpad(timestamp, joystick, i, j, finger->down, finger->x, finger->y, finger->pressure); 758 } 759 } 760 } 761 if (hwdata->num_sensor_events > 0) { 762 if (hwdata->sensors_enabled) { 763 for (int i = 0; i < hwdata->num_sensor_events; ++i) { 764 const VirtualSensorEvent *event = &hwdata->sensor_events[i]; 765 SDL_SendJoystickSensor(timestamp, joystick, event->type, event->sensor_timestamp, event->data, event->num_values); 766 } 767 } 768 hwdata->num_sensor_events = 0; 769 } 770 hwdata->changes = 0; 771} 772 773static void VIRTUAL_JoystickClose(SDL_Joystick *joystick) 774{ 775 SDL_AssertJoysticksLocked(); 776 777 if (joystick->hwdata) { 778 joystick_hwdata *hwdata = joystick->hwdata; 779 hwdata->joystick = NULL; 780 joystick->hwdata = NULL; 781 } 782} 783 784static void VIRTUAL_JoystickQuit(void) 785{ 786 SDL_AssertJoysticksLocked(); 787 788 while (g_VJoys) { 789 VIRTUAL_FreeHWData(g_VJoys); 790 } 791} 792 793static bool VIRTUAL_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) 794{ 795 joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index); 796 Uint8 current_button = 0; 797 Uint8 current_axis = 0; 798 799 if (!hwdata || hwdata->desc.type != SDL_JOYSTICK_TYPE_GAMEPAD) { 800 return false; 801 } 802 803 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_SOUTH))) { 804 out->a.kind = EMappingKind_Button; 805 out->a.target = current_button++; 806 } 807 808 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_EAST))) { 809 out->b.kind = EMappingKind_Button; 810 out->b.target = current_button++; 811 } 812 813 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_WEST))) { 814 out->x.kind = EMappingKind_Button; 815 out->x.target = current_button++; 816 } 817 818 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_NORTH))) { 819 out->y.kind = EMappingKind_Button; 820 out->y.target = current_button++; 821 } 822 823 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_BACK))) { 824 out->back.kind = EMappingKind_Button; 825 out->back.target = current_button++; 826 } 827 828 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_GUIDE))) { 829 out->guide.kind = EMappingKind_Button; 830 out->guide.target = current_button++; 831 } 832 833 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_START))) { 834 out->start.kind = EMappingKind_Button; 835 out->start.target = current_button++; 836 } 837 838 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_LEFT_STICK))) { 839 out->leftstick.kind = EMappingKind_Button; 840 out->leftstick.target = current_button++; 841 } 842 843 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_RIGHT_STICK))) { 844 out->rightstick.kind = EMappingKind_Button; 845 out->rightstick.target = current_button++; 846 } 847 848 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_LEFT_SHOULDER))) { 849 out->leftshoulder.kind = EMappingKind_Button; 850 out->leftshoulder.target = current_button++; 851 } 852 853 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER))) { 854 out->rightshoulder.kind = EMappingKind_Button; 855 out->rightshoulder.target = current_button++; 856 } 857 858 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_DPAD_UP))) { 859 out->dpup.kind = EMappingKind_Button; 860 out->dpup.target = current_button++; 861 } 862 863 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_DPAD_DOWN))) { 864 out->dpdown.kind = EMappingKind_Button; 865 out->dpdown.target = current_button++; 866 } 867 868 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_DPAD_LEFT))) { 869 out->dpleft.kind = EMappingKind_Button; 870 out->dpleft.target = current_button++; 871 } 872 873 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_DPAD_RIGHT))) { 874 out->dpright.kind = EMappingKind_Button; 875 out->dpright.target = current_button++; 876 } 877 878 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_MISC1))) { 879 out->misc1.kind = EMappingKind_Button; 880 out->misc1.target = current_button++; 881 } 882 883 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1))) { 884 out->right_paddle1.kind = EMappingKind_Button; 885 out->right_paddle1.target = current_button++; 886 } 887 888 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_LEFT_PADDLE1))) { 889 out->left_paddle1.kind = EMappingKind_Button; 890 out->left_paddle1.target = current_button++; 891 } 892 893 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2))) { 894 out->right_paddle2.kind = EMappingKind_Button; 895 out->right_paddle2.target = current_button++; 896 } 897 898 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_LEFT_PADDLE2))) { 899 out->left_paddle2.kind = EMappingKind_Button; 900 out->left_paddle2.target = current_button++; 901 } 902 903 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_TOUCHPAD))) { 904 out->touchpad.kind = EMappingKind_Button; 905 out->touchpad.target = current_button++; 906 } 907 908 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_MISC2))) { 909 out->misc2.kind = EMappingKind_Button; 910 out->misc2.target = current_button++; 911 } 912 913 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_MISC3))) { 914 out->misc3.kind = EMappingKind_Button; 915 out->misc3.target = current_button++; 916 } 917 918 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_MISC4))) { 919 out->misc4.kind = EMappingKind_Button; 920 out->misc4.target = current_button++; 921 } 922 923 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_MISC5))) { 924 out->misc5.kind = EMappingKind_Button; 925 out->misc5.target = current_button++; 926 } 927 928 if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_MISC6))) { 929 out->misc6.kind = EMappingKind_Button; 930 out->misc6.target = current_button++; 931 } 932 933 if (current_axis < hwdata->desc.naxes && (hwdata->desc.axis_mask & (1 << SDL_GAMEPAD_AXIS_LEFTX))) { 934 out->leftx.kind = EMappingKind_Axis; 935 out->leftx.target = current_axis++; 936 } 937 938 if (current_axis < hwdata->desc.naxes && (hwdata->desc.axis_mask & (1 << SDL_GAMEPAD_AXIS_LEFTY))) { 939 out->lefty.kind = EMappingKind_Axis; 940 out->lefty.target = current_axis++; 941 } 942 943 if (current_axis < hwdata->desc.naxes && (hwdata->desc.axis_mask & (1 << SDL_GAMEPAD_AXIS_RIGHTX))) { 944 out->rightx.kind = EMappingKind_Axis; 945 out->rightx.target = current_axis++; 946 } 947 948 if (current_axis < hwdata->desc.naxes && (hwdata->desc.axis_mask & (1 << SDL_GAMEPAD_AXIS_RIGHTY))) { 949 out->righty.kind = EMappingKind_Axis; 950 out->righty.target = current_axis++; 951 } 952 953 if (current_axis < hwdata->desc.naxes && (hwdata->desc.axis_mask & (1 << SDL_GAMEPAD_AXIS_LEFT_TRIGGER))) { 954 out->lefttrigger.kind = EMappingKind_Axis; 955 out->lefttrigger.target = current_axis++; 956 } 957 958 if (current_axis < hwdata->desc.naxes && (hwdata->desc.axis_mask & (1 << SDL_GAMEPAD_AXIS_RIGHT_TRIGGER))) { 959 out->righttrigger.kind = EMappingKind_Axis; 960 out->righttrigger.target = current_axis++; 961 } 962 963 return true; 964} 965 966SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver = { 967 VIRTUAL_JoystickInit, 968 VIRTUAL_JoystickGetCount, 969 VIRTUAL_JoystickDetect, 970 VIRTUAL_JoystickIsDevicePresent, 971 VIRTUAL_JoystickGetDeviceName, 972 VIRTUAL_JoystickGetDevicePath, 973 VIRTUAL_JoystickGetDeviceSteamVirtualGamepadSlot, 974 VIRTUAL_JoystickGetDevicePlayerIndex, 975 VIRTUAL_JoystickSetDevicePlayerIndex, 976 VIRTUAL_JoystickGetDeviceGUID, 977 VIRTUAL_JoystickGetDeviceInstanceID, 978 VIRTUAL_JoystickOpen, 979 VIRTUAL_JoystickRumble, 980 VIRTUAL_JoystickRumbleTriggers, 981 VIRTUAL_JoystickSetLED, 982 VIRTUAL_JoystickSendEffect, 983 VIRTUAL_JoystickSetSensorsEnabled, 984 VIRTUAL_JoystickUpdate, 985 VIRTUAL_JoystickClose, 986 VIRTUAL_JoystickQuit, 987 VIRTUAL_JoystickGetGamepadMapping 988}; 989 990#endif // SDL_JOYSTICK_VIRTUAL 991[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.