Home | History | Annotate | Download | only in wincommon
      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 #define WIN32_LEAN_AND_MEAN
     25 #include <windows.h>
     26 
     27 #include "SDL_mouse.h"
     28 #include "../../events/SDL_events_c.h"
     29 #include "../SDL_cursor_c.h"
     30 #include "SDL_sysmouse_c.h"
     31 #include "SDL_lowvideo.h"
     32 
     33 #ifdef _WIN32_WCE
     34 #define USE_STATIC_CURSOR
     35 #endif
     36 
     37 HCURSOR	SDL_hcursor = NULL;		/* Exported for SDL_eventloop.c */
     38 
     39 /* The implementation dependent data for the window manager cursor */
     40 /* For some reason when creating a windows cursor, the ands and xors memory
     41    is not copied, so we need to keep track of it and free it when we are done
     42    with the cursor.  If we free the memory prematurely, the app crashes. :-}
     43 */
     44 struct WMcursor {
     45 	HCURSOR curs;
     46 #ifndef USE_STATIC_CURSOR
     47 	Uint8 *ands;
     48 	Uint8 *xors;
     49 #endif
     50 };
     51 
     52 /* Convert bits to padded bytes */
     53 #define PAD_BITS(bits)	((bits+7)/8)
     54 
     55 #ifdef CURSOR_DEBUG
     56 static void PrintBITMAP(FILE *out, char *bits, int w, int h)
     57 {
     58 	int i;
     59 	unsigned char ch;
     60 
     61 	while ( h-- > 0 ) {
     62 		for ( i=0; i<w; ++i ) {
     63 			if ( (i%8) == 0 )
     64 				ch = *bits++;
     65 			if ( ch&0x80 )
     66 				fprintf(out, "X");
     67 			else
     68 				fprintf(out, " ");
     69 			ch <<= 1;
     70 		}
     71 		fprintf(out, "\n");
     72 	}
     73 }
     74 #endif
     75 
     76 #ifndef USE_STATIC_CURSOR
     77 /* Local functions to convert the SDL cursor mask into Windows format */
     78 static void memnot(Uint8 *dst, Uint8 *src, int len)
     79 {
     80 	while ( len-- > 0 )
     81 		*dst++ = ~*src++;
     82 }
     83 static void memxor(Uint8 *dst, Uint8 *src1, Uint8 *src2, int len)
     84 {
     85 	while ( len-- > 0 )
     86 		*dst++ = (*src1++)^(*src2++);
     87 }
     88 #endif /* !USE_STATIC_CURSOR */
     89 
     90 void WIN_FreeWMCursor(_THIS, WMcursor *cursor)
     91 {
     92 #ifndef USE_STATIC_CURSOR
     93 	if ( cursor->curs == GetCursor() )
     94 		SetCursor(NULL);
     95 	if ( cursor->curs != NULL )
     96 		DestroyCursor(cursor->curs);
     97 	if ( cursor->ands != NULL )
     98 		SDL_free(cursor->ands);
     99 	if ( cursor->xors != NULL )
    100 		SDL_free(cursor->xors);
    101 #endif /* !USE_STATIC_CURSOR */
    102 	SDL_free(cursor);
    103 }
    104 
    105 WMcursor *WIN_CreateWMCursor(_THIS,
    106 		Uint8 *data, Uint8 *mask, int w, int h, int hot_x, int hot_y)
    107 {
    108 #ifdef USE_STATIC_CURSOR
    109 	WMcursor *cursor;
    110 
    111 	/* Allocate the cursor */
    112 	cursor = (WMcursor *)SDL_malloc(sizeof(*cursor));
    113 	if ( cursor ) {
    114 		cursor->curs = LoadCursor(NULL, IDC_ARROW);
    115 	}
    116 	return(cursor);
    117 #else
    118 	WMcursor *cursor;
    119 	int allowed_x;
    120 	int allowed_y;
    121 	int run, pad, i;
    122 	Uint8 *aptr, *xptr;
    123 
    124 	/* Check to make sure the cursor size is okay */
    125 	allowed_x = GetSystemMetrics(SM_CXCURSOR);
    126 	allowed_y = GetSystemMetrics(SM_CYCURSOR);
    127 	if ( (w > allowed_x) || (h > allowed_y) ) {
    128 		SDL_SetError("Only cursors of dimension (%dx%d) are allowed",
    129 							allowed_x, allowed_y);
    130 		return(NULL);
    131 	}
    132 
    133 	/* Allocate the cursor */
    134 	cursor = (WMcursor *)SDL_malloc(sizeof(*cursor));
    135 	if ( cursor == NULL ) {
    136 		SDL_SetError("Out of memory");
    137 		return(NULL);
    138 	}
    139 	cursor->curs = NULL;
    140 	cursor->ands = NULL;
    141 	cursor->xors = NULL;
    142 
    143 	/* Pad out to the normal cursor size */
    144 	run = PAD_BITS(w);
    145 	pad = PAD_BITS(allowed_x)-run;
    146 	aptr = cursor->ands = (Uint8 *)SDL_malloc((run+pad)*allowed_y);
    147 	xptr = cursor->xors = (Uint8 *)SDL_malloc((run+pad)*allowed_y);
    148 	if ( (aptr == NULL) || (xptr == NULL) ) {
    149 		WIN_FreeWMCursor(NULL, cursor);
    150 		SDL_OutOfMemory();
    151 		return(NULL);
    152 	}
    153 	for ( i=0; i<h; ++i ) {
    154 		memxor(xptr, data, mask, run);
    155 		xptr += run;
    156 		data += run;
    157 		memnot(aptr, mask, run);
    158 		mask += run;
    159 		aptr += run;
    160 		SDL_memset(xptr,  0, pad);
    161 		xptr += pad;
    162 		SDL_memset(aptr, ~0, pad);
    163 		aptr += pad;
    164 	}
    165 	pad += run;
    166 	for ( ; i<allowed_y; ++i ) {
    167 		SDL_memset(xptr,  0, pad);
    168 		xptr += pad;
    169 		SDL_memset(aptr, ~0, pad);
    170 		aptr += pad;
    171 	}
    172 
    173 	/* Create the cursor */
    174 	cursor->curs = CreateCursor(
    175 			(HINSTANCE)GetWindowLongPtr(SDL_Window, GWLP_HINSTANCE),
    176 					hot_x, hot_y, allowed_x, allowed_y,
    177 						cursor->ands, cursor->xors);
    178 	if ( cursor->curs == NULL ) {
    179 		WIN_FreeWMCursor(NULL, cursor);
    180 		SDL_SetError("Windows couldn't create the requested cursor");
    181 		return(NULL);
    182 	}
    183 	return(cursor);
    184 #endif /* USE_STATIC_CURSOR */
    185 }
    186 
    187 int WIN_ShowWMCursor(_THIS, WMcursor *cursor)
    188 {
    189 	POINT mouse_pos;
    190 
    191 	/* The fullscreen cursor must be done in software with DirectInput */
    192 	if ( !this->screen || DDRAW_FULLSCREEN() ) {
    193 		return(0);
    194 	}
    195 
    196 	/* Set the window cursor to our cursor, if applicable */
    197 	if ( cursor != NULL ) {
    198 		SDL_hcursor = cursor->curs;
    199 	} else {
    200 		SDL_hcursor = NULL;
    201 	}
    202 	GetCursorPos(&mouse_pos);
    203 	if ( PtInRect(&SDL_bounds, mouse_pos) ) {
    204 		SetCursor(SDL_hcursor);
    205 	}
    206 	return(1);
    207 }
    208 
    209 void WIN_WarpWMCursor(_THIS, Uint16 x, Uint16 y)
    210 {
    211 	if ( DDRAW_FULLSCREEN() ) {
    212 		SDL_PrivateMouseMotion(0, 0, x, y);
    213 	} else if ( mouse_relative) {
    214 		/*	RJR: March 28, 2000
    215 			leave physical cursor at center of screen if
    216 			mouse hidden and grabbed */
    217 		SDL_PrivateMouseMotion(0, 0, x, y);
    218 	} else {
    219 		POINT pt;
    220 		pt.x = x;
    221 		pt.y = y;
    222 		ClientToScreen(SDL_Window, &pt);
    223 		SetCursorPos(pt.x, pt.y);
    224 	}
    225 }
    226 
    227 /* Update the current mouse state and position */
    228 void WIN_UpdateMouse(_THIS)
    229 {
    230 	RECT rect;
    231 	POINT pt;
    232 
    233 	if ( ! DDRAW_FULLSCREEN() ) {
    234 		GetClientRect(SDL_Window, &rect);
    235 		GetCursorPos(&pt);
    236 		MapWindowPoints(NULL, SDL_Window, &pt, 1);
    237 		if (PtInRect(&rect, pt) && (WindowFromPoint(pt) == SDL_Window)){
    238 			SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
    239 			SDL_PrivateMouseMotion(0,0, (Sint16)pt.x, (Sint16)pt.y);
    240 		} else {
    241 			SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
    242 		}
    243 	}
    244 }
    245 
    246 /* Check to see if we need to enter or leave mouse relative mode */
    247 void WIN_CheckMouseMode(_THIS)
    248 {
    249 #ifndef _WIN32_WCE
    250         /* If the mouse is hidden and input is grabbed, we use relative mode */
    251         if ( !(SDL_cursorstate & CURSOR_VISIBLE) &&
    252              (this->input_grab != SDL_GRAB_OFF) ) {
    253                 mouse_relative = 1;
    254         } else {
    255                 mouse_relative = 0;
    256         }
    257 #else
    258 		mouse_relative =  0;
    259 #endif
    260 }
    261