Atlas - SDL_touch.c
Home / ext / SDL / src / events Lines: 2 | Size: 19686 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// General touch handling code for SDL 24 25#include "SDL_events_c.h" 26#include "../video/SDL_sysvideo.h" 27 28static SDL_Mutex *SDL_touch_lock = NULL; // This needs to support recursive locks 29static int SDL_touch_locked = 0; 30 31struct SDL_Touch 32{ 33 SDL_TouchID id SDL_GUARDED_BY(SDL_touch_lock); 34 SDL_TouchDeviceType type SDL_GUARDED_BY(SDL_touch_lock); 35 int num_fingers SDL_GUARDED_BY(SDL_touch_lock); 36 int max_fingers SDL_GUARDED_BY(SDL_touch_lock); 37 SDL_Finger **fingers SDL_GUARDED_BY(SDL_touch_lock); 38 char *name SDL_GUARDED_BY(SDL_touch_lock); 39}; 40 41static int SDL_num_touch SDL_GUARDED_BY(SDL_touch_lock) = 0; 42static SDL_Touch **SDL_touchDevices SDL_GUARDED_BY(SDL_touch_lock) = NULL; 43 44// for mapping touch events to mice 45static bool finger_touching = false; 46static SDL_FingerID track_fingerid; 47static SDL_TouchID track_touchid; 48 49// Public functions 50bool SDL_InitTouch(void) 51{ 52 SDL_touch_lock = SDL_CreateMutex(); 53 return true; 54} 55 56static void SDL_LockTouch(void) SDL_ACQUIRE(SDL_touch_lock) 57{ 58 SDL_LockMutex(SDL_touch_lock); 59 ++SDL_touch_locked; 60} 61 62static void SDL_UnlockTouch(void) SDL_RELEASE(SDL_touch_lock) 63{ 64 --SDL_touch_locked; 65 SDL_UnlockMutex(SDL_touch_lock); 66} 67 68static void SDL_AssertTouchLocked(void) SDL_ASSERT_CAPABILITY(SDL_touch_lock) 69{ 70 SDL_assert(SDL_touch_locked > 0); 71} 72 73bool SDL_TouchDevicesAvailable(void) 74{ 75 bool available; 76 77 SDL_LockTouch(); 78 { 79 available = (SDL_num_touch > 0); 80 } 81 SDL_UnlockTouch(); 82 83 return available; 84} 85 86SDL_TouchID *SDL_GetTouchDevices(int *count) 87{ 88 SDL_TouchID *result; 89 90 if (count) { 91 *count = 0; 92 } 93 94 SDL_LockTouch(); 95 { 96 const int total = SDL_num_touch; 97 result = (SDL_TouchID *)SDL_malloc(sizeof (SDL_TouchID) * (total + 1)); 98 if (result) { 99 for (int i = 0; i < total; i++) { 100 result[i] = SDL_touchDevices[i]->id; 101 } 102 result[total] = 0; 103 if (count) { 104 *count = SDL_num_touch; 105 } 106 } 107 } 108 SDL_UnlockTouch(); 109 110 return result; 111} 112 113static int SDL_GetTouchIndex(SDL_TouchID id) 114{ 115 int index; 116 SDL_Touch *touch; 117 118 SDL_AssertTouchLocked(); 119 120 for (index = 0; index < SDL_num_touch; ++index) { 121 touch = SDL_touchDevices[index]; 122 if (touch->id == id) { 123 return index; 124 } 125 } 126 return -1; 127} 128 129SDL_Touch *SDL_GetTouch(SDL_TouchID id) 130{ 131 SDL_AssertTouchLocked(); 132 133 int index = SDL_GetTouchIndex(id); 134 if (index < 0 || index >= SDL_num_touch) { 135 if ((id == SDL_MOUSE_TOUCHID) || (id == SDL_PEN_TOUCHID)) { 136 // this is a virtual touch device, but for some reason they aren't added to the system. Just ignore it. 137 } else if ( SDL_GetVideoDevice()->ResetTouch) { 138 SDL_SetError("Unknown touch id %d, resetting", (int)id); 139 SDL_GetVideoDevice()->ResetTouch(SDL_GetVideoDevice()); 140 } else { 141 SDL_SetError("Unknown touch device id %d, cannot reset", (int)id); 142 } 143 return NULL; 144 } 145 return SDL_touchDevices[index]; 146} 147 148const char *SDL_GetTouchDeviceName(SDL_TouchID id) 149{ 150 const char *name = NULL; 151 152 SDL_LockTouch(); 153 { 154 SDL_Touch *touch = SDL_GetTouch(id); 155 if (touch) { 156 name = SDL_GetPersistentString(touch->name); 157 } 158 } 159 SDL_UnlockTouch(); 160 161 return name; 162} 163 164SDL_TouchDeviceType SDL_GetTouchDeviceType(SDL_TouchID id) 165{ 166 SDL_TouchDeviceType type = SDL_TOUCH_DEVICE_INVALID; 167 168 SDL_LockTouch(); 169 { 170 SDL_Touch *touch = SDL_GetTouch(id); 171 if (touch) { 172 type = touch->type; 173 } 174 } 175 SDL_UnlockTouch(); 176 177 return type; 178} 179 180static int SDL_GetFingerIndex(const SDL_Touch *touch, SDL_FingerID fingerid) 181{ 182 SDL_AssertTouchLocked(); 183 184 int index; 185 for (index = 0; index < touch->num_fingers; ++index) { 186 if (touch->fingers[index]->id == fingerid) { 187 return index; 188 } 189 } 190 return -1; 191} 192 193static SDL_Finger *SDL_GetFinger(const SDL_Touch *touch, SDL_FingerID id) 194{ 195 SDL_AssertTouchLocked(); 196 197 int index = SDL_GetFingerIndex(touch, id); 198 if (index < 0 || index >= touch->num_fingers) { 199 return NULL; 200 } 201 return touch->fingers[index]; 202} 203 204SDL_Finger **SDL_GetTouchFingers(SDL_TouchID touchID, int *count) 205{ 206 SDL_Finger **fingers; 207 SDL_Finger *finger_data; 208 209 if (count) { 210 *count = 0; 211 } 212 213 SDL_LockTouch(); 214 { 215 SDL_Touch *touch = SDL_GetTouch(touchID); 216 if (!touch) { 217 SDL_UnlockTouch(); 218 return NULL; 219 } 220 221 // Create a snapshot of the current finger state 222 fingers = (SDL_Finger **)SDL_malloc((touch->num_fingers + 1) * sizeof(*fingers) + touch->num_fingers * sizeof(**fingers)); 223 if (!fingers) { 224 SDL_UnlockTouch(); 225 return NULL; 226 } 227 finger_data = (SDL_Finger *)(fingers + (touch->num_fingers + 1)); 228 229 for (int i = 0; i < touch->num_fingers; ++i) { 230 fingers[i] = &finger_data[i]; 231 SDL_copyp(fingers[i], touch->fingers[i]); 232 } 233 fingers[touch->num_fingers] = NULL; 234 235 if (count) { 236 *count = touch->num_fingers; 237 } 238 } 239 SDL_UnlockTouch(); 240 241 return fingers; 242} 243 244int SDL_AddTouch(SDL_TouchID touchID, SDL_TouchDeviceType type, const char *name) 245{ 246 SDL_Touch **touchDevices; 247 int index; 248 249 SDL_assert(touchID != 0); 250 251 SDL_LockTouch(); 252 { 253 index = SDL_GetTouchIndex(touchID); 254 if (index >= 0) { 255 SDL_UnlockTouch(); 256 return index; 257 } 258 259 // Add the touch to the list of touch 260 touchDevices = (SDL_Touch **)SDL_realloc(SDL_touchDevices, 261 (SDL_num_touch + 1) * sizeof(*touchDevices)); 262 if (!touchDevices) { 263 SDL_UnlockTouch(); 264 return -1; 265 } 266 267 SDL_touchDevices = touchDevices; 268 index = SDL_num_touch; 269 270 SDL_touchDevices[index] = (SDL_Touch *)SDL_malloc(sizeof(*SDL_touchDevices[index])); 271 if (!SDL_touchDevices[index]) { 272 SDL_UnlockTouch(); 273 return -1; 274 } 275 276 // Added touch to list 277 ++SDL_num_touch; 278 279 // we're setting the touch properties 280 SDL_touchDevices[index]->id = touchID; 281 SDL_touchDevices[index]->type = type; 282 SDL_touchDevices[index]->num_fingers = 0; 283 SDL_touchDevices[index]->max_fingers = 0; 284 SDL_touchDevices[index]->fingers = NULL; 285 SDL_touchDevices[index]->name = SDL_strdup(name ? name : ""); 286 } 287 SDL_UnlockTouch(); 288 289 return index; 290} 291 292static bool SDL_AddFinger(SDL_Touch *touch, SDL_FingerID fingerid, float x, float y, float pressure) 293{ 294 SDL_Finger *finger; 295 296 SDL_assert(fingerid != 0); 297 298 SDL_AssertTouchLocked(); 299 300 if (touch->num_fingers == touch->max_fingers) { 301 SDL_Finger **new_fingers; 302 new_fingers = (SDL_Finger **)SDL_realloc(touch->fingers, (touch->max_fingers + 1) * sizeof(*touch->fingers)); 303 if (!new_fingers) { 304 return false; 305 } 306 touch->fingers = new_fingers; 307 touch->fingers[touch->max_fingers] = (SDL_Finger *)SDL_malloc(sizeof(*finger)); 308 if (!touch->fingers[touch->max_fingers]) { 309 return false; 310 } 311 touch->max_fingers++; 312 } 313 314 finger = touch->fingers[touch->num_fingers++]; 315 finger->id = fingerid; 316 finger->x = x; 317 finger->y = y; 318 finger->pressure = pressure; 319 return true; 320} 321 322static void SDL_DelFinger(SDL_Touch *touch, SDL_FingerID fingerid) 323{ 324 SDL_AssertTouchLocked(); 325 326 int index = SDL_GetFingerIndex(touch, fingerid); 327 if (index < 0) { 328 return; 329 } 330 331 --touch->num_fingers; 332 if (index < (touch->num_fingers)) { 333 // Move the deleted finger to just past the end of the active fingers array and shift the active fingers by one. 334 // This ensures that the descriptor for the now-deleted finger is located at `touch->fingers[touch->num_fingers]` 335 // and is ready for use in SDL_AddFinger. 336 SDL_Finger *deleted_finger = touch->fingers[index]; 337 SDL_memmove(&touch->fingers[index], &touch->fingers[index + 1], (touch->num_fingers - index) * sizeof(touch->fingers[index])); 338 touch->fingers[touch->num_fingers] = deleted_finger; 339 } 340} 341 342void SDL_SendTouch(Uint64 timestamp, SDL_TouchID id, SDL_FingerID fingerid, SDL_Window *window, SDL_EventType type, float x, float y, float pressure) 343{ 344 SDL_Finger *finger; 345 bool down = (type == SDL_EVENT_FINGER_DOWN); 346 347 SDL_LockTouch(); 348 { 349 SDL_Touch *touch = SDL_GetTouch(id); 350 if (!touch) { 351 SDL_UnlockTouch(); 352 return; 353 } 354 355 SDL_Mouse *mouse = SDL_GetMouse(); 356 357 // SDL_HINT_TOUCH_MOUSE_EVENTS: controlling whether touch events should generate synthetic mouse events 358 // SDL_HINT_VITA_TOUCH_MOUSE_DEVICE: controlling which touchpad should generate synthetic mouse events, PSVita-only 359 { 360 // FIXME: maybe we should only restrict to a few SDL_TouchDeviceType 361 if ((id != SDL_MOUSE_TOUCHID) && (id != SDL_PEN_TOUCHID)) { 362 #ifdef SDL_PLATFORM_VITA 363 if (mouse->touch_mouse_events && ((mouse->vita_touch_mouse_device == id) || (mouse->vita_touch_mouse_device == 3))) { 364 #else 365 if (mouse->touch_mouse_events) { 366 #endif 367 if (window) { 368 if (down) { 369 if (finger_touching == false) { 370 float pos_x = (x * (float)window->w); 371 float pos_y = (y * (float)window->h); 372 if (pos_x < 0) { 373 pos_x = 0; 374 } 375 if (pos_x > (float)(window->w - 1)) { 376 pos_x = (float)(window->w - 1); 377 } 378 if (pos_y < 0.0f) { 379 pos_y = 0.0f; 380 } 381 if (pos_y > (float)(window->h - 1)) { 382 pos_y = (float)(window->h - 1); 383 } 384 SDL_SendMouseMotion(timestamp, window, SDL_TOUCH_MOUSEID, false, pos_x, pos_y); 385 SDL_SendMouseButton(timestamp, window, SDL_TOUCH_MOUSEID, SDL_BUTTON_LEFT, true); 386 } 387 } else { 388 if (finger_touching == true && track_touchid == id && track_fingerid == fingerid) { 389 SDL_SendMouseButton(timestamp, window, SDL_TOUCH_MOUSEID, SDL_BUTTON_LEFT, false); 390 } 391 } 392 } 393 if (down) { 394 if (finger_touching == false) { 395 finger_touching = true; 396 track_touchid = id; 397 track_fingerid = fingerid; 398 } 399 } else { 400 if (finger_touching == true && track_touchid == id && track_fingerid == fingerid) { 401 finger_touching = false; 402 } 403 } 404 } 405 } 406 } 407 408 // SDL_HINT_MOUSE_TOUCH_EVENTS: if not set, discard synthetic touch events coming from platform layer 409 if (!mouse->mouse_touch_events && (id == SDL_MOUSE_TOUCHID)) { 410 SDL_UnlockTouch(); 411 return; 412 } else if (!mouse->pen_touch_events && (id == SDL_PEN_TOUCHID)) { 413 SDL_UnlockTouch(); 414 return; 415 } 416 417 finger = SDL_GetFinger(touch, fingerid); 418 if (down) { 419 if (finger) { 420 /* This finger is already down. 421 Assume the finger-up for the previous touch was lost, and send it. */ 422 SDL_SendTouch(timestamp, id, fingerid, window, SDL_EVENT_FINGER_CANCELED, x, y, pressure); 423 } 424 425 if (!SDL_AddFinger(touch, fingerid, x, y, pressure)) { 426 SDL_UnlockTouch(); 427 return; 428 } 429 430 if (SDL_EventEnabled(type)) { 431 SDL_Event event; 432 event.type = type; 433 event.common.timestamp = timestamp; 434 event.tfinger.touchID = id; 435 event.tfinger.fingerID = fingerid; 436 event.tfinger.x = x; 437 event.tfinger.y = y; 438 event.tfinger.dx = 0; 439 event.tfinger.dy = 0; 440 event.tfinger.pressure = pressure; 441 event.tfinger.windowID = window ? SDL_GetWindowID(window) : 0; 442 SDL_PushEvent(&event); 443 } 444 } else { 445 if (!finger) { 446 // This finger is already up 447 SDL_UnlockTouch(); 448 return; 449 } 450 451 if (SDL_EventEnabled(type)) { 452 SDL_Event event; 453 event.type = type; 454 event.common.timestamp = timestamp; 455 event.tfinger.touchID = id; 456 event.tfinger.fingerID = fingerid; 457 // I don't trust the coordinates passed on fingerUp 458 event.tfinger.x = finger->x; 459 event.tfinger.y = finger->y; 460 event.tfinger.dx = 0; 461 event.tfinger.dy = 0; 462 event.tfinger.pressure = pressure; 463 event.tfinger.windowID = window ? SDL_GetWindowID(window) : 0; 464 SDL_PushEvent(&event); 465 } 466 467 SDL_DelFinger(touch, fingerid); 468 } 469 } 470 SDL_UnlockTouch(); 471} 472 473void SDL_SendTouchMotion(Uint64 timestamp, SDL_TouchID id, SDL_FingerID fingerid, SDL_Window *window, 474 float x, float y, float pressure) 475{ 476 SDL_Touch *touch; 477 SDL_Finger *finger; 478 float xrel, yrel, prel; 479 480 SDL_LockTouch(); 481 { 482 touch = SDL_GetTouch(id); 483 if (!touch) { 484 SDL_UnlockTouch(); 485 return; 486 } 487 488 SDL_Mouse *mouse = SDL_GetMouse(); 489 490 // SDL_HINT_TOUCH_MOUSE_EVENTS: controlling whether touch events should generate synthetic mouse events 491 { 492 if ((id != SDL_MOUSE_TOUCHID) && (id != SDL_PEN_TOUCHID)) { 493 if (mouse->touch_mouse_events) { 494 if (window) { 495 if (finger_touching == true && track_touchid == id && track_fingerid == fingerid) { 496 float pos_x = (x * (float)window->w); 497 float pos_y = (y * (float)window->h); 498 if (pos_x < 0.0f) { 499 pos_x = 0.0f; 500 } 501 if (pos_x > (float)(window->w - 1)) { 502 pos_x = (float)(window->w - 1); 503 } 504 if (pos_y < 0.0f) { 505 pos_y = 0.0f; 506 } 507 if (pos_y > (float)(window->h - 1)) { 508 pos_y = (float)(window->h - 1); 509 } 510 SDL_SendMouseMotion(timestamp, window, SDL_TOUCH_MOUSEID, false, pos_x, pos_y); 511 } 512 } 513 } 514 } 515 } 516 517 // SDL_HINT_MOUSE_TOUCH_EVENTS: if not set, discard synthetic touch events coming from platform layer 518 if (!mouse->mouse_touch_events) { 519 if (id == SDL_MOUSE_TOUCHID) { 520 SDL_UnlockTouch(); 521 return; 522 } 523 } 524 525 finger = SDL_GetFinger(touch, fingerid); 526 if (!finger) { 527 SDL_SendTouch(timestamp, id, fingerid, window, SDL_EVENT_FINGER_DOWN, x, y, pressure); 528 SDL_UnlockTouch(); 529 return; 530 } 531 532 xrel = x - finger->x; 533 yrel = y - finger->y; 534 prel = pressure - finger->pressure; 535 536 // Drop events that don't change state 537 if (xrel == 0.0f && yrel == 0.0f && prel == 0.0f) { 538 #if 0 539 printf("Touch event didn't change state - dropped!\n"); 540 #endif 541 SDL_UnlockTouch(); 542 return; 543 } 544 545 // Update internal touch coordinates 546 finger->x = x; 547 finger->y = y; 548 finger->pressure = pressure; 549 550 // Post the event, if desired 551 if (SDL_EventEnabled(SDL_EVENT_FINGER_MOTION)) { 552 SDL_Event event; 553 event.type = SDL_EVENT_FINGER_MOTION; 554 event.common.timestamp = timestamp; 555 event.tfinger.touchID = id; 556 event.tfinger.fingerID = fingerid; 557 event.tfinger.x = x; 558 event.tfinger.y = y; 559 event.tfinger.dx = xrel; 560 event.tfinger.dy = yrel; 561 event.tfinger.pressure = pressure; 562 event.tfinger.windowID = window ? SDL_GetWindowID(window) : 0; 563 SDL_PushEvent(&event); 564 } 565 } 566 SDL_UnlockTouch(); 567} 568 569void SDL_DelTouch(SDL_TouchID id) 570{ 571 int i, index; 572 SDL_Touch *touch; 573 574 SDL_LockTouch(); 575 { 576 if (SDL_num_touch == 0) { 577 // We've already cleaned up, we won't find this device 578 SDL_UnlockTouch(); 579 return; 580 } 581 582 index = SDL_GetTouchIndex(id); 583 touch = SDL_GetTouch(id); 584 if (!touch) { 585 SDL_UnlockTouch(); 586 return; 587 } 588 589 for (i = 0; i < touch->max_fingers; ++i) { 590 SDL_free(touch->fingers[i]); 591 } 592 SDL_free(touch->fingers); 593 SDL_free(touch->name); 594 SDL_free(touch); 595 596 SDL_num_touch--; 597 SDL_touchDevices[index] = SDL_touchDevices[SDL_num_touch]; 598 } 599 SDL_UnlockTouch(); 600} 601 602void SDL_QuitTouch(void) 603{ 604 int i; 605 606 SDL_LockTouch(); 607 { 608 for (i = SDL_num_touch; i--;) { 609 SDL_DelTouch(SDL_touchDevices[i]->id); 610 } 611 SDL_assert(SDL_num_touch == 0); 612 613 SDL_free(SDL_touchDevices); 614 SDL_touchDevices = NULL; 615 } 616 SDL_UnlockTouch(); 617 618 SDL_DestroyMutex(SDL_touch_lock); 619 SDL_touch_lock = NULL; 620} 621 622int SDL_SendPinch(SDL_EventType type, Uint64 timestamp, SDL_Window *window, float scale) 623{ 624 /* Post the event, if desired */ 625 int posted = 0; 626 if (SDL_EventEnabled(type)) { 627 SDL_Event event; 628 event.type = type; 629 event.common.timestamp = timestamp; 630 event.pinch.scale = scale; 631 event.pinch.windowID = window ? SDL_GetWindowID(window) : 0; 632 posted = (SDL_PushEvent(&event) > 0); 633 } 634 return posted; 635} 636 637[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.