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