1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2012 Sam Lantinga 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 19 Sam Lantinga 20 slouken (at) libsdl.org 21 */ 22 #include "SDL_config.h" 23 24 /* General mouse handling code for SDL */ 25 26 #include "SDL_events.h" 27 #include "SDL_events_c.h" 28 #include "../video/SDL_cursor_c.h" 29 #include "../video/SDL_sysvideo.h" 30 31 32 /* These are static for our mouse handling code */ 33 static Sint16 SDL_MouseX = 0; 34 static Sint16 SDL_MouseY = 0; 35 static Sint16 SDL_DeltaX = 0; 36 static Sint16 SDL_DeltaY = 0; 37 static Sint16 SDL_MouseMaxX = 0; 38 static Sint16 SDL_MouseMaxY = 0; 39 static Uint8 SDL_ButtonState = 0; 40 41 42 /* Public functions */ 43 int SDL_MouseInit(void) 44 { 45 /* The mouse is at (0,0) */ 46 SDL_MouseX = 0; 47 SDL_MouseY = 0; 48 SDL_DeltaX = 0; 49 SDL_DeltaY = 0; 50 SDL_MouseMaxX = 0; 51 SDL_MouseMaxY = 0; 52 SDL_ButtonState = 0; 53 54 /* That's it! */ 55 return(0); 56 } 57 void SDL_MouseQuit(void) 58 { 59 } 60 61 /* We lost the mouse, so post button up messages for all pressed buttons */ 62 void SDL_ResetMouse(void) 63 { 64 Uint8 i; 65 for ( i = 0; i < sizeof(SDL_ButtonState)*8; ++i ) { 66 if ( SDL_ButtonState & SDL_BUTTON(i) ) { 67 SDL_PrivateMouseButton(SDL_RELEASED, i, 0, 0); 68 } 69 } 70 } 71 72 Uint8 SDL_GetMouseState (int *x, int *y) 73 { 74 if ( x ) { 75 *x = SDL_MouseX; 76 } 77 if ( y ) { 78 *y = SDL_MouseY; 79 } 80 return(SDL_ButtonState); 81 } 82 83 Uint8 SDL_GetRelativeMouseState (int *x, int *y) 84 { 85 if ( x ) 86 *x = SDL_DeltaX; 87 if ( y ) 88 *y = SDL_DeltaY; 89 SDL_DeltaX = 0; 90 SDL_DeltaY = 0; 91 return(SDL_ButtonState); 92 } 93 94 static void ClipOffset(Sint16 *x, Sint16 *y) 95 { 96 /* This clips absolute mouse coordinates when the apparent 97 display surface is smaller than the real display surface. 98 */ 99 if ( SDL_VideoSurface && SDL_VideoSurface->offset ) { 100 *y -= SDL_VideoSurface->offset/SDL_VideoSurface->pitch; 101 *x -= (SDL_VideoSurface->offset%SDL_VideoSurface->pitch)/ 102 SDL_VideoSurface->format->BytesPerPixel; 103 } 104 } 105 106 void SDL_SetMouseRange(int maxX, int maxY) 107 { 108 SDL_MouseMaxX = (Sint16)maxX; 109 SDL_MouseMaxY = (Sint16)maxY; 110 } 111 112 /* These are global for SDL_eventloop.c */ 113 int SDL_PrivateMouseMotion(Uint8 buttonstate, int relative, Sint16 x, Sint16 y) 114 { 115 int posted; 116 Uint16 X, Y; 117 Sint16 Xrel; 118 Sint16 Yrel; 119 120 /* Default buttonstate is the current one */ 121 if ( ! buttonstate ) { 122 buttonstate = SDL_ButtonState; 123 } 124 125 Xrel = x; 126 Yrel = y; 127 if ( relative ) { 128 /* Push the cursor around */ 129 x = (SDL_MouseX+x); 130 y = (SDL_MouseY+y); 131 } else { 132 /* Do we need to clip {x,y} ? */ 133 ClipOffset(&x, &y); 134 } 135 136 /* Mouse coordinates range from 0 - width-1 and 0 - height-1 */ 137 if ( x < 0 ) 138 X = 0; 139 else 140 if ( x >= SDL_MouseMaxX ) 141 X = SDL_MouseMaxX-1; 142 else 143 X = (Uint16)x; 144 145 if ( y < 0 ) 146 Y = 0; 147 else 148 if ( y >= SDL_MouseMaxY ) 149 Y = SDL_MouseMaxY-1; 150 else 151 Y = (Uint16)y; 152 153 /* If not relative mode, generate relative motion from clamped X/Y. 154 This prevents lots of extraneous large delta relative motion when 155 the screen is windowed mode and the mouse is outside the window. 156 */ 157 if ( ! relative ) { 158 Xrel = X-SDL_MouseX; 159 Yrel = Y-SDL_MouseY; 160 } 161 162 /* Drop events that don't change state */ 163 if ( ! Xrel && ! Yrel ) { 164 #if 0 165 printf("Mouse event didn't change state - dropped!\n"); 166 #endif 167 return(0); 168 } 169 170 /* Update internal mouse state */ 171 SDL_ButtonState = buttonstate; 172 SDL_MouseX = X; 173 SDL_MouseY = Y; 174 SDL_DeltaX += Xrel; 175 SDL_DeltaY += Yrel; 176 SDL_MoveCursor(SDL_MouseX, SDL_MouseY); 177 178 /* Post the event, if desired */ 179 posted = 0; 180 if ( SDL_ProcessEvents[SDL_MOUSEMOTION] == SDL_ENABLE ) { 181 SDL_Event event; 182 SDL_memset(&event, 0, sizeof(event)); 183 event.type = SDL_MOUSEMOTION; 184 event.motion.state = buttonstate; 185 event.motion.x = X; 186 event.motion.y = Y; 187 event.motion.xrel = Xrel; 188 event.motion.yrel = Yrel; 189 if ( (SDL_EventOK == NULL) || (*SDL_EventOK)(&event) ) { 190 posted = 1; 191 SDL_PushEvent(&event); 192 } 193 } 194 return(posted); 195 } 196 197 int SDL_PrivateMouseButton(Uint8 state, Uint8 button, Sint16 x, Sint16 y) 198 { 199 SDL_Event event; 200 int posted; 201 int move_mouse; 202 Uint8 buttonstate; 203 204 SDL_memset(&event, 0, sizeof(event)); 205 206 /* Check parameters */ 207 if ( x || y ) { 208 ClipOffset(&x, &y); 209 move_mouse = 1; 210 /* Mouse coordinates range from 0 - width-1 and 0 - height-1 */ 211 if ( x < 0 ) 212 x = 0; 213 else 214 if ( x >= SDL_MouseMaxX ) 215 x = SDL_MouseMaxX-1; 216 217 if ( y < 0 ) 218 y = 0; 219 else 220 if ( y >= SDL_MouseMaxY ) 221 y = SDL_MouseMaxY-1; 222 } else { 223 move_mouse = 0; 224 } 225 if ( ! x ) 226 x = SDL_MouseX; 227 if ( ! y ) 228 y = SDL_MouseY; 229 230 /* Figure out which event to perform */ 231 buttonstate = SDL_ButtonState; 232 switch ( state ) { 233 case SDL_PRESSED: 234 event.type = SDL_MOUSEBUTTONDOWN; 235 buttonstate |= SDL_BUTTON(button); 236 break; 237 case SDL_RELEASED: 238 event.type = SDL_MOUSEBUTTONUP; 239 buttonstate &= ~SDL_BUTTON(button); 240 break; 241 default: 242 /* Invalid state -- bail */ 243 return(0); 244 } 245 246 /* Update internal mouse state */ 247 SDL_ButtonState = buttonstate; 248 if ( move_mouse ) { 249 SDL_MouseX = x; 250 SDL_MouseY = y; 251 SDL_MoveCursor(SDL_MouseX, SDL_MouseY); 252 } 253 254 /* Post the event, if desired */ 255 posted = 0; 256 if ( SDL_ProcessEvents[event.type] == SDL_ENABLE ) { 257 event.button.state = state; 258 event.button.button = button; 259 event.button.x = x; 260 event.button.y = y; 261 if ( (SDL_EventOK == NULL) || (*SDL_EventOK)(&event) ) { 262 posted = 1; 263 SDL_PushEvent(&event); 264 } 265 } 266 return(posted); 267 } 268 269