src/events/SDL_mouse.c
author Sam Lantinga
Tue, 14 Mar 2006 06:00:30 +0000
changeset 1525 23a347cfbed8
parent 1442 e3242177fe4a
child 1662 782fd950bd46
child 1895 c121d94672cb
child 4159 a1b03ba2fcd0
permissions -rw-r--r--
Fixed bug #38

I'm using SDL 1.2.9 with Visual C++ 7.0 on Windows 2000.

Here's the setup: my game starts in a window, with
SDL_WM_GrabInput(SDL_GRAB_ON) to constrain the cursor to the game window. The
mouse cursor is outside of the window when the game launches, and when the
window appears the cursor is grabbed and placed at the top left corner of the
inside of the game window. At this point, if I click the mouse without moving
it, the SDL_MOUSEBUTTONDOWN event's mouse coordinates are (65535,65535).
     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@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