SDL_touch.c (13629B)
1 /* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> 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.h" 26 #include "SDL_events_c.h" 27 #include "../video/SDL_sysvideo.h" 28 29 30 static int SDL_num_touch = 0; 31 static SDL_Touch **SDL_touchDevices = NULL; 32 33 /* for mapping touch events to mice */ 34 35 #define SYNTHESIZE_TOUCH_TO_MOUSE 1 36 37 #if SYNTHESIZE_TOUCH_TO_MOUSE 38 static SDL_bool finger_touching = SDL_FALSE; 39 static SDL_FingerID track_fingerid; 40 static SDL_TouchID track_touchid; 41 #endif 42 43 /* Public functions */ 44 int 45 SDL_TouchInit(void) 46 { 47 return (0); 48 } 49 50 int 51 SDL_GetNumTouchDevices(void) 52 { 53 return SDL_num_touch; 54 } 55 56 SDL_TouchID 57 SDL_GetTouchDevice(int index) 58 { 59 if (index < 0 || index >= SDL_num_touch) { 60 SDL_SetError("Unknown touch device index %d", index); 61 return 0; 62 } 63 return SDL_touchDevices[index]->id; 64 } 65 66 static int 67 SDL_GetTouchIndex(SDL_TouchID id) 68 { 69 int index; 70 SDL_Touch *touch; 71 72 for (index = 0; index < SDL_num_touch; ++index) { 73 touch = SDL_touchDevices[index]; 74 if (touch->id == id) { 75 return index; 76 } 77 } 78 return -1; 79 } 80 81 SDL_Touch * 82 SDL_GetTouch(SDL_TouchID id) 83 { 84 int index = SDL_GetTouchIndex(id); 85 if (index < 0 || index >= SDL_num_touch) { 86 if (SDL_GetVideoDevice()->ResetTouch != NULL) { 87 SDL_SetError("Unknown touch id %d, resetting", (int) id); 88 (SDL_GetVideoDevice()->ResetTouch)(SDL_GetVideoDevice()); 89 } else { 90 SDL_SetError("Unknown touch device id %d, cannot reset", (int) id); 91 } 92 return NULL; 93 } 94 return SDL_touchDevices[index]; 95 } 96 97 SDL_TouchDeviceType 98 SDL_GetTouchDeviceType(SDL_TouchID id) 99 { 100 SDL_Touch *touch = SDL_GetTouch(id); 101 if (touch) { 102 return touch->type; 103 } 104 return SDL_TOUCH_DEVICE_INVALID; 105 } 106 107 static int 108 SDL_GetFingerIndex(const SDL_Touch * touch, SDL_FingerID fingerid) 109 { 110 int index; 111 for (index = 0; index < touch->num_fingers; ++index) { 112 if (touch->fingers[index]->id == fingerid) { 113 return index; 114 } 115 } 116 return -1; 117 } 118 119 static SDL_Finger * 120 SDL_GetFinger(const SDL_Touch * touch, SDL_FingerID id) 121 { 122 int index = SDL_GetFingerIndex(touch, id); 123 if (index < 0 || index >= touch->num_fingers) { 124 return NULL; 125 } 126 return touch->fingers[index]; 127 } 128 129 int 130 SDL_GetNumTouchFingers(SDL_TouchID touchID) 131 { 132 SDL_Touch *touch = SDL_GetTouch(touchID); 133 if (touch) { 134 return touch->num_fingers; 135 } 136 return 0; 137 } 138 139 SDL_Finger * 140 SDL_GetTouchFinger(SDL_TouchID touchID, int index) 141 { 142 SDL_Touch *touch = SDL_GetTouch(touchID); 143 if (!touch) { 144 return NULL; 145 } 146 if (index < 0 || index >= touch->num_fingers) { 147 SDL_SetError("Unknown touch finger"); 148 return NULL; 149 } 150 return touch->fingers[index]; 151 } 152 153 int 154 SDL_AddTouch(SDL_TouchID touchID, SDL_TouchDeviceType type, const char *name) 155 { 156 SDL_Touch **touchDevices; 157 int index; 158 159 index = SDL_GetTouchIndex(touchID); 160 if (index >= 0) { 161 return index; 162 } 163 164 /* Add the touch to the list of touch */ 165 touchDevices = (SDL_Touch **) SDL_realloc(SDL_touchDevices, 166 (SDL_num_touch + 1) * sizeof(*touchDevices)); 167 if (!touchDevices) { 168 return SDL_OutOfMemory(); 169 } 170 171 SDL_touchDevices = touchDevices; 172 index = SDL_num_touch; 173 174 SDL_touchDevices[index] = (SDL_Touch *) SDL_malloc(sizeof(*SDL_touchDevices[index])); 175 if (!SDL_touchDevices[index]) { 176 return SDL_OutOfMemory(); 177 } 178 179 /* Added touch to list */ 180 ++SDL_num_touch; 181 182 /* we're setting the touch properties */ 183 SDL_touchDevices[index]->id = touchID; 184 SDL_touchDevices[index]->type = type; 185 SDL_touchDevices[index]->num_fingers = 0; 186 SDL_touchDevices[index]->max_fingers = 0; 187 SDL_touchDevices[index]->fingers = NULL; 188 189 /* Record this touch device for gestures */ 190 /* We could do this on the fly in the gesture code if we wanted */ 191 SDL_GestureAddTouch(touchID); 192 193 return index; 194 } 195 196 static int 197 SDL_AddFinger(SDL_Touch *touch, SDL_FingerID fingerid, float x, float y, float pressure) 198 { 199 SDL_Finger *finger; 200 201 if (touch->num_fingers == touch->max_fingers) { 202 SDL_Finger **new_fingers; 203 new_fingers = (SDL_Finger **)SDL_realloc(touch->fingers, (touch->max_fingers+1)*sizeof(*touch->fingers)); 204 if (!new_fingers) { 205 return SDL_OutOfMemory(); 206 } 207 touch->fingers = new_fingers; 208 touch->fingers[touch->max_fingers] = (SDL_Finger *)SDL_malloc(sizeof(*finger)); 209 if (!touch->fingers[touch->max_fingers]) { 210 return SDL_OutOfMemory(); 211 } 212 touch->max_fingers++; 213 } 214 215 finger = touch->fingers[touch->num_fingers++]; 216 finger->id = fingerid; 217 finger->x = x; 218 finger->y = y; 219 finger->pressure = pressure; 220 return 0; 221 } 222 223 static int 224 SDL_DelFinger(SDL_Touch* touch, SDL_FingerID fingerid) 225 { 226 SDL_Finger *temp; 227 228 int index = SDL_GetFingerIndex(touch, fingerid); 229 if (index < 0) { 230 return -1; 231 } 232 233 touch->num_fingers--; 234 temp = touch->fingers[index]; 235 touch->fingers[index] = touch->fingers[touch->num_fingers]; 236 touch->fingers[touch->num_fingers] = temp; 237 return 0; 238 } 239 240 int 241 SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window * window, 242 SDL_bool down, float x, float y, float pressure) 243 { 244 int posted; 245 SDL_Finger *finger; 246 SDL_Mouse *mouse; 247 248 SDL_Touch* touch = SDL_GetTouch(id); 249 if (!touch) { 250 return -1; 251 } 252 253 mouse = SDL_GetMouse(); 254 255 #if SYNTHESIZE_TOUCH_TO_MOUSE 256 /* SDL_HINT_TOUCH_MOUSE_EVENTS: controlling whether touch events should generate synthetic mouse events */ 257 { 258 if (mouse->touch_mouse_events) { 259 /* FIXME: maybe we should only restrict to a few SDL_TouchDeviceType */ 260 if (id != SDL_MOUSE_TOUCHID) { 261 if (window) { 262 if (down) { 263 if (finger_touching == SDL_FALSE) { 264 int pos_x = (int)(x * (float)window->w); 265 int pos_y = (int)(y * (float)window->h); 266 if (pos_x < 0) pos_x = 0; 267 if (pos_x > window->w - 1) pos_x = window->w - 1; 268 if (pos_y < 0) pos_y = 0; 269 if (pos_y > window->h - 1) pos_y = window->h - 1; 270 SDL_SendMouseMotion(window, SDL_TOUCH_MOUSEID, 0, pos_x, pos_y); 271 SDL_SendMouseButton(window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT); 272 } 273 } else { 274 if (finger_touching == SDL_TRUE && track_touchid == id && track_fingerid == fingerid) { 275 SDL_SendMouseButton(window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT); 276 } 277 } 278 } 279 if (down) { 280 if (finger_touching == SDL_FALSE) { 281 finger_touching = SDL_TRUE; 282 track_touchid = id; 283 track_fingerid = fingerid; 284 } 285 } else { 286 if (finger_touching == SDL_TRUE && track_touchid == id && track_fingerid == fingerid) { 287 finger_touching = SDL_FALSE; 288 } 289 } 290 } 291 } 292 } 293 #endif 294 295 /* SDL_HINT_MOUSE_TOUCH_EVENTS: if not set, discard synthetic touch events coming from platform layer */ 296 if (mouse->mouse_touch_events == 0) { 297 if (id == SDL_MOUSE_TOUCHID) { 298 return 0; 299 } 300 } 301 302 finger = SDL_GetFinger(touch, fingerid); 303 if (down) { 304 if (finger) { 305 /* This finger is already down */ 306 return 0; 307 } 308 309 if (SDL_AddFinger(touch, fingerid, x, y, pressure) < 0) { 310 return 0; 311 } 312 313 posted = 0; 314 if (SDL_GetEventState(SDL_FINGERDOWN) == SDL_ENABLE) { 315 SDL_Event event; 316 event.tfinger.type = SDL_FINGERDOWN; 317 event.tfinger.touchId = id; 318 event.tfinger.fingerId = fingerid; 319 event.tfinger.x = x; 320 event.tfinger.y = y; 321 event.tfinger.dx = 0; 322 event.tfinger.dy = 0; 323 event.tfinger.pressure = pressure; 324 event.tfinger.windowID = window ? SDL_GetWindowID(window) : 0; 325 posted = (SDL_PushEvent(&event) > 0); 326 } 327 } else { 328 if (!finger) { 329 /* This finger is already up */ 330 return 0; 331 } 332 333 posted = 0; 334 if (SDL_GetEventState(SDL_FINGERUP) == SDL_ENABLE) { 335 SDL_Event event; 336 event.tfinger.type = SDL_FINGERUP; 337 event.tfinger.touchId = id; 338 event.tfinger.fingerId = fingerid; 339 /* I don't trust the coordinates passed on fingerUp */ 340 event.tfinger.x = finger->x; 341 event.tfinger.y = finger->y; 342 event.tfinger.dx = 0; 343 event.tfinger.dy = 0; 344 event.tfinger.pressure = pressure; 345 event.tfinger.windowID = window ? SDL_GetWindowID(window) : 0; 346 posted = (SDL_PushEvent(&event) > 0); 347 } 348 349 SDL_DelFinger(touch, fingerid); 350 } 351 return posted; 352 } 353 354 int 355 SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window * window, 356 float x, float y, float pressure) 357 { 358 SDL_Touch *touch; 359 SDL_Finger *finger; 360 SDL_Mouse *mouse; 361 int posted; 362 float xrel, yrel, prel; 363 364 touch = SDL_GetTouch(id); 365 if (!touch) { 366 return -1; 367 } 368 369 mouse = SDL_GetMouse(); 370 371 #if SYNTHESIZE_TOUCH_TO_MOUSE 372 /* SDL_HINT_TOUCH_MOUSE_EVENTS: controlling whether touch events should generate synthetic mouse events */ 373 { 374 if (mouse->touch_mouse_events) { 375 if (id != SDL_MOUSE_TOUCHID) { 376 if (window) { 377 if (finger_touching == SDL_TRUE && track_touchid == id && track_fingerid == fingerid) { 378 int pos_x = (int)(x * (float)window->w); 379 int pos_y = (int)(y * (float)window->h); 380 if (pos_x < 0) pos_x = 0; 381 if (pos_x > window->w - 1) pos_x = window->w - 1; 382 if (pos_y < 0) pos_y = 0; 383 if (pos_y > window->h - 1) pos_y = window->h - 1; 384 SDL_SendMouseMotion(window, SDL_TOUCH_MOUSEID, 0, pos_x, pos_y); 385 } 386 } 387 } 388 } 389 } 390 #endif 391 392 /* SDL_HINT_MOUSE_TOUCH_EVENTS: if not set, discard synthetic touch events coming from platform layer */ 393 if (mouse->mouse_touch_events == 0) { 394 if (id == SDL_MOUSE_TOUCHID) { 395 return 0; 396 } 397 } 398 399 finger = SDL_GetFinger(touch,fingerid); 400 if (!finger) { 401 return SDL_SendTouch(id, fingerid, window, SDL_TRUE, x, y, pressure); 402 } 403 404 xrel = x - finger->x; 405 yrel = y - finger->y; 406 prel = pressure - finger->pressure; 407 408 /* Drop events that don't change state */ 409 if (xrel == 0.0f && yrel == 0.0f && prel == 0.0f) { 410 #if 0 411 printf("Touch event didn't change state - dropped!\n"); 412 #endif 413 return 0; 414 } 415 416 /* Update internal touch coordinates */ 417 finger->x = x; 418 finger->y = y; 419 finger->pressure = pressure; 420 421 /* Post the event, if desired */ 422 posted = 0; 423 if (SDL_GetEventState(SDL_FINGERMOTION) == SDL_ENABLE) { 424 SDL_Event event; 425 event.tfinger.type = SDL_FINGERMOTION; 426 event.tfinger.touchId = id; 427 event.tfinger.fingerId = fingerid; 428 event.tfinger.x = x; 429 event.tfinger.y = y; 430 event.tfinger.dx = xrel; 431 event.tfinger.dy = yrel; 432 event.tfinger.pressure = pressure; 433 event.tfinger.windowID = window ? SDL_GetWindowID(window) : 0; 434 posted = (SDL_PushEvent(&event) > 0); 435 } 436 return posted; 437 } 438 439 void 440 SDL_DelTouch(SDL_TouchID id) 441 { 442 int i; 443 int index = SDL_GetTouchIndex(id); 444 SDL_Touch *touch = SDL_GetTouch(id); 445 446 if (!touch) { 447 return; 448 } 449 450 for (i = 0; i < touch->max_fingers; ++i) { 451 SDL_free(touch->fingers[i]); 452 } 453 SDL_free(touch->fingers); 454 SDL_free(touch); 455 456 SDL_num_touch--; 457 SDL_touchDevices[index] = SDL_touchDevices[SDL_num_touch]; 458 459 /* Delete this touch device for gestures */ 460 SDL_GestureDelTouch(id); 461 } 462 463 void 464 SDL_TouchQuit(void) 465 { 466 int i; 467 468 for (i = SDL_num_touch; i--; ) { 469 SDL_DelTouch(SDL_touchDevices[i]->id); 470 } 471 SDL_assert(SDL_num_touch == 0); 472 473 SDL_free(SDL_touchDevices); 474 SDL_touchDevices = NULL; 475 SDL_GestureQuit(); 476 } 477 478 /* vi: set ts=4 sw=4 expandtab: */