Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

Commit

Permalink
Reset the mouse button state when losing mouse focus.
Browse files Browse the repository at this point in the history
Implemented mouse focus handling entirely using mouse motion events, with SetCapture() semantics, as long as the windowing system continues to provide mouse events.
  • Loading branch information
slouken committed Nov 8, 2012
1 parent 6c83a63 commit 3050f6f
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 69 deletions.
113 changes: 92 additions & 21 deletions src/events/SDL_mouse.c
Expand Up @@ -22,11 +22,13 @@

/* General mouse handling code for SDL */

#include "SDL_assert.h"
#include "SDL_events.h"
#include "SDL_events_c.h"
#include "default_cursor.h"
#include "../video/SDL_sysvideo.h"

/*#define DEBUG_MOUSE*/

/* The mouse state */
static SDL_Mouse SDL_mouse;
Expand Down Expand Up @@ -68,6 +70,23 @@ SDL_GetMouseFocus(void)
return mouse->focus;
}

void
SDL_ResetMouse(void)
{
SDL_Mouse *mouse = SDL_GetMouse();
Uint8 i;

#ifdef DEBUG_MOUSE
printf("Resetting mouse\n");
#endif
for (i = 1; i <= sizeof(mouse->buttonstate)*8; ++i) {
if (mouse->buttonstate & SDL_BUTTON(i)) {
SDL_SendMouseButton(mouse->focus, SDL_RELEASED, i);
}
}
SDL_assert(mouse->buttonstate == 0);
}

void
SDL_SetMouseFocus(SDL_Window * window)
{
Expand All @@ -77,6 +96,11 @@ SDL_SetMouseFocus(SDL_Window * window)
return;
}

if (mouse->focus && !window) {
/* We won't get anymore mouse messages, so reset mouse state */
SDL_ResetMouse();
}

/* See if the current window has lost focus */
if (mouse->focus) {
SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
Expand All @@ -87,6 +111,45 @@ SDL_SetMouseFocus(SDL_Window * window)
if (mouse->focus) {
SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
}

/* Update cursor visibility */
SDL_SetCursor(NULL);
}

/* Check to see if we need to synthesize focus events */
static SDL_bool
SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint8 buttonstate)
{
SDL_Mouse *mouse = SDL_GetMouse();
int w, h;
SDL_bool inWindow;

SDL_GetWindowSize(window, &w, &h);
if (x < 0 || y < 0 || x >= w || y >= h) {
inWindow = SDL_FALSE;
} else {
inWindow = SDL_TRUE;
}
if (!inWindow && !buttonstate) {
if (window == mouse->focus) {
#ifdef DEBUG_MOUSE
printf("Mouse left window, synthesizing focus lost event\n");
#endif
SDL_SetMouseFocus(NULL);
}
return SDL_FALSE;
}

if (window != mouse->focus) {
mouse->last_x = x;
mouse->last_y = y;

#ifdef DEBUG_MOUSE
printf("Mouse entered window, synthesizing focus gain event\n");
#endif
SDL_SetMouseFocus(window);
}
return SDL_TRUE;
}

int
Expand All @@ -98,11 +161,13 @@ SDL_SendMouseMotion(SDL_Window * window, int relative, int x, int y)
int yrel;
int x_max = 0, y_max = 0;

