Darrell's fix for Quartz mouse motion
authorSam Lantinga
Mon, 12 Aug 2002 22:43:58 +0000
changeset 435140798e1e7a6
parent 434 ed58b98c0d9d
child 436 3691cc3e14b3
Darrell's fix for Quartz mouse motion
src/video/quartz/SDL_QuartzEvents.m
src/video/quartz/SDL_QuartzVideo.h
src/video/quartz/SDL_QuartzVideo.m
     1.1 --- a/src/video/quartz/SDL_QuartzEvents.m	Mon Aug 12 14:54:38 2002 +0000
     1.2 +++ b/src/video/quartz/SDL_QuartzEvents.m	Mon Aug 12 22:43:58 2002 +0000
     1.3 @@ -23,6 +23,8 @@
     1.4  
     1.5  #include "SDL_QuartzKeys.h"
     1.6  
     1.7 +
     1.8 +
     1.9  static SDLKey keymap[256];
    1.10  static unsigned int currentMods = 0; /* Current keyboard modifiers, to track modifier state */
    1.11  static int last_virtual_button = 0; /* Last virtual mouse button pressed */
    1.12 @@ -305,9 +307,7 @@
    1.13  
    1.14  static void QZ_PumpEvents (_THIS)
    1.15  {
    1.16 -    static NSPoint lastMouse;
    1.17 -    NSPoint mouse, saveMouse;
    1.18 -    Point qdMouse;
    1.19 +    int firstMouseEvent;
    1.20      CGMouseDelta dx, dy;
    1.21  
    1.22      NSDate *distantPast;
    1.23 @@ -320,33 +320,13 @@
    1.24      distantPast = [ NSDate distantPast ];
    1.25  
    1.26      winRect = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h);
    1.27 -    titleBarRect = NSMakeRect ( 0, SDL_VideoSurface->h, SDL_VideoSurface->w,
    1.28 -                                SDL_VideoSurface->h + 22 );
    1.29 -
    1.30 -    if (currentGrabMode != SDL_GRAB_ON) { /* if grabbed, the cursor can't move! (see fallback below) */
    1.31 -
    1.32 -        /* 1/2 second after a warp, the mouse cannot move (don't ask me why) */
    1.33 -        /* So, approximate motion with CGGetLastMouseDelta, which still works, somehow */
    1.34 -        if (! warp_flag) {
    1.35 -
    1.36 -            GetGlobalMouse (&qdMouse);  /* use Carbon since [ NSEvent mouseLocation ] is broken */
    1.37 -            mouse = NSMakePoint (qdMouse.h, qdMouse.v);
    1.38 -            saveMouse = mouse;
    1.39 -
    1.40 -            if (mouse.x != lastMouse.x || mouse.y != lastMouse.y) {
    1.41 -
    1.42 -                QZ_PrivateCGToSDL (this, &mouse);
    1.43 -                /* -note- we now generate mouse motion events if the mouse isn't over the window */
    1.44 -                if (inForeground /* && NSPointInRect (mouse, winRect)*/) {
    1.45 -                    //printf ("Mouse Loc: (%f, %f)\n", mouse.x, mouse.y);
    1.46 -                    SDL_PrivateMouseMotion (0, 0, mouse.x, mouse.y);
    1.47 -                }
    1.48 -            }
    1.49 -            lastMouse = saveMouse;
    1.50 -        }
    1.51 -    }
    1.52 -
    1.53 -    /* accumulate any mouse events into one SDL mouse event */
    1.54 +    titleBarRect = NSMakeRect (0, SDL_VideoSurface->h, SDL_VideoSurface->w,
    1.55 +                                SDL_VideoSurface->h + 22);
    1.56 +    
    1.57 +    /* send the first mouse event in absolute coordinates */
    1.58 +    firstMouseEvent = 1;
    1.59 +    
    1.60 +    /* accumulate any additional mouse moved events into one SDL mouse event */
    1.61      dx = 0;
    1.62      dy = 0;
    1.63      
    1.64 @@ -419,14 +399,14 @@
    1.65                      break;
    1.66                  case NSLeftMouseDragged:
    1.67                  case NSRightMouseDragged:
    1.68 -                case 27:
    1.69 +                case NSOtherMouseDragged: /* usually middle mouse dragged */
    1.70                  case NSMouseMoved:
    1.71                      if (currentGrabMode == SDL_GRAB_ON) {
    1.72                  
    1.73                          /**
    1.74 -                         *  If input is grabbed, we'll wing it and try to send some mouse
    1.75 -                         *  moved events with CGGetLastMouseDelta(). Not optimal, but better
    1.76 -                         *  than nothing.
    1.77 +                         *  If input is grabbed, the cursor doesn't move,
    1.78 +                         *  so we have to call the lowlevel window server
    1.79 +                         *  function. This is less accurate but works OK.                         
    1.80                           **/
    1.81                          CGMouseDelta dx1, dy1;
    1.82                          CGGetLastMouseDelta (&dx1, &dy1);
    1.83 @@ -435,6 +415,12 @@
    1.84                      }
    1.85                      else if (warp_flag) {
    1.86                  
    1.87 +                        /**
    1.88 +                         * If we just warped the mouse, the cursor is frozen for a while.
    1.89 +                         * So we have to use the lowlevel function until it
    1.90 +                         * unfreezes. This really helps apps that continuously
    1.91 +                         * warp the mouse to keep it in the game window.
    1.92 +                         **/
    1.93                          Uint32 ticks;
    1.94                  
    1.95                          ticks = SDL_GetTicks();
    1.96 @@ -450,6 +436,30 @@
    1.97                              warp_flag = 0;
    1.98                          }
    1.99                      }
   1.100 +                    else if (firstMouseEvent) {
   1.101 +                        
   1.102 +                        /**
   1.103 +                         * Get the first mouse event in a possible
   1.104 +                         * sequence of mouse moved events. Since we
   1.105 +                         * use absolute coordinates, this serves to
   1.106 +                         * compensate any inaccuracy in deltas, and
   1.107 +                         * provides the first known mouse position,
   1.108 +                         * since everything after this uses deltas
   1.109 +                         **/
   1.110 +                        NSPoint p = [ event locationInWindow ];
   1.111 +                        QZ_PrivateCocoaToSDL(this, &p);
   1.112 +                        
   1.113 +                        firstMouseEvent = 0;
   1.114 +                    }
   1.115 +                    else {
   1.116 +                    
   1.117 +                       /**
   1.118 +                        * Get the amount moved since the last drag or move event,
   1.119 +                        * add it on for one big move event at the end.
   1.120 +                        **/
   1.121 +                       dx += [ event deltaX ];
   1.122 +                       dy += [ event deltaY ];
   1.123 +                    }
   1.124                      break;
   1.125                  case NSScrollWheel:
   1.126                      if (NSPointInRect([ event locationInWindow ], winRect)) {
   1.127 @@ -490,9 +500,9 @@
   1.128          }
   1.129      } while (event != nil);
   1.130      
   1.131 -    /* check for accumulated mouse events */
   1.132 +    /* handle accumulated mouse moved events */
   1.133      if (dx != 0 || dy != 0)
   1.134 -    SDL_PrivateMouseMotion (0, 1, dx, dy);
   1.135 +        SDL_PrivateMouseMotion (0, 1, dx, dy);
   1.136      
   1.137      [ pool release ];
   1.138  }
     2.1 --- a/src/video/quartz/SDL_QuartzVideo.h	Mon Aug 12 14:54:38 2002 +0000
     2.2 +++ b/src/video/quartz/SDL_QuartzVideo.h	Mon Aug 12 22:43:58 2002 +0000
     2.3 @@ -61,6 +61,24 @@
     2.4  #include "SDL_pixels_c.h"
     2.5  #include "SDL_events_c.h"
     2.6  
     2.7 +/* 
     2.8 +   Add methods to get at private members of NSScreen. 
     2.9 +   Since there is a bug in Apple's screen switching code
    2.10 +   that does not update this variable when switching
    2.11 +   to fullscreen, we'll set it manually (but only for the
    2.12 +   main screen).
    2.13 +*/
    2.14 +@interface NSScreen (NSScreenAccess)
    2.15 +- (void) setFrame:(NSRect)frame;
    2.16 +@end
    2.17 +
    2.18 +@implementation NSScreen (NSScreenAccess)
    2.19 +- (void) setFrame:(NSRect)frame;
    2.20 +{
    2.21 +    _frame = frame;
    2.22 +}
    2.23 +@end
    2.24 +
    2.25  /* This is a workaround to directly access NSOpenGLContext's CGL context */
    2.26  /* We need to do this in order to check for errors */
    2.27  @interface NSOpenGLContext (CGLContextAccess)
     3.1 --- a/src/video/quartz/SDL_QuartzVideo.m	Mon Aug 12 14:54:38 2002 +0000
     3.2 +++ b/src/video/quartz/SDL_QuartzVideo.m	Mon Aug 12 22:43:58 2002 +0000
     3.3 @@ -345,7 +345,8 @@
     3.4  
     3.5          SDL_QuartzGammaTable gamma_table;
     3.6          int gamma_error;
     3.7 -
     3.8 +        NSRect screen_rect;
     3.9 +        
    3.10          gamma_error = QZ_FadeGammaOut (this, &gamma_table);
    3.11  
    3.12          /* Release the OpenGL context */
    3.13 @@ -361,6 +362,13 @@
    3.14          CGDisplayRelease (display_id);
    3.15          ShowMenuBar ();
    3.16  
    3.17 +        /* 
    3.18 +           reset the main screen's rectangle, see comment
    3.19 +           in QZ_SetVideoFullscreen
    3.20 +        */
    3.21 +        screen_rect = NSMakeRect(0,0,device_width,device_height);
    3.22 +        [ [ NSScreen mainScreen ] setFrame:screen_rect ];
    3.23 +        
    3.24          if (! gamma_error)
    3.25              QZ_FadeGammaIn (this, &gamma_table);
    3.26      }
    3.27 @@ -401,7 +409,8 @@
    3.28      int exact_match;
    3.29      int gamma_error;
    3.30      SDL_QuartzGammaTable gamma_table;
    3.31 -
    3.32 +    NSRect screen_rect;
    3.33 +    
    3.34      /* See if requested mode exists */
    3.35      mode = CGDisplayBestModeForParameters (display_id, bpp, width,
    3.36                                             height, &exact_match);
    3.37 @@ -484,6 +493,16 @@
    3.38      if (! gamma_error )
    3.39          QZ_FadeGammaIn (this, &gamma_table);
    3.40  
    3.41 +    /* 
    3.42 +       There is a bug in Cocoa where NSScreen doesn't synchronize
    3.43 +       with CGDirectDisplay, so the main screen's frame is wrong.
    3.44 +       As a result, coordinate translation produces wrong results.
    3.45 +       We can hack around this bug by setting the screen rect
    3.46 +       ourselves. This hack should be removed if/when the bug is fixed.
    3.47 +    */
    3.48 +    screen_rect = NSMakeRect(0,0,width,height);
    3.49 +    [ [ NSScreen mainScreen ] setFrame:screen_rect ]; 
    3.50 +
    3.51      /* Save the flags to ensure correct tear-down */
    3.52      mode_flags = current->flags;
    3.53