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