src/video/wincommon/SDL_sysmouse.c
author Sam Lantinga
Sun, 29 Apr 2001 23:00:03 +0000
changeset 13 e30a8ce27c22
parent 0 74212992fb08
child 252 e8157fcb3114
permissions -rw-r--r--
Fixed double-mouse event bug on Windows using OpenGL
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998, 1999  Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 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     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     slouken@devolution.com
    21 */
    22 
    23 #ifdef SAVE_RCSID
    24 static char rcsid =
    25  "@(#) $Id$";
    26 #endif
    27 
    28 #include <stdlib.h>
    29 #include <windows.h>
    30 
    31 #include "SDL_error.h"
    32 #include "SDL_mouse.h"
    33 #include "SDL_sysmouse_c.h"
    34 #include "SDL_events_c.h"
    35 #include "SDL_cursor_c.h"
    36 #include "SDL_lowvideo.h"
    37 
    38 #ifdef _WIN32_WCE
    39 #define USE_STATIC_CURSOR
    40 #endif
    41 
    42 HCURSOR	SDL_hcursor = NULL;		/* Exported for SDL_eventloop.c */
    43 
    44 /* The implementation dependent data for the window manager cursor */
    45 /* For some reason when creating a windows cursor, the ands and xors memory
    46    is not copied, so we need to keep track of it and free it when we are done
    47    with the cursor.  If we free the memory prematurely, the app crashes. :-}
    48 */
    49 struct WMcursor {
    50 	HCURSOR curs;
    51 #ifndef USE_STATIC_CURSOR
    52 	Uint8 *ands;
    53 	Uint8 *xors;
    54 #endif
    55 };
    56 
    57 /* Convert bits to padded bytes */
    58 #define PAD_BITS(bits)	((bits+7)/8)
    59 
    60 #ifdef CURSOR_DEBUG
    61 static void PrintBITMAP(FILE *out, char *bits, int w, int h)
    62 {
    63 	int i;
    64 	unsigned char ch;
    65 
    66 	while ( h-- > 0 ) {
    67 		for ( i=0; i<w; ++i ) {
    68 			if ( (i%8) == 0 )
    69 				ch = *bits++;
    70 			if ( ch&0x80 )
    71 				fprintf(out, "X");
    72 			else
    73 				fprintf(out, " ");
    74 			ch <<= 1;
    75 		}
    76 		fprintf(out, "\n");
    77 	}
    78 }
    79 #endif
    80 
    81 #ifndef USE_STATIC_CURSOR
    82 /* Local functions to convert the SDL cursor mask into Windows format */
    83 static void memnot(Uint8 *dst, Uint8 *src, int len)
    84 {
    85 	while ( len-- > 0 )
    86 		*dst++ = ~*src++;
    87 }
    88 static void memxor(Uint8 *dst, Uint8 *src1, Uint8 *src2, int len)
    89 {
    90 	while ( len-- > 0 )
    91 		*dst++ = (*src1++)^(*src2++);
    92 }
    93 #endif /* !USE_STATIC_CURSOR */
    94 
    95 void WIN_FreeWMCursor(_THIS, WMcursor *cursor)
    96 {
    97 #ifndef USE_STATIC_CURSOR
    98 	if ( cursor->curs != NULL )
    99 		DestroyCursor(cursor->curs);
   100 	if ( cursor->ands != NULL )
   101 		free(cursor->ands);
   102 	if ( cursor->xors != NULL )
   103 		free(cursor->xors);
   104 #endif /* !USE_STATIC_CURSOR */
   105 	free(cursor);
   106 }
   107 
   108 WMcursor *WIN_CreateWMCursor(_THIS,
   109 		Uint8 *data, Uint8 *mask, int w, int h, int hot_x, int hot_y)
   110 {
   111 #ifdef USE_STATIC_CURSOR
   112 	WMcursor *cursor;
   113 
   114 	/* Allocate the cursor */
   115 	cursor = (WMcursor *)malloc(sizeof(*cursor));
   116 	if ( cursor ) {
   117 		cursor->curs = LoadCursor(NULL, IDC_ARROW);
   118 	}
   119 	return(cursor);
   120 #else
   121 	WMcursor *cursor;
   122 	int allowed_x;
   123 	int allowed_y;
   124 	int run, pad, i;
   125 	Uint8 *aptr, *xptr;
   126 
   127 	/* Check to make sure the cursor size is okay */
   128 	allowed_x = GetSystemMetrics(SM_CXCURSOR);
   129 	allowed_y = GetSystemMetrics(SM_CYCURSOR);
   130 	if ( (w > allowed_x) || (h > allowed_y) ) {
   131 		SDL_SetError("Only cursors of dimension (%dx%d) are allowed",
   132 							allowed_x, allowed_y);
   133 		return(NULL);
   134 	}
   135 
   136 	/* Allocate the cursor */
   137 	cursor = (WMcursor *)malloc(sizeof(*cursor));
   138 	if ( cursor == NULL ) {
   139 		SDL_SetError("Out of memory");
   140 		return(NULL);
   141 	}
   142 	cursor->curs = NULL;
   143 	cursor->ands = NULL;
   144 	cursor->xors = NULL;
   145 
   146 	/* Pad out to the normal cursor size */
   147 	run = PAD_BITS(w);
   148 	pad = PAD_BITS(allowed_x)-run;
   149 	aptr = cursor->ands = (Uint8 *)malloc((run+pad)*allowed_y);
   150 	xptr = cursor->xors = (Uint8 *)malloc((run+pad)*allowed_y);
   151 	if ( (aptr == NULL) || (xptr == NULL) ) {
   152 		WIN_FreeWMCursor(NULL, cursor);
   153 		SDL_OutOfMemory();
   154 		return(NULL);
   155 	}
   156 	for ( i=0; i<h; ++i ) {
   157 		memxor(xptr, data, mask, run);
   158 		xptr += run;
   159 		data += run;
   160 		memnot(aptr, mask, run);
   161 		mask += run;
   162 		aptr += run;
   163 		memset(xptr,  0, pad);
   164 		xptr += pad;
   165 		memset(aptr, ~0, pad);
   166 		aptr += pad;
   167 	}
   168 	pad += run;
   169 	for ( ; i<allowed_y; ++i ) {
   170 		memset(xptr,  0, pad);
   171 		xptr += pad;
   172 		memset(aptr, ~0, pad);
   173 		aptr += pad;
   174 	}
   175 
   176 	/* Create the cursor */
   177 	cursor->curs = CreateCursor(
   178 			(HINSTANCE)GetWindowLong(SDL_Window, GWL_HINSTANCE),
   179 					hot_x, hot_y, allowed_x, allowed_y, 
   180 						cursor->ands, cursor->xors);
   181 	if ( cursor->curs == NULL ) {
   182 		WIN_FreeWMCursor(NULL, cursor);
   183 		SDL_SetError("Windows couldn't create the requested cursor");
   184 		return(NULL);
   185 	}
   186 	return(cursor);
   187 #endif /* USE_STATIC_CURSOR */
   188 }
   189 
   190 int WIN_ShowWMCursor(_THIS, WMcursor *cursor)
   191 {
   192 	POINT mouse_pos;
   193 
   194 	/* The fullscreen cursor must be done in software with DirectInput */
   195 	if ( !this->screen || DDRAW_FULLSCREEN() ) {
   196 		return(0);
   197 	}
   198 
   199 	/* Set the window cursor to our cursor, if applicable */
   200 	if ( cursor != NULL ) {
   201 		SDL_hcursor = cursor->curs;
   202 	} else {
   203 		SDL_hcursor = NULL;
   204 	}
   205 	GetCursorPos(&mouse_pos);
   206 	if ( PtInRect(&SDL_bounds, mouse_pos) ) {
   207 		SetCursor(SDL_hcursor);
   208 	}
   209 	return(1);
   210 }
   211 
   212 void WIN_WarpWMCursor(_THIS, Uint16 x, Uint16 y)
   213 {
   214 	POINT pt;
   215 
   216 	if ( DDRAW_FULLSCREEN() ) {
   217 		x += (this->screen->offset % this->screen->pitch) /
   218 		      this->screen->format->BytesPerPixel;
   219 		y += (this->screen->offset / this->screen->pitch);
   220 		SDL_PrivateMouseMotion(0, 0, x, y);
   221 	} else if ( mouse_relative) {
   222 		/*	RJR: March 28, 2000
   223 			leave physical cursor at center of screen if
   224 			mouse hidden and grabbed */
   225 		SDL_PrivateMouseMotion(0, 0, x, y);
   226 	} else {
   227 		pt.x = x;
   228 		pt.y = y;
   229 		ClientToScreen(SDL_Window, &pt);
   230 		SetCursorPos(pt.x, pt.y);
   231 	}
   232 }
   233 
   234 /* Update the current mouse state and position */
   235 void WIN_UpdateMouse(_THIS)
   236 {
   237 	RECT rect;
   238 	POINT pt;
   239 
   240 	if ( ! DDRAW_FULLSCREEN() ) {
   241 		GetClientRect(SDL_Window, &rect);
   242 		GetCursorPos(&pt);
   243 		MapWindowPoints(NULL, SDL_Window, &pt, 1);
   244 		if (PtInRect(&rect, pt) && (WindowFromPoint(pt) == SDL_Window)){
   245 			SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
   246 			SDL_PrivateMouseMotion(0,0, (Sint16)pt.x, (Sint16)pt.y);
   247 		} else {
   248 			SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
   249 		}
   250 	}
   251 }
   252 
   253 /* Check to see if we need to enter or leave mouse relative mode */
   254 void WIN_CheckMouseMode(_THIS)
   255 {
   256         /* If the mouse is hidden and input is grabbed, we use relative mode */
   257         if ( !(SDL_cursorstate & CURSOR_VISIBLE) &&
   258              (this->input_grab != SDL_GRAB_OFF) ) {
   259                 mouse_relative = 1;
   260         } else {
   261                 mouse_relative = 0;
   262         }
   263 }