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@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 */ 33static Sint16 SDL_MouseX = 0; 34static Sint16 SDL_MouseY = 0; 35static Sint16 SDL_DeltaX = 0; 36static Sint16 SDL_DeltaY = 0; 37static Sint16 SDL_MouseMaxX = 0; 38static Sint16 SDL_MouseMaxY = 0; 39static Uint8 SDL_ButtonState = 0; 40 41 42/* Public functions */ 43int 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} 57void SDL_MouseQuit(void) 58{ 59} 60 61/* We lost the mouse, so post button up messages for all pressed buttons */ 62void 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 72Uint8 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 83Uint8 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 94static 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 106void 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 */ 113int 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 165printf("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 197int 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