comparison src/video/wincommon/SDL_sysevents.c @ 0:74212992fb08

Initial revision
author Sam Lantinga <slouken@lokigames.com>
date Thu, 26 Apr 2001 16:45:43 +0000
parents
children cf2af46e9e2a
comparison
equal deleted inserted replaced
-1:000000000000 0:74212992fb08
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 <stdio.h>
30 #include <windows.h>
31
32 #include "SDL_getenv.h"
33 #include "SDL_events.h"
34 #include "SDL_video.h"
35 #include "SDL_error.h"
36 #include "SDL_syswm.h"
37 #include "SDL_sysevents.h"
38 #include "SDL_events_c.h"
39 #include "SDL_sysvideo.h"
40 #include "SDL_lowvideo.h"
41 #include "SDL_syswm_c.h"
42 #include "SDL_main.h"
43
44 #ifdef WMMSG_DEBUG
45 #include "wmmsg.h"
46 #endif
47
48 #ifdef _WIN32_WCE
49 #define NO_GETKEYBOARDSTATE
50 #endif
51
52 /* The window we use for everything... */
53 const char *SDL_Appname = NULL;
54 HINSTANCE SDL_Instance = NULL;
55 HWND SDL_Window = NULL;
56 RECT SDL_bounds = {0, 0, 0, 0};
57 int SDL_resizing = 0;
58 int mouse_relative = 0;
59 int posted = 0;
60
61
62 /* Functions called by the message processing function */
63 LONG
64 (*HandleMessage)(_THIS, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)=NULL;
65 void (*WIN_RealizePalette)(_THIS);
66 void (*WIN_PaletteChanged)(_THIS, HWND window);
67 void (*WIN_SwapGamma)(_THIS);
68 void (*WIN_WinPAINT)(_THIS, HDC hdc);
69
70 #ifdef WM_MOUSELEAVE
71 /*
72 Special code to handle mouse leave events - this sucks...
73 http://support.microsoft.com/support/kb/articles/q183/1/07.asp
74
75 TrackMouseEvent() is only available on Win98 and WinNT.
76 _TrackMouseEvent() is available on Win95, but isn't yet in the mingw32
77 development environment, and only works on systems that have had IE 3.0
78 or newer installed on them (which is not the case with the base Win95).
79 Therefore, we implement our own version of _TrackMouseEvent() which
80 uses our own implementation if TrackMouseEvent() is not available.
81 */
82 static BOOL (WINAPI *_TrackMouseEvent)(TRACKMOUSEEVENT *ptme) = NULL;
83
84 static VOID CALLBACK
85 TrackMouseTimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
86 {
87 RECT rect;
88 POINT pt;
89
90 GetClientRect(hWnd, &rect);
91 MapWindowPoints(hWnd, NULL, (LPPOINT)&rect, 2);
92 GetCursorPos(&pt);
93 if ( !PtInRect(&rect, pt) || (WindowFromPoint(pt) != hWnd) ) {
94 if ( !KillTimer(hWnd, idEvent) ) {
95 /* Error killing the timer! */
96 }
97 PostMessage(hWnd, WM_MOUSELEAVE, 0, 0);
98 }
99 }
100 static BOOL WINAPI WIN_TrackMouseEvent(TRACKMOUSEEVENT *ptme)
101 {
102 if ( ptme->dwFlags == TME_LEAVE ) {
103 return SetTimer(ptme->hwndTrack, ptme->dwFlags, 100,
104 (TIMERPROC)TrackMouseTimerProc);
105 }
106 return FALSE;
107 }
108 #endif /* WM_MOUSELEAVE */
109
110 /* Function to retrieve the current keyboard modifiers */
111 static void WIN_GetKeyboardState(void)
112 {
113 #ifndef NO_GETKEYBOARDSTATE
114 SDLMod state;
115 BYTE keyboard[256];
116
117 state = KMOD_NONE;
118 if ( GetKeyboardState(keyboard) ) {
119 if ( keyboard[VK_LSHIFT] & 0x80) {
120 state |= KMOD_LSHIFT;
121 }
122 if ( keyboard[VK_RSHIFT] & 0x80) {
123 state |= KMOD_RSHIFT;
124 }
125 if ( keyboard[VK_LCONTROL] & 0x80) {
126 state |= KMOD_LCTRL;
127 }
128 if ( keyboard[VK_RCONTROL] & 0x80) {
129 state |= KMOD_RCTRL;
130 }
131 if ( keyboard[VK_LMENU] & 0x80) {
132 state |= KMOD_LALT;
133 }
134 if ( keyboard[VK_RMENU] & 0x80) {
135 state |= KMOD_RALT;
136 }
137 if ( keyboard[VK_NUMLOCK] & 0x80) {
138 state |= KMOD_NUM;
139 }
140 if ( keyboard[VK_CAPITAL] & 0x80) {
141 state |= KMOD_CAPS;
142 }
143 }
144 SDL_SetModState(state);
145 #endif /* !NO_GETKEYBOARDSTATE */
146 }
147
148 /* The main Win32 event handler */
149 static LONG CALLBACK WinMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
150 {
151 SDL_VideoDevice *this = current_video;
152 static int mouse_pressed = 0;
153 static int in_window = 0;
154 #ifdef WMMSG_DEBUG
155 fprintf(stderr, "Received windows message: ");
156 if ( msg > MAX_WMMSG ) {
157 fprintf(stderr, "%d", msg);
158 } else {
159 fprintf(stderr, "%s", wmtab[msg]);
160 }
161 fprintf(stderr, " -- 0x%X, 0x%X\n", wParam, lParam);
162 #endif
163 switch (msg) {
164
165 case WM_ACTIVATE: {
166 SDL_VideoDevice *this = current_video;
167 BOOL minimized;
168 Uint8 appstate;
169
170 minimized = HIWORD(wParam);
171 if ( !minimized && (LOWORD(wParam) != WA_INACTIVE) ) {
172 /* Gain the following states */
173 appstate = SDL_APPACTIVE|SDL_APPINPUTFOCUS;
174 if ( this->input_grab != SDL_GRAB_OFF ) {
175 WIN_GrabInput(this, SDL_GRAB_ON);
176 }
177 if ( !(SDL_GetAppState()&SDL_APPINPUTFOCUS) ) {
178 WIN_SwapGamma(this);
179 }
180 posted = SDL_PrivateAppActive(1, appstate);
181 WIN_GetKeyboardState();
182 } else {
183 /* Lose the following states */
184 appstate = SDL_APPINPUTFOCUS;
185 if ( minimized ) {
186 appstate |= SDL_APPACTIVE;
187 }
188 if ( this->input_grab != SDL_GRAB_OFF ) {
189 WIN_GrabInput(this, SDL_GRAB_OFF);
190 }
191 if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) {
192 WIN_SwapGamma(this);
193 }
194 posted = SDL_PrivateAppActive(0, appstate);
195 }
196 return(0);
197 }
198 break;
199
200 case WM_MOUSEMOVE: {
201
202 /* Mouse is handled by DirectInput when fullscreen */
203 if ( SDL_VideoSurface && ! DIRECTX_FULLSCREEN() ) {
204 Sint16 x, y;
205
206 /* mouse has entered the window */
207 if ( ! in_window ) {
208 #ifdef WM_MOUSELEAVE
209 TRACKMOUSEEVENT tme;
210
211 tme.cbSize = sizeof(tme);
212 tme.dwFlags = TME_LEAVE;
213 tme.hwndTrack = SDL_Window;
214 _TrackMouseEvent(&tme);
215 #endif /* WM_MOUSELEAVE */
216 in_window = TRUE;
217
218 posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
219 }
220
221 /* mouse has moved within the window */
222 x = LOWORD(lParam);
223 y = HIWORD(lParam);
224 if ( mouse_relative ) {
225 POINT center;
226 center.x = (SDL_VideoSurface->w/2);
227 center.y = (SDL_VideoSurface->h/2);
228 x -= (Sint16)center.x;
229 y -= (Sint16)center.y;
230 if ( x || y ) {
231 ClientToScreen(SDL_Window, &center);
232 SetCursorPos(center.x, center.y);
233 posted = SDL_PrivateMouseMotion(0, 1, x, y);
234 }
235 } else {
236 posted = SDL_PrivateMouseMotion(0, 0, x, y);
237 }
238 }
239 }
240 return(0);
241
242 #ifdef WM_MOUSELEAVE
243 case WM_MOUSELEAVE: {
244
245 /* Mouse is handled by DirectInput when fullscreen */
246 if ( SDL_VideoSurface && ! DIRECTX_FULLSCREEN() ) {
247 /* mouse has left the window */
248 /* or */
249 /* Elvis has left the building! */
250 in_window = FALSE;
251 posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
252 }
253 }
254 return(0);
255 #endif /* WM_MOUSELEAVE */
256
257 case WM_LBUTTONDOWN:
258 case WM_LBUTTONUP:
259 case WM_MBUTTONDOWN:
260 case WM_MBUTTONUP:
261 case WM_RBUTTONDOWN:
262 case WM_RBUTTONUP: {
263 /* Mouse is handled by DirectInput when fullscreen */
264 if ( SDL_VideoSurface && ! DIRECTX_FULLSCREEN() ) {
265 Sint16 x, y;
266 Uint8 button, state;
267
268 /* Figure out which button to use */
269 switch (msg) {
270 case WM_LBUTTONDOWN:
271 button = 1;
272 state = SDL_PRESSED;
273 break;
274 case WM_LBUTTONUP:
275 button = 1;
276 state = SDL_RELEASED;
277 break;
278 case WM_MBUTTONDOWN:
279 button = 2;
280 state = SDL_PRESSED;
281 break;
282 case WM_MBUTTONUP:
283 button = 2;
284 state = SDL_RELEASED;
285 break;
286 case WM_RBUTTONDOWN:
287 button = 3;
288 state = SDL_PRESSED;
289 break;
290 case WM_RBUTTONUP:
291 button = 3;
292 state = SDL_RELEASED;
293 break;
294 default:
295 /* Eh? Unknown button? */
296 return(0);
297 }
298 if ( state == SDL_PRESSED ) {
299 /* Grab mouse so we get up events */
300 if ( ++mouse_pressed > 0 ) {
301 SetCapture(hwnd);
302 }
303 } else {
304 /* Release mouse after all up events */
305 if ( --mouse_pressed <= 0 ) {
306 ReleaseCapture();
307 mouse_pressed = 0;
308 }
309 }
310 if ( mouse_relative ) {
311 /* RJR: March 28, 2000
312 report internal mouse position if in relative mode */
313 x = 0; y = 0;
314 } else {
315 x = (Sint16)LOWORD(lParam);
316 y = (Sint16)HIWORD(lParam);
317 }
318 posted = SDL_PrivateMouseButton(
319 state, button, x, y);
320 }
321 }
322 return(0);
323
324 #ifdef WM_GETMINMAXINFO
325 /* This message is sent as a way for us to "check" the values
326 * of a position change. If we don't like it, we can adjust
327 * the values before they are changed.
328 */
329 case WM_GETMINMAXINFO: {
330 MINMAXINFO *info;
331 RECT size;
332 int x, y;
333 int width;
334 int height;
335
336 /* We don't want to clobber an internal resize */
337 if ( SDL_resizing )
338 return(0);
339
340 /* We allow resizing with the SDL_RESIZABLE flag */
341 if ( SDL_PublicSurface &&
342 (SDL_PublicSurface->flags & SDL_RESIZABLE) ) {
343 return(0);
344 }
345
346 /* Get the current position of our window */
347 GetWindowRect(SDL_Window, &size);
348 x = size.left;
349 y = size.top;
350
351 /* Calculate current width and height of our window */
352 size.top = 0;
353 size.left = 0;
354 if ( SDL_PublicSurface != NULL ) {
355 size.bottom = SDL_PublicSurface->h;
356 size.right = SDL_PublicSurface->w;
357 } else {
358 size.bottom = 0;
359 size.right = 0;
360 }
361 AdjustWindowRect(&size, GetWindowLong(hwnd, GWL_STYLE),
362 FALSE);
363 width = size.right - size.left;
364 height = size.bottom - size.top;
365
366 /* Fix our size to the current size */
367 info = (MINMAXINFO *)lParam;
368 info->ptMaxSize.x = width;
369 info->ptMaxSize.y = height;
370 info->ptMaxPosition.x = x;
371 info->ptMaxPosition.y = y;
372 info->ptMinTrackSize.x = width;
373 info->ptMinTrackSize.y = height;
374 info->ptMaxTrackSize.x = width;
375 info->ptMaxTrackSize.y = height;
376 }
377 return(0);
378 #endif /* WM_GETMINMAXINFO */
379
380 case WM_MOVE: {
381 SDL_VideoDevice *this = current_video;
382
383 GetClientRect(SDL_Window, &SDL_bounds);
384 ClientToScreen(SDL_Window, (LPPOINT)&SDL_bounds);
385 ClientToScreen(SDL_Window, (LPPOINT)&SDL_bounds+1);
386 if ( this->input_grab != SDL_GRAB_OFF ) {
387 ClipCursor(&SDL_bounds);
388 }
389 }
390 break;
391
392 case WM_SIZE: {
393 if ( SDL_PublicSurface &&
394 (SDL_PublicSurface->flags & SDL_RESIZABLE) ) {
395 SDL_PrivateResize(LOWORD(lParam), HIWORD(lParam));
396 }
397 return(0);
398 }
399 break;
400
401 /* We need to set the cursor */
402 case WM_SETCURSOR: {
403 Uint16 hittest;
404
405 hittest = LOWORD(lParam);
406 if ( hittest == HTCLIENT ) {
407 SetCursor(SDL_hcursor);
408 return(TRUE);
409 }
410 }
411 break;
412
413 /* We are about to get palette focus! */
414 case WM_QUERYNEWPALETTE: {
415 WIN_RealizePalette(current_video);
416 return(TRUE);
417 }
418 break;
419
420 /* Another application changed the palette */
421 case WM_PALETTECHANGED: {
422 WIN_PaletteChanged(current_video, (HWND)wParam);
423 }
424 break;
425
426 /* We were occluded, refresh our display */
427 case WM_PAINT: {
428 HDC hdc;
429 PAINTSTRUCT ps;
430
431 hdc = BeginPaint(SDL_Window, &ps);
432 if ( current_video->screen &&
433 !(current_video->screen->flags & SDL_OPENGL) ) {
434 WIN_WinPAINT(current_video, hdc);
435 }
436 EndPaint(SDL_Window, &ps);
437 }
438 return(0);
439
440 case WM_ERASEBKGND: {
441 /* Just do nothing */ ;
442 }
443 return(1);
444
445 case WM_CLOSE: {
446 if ( (posted = SDL_PrivateQuit()) )
447 PostQuitMessage(0);
448 }
449 return(0);
450
451 case WM_DESTROY: {
452 PostQuitMessage(0);
453 }
454 return(0);
455
456 default: {
457 /* Special handling by the video driver */
458 if (HandleMessage) {
459 return(HandleMessage(current_video,
460 hwnd, msg, wParam, lParam));
461 }
462 }
463 break;
464 }
465 return(DefWindowProc(hwnd, msg, wParam, lParam));
466 }
467
468 /* This allows the SDL_WINDOWID hack */
469 const char *SDL_windowid = NULL;
470
471 /* Register the class for this application -- exported for winmain.c */
472 int SDL_RegisterApp(char *name, Uint32 style, void *hInst)
473 {
474 static int initialized = 0;
475 WNDCLASS class;
476 #ifdef WM_MOUSELEAVE
477 HMODULE handle;
478 #endif
479
480 /* Only do this once... */
481 if ( initialized ) {
482 return(0);
483 }
484
485 /* This function needs to be passed the correct process handle
486 by the application. The following call just returns a handle
487 to the SDL DLL, which is useless for our purposes and causes
488 DirectInput to fail to initialize.
489 */
490 if ( ! hInst ) {
491 hInst = GetModuleHandle(NULL);
492 }
493
494 /* Register the application class */
495 class.hCursor = NULL;
496 #ifdef _WIN32_WCE
497 {
498 /* WinCE uses the UNICODE version */
499 int nLen = strlen(name);
500 LPWSTR lpszW = alloca((nLen+1)*2);
501 MultiByteToWideChar(CP_ACP, 0, name, -1, lpszW, nLen);
502 class.hIcon = LoadImage(hInst, lpszW, IMAGE_ICON,
503 0, 0, LR_DEFAULTCOLOR);
504 class.lpszMenuName = lpszW;
505 class.lpszClassName = lpszW;
506 }
507 #else
508 class.hIcon = LoadImage(hInst, name, IMAGE_ICON,
509 0, 0, LR_DEFAULTCOLOR);
510 class.lpszMenuName = "(none)";
511 class.lpszClassName = name;
512 #endif /* _WIN32_WCE */
513 class.hbrBackground = NULL;
514 class.hInstance = hInst ? hInst : GetModuleHandle(0);
515 class.style = style;
516 #ifdef HAVE_OPENGL
517 class.style |= CS_OWNDC;
518 #endif
519 class.lpfnWndProc = WinMessage;
520 class.cbWndExtra = 0;
521 class.cbClsExtra = 0;
522 if ( ! RegisterClass(&class) ) {
523 SDL_SetError("Couldn't register application class");
524 return(-1);
525 }
526 SDL_Appname = name;
527 SDL_Instance = hInst;
528
529 #ifdef WM_MOUSELEAVE
530 /* Get the version of TrackMouseEvent() we use */
531 _TrackMouseEvent = NULL;
532 handle = GetModuleHandle("USER32.DLL");
533 if ( handle ) {
534 _TrackMouseEvent = (BOOL (WINAPI *)(TRACKMOUSEEVENT *))GetProcAddress(handle, "TrackMouseEvent");
535 }
536 if ( _TrackMouseEvent == NULL ) {
537 _TrackMouseEvent = WIN_TrackMouseEvent;
538 }
539 #endif /* WM_MOUSELEAVE */
540
541 /* Check for SDL_WINDOWID hack */
542 SDL_windowid = getenv("SDL_WINDOWID");
543
544 initialized = 1;
545 return(0);
546 }
547