src/events/SDL_mouse.c
changeset 6666 018f8019ce36
parent 6302 b0ae93a5b8d6
child 6667 243bfb5c31d6
     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