Simple Directmedia Layer

Added SDL_EVENT_FINGER_CANCELED

Fixes https://github.com/libsdl-org/SDL/issues/10528

Changed files
+90 -40
android-project
app
src
main
java
org
libsdl
include
src
+1 -2
android-project/app/src/main/java/org/libsdl/app/SDLSurface.java
··· 287 287 p = 1.0f; 288 288 } 289 289 290 - SDLActivity.onNativeTouch(touchDevId, pointerId, 291 - action == MotionEvent.ACTION_CANCEL ? MotionEvent.ACTION_UP : action, x, y, p); 290 + SDLActivity.onNativeTouch(touchDevId, pointerId, action, x, y, p); 292 291 } 293 292 294 293 // Non-primary up/down
+2 -1
include/SDL3/SDL_events.h
··· 212 212 SDL_EVENT_FINGER_DOWN = 0x700, 213 213 SDL_EVENT_FINGER_UP, 214 214 SDL_EVENT_FINGER_MOTION, 215 + SDL_EVENT_FINGER_CANCELED, 215 216 216 217 /* 0x800, 0x801, and 0x802 were the Gesture events from SDL2. Do not reuse these values! sdl2-compat needs them! */ 217 218 ··· 764 765 */ 765 766 typedef struct SDL_TouchFingerEvent 766 767 { 767 - SDL_EventType type; /**< SDL_EVENT_FINGER_MOTION or SDL_EVENT_FINGER_DOWN or SDL_EVENT_FINGER_UP */ 768 + SDL_EventType type; /**< SDL_EVENT_FINGER_DOWN, SDL_EVENT_FINGER_UP, SDL_EVENT_FINGER_MOTION, or SDL_EVENT_FINGER_CANCELED */ 768 769 Uint32 reserved; 769 770 Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */ 770 771 SDL_TouchID touchID; /**< The touch device id */
+2 -2
src/core/linux/SDL_evdev.c
··· 546 546 * be window-relative in that case. */ 547 547 switch (item->touchscreen_data->slots[j].delta) { 548 548 case EVDEV_TOUCH_SLOTDELTA_DOWN: 549 - SDL_SendTouch(SDL_EVDEV_GetEventTimestamp(event), item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, true, norm_x, norm_y, norm_pressure); 549 + SDL_SendTouch(SDL_EVDEV_GetEventTimestamp(event), item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, SDL_EVENT_FINGER_DOWN, norm_x, norm_y, norm_pressure); 550 550 item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE; 551 551 break; 552 552 case EVDEV_TOUCH_SLOTDELTA_UP: 553 - SDL_SendTouch(SDL_EVDEV_GetEventTimestamp(event), item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, false, norm_x, norm_y, norm_pressure); 553 + SDL_SendTouch(SDL_EVDEV_GetEventTimestamp(event), item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, SDL_EVENT_FINGER_UP, norm_x, norm_y, norm_pressure); 554 554 item->touchscreen_data->slots[j].tracking_id = 0; 555 555 item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE; 556 556 break;
+1
src/events/SDL_categories.c
··· 136 136 137 137 case SDL_EVENT_FINGER_DOWN: 138 138 case SDL_EVENT_FINGER_UP: 139 + case SDL_EVENT_FINGER_CANCELED: 139 140 case SDL_EVENT_FINGER_MOTION: 140 141 return SDL_EVENTCATEGORY_TFINGER; 141 142
+3
src/events/SDL_events.c
··· 705 705 SDL_EVENT_CASE(SDL_EVENT_FINGER_UP) 706 706 PRINT_FINGER_EVENT(event); 707 707 break; 708 + SDL_EVENT_CASE(SDL_EVENT_FINGER_CANCELED) 709 + PRINT_FINGER_EVENT(event); 710 + break; 708 711 SDL_EVENT_CASE(SDL_EVENT_FINGER_MOTION) 709 712 PRINT_FINGER_EVENT(event); 710 713 break;
+3 -2
src/events/SDL_mouse.c
··· 827 827 static void SDL_PrivateSendMouseButton(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, Uint8 button, bool down, int clicks) 828 828 { 829 829 SDL_Mouse *mouse = SDL_GetMouse(); 830 - Uint32 type; 830 + SDL_EventType type; 831 831 Uint32 buttonstate; 832 832 SDL_MouseInputSource *source; 833 833 ··· 851 851 track_mouse_down = false; 852 852 } 853 853 if (window) { 854 + type = track_mouse_down ? SDL_EVENT_FINGER_DOWN : SDL_EVENT_FINGER_UP; 854 855 float normalized_x = mouse->x / (float)window->w; 855 856 float normalized_y = mouse->y / (float)window->h; 856 - SDL_SendTouch(timestamp, SDL_MOUSE_TOUCHID, SDL_BUTTON_LEFT, window, track_mouse_down, normalized_x, normalized_y, 1.0f); 857 + SDL_SendTouch(timestamp, SDL_MOUSE_TOUCHID, SDL_BUTTON_LEFT, window, type, normalized_x, normalized_y, 1.0f); 857 858 } 858 859 } 859 860 }
+8 -7
src/events/SDL_touch.c
··· 254 254 } 255 255 } 256 256 257 - void SDL_SendTouch(Uint64 timestamp, SDL_TouchID id, SDL_FingerID fingerid, SDL_Window *window, bool down, float x, float y, float pressure) 257 + void SDL_SendTouch(Uint64 timestamp, SDL_TouchID id, SDL_FingerID fingerid, SDL_Window *window, SDL_EventType type, float x, float y, float pressure) 258 258 { 259 259 SDL_Finger *finger; 260 260 SDL_Mouse *mouse; 261 + bool down = (type == SDL_EVENT_FINGER_DOWN); 261 262 262 263 SDL_Touch *touch = SDL_GetTouch(id); 263 264 if (!touch) { ··· 331 332 if (finger) { 332 333 /* This finger is already down. 333 334 Assume the finger-up for the previous touch was lost, and send it. */ 334 - SDL_SendTouch(timestamp, id, fingerid, window, false, x, y, pressure); 335 + SDL_SendTouch(timestamp, id, fingerid, window, SDL_EVENT_FINGER_CANCELED, x, y, pressure); 335 336 } 336 337 337 338 if (!SDL_AddFinger(touch, fingerid, x, y, pressure)) { 338 339 return; 339 340 } 340 341 341 - if (SDL_EventEnabled(SDL_EVENT_FINGER_DOWN)) { 342 + if (SDL_EventEnabled(type)) { 342 343 SDL_Event event; 343 - event.type = SDL_EVENT_FINGER_DOWN; 344 + event.type = type; 344 345 event.common.timestamp = timestamp; 345 346 event.tfinger.touchID = id; 346 347 event.tfinger.fingerID = fingerid; ··· 358 359 return; 359 360 } 360 361 361 - if (SDL_EventEnabled(SDL_EVENT_FINGER_UP)) { 362 + if (SDL_EventEnabled(type)) { 362 363 SDL_Event event; 363 - event.type = SDL_EVENT_FINGER_UP; 364 + event.type = type; 364 365 event.common.timestamp = timestamp; 365 366 event.tfinger.touchID = id; 366 367 event.tfinger.fingerID = fingerid; ··· 431 432 432 433 finger = SDL_GetFinger(touch, fingerid); 433 434 if (!finger) { 434 - SDL_SendTouch(timestamp, id, fingerid, window, true, x, y, pressure); 435 + SDL_SendTouch(timestamp, id, fingerid, window, SDL_EVENT_FINGER_DOWN, x, y, pressure); 435 436 return; 436 437 } 437 438
+1 -1
src/events/SDL_touch_c.h
··· 46 46 extern SDL_Touch *SDL_GetTouch(SDL_TouchID id); 47 47 48 48 // Send a touch down/up event for a touch 49 - extern void SDL_SendTouch(Uint64 timestamp, SDL_TouchID id, SDL_FingerID fingerid, SDL_Window *window, bool down, float x, float y, float pressure); 49 + extern void SDL_SendTouch(Uint64 timestamp, SDL_TouchID id, SDL_FingerID fingerid, SDL_Window *window, SDL_EventType type, float x, float y, float pressure); 50 50 51 51 // Send a touch motion event for a touch 52 52 extern void SDL_SendTouchMotion(Uint64 timestamp, SDL_TouchID id, SDL_FingerID fingerid, SDL_Window *window, float x, float y, float pressure);
+1
src/render/SDL_render.c
··· 2897 2897 } 2898 2898 } else if (event->type == SDL_EVENT_FINGER_DOWN || 2899 2899 event->type == SDL_EVENT_FINGER_UP || 2900 + event->type == SDL_EVENT_FINGER_CANCELED || 2900 2901 event->type == SDL_EVENT_FINGER_MOTION) { 2901 2902 // FIXME: Are these events guaranteed to be window relative? 2902 2903 if (renderer->window) {
+3 -1
src/test/SDL_test_common.c
··· 1910 1910 break; 1911 1911 case SDL_EVENT_FINGER_DOWN: 1912 1912 case SDL_EVENT_FINGER_UP: 1913 + case SDL_EVENT_FINGER_CANCELED: 1913 1914 SDL_Log("SDL EVENT: Finger: %s touch=%" SDL_PRIu64 ", finger=%" SDL_PRIu64 ", x=%f, y=%f, dx=%f, dy=%f, pressure=%f", 1914 - (event->type == SDL_EVENT_FINGER_DOWN) ? "down" : "up", 1915 + (event->type == SDL_EVENT_FINGER_DOWN) ? "down" : 1916 + (event->type == SDL_EVENT_FINGER_UP) ? "up" : "cancel", 1915 1917 event->tfinger.touchID, 1916 1918 event->tfinger.fingerID, 1917 1919 event->tfinger.x, event->tfinger.y,
+7 -3
src/video/android/SDL_androidtouch.c
··· 32 32 #define ACTION_DOWN 0 33 33 #define ACTION_UP 1 34 34 #define ACTION_MOVE 2 35 - // #define ACTION_CANCEL 3 35 + #define ACTION_CANCEL 3 36 36 // #define ACTION_OUTSIDE 4 37 37 #define ACTION_POINTER_DOWN 5 38 38 #define ACTION_POINTER_UP 6 ··· 72 72 switch (action) { 73 73 case ACTION_DOWN: 74 74 case ACTION_POINTER_DOWN: 75 - SDL_SendTouch(0, touchDeviceId, fingerId, window, true, x, y, p); 75 + SDL_SendTouch(0, touchDeviceId, fingerId, window, SDL_EVENT_FINGER_DOWN, x, y, p); 76 76 break; 77 77 78 78 case ACTION_MOVE: ··· 81 81 82 82 case ACTION_UP: 83 83 case ACTION_POINTER_UP: 84 - SDL_SendTouch(0, touchDeviceId, fingerId, window, false, x, y, p); 84 + SDL_SendTouch(0, touchDeviceId, fingerId, window, SDL_EVENT_FINGER_UP, x, y, p); 85 + break; 86 + 87 + case ACTION_CANCEL: 88 + SDL_SendTouch(0, touchDeviceId, fingerId, window, SDL_EVENT_FINGER_CANCELED, x, y, p); 85 89 break; 86 90 87 91 default:
+5 -3
src/video/cocoa/SDL_cocoawindow.m
··· 1844 1844 * events from being generated from touch events. 1845 1845 */ 1846 1846 SDL_Window *window = NULL; 1847 - SDL_SendTouch(Cocoa_GetEventTimestamp([theEvent timestamp]), touchID, finger->id, window, false, 0, 0, 0); 1847 + SDL_SendTouch(Cocoa_GetEventTimestamp([theEvent timestamp]), touchID, finger->id, window, SDL_EVENT_FINGER_CANCELED, 0, 0, 0); 1848 1848 } 1849 1849 SDL_free(fingers); 1850 1850 } ··· 1914 1914 1915 1915 switch (phase) { 1916 1916 case NSTouchPhaseBegan: 1917 - SDL_SendTouch(Cocoa_GetEventTimestamp([theEvent timestamp]), touchId, fingerId, window, true, x, y, 1.0f); 1917 + SDL_SendTouch(Cocoa_GetEventTimestamp([theEvent timestamp]), touchId, fingerId, window, SDL_EVENT_FINGER_DOWN, x, y, 1.0f); 1918 1918 break; 1919 1919 case NSTouchPhaseEnded: 1920 + SDL_SendTouch(Cocoa_GetEventTimestamp([theEvent timestamp]), touchId, fingerId, window, SDL_EVENT_FINGER_UP, x, y, 1.0f); 1921 + break; 1920 1922 case NSTouchPhaseCancelled: 1921 - SDL_SendTouch(Cocoa_GetEventTimestamp([theEvent timestamp]), touchId, fingerId, window, false, x, y, 1.0f); 1923 + SDL_SendTouch(Cocoa_GetEventTimestamp([theEvent timestamp]), touchId, fingerId, window, SDL_EVENT_FINGER_CANCELED, x, y, 1.0f); 1922 1924 break; 1923 1925 case NSTouchPhaseMoved: 1924 1926 SDL_SendTouchMotion(Cocoa_GetEventTimestamp([theEvent timestamp]), touchId, fingerId, window, x, y, 1.0f);
+5 -3
src/video/emscripten/SDL_emscriptenevents.c
··· 433 433 } 434 434 435 435 if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) { 436 - SDL_SendTouch(0, deviceId, id, window_data->window, true, x, y, 1.0f); 436 + SDL_SendTouch(0, deviceId, id, window_data->window, SDL_EVENT_FINGER_DOWN, x, y, 1.0f); 437 437 438 438 // disable browser scrolling/pinch-to-zoom if app handles touch events 439 439 if (!preventDefault && SDL_EventEnabled(SDL_EVENT_FINGER_DOWN)) { ··· 441 441 } 442 442 } else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) { 443 443 SDL_SendTouchMotion(0, deviceId, id, window_data->window, x, y, 1.0f); 444 - } else { 445 - SDL_SendTouch(0, deviceId, id, window_data->window, false, x, y, 1.0f); 444 + } else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) { 445 + SDL_SendTouch(0, deviceId, id, window_data->window, SDL_EVENT_FINGER_UP, x, y, 1.0f); 446 446 447 447 // block browser's simulated mousedown/mouseup on touchscreen devices 448 448 preventDefault = 1; 449 + } else if (eventType == EMSCRIPTEN_EVENT_TOUCHCANCEL) { 450 + SDL_SendTouch(0, deviceId, id, window_data->window, SDL_EVENT_FINGER_CANCELED, x, y, 1.0f); 449 451 } 450 452 } 451 453
+1 -1
src/video/n3ds/SDL_n3dstouch.c
··· 70 70 was_pressed = pressed; 71 71 SDL_SendTouch(0, N3DS_TOUCH_ID, N3DS_TOUCH_FINGER, 72 72 window, 73 - pressed, 73 + pressed ? SDL_EVENT_FINGER_DOWN : SDL_EVENT_FINGER_UP, 74 74 touch.px * TOUCHSCREEN_SCALE_X, 75 75 touch.py * TOUCHSCREEN_SCALE_Y, 76 76 pressed ? 1.0f : 0.0f);
+38 -5
src/video/uikit/SDL_uikitview.m
··· 353 353 } 354 354 } 355 355 #endif 356 - 356 + 357 357 #if defined(__IPHONE_13_4) 358 358 if (@available(iOS 13.4, *)) { 359 359 if (touch.type == UITouchTypeIndirectPointer) { ··· 377 377 CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES]; 378 378 SDL_SendTouch(UIKit_GetEventTimestamp([event timestamp]), 379 379 touchId, (SDL_FingerID)(uintptr_t)touch, sdlwindow, 380 - true, locationInView.x, locationInView.y, pressure); 380 + SDL_EVENT_FINGER_DOWN, locationInView.x, locationInView.y, pressure); 381 381 } 382 382 } 383 383 ··· 393 393 } 394 394 } 395 395 #endif 396 - 396 + 397 397 #if defined(__IPHONE_13_4) 398 398 if (@available(iOS 13.4, *)) { 399 399 if (touch.type == UITouchTypeIndirectPointer) { ··· 417 417 CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES]; 418 418 SDL_SendTouch(UIKit_GetEventTimestamp([event timestamp]), 419 419 touchId, (SDL_FingerID)(uintptr_t)touch, sdlwindow, 420 - false, locationInView.x, locationInView.y, pressure); 420 + SDL_EVENT_FINGER_UP, locationInView.x, locationInView.y, pressure); 421 421 } 422 422 } 423 423 424 424 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 425 425 { 426 - [self touchesEnded:touches withEvent:event]; 426 + for (UITouch *touch in touches) { 427 + #if !defined(SDL_PLATFORM_TVOS) 428 + #if defined(__IPHONE_13_0) 429 + if (@available(iOS 13.0, *)) { 430 + if (touch.type == UITouchTypePencil) { 431 + [self pencilReleased:touch]; 432 + continue; 433 + } 434 + } 435 + #endif 436 + 437 + #if defined(__IPHONE_13_4) 438 + if (@available(iOS 13.4, *)) { 439 + if (touch.type == UITouchTypeIndirectPointer) { 440 + [self indirectPointerReleased:touch fromEvent:event]; 441 + continue; 442 + } 443 + } 444 + #endif 445 + #endif // !defined(SDL_PLATFORM_TVOS) 446 + 447 + SDL_TouchDeviceType touchType = [self touchTypeForTouch:touch]; 448 + SDL_TouchID touchId = [self touchIdForType:touchType]; 449 + float pressure = [self pressureForTouch:touch]; 450 + 451 + if (SDL_AddTouch(touchId, touchType, "") < 0) { 452 + continue; 453 + } 454 + 455 + CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES]; 456 + SDL_SendTouch(UIKit_GetEventTimestamp([event timestamp]), 457 + touchId, (SDL_FingerID)(uintptr_t)touch, sdlwindow, 458 + SDL_EVENT_FINGER_CANCELED, locationInView.x, locationInView.y, pressure); 459 + } 427 460 } 428 461 429 462 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
+2 -2
src/video/vita/SDL_vitatouch.c
··· 125 125 // Skip if finger was already previously down 126 126 if (!finger_down) { 127 127 // Send an initial touch 128 - SDL_SendTouch(0, touch_id, finger_id, Vita_Window, true, x, y, force); 128 + SDL_SendTouch(0, touch_id, finger_id, Vita_Window, SDL_EVENT_FINGER_DOWN, x, y, force); 129 129 } 130 130 131 131 // Always send the motion ··· 151 151 VITA_ConvertTouchXYToSDLXY(&x, &y, touch_old[port].report[i].x, touch_old[port].report[i].y, port); 152 152 finger_id = (SDL_FingerID)(touch_old[port].report[i].id + 1); 153 153 // Finger released from screen 154 - SDL_SendTouch(0, touch_id, finger_id, Vita_Window, false, x, y, force); 154 + SDL_SendTouch(0, touch_id, finger_id, Vita_Window, SDL_EVENT_FINGER_UP, x, y, force); 155 155 } 156 156 } 157 157 }
+3 -3
src/video/wayland/SDL_waylandevents.c
··· 1148 1148 SDL_SetMouseFocus(window_data->sdlwindow); 1149 1149 1150 1150 SDL_SendTouch(Wayland_GetTouchTimestamp(input, timestamp), (SDL_TouchID)(uintptr_t)touch, 1151 - (SDL_FingerID)(id + 1), window_data->sdlwindow, true, x, y, 1.0f); 1151 + (SDL_FingerID)(id + 1), window_data->sdlwindow, SDL_EVENT_FINGER_DOWN, x, y, 1.0f); 1152 1152 } 1153 1153 } 1154 1154 ··· 1169 1169 const float y = (float)wl_fixed_to_double(fy) / window_data->current.logical_height; 1170 1170 1171 1171 SDL_SendTouch(Wayland_GetTouchTimestamp(input, timestamp), (SDL_TouchID)(uintptr_t)touch, 1172 - (SDL_FingerID)(id + 1), window_data->sdlwindow, false, x, y, 0.0f); 1172 + (SDL_FingerID)(id + 1), window_data->sdlwindow, SDL_EVENT_FINGER_UP, x, y, 0.0f); 1173 1173 1174 1174 /* If the seat lacks pointer focus, the seat's keyboard focus is another window or NULL, this window currently 1175 1175 * has mouse focus, and the surface has no active touch events, consider mouse focus to be lost. ··· 1223 1223 const float y = (float)(wl_fixed_to_double(tp->fy) / window_data->current.logical_height); 1224 1224 1225 1225 SDL_SendTouch(0, (SDL_TouchID)(uintptr_t)touch, 1226 - (SDL_FingerID)(tp->id + 1), window_data->sdlwindow, false, x, y, 0.0f); 1226 + (SDL_FingerID)(tp->id + 1), window_data->sdlwindow, SDL_EVENT_FINGER_CANCELED, x, y, 0.0f); 1227 1227 1228 1228 // Remove the touch from the list before checking for still-active touches on the surface. 1229 1229 WAYLAND_wl_list_remove(&tp->link);
+2 -2
src/video/windows/SDL_windowsevents.c
··· 1811 1811 1812 1812 // FIXME: Should we use the input->dwTime field for the tick source of the timestamp? 1813 1813 if (input->dwFlags & TOUCHEVENTF_DOWN) { 1814 - SDL_SendTouch(WIN_GetEventTimestamp(), touchId, fingerId, data->window, true, x, y, 1.0f); 1814 + SDL_SendTouch(WIN_GetEventTimestamp(), touchId, fingerId, data->window, SDL_EVENT_FINGER_DOWN, x, y, 1.0f); 1815 1815 } 1816 1816 if (input->dwFlags & TOUCHEVENTF_MOVE) { 1817 1817 SDL_SendTouchMotion(WIN_GetEventTimestamp(), touchId, fingerId, data->window, x, y, 1.0f); 1818 1818 } 1819 1819 if (input->dwFlags & TOUCHEVENTF_UP) { 1820 - SDL_SendTouch(WIN_GetEventTimestamp(), touchId, fingerId, data->window, false, x, y, 1.0f); 1820 + SDL_SendTouch(WIN_GetEventTimestamp(), touchId, fingerId, data->window, SDL_EVENT_FINGER_UP, x, y, 1.0f); 1821 1821 } 1822 1822 } 1823 1823 }
+2 -2
src/video/x11/SDL_x11xinput2.c
··· 482 482 float x, y; 483 483 SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event); 484 484 xinput2_normalize_touch_coordinates(window, xev->event_x, xev->event_y, &x, &y); 485 - SDL_SendTouch(0, xev->sourceid, xev->detail, window, true, x, y, 1.0); 485 + SDL_SendTouch(0, xev->sourceid, xev->detail, window, SDL_EVENT_FINGER_DOWN, x, y, 1.0); 486 486 } break; 487 487 488 488 case XI_TouchEnd: ··· 491 491 float x, y; 492 492 SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event); 493 493 xinput2_normalize_touch_coordinates(window, xev->event_x, xev->event_y, &x, &y); 494 - SDL_SendTouch(0, xev->sourceid, xev->detail, window, false, x, y, 1.0); 494 + SDL_SendTouch(0, xev->sourceid, xev->detail, window, SDL_EVENT_FINGER_UP, x, y, 1.0); 495 495 } break; 496 496 497 497 case XI_TouchUpdate: