Fixed comment in gesture source.
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
21 #include "../SDL_internal.h"
23 /* General mouse handling code for SDL */
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 "default_cursor.h"
31 #include "../video/SDL_sysvideo.h"
33 /* #define DEBUG_MOUSE */
36 static SDL_Mouse SDL_mouse;
37 static Uint32 SDL_double_click_time = 500;
38 static int SDL_double_click_radius = 1;
41 SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y);
43 /* Public functions */
47 SDL_Mouse *mouse = SDL_GetMouse();
49 mouse->cursor_shown = SDL_TRUE;
55 SDL_SetDefaultCursor(SDL_Cursor * cursor)
57 SDL_Mouse *mouse = SDL_GetMouse();
59 mouse->def_cursor = cursor;
60 if (!mouse->cur_cursor) {
61 SDL_SetCursor(cursor);
72 SDL_SetDoubleClickTime(Uint32 interval)
74 SDL_double_click_time = interval;
78 SDL_GetMouseFocus(void)
80 SDL_Mouse *mouse = SDL_GetMouse();
88 SDL_Mouse *mouse = SDL_GetMouse();
92 printf("Resetting mouse\n");
94 for (i = 1; i <= sizeof(mouse->buttonstate)*8; ++i) {
95 if (mouse->buttonstate & SDL_BUTTON(i)) {
96 SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, i);
99 SDL_assert(mouse->buttonstate == 0);
103 SDL_SetMouseFocus(SDL_Window * window)
105 SDL_Mouse *mouse = SDL_GetMouse();
107 if (mouse->focus == window) {
111 /* Actually, this ends up being a bad idea, because most operating
112 systems have an implicit grab when you press the mouse button down
113 so you can drag things out of the window and then get the mouse up
114 when it happens. So, #if 0...
117 if (mouse->focus && !window) {
118 /* We won't get anymore mouse messages, so reset mouse state */
123 /* See if the current window has lost focus */
125 SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
128 mouse->focus = window;
131 SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
134 /* Update cursor visibility */
138 /* Check to see if we need to synthesize focus events */
140 SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate)
142 SDL_Mouse *mouse = SDL_GetMouse();
143 SDL_bool inWindow = SDL_TRUE;
145 if (window && ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0)) {
147 SDL_GetWindowSize(window, &w, &h);
148 if (x < 0 || y < 0 || x >= w || y >= h) {
149 inWindow = SDL_FALSE;
153 /* Linux doesn't give you mouse events outside your window unless you grab
156 Windows doesn't give you mouse events outside your window unless you call
159 Both of these are slightly scary changes, so for now we'll punt and if the
160 mouse leaves the window you'll lose mouse focus and reset button state.
162 #ifdef SUPPORT_DRAG_OUTSIDE_WINDOW
163 if (!inWindow && !buttonstate) {
167 if (window == mouse->focus) {
169 printf("Mouse left window, synthesizing move & focus lost event\n");
171 SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
172 SDL_SetMouseFocus(NULL);
177 if (window != mouse->focus) {
179 printf("Mouse entered window, synthesizing focus gain & move event\n");
181 SDL_SetMouseFocus(window);
182 SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
188 SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
190 if (window && !relative) {
191 SDL_Mouse *mouse = SDL_GetMouse();
192 if (!SDL_UpdateMouseFocus(window, x, y, mouse->buttonstate)) {
197 return SDL_PrivateSendMouseMotion(window, mouseID, relative, x, y);
201 SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
203 SDL_Mouse *mouse = SDL_GetMouse();
208 if (mouse->relative_mode_warp) {
209 int center_x = 0, center_y = 0;
210 SDL_GetWindowSize(window, ¢er_x, ¢er_y);
213 if (x == center_x && y == center_y) {
214 mouse->last_x = center_x;
215 mouse->last_y = center_y;
218 SDL_WarpMouseInWindow(window, center_x, center_y);
224 x = (mouse->last_x + xrel);
225 y = (mouse->last_y + yrel);
227 xrel = x - mouse->last_x;
228 yrel = y - mouse->last_y;
231 /* Drop events that don't change state */
232 if (!xrel && !yrel) {
234 printf("Mouse event didn't change state - dropped!\n");
239 /* Update internal mouse coordinates */
240 if (!mouse->relative_mode) {
248 /* make sure that the pointers find themselves inside the windows,
249 unless we have the mouse captured. */
250 if (window && ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0)) {
251 int x_max = 0, y_max = 0;
253 // !!! FIXME: shouldn't this be (window) instead of (mouse->focus)?
254 SDL_GetWindowSize(mouse->focus, &x_max, &y_max);
258 if (mouse->x > x_max) {
265 if (mouse->y > y_max) {
273 mouse->xdelta += xrel;
274 mouse->ydelta += yrel;
276 /* Move the mouse cursor, if needed */
277 if (mouse->cursor_shown && !mouse->relative_mode &&
278 mouse->MoveCursor && mouse->cur_cursor) {
279 mouse->MoveCursor(mouse->cur_cursor);
282 /* Post the event, if desired */
284 if (SDL_GetEventState(SDL_MOUSEMOTION) == SDL_ENABLE) {
286 event.motion.type = SDL_MOUSEMOTION;
287 event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
288 event.motion.which = mouseID;
289 event.motion.state = mouse->buttonstate;
290 event.motion.x = mouse->x;
291 event.motion.y = mouse->y;
292 event.motion.xrel = xrel;
293 event.motion.yrel = yrel;
294 posted = (SDL_PushEvent(&event) > 0);
297 mouse->last_x = mouse->x;
298 mouse->last_y = mouse->y;
300 /* Use unclamped values if we're getting events outside the window */
307 static SDL_MouseClickState *GetMouseClickState(SDL_Mouse *mouse, Uint8 button)
309 if (button >= mouse->num_clickstates) {
310 int i, count = button + 1;
311 SDL_MouseClickState *clickstate = (SDL_MouseClickState *)SDL_realloc(mouse->clickstate, count * sizeof(*mouse->clickstate));
315 mouse->clickstate = clickstate;
317 for (i = mouse->num_clickstates; i < count; ++i) {
318 SDL_zero(mouse->clickstate[i]);
320 mouse->num_clickstates = count;
322 return &mouse->clickstate[button];
326 SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
328 SDL_Mouse *mouse = SDL_GetMouse();
331 Uint32 buttonstate = mouse->buttonstate;
332 SDL_MouseClickState *clickstate = GetMouseClickState(mouse, button);
335 /* Figure out which event to perform */
338 type = SDL_MOUSEBUTTONDOWN;
339 buttonstate |= SDL_BUTTON(button);
342 type = SDL_MOUSEBUTTONUP;
343 buttonstate &= ~SDL_BUTTON(button);
346 /* Invalid state -- bail */
350 /* We do this after calculating buttonstate so button presses gain focus */
351 if (window && state == SDL_PRESSED) {
352 SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
355 if (buttonstate == mouse->buttonstate) {
356 /* Ignore this event, no state change */
359 mouse->buttonstate = buttonstate;
362 if (state == SDL_PRESSED) {
363 Uint32 now = SDL_GetTicks();
365 if (SDL_TICKS_PASSED(now, clickstate->last_timestamp + SDL_double_click_time) ||
366 SDL_abs(mouse->x - clickstate->last_x) > SDL_double_click_radius ||
367 SDL_abs(mouse->y - clickstate->last_y) > SDL_double_click_radius) {
368 clickstate->click_count = 0;
370 clickstate->last_timestamp = now;
371 clickstate->last_x = mouse->x;
372 clickstate->last_y = mouse->y;
373 if (clickstate->click_count < 255) {
374 ++clickstate->click_count;
377 click_count = clickstate->click_count;
382 /* Post the event, if desired */
384 if (SDL_GetEventState(type) == SDL_ENABLE) {
387 event.button.windowID = mouse->focus ? mouse->focus->id : 0;
388 event.button.which = mouseID;
389 event.button.state = state;
390 event.button.button = button;
391 event.button.clicks = click_count;
392 event.button.x = mouse->x;
393 event.button.y = mouse->y;
394 posted = (SDL_PushEvent(&event) > 0);
397 /* We do this after dispatching event so button releases can lose focus */
398 if (window && state == SDL_RELEASED) {
399 SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
406 SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, int x, int y, SDL_MouseWheelDirection direction)
408 SDL_Mouse *mouse = SDL_GetMouse();
412 SDL_SetMouseFocus(window);
419 /* Post the event, if desired */
421 if (SDL_GetEventState(SDL_MOUSEWHEEL) == SDL_ENABLE) {
423 event.type = SDL_MOUSEWHEEL;
424 event.wheel.windowID = mouse->focus ? mouse->focus->id : 0;
425 event.wheel.which = mouseID;
428 event.wheel.direction = (Uint32)direction;
429 posted = (SDL_PushEvent(&event) > 0);
437 SDL_Cursor *cursor, *next;
438 SDL_Mouse *mouse = SDL_GetMouse();
440 if (mouse->CaptureMouse) {
441 SDL_CaptureMouse(SDL_FALSE);
443 SDL_SetRelativeMouseMode(SDL_FALSE);
446 cursor = mouse->cursors;
449 SDL_FreeCursor(cursor);
453 if (mouse->def_cursor && mouse->FreeCursor) {
454 mouse->FreeCursor(mouse->def_cursor);
457 if (mouse->clickstate) {
458 SDL_free(mouse->clickstate);
465 SDL_GetMouseState(int *x, int *y)
467 SDL_Mouse *mouse = SDL_GetMouse();
475 return mouse->buttonstate;
479 SDL_GetRelativeMouseState(int *x, int *y)
481 SDL_Mouse *mouse = SDL_GetMouse();
491 return mouse->buttonstate;
495 SDL_GetGlobalMouseState(int *x, int *y)
497 SDL_Mouse *mouse = SDL_GetMouse();
500 /* make sure these are never NULL for the backend implementations... */
510 if (!mouse->GetGlobalMouseState) {
511 SDL_assert(0 && "This should really be implemented for every target.");
515 return mouse->GetGlobalMouseState(x, y);
519 SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
521 SDL_Mouse *mouse = SDL_GetMouse();
523 if (window == NULL) {
524 window = mouse->focus;
527 if (window == NULL) {
531 if (mouse->WarpMouse) {
532 mouse->WarpMouse(window, x, y);
534 SDL_SendMouseMotion(window, mouse->mouseID, 0, x, y);
539 SDL_WarpMouseGlobal(int x, int y)
541 SDL_Mouse *mouse = SDL_GetMouse();
543 if (mouse->WarpMouseGlobal) {
544 return mouse->WarpMouseGlobal(x, y);
547 return SDL_Unsupported();
551 ShouldUseRelativeModeWarp(SDL_Mouse *mouse)
555 if (!mouse->SetRelativeMouseMode) {
559 hint = SDL_GetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP);
571 SDL_SetRelativeMouseMode(SDL_bool enabled)
573 SDL_Mouse *mouse = SDL_GetMouse();
574 SDL_Window *focusWindow = SDL_GetKeyboardFocus();
576 if (enabled == mouse->relative_mode) {
580 if (enabled && focusWindow) {
581 /* Center it in the focused window to prevent clicks from going through
582 * to background windows.
584 SDL_SetMouseFocus(focusWindow);
585 SDL_WarpMouseInWindow(focusWindow, focusWindow->w/2, focusWindow->h/2);
588 /* Set the relative mode */
589 if (!enabled && mouse->relative_mode_warp) {
590 mouse->relative_mode_warp = SDL_FALSE;
591 } else if (enabled && ShouldUseRelativeModeWarp(mouse)) {
592 mouse->relative_mode_warp = SDL_TRUE;
593 } else if (mouse->SetRelativeMouseMode(enabled) < 0) {
595 /* Fall back to warp mode if native relative mode failed */
596 mouse->relative_mode_warp = SDL_TRUE;
599 mouse->relative_mode = enabled;
602 SDL_UpdateWindowGrab(mouse->focus);
604 /* Put the cursor back to where the application expects it */
606 SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y);
610 /* Flush pending mouse motion - ideally we would pump events, but that's not always safe */
611 SDL_FlushEvent(SDL_MOUSEMOTION);
613 /* Update cursor visibility */
620 SDL_GetRelativeMouseMode()
622 SDL_Mouse *mouse = SDL_GetMouse();
624 return mouse->relative_mode;
628 SDL_CaptureMouse(SDL_bool enabled)
630 SDL_Mouse *mouse = SDL_GetMouse();
631 SDL_Window *focusWindow;
634 if (!mouse->CaptureMouse) {
635 return SDL_Unsupported();
638 focusWindow = SDL_GetKeyboardFocus();
640 isCaptured = focusWindow && (focusWindow->flags & SDL_WINDOW_MOUSE_CAPTURE);
641 if (isCaptured == enabled) {
642 return 0; /* already done! */
647 return SDL_SetError("No window has focus");
648 } else if (mouse->CaptureMouse(focusWindow) == -1) {
649 return -1; /* CaptureMouse() should call SetError */
651 focusWindow->flags |= SDL_WINDOW_MOUSE_CAPTURE;
653 if (mouse->CaptureMouse(NULL) == -1) {
654 return -1; /* CaptureMouse() should call SetError */
656 focusWindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
663 SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
664 int w, int h, int hot_x, int hot_y)
666 SDL_Surface *surface;
670 Uint8 datab = 0, maskb = 0;
671 const Uint32 black = 0xFF000000;
672 const Uint32 white = 0xFFFFFFFF;
673 const Uint32 transparent = 0x00000000;
675 /* Make sure the width is a multiple of 8 */
678 /* Create the surface from a bitmap */
679 surface = SDL_CreateRGBSurface(0, w, h, 32,
687 for (y = 0; y < h; ++y) {
688 pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
689 for (x = 0; x < w; ++x) {
695 *pixel++ = (datab & 0x80) ? black : white;
697 *pixel++ = (datab & 0x80) ? black : transparent;
704 cursor = SDL_CreateColorCursor(surface, hot_x, hot_y);
706 SDL_FreeSurface(surface);
712 SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y)
714 SDL_Mouse *mouse = SDL_GetMouse();
715 SDL_Surface *temp = NULL;
719 SDL_SetError("Passed NULL cursor surface");
723 if (!mouse->CreateCursor) {
724 SDL_SetError("Cursors are not currently supported");
728 /* Sanity check the hot spot */
729 if ((hot_x < 0) || (hot_y < 0) ||
730 (hot_x >= surface->w) || (hot_y >= surface->h)) {
731 SDL_SetError("Cursor hot spot doesn't lie within cursor");
735 if (surface->format->format != SDL_PIXELFORMAT_ARGB8888) {
736 temp = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0);
743 cursor = mouse->CreateCursor(surface, hot_x, hot_y);
745 cursor->next = mouse->cursors;
746 mouse->cursors = cursor;
749 SDL_FreeSurface(temp);
755 SDL_CreateSystemCursor(SDL_SystemCursor id)
757 SDL_Mouse *mouse = SDL_GetMouse();
760 if (!mouse->CreateSystemCursor) {
761 SDL_SetError("CreateSystemCursor is not currently supported");
765 cursor = mouse->CreateSystemCursor(id);
767 cursor->next = mouse->cursors;
768 mouse->cursors = cursor;
774 /* SDL_SetCursor(NULL) can be used to force the cursor redraw,
775 if this is desired for any reason. This is used when setting
776 the video mode and when the SDL window gains the mouse focus.
779 SDL_SetCursor(SDL_Cursor * cursor)
781 SDL_Mouse *mouse = SDL_GetMouse();
783 /* Set the new cursor */
785 /* Make sure the cursor is still valid for this mouse */
786 if (cursor != mouse->def_cursor) {
788 for (found = mouse->cursors; found; found = found->next) {
789 if (found == cursor) {
794 SDL_SetError("Cursor not associated with the current mouse");
798 mouse->cur_cursor = cursor;
801 cursor = mouse->cur_cursor;
803 cursor = mouse->def_cursor;
807 if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
808 if (mouse->ShowCursor) {
809 mouse->ShowCursor(cursor);
812 if (mouse->ShowCursor) {
813 mouse->ShowCursor(NULL);
821 SDL_Mouse *mouse = SDL_GetMouse();
826 return mouse->cur_cursor;
830 SDL_GetDefaultCursor(void)
832 SDL_Mouse *mouse = SDL_GetMouse();
837 return mouse->def_cursor;
841 SDL_FreeCursor(SDL_Cursor * cursor)
843 SDL_Mouse *mouse = SDL_GetMouse();
844 SDL_Cursor *curr, *prev;
850 if (cursor == mouse->def_cursor) {
853 if (cursor == mouse->cur_cursor) {
854 SDL_SetCursor(mouse->def_cursor);
857 for (prev = NULL, curr = mouse->cursors; curr;
858 prev = curr, curr = curr->next) {
859 if (curr == cursor) {
861 prev->next = curr->next;
863 mouse->cursors = curr->next;
866 if (mouse->FreeCursor) {
867 mouse->FreeCursor(curr);
875 SDL_ShowCursor(int toggle)
877 SDL_Mouse *mouse = SDL_GetMouse();
884 shown = mouse->cursor_shown;
887 mouse->cursor_shown = SDL_TRUE;
889 mouse->cursor_shown = SDL_FALSE;
891 if (mouse->cursor_shown != shown) {
898 /* vi: set ts=4 sw=4 expandtab: */