Home | History | Annotate | Download | only in events
      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