Atlas - SDL_mouse.c

Home / ext / SDL2 / src / events Lines: 5 | Size: 27031 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 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 mouse handling code for SDL */ 24 25#include "SDL_assert.h" 26#include "SDL_hints.h" 27#include "SDL_timer.h" 28#include "SDL_events.h" 29#include "SDL_events_c.h" 30#include "../video/SDL_sysvideo.h" 31 32/* #define DEBUG_MOUSE */ 33 34/* The mouse state */ 35static SDL_Mouse SDL_mouse; 36static Uint32 SDL_double_click_time = 500; 37static int SDL_double_click_radius = 1; 38 39static int 40SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y); 41 42static void SDLCALL 43SDL_MouseNormalSpeedScaleChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 44{ 45 SDL_Mouse *mouse = (SDL_Mouse *)userdata; 46 47 if (hint && *hint) { 48 mouse->normal_speed_scale = (float)SDL_atof(hint); 49 } else { 50 mouse->normal_speed_scale = 1.0f; 51 } 52} 53 54static void SDLCALL 55SDL_MouseRelativeSpeedScaleChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 56{ 57 SDL_Mouse *mouse = (SDL_Mouse *)userdata; 58 59 if (hint && *hint) { 60 mouse->relative_speed_scale = (float)SDL_atof(hint); 61 } else { 62 mouse->relative_speed_scale = 1.0f; 63 } 64} 65 66static void SDLCALL 67SDL_TouchMouseEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 68{ 69 SDL_Mouse *mouse = (SDL_Mouse *)userdata; 70 71 if (hint && (*hint == '0' || SDL_strcasecmp(hint, "false") == 0)) { 72 mouse->touch_mouse_events = SDL_FALSE; 73 } else { 74 mouse->touch_mouse_events = SDL_TRUE; 75 } 76} 77 78/* Public functions */ 79int 80SDL_MouseInit(void) 81{ 82 SDL_Mouse *mouse = SDL_GetMouse(); 83 84 SDL_zerop(mouse); 85 86 SDL_AddHintCallback(SDL_HINT_MOUSE_NORMAL_SPEED_SCALE, 87 SDL_MouseNormalSpeedScaleChanged, mouse); 88 89 SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE, 90 SDL_MouseRelativeSpeedScaleChanged, mouse); 91 92 SDL_AddHintCallback(SDL_HINT_TOUCH_MOUSE_EVENTS, 93 SDL_TouchMouseEventsChanged, mouse); 94 95 mouse->cursor_shown = SDL_TRUE; 96 97 return (0); 98} 99 100void 101SDL_SetDefaultCursor(SDL_Cursor * cursor) 102{ 103 SDL_Mouse *mouse = SDL_GetMouse(); 104 105 mouse->def_cursor = cursor; 106 if (!mouse->cur_cursor) { 107 SDL_SetCursor(cursor); 108 } 109} 110 111SDL_Mouse * 112SDL_GetMouse(void) 113{ 114 return &SDL_mouse; 115} 116 117void 118SDL_SetDoubleClickTime(Uint32 interval) 119{ 120 SDL_double_click_time = interval; 121} 122 123SDL_Window * 124SDL_GetMouseFocus(void) 125{ 126 SDL_Mouse *mouse = SDL_GetMouse(); 127 128 return mouse->focus; 129} 130 131#if 0 132void 133SDL_ResetMouse(void) 134{ 135 SDL_Mouse *mouse = SDL_GetMouse(); 136 Uint8 i; 137 138#ifdef DEBUG_MOUSE 139 printf("Resetting mouse\n"); 140#endif 141 for (i = 1; i <= sizeof(mouse->buttonstate)*8; ++i) { 142 if (mouse->buttonstate & SDL_BUTTON(i)) { 143 SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, i); 144 } 145 } 146 SDL_assert(mouse->buttonstate == 0); 147} 148#endif 149 150void 151SDL_SetMouseFocus(SDL_Window * window) 152{ 153 SDL_Mouse *mouse = SDL_GetMouse(); 154 155 if (mouse->focus == window) { 156 return; 157 } 158 159 /* Actually, this ends up being a bad idea, because most operating 160 systems have an implicit grab when you press the mouse button down 161 so you can drag things out of the window and then get the mouse up 162 when it happens. So, #if 0... 163 */ 164#if 0 165 if (mouse->focus && !window) { 166 /* We won't get anymore mouse messages, so reset mouse state */ 167 SDL_ResetMouse(); 168 } 169#endif 170 171 /* See if the current window has lost focus */ 172 if (mouse->focus) { 173 SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0); 174 } 175 176 mouse->focus = window; 177 mouse->has_position = SDL_FALSE; 178 179 if (mouse->focus) { 180 SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0); 181 } 182 183 /* Update cursor visibility */ 184 SDL_SetCursor(NULL); 185} 186 187/* Check to see if we need to synthesize focus events */ 188static SDL_bool 189SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate) 190{ 191 SDL_Mouse *mouse = SDL_GetMouse(); 192 SDL_bool inWindow = SDL_TRUE; 193 194 if (window && ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0)) { 195 int w, h; 196 SDL_GetWindowSize(window, &w, &h); 197 if (x < 0 || y < 0 || x >= w || y >= h) { 198 inWindow = SDL_FALSE; 199 } 200 } 201 202/* Linux doesn't give you mouse events outside your window unless you grab 203 the pointer. 204 205 Windows doesn't give you mouse events outside your window unless you call 206 SetCapture(). 207 208 Both of these are slightly scary changes, so for now we'll punt and if the 209 mouse leaves the window you'll lose mouse focus and reset button state. 210*/ 211#ifdef SUPPORT_DRAG_OUTSIDE_WINDOW 212 if (!inWindow && !buttonstate) { 213#else 214 if (!inWindow) { 215#endif 216 if (window == mouse->focus) { 217#ifdef DEBUG_MOUSE 218 printf("Mouse left window, synthesizing move & focus lost event\n"); 219#endif 220 SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y); 221 SDL_SetMouseFocus(NULL); 222 } 223 return SDL_FALSE; 224 } 225 226 if (window != mouse->focus) { 227#ifdef DEBUG_MOUSE 228 printf("Mouse entered window, synthesizing focus gain & move event\n"); 229#endif 230 SDL_SetMouseFocus(window); 231 SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y); 232 } 233 return SDL_TRUE; 234} 235 236int 237SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y) 238{ 239 if (window && !relative) { 240 SDL_Mouse *mouse = SDL_GetMouse(); 241 if (!SDL_UpdateMouseFocus(window, x, y, mouse->buttonstate)) { 242 return 0; 243 } 244 } 245 246 return SDL_PrivateSendMouseMotion(window, mouseID, relative, x, y); 247} 248 249static int 250GetScaledMouseDelta(float scale, int value, float *accum) 251{ 252 if (scale != 1.0f) { 253 *accum += scale * value; 254 if (*accum >= 0.0f) { 255 value = (int)SDL_floor(*accum); 256 } else { 257 value = (int)SDL_ceil(*accum); 258 } 259 *accum -= value; 260 } 261 return value; 262} 263 264static int 265SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y) 266{ 267 SDL_Mouse *mouse = SDL_GetMouse(); 268 int posted; 269 int xrel; 270 int yrel; 271 272 if (mouseID == SDL_TOUCH_MOUSEID && !mouse->touch_mouse_events) { 273 return 0; 274 } 275 276 if (mouseID != SDL_TOUCH_MOUSEID && mouse->relative_mode_warp) { 277 int center_x = 0, center_y = 0; 278 SDL_GetWindowSize(window, &center_x, &center_y); 279 center_x /= 2; 280 center_y /= 2; 281 if (x == center_x && y == center_y) { 282 mouse->last_x = center_x; 283 mouse->last_y = center_y; 284 return 0; 285 } 286 SDL_WarpMouseInWindow(window, center_x, center_y); 287 } 288 289 if (relative) { 290 if (mouse->relative_mode) { 291 x = GetScaledMouseDelta(mouse->relative_speed_scale, x, &mouse->scale_accum_x); 292 y = GetScaledMouseDelta(mouse->relative_speed_scale, y, &mouse->scale_accum_y); 293 } else { 294 x = GetScaledMouseDelta(mouse->normal_speed_scale, x, &mouse->scale_accum_x); 295 y = GetScaledMouseDelta(mouse->normal_speed_scale, y, &mouse->scale_accum_y); 296 } 297 xrel = x; 298 yrel = y; 299 x = (mouse->last_x + xrel); 300 y = (mouse->last_y + yrel); 301 } else { 302 xrel = x - mouse->last_x; 303 yrel = y - mouse->last_y; 304 } 305 306 /* Drop events that don't change state */ 307 if (!xrel && !yrel) { 308#ifdef DEBUG_MOUSE 309 printf("Mouse event didn't change state - dropped!\n"); 310#endif 311 return 0; 312 } 313 314 /* Ignore relative motion when first positioning the mouse */ 315 if (!mouse->has_position) { 316 xrel = 0; 317 yrel = 0; 318 mouse->has_position = SDL_TRUE; 319 } 320 321 /* Ignore relative motion positioning the first touch */ 322 if (mouseID == SDL_TOUCH_MOUSEID && !mouse->buttonstate) { 323 xrel = 0; 324 yrel = 0; 325 } 326 327 /* Update internal mouse coordinates */ 328 if (!mouse->relative_mode) { 329 mouse->x = x; 330 mouse->y = y; 331 } else { 332 mouse->x += xrel; 333 mouse->y += yrel; 334 } 335 336 /* make sure that the pointers find themselves inside the windows, 337 unless we have the mouse captured. */ 338 if (window && ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0)) { 339 int x_max = 0, y_max = 0; 340 341 /* !!! FIXME: shouldn't this be (window) instead of (mouse->focus)? */ 342 SDL_GetWindowSize(mouse->focus, &x_max, &y_max); 343 --x_max; 344 --y_max; 345 346 if (mouse->x > x_max) { 347 mouse->x = x_max; 348 } 349 if (mouse->x < 0) { 350 mouse->x = 0; 351 } 352 353 if (mouse->y > y_max) { 354 mouse->y = y_max; 355 } 356 if (mouse->y < 0) { 357 mouse->y = 0; 358 } 359 } 360 361 mouse->xdelta += xrel; 362 mouse->ydelta += yrel; 363 364 /* Move the mouse cursor, if needed */ 365 if (mouse->cursor_shown && !mouse->relative_mode && 366 mouse->MoveCursor && mouse->cur_cursor) { 367 mouse->MoveCursor(mouse->cur_cursor); 368 } 369 370 /* Post the event, if desired */ 371 posted = 0; 372 if (SDL_GetEventState(SDL_MOUSEMOTION) == SDL_ENABLE) { 373 SDL_Event event; 374 event.motion.type = SDL_MOUSEMOTION; 375 event.motion.windowID = mouse->focus ? mouse->focus->id : 0; 376 event.motion.which = mouseID; 377 event.motion.state = mouse->buttonstate; 378 event.motion.x = mouse->x; 379 event.motion.y = mouse->y; 380 event.motion.xrel = xrel; 381 event.motion.yrel = yrel; 382 posted = (SDL_PushEvent(&event) > 0); 383 } 384 if (relative) { 385 mouse->last_x = mouse->x; 386 mouse->last_y = mouse->y; 387 } else { 388 /* Use unclamped values if we're getting events outside the window */ 389 mouse->last_x = x; 390 mouse->last_y = y; 391 } 392 return posted; 393} 394 395static SDL_MouseClickState *GetMouseClickState(SDL_Mouse *mouse, Uint8 button) 396{ 397 if (button >= mouse->num_clickstates) { 398 int i, count = button + 1; 399 SDL_MouseClickState *clickstate = (SDL_MouseClickState *)SDL_realloc(mouse->clickstate, count * sizeof(*mouse->clickstate)); 400 if (!clickstate) { 401 return NULL; 402 } 403 mouse->clickstate = clickstate; 404 405 for (i = mouse->num_clickstates; i < count; ++i) { 406 SDL_zero(mouse->clickstate[i]); 407 } 408 mouse->num_clickstates = count; 409 } 410 return &mouse->clickstate[button]; 411} 412 413static int 414SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button, int clicks) 415{ 416 SDL_Mouse *mouse = SDL_GetMouse(); 417 int posted; 418 Uint32 type; 419 Uint32 buttonstate = mouse->buttonstate; 420 421 if (mouseID == SDL_TOUCH_MOUSEID && !mouse->touch_mouse_events) { 422 return 0; 423 } 424 425 /* Figure out which event to perform */ 426 switch (state) { 427 case SDL_PRESSED: 428 type = SDL_MOUSEBUTTONDOWN; 429 buttonstate |= SDL_BUTTON(button); 430 break; 431 case SDL_RELEASED: 432 type = SDL_MOUSEBUTTONUP; 433 buttonstate &= ~SDL_BUTTON(button); 434 break; 435 default: 436 /* Invalid state -- bail */ 437 return 0; 438 } 439 440 /* We do this after calculating buttonstate so button presses gain focus */ 441 if (window && state == SDL_PRESSED) { 442 SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate); 443 } 444 445 if (buttonstate == mouse->buttonstate) { 446 /* Ignore this event, no state change */ 447 return 0; 448 } 449 mouse->buttonstate = buttonstate; 450 451 if (clicks < 0) { 452 SDL_MouseClickState *clickstate = GetMouseClickState(mouse, button); 453 if (clickstate) { 454 if (state == SDL_PRESSED) { 455 Uint32 now = SDL_GetTicks(); 456 457 if (SDL_TICKS_PASSED(now, clickstate->last_timestamp + SDL_double_click_time) || 458 SDL_abs(mouse->x - clickstate->last_x) > SDL_double_click_radius || 459 SDL_abs(mouse->y - clickstate->last_y) > SDL_double_click_radius) { 460 clickstate->click_count = 0; 461 } 462 clickstate->last_timestamp = now; 463 clickstate->last_x = mouse->x; 464 clickstate->last_y = mouse->y; 465 if (clickstate->click_count < 255) { 466 ++clickstate->click_count; 467 } 468 } 469 clicks = clickstate->click_count; 470 } else { 471 clicks = 1; 472 } 473 } 474 475 /* Post the event, if desired */ 476 posted = 0; 477 if (SDL_GetEventState(type) == SDL_ENABLE) { 478 SDL_Event event; 479 event.type = type; 480 event.button.windowID = mouse->focus ? mouse->focus->id : 0; 481 event.button.which = mouseID; 482 event.button.state = state; 483 event.button.button = button; 484 event.button.clicks = (Uint8) SDL_min(clicks, 255); 485 event.button.x = mouse->x; 486 event.button.y = mouse->y; 487 posted = (SDL_PushEvent(&event) > 0); 488 } 489 490 /* We do this after dispatching event so button releases can lose focus */ 491 if (window && state == SDL_RELEASED) { 492 SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate); 493 } 494 495 return posted; 496} 497 498int 499SDL_SendMouseButtonClicks(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button, int clicks) 500{ 501 clicks = SDL_max(clicks, 0); 502 return SDL_PrivateSendMouseButton(window, mouseID, state, button, clicks); 503} 504 505int 506SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button) 507{ 508 return SDL_PrivateSendMouseButton(window, mouseID, state, button, -1); 509} 510 511int 512SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, float x, float y, SDL_MouseWheelDirection direction) 513{ 514 SDL_Mouse *mouse = SDL_GetMouse(); 515 int posted; 516 int integral_x, integral_y; 517 518 if (window) { 519 SDL_SetMouseFocus(window); 520 } 521 522 if (!x && !y) { 523 return 0; 524 } 525 526 mouse->accumulated_wheel_x += x; 527 if (mouse->accumulated_wheel_x > 0) { 528 integral_x = (int)SDL_floor(mouse->accumulated_wheel_x); 529 } else if (mouse->accumulated_wheel_x < 0) { 530 integral_x = (int)SDL_ceil(mouse->accumulated_wheel_x); 531 } else { 532 integral_x = 0; 533 } 534 mouse->accumulated_wheel_x -= integral_x; 535 536 mouse->accumulated_wheel_y += y; 537 if (mouse->accumulated_wheel_y > 0) { 538 integral_y = (int)SDL_floor(mouse->accumulated_wheel_y); 539 } else if (mouse->accumulated_wheel_y < 0) { 540 integral_y = (int)SDL_ceil(mouse->accumulated_wheel_y); 541 } else { 542 integral_y = 0; 543 } 544 mouse->accumulated_wheel_y -= integral_y; 545 546 /* Post the event, if desired */ 547 posted = 0; 548 if (SDL_GetEventState(SDL_MOUSEWHEEL) == SDL_ENABLE) { 549 SDL_Event event; 550 event.type = SDL_MOUSEWHEEL; 551 event.wheel.windowID = mouse->focus ? mouse->focus->id : 0; 552 event.wheel.which = mouseID; 553#if 0 /* Uncomment this when it goes in for SDL 2.1 */ 554 event.wheel.preciseX = x; 555 event.wheel.preciseY = y; 556#endif 557 event.wheel.x = integral_x; 558 event.wheel.y = integral_y; 559 event.wheel.direction = (Uint32)direction; 560 posted = (SDL_PushEvent(&event) > 0); 561 } 562 return posted; 563} 564 565void 566SDL_MouseQuit(void) 567{ 568 SDL_Cursor *cursor, *next; 569 SDL_Mouse *mouse = SDL_GetMouse(); 570 571 if (mouse->CaptureMouse) { 572 SDL_CaptureMouse(SDL_FALSE); 573 } 574 SDL_SetRelativeMouseMode(SDL_FALSE); 575 SDL_ShowCursor(1); 576 577 cursor = mouse->cursors; 578 while (cursor) { 579 next = cursor->next; 580 SDL_FreeCursor(cursor); 581 cursor = next; 582 } 583 mouse->cursors = NULL; 584 585 if (mouse->def_cursor && mouse->FreeCursor) { 586 mouse->FreeCursor(mouse->def_cursor); 587 mouse->def_cursor = NULL; 588 } 589 590 if (mouse->clickstate) { 591 SDL_free(mouse->clickstate); 592 mouse->clickstate = NULL; 593 } 594 595 SDL_DelHintCallback(SDL_HINT_MOUSE_NORMAL_SPEED_SCALE, 596 SDL_MouseNormalSpeedScaleChanged, mouse); 597 598 SDL_DelHintCallback(SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE, 599 SDL_MouseRelativeSpeedScaleChanged, mouse); 600} 601 602Uint32 603SDL_GetMouseState(int *x, int *y) 604{ 605 SDL_Mouse *mouse = SDL_GetMouse(); 606 607 if (x) { 608 *x = mouse->x; 609 } 610 if (y) { 611 *y = mouse->y; 612 } 613 return mouse->buttonstate; 614} 615 616Uint32 617SDL_GetRelativeMouseState(int *x, int *y) 618{ 619 SDL_Mouse *mouse = SDL_GetMouse(); 620 621 if (x) { 622 *x = mouse->xdelta; 623 } 624 if (y) { 625 *y = mouse->ydelta; 626 } 627 mouse->xdelta = 0; 628 mouse->ydelta = 0; 629 return mouse->buttonstate; 630} 631 632Uint32 633SDL_GetGlobalMouseState(int *x, int *y) 634{ 635 SDL_Mouse *mouse = SDL_GetMouse(); 636 int tmpx, tmpy; 637 638 /* make sure these are never NULL for the backend implementations... */ 639 if (!x) { 640 x = &tmpx; 641 } 642 if (!y) { 643 y = &tmpy; 644 } 645 646 *x = *y = 0; 647 648 if (!mouse->GetGlobalMouseState) { 649 return 0; 650 } 651 652 return mouse->GetGlobalMouseState(x, y); 653} 654 655void 656SDL_WarpMouseInWindow(SDL_Window * window, int x, int y) 657{ 658 SDL_Mouse *mouse = SDL_GetMouse(); 659 660 if (window == NULL) { 661 window = mouse->focus; 662 } 663 664 if (window == NULL) { 665 return; 666 } 667 668 if (mouse->WarpMouse) { 669 mouse->WarpMouse(window, x, y); 670 } else { 671 SDL_SendMouseMotion(window, mouse->mouseID, 0, x, y); 672 } 673} 674 675int 676SDL_WarpMouseGlobal(int x, int y) 677{ 678 SDL_Mouse *mouse = SDL_GetMouse(); 679 680 if (mouse->WarpMouseGlobal) { 681 return mouse->WarpMouseGlobal(x, y); 682 } 683 684 return SDL_Unsupported(); 685} 686 687static SDL_bool 688ShouldUseRelativeModeWarp(SDL_Mouse *mouse) 689{ 690 if (!mouse->SetRelativeMouseMode) { 691 SDL_assert(mouse->WarpMouse); /* Need this functionality for relative mode warp implementation */ 692 return SDL_TRUE; 693 } 694 695 return SDL_GetHintBoolean(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, SDL_FALSE); 696} 697 698int 699SDL_SetRelativeMouseMode(SDL_bool enabled) 700{ 701 SDL_Mouse *mouse = SDL_GetMouse(); 702 SDL_Window *focusWindow = SDL_GetKeyboardFocus(); 703 704 if (enabled == mouse->relative_mode) { 705 return 0; 706 } 707 708 if (enabled && focusWindow) { 709 /* Center it in the focused window to prevent clicks from going through 710 * to background windows. 711 */ 712 SDL_SetMouseFocus(focusWindow); 713 SDL_WarpMouseInWindow(focusWindow, focusWindow->w/2, focusWindow->h/2); 714 } 715 716 /* Set the relative mode */ 717 if (!enabled && mouse->relative_mode_warp) { 718 mouse->relative_mode_warp = SDL_FALSE; 719 } else if (enabled && ShouldUseRelativeModeWarp(mouse)) { 720 mouse->relative_mode_warp = SDL_TRUE; 721 } else if (mouse->SetRelativeMouseMode(enabled) < 0) { 722 if (enabled) { 723 /* Fall back to warp mode if native relative mode failed */ 724 if (!mouse->WarpMouse) { 725 return SDL_SetError("No relative mode implementation available"); 726 } 727 mouse->relative_mode_warp = SDL_TRUE; 728 } 729 } 730 mouse->relative_mode = enabled; 731 mouse->scale_accum_x = 0.0f; 732 mouse->scale_accum_y = 0.0f; 733 734 if (mouse->focus) { 735 SDL_UpdateWindowGrab(mouse->focus); 736 737 /* Put the cursor back to where the application expects it */ 738 if (!enabled) { 739 SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y); 740 } 741 } 742 743 /* Flush pending mouse motion - ideally we would pump events, but that's not always safe */ 744 SDL_FlushEvent(SDL_MOUSEMOTION); 745 746 /* Update cursor visibility */ 747 SDL_SetCursor(NULL); 748 749 return 0; 750} 751 752SDL_bool 753SDL_GetRelativeMouseMode() 754{ 755 SDL_Mouse *mouse = SDL_GetMouse(); 756 757 return mouse->relative_mode; 758} 759 760int 761SDL_CaptureMouse(SDL_bool enabled) 762{ 763 SDL_Mouse *mouse = SDL_GetMouse(); 764 SDL_Window *focusWindow; 765 SDL_bool isCaptured; 766 767 if (!mouse->CaptureMouse) { 768 return SDL_Unsupported(); 769 } 770 771 focusWindow = SDL_GetKeyboardFocus(); 772 773 isCaptured = focusWindow && (focusWindow->flags & SDL_WINDOW_MOUSE_CAPTURE); 774 if (isCaptured == enabled) { 775 return 0; /* already done! */ 776 } 777 778 if (enabled) { 779 if (!focusWindow) { 780 return SDL_SetError("No window has focus"); 781 } else if (mouse->CaptureMouse(focusWindow) == -1) { 782 return -1; /* CaptureMouse() should call SetError */ 783 } 784 focusWindow->flags |= SDL_WINDOW_MOUSE_CAPTURE; 785 } else { 786 if (mouse->CaptureMouse(NULL) == -1) { 787 return -1; /* CaptureMouse() should call SetError */ 788 } 789 focusWindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE; 790 } 791 792 return 0; 793} 794 795SDL_Cursor * 796SDL_CreateCursor(const Uint8 * data, const Uint8 * mask, 797 int w, int h, int hot_x, int hot_y) 798{ 799 SDL_Surface *surface; 800 SDL_Cursor *cursor; 801 int x, y; 802 Uint32 *pixel; 803 Uint8 datab = 0, maskb = 0; 804 const Uint32 black = 0xFF000000; 805 const Uint32 white = 0xFFFFFFFF; 806 const Uint32 transparent = 0x00000000; 807 808 /* Make sure the width is a multiple of 8 */ 809 w = ((w + 7) & ~7); 810 811 /* Create the surface from a bitmap */ 812 surface = SDL_CreateRGBSurface(0, w, h, 32, 813 0x00FF0000, 814 0x0000FF00, 815 0x000000FF, 816 0xFF000000); 817 if (!surface) { 818 return NULL; 819 } 820 for (y = 0; y < h; ++y) { 821 pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch); 822 for (x = 0; x < w; ++x) { 823 if ((x % 8) == 0) { 824 datab = *data++; 825 maskb = *mask++; 826 } 827 if (maskb & 0x80) { 828 *pixel++ = (datab & 0x80) ? black : white; 829 } else { 830 *pixel++ = (datab & 0x80) ? black : transparent; 831 } 832 datab <<= 1; 833 maskb <<= 1; 834 } 835 } 836 837 cursor = SDL_CreateColorCursor(surface, hot_x, hot_y); 838 839 SDL_FreeSurface(surface); 840 841 return cursor; 842} 843 844SDL_Cursor * 845SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y) 846{ 847 SDL_Mouse *mouse = SDL_GetMouse(); 848 SDL_Surface *temp = NULL; 849 SDL_Cursor *cursor; 850 851 if (!surface) { 852 SDL_SetError("Passed NULL cursor surface"); 853 return NULL; 854 } 855 856 if (!mouse->CreateCursor) { 857 SDL_SetError("Cursors are not currently supported"); 858 return NULL; 859 } 860 861 /* Sanity check the hot spot */ 862 if ((hot_x < 0) || (hot_y < 0) || 863 (hot_x >= surface->w) || (hot_y >= surface->h)) { 864 SDL_SetError("Cursor hot spot doesn't lie within cursor"); 865 return NULL; 866 } 867 868 if (surface->format->format != SDL_PIXELFORMAT_ARGB8888) { 869 temp = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0); 870 if (!temp) { 871 return NULL; 872 } 873 surface = temp; 874 } 875 876 cursor = mouse->CreateCursor(surface, hot_x, hot_y); 877 if (cursor) { 878 cursor->next = mouse->cursors; 879 mouse->cursors = cursor; 880 } 881 882 SDL_FreeSurface(temp); 883 884 return cursor; 885} 886 887SDL_Cursor * 888SDL_CreateSystemCursor(SDL_SystemCursor id) 889{ 890 SDL_Mouse *mouse = SDL_GetMouse(); 891 SDL_Cursor *cursor; 892 893 if (!mouse->CreateSystemCursor) { 894 SDL_SetError("CreateSystemCursor is not currently supported"); 895 return NULL; 896 } 897 898 cursor = mouse->CreateSystemCursor(id); 899 if (cursor) { 900 cursor->next = mouse->cursors; 901 mouse->cursors = cursor; 902 } 903 904 return cursor; 905} 906 907/* SDL_SetCursor(NULL) can be used to force the cursor redraw, 908 if this is desired for any reason. This is used when setting 909 the video mode and when the SDL window gains the mouse focus. 910 */ 911void 912SDL_SetCursor(SDL_Cursor * cursor) 913{ 914 SDL_Mouse *mouse = SDL_GetMouse(); 915 916 /* Set the new cursor */ 917 if (cursor) { 918 /* Make sure the cursor is still valid for this mouse */ 919 if (cursor != mouse->def_cursor) { 920 SDL_Cursor *found; 921 for (found = mouse->cursors; found; found = found->next) { 922 if (found == cursor) { 923 break; 924 } 925 } 926 if (!found) { 927 SDL_SetError("Cursor not associated with the current mouse"); 928 return; 929 } 930 } 931 mouse->cur_cursor = cursor; 932 } else { 933 if (mouse->focus) { 934 cursor = mouse->cur_cursor; 935 } else { 936 cursor = mouse->def_cursor; 937 } 938 } 939 940 if (cursor && mouse->cursor_shown && !mouse->relative_mode) { 941 if (mouse->ShowCursor) { 942 mouse->ShowCursor(cursor); 943 } 944 } else { 945 if (mouse->ShowCursor) { 946 mouse->ShowCursor(NULL); 947 } 948 } 949} 950 951SDL_Cursor * 952SDL_GetCursor(void) 953{ 954 SDL_Mouse *mouse = SDL_GetMouse(); 955 956 if (!mouse) { 957 return NULL; 958 } 959 return mouse->cur_cursor; 960} 961 962SDL_Cursor * 963SDL_GetDefaultCursor(void) 964{ 965 SDL_Mouse *mouse = SDL_GetMouse(); 966 967 if (!mouse) { 968 return NULL; 969 } 970 return mouse->def_cursor; 971} 972 973void 974SDL_FreeCursor(SDL_Cursor * cursor) 975{ 976 SDL_Mouse *mouse = SDL_GetMouse(); 977 SDL_Cursor *curr, *prev; 978 979 if (!cursor) { 980 return; 981 } 982 983 if (cursor == mouse->def_cursor) { 984 return; 985 } 986 if (cursor == mouse->cur_cursor) { 987 SDL_SetCursor(mouse->def_cursor); 988 } 989 990 for (prev = NULL, curr = mouse->cursors; curr; 991 prev = curr, curr = curr->next) { 992 if (curr == cursor) { 993 if (prev) { 994 prev->next = curr->next; 995 } else { 996 mouse->cursors = curr->next; 997 } 998 999 if (mouse->FreeCursor) { 1000 mouse->FreeCursor(curr); 1001 } 1002 return; 1003 } 1004 } 1005} 1006 1007int 1008SDL_ShowCursor(int toggle) 1009{ 1010 SDL_Mouse *mouse = SDL_GetMouse(); 1011 SDL_bool shown; 1012 1013 if (!mouse) { 1014 return 0; 1015 } 1016 1017 shown = mouse->cursor_shown; 1018 if (toggle >= 0) { 1019 if (toggle) { 1020 mouse->cursor_shown = SDL_TRUE; 1021 } else { 1022 mouse->cursor_shown = SDL_FALSE; 1023 } 1024 if (mouse->cursor_shown != shown) { 1025 SDL_SetCursor(NULL); 1026 } 1027 } 1028 return shown; 1029} 1030 1031/* vi: set ts=4 sw=4 expandtab: */ 1032
[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.