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@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
PrintBITMAP(FILE * out,char * bits,int w,int h)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 */
memnot(Uint8 * dst,Uint8 * src,int len)78 static void memnot(Uint8 *dst, Uint8 *src, int len)
79 {
80 while ( len-- > 0 )
81 *dst++ = ~*src++;
82 }
memxor(Uint8 * dst,Uint8 * src1,Uint8 * src2,int len)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
WIN_FreeWMCursor(_THIS,WMcursor * cursor)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
WIN_CreateWMCursor(_THIS,Uint8 * data,Uint8 * mask,int w,int h,int hot_x,int hot_y)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
WIN_ShowWMCursor(_THIS,WMcursor * cursor)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
WIN_WarpWMCursor(_THIS,Uint16 x,Uint16 y)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 */
WIN_UpdateMouse(_THIS)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 */
WIN_CheckMouseMode(_THIS)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