if (window) {
SDL_SetMouseFocus(window);
if (window && !relative) {
if (!SDL_UpdateMouseFocus(window, x, y, mouse->buttonstate)) {
return 0;
}
}

/* the relative motion is calculated regarding the system cursor last position */
/* relative motion is calculated regarding the system cursor last position */
if (relative) {
xrel = x;
yrel = y;
Expand All @@ -115,7 +180,7 @@ SDL_SendMouseMotion(SDL_Window * window, int relative, int x, int y)

/* Drop events that don't change state */
if (!xrel && !yrel) {
#if 0
#ifdef DEBUG_MOUSE
printf("Mouse event didn't change state - dropped!\n");
#endif
return 0;
Expand All @@ -135,7 +200,6 @@ SDL_SendMouseMotion(SDL_Window * window, int relative, int x, int y)
--y_max;

/* make sure that the pointers find themselves inside the windows */
/* only check if mouse->xmax is set ! */
if (mouse->x > x_max) {
mouse->x = x_max;
}
Expand Down Expand Up @@ -174,8 +238,9 @@ SDL_SendMouseMotion(SDL_Window * window, int relative, int x, int y)
event.motion.yrel = yrel;
posted = (SDL_PushEvent(&event) > 0);
}
mouse->last_x = mouse->x;
mouse->last_y = mouse->y;
/* Use unclamped values if we're getting events outside the window */
mouse->last_x = x;
mouse->last_y = y;
return posted;
}

Expand All @@ -185,34 +250,34 @@ SDL_SendMouseButton(SDL_Window * window, Uint8 state, Uint8 button)
SDL_Mouse *mouse = SDL_GetMouse();
int posted;
Uint32 type;

if (window) {
SDL_SetMouseFocus(window);
}
Uint8 buttonstate = mouse->buttonstate;

/* Figure out which event to perform */
switch (state) {
case SDL_PRESSED:
if (mouse->buttonstate & SDL_BUTTON(button)) {
/* Ignore this event, no state change */
return 0;
}
type = SDL_MOUSEBUTTONDOWN;
mouse->buttonstate |= SDL_BUTTON(button);
buttonstate |= SDL_BUTTON(button);
break;
case SDL_RELEASED:
if (!(mouse->buttonstate & SDL_BUTTON(button))) {
/* Ignore this event, no state change */
return 0;
}
type = SDL_MOUSEBUTTONUP;
mouse->buttonstate &= ~SDL_BUTTON(button);
buttonstate &= ~SDL_BUTTON(button);
break;
default:
/* Invalid state -- bail */
return 0;
}

/* We do this after calculating buttonstate so button presses gain focus */
if (window && state == SDL_PRESSED) {
SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
}

if (buttonstate == mouse->buttonstate) {
/* Ignore this event, no state change */
return 0;
}
mouse->buttonstate = buttonstate;

/* Post the event, if desired */
posted = 0;
if (SDL_GetEventState(type) == SDL_ENABLE) {
Expand All @@ -225,6 +290,12 @@ SDL_SendMouseButton(SDL_Window * window, Uint8 state, Uint8 button)
event.button.windowID = mouse->focus ? mouse->focus->id : 0;
posted = (SDL_PushEvent(&event) > 0);
}

/* We do this after dispatching event so button releases can lose focus */
if (window && state == SDL_RELEASED) {
SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
}

return posted;
}

Expand Down
8 changes: 4 additions & 4 deletions src/video/SDL_bmp.c
Expand Up @@ -51,7 +51,7 @@ SDL_Surface *
SDL_LoadBMP_RW(SDL_RWops * src, int freesrc)
{
SDL_bool was_error;
long fp_offset = 0;
Sint64 fp_offset = 0;
int bmpPitch;
int i, pad;
SDL_Surface *surface;
Expand Down Expand Up @@ -371,7 +371,7 @@ SDL_LoadBMP_RW(SDL_RWops * src, int freesrc)
int
SDL_SaveBMP_RW(SDL_Surface * saveme, SDL_RWops * dst, int freedst)
{
long fp_offset;
Sint64 fp_offset;
int i, pad;
SDL_Surface *surface;
Uint8 *bits;
Expand Down Expand Up @@ -515,7 +515,7 @@ SDL_SaveBMP_RW(SDL_Surface * saveme, SDL_RWops * dst, int freedst)
}

/* Write the bitmap offset */
bfOffBits = SDL_RWtell(dst) - fp_offset;
bfOffBits = (Uint32)(SDL_RWtell(dst) - fp_offset);
if (SDL_RWseek(dst, fp_offset + 10, RW_SEEK_SET) < 0) {
SDL_Error(SDL_EFSEEK);
}
Expand All @@ -542,7 +542,7 @@ SDL_SaveBMP_RW(SDL_Surface * saveme, SDL_RWops * dst, int freedst)
}

