Atlas - SDL_pen.c

Home / ext / SDL / src / events Lines: 1 | Size: 24194 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#include "SDL_internal.h" 22 23// Pressure-sensitive pen handling code for SDL 24 25#include "../SDL_hints_c.h" 26#include "SDL_events_c.h" 27#include "SDL_pen_c.h" 28 29static SDL_PenID pen_touching = 0; // used for synthetic mouse/touch events. 30 31typedef struct SDL_Pen 32{ 33 SDL_PenID instance_id; 34 char *name; 35 SDL_PenInfo info; 36 float axes[SDL_PEN_AXIS_COUNT]; 37 float x; 38 float y; 39 SDL_PenInputFlags input_state; 40 bool pending_proximity_out; 41 SDL_WindowID pending_proximity_window_id; 42 void *driverdata; 43} SDL_Pen; 44 45// we assume there's usually 0-1 pens in most cases and this list doesn't 46// usually change after startup, so a simple array with a RWlock is fine for now. 47static SDL_RWLock *pen_device_rwlock = NULL; 48static SDL_Pen *pen_devices SDL_GUARDED_BY(pen_device_rwlock) = NULL; 49static int pen_device_count SDL_GUARDED_BY(pen_device_rwlock) = 0; 50static SDL_AtomicInt pending_proximity_out; 51 52// You must hold pen_device_rwlock before calling this, and result is only safe while lock is held! 53// If SDL isn't initialized, grabbing the NULL lock is a no-op and there will be zero devices, so 54// locking and calling this in that case will do the right thing. 55static SDL_Pen *FindPenByInstanceId(SDL_PenID instance_id) SDL_REQUIRES_SHARED(pen_device_rwlock) 56{ 57 if (instance_id) { 58 for (int i = 0; i < pen_device_count; i++) { 59 if (pen_devices[i].instance_id == instance_id) { 60 return &pen_devices[i]; 61 } 62 } 63 } 64 SDL_SetError("Invalid pen instance ID"); 65 return NULL; 66} 67 68SDL_PenID SDL_FindPenByHandle(void *handle) 69{ 70 SDL_PenID result = 0; 71 SDL_LockRWLockForReading(pen_device_rwlock); 72 for (int i = 0; i < pen_device_count; i++) { 73 if (pen_devices[i].driverdata == handle) { 74 result = pen_devices[i].instance_id; 75 break; 76 } 77 } 78 SDL_UnlockRWLock(pen_device_rwlock); 79 return result; 80} 81 82SDL_PenID SDL_FindPenByCallback(bool (*callback)(void *handle, void *userdata), void *userdata) 83{ 84 SDL_PenID result = 0; 85 SDL_LockRWLockForReading(pen_device_rwlock); 86 for (int i = 0; i < pen_device_count; i++) { 87 if (callback(pen_devices[i].driverdata, userdata)) { 88 result = pen_devices[i].instance_id; 89 break; 90 } 91 } 92 SDL_UnlockRWLock(pen_device_rwlock); 93 return result; 94} 95 96 97 98// public API ... 99 100bool SDL_InitPen(void) 101{ 102 SDL_assert(pen_device_rwlock == NULL); 103 SDL_assert(pen_devices == NULL); 104 SDL_assert(pen_device_count == 0); 105 pen_device_rwlock = SDL_CreateRWLock(); 106 if (!pen_device_rwlock) { 107 return false; 108 } 109 return true; 110} 111 112void SDL_QuitPen(void) 113{ 114 SDL_RemoveAllPenDevices(NULL, NULL); 115 SDL_DestroyRWLock(pen_device_rwlock); 116 pen_device_rwlock = NULL; 117} 118 119#if 0 // not a public API at the moment. 120SDL_PenID *SDL_GetPens(int *count) 121{ 122 SDL_LockRWLockForReading(pen_device_rwlock); 123 const int num_devices = pen_device_count; 124 SDL_PenID *result = (SDL_PenID *) SDL_malloc((num_devices + 1) * sizeof (SDL_PenID)); 125 if (result) { 126 for (int i = 0; i < num_devices; i++) { 127 result[i] = pen_devices[i].instance_id; 128 } 129 result[num_devices] = 0; // null-terminated. 130 } 131 SDL_UnlockRWLock(pen_device_rwlock); 132 133 if (count) { 134 *count = result ? num_devices : 0; 135 } 136 return result; 137} 138 139const char *SDL_GetPenName(SDL_PenID instance_id) 140{ 141 SDL_LockRWLockForReading(pen_device_rwlock); 142 const SDL_Pen *pen = FindPenByInstanceId(instance_id); 143 const char *result = pen ? SDL_GetPersistentString(pen->name) : NULL; 144 SDL_UnlockRWLock(pen_device_rwlock); 145 return result; 146} 147 148bool SDL_GetPenInfo(SDL_PenID instance_id, SDL_PenInfo *info) 149{ 150 SDL_LockRWLockForReading(pen_device_rwlock); 151 const SDL_Pen *pen = FindPenByInstanceId(instance_id); 152 const bool result = pen ? true : false; 153 if (info) { 154 if (result) { 155 SDL_copyp(info, &pen->info); 156 } else { 157 SDL_zerop(info); 158 } 159 } 160 SDL_UnlockRWLock(pen_device_rwlock); 161 return result; 162} 163 164bool SDL_PenConnected(SDL_PenID instance_id) 165{ 166 SDL_LockRWLockForReading(pen_device_rwlock); 167 const SDL_Pen *pen = FindPenByInstanceId(instance_id); 168 const bool result = (pen != NULL); 169 SDL_UnlockRWLock(pen_device_rwlock); 170 return result; 171} 172#endif 173 174SDL_PenInputFlags SDL_GetPenStatus(SDL_PenID instance_id, float *axes, int num_axes) 175{ 176 if (num_axes < 0) { 177 num_axes = 0; 178 } 179 180 SDL_LockRWLockForReading(pen_device_rwlock); 181 const SDL_Pen *pen = FindPenByInstanceId(instance_id); 182 SDL_PenInputFlags result = 0; 183 if (pen) { 184 result = pen->input_state; 185 if (axes && num_axes) { 186 SDL_memcpy(axes, pen->axes, SDL_min(num_axes, SDL_PEN_AXIS_COUNT) * sizeof (*axes)); 187 // zero out axes we don't know about, in case the caller built with newer SDL headers that support more of them. 188 if (num_axes > SDL_PEN_AXIS_COUNT) { 189 SDL_memset(&axes[SDL_PEN_AXIS_COUNT], '\0', (num_axes - SDL_PEN_AXIS_COUNT) * sizeof (*axes)); 190 } 191 } 192 } 193 SDL_UnlockRWLock(pen_device_rwlock); 194 return result; 195} 196 197SDL_PenDeviceType SDL_GetPenDeviceType(SDL_PenID instance_id) 198{ 199 SDL_LockRWLockForReading(pen_device_rwlock); 200 const SDL_Pen *pen = FindPenByInstanceId(instance_id); 201 const SDL_PenDeviceType result = pen ? pen->info.device_type : SDL_PEN_DEVICE_TYPE_INVALID; 202 SDL_UnlockRWLock(pen_device_rwlock); 203 return result; 204} 205 206SDL_PenCapabilityFlags SDL_GetPenCapabilityFromAxis(SDL_PenAxis axis) 207{ 208 // the initial capability bits happen to match up, but as 209 // more features show up later, the bits may no longer be contiguous! 210 if ((axis >= SDL_PEN_AXIS_PRESSURE) && (axis <= SDL_PEN_AXIS_SLIDER)) { 211 return ((SDL_PenCapabilityFlags) 1u) << ((SDL_PenCapabilityFlags) axis); 212 } 213 return 0; // oh well. 214} 215 216SDL_PenID SDL_AddPenDevice(Uint64 timestamp, const char *name, SDL_Window *window, const SDL_PenInfo *info, void *handle, bool in_proximity) 217{ 218 SDL_assert(handle != NULL); // just allocate a Uint8 so you have a unique pointer if not needed! 219 SDL_assert(SDL_FindPenByHandle(handle) == 0); // Backends shouldn't double-add pens! 220 SDL_assert(pen_device_rwlock != NULL); // subsystem should be initialized by now! 221 222 char *namecpy = SDL_strdup(name ? name : "Unnamed pen"); 223 if (!namecpy) { 224 return 0; 225 } 226 227 SDL_PenID result = 0; 228 229 SDL_LockRWLockForWriting(pen_device_rwlock); 230 231 SDL_Pen *pen = NULL; 232 void *ptr = SDL_realloc(pen_devices, (pen_device_count + 1) * sizeof (*pen)); 233 if (ptr) { 234 result = (SDL_PenID) SDL_GetNextObjectID(); 235 pen_devices = (SDL_Pen *) ptr; 236 pen = &pen_devices[pen_device_count]; 237 pen_device_count++; 238 239 SDL_zerop(pen); 240 pen->instance_id = result; 241 pen->name = namecpy; 242 if (info) { 243 SDL_copyp(&pen->info, info); 244 } 245 pen->driverdata = handle; 246 // axes and input state defaults to zero. 247 } 248 SDL_UnlockRWLock(pen_device_rwlock); 249 250 if (!pen) { 251 SDL_free(namecpy); 252 } 253 254 if (result && in_proximity) { 255 SDL_SendPenProximity(timestamp, result, window, true, true); 256 } 257 258 return result; 259} 260 261void SDL_RemovePenDevice(Uint64 timestamp, SDL_Window *window, SDL_PenID instance_id) 262{ 263 if (!instance_id) { 264 return; 265 } 266 267 SDL_SendPenProximity(timestamp, instance_id, window, false, true); // bye bye 268 269 SDL_LockRWLockForWriting(pen_device_rwlock); 270 SDL_Pen *pen = FindPenByInstanceId(instance_id); 271 if (pen) { 272 SDL_free(pen->name); 273 // we don't free `pen`, it's just part of simple array. Shuffle it out. 274 const int idx = ((int) (pen - pen_devices)); 275 SDL_assert((idx >= 0) && (idx < pen_device_count)); 276 if ( idx < (pen_device_count - 1) ) { 277 SDL_memmove(&pen_devices[idx], &pen_devices[idx + 1], sizeof (*pen) * ((pen_device_count - idx) - 1)); 278 } 279 280 SDL_assert(pen_device_count > 0); 281 pen_device_count--; 282 283 if (pen_device_count) { 284 void *ptr = SDL_realloc(pen_devices, sizeof (*pen) * pen_device_count); // shrink it down. 285 if (ptr) { 286 pen_devices = (SDL_Pen *) ptr; 287 } 288 } else { 289 SDL_free(pen_devices); 290 pen_devices = NULL; 291 } 292 } 293 SDL_UnlockRWLock(pen_device_rwlock); 294} 295 296// This presumably is happening during video quit, so we don't send PROXIMITY_OUT events here. 297void SDL_RemoveAllPenDevices(void (*callback)(SDL_PenID instance_id, void *handle, void *userdata), void *userdata) 298{ 299 SDL_LockRWLockForWriting(pen_device_rwlock); 300 if (pen_device_count > 0) { 301 SDL_assert(pen_devices != NULL); 302 for (int i = 0; i < pen_device_count; i++) { 303 if (callback) { 304 callback(pen_devices[i].instance_id, pen_devices[i].driverdata, userdata); 305 } 306 SDL_free(pen_devices[i].name); 307 } 308 } 309 SDL_free(pen_devices); 310 pen_devices = NULL; 311 pen_device_count = 0; 312 pen_touching = 0; 313 SDL_UnlockRWLock(pen_device_rwlock); 314} 315 316void SDL_SendPenTouch(Uint64 timestamp, SDL_PenID instance_id, SDL_Window *window, bool eraser, bool down) 317{ 318 bool send_event = false; 319 SDL_PenInputFlags input_state = 0; 320 float x = 0.0f; 321 float y = 0.0f; 322 323 // note that this locks for _reading_ because the lock protects the 324 // pen_devices array from being reallocated from under us, not the data in it; 325 // we assume only one thread (in the backend) is modifying an individual pen at 326 // a time, so it can update input state cleanly here. 327 SDL_LockRWLockForReading(pen_device_rwlock); 328 SDL_Pen *pen = FindPenByInstanceId(instance_id); 329 if (pen) { 330 input_state = pen->input_state; 331 x = pen->x; 332 y = pen->y; 333 334 if (down && ((input_state & SDL_PEN_INPUT_DOWN) == 0)) { 335 input_state |= SDL_PEN_INPUT_DOWN; 336 send_event = true; 337 } else if (!down && (input_state & SDL_PEN_INPUT_DOWN)) { 338 input_state &= ~SDL_PEN_INPUT_DOWN; 339 send_event = true; 340 } 341 342 if (eraser && ((input_state & SDL_PEN_INPUT_ERASER_TIP) == 0)) { 343 input_state |= SDL_PEN_INPUT_ERASER_TIP; 344 send_event = true; 345 } else if (!eraser && (input_state & SDL_PEN_INPUT_ERASER_TIP)) { 346 input_state &= ~SDL_PEN_INPUT_ERASER_TIP; 347 send_event = true; 348 } 349 350 pen->input_state = input_state; // we could do an SDL_SetAtomicInt here if we run into trouble... 351 } 352 SDL_UnlockRWLock(pen_device_rwlock); 353 354 if (send_event) { 355 const SDL_EventType evtype = down ? SDL_EVENT_PEN_DOWN : SDL_EVENT_PEN_UP; 356 if (SDL_EventEnabled(evtype)) { 357 SDL_Event event; 358 SDL_zero(event); 359 event.ptouch.type = evtype; 360 event.ptouch.timestamp = timestamp; 361 event.ptouch.windowID = window ? window->id : 0; 362 event.ptouch.which = instance_id; 363 event.ptouch.pen_state = input_state; 364 event.ptouch.x = x; 365 event.ptouch.y = y; 366 event.ptouch.eraser = eraser; 367 event.ptouch.down = down; 368 SDL_PushEvent(&event); 369 } 370 371 SDL_Mouse *mouse = SDL_GetMouse(); 372 if (mouse && window) { 373 if (mouse->pen_mouse_events) { 374 if (down) { 375 if (!pen_touching) { 376 SDL_SendMouseMotion(timestamp, window, SDL_PEN_MOUSEID, false, x, y); 377 SDL_SendMouseButton(timestamp, window, SDL_PEN_MOUSEID, SDL_BUTTON_LEFT, true); 378 } 379 } else { 380 if (pen_touching == instance_id) { 381 SDL_SendMouseButton(timestamp, window, SDL_PEN_MOUSEID, SDL_BUTTON_LEFT, false); 382 } 383 } 384 } 385 386 if (mouse->pen_touch_events) { 387 const SDL_EventType touchtype = down ? SDL_EVENT_FINGER_DOWN : SDL_EVENT_FINGER_UP; 388 const float normalized_x = x / (float)window->w; 389 const float normalized_y = y / (float)window->h; 390 if (!pen_touching || (pen_touching == instance_id)) { 391 SDL_SendTouch(timestamp, SDL_PEN_TOUCHID, SDL_BUTTON_LEFT, window, touchtype, normalized_x, normalized_y, pen->axes[SDL_PEN_AXIS_PRESSURE]); 392 } 393 } 394 } 395 396 if (down) { 397 if (!pen_touching) { 398 pen_touching = instance_id; 399 } 400 } else { 401 if (pen_touching == instance_id) { 402 pen_touching = 0; 403 } 404 } 405 } 406} 407 408void SDL_SendPenAxis(Uint64 timestamp, SDL_PenID instance_id, SDL_Window *window, SDL_PenAxis axis, float value) 409{ 410 SDL_assert((axis >= 0) && (axis < SDL_PEN_AXIS_COUNT)); // fix the backend if this triggers. 411 412 bool send_event = false; 413 SDL_PenInputFlags input_state = 0; 414 float x = 0.0f; 415 float y = 0.0f; 416 417 // note that this locks for _reading_ because the lock protects the 418 // pen_devices array from being reallocated from under us, not the data in it; 419 // we assume only one thread (in the backend) is modifying an individual pen at 420 // a time, so it can update input state cleanly here. 421 SDL_LockRWLockForReading(pen_device_rwlock); 422 SDL_Pen *pen = FindPenByInstanceId(instance_id); 423 if (pen) { 424 if (pen->axes[axis] != value) { 425 pen->axes[axis] = value; // we could do an SDL_SetAtomicInt here if we run into trouble... 426 input_state = pen->input_state; 427 x = pen->x; 428 y = pen->y; 429 send_event = true; 430 } 431 } 432 SDL_UnlockRWLock(pen_device_rwlock); 433 434 if (send_event && SDL_EventEnabled(SDL_EVENT_PEN_AXIS)) { 435 SDL_Event event; 436 SDL_zero(event); 437 event.paxis.type = SDL_EVENT_PEN_AXIS; 438 event.paxis.timestamp = timestamp; 439 event.paxis.windowID = window ? window->id : 0; 440 event.paxis.which = instance_id; 441 event.paxis.pen_state = input_state; 442 event.paxis.x = x; 443 event.paxis.y = y; 444 event.paxis.axis = axis; 445 event.paxis.value = value; 446 SDL_PushEvent(&event); 447 448 if (window && (axis == SDL_PEN_AXIS_PRESSURE) && (pen_touching == instance_id)) { 449 SDL_Mouse *mouse = SDL_GetMouse(); 450 if (mouse && mouse->pen_touch_events) { 451 const float normalized_x = x / (float)window->w; 452 const float normalized_y = y / (float)window->h; 453 SDL_SendTouchMotion(timestamp, SDL_PEN_TOUCHID, SDL_BUTTON_LEFT, window, normalized_x, normalized_y, value); 454 } 455 } 456 } 457} 458 459static void EnsurePenProximity(Uint64 timestamp, SDL_Pen *pen, SDL_Window *window) 460{ 461 if (pen->pending_proximity_out) { 462 pen->pending_proximity_out = false; 463 } else if (!(pen->input_state & SDL_PEN_INPUT_IN_PROXIMITY)) { 464 SDL_SendPenProximity(timestamp, pen->instance_id, window, true, true); 465 } 466} 467 468void SDL_SendPenMotion(Uint64 timestamp, SDL_PenID instance_id, SDL_Window *window, float x, float y) 469{ 470 bool send_event = false; 471 SDL_PenInputFlags input_state = 0; 472 473 // note that this locks for _reading_ because the lock protects the 474 // pen_devices array from being reallocated from under us, not the data in it; 475 // we assume only one thread (in the backend) is modifying an individual pen at 476 // a time, so it can update input state cleanly here. 477 SDL_LockRWLockForReading(pen_device_rwlock); 478 SDL_Pen *pen = FindPenByInstanceId(instance_id); 479 if (pen) { 480 EnsurePenProximity(timestamp, pen, window); 481 482 if ((pen->x != x) || (pen->y != y)) { 483 pen->x = x; // we could do an SDL_SetAtomicInt here if we run into trouble... 484 pen->y = y; // we could do an SDL_SetAtomicInt here if we run into trouble... 485 input_state = pen->input_state; 486 send_event = true; 487 } 488 } 489 SDL_UnlockRWLock(pen_device_rwlock); 490 491 if (send_event && SDL_EventEnabled(SDL_EVENT_PEN_MOTION)) { 492 SDL_Event event; 493 SDL_zero(event); 494 event.pmotion.type = SDL_EVENT_PEN_MOTION; 495 event.pmotion.timestamp = timestamp; 496 event.pmotion.windowID = window ? window->id : 0; 497 event.pmotion.which = instance_id; 498 event.pmotion.pen_state = input_state; 499 event.pmotion.x = x; 500 event.pmotion.y = y; 501 SDL_PushEvent(&event); 502 503 if (window) { 504 SDL_Mouse *mouse = SDL_GetMouse(); 505 if (mouse) { 506 if (pen_touching == instance_id) { 507 if (mouse->pen_mouse_events) { 508 SDL_SendMouseMotion(timestamp, window, SDL_PEN_MOUSEID, false, x, y); 509 } 510 511 if (mouse->pen_touch_events) { 512 const float normalized_x = x / (float)window->w; 513 const float normalized_y = y / (float)window->h; 514 SDL_SendTouchMotion(timestamp, SDL_PEN_TOUCHID, SDL_BUTTON_LEFT, window, normalized_x, normalized_y, pen->axes[SDL_PEN_AXIS_PRESSURE]); 515 } 516 } else if (pen_touching == 0) { // send mouse motion (without a pressed button) for pens that aren't touching. 517 // this might cause a little chaos if you have multiple pens hovering at the same time, but this seems unlikely in the real world, and also something you did to yourself. :) 518 if (mouse->pen_mouse_events) { 519 SDL_SendMouseMotion(timestamp, window, SDL_PEN_MOUSEID, false, x, y); 520 } 521 } 522 } 523 } 524 } 525} 526 527void SDL_SendPenButton(Uint64 timestamp, SDL_PenID instance_id, SDL_Window *window, Uint8 button, bool down) 528{ 529 bool send_event = false; 530 SDL_PenInputFlags input_state = 0; 531 float x = 0.0f; 532 float y = 0.0f; 533 534 if ((button < 1) || (button > 5)) { 535 return; // clamp for now. 536 } 537 538 // note that this locks for _reading_ because the lock protects the 539 // pen_devices array from being reallocated from under us, not the data in it; 540 // we assume only one thread (in the backend) is modifying an individual pen at 541 // a time, so it can update input state cleanly here. 542 SDL_LockRWLockForReading(pen_device_rwlock); 543 SDL_Pen *pen = FindPenByInstanceId(instance_id); 544 if (pen) { 545 EnsurePenProximity(timestamp, pen, window); 546 547 input_state = pen->input_state; 548 const Uint32 flag = (Uint32) (1u << button); 549 const bool current = ((input_state & flag) != 0); 550 x = pen->x; 551 y = pen->y; 552 if (down && !current) { 553 input_state |= flag; 554 send_event = true; 555 } else if (!down && current) { 556 input_state &= ~flag; 557 send_event = true; 558 } 559 pen->input_state = input_state; // we could do an SDL_SetAtomicInt here if we run into trouble... 560 } 561 SDL_UnlockRWLock(pen_device_rwlock); 562 563 if (send_event) { 564 const SDL_EventType evtype = down ? SDL_EVENT_PEN_BUTTON_DOWN : SDL_EVENT_PEN_BUTTON_UP; 565 if (SDL_EventEnabled(evtype)) { 566 SDL_Event event; 567 SDL_zero(event); 568 event.pbutton.type = evtype; 569 event.pbutton.timestamp = timestamp; 570 event.pbutton.windowID = window ? window->id : 0; 571 event.pbutton.which = instance_id; 572 event.pbutton.pen_state = input_state; 573 event.pbutton.x = x; 574 event.pbutton.y = y; 575 event.pbutton.button = button; 576 event.pbutton.down = down; 577 SDL_PushEvent(&event); 578 579 if (window && (!pen_touching || (pen_touching == instance_id))) { 580 SDL_Mouse *mouse = SDL_GetMouse(); 581 if (mouse && mouse->pen_mouse_events) { 582 static const Uint8 mouse_buttons[] = { 583 SDL_BUTTON_LEFT, 584 SDL_BUTTON_RIGHT, 585 SDL_BUTTON_MIDDLE, 586 SDL_BUTTON_X1, 587 SDL_BUTTON_X2 588 }; 589 if (button < SDL_arraysize(mouse_buttons)) { 590 SDL_SendMouseButton(timestamp, window, SDL_PEN_MOUSEID, mouse_buttons[button], down); 591 } 592 } 593 } 594 } 595 } 596} 597 598void SDL_SendPenProximity(Uint64 timestamp, SDL_PenID instance_id, SDL_Window *window, bool in, bool immediate) 599{ 600 bool send_event = false; 601 SDL_PenInputFlags input_state = 0; 602 603 // note that this locks for _reading_ because the lock protects the 604 // pen_devices array from being reallocated from under us, not the data in it; 605 // we assume only one thread (in the backend) is modifying an individual pen at 606 // a time, so it can update input state cleanly here. 607 SDL_LockRWLockForReading(pen_device_rwlock); 608 SDL_Pen *pen = FindPenByInstanceId(instance_id); 609 if (pen) { 610 if (in || immediate) { 611 input_state = pen->input_state; 612 const bool in_proximity = ((input_state & SDL_PEN_INPUT_IN_PROXIMITY) != 0); 613 if (in_proximity != in) { 614 if (in) { 615 input_state |= SDL_PEN_INPUT_IN_PROXIMITY; 616 } else { 617 input_state &= ~SDL_PEN_INPUT_IN_PROXIMITY; 618 } 619 send_event = true; 620 pen->input_state = input_state; // we could do an SDL_SetAtomicInt here if we run into trouble... 621 } 622 pen->pending_proximity_out = false; 623 } else { 624 pen->pending_proximity_out = true; 625 pen->pending_proximity_window_id = (window ? window->id : 0); 626 SDL_SetAtomicInt(&pending_proximity_out, true); 627 } 628 } 629 SDL_UnlockRWLock(pen_device_rwlock); 630 631 const Uint32 event_type = in ? SDL_EVENT_PEN_PROXIMITY_IN : SDL_EVENT_PEN_PROXIMITY_OUT; 632 if (send_event && SDL_EventEnabled(event_type)) { 633 SDL_Event event; 634 SDL_zero(event); 635 event.pproximity.type = event_type; 636 event.pproximity.timestamp = timestamp; 637 event.pproximity.windowID = window ? window->id : 0; 638 event.pproximity.which = instance_id; 639 SDL_PushEvent(&event); 640 } 641} 642 643void SDL_SendPendingPenProximity(void) 644{ 645 if (SDL_CompareAndSwapAtomicInt(&pending_proximity_out, true, false)) { 646 SDL_LockRWLockForReading(pen_device_rwlock); 647 for (int i = 0; i < pen_device_count; i++) { 648 SDL_Pen *pen = &pen_devices[i]; 649 if (pen->pending_proximity_out) { 650 pen->pending_proximity_out = false; 651 652 SDL_Window *window = NULL; 653 if (pen->pending_proximity_window_id) { 654 window = SDL_GetWindowFromID(pen->pending_proximity_window_id); 655 if (!window) { 656 // The window is already gone, ignore this event 657 continue; 658 } 659 } 660 SDL_SendPenProximity(0, pen->instance_id, window, false, true); 661 } 662 } 663 SDL_UnlockRWLock(pen_device_rwlock); 664 } 665} 666 667
[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.