Commit fb889259 authored by Sam Lantinga's avatar Sam Lantinga

Darrell's fix for Quartz mouse motion

--HG--
extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%40436
parent 932fe2ac
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include "SDL_QuartzKeys.h" #include "SDL_QuartzKeys.h"
static SDLKey keymap[256]; static SDLKey keymap[256];
static unsigned int currentMods = 0; /* Current keyboard modifiers, to track modifier state */ static unsigned int currentMods = 0; /* Current keyboard modifiers, to track modifier state */
static int last_virtual_button = 0; /* Last virtual mouse button pressed */ static int last_virtual_button = 0; /* Last virtual mouse button pressed */
...@@ -305,9 +307,7 @@ static void QZ_DoDeactivate (_THIS) { ...@@ -305,9 +307,7 @@ static void QZ_DoDeactivate (_THIS) {
static void QZ_PumpEvents (_THIS) static void QZ_PumpEvents (_THIS)
{ {
static NSPoint lastMouse; int firstMouseEvent;
NSPoint mouse, saveMouse;
Point qdMouse;
CGMouseDelta dx, dy; CGMouseDelta dx, dy;
NSDate *distantPast; NSDate *distantPast;
...@@ -320,33 +320,13 @@ static void QZ_PumpEvents (_THIS) ...@@ -320,33 +320,13 @@ static void QZ_PumpEvents (_THIS)
distantPast = [ NSDate distantPast ]; distantPast = [ NSDate distantPast ];
winRect = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h); winRect = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h);
titleBarRect = NSMakeRect ( 0, SDL_VideoSurface->h, SDL_VideoSurface->w, titleBarRect = NSMakeRect (0, SDL_VideoSurface->h, SDL_VideoSurface->w,
SDL_VideoSurface->h + 22 ); SDL_VideoSurface->h + 22);
if (currentGrabMode != SDL_GRAB_ON) { /* if grabbed, the cursor can't move! (see fallback below) */ /* send the first mouse event in absolute coordinates */
firstMouseEvent = 1;
/* 1/2 second after a warp, the mouse cannot move (don't ask me why) */
/* So, approximate motion with CGGetLastMouseDelta, which still works, somehow */ /* accumulate any additional mouse moved events into one SDL mouse event */
if (! warp_flag) {
GetGlobalMouse (&qdMouse); /* use Carbon since [ NSEvent mouseLocation ] is broken */
mouse = NSMakePoint (qdMouse.h, qdMouse.v);
saveMouse = mouse;
if (mouse.x != lastMouse.x || mouse.y != lastMouse.y) {
QZ_PrivateCGToSDL (this, &mouse);
/* -note- we now generate mouse motion events if the mouse isn't over the window */
if (inForeground /* && NSPointInRect (mouse, winRect)*/) {
//printf ("Mouse Loc: (%f, %f)\n", mouse.x, mouse.y);
SDL_PrivateMouseMotion (0, 0, mouse.x, mouse.y);
}
}
lastMouse = saveMouse;
}
}
/* accumulate any mouse events into one SDL mouse event */
dx = 0; dx = 0;
dy = 0; dy = 0;
...@@ -419,14 +399,14 @@ static void QZ_PumpEvents (_THIS) ...@@ -419,14 +399,14 @@ static void QZ_PumpEvents (_THIS)
break; break;
case NSLeftMouseDragged: case NSLeftMouseDragged:
case NSRightMouseDragged: case NSRightMouseDragged:
case 27: case NSOtherMouseDragged: /* usually middle mouse dragged */
case NSMouseMoved: case NSMouseMoved:
if (currentGrabMode == SDL_GRAB_ON) { if (currentGrabMode == SDL_GRAB_ON) {
/** /**
* If input is grabbed, we'll wing it and try to send some mouse * If input is grabbed, the cursor doesn't move,
* moved events with CGGetLastMouseDelta(). Not optimal, but better * so we have to call the lowlevel window server
* than nothing. * function. This is less accurate but works OK.
**/ **/
CGMouseDelta dx1, dy1; CGMouseDelta dx1, dy1;
CGGetLastMouseDelta (&dx1, &dy1); CGGetLastMouseDelta (&dx1, &dy1);
...@@ -435,6 +415,12 @@ static void QZ_PumpEvents (_THIS) ...@@ -435,6 +415,12 @@ static void QZ_PumpEvents (_THIS)
} }
else if (warp_flag) { else if (warp_flag) {
/**
* If we just warped the mouse, the cursor is frozen for a while.
* So we have to use the lowlevel function until it
* unfreezes. This really helps apps that continuously
* warp the mouse to keep it in the game window.
**/
Uint32 ticks; Uint32 ticks;
ticks = SDL_GetTicks(); ticks = SDL_GetTicks();
...@@ -450,6 +436,30 @@ static void QZ_PumpEvents (_THIS) ...@@ -450,6 +436,30 @@ static void QZ_PumpEvents (_THIS)
warp_flag = 0; warp_flag = 0;
} }
} }
else if (firstMouseEvent) {
/**
* Get the first mouse event in a possible
* sequence of mouse moved events. Since we
* use absolute coordinates, this serves to
* compensate any inaccuracy in deltas, and
* provides the first known mouse position,
* since everything after this uses deltas
**/
NSPoint p = [ event locationInWindow ];
QZ_PrivateCocoaToSDL(this, &p);
firstMouseEvent = 0;
}
else {
/**
* Get the amount moved since the last drag or move event,
* add it on for one big move event at the end.
**/
dx += [ event deltaX ];
dy += [ event deltaY ];
}
break; break;
case NSScrollWheel: case NSScrollWheel:
if (NSPointInRect([ event locationInWindow ], winRect)) { if (NSPointInRect([ event locationInWindow ], winRect)) {
...@@ -490,9 +500,9 @@ static void QZ_PumpEvents (_THIS) ...@@ -490,9 +500,9 @@ static void QZ_PumpEvents (_THIS)
} }
} while (event != nil); } while (event != nil);
/* check for accumulated mouse events */ /* handle accumulated mouse moved events */
if (dx != 0 || dy != 0) if (dx != 0 || dy != 0)
SDL_PrivateMouseMotion (0, 1, dx, dy); SDL_PrivateMouseMotion (0, 1, dx, dy);
[ pool release ]; [ pool release ];
} }
......
...@@ -61,6 +61,24 @@ ...@@ -61,6 +61,24 @@
#include "SDL_pixels_c.h" #include "SDL_pixels_c.h"
#include "SDL_events_c.h" #include "SDL_events_c.h"
/*
Add methods to get at private members of NSScreen.
Since there is a bug in Apple's screen switching code
that does not update this variable when switching
to fullscreen, we'll set it manually (but only for the
main screen).
*/
@interface NSScreen (NSScreenAccess)
- (void) setFrame:(NSRect)frame;
@end
@implementation NSScreen (NSScreenAccess)
- (void) setFrame:(NSRect)frame;
{
_frame = frame;
}
@end
/* This is a workaround to directly access NSOpenGLContext's CGL context */ /* This is a workaround to directly access NSOpenGLContext's CGL context */
/* We need to do this in order to check for errors */ /* We need to do this in order to check for errors */
@interface NSOpenGLContext (CGLContextAccess) @interface NSOpenGLContext (CGLContextAccess)
......
...@@ -345,7 +345,8 @@ static void QZ_UnsetVideoMode (_THIS) { ...@@ -345,7 +345,8 @@ static void QZ_UnsetVideoMode (_THIS) {
SDL_QuartzGammaTable gamma_table; SDL_QuartzGammaTable gamma_table;
int gamma_error; int gamma_error;
NSRect screen_rect;
gamma_error = QZ_FadeGammaOut (this, &gamma_table); gamma_error = QZ_FadeGammaOut (this, &gamma_table);
/* Release the OpenGL context */ /* Release the OpenGL context */
...@@ -361,6 +362,13 @@ static void QZ_UnsetVideoMode (_THIS) { ...@@ -361,6 +362,13 @@ static void QZ_UnsetVideoMode (_THIS) {
CGDisplayRelease (display_id); CGDisplayRelease (display_id);
ShowMenuBar (); ShowMenuBar ();
/*
reset the main screen's rectangle, see comment
in QZ_SetVideoFullscreen
*/
screen_rect = NSMakeRect(0,0,device_width,device_height);
[ [ NSScreen mainScreen ] setFrame:screen_rect ];
if (! gamma_error) if (! gamma_error)
QZ_FadeGammaIn (this, &gamma_table); QZ_FadeGammaIn (this, &gamma_table);
} }
...@@ -401,7 +409,8 @@ static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int widt ...@@ -401,7 +409,8 @@ static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int widt
int exact_match; int exact_match;
int gamma_error; int gamma_error;
SDL_QuartzGammaTable gamma_table; SDL_QuartzGammaTable gamma_table;
NSRect screen_rect;
/* See if requested mode exists */ /* See if requested mode exists */
mode = CGDisplayBestModeForParameters (display_id, bpp, width, mode = CGDisplayBestModeForParameters (display_id, bpp, width,
height, &exact_match); height, &exact_match);
...@@ -484,6 +493,16 @@ static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int widt ...@@ -484,6 +493,16 @@ static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int widt
if (! gamma_error ) if (! gamma_error )
QZ_FadeGammaIn (this, &gamma_table); QZ_FadeGammaIn (this, &gamma_table);
/*
There is a bug in Cocoa where NSScreen doesn't synchronize
with CGDirectDisplay, so the main screen's frame is wrong.
As a result, coordinate translation produces wrong results.
We can hack around this bug by setting the screen rect
ourselves. This hack should be removed if/when the bug is fixed.
*/
screen_rect = NSMakeRect(0,0,width,height);
[ [ NSScreen mainScreen ] setFrame:screen_rect ];
/* Save the flags to ensure correct tear-down */ /* Save the flags to ensure correct tear-down */
mode_flags = current->flags; mode_flags = current->flags;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment