1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2006 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 Uint8 SDL_ButtonState = 0; 38 39 40 /* Public functions */ 41 int SDL_MouseInit(void) 42 { 43 /* The mouse is at (0,0) */ 44 SDL_MouseX = 0; 45 SDL_MouseY = 0; 46 SDL_DeltaX = 0; 47 SDL_DeltaY = 0; 48 SDL_ButtonState = 0; 49 50 /* That's it! */ 51 return(0); 52 } 53 void SDL_MouseQuit(void) 54 { 55 } 56 57 /* We lost the mouse, so post button up messages for all pressed buttons */ 58 void SDL_ResetMouse(void) 59 { 60 Uint8 i; 61 for ( i = 0; i < sizeof(SDL_ButtonState)*8; ++i ) { 62 if ( SDL_ButtonState & SDL_BUTTON(i) ) { 63 SDL_PrivateMouseButton(SDL_RELEASED, i, 0, 0); 64 } 65 } 66 } 67 68 Uint8 SDL_GetMouseState (int *x, int *y) 69 { 70 if ( x ) { 71 *x = SDL_MouseX; 72 } 73 if ( y ) { 74 *y = SDL_MouseY; 75 } 76 return(SDL_ButtonState); 77 } 78 79 Uint8 SDL_GetRelativeMouseState (int *x, int *y) 80 { 81 if ( x ) 82 *x = SDL_DeltaX; 83 if ( y ) 84 *y = SDL_DeltaY; 85 SDL_DeltaX = 0; 86 SDL_DeltaY = 0; 87 return(SDL_ButtonState); 88 } 89 90 static void ClipOffset(Sint16 *x, Sint16 *y) 91 { 92 /* This clips absolute mouse coordinates when the apparent 93 display surface is smaller than the real display surface. 94 */ 95 if ( SDL_VideoSurface->offset ) { 96 *y -= SDL_VideoSurface->offset/SDL_VideoSurface->pitch; 97 *x -= (SDL_VideoSurface->offset%SDL_VideoSurface->pitch)/ 98 SDL_VideoSurface->format->BytesPerPixel; 99 } 100 } 101 102 /* These are global for SDL_eventloop.c */ 103 int SDL_PrivateMouseMotion(Uint8 buttonstate, int relative, Sint16 x, Sint16 y) 104 { 105 int posted; 106 Uint16 X, Y; 107 Sint16 Xrel; 108 Sint16 Yrel; 109 110 /* Don't handle mouse motion if there's no cursor surface */ 111 if ( SDL_VideoSurface == NULL ) { 112 return(0); 113 } 114 115 /* Default buttonstate is the current one */ 116 if ( ! buttonstate ) { 117 buttonstate = SDL_ButtonState; 118 } 119 120 Xrel = x; 121 Yrel = y; 122 if ( relative ) { 123 /* Push the cursor around */ 124 x = (SDL_MouseX+x); 125 y = (SDL_MouseY+y); 126 } else { 127 /* Do we need to clip {x,y} ? */ 128 ClipOffset(&x, &y); 129 } 130 131 /* Mouse coordinates range from 0 - width-1 and 0 - height-1 */ 132 if ( x < 0 ) 133 X = 0; 134 else 135 if ( x >= SDL_VideoSurface->w ) 136 X = SDL_VideoSurface->w-1; 137 else 138 X = (Uint16)x; 139 140 if ( y < 0 ) 141 Y = 0; 142 else 143 if ( y >= SDL_VideoSurface->h ) 144 Y = SDL_VideoSurface->h-1; 145 else 146 Y = (Uint16)y; 147 148 /* If not relative mode, generate relative motion from clamped X/Y. 149 This prevents lots of extraneous large delta relative motion when 150 the screen is windowed mode and the mouse is outside the window. 151 */ 152 if ( ! relative ) { 153 Xrel = X-SDL_MouseX; 154 Yrel = Y-SDL_MouseY; 155 } 156 157 /* Drop events that don't change state */ 158 if ( ! Xrel && ! Yrel ) { 159 #if 0 160 printf("Mouse event didn't change state - dropped!\n"); 161 #endif 162 return(0); 163 } 164 165 /* Update internal mouse state */ 166 SDL_ButtonState = buttonstate; 167 SDL_MouseX = X; 168 SDL_MouseY = Y; 169 SDL_DeltaX += Xrel; 170 SDL_DeltaY += Yrel; 171 SDL_MoveCursor(SDL_MouseX, SDL_MouseY); 172 173 /* Post the event, if desired */ 174 posted = 0; 175 if ( SDL_ProcessEvents[SDL_MOUSEMOTION] == SDL_ENABLE ) { 176 SDL_Event event; 177 SDL_memset(&event, 0, sizeof(event)); 178 event.type = SDL_MOUSEMOTION; 179 event.motion.state = buttonstate; 180 event.motion.x = X; 181 event.motion.y = Y; 182 event.motion.xrel = Xrel; 183 event.motion.yrel = Yrel; 184 if ( (SDL_EventOK == NULL) || (*SDL_EventOK)(&event) ) { 185 posted = 1; 186 SDL_PushEvent(&event); 187 } 188 } 189 return(posted); 190 } 191 192 int SDL_PrivateMouseButton(Uint8 state, Uint8 button, Sint16 x, Sint16 y) 193 { 194 SDL_Event event; 195 int posted; 196 int move_mouse; 197 Uint8 buttonstate; 198 199 SDL_memset(&event, 0, sizeof(event)); 200 201 /* Check parameters */ 202 if ( x || y ) { 203 ClipOffset(&x, &y); 204 move_mouse = 1; 205 /* Mouse coordinates range from 0 - width-1 and 0 - height-1 */ 206 if ( x < 0 ) 207 x = 0; 208 else 209 if ( x >= SDL_VideoSurface->w ) 210 x = SDL_VideoSurface->w-1; 211 212 if ( y < 0 ) 213 y = 0; 214 else 215 if ( y >= SDL_VideoSurface->h ) 216 y = SDL_VideoSurface->h-1; 217 } else { 218 move_mouse = 0; 219 } 220 if ( ! x ) 221 x = SDL_MouseX; 222 if ( ! y ) 223 y = SDL_MouseY; 224 225 /* Figure out which event to perform */ 226 buttonstate = SDL_ButtonState; 227 switch ( state ) { 228 case SDL_PRESSED: 229 event.type = SDL_MOUSEBUTTONDOWN; 230 buttonstate |= SDL_BUTTON(button); 231 break; 232 case SDL_RELEASED: 233 event.type = SDL_MOUSEBUTTONUP; 234 buttonstate &= ~SDL_BUTTON(button); 235 break; 236 default: 237 /* Invalid state -- bail */ 238 return(0); 239 } 240 241 /* Update internal mouse state */ 242 SDL_ButtonState = buttonstate; 243 if ( move_mouse ) { 244 SDL_MouseX = x; 245 SDL_MouseY = y; 246 SDL_MoveCursor(SDL_MouseX, SDL_MouseY); 247 } 248 249 /* Post the event, if desired */ 250 posted = 0; 251 if ( SDL_ProcessEvents[event.type] == SDL_ENABLE ) { 252 event.button.state = state; 253 event.button.button = button; 254 event.button.x = x; 255 event.button.y = y; 256 if ( (SDL_EventOK == NULL) || (*SDL_EventOK)(&event) ) { 257 posted = 1; 258 SDL_PushEvent(&event); 259 } 260 } 261 return(posted); 262 } 263 264