src/video/wincommon/SDL_sysevents.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 13 Apr 2009 08:38:04 +0000
branchSDL-1.2
changeset 4169 27c0db0fbfad
parent 4167 a6f635e5eaa6
child 4179 d7294b7c732d
permissions -rw-r--r--
Fixed bug #611

Comment #22 From Tim Angus 2009-04-02 08:45:52 (-) [reply] -------

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