Fixed the responder chain for event handling, the listener fully handles mouse events - even in fullscreen mode.
The only reason we need a custom view is to handle right mouse down.
Implemented mouse grabbing, although it's kind of clunky right now. I'll be adding a relative mode that will be smoother soon.
--- a/src/events/SDL_mouse.c Sun Feb 20 23:51:59 2011 -0800
+++ b/src/events/SDL_mouse.c Mon Feb 21 10:50:53 2011 -0800
@@ -29,43 +29,7 @@
#include "../video/SDL_sysvideo.h"
-/* Global mouse information */
-
-typedef struct SDL_Mouse SDL_Mouse;
-
-struct SDL_Mouse
-{
- /* Create a cursor from a surface */
- SDL_Cursor *(*CreateCursor) (SDL_Surface * surface, int hot_x, int hot_y);
-
- /* Show the specified cursor, or hide if cursor is NULL */
- int (*ShowCursor) (SDL_Cursor * cursor);
-
- /* This is called when a mouse motion event occurs */
- void (*MoveCursor) (SDL_Cursor * cursor);
-
- /* Free a window manager cursor */
- void (*FreeCursor) (SDL_Cursor * cursor);
-
- /* Warp the mouse to (x,y) */
- void (*WarpMouse) (SDL_Mouse * mouse, SDL_Window * window, int x, int y);
-
- /* Data common to all mice */
- SDL_Window *focus;
- int x;
- int y;
- int xdelta;
- int ydelta;
- int last_x, last_y; /* the last reported x and y coordinates */
- Uint8 buttonstate;
- SDL_bool relative_mode;
-
- SDL_Cursor *cursors;
- SDL_Cursor *def_cursor;
- SDL_Cursor *cur_cursor;
- SDL_bool cursor_shown;
-};
-
+/* The mouse state */
static SDL_Mouse SDL_mouse;
@@ -76,6 +40,12 @@
return (0);
}
+SDL_Mouse *
+SDL_GetMouse(void)
+{
+ return &SDL_mouse;
+}
+
void
SDL_ResetMouse(void)
{
@@ -85,7 +55,7 @@
SDL_Window *
SDL_GetMouseFocus(void)
{
- SDL_Mouse *mouse = &SDL_mouse;
+ SDL_Mouse *mouse = SDL_GetMouse();
return mouse->focus;
}
@@ -93,7 +63,7 @@
void
SDL_SetMouseFocus(SDL_Window * window)
{
- SDL_Mouse *mouse = &SDL_mouse;
+ SDL_Mouse *mouse = SDL_GetMouse();
if (mouse->focus == window) {
return;
@@ -114,7 +84,7 @@
int
SDL_SendMouseMotion(SDL_Window * window, int relative, int x, int y)
{
- SDL_Mouse *mouse = &SDL_mouse;
+ SDL_Mouse *mouse = SDL_GetMouse();
int posted;
int xrel;
int yrel;
@@ -204,7 +174,7 @@
int
SDL_SendMouseButton(SDL_Window * window, Uint8 state, Uint8 button)
{
- SDL_Mouse *mouse = &SDL_mouse;
+ SDL_Mouse *mouse = SDL_GetMouse();
int posted;
Uint32 type;
@@ -253,7 +223,7 @@
int
SDL_SendMouseWheel(SDL_Window * window, int x, int y)
{
- SDL_Mouse *mouse = &SDL_mouse;
+ SDL_Mouse *mouse = SDL_GetMouse();
int posted;
if (window) {
@@ -285,7 +255,7 @@
Uint8
SDL_GetMouseState(int *x, int *y)
{
- SDL_Mouse *mouse = &SDL_mouse;
+ SDL_Mouse *mouse = SDL_GetMouse();
if (x) {
*x = mouse->x;
@@ -299,7 +269,7 @@
Uint8
SDL_GetRelativeMouseState(int *x, int *y)
{
- SDL_Mouse *mouse = &SDL_mouse;
+ SDL_Mouse *mouse = SDL_GetMouse();
if (x) {
*x = mouse->xdelta;
@@ -315,10 +285,10 @@
void
SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
{
- SDL_Mouse *mouse = &SDL_mouse;
+ SDL_Mouse *mouse = SDL_GetMouse();
if (mouse->WarpMouse) {
- mouse->WarpMouse(mouse, window, x, y);
+ mouse->WarpMouse(window, x, y);
} else {
SDL_SendMouseMotion(window, 0, x, y);
}
@@ -327,7 +297,7 @@
int
SDL_SetRelativeMouseMode(SDL_bool enabled)
{
- SDL_Mouse *mouse = &SDL_mouse;
+ SDL_Mouse *mouse = SDL_GetMouse();
/* Flush pending mouse motion */
SDL_FlushEvent(SDL_MOUSEMOTION);
@@ -349,7 +319,7 @@
SDL_bool
SDL_GetRelativeMouseMode()
{
- SDL_Mouse *mouse = &SDL_mouse;
+ SDL_Mouse *mouse = SDL_GetMouse();
return mouse->relative_mode;
}
@@ -358,7 +328,7 @@
SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
int w, int h, int hot_x, int hot_y)
{
- SDL_Mouse *mouse = &SDL_mouse;
+ SDL_Mouse *mouse = SDL_GetMouse();
SDL_Surface *surface;
SDL_Cursor *cursor;
int x, y;
@@ -424,7 +394,7 @@
void
SDL_SetCursor(SDL_Cursor * cursor)
{
- SDL_Mouse *mouse = &SDL_mouse;
+ SDL_Mouse *mouse = SDL_GetMouse();
/* Set the new cursor */
if (cursor) {
@@ -458,7 +428,7 @@
SDL_Cursor *
SDL_GetCursor(void)
{
- SDL_Mouse *mouse = &SDL_mouse;
+ SDL_Mouse *mouse = SDL_GetMouse();
if (!mouse) {
return NULL;
@@ -469,7 +439,7 @@
void
SDL_FreeCursor(SDL_Cursor * cursor)
{
- SDL_Mouse *mouse = &SDL_mouse;
+ SDL_Mouse *mouse = SDL_GetMouse();
SDL_Cursor *curr, *prev;
if (!cursor) {
@@ -503,7 +473,7 @@
int
SDL_ShowCursor(int toggle)
{
- SDL_Mouse *mouse = &SDL_mouse;
+ SDL_Mouse *mouse = SDL_GetMouse();
SDL_bool shown;
if (!mouse) {
--- a/src/events/SDL_mouse_c.h Sun Feb 20 23:51:59 2011 -0800
+++ b/src/events/SDL_mouse_c.h Mon Feb 21 10:50:53 2011 -0800
@@ -24,15 +24,54 @@
#ifndef _SDL_mouse_c_h
#define _SDL_mouse_c_h
+#include "SDL_mouse.h"
+
struct SDL_Cursor
{
struct SDL_Cursor *next;
void *driverdata;
};
+typedef struct
+{
+ /* Create a cursor from a surface */
+ SDL_Cursor *(*CreateCursor) (SDL_Surface * surface, int hot_x, int hot_y);
+
+ /* Show the specified cursor, or hide if cursor is NULL */
+ int (*ShowCursor) (SDL_Cursor * cursor);
+
+ /* This is called when a mouse motion event occurs */
+ void (*MoveCursor) (SDL_Cursor * cursor);
+
+ /* Free a window manager cursor */
+ void (*FreeCursor) (SDL_Cursor * cursor);
+
+ /* Warp the mouse to (x,y) */
+ void (*WarpMouse) (SDL_Window * window, int x, int y);
+
+ /* Data common to all mice */
+ SDL_Window *focus;
+ int x;
+ int y;
+ int xdelta;
+ int ydelta;
+ int last_x, last_y; /* the last reported x and y coordinates */
+ Uint8 buttonstate;
+ SDL_bool relative_mode;
+
+ SDL_Cursor *cursors;
+ SDL_Cursor *def_cursor;
+ SDL_Cursor *cur_cursor;
+ SDL_bool cursor_shown;
+} SDL_Mouse;
+
+
/* Initialize the mouse subsystem */
extern int SDL_MouseInit(void);
+/* Get the mouse state structure */
+SDL_Mouse *SDL_GetMouse(void);
+
/* Clear the mouse state */
extern void SDL_ResetMouse(void);
--- a/src/video/cocoa/SDL_cocoamouse.m Sun Feb 20 23:51:59 2011 -0800
+++ b/src/video/cocoa/SDL_cocoamouse.m Mon Feb 21 10:50:53 2011 -0800
@@ -49,62 +49,7 @@
void
Cocoa_HandleMouseEvent(_THIS, NSEvent *event)
{
- int i;
- NSPoint point = { 0, 0 };
- SDL_Window *window;
- SDL_Window *focus = SDL_GetMouseFocus();
-
- /* See if there are any fullscreen windows that might handle this event */
- window = NULL;
- for (i = 0; i < _this->num_displays; ++i) {
- SDL_VideoDisplay *display = &_this->displays[i];
- SDL_Window *candidate = display->fullscreen_window;
-
- if (candidate) {
- SDL_Rect bounds;
-
- Cocoa_GetDisplayBounds(_this, display, &bounds);
- point = [NSEvent mouseLocation];
- point.x = point.x - bounds.x;
- point.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - point.y - bounds.y;
- if ((point.x >= 0 && point.x < candidate->w) &&
- (point.y >= 0 && point.y < candidate->h)) {
- /* This is it! */
- window = candidate;
- break;
- } else if (candidate == focus) {
- SDL_SetMouseFocus(NULL);
- }
- }
- }
-
- if (!window) {
- return;
- }
-
- switch ([event type]) {
- case NSLeftMouseDown:
- case NSOtherMouseDown:
- case NSRightMouseDown:
- SDL_SendMouseButton(window, SDL_PRESSED, ConvertMouseButtonToSDL([event buttonNumber]));
- break;
- case NSLeftMouseUp:
- case NSOtherMouseUp:
- case NSRightMouseUp:
- SDL_SendMouseButton(window, SDL_RELEASED, ConvertMouseButtonToSDL([event buttonNumber]));
- break;
- case NSScrollWheel:
- Cocoa_HandleMouseWheel(window, event);
- break;
- case NSLeftMouseDragged:
- case NSRightMouseDragged:
- case NSOtherMouseDragged: /* usually middle mouse dragged */
- case NSMouseMoved:
- SDL_SendMouseMotion(window, 0, (int)point.x, (int)point.y);
- break;
- default: /* just to avoid compiler warnings */
- break;
- }
+ /* We're correctly using views even in fullscreen mode now */
}
void
--- a/src/video/cocoa/SDL_cocoawindow.h Sun Feb 20 23:51:59 2011 -0800
+++ b/src/video/cocoa/SDL_cocoawindow.h Mon Feb 21 10:50:53 2011 -0800
@@ -29,11 +29,7 @@
typedef struct SDL_WindowData SDL_WindowData;
/* *INDENT-OFF* */
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
-@interface Cocoa_WindowListener : NSResponder <NSWindowDelegate> {
-#else
@interface Cocoa_WindowListener : NSResponder {
-#endif
SDL_WindowData *_data;
}
@@ -59,6 +55,8 @@
-(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;
--- a/src/video/cocoa/SDL_cocoawindow.m Sun Feb 20 23:51:59 2011 -0800
+++ b/src/video/cocoa/SDL_cocoawindow.m Mon Feb 21 10:50:53 2011 -0800
@@ -41,54 +41,53 @@
- (void)listen:(SDL_WindowData *)data
{
NSNotificationCenter *center;
+ NSWindow *window = data->nswindow;
+ NSView *view = [window contentView];
_data = data;
center = [NSNotificationCenter defaultCenter];
- [_data->nswindow setNextResponder:self];
- if ([_data->nswindow delegate] != nil) {
- [center addObserver:self selector:@selector(windowDisExpose:) name:NSWindowDidExposeNotification object:_data->nswindow];
- [center addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:_data->nswindow];
- [center addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:_data->nswindow];
- [center addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:_data->nswindow];
- [center addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:_data->nswindow];
- [center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:_data->nswindow];
- [center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:_data->nswindow];
- } else {
- [_data->nswindow setDelegate:self];
- }
-// FIXME: Why doesn't this work?
-// [center addObserver:self selector:@selector(rightMouseDown:) name:[NSString stringWithCString:"rightMouseDown" encoding:NSUTF8StringEncoding] object:[_data->nswindow contentView]];
+ [center addObserver:self selector:@selector(windowDisExpose:) name:NSWindowDidExposeNotification object:window];
+ [center addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:window];
+ [center addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:window];
+ [center addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:window];
+ [center addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:window];
+ [center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:window];
+ [center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:window];
[center addObserver:self selector:@selector(windowDidHide:) name:NSApplicationDidHideNotification object:NSApp];
[center addObserver:self selector:@selector(windowDidUnhide:) name:NSApplicationDidUnhideNotification object:NSApp];
- [_data->nswindow setAcceptsMouseMovedEvents:YES];
+ [window setNextResponder:self];
+ [window setAcceptsMouseMovedEvents:YES];
+
+ [view setNextResponder:self];
+ [view addTrackingRect:[view visibleRect] owner:self userData:nil assumeInside:NO];
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
- [[_data->nswindow contentView] setAcceptsTouchEvents:YES];
+ [view setAcceptsTouchEvents:YES];
#endif
}
- (void)close
{
NSNotificationCenter *center;
+ NSWindow *window = _data->nswindow;
+ NSView *view = [window contentView];
center = [NSNotificationCenter defaultCenter];
- [_data->nswindow setNextResponder:nil];
- if ([_data->nswindow delegate] != self) {
- [center removeObserver:self name:NSWindowDidExposeNotification object:_data->nswindow];
- [center removeObserver:self name:NSWindowDidMoveNotification object:_data->nswindow];
- [center removeObserver:self name:NSWindowDidResizeNotification object:_data->nswindow];
- [center removeObserver:self name:NSWindowDidMiniaturizeNotification object:_data->nswindow];
- [center removeObserver:self name:NSWindowDidDeminiaturizeNotification object:_data->nswindow];
- [center removeObserver:self name:NSWindowDidBecomeKeyNotification object:_data->nswindow];
- [center removeObserver:self name:NSWindowDidResignKeyNotification object:_data->nswindow];
- } else {
- [_data->nswindow setDelegate:nil];
- }
+ [center removeObserver:self name:NSWindowDidExposeNotification object:window];
+ [center removeObserver:self name:NSWindowDidMoveNotification object:window];
+ [center removeObserver:self name:NSWindowDidResizeNotification object:window];
+ [center removeObserver:self name:NSWindowDidMiniaturizeNotification object:window];
+ [center removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window];
+ [center removeObserver:self name:NSWindowDidBecomeKeyNotification object:window];
+ [center removeObserver:self name:NSWindowDidResignKeyNotification object:window];
[center removeObserver:self name:NSApplicationDidHideNotification object:NSApp];
[center removeObserver:self name:NSApplicationDidUnhideNotification object:NSApp];
+
+ [window setNextResponder:nil];
+ [view setNextResponder:nil];
}
- (BOOL)windowShouldClose:(id)sender
@@ -141,11 +140,10 @@
SDL_SetKeyboardFocus(window);
/* If we just gained focus we need the updated mouse position */
- if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
+ if (SDL_GetMouseFocus() == window) {
NSPoint point;
point = [NSEvent mouseLocation];
point = [_data->nswindow convertScreenToBase:point];
- point = [[_data->nswindow contentView] convertPoint:point fromView:nil];
point.y = window->h - point.y;
SDL_SendMouseMotion(window, 0, (int)point.x, (int)point.y);
}
@@ -239,22 +237,51 @@
[self mouseUp:theEvent];
}
+- (void)mouseEntered:(NSEvent *)theEvent
+{
+ SDL_SetMouseFocus(_data->window);
+}
+
+- (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);
+ }
+ }
+}
+
- (void)mouseMoved:(NSEvent *)theEvent
{
SDL_Window *window = _data->window;
- NSPoint point;
- if (window->flags & SDL_WINDOW_FULLSCREEN)
+#ifdef RELATIVE_MOTION
+ if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
return;
+ }
+#endif
- point = [theEvent locationInWindow];
- point.y = window->h - point.y;
- if ( point.x < 0 || point.x >= window->w ||
- point.y < 0 || point.y >= window->h ) {
- if (SDL_GetMouseFocus() == window) {
- SDL_SetMouseFocus(NULL);
- }
- } else {
+ if (SDL_GetMouseFocus() == window) {
+ NSPoint point;
+
+ point = [theEvent locationInWindow];
+ point.y = window->h - point.y;
+
SDL_SendMouseMotion(window, 0, (int)point.x, (int)point.y);
}
}
@@ -386,28 +413,14 @@
}
@end
-@interface SDLView : NSView {
- Cocoa_WindowListener *listener;
-}
+@interface SDLView : NSView { }
@end
@implementation SDLView
-
-- (id) initWithFrame: (NSRect) rect
- listener: (Cocoa_WindowListener *) theListener
-{
- if (self = [super initWithFrame:rect]) {
- listener = theListener;
- }
-
- return self;
-}
-
- (void)rightMouseDown:(NSEvent *)theEvent
{
- [listener mouseDown:theEvent];
+ [[self nextResponder] rightMouseDown:theEvent];
}
-
@end
static unsigned int
@@ -452,16 +465,11 @@
/* Create an event listener for the window */
data->listener = [[Cocoa_WindowListener alloc] init];
- [data->listener listen:data];
/* Fill in the SDL window with the window data */
{
NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
- NSView *contentView = [[SDLView alloc] initWithFrame: rect
- listener: data->listener];
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
- [contentView setAcceptsTouchEvents:YES];
-#endif
+ NSView *contentView = [[SDLView alloc] initWithFrame:rect];
[nswindow setContentView: contentView];
[contentView release];
@@ -471,6 +479,10 @@
window->w = (int)rect.size.width;
window->h = (int)rect.size.height;
}
+
+ /* Set up the listener after we create the view */
+ [data->listener listen:data];
+
if ([nswindow isVisible]) {
window->flags |= SDL_WINDOW_SHOWN;
} else {
@@ -764,15 +776,35 @@
[pool release];
}
+NSPoint origin;
void
Cocoa_SetWindowGrab(_THIS, SDL_Window * window)
{
+#ifdef RELATIVE_MOTION
+ /* FIXME: work in progress
+ You set relative mode by using the following code in conjunction with
+ CGDisplayHideCursor(kCGDirectMainDisplay) and
+ CGDisplayShowCursor(kCGDirectMainDisplay)
+ */
if ((window->flags & SDL_WINDOW_INPUT_GRABBED) &&
(window->flags & SDL_WINDOW_INPUT_FOCUS)) {
- /* FIXME: Grab mouse */
+ CGAssociateMouseAndMouseCursorPosition(NO);
} else {
- /* FIXME: Release mouse */
+ CGAssociateMouseAndMouseCursorPosition(YES);
}
+#else
+ /* Move the cursor to the nearest point in the window */
+ if ((window->flags & SDL_WINDOW_INPUT_GRABBED) &&
+ (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
+ int x, y;
+ CGPoint cgpoint;
+
+ SDL_GetMouseState(&x, &y);
+ cgpoint.x = window->x + x;
+ cgpoint.y = window->y + y;
+ CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
+ }
+#endif
}
void