Home | History | Annotate | Download | only in wincommon
      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 (at) 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_WHEELDOWN + xbuttonval;
    524 						state = SDL_PRESSED;
    525 						break;
    526 					case WM_XBUTTONUP:
    527 						xbuttonval = GET_XBUTTON_WPARAM(wParam);
    528 						button = SDL_BUTTON_WHEELDOWN + xbuttonval;
    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 */
    925