Reset the mouse button state when losing mouse focus.

Implemented mouse focus handling entirely using mouse motion events, with SetCapture() semantics, as long as the windowing system continues to provide mouse events.
This commit is contained in:
Sam Lantinga 2012-11-08 02:26:40 -08:00
parent ea720974f5
commit 138cd7fa11
4 changed files with 115 additions and 69 deletions

View file

@ -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;
@ -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)
{
@ -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);
@ -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
@ -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;
@ -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;
@ -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;
}
@ -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;
}
@ -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) {
@ -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;
}

View file

@ -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;
@ -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;
@ -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);
}
@ -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);
}

View file

@ -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;

View file

@ -200,10 +200,8 @@ static __inline__ void ConvertNSRect(NSRect *r)
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);
}
}
@ -309,38 +307,6 @@ static __inline__ void ConvertNSRect(NSRect *r)
[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();
@ -357,15 +323,26 @@ static __inline__ void ConvertNSRect(NSRect *r)
y = (int)(window->h - point.y);
if (x < 0 || x >= window->w || y < 0 || y >= window->h) {
if (SDL_GetMouseFocus() == window) {
[self mouseExited: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);
}
} else {
if (SDL_GetMouseFocus() != window) {
[self mouseEntered:theEvent];
}
SDL_SendMouseMotion(window, 0, x, y);
}
SDL_SendMouseMotion(window, 0, x, y);
}
- (void)mouseDragged:(NSEvent *)theEvent