2001-04-26 16:45:43 +00:00
|
|
|
/*
|
|
|
|
SDL - Simple DirectMedia Layer
|
2008-12-08 00:25:42 +00:00
|
|
|
Copyright (C) 1997-2009 Sam Lantinga
|
2001-04-26 16:45:43 +00:00
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
2006-02-01 06:32:25 +00:00
|
|
|
modify it under the terms of the GNU Lesser General Public
|
2001-04-26 16:45:43 +00:00
|
|
|
License as published by the Free Software Foundation; either
|
2006-02-01 06:32:25 +00:00
|
|
|
version 2.1 of the License, or (at your option) any later version.
|
2001-04-26 16:45:43 +00:00
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
2006-02-01 06:32:25 +00:00
|
|
|
Lesser General Public License for more details.
|
2001-04-26 16:45:43 +00:00
|
|
|
|
2006-02-01 06:32:25 +00:00
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with this library; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
2001-04-26 16:45:43 +00:00
|
|
|
|
|
|
|
Sam Lantinga
|
2001-12-14 12:38:15 +00:00
|
|
|
slouken@libsdl.org
|
2001-04-26 16:45:43 +00:00
|
|
|
*/
|
2006-02-21 08:46:50 +00:00
|
|
|
#include "SDL_config.h"
|
2001-04-26 16:45:43 +00:00
|
|
|
|
2006-02-25 22:18:25 +00:00
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
|
|
#include <windows.h>
|
2001-04-26 16:45:43 +00:00
|
|
|
|
2006-02-07 09:29:18 +00:00
|
|
|
#include "SDL_mouse.h"
|
2006-02-16 10:11:48 +00:00
|
|
|
#include "../../events/SDL_events_c.h"
|
|
|
|
#include "../SDL_cursor_c.h"
|
2001-04-26 16:45:43 +00:00
|
|
|
#include "SDL_sysmouse_c.h"
|
|
|
|
#include "SDL_lowvideo.h"
|
|
|
|
|
|
|
|
#ifdef _WIN32_WCE
|
|
|
|
#define USE_STATIC_CURSOR
|
|
|
|
#endif
|
|
|
|
|
|
|
|
HCURSOR SDL_hcursor = NULL; /* Exported for SDL_eventloop.c */
|
|
|
|
|
|
|
|
/* The implementation dependent data for the window manager cursor */
|
|
|
|
/* For some reason when creating a windows cursor, the ands and xors memory
|
|
|
|
is not copied, so we need to keep track of it and free it when we are done
|
|
|
|
with the cursor. If we free the memory prematurely, the app crashes. :-}
|
|
|
|
*/
|
|
|
|
struct WMcursor {
|
|
|
|
HCURSOR curs;
|
|
|
|
#ifndef USE_STATIC_CURSOR
|
|
|
|
Uint8 *ands;
|
|
|
|
Uint8 *xors;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Convert bits to padded bytes */
|
|
|
|
#define PAD_BITS(bits) ((bits+7)/8)
|
|
|
|
|
|
|
|
#ifdef CURSOR_DEBUG
|
|
|
|
static void PrintBITMAP(FILE *out, char *bits, int w, int h)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
unsigned char ch;
|
|
|
|
|
|
|
|
while ( h-- > 0 ) {
|
|
|
|
for ( i=0; i<w; ++i ) {
|
|
|
|
if ( (i%8) == 0 )
|
|
|
|
ch = *bits++;
|
|
|
|
if ( ch&0x80 )
|
|
|
|
fprintf(out, "X");
|
|
|
|
else
|
|
|
|
fprintf(out, " ");
|
|
|
|
ch <<= 1;
|
|
|
|
}
|
|
|
|
fprintf(out, "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef USE_STATIC_CURSOR
|
|
|
|
/* Local functions to convert the SDL cursor mask into Windows format */
|
|
|
|
static void memnot(Uint8 *dst, Uint8 *src, int len)
|
|
|
|
{
|
|
|
|
while ( len-- > 0 )
|
|
|
|
*dst++ = ~*src++;
|
|
|
|
}
|
|
|
|
static void memxor(Uint8 *dst, Uint8 *src1, Uint8 *src2, int len)
|
|
|
|
{
|
|
|
|
while ( len-- > 0 )
|
|
|
|
*dst++ = (*src1++)^(*src2++);
|
|
|
|
}
|
|
|
|
#endif /* !USE_STATIC_CURSOR */
|
|
|
|
|
|
|
|
void WIN_FreeWMCursor(_THIS, WMcursor *cursor)
|
|
|
|
{
|
|
|
|
#ifndef USE_STATIC_CURSOR
|
2002-10-05 05:46:32 +00:00
|
|
|
if ( cursor->curs == GetCursor() )
|
|
|
|
SetCursor(NULL);
|
2001-04-26 16:45:43 +00:00
|
|
|
if ( cursor->curs != NULL )
|
|
|
|
DestroyCursor(cursor->curs);
|
|
|
|
if ( cursor->ands != NULL )
|
2006-02-07 06:59:48 +00:00
|
|
|
SDL_free(cursor->ands);
|
2001-04-26 16:45:43 +00:00
|
|
|
if ( cursor->xors != NULL )
|
2006-02-07 06:59:48 +00:00
|
|
|
SDL_free(cursor->xors);
|
2001-04-26 16:45:43 +00:00
|
|
|
#endif /* !USE_STATIC_CURSOR */
|
2006-02-07 06:59:48 +00:00
|
|
|
SDL_free(cursor);
|
2001-04-26 16:45:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
WMcursor *WIN_CreateWMCursor(_THIS,
|
|
|
|
Uint8 *data, Uint8 *mask, int w, int h, int hot_x, int hot_y)
|
|
|
|
{
|
|
|
|
#ifdef USE_STATIC_CURSOR
|
|
|
|
WMcursor *cursor;
|
|
|
|
|
|
|
|
/* Allocate the cursor */
|
2006-02-07 06:59:48 +00:00
|
|
|
cursor = (WMcursor *)SDL_malloc(sizeof(*cursor));
|
2001-04-26 16:45:43 +00:00
|
|
|
if ( cursor ) {
|
|
|
|
cursor->curs = LoadCursor(NULL, IDC_ARROW);
|
|
|
|
}
|
|
|
|
return(cursor);
|
|
|
|
#else
|
|
|
|
WMcursor *cursor;
|
|
|
|
int allowed_x;
|
|
|
|
int allowed_y;
|
|
|
|
int run, pad, i;
|
|
|
|
Uint8 *aptr, *xptr;
|
|
|
|
|
|
|
|
/* Check to make sure the cursor size is okay */
|
|
|
|
allowed_x = GetSystemMetrics(SM_CXCURSOR);
|
|
|
|
allowed_y = GetSystemMetrics(SM_CYCURSOR);
|
|
|
|
if ( (w > allowed_x) || (h > allowed_y) ) {
|
|
|
|
SDL_SetError("Only cursors of dimension (%dx%d) are allowed",
|
|
|
|
allowed_x, allowed_y);
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate the cursor */
|
2006-02-07 06:59:48 +00:00
|
|
|
cursor = (WMcursor *)SDL_malloc(sizeof(*cursor));
|
2001-04-26 16:45:43 +00:00
|
|
|
if ( cursor == NULL ) {
|
|
|
|
SDL_SetError("Out of memory");
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
cursor->curs = NULL;
|
|
|
|
cursor->ands = NULL;
|
|
|
|
cursor->xors = NULL;
|
|
|
|
|
|
|
|
/* Pad out to the normal cursor size */
|
|
|
|
run = PAD_BITS(w);
|
|
|
|
pad = PAD_BITS(allowed_x)-run;
|
2006-02-07 06:59:48 +00:00
|
|
|
aptr = cursor->ands = (Uint8 *)SDL_malloc((run+pad)*allowed_y);
|
|
|
|
xptr = cursor->xors = (Uint8 *)SDL_malloc((run+pad)*allowed_y);
|
2001-04-26 16:45:43 +00:00
|
|
|
if ( (aptr == NULL) || (xptr == NULL) ) {
|
|
|
|
WIN_FreeWMCursor(NULL, cursor);
|
|
|
|
SDL_OutOfMemory();
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
for ( i=0; i<h; ++i ) {
|
|
|
|
memxor(xptr, data, mask, run);
|
|
|
|
xptr += run;
|
|
|
|
data += run;
|
|
|
|
memnot(aptr, mask, run);
|
|
|
|
mask += run;
|
|
|
|
aptr += run;
|
2006-02-07 06:59:48 +00:00
|
|
|
SDL_memset(xptr, 0, pad);
|
2001-04-26 16:45:43 +00:00
|
|
|
xptr += pad;
|
2006-02-07 06:59:48 +00:00
|
|
|
SDL_memset(aptr, ~0, pad);
|
2001-04-26 16:45:43 +00:00
|
|
|
aptr += pad;
|
|
|
|
}
|
|
|
|
pad += run;
|
|
|
|
for ( ; i<allowed_y; ++i ) {
|
2006-02-07 06:59:48 +00:00
|
|
|
SDL_memset(xptr, 0, pad);
|
2001-04-26 16:45:43 +00:00
|
|
|
xptr += pad;
|
2006-02-07 06:59:48 +00:00
|
|
|
SDL_memset(aptr, ~0, pad);
|
2001-04-26 16:45:43 +00:00
|
|
|
aptr += pad;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create the cursor */
|
|
|
|
cursor->curs = CreateCursor(
|
2006-03-06 08:11:10 +00:00
|
|
|
(HINSTANCE)GetWindowLongPtr(SDL_Window, GWLP_HINSTANCE),
|
2001-04-26 16:45:43 +00:00
|
|
|
hot_x, hot_y, allowed_x, allowed_y,
|
|
|
|
cursor->ands, cursor->xors);
|
|
|
|
if ( cursor->curs == NULL ) {
|
|
|
|
WIN_FreeWMCursor(NULL, cursor);
|
|
|
|
SDL_SetError("Windows couldn't create the requested cursor");
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
return(cursor);
|
|
|
|
#endif /* USE_STATIC_CURSOR */
|
|
|
|
}
|
|
|
|
|
|
|
|
int WIN_ShowWMCursor(_THIS, WMcursor *cursor)
|
|
|
|
{
|
|
|
|
POINT mouse_pos;
|
|
|
|
|
2009-04-02 04:43:36 +00:00
|
|
|
if ( !this->screen ) {
|
2001-04-26 16:45:43 +00:00
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the window cursor to our cursor, if applicable */
|
|
|
|
if ( cursor != NULL ) {
|
|
|
|
SDL_hcursor = cursor->curs;
|
|
|
|
} else {
|
|
|
|
SDL_hcursor = NULL;
|
|
|
|
}
|
|
|
|
GetCursorPos(&mouse_pos);
|
|
|
|
if ( PtInRect(&SDL_bounds, mouse_pos) ) {
|
|
|
|
SetCursor(SDL_hcursor);
|
|
|
|
}
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void WIN_WarpWMCursor(_THIS, Uint16 x, Uint16 y)
|
|
|
|
{
|
2009-04-02 04:43:36 +00:00
|
|
|
if ( mouse_relative) {
|
2001-04-26 16:45:43 +00:00
|
|
|
/* RJR: March 28, 2000
|
|
|
|
leave physical cursor at center of screen if
|
|
|
|
mouse hidden and grabbed */
|
|
|
|
SDL_PrivateMouseMotion(0, 0, x, y);
|
|
|
|
} else {
|
2002-10-11 08:09:26 +00:00
|
|
|
POINT pt;
|
2009-04-02 04:43:36 +00:00
|
|
|
|
|
|
|
/* With DirectInput the position doesn't follow
|
|
|
|
* the cursor, so it is set manually */
|
|
|
|
if ( DINPUT() ) {
|
|
|
|
SDL_PrivateMouseMotion(0, 0, x, y);
|
|
|
|
}
|
|
|
|
|
2001-04-26 16:45:43 +00:00
|
|
|
pt.x = x;
|
|
|
|
pt.y = y;
|
|
|
|
ClientToScreen(SDL_Window, &pt);
|
|
|
|
SetCursorPos(pt.x, pt.y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the current mouse state and position */
|
|
|
|
void WIN_UpdateMouse(_THIS)
|
|
|
|
{
|
|
|
|
POINT pt;
|
|
|
|
|
2009-04-02 04:43:36 +00:00
|
|
|
/* Always unset SDL_APPMOUSEFOCUS to give the WM_MOUSEMOVE event
|
|
|
|
* handler a chance to install a TRACKMOUSEEVENT */
|
|
|
|
SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
|
|
|
|
|
|
|
|
GetCursorPos(&pt);
|
|
|
|
ScreenToClient(SDL_Window, &pt);
|
|
|
|
SDL_PrivateMouseMotion(0,0, (Sint16)pt.x, (Sint16)pt.y);
|
2001-04-26 16:45:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Check to see if we need to enter or leave mouse relative mode */
|
|
|
|
void WIN_CheckMouseMode(_THIS)
|
|
|
|
{
|
2006-01-19 08:43:00 +00:00
|
|
|
#ifndef _WIN32_WCE
|
2001-04-26 16:45:43 +00:00
|
|
|
/* If the mouse is hidden and input is grabbed, we use relative mode */
|
|
|
|
if ( !(SDL_cursorstate & CURSOR_VISIBLE) &&
|
|
|
|
(this->input_grab != SDL_GRAB_OFF) ) {
|
|
|
|
mouse_relative = 1;
|
|
|
|
} else {
|
|
|
|
mouse_relative = 0;
|
|
|
|
}
|
2006-01-19 08:43:00 +00:00
|
|
|
#else
|
|
|
|
mouse_relative = 0;
|
|
|
|
#endif
|
2001-04-26 16:45:43 +00:00
|
|
|
}
|