Reset the mouse button state when losing mouse focus.
authorSam Lantinga <slouken@libsdl.org>
Thu, 08 Nov 2012 02:26:40 -0800
changeset 6666018f8019ce36
parent 6665 c0ea8c57034c
child 6667 243bfb5c31d6
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.
src/events/SDL_mouse.c
src/video/SDL_bmp.c
src/video/cocoa/SDL_cocoawindow.h
src/video/cocoa/SDL_cocoawindow.m
     1.1 --- a/src/events/SDL_mouse.c	Thu Nov 08 01:07:29 2012 -0800
     1.2 +++ b/src/events/SDL_mouse.c	Thu Nov 08 02:26:40 2012 -0800
     1.3 @@ -22,11 +22,13 @@
     1.4  
     1.5  /* General mouse handling code for SDL */
     1.6  
     1.7 +#include "SDL_assert.h"
     1.8  #include "SDL_events.h"
     1.9  #include "SDL_events_c.h"
    1.10  #include "default_cursor.h"
    1.11  #include "../video/SDL_sysvideo.h"
    1.12  
    1.13 +/*#define DEBUG_MOUSE*/
    1.14  
    1.15  /* The mouse state */
    1.16  static SDL_Mouse SDL_mouse;
    1.17 @@ -69,6 +71,23 @@
    1.18  }
    1.19  
    1.20  void
    1.21 +SDL_ResetMouse(void)
    1.22 +{
    1.23 +    SDL_Mouse *mouse = SDL_GetMouse();
    1.24 +    Uint8 i;
    1.25 +
    1.26 +#ifdef DEBUG_MOUSE
    1.27 +    printf("Resetting mouse\n");
    1.28 +#endif
    1.29 +    for (i = 1; i <= sizeof(mouse->buttonstate)*8; ++i) {
    1.30 +        if (mouse->buttonstate & SDL_BUTTON(i)) {
    1.31 +            SDL_SendMouseButton(mouse->focus, SDL_RELEASED, i);
    1.32 +        }
    1.33 +    }
    1.34 +    SDL_assert(mouse->buttonstate == 0);
    1.35 +}
    1.36 +
    1.37 +void
    1.38  SDL_SetMouseFocus(SDL_Window * window)
    1.39  {
    1.40      SDL_Mouse *mouse = SDL_GetMouse();
    1.41 @@ -77,6 +96,11 @@
    1.42          return;
    1.43      }
    1.44  
    1.45 +    if (mouse->focus && !window) {
    1.46 +        /* We won't get anymore mouse messages, so reset mouse state */
    1.47 +        SDL_ResetMouse();
    1.48 +    }
    1.49 +
    1.50      /* See if the current window has lost focus */
    1.51      if (mouse->focus) {
    1.52          SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
    1.53 @@ -87,6 +111,45 @@
    1.54      if (mouse->focus) {
    1.55          SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
    1.56      }
    1.57 +
    1.58 +    /* Update cursor visibility */
    1.59 +    SDL_SetCursor(NULL);
    1.60 +}
    1.61 +
    1.62 +/* Check to see if we need to synthesize focus events */
    1.63 +static SDL_bool
    1.64 +SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint8 buttonstate)
    1.65 +{
    1.66 +    SDL_Mouse *mouse = SDL_GetMouse();
    1.67 +    int w, h;
    1.68 +    SDL_bool inWindow;
    1.69 +
    1.70 +    SDL_GetWindowSize(window, &w, &h);
    1.71 +    if (x < 0 || y < 0 || x >= w || y >= h) {
    1.72 +        inWindow = SDL_FALSE;
    1.73 +    } else {
    1.74 +        inWindow = SDL_TRUE;
    1.75 +    }
    1.76 +    if (!inWindow && !buttonstate) {
    1.77 +        if (window == mouse->focus) {
    1.78 +#ifdef DEBUG_MOUSE
    1.79 +            printf("Mouse left window, synthesizing focus lost event\n");
    1.80 +#endif
    1.81 +            SDL_SetMouseFocus(NULL);
    1.82 +        }
    1.83 +        return SDL_FALSE;
    1.84 +    }
    1.85 +
    1.86 +    if (window != mouse->focus) {
    1.87 +        mouse->last_x = x;
    1.88 +        mouse->last_y = y;
    1.89 +
    1.90 +#ifdef DEBUG_MOUSE
    1.91 +        printf("Mouse entered window, synthesizing focus gain event\n");
    1.92 +#endif
    1.93 +        SDL_SetMouseFocus(window);
    1.94 +    }
    1.95 +    return SDL_TRUE;
    1.96  }
    1.97  
    1.98  int
    1.99 @@ -98,11 +161,13 @@
   1.100      int yrel;
   1.101      int x_max = 0, y_max = 0;
   1.102  
   1.103 -    if (window) {
   1.104 -        SDL_SetMouseFocus(window);
   1.105 +    if (window && !relative) {
   1.106 +        if (!SDL_UpdateMouseFocus(window, x, y, mouse->buttonstate)) {
   1.107 +            return 0;
   1.108 +        }
   1.109      }
   1.110  
   1.111 -    /* the relative motion is calculated regarding the system cursor last position */
   1.112 +    /* relative motion is calculated regarding the system cursor last position */
   1.113      if (relative) {
   1.114          xrel = x;
   1.115          yrel = y;
   1.116 @@ -115,7 +180,7 @@
   1.117  
   1.118      /* Drop events that don't change state */
   1.119      if (!xrel && !yrel) {
   1.120 -#if 0
   1.121 +#ifdef DEBUG_MOUSE
   1.122          printf("Mouse event didn't change state - dropped!\n");
   1.123  #endif
   1.124          return 0;
   1.125 @@ -135,7 +200,6 @@
   1.126      --y_max;
   1.127  
   1.128      /* make sure that the pointers find themselves inside the windows */
   1.129 -    /* only check if mouse->xmax is set ! */
   1.130      if (mouse->x > x_max) {
   1.131          mouse->x = x_max;
   1.132      }
   1.133 @@ -174,8 +238,9 @@
   1.134          event.motion.yrel = yrel;
   1.135          posted = (SDL_PushEvent(&event) > 0);
   1.136      }
   1.137 -    mouse->last_x = mouse->x;
   1.138 -    mouse->last_y = mouse->y;
   1.139 +    /* Use unclamped values if we're getting events outside the window */
   1.140 +    mouse->last_x = x;
   1.141 +    mouse->last_y = y;
   1.142      return posted;
   1.143  }
   1.144  
   1.145 @@ -185,34 +250,34 @@
   1.146      SDL_Mouse *mouse = SDL_GetMouse();
   1.147      int posted;
   1.148      Uint32 type;
   1.149 -
   1.150 -    if (window) {
   1.151 -        SDL_SetMouseFocus(window);
   1.152 -    }
   1.153 +    Uint8 buttonstate = mouse->buttonstate;
   1.154  
   1.155      /* Figure out which event to perform */
   1.156      switch (state) {
   1.157      case SDL_PRESSED:
   1.158 -        if (mouse->buttonstate & SDL_BUTTON(button)) {
   1.159 -            /* Ignore this event, no state change */
   1.160 -            return 0;
   1.161 -        }
   1.162          type = SDL_MOUSEBUTTONDOWN;
   1.163 -        mouse->buttonstate |= SDL_BUTTON(button);
   1.164 +        buttonstate |= SDL_BUTTON(button);
   1.165          break;
   1.166      case SDL_RELEASED:
   1.167 -        if (!(mouse->buttonstate & SDL_BUTTON(button))) {
   1.168 -            /* Ignore this event, no state change */
   1.169 -            return 0;
   1.170 -        }
   1.171          type = SDL_MOUSEBUTTONUP;
   1.172 -        mouse->buttonstate &= ~SDL_BUTTON(button);
   1.173 +        buttonstate &= ~SDL_BUTTON(button);
   1.174          break;
   1.175      default:
   1.176          /* Invalid state -- bail */
   1.177          return 0;
   1.178      }
   1.179  
   1.180 +    /* We do this after calculating buttonstate so button presses gain focus */
   1.181 +    if (window && state == SDL_PRESSED) {
   1.182 +        SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
   1.183 +    }
   1.184 +
   1.185 +    if (buttonstate == mouse->buttonstate) {
   1.186 +        /* Ignore this event, no state change */
   1.187 +        return 0;
   1.188 +    }
   1.189 +    mouse->buttonstate = buttonstate;
   1.190 +
   1.191      /* Post the event, if desired */
   1.192      posted = 0;
   1.193      if (SDL_GetEventState(type) == SDL_ENABLE) {
   1.194 @@ -225,6 +290,12 @@
   1.195          event.button.windowID = mouse->focus ? mouse->focus->id : 0;
   1.196          posted = (SDL_PushEvent(&event) > 0);
   1.197      }
   1.198 +
   1.199 +    /* We do this after dispatching event so button releases can lose focus */
   1.200 +    if (window && state == SDL_RELEASED) {
   1.201 +        SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
   1.202 +    }
   1.203 +
   1.204      return posted;
   1.205  }
   1.206  
     2.1 --- a/src/video/SDL_bmp.c	Thu Nov 08 01:07:29 2012 -0800
     2.2 +++ b/src/video/SDL_bmp.c	Thu Nov 08 02:26:40 2012 -0800
     2.3 @@ -51,7 +51,7 @@
     2.4  SDL_LoadBMP_RW(SDL_RWops * src, int freesrc)
     2.5  {
     2.6      SDL_bool was_error;
     2.7 -    long fp_offset = 0;
     2.8 +    Sint64 fp_offset = 0;
     2.9      int bmpPitch;
    2.10      int i, pad;
    2.11      SDL_Surface *surface;
    2.12 @@ -371,7 +371,7 @@
    2.13  int
    2.14  SDL_SaveBMP_RW(SDL_Surface * saveme, SDL_RWops * dst, int freedst)
    2.15  {
    2.16 -    long fp_offset;
    2.17 +    Sint64 fp_offset;
    2.18      int i, pad;
    2.19      SDL_Surface *surface;
    2.20      Uint8 *bits;
    2.21 @@ -515,7 +515,7 @@
    2.22          }
    2.23  
    2.24          /* Write the bitmap offset */
    2.25 -        bfOffBits = SDL_RWtell(dst) - fp_offset;
    2.26 +        bfOffBits = (Uint32)(SDL_RWtell(dst) - fp_offset);
    2.27          if (SDL_RWseek(dst, fp_offset + 10, RW_SEEK_SET) < 0) {
    2.28              SDL_Error(SDL_EFSEEK);
    2.29          }
    2.30 @@ -542,7 +542,7 @@
    2.31          }
    2.32  
    2.33          /* Write the BMP file size */
    2.34 -        bfSize = SDL_RWtell(dst) - fp_offset;
    2.35 +        bfSize = (Uint32)(SDL_RWtell(dst) - fp_offset);
    2.36          if (SDL_RWseek(dst, fp_offset + 2, RW_SEEK_SET) < 0) {
    2.37              SDL_Error(SDL_EFSEEK);
    2.38          }
     3.1 --- a/src/video/cocoa/SDL_cocoawindow.h	Thu Nov 08 01:07:29 2012 -0800
     3.2 +++ b/src/video/cocoa/SDL_cocoawindow.h	Thu Nov 08 02:26:40 2012 -0800
     3.3 @@ -56,8 +56,6 @@
     3.4  -(void) mouseUp:(NSEvent *) theEvent;
     3.5  -(void) rightMouseUp:(NSEvent *) theEvent;
     3.6  -(void) otherMouseUp:(NSEvent *) theEvent;
     3.7 --(void) mouseEntered:(NSEvent *)theEvent;
     3.8 --(void) mouseExited:(NSEvent *)theEvent;
     3.9  -(void) mouseMoved:(NSEvent *) theEvent;
    3.10  -(void) mouseDragged:(NSEvent *) theEvent;
    3.11  -(void) rightMouseDragged:(NSEvent *) theEvent;
     4.1 --- a/src/video/cocoa/SDL_cocoawindow.m	Thu Nov 08 01:07:29 2012 -0800
     4.2 +++ b/src/video/cocoa/SDL_cocoawindow.m	Thu Nov 08 02:26:40 2012 -0800
     4.3 @@ -200,10 +200,8 @@
     4.4          y = (int)(window->h - point.y);
     4.5  
     4.6          if (x >= 0 && x < window->w && y >= 0 && y < window->h) {
     4.7 -            if (SDL_GetMouseFocus() != window) {
     4.8 -                [self mouseEntered:nil];
     4.9 -            }
    4.10              SDL_SendMouseMotion(window, 0, x, y);
    4.11 +            SDL_SetCursor(NULL);
    4.12          }
    4.13      }
    4.14  
    4.15 @@ -309,38 +307,6 @@
    4.16      [self mouseUp:theEvent];
    4.17  }
    4.18  
    4.19 -- (void)mouseEntered:(NSEvent *)theEvent
    4.20 -{
    4.21 -    SDL_SetMouseFocus(_data->window);
    4.22 -
    4.23 -    SDL_SetCursor(NULL);
    4.24 -}
    4.25 -
    4.26 -- (void)mouseExited:(NSEvent *)theEvent
    4.27 -{
    4.28 -    SDL_Window *window = _data->window;
    4.29 -
    4.30 -    if (SDL_GetMouseFocus() == window) {
    4.31 -        if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
    4.32 -            int x, y;
    4.33 -            NSPoint point;
    4.34 -            CGPoint cgpoint;
    4.35 -
    4.36 -            point = [theEvent locationInWindow];
    4.37 -            point.y = window->h - point.y;
    4.38 -
    4.39 -            SDL_SendMouseMotion(window, 0, (int)point.x, (int)point.y);
    4.40 -            SDL_GetMouseState(&x, &y);
    4.41 -            cgpoint.x = window->x + x;
    4.42 -            cgpoint.y = window->y + y;
    4.43 -            CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
    4.44 -        } else {
    4.45 -            SDL_SetMouseFocus(NULL);
    4.46 -            SDL_SetCursor(NULL);
    4.47 -        }
    4.48 -    }
    4.49 -}
    4.50 -
    4.51  - (void)mouseMoved:(NSEvent *)theEvent
    4.52  {
    4.53      SDL_Mouse *mouse = SDL_GetMouse();
    4.54 @@ -357,15 +323,26 @@
    4.55      y = (int)(window->h - point.y);
    4.56  
    4.57      if (x < 0 || x >= window->w || y < 0 || y >= window->h) {
    4.58 -        if (SDL_GetMouseFocus() == window) {
    4.59 -            [self mouseExited:theEvent];
    4.60 +        if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
    4.61 +            CGPoint cgpoint;
    4.62 +
    4.63 +            if (x < 0) {
    4.64 +                x = 0;
    4.65 +            } else if (x >= window->w) {
    4.66 +                x = window->w - 1;
    4.67 +            }
    4.68 +            if (y < 0) {
    4.69 +                y = 0;
    4.70 +            } else if (y >= window->h) {
    4.71 +                y = window->h - 1;
    4.72 +            }
    4.73 +
    4.74 +            cgpoint.x = window->x + x;
    4.75 +            cgpoint.y = window->y + y;
    4.76 +            CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
    4.77          }
    4.78 -    } else {
    4.79 -        if (SDL_GetMouseFocus() != window) {
    4.80 -            [self mouseEntered:theEvent];
    4.81 -        }
    4.82 -        SDL_SendMouseMotion(window, 0, x, y);
    4.83      }
    4.84 +    SDL_SendMouseMotion(window, 0, x, y);
    4.85  }
    4.86  
    4.87  - (void)mouseDragged:(NSEvent *)theEvent