1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2012 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 /* Make sure XBUTTON stuff is defined that isn't in older Platform SDKs... */
28 #ifndef WM_XBUTTONDOWN
29 #define WM_XBUTTONDOWN 0x020B
30 #endif
31 #ifndef WM_XBUTTONUP
32 #define WM_XBUTTONUP 0x020C
33 #endif
34 #ifndef GET_XBUTTON_WPARAM
35 #define GET_XBUTTON_WPARAM(w) (HIWORD(w))
36 #endif
37 
38 #include "SDL_events.h"
39 #include "SDL_video.h"
40 #include "SDL_syswm.h"
41 #include "../SDL_sysvideo.h"
42 #include "../../events/SDL_sysevents.h"
43 #include "../../events/SDL_events_c.h"
44 #include "SDL_lowvideo.h"
45 #include "SDL_syswm_c.h"
46 #include "SDL_main.h"
47 #include "SDL_loadso.h"
48 
49 #ifdef WMMSG_DEBUG
50 #include "wmmsg.h"
51 #endif
52 
53 #include "../windib/SDL_gapidibvideo.h"
54 
55 #ifdef SDL_VIDEO_DRIVER_GAPI
56 #include "../gapi/SDL_gapivideo.h"
57 #endif
58 
59 #ifdef _WIN32_WCE
60 #define IsZoomed(HWND) 1
61 #define NO_GETKEYBOARDSTATE
62 #if _WIN32_WCE < 420
63 #define NO_CHANGEDISPLAYSETTINGS
64 #endif
65 #endif
66 
67 /* The window we use for everything... */
68 #ifdef _WIN32_WCE
69 LPWSTR SDL_Appname = NULL;
70 #else
71 LPSTR SDL_Appname = NULL;
72 #endif
73 Uint32 SDL_Appstyle = 0;
74 HINSTANCE SDL_Instance = NULL;
75 HWND SDL_Window = NULL;
76 RECT SDL_bounds = {0, 0, 0, 0};
77 int SDL_windowX = 0;
78 int SDL_windowY = 0;
79 int SDL_resizing = 0;
80 int mouse_relative = 0;
81 int posted = 0;
82 #ifndef NO_CHANGEDISPLAYSETTINGS
83 DEVMODE SDL_desktop_mode;
84 DEVMODE SDL_fullscreen_mode;
85 #endif
86 WORD *gamma_saved = NULL;
87 
88 
89 /* Functions called by the message processing function */
90 LONG (*HandleMessage)(_THIS, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)=NULL;
91 void (*WIN_Activate)(_THIS, BOOL active, BOOL iconic);
92 void (*WIN_RealizePalette)(_THIS);
93 void (*WIN_PaletteChanged)(_THIS, HWND window);
94 void (*WIN_WinPAINT)(_THIS, HDC hdc);
95 extern void DIB_SwapGamma(_THIS);
96 
97 #ifndef NO_GETKEYBOARDSTATE
98 #ifndef _WIN64
99 /* Variables and support functions for SDL_ToUnicode() */
100 static int codepage;
101 static int Is9xME();
102 static int GetCodePage();
103 static int WINAPI ToUnicode9xME(UINT vkey, UINT scancode, const BYTE *keystate, LPWSTR wchars, int wsize, UINT flags);
104 
105 ToUnicodeFN SDL_ToUnicode = ToUnicode9xME;
106 #endif
107 #endif /* !NO_GETKEYBOARDSTATE */
108 
109 
110 #if defined(_WIN32_WCE)
111 
112 //AdjustWindowRect is not available under WinCE 2003
113 #define AdjustWindowRect(a,b,c) (AdjustWindowRectEx((a),(b),(c),0))
114 
115 // dynamically load aygshell dll because we want SDL to work on HPC and be300
116 HINSTANCE aygshell = NULL;
117 BOOL (WINAPI *SHFullScreen)(HWND hwndRequester, DWORD dwState) = 0;
118 
119 #define SHFS_SHOWTASKBAR            0x0001
120 #define SHFS_HIDETASKBAR            0x0002
121 #define SHFS_SHOWSIPBUTTON          0x0004
122 #define SHFS_HIDESIPBUTTON          0x0008
123 #define SHFS_SHOWSTARTICON          0x0010
124 #define SHFS_HIDESTARTICON          0x0020
125 
LoadAygshell(void)126 static void LoadAygshell(void)
127 {
128 	if( !aygshell )
129 		 aygshell = SDL_LoadObject("aygshell.dll");
130 	if( (aygshell != 0) && (SHFullScreen == 0) )
131 	{
132 		SHFullScreen = (int (WINAPI *)(struct HWND__ *,unsigned long)) SDL_LoadFunction(aygshell, "SHFullScreen");
133 	}
134 }
135 
136 #endif
137 
138 /* JC 14 Mar 2006
139    This is used all over the place, in the windib driver and in the dx5 driver
140    So we may as well stick it here instead of having multiple copies scattered
141    about
142 */
WIN_FlushMessageQueue()143 void WIN_FlushMessageQueue()
144 {
145 	MSG  msg;
146 	while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) {
147 		if ( msg.message == WM_QUIT ) break;
148 		TranslateMessage( &msg );
149 		DispatchMessage( &msg );
150 	}
151 }
152 
SDL_RestoreGameMode(void)153 static void SDL_RestoreGameMode(void)
154 {
155 #ifdef _WIN32_WCE //Under ce we don't minimize, therefore no restore
156 
157 #ifdef SDL_VIDEO_DRIVER_GAPI
158 	SDL_VideoDevice *this = current_video;
159 	if(SDL_strcmp(this->name, "gapi") == 0)
160 	{
161 		if( this->hidden->gapiInfo->suspended )
162 		{
163 			this->hidden->gapiInfo->suspended = 0;
164 		}
165 	}
166 #endif
167 
168 #else
169 	ShowWindow(SDL_Window, SW_RESTORE);
170 #endif
171 
172 #ifndef NO_CHANGEDISPLAYSETTINGS
173 #ifndef _WIN32_WCE
174 	ChangeDisplaySettings(&SDL_fullscreen_mode, CDS_FULLSCREEN);
175 #endif
176 #endif /* NO_CHANGEDISPLAYSETTINGS */
177 }
SDL_RestoreDesktopMode(void)178 static void SDL_RestoreDesktopMode(void)
179 {
180 
181 #ifdef _WIN32_WCE
182 
183 #ifdef SDL_VIDEO_DRIVER_GAPI
184 	SDL_VideoDevice *this = current_video;
185 	if(SDL_strcmp(this->name, "gapi") == 0)
186 	{
187 		if( !this->hidden->gapiInfo->suspended )
188 		{
189 			this->hidden->gapiInfo->suspended = 1;
190 		}
191 	}
192 #endif
193 
194 #else
195 	/* WinCE does not have a taskbar, so minimizing is not convenient */
196 	ShowWindow(SDL_Window, SW_MINIMIZE);
197 #endif
198 
199 #ifndef NO_CHANGEDISPLAYSETTINGS
200 #ifndef _WIN32_WCE
201 	ChangeDisplaySettings(NULL, 0);
202 #endif
203 #endif /* NO_CHANGEDISPLAYSETTINGS */
204 }
205 
206 #ifdef WM_MOUSELEAVE
207 /*
208    Special code to handle mouse leave events - this sucks...
209    http://support.microsoft.com/support/kb/articles/q183/1/07.asp
210 
211    TrackMouseEvent() is only available on Win98 and WinNT.
212    _TrackMouseEvent() is available on Win95, but isn't yet in the mingw32
213    development environment, and only works on systems that have had IE 3.0
214    or newer installed on them (which is not the case with the base Win95).
215    Therefore, we implement our own version of _TrackMouseEvent() which
216    uses our own implementation if TrackMouseEvent() is not available.
217 */
218 static BOOL (WINAPI *_TrackMouseEvent)(TRACKMOUSEEVENT *ptme) = NULL;
219 
220 static VOID CALLBACK
TrackMouseTimerProc(HWND hWnd,UINT uMsg,UINT idEvent,DWORD dwTime)221 TrackMouseTimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
222 {
223 	union { RECT rect; POINT pt; } rectpt;  /* prevent type-punning issue. */
224 	POINT pt;
225 
226 	GetClientRect(hWnd, &rectpt.rect);
227 	MapWindowPoints(hWnd, NULL, &rectpt.pt, 2);
228 	GetCursorPos(&pt);
229 	if ( !PtInRect(&rectpt.rect, pt) || (WindowFromPoint(pt) != hWnd) ) {
230 		if ( !KillTimer(hWnd, idEvent) ) {
231 			/* Error killing the timer! */
232 		}
233 		PostMessage(hWnd, WM_MOUSELEAVE, 0, 0);
234 	}
235 }
WIN_TrackMouseEvent(TRACKMOUSEEVENT * ptme)236 static BOOL WINAPI WIN_TrackMouseEvent(TRACKMOUSEEVENT *ptme)
237 {
238 	if ( ptme->dwFlags == TME_LEAVE ) {
239 		return SetTimer(ptme->hwndTrack, ptme->dwFlags, 100,
240 		                (TIMERPROC)TrackMouseTimerProc) != 0;
241 	}
242 	return FALSE;
243 }
244 #endif /* WM_MOUSELEAVE */
245 
246 int sysevents_mouse_pressed = 0;
247 
248 /* The main Win32 event handler
249 DJM: This is no longer static as (DX5/DIB)_CreateWindow needs it
250 */
WinMessage(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)251 LRESULT CALLBACK WinMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
252 {
253 	SDL_VideoDevice *this = current_video;
254 #ifdef WMMSG_DEBUG
255 	fprintf(stderr, "Received windows message:  ");
256 	if ( msg > MAX_WMMSG ) {
257 		fprintf(stderr, "%d", msg);
258 	} else {
259 		fprintf(stderr, "%s", wmtab[msg]);
260 	}
261 	fprintf(stderr, " -- 0x%X, 0x%X\n", wParam, lParam);
262 #endif
263 	switch (msg) {
264 
265 		case WM_ACTIVATE: {
266 			SDL_VideoDevice *this = current_video;
267 			BOOL active, minimized;
268 			Uint8 appstate;
269 
270 			minimized = HIWORD(wParam);
271 			active = (LOWORD(wParam) != WA_INACTIVE) && !minimized;
272 			if ( active ) {
273 				/* Gain the following states */
274 				appstate = SDL_APPACTIVE|SDL_APPINPUTFOCUS;
275 				if ( !(SDL_GetAppState() & SDL_APPINPUTFOCUS) ) {
276 					if ( this->input_grab != SDL_GRAB_OFF ) {
277 						WIN_GrabInput(this, SDL_GRAB_ON);
278 					}
279 					if ( ! DDRAW_FULLSCREEN() ) {
280 						DIB_SwapGamma(this);
281 					}
282 					if ( WINDIB_FULLSCREEN() ) {
283 						SDL_RestoreGameMode();
284 					}
285 				}
286 #if defined(_WIN32_WCE)
287 				if ( WINDIB_FULLSCREEN() ) {
288 					LoadAygshell();
289 					if( SHFullScreen )
290 						SHFullScreen(SDL_Window, SHFS_HIDESTARTICON|SHFS_HIDETASKBAR|SHFS_HIDESIPBUTTON);
291 					else
292 						ShowWindow(FindWindow(TEXT("HHTaskBar"),NULL),SW_HIDE);
293 				}
294 #endif
295 				posted = SDL_PrivateAppActive(1, appstate);
296 			} else {
297 				/* Lose the following states */
298 				appstate = SDL_APPINPUTFOCUS;
299 				if ( minimized ) {
300 					appstate |= SDL_APPACTIVE;
301 				}
302 
303 				if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) {
304 					if ( this->input_grab != SDL_GRAB_OFF ) {
305 						WIN_GrabInput(this, SDL_GRAB_OFF);
306 					}
307 					if ( ! DDRAW_FULLSCREEN() ) {
308 						DIB_SwapGamma(this);
309 					}
310 					if ( WINDIB_FULLSCREEN() ) {
311 						appstate |= SDL_APPMOUSEFOCUS;
312 						SDL_RestoreDesktopMode();
313 						/* A fullscreen app gets hidden but will not get a minimize event */
314 						appstate |= (SDL_APPACTIVE | SDL_APPMOUSEFOCUS);
315 #if defined(_WIN32_WCE)
316 						LoadAygshell();
317 						if( SHFullScreen )
318 							SHFullScreen(SDL_Window, SHFS_SHOWSTARTICON|SHFS_SHOWTASKBAR|SHFS_SHOWSIPBUTTON);
319 						else
320 							ShowWindow(FindWindow(TEXT("HHTaskBar"),NULL),SW_SHOW);
321 #endif
322 					}
323 				}
324 				posted = SDL_PrivateAppActive(0, appstate);
325 			}
326 			WIN_Activate(this, active, minimized);
327 			return(0);
328 		}
329 		break;
330 
331 		case WM_MOUSEMOVE: {
332 
333 #ifdef WM_MOUSELEAVE
334 			if ( SDL_VideoSurface ) {
335 				/* mouse has entered the window */
336 
337 				if ( !(SDL_GetAppState() & SDL_APPMOUSEFOCUS) ) {
338 					TRACKMOUSEEVENT tme;
339 
340 					tme.cbSize = sizeof(tme);
341 					tme.dwFlags = TME_LEAVE;
342 					tme.hwndTrack = SDL_Window;
343 					_TrackMouseEvent(&tme);
344 				}
345 			}
346 #endif /* WM_MOUSELEAVE */
347 
348 			/* Mouse motion is handled in DIB_PumpEvents or
349 			 * DX5_PumpEvents, depending on the video driver
350 			 * in use */
351 
352 			posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
353 		}
354 		return(0);
355 
356 #ifdef WM_MOUSELEAVE
357 		case WM_MOUSELEAVE: {
358 
359 			if ( SDL_VideoSurface ) {
360 				/* mouse has left the window */
361 				posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
362 			}
363 		}
364 		return(0);
365 #endif /* WM_MOUSELEAVE */
366 
367 		case WM_LBUTTONDOWN:
368 		case WM_LBUTTONUP:
369 		case WM_MBUTTONDOWN:
370 		case WM_MBUTTONUP:
371 		case WM_RBUTTONDOWN:
372 		case WM_RBUTTONUP:
373 		case WM_XBUTTONDOWN:
374 		case WM_XBUTTONUP: {
375 			/* Mouse is handled by DirectInput when fullscreen */
376 			if ( SDL_VideoSurface && ! DINPUT() ) {
377 				WORD xbuttonval = 0;
378 				Uint8 button, state;
379                 int x, y;
380 
381 				/* DJM:
382 				   We want the SDL window to take focus so that
383 				   it acts like a normal windows "component"
384 				   (e.g. gains keyboard focus on a mouse click).
385 				 */
386 				SetFocus(SDL_Window);
387 
388 				/* Figure out which button to use */
389 				switch (msg) {
390 					case WM_LBUTTONDOWN:
391 						button = SDL_BUTTON_LEFT;
392 						state = SDL_PRESSED;
393 						break;
394 					case WM_LBUTTONUP:
395 						button = SDL_BUTTON_LEFT;
396 						state = SDL_RELEASED;
397 						break;
398 					case WM_MBUTTONDOWN:
399 						button = SDL_BUTTON_MIDDLE;
400 						state = SDL_PRESSED;
401 						break;
402 					case WM_MBUTTONUP:
403 						button = SDL_BUTTON_MIDDLE;
404 						state = SDL_RELEASED;
405 						break;
406 					case WM_RBUTTONDOWN:
407 						button = SDL_BUTTON_RIGHT;
408 						state = SDL_PRESSED;
409 						break;
410 					case WM_RBUTTONUP:
411 						button = SDL_BUTTON_RIGHT;
412 						state = SDL_RELEASED;
413 						break;
414 					case WM_XBUTTONDOWN:
415 						xbuttonval = GET_XBUTTON_WPARAM(wParam);
416 						button = SDL_BUTTON_X1 + xbuttonval - 1;
417 						state = SDL_PRESSED;
418 						break;
419 					case WM_XBUTTONUP:
420 						xbuttonval = GET_XBUTTON_WPARAM(wParam);
421 						button = SDL_BUTTON_X1 + xbuttonval - 1;
422 						state = SDL_RELEASED;
423 						break;
424 					default:
425 						/* Eh? Unknown button? */
426 						return(0);
427 				}
428 				if ( state == SDL_PRESSED ) {
429 					/* Grab mouse so we get up events */
430 					if ( ++sysevents_mouse_pressed > 0 ) {
431 						SetCapture(hwnd);
432 					}
433 				} else {
434 					/* Release mouse after all up events */
435 					if ( --sysevents_mouse_pressed <= 0 ) {
436 						ReleaseCapture();
437 						sysevents_mouse_pressed = 0;
438 					}
439 				}
440 				if ( mouse_relative ) {
441 				/*	RJR: March 28, 2000
442 					report internal mouse position if in relative mode */
443 					x = 0; y = 0;
444 				} else {
445 					x = (Sint16)LOWORD(lParam);
446 					y = (Sint16)HIWORD(lParam);
447 #ifdef _WIN32_WCE
448 					if (SDL_VideoSurface)
449 						GapiTransform(this->hidden->userOrientation,
450 this->hidden->hiresFix, &x, &y);
451 #endif
452 				}
453 				posted = SDL_PrivateMouseButton(
454 							state, button, x, y);
455 
456 				/*
457 				 * MSDN says:
458 				 *  "Unlike the WM_LBUTTONUP, WM_MBUTTONUP, and WM_RBUTTONUP
459 				 *   messages, an application should return TRUE from [an
460 				 *   XBUTTON message] if it processes it. Doing so will allow
461 				 *   software that simulates this message on Microsoft Windows
462 				 *   systems earlier than Windows 2000 to determine whether
463 				 *   the window procedure processed the message or called
464 				 *   DefWindowProc to process it.
465 				 */
466 				if (xbuttonval > 0)
467 					return(TRUE);
468 			}
469 		}
470 		return(0);
471 
472 
473 #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
474 		case WM_MOUSEWHEEL:
475 			if ( SDL_VideoSurface && ! DINPUT() ) {
476 				int move = (short)HIWORD(wParam);
477 				if ( move ) {
478 					Uint8 button;
479 					if ( move > 0 )
480 						button = SDL_BUTTON_WHEELUP;
481 					else
482 						button = SDL_BUTTON_WHEELDOWN;
483 					posted = SDL_PrivateMouseButton(
484 						SDL_PRESSED, button, 0, 0);
485 					posted |= SDL_PrivateMouseButton(
486 						SDL_RELEASED, button, 0, 0);
487 				}
488 			}
489 			return(0);
490 #endif
491 
492 #ifdef WM_GETMINMAXINFO
493 		/* This message is sent as a way for us to "check" the values
494 		 * of a position change.  If we don't like it, we can adjust
495 		 * the values before they are changed.
496 		 */
497 		case WM_GETMINMAXINFO: {
498 			MINMAXINFO *info;
499 			RECT        size;
500 			int x, y;
501 			int style;
502 			int width;
503 			int height;
504 
505 			/* We don't want to clobber an internal resize */
506 			if ( SDL_resizing )
507 				return(0);
508 
509 			/* We allow resizing with the SDL_RESIZABLE flag */
510 			if ( SDL_PublicSurface &&
511 				(SDL_PublicSurface->flags & SDL_RESIZABLE) ) {
512 				return(0);
513 			}
514 
515 			/* Get the current position of our window */
516 			GetWindowRect(SDL_Window, &size);
517 			x = size.left;
518 			y = size.top;
519 
520 			/* Calculate current width and height of our window */
521 			size.top = 0;
522 			size.left = 0;
523 			if ( SDL_PublicSurface != NULL ) {
524 				size.bottom = SDL_PublicSurface->h;
525 				size.right = SDL_PublicSurface->w;
526 			} else {
527 				size.bottom = 0;
528 				size.right = 0;
529 			}
530 
531 			/* DJM - according to the docs for GetMenu(), the
532 			   return value is undefined if hwnd is a child window.
533 			   Aparently it's too difficult for MS to check
534 			   inside their function, so I have to do it here.
535           		 */
536          		style = GetWindowLong(hwnd, GWL_STYLE);
537          		AdjustWindowRect(
538 				&size,
539 				style,
540             			style & WS_CHILDWINDOW ? FALSE
541 						       : GetMenu(hwnd) != NULL);
542 
543 			width = size.right - size.left;
544 			height = size.bottom - size.top;
545 
546 			/* Fix our size to the current size */
547 			info = (MINMAXINFO *)lParam;
548 			info->ptMaxSize.x = width;
549 			info->ptMaxSize.y = height;
550 			info->ptMaxPosition.x = x;
551 			info->ptMaxPosition.y = y;
552 			info->ptMinTrackSize.x = width;
553 			info->ptMinTrackSize.y = height;
554 			info->ptMaxTrackSize.x = width;
555 			info->ptMaxTrackSize.y = height;
556 		}
557 		return(0);
558 #endif /* WM_GETMINMAXINFO */
559 
560 		case WM_WINDOWPOSCHANGING: {
561 			WINDOWPOS *windowpos = (WINDOWPOS*)lParam;
562 
563 			/* When menu is at the side or top, Windows likes
564 			   to try to reposition the fullscreen window when
565 			   changing video modes.
566 			 */
567 			if ( !SDL_resizing &&
568 			     SDL_PublicSurface &&
569 			     (SDL_PublicSurface->flags & SDL_FULLSCREEN) ) {
570 				windowpos->x = 0;
571 				windowpos->y = 0;
572 			}
573 		}
574 		return(0);
575 
576 		case WM_WINDOWPOSCHANGED: {
577 			SDL_VideoDevice *this = current_video;
578 			POINT pt;
579 			int w, h;
580 
581 			GetClientRect(SDL_Window, &SDL_bounds);
582 
583 			/* avoiding type-punning here... */
584 			pt.x = SDL_bounds.left;
585 			pt.y = SDL_bounds.top;
586 			ClientToScreen(SDL_Window, &pt);
587 			SDL_bounds.left = pt.x;
588 			SDL_bounds.top = pt.y;
589 
590 			pt.x = SDL_bounds.right;
591 			pt.y = SDL_bounds.bottom;
592 			ClientToScreen(SDL_Window, &pt);
593 			SDL_bounds.right = pt.x;
594 			SDL_bounds.bottom = pt.y;
595 
596 			if ( !SDL_resizing && !IsZoomed(SDL_Window) &&
597 			     SDL_PublicSurface &&
598 				!(SDL_PublicSurface->flags & SDL_FULLSCREEN) ) {
599 				SDL_windowX = SDL_bounds.left;
600 				SDL_windowY = SDL_bounds.top;
601 			}
602 			w = SDL_bounds.right-SDL_bounds.left;
603 			h = SDL_bounds.bottom-SDL_bounds.top;
604 			if ( this->input_grab != SDL_GRAB_OFF ) {
605 				ClipCursor(&SDL_bounds);
606 			}
607 			if ( SDL_PublicSurface &&
608 				(SDL_PublicSurface->flags & SDL_RESIZABLE) ) {
609 				SDL_PrivateResize(w, h);
610 			}
611 		}
612 		break;
613 
614 		/* We need to set the cursor */
615 		case WM_SETCURSOR: {
616 			Uint16 hittest;
617 
618 			hittest = LOWORD(lParam);
619 			if ( hittest == HTCLIENT ) {
620 				SetCursor(SDL_hcursor);
621 				return(TRUE);
622 			}
623 		}
624 		break;
625 
626 		/* We are about to get palette focus! */
627 		case WM_QUERYNEWPALETTE: {
628 			WIN_RealizePalette(current_video);
629 			return(TRUE);
630 		}
631 		break;
632 
633 		/* Another application changed the palette */
634 		case WM_PALETTECHANGED: {
635 			WIN_PaletteChanged(current_video, (HWND)wParam);
636 		}
637 		break;
638 
639 		/* We were occluded, refresh our display */
640 		case WM_PAINT: {
641 			HDC hdc;
642 			PAINTSTRUCT ps;
643 
644 			hdc = BeginPaint(SDL_Window, &ps);
645 			if ( current_video->screen &&
646 			     !(current_video->screen->flags & SDL_OPENGL) ) {
647 				WIN_WinPAINT(current_video, hdc);
648 			}
649 			EndPaint(SDL_Window, &ps);
650 		}
651 		return(0);
652 
653 		/* DJM: Send an expose event in this case */
654 		case WM_ERASEBKGND: {
655 			posted = SDL_PrivateExpose();
656 		}
657 		return(0);
658 
659 		case WM_CLOSE: {
660 			if ( (posted = SDL_PrivateQuit()) )
661 				PostQuitMessage(0);
662 		}
663 		return(0);
664 
665 		case WM_DESTROY: {
666 			PostQuitMessage(0);
667 		}
668 		return(0);
669 
670 #ifndef NO_GETKEYBOARDSTATE
671 		case WM_INPUTLANGCHANGE:
672 #ifndef _WIN64
673 			codepage = GetCodePage();
674 #endif
675 		return(TRUE);
676 #endif
677 
678 		default: {
679 			/* Special handling by the video driver */
680 			if (HandleMessage) {
681 				return(HandleMessage(current_video,
682 			                     hwnd, msg, wParam, lParam));
683 			}
684 		}
685 		break;
686 	}
687 	return(DefWindowProc(hwnd, msg, wParam, lParam));
688 }
689 
690 /* Allow the application handle to be stored and retrieved later */
691 static void *SDL_handle = NULL;
692 
SDL_SetModuleHandle(void * handle)693 void SDL_SetModuleHandle(void *handle)
694 {
695 	SDL_handle = handle;
696 }
SDL_GetModuleHandle(void)697 void *SDL_GetModuleHandle(void)
698 {
699 	void *handle;
700 
701 	if ( SDL_handle ) {
702 		handle = SDL_handle;
703 	} else {
704 		handle = GetModuleHandle(NULL);
705 	}
706 	return(handle);
707 }
708 
709 /* This allows the SDL_WINDOWID hack */
710 BOOL SDL_windowid = FALSE;
711 
712 static int app_registered = 0;
713 
714 /* Register the class for this application -- exported for winmain.c */
SDL_RegisterApp(char * name,Uint32 style,void * hInst)715 int SDL_RegisterApp(char *name, Uint32 style, void *hInst)
716 {
717 	WNDCLASS class;
718 #ifdef WM_MOUSELEAVE
719 	HMODULE handle;
720 #endif
721 
722 	/* Only do this once... */
723 	if ( app_registered ) {
724 		++app_registered;
725 		return(0);
726 	}
727 
728 #ifndef CS_BYTEALIGNCLIENT
729 #define CS_BYTEALIGNCLIENT	0
730 #endif
731 	if ( ! name && ! SDL_Appname ) {
732 		name = "SDL_app";
733 		SDL_Appstyle = CS_BYTEALIGNCLIENT;
734 		SDL_Instance = hInst ? hInst : SDL_GetModuleHandle();
735 	}
736 
737 	if ( name ) {
738 #ifdef _WIN32_WCE
739 		/* WinCE uses the UNICODE version */
740 		SDL_Appname = SDL_iconv_utf8_ucs2(name);
741 #else
742 		SDL_Appname = SDL_iconv_utf8_locale(name);
743 #endif /* _WIN32_WCE */
744 		SDL_Appstyle = style;
745 		SDL_Instance = hInst ? hInst : SDL_GetModuleHandle();
746 	}
747 
748 	/* Register the application class */
749 	class.hCursor		= NULL;
750 	class.hIcon		= LoadImage(SDL_Instance, SDL_Appname,
751 				            IMAGE_ICON,
752 	                                    0, 0, LR_DEFAULTCOLOR);
753 	class.lpszMenuName	= NULL;
754 	class.lpszClassName	= SDL_Appname;
755 	class.hbrBackground	= NULL;
756 	class.hInstance		= SDL_Instance;
757 	class.style		= SDL_Appstyle;
758 #if SDL_VIDEO_OPENGL
759 	class.style		|= CS_OWNDC;
760 #endif
761 	class.lpfnWndProc	= WinMessage;
762 	class.cbWndExtra	= 0;
763 	class.cbClsExtra	= 0;
764 	if ( ! RegisterClass(&class) ) {
765 		SDL_SetError("Couldn't register application class");
766 		return(-1);
767 	}
768 
769 #ifdef WM_MOUSELEAVE
770 	/* Get the version of TrackMouseEvent() we use */
771 	_TrackMouseEvent = NULL;
772 	handle = GetModuleHandle("USER32.DLL");
773 	if ( handle ) {
774 		_TrackMouseEvent = (BOOL (WINAPI *)(TRACKMOUSEEVENT *))GetProcAddress(handle, "TrackMouseEvent");
775 	}
776 	if ( _TrackMouseEvent == NULL ) {
777 		_TrackMouseEvent = WIN_TrackMouseEvent;
778 	}
779 #endif /* WM_MOUSELEAVE */
780 
781 #ifndef NO_GETKEYBOARDSTATE
782 #ifndef _WIN64
783 	/* Initialise variables for SDL_ToUnicode() */
784 	codepage = GetCodePage();
785 
786 	/* Cygwin headers don't match windows.h, so we have to cast around a
787 	   const issue here... */
788 	SDL_ToUnicode = Is9xME() ? ToUnicode9xME : (ToUnicodeFN) ToUnicode;
789 #endif
790 #endif /* NO_GETKEYBOARDSTATE */
791 
792 	app_registered = 1;
793 	return(0);
794 }
795 
796 /* Unregisters the windowclass registered in SDL_RegisterApp above. */
SDL_UnregisterApp()797 void SDL_UnregisterApp()
798 {
799 	WNDCLASS class;
800 
801 	/* SDL_RegisterApp might not have been called before */
802 	if ( !app_registered ) {
803 		return;
804 	}
805 	--app_registered;
806 	if ( app_registered == 0 ) {
807 		/* Check for any registered window classes. */
808 		if ( GetClassInfo(SDL_Instance, SDL_Appname, &class) ) {
809 			UnregisterClass(SDL_Appname, SDL_Instance);
810 		}
811 		SDL_free(SDL_Appname);
812 		SDL_Appname = NULL;
813 	}
814 }
815 
816 #ifndef NO_GETKEYBOARDSTATE
817 #ifndef _WIN64
818 /* JFP: Implementation of ToUnicode() that works on 9x/ME/2K/XP */
819 
Is9xME()820 static int Is9xME()
821 {
822 	OSVERSIONINFO   info;
823 
824 	SDL_memset(&info, 0, sizeof(info));
825 	info.dwOSVersionInfoSize = sizeof(info);
826 	if (!GetVersionEx(&info)) {
827 		return 0;
828 	}
829 	return (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
830 }
831 
GetCodePage()832 static int GetCodePage()
833 {
834 	char	buff[8];
835 	int	lcid = MAKELCID(LOWORD(GetKeyboardLayout(0)), SORT_DEFAULT);
836 	int	cp = GetACP();
837 
838 	if (GetLocaleInfo(lcid, LOCALE_IDEFAULTANSICODEPAGE, buff, sizeof(buff))) {
839 		cp = SDL_atoi(buff);
840 	}
841 	return cp;
842 }
843 
ToUnicode9xME(UINT vkey,UINT scancode,const BYTE * keystate,LPWSTR wchars,int wsize,UINT flags)844 static int WINAPI ToUnicode9xME(UINT vkey, UINT scancode, const BYTE *keystate, LPWSTR wchars, int wsize, UINT flags)
845 {
846 	BYTE	chars[2];
847 
848 	/* arg #3 should be const BYTE *, but cygwin lists it as PBYTE. */
849 	if (ToAsciiEx(vkey, scancode, (PBYTE) keystate, (WORD*)chars, 0, GetKeyboardLayout(0)) == 1) {
850 		return MultiByteToWideChar(codepage, 0, (LPCSTR) chars, 1, wchars, wsize);
851 	}
852 	return 0;
853 }
854 #endif
855 #endif /* !NO_GETKEYBOARDSTATE */
856