/* Write the BMP file size */
bfSize = SDL_RWtell(dst) - fp_offset;
bfSize = (Uint32)(SDL_RWtell(dst) - fp_offset);
if (SDL_RWseek(dst, fp_offset + 2, RW_SEEK_SET) < 0) {
SDL_Error(SDL_EFSEEK);
}
Expand Down
2 changes: 0 additions & 2 deletions src/video/cocoa/SDL_cocoawindow.h
Expand Up @@ -56,8 +56,6 @@ typedef struct SDL_WindowData SDL_WindowData;
-(void) mouseUp:(NSEvent *) theEvent;
-(void) rightMouseUp:(NSEvent *) theEvent;
-(void) otherMouseUp:(NSEvent *) theEvent;
-(void) mouseEntered:(NSEvent *)theEvent;
-(void) mouseExited:(NSEvent *)theEvent;
-(void) mouseMoved:(NSEvent *) theEvent;
-(void) mouseDragged:(NSEvent *) theEvent;
-(void) rightMouseDragged:(NSEvent *) theEvent;
Expand Down
61 changes: 19 additions & 42 deletions src/video/cocoa/SDL_cocoawindow.m
Expand Up @@ -200,10 +200,8 @@ - (void)windowDidBecomeKey:(NSNotification *)aNotification
y = (int)(window->h - point.y);

if (x >= 0 && x < window->w && y >= 0 && y < window->h) {
if (SDL_GetMouseFocus() != window) {
[self mouseEntered:nil];
}
SDL_SendMouseMotion(window, 0, x, y);
SDL_SetCursor(NULL);
}
}

Expand Down Expand Up @@ -309,38 +307,6 @@ - (void)otherMouseUp:(NSEvent *)theEvent
[self mouseUp:theEvent];
}

- (void)mouseEntered:(NSEvent *)theEvent
{
SDL_SetMouseFocus(_data->window);

SDL_SetCursor(NULL);
}

- (void)mouseExited:(NSEvent *)theEvent
{
SDL_Window *window = _data->window;

if (SDL_GetMouseFocus() == window) {
if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
int x, y;
NSPoint point;
CGPoint cgpoint;

point = [theEvent locationInWindow];
point.y = window->h - point.y;

SDL_SendMouseMotion(window, 0, (int)point.x, (int)point.y);
SDL_GetMouseState(&x, &y);
cgpoint.x = window->x + x;
cgpoint.y = window->y + y;
CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
} else {
SDL_SetMouseFocus(NULL);
SDL_SetCursor(NULL);
}
}
}

- (void)mouseMoved:(NSEvent *)theEvent
{
SDL_Mouse *mouse = SDL_GetMouse();
Expand All @@ -357,15 +323,26 @@ - (void)mouseMoved:(NSEvent *)theEvent
y = (int)(window->h - point.y);

if (x < 0 || x >= window->w || y < 0 || y >= window->h) {
if (SDL_GetMouseFocus() == window) {
[self mouseExited:theEvent];
}
} else {
if (SDL_GetMouseFocus() != window) {
[self mouseEntered:theEvent];
if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
CGPoint cgpoint;

if (x < 0) {
x = 0;
} else if (x >= window->w) {
x = window->w - 1;
}
if (y < 0) {
y = 0;
} else if (y >= window->h) {
y = window->h - 1;
}

cgpoint.x = window->x + x;
cgpoint.y = window->y + y;
CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
}
SDL_SendMouseMotion(window, 0, x, y);
}
SDL_SendMouseMotion(window, 0, x, y);
}

- (void)mouseDragged:(NSEvent *)theEvent
Expand Down

0 comments on commit 3050f6f

Please sign in to comment.