src/events/SDL_mouse.c
author Sam Lantinga
Sun, 27 Sep 2009 05:18:43 +0000
branchSDL-1.2
changeset 4249 429c8dd3175d
parent 4159 a1b03ba2fcd0
child 6137 4720145f848b
permissions -rw-r--r--
Fixed bug #713

Don't clamp the mouse coordinates to the video surface size, instead clamp them to the last known window size.

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