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:
parent
ea720974f5
commit
138cd7fa11
4 changed files with 115 additions and 69 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue