src/video/windib/SDL_dibevents.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 02 Apr 2009 04:43:36 +0000
branchSDL-1.2
changeset 4167 a6f635e5eaa6
parent 4162 3b7fc3416601
child 4170 092c0bc69155
permissions -rw-r--r--
Fixed bug #611

From Tim Angus 2008-08-12 11:18:06

I'm one of the maintainers of ioquake3.org, an updated version of the
Quake 3 engine. Relatively recently, we moved ioq3 to use SDL as a
replacement for 95% of the platform specific code that was there. On the
whole it's doing a great job but unfortunately since the move we've been
getting complaints about the quality of the mouse input on the Windows
platform to the point where for many the game is unplayable. Put in
other terms, the current stable SDL 1.2 is basically not fit for purpose
if you need high quality mouse input as you do in a first person shooter.

Over the weekend I decided to pull my finger out and actually figure out
what's going on. There are basically two major problems. Firstly, when
using the "windib" driver, mouse input is gathered via the WM_MOUSEMOVE
message. Googling for this indicates that often this is known to result
in "spurious" and/or "missing" mouse movement events; this is the
primary cause of the poor mouse input. The second problem is that the
"directx" driver does not work at all in combination with OpenGL meaning
that you can't use DirectInput if your application also uses OpenGL. In
other words you're locked into using the "windib" driver and its poor
mouse input.

In order to address these problems I've done the following:

* Remove WM_MOUSEMOVE based motion event generation and replace with
calls to GetCursorPos which seems much more reliable. In order to
achieve this I've moved mouse motion out into a separate function that
is called once per DIB_PumpEvents.

* Remove the restriction on the "directx" driver being inoperable in
combination with OpenGL. There is a bug for this issues that I've
hijacked to a certain extent
(http://bugzilla.libsdl.org/show_bug.cgi?id=265). I'm the first to admit
I don't really understand why this restriction is there in the first
place. The commit message for the bug fix that introduced this
restriction (r581) isn't very elaborate and I couldn't see any other bug
tracking the issue. If anyone has more information on the bug that was
avoided by r581 it would be helpful as I/someone could then look into
addressing the problem without disabling the "directx" driver.

* I've also removed the restriction on not being allowed to use
DirectInput in windowed mode. I couldn't see any reason for this, at
least not from our perspective. I have my suspicions that it'll be
something like matching up the cursor with the mouse coordinates...

* I bumped up the DirectInput API used to version 7 in order to get
access to mouse buttons 4-7. I've had to inject a little bit of the DX7
headers into SDL there as the MinGW ones aren't up to date in this respect.
     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 #include "SDL_main.h"
    28 #include "SDL_events.h"
    29 #include "SDL_syswm.h"
    30 #include "../../events/SDL_sysevents.h"
    31 #include "../../events/SDL_events_c.h"
    32 #include "../wincommon/SDL_lowvideo.h"
    33 #include "SDL_gapidibvideo.h"
    34 #include "SDL_vkeys.h"
    35 
    36 #ifdef SDL_VIDEO_DRIVER_GAPI
    37 #include "../gapi/SDL_gapivideo.h"
    38 #endif
    39 
    40 #ifdef SDL_VIDEO_DRIVER_WINDIB
    41 #include "SDL_dibvideo.h"
    42 #endif
    43 
    44 #ifndef WM_APP
    45 #define WM_APP	0x8000
    46 #endif
    47 
    48 #ifdef _WIN32_WCE
    49 #define NO_GETKEYBOARDSTATE
    50 #endif
    51 
    52 /* The translation table from a Microsoft VK keysym to a SDL keysym */
    53 static SDLKey VK_keymap[SDLK_LAST];
    54 static SDL_keysym *TranslateKey(WPARAM vkey, UINT scancode, SDL_keysym *keysym, int pressed);
    55 static SDLKey Arrows_keymap[4];
    56 
    57 /* Masks for processing the windows KEYDOWN and KEYUP messages */
    58 #define REPEATED_KEYMASK	(1<<30)
    59 #define EXTENDED_KEYMASK	(1<<24)
    60 
    61 /* DJM: If the user setup the window for us, we want to save his window proc,
    62    and give him a chance to handle some messages. */
    63 #ifdef STRICT
    64 #define WNDPROCTYPE	WNDPROC
    65 #else
    66 #define WNDPROCTYPE	FARPROC
    67 #endif
    68 static WNDPROCTYPE userWindowProc = NULL;
    69 
    70 
    71 #ifdef SDL_VIDEO_DRIVER_GAPI
    72 
    73 WPARAM rotateKey(WPARAM key,int direction) 
    74 {
    75 	if(direction ==0 ) return key;
    76 	
    77 	switch (key) {
    78 		case 0x26: /* up */
    79 			return Arrows_keymap[(2 + direction) % 4];
    80 		case 0x27: /* right */
    81 			return Arrows_keymap[(1 + direction) % 4];
    82 		case 0x28: /* down */
    83 			return Arrows_keymap[direction % 4];
    84 		case 0x25: /* left */
    85 			return Arrows_keymap[(3 + direction) % 4];
    86 	}
    87 
    88 	return key;
    89 }
    90 
    91 #endif 
    92 
    93 
    94 /* The main Win32 event handler */
    95 LRESULT DIB_HandleMessage(_THIS, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    96 {
    97 	extern int posted;
    98 
    99 	switch (msg) {
   100 		case WM_SYSKEYDOWN:
   101 		case WM_KEYDOWN: {
   102 			SDL_keysym keysym;
   103 
   104 #ifdef SDL_VIDEO_DRIVER_GAPI
   105 			if(this->hidden->gapiInfo)
   106 			{
   107 				// Drop GAPI artefacts
   108 				if (wParam == 0x84 || wParam == 0x5B)
   109 					return 0;
   110 
   111 				wParam = rotateKey(wParam, this->hidden->gapiInfo->coordinateTransform);
   112 			}
   113 #endif 
   114 			/* Ignore repeated keys */
   115 			if ( lParam&REPEATED_KEYMASK ) {
   116 				return(0);
   117 			}
   118 			switch (wParam) {
   119 				case VK_CONTROL:
   120 					if ( lParam&EXTENDED_KEYMASK )
   121 						wParam = VK_RCONTROL;
   122 					else
   123 						wParam = VK_LCONTROL;
   124 					break;
   125 				case VK_SHIFT:
   126 					/* EXTENDED trick doesn't work here */
   127 					{
   128 					Uint8 *state = SDL_GetKeyState(NULL);
   129 					if (state[SDLK_LSHIFT] == SDL_RELEASED && (GetKeyState(VK_LSHIFT) & 0x8000)) {
   130 						wParam = VK_LSHIFT;
   131 					} else if (state[SDLK_RSHIFT] == SDL_RELEASED && (GetKeyState(VK_RSHIFT) & 0x8000)) {
   132 						wParam = VK_RSHIFT;
   133 					} else {
   134 						/* Win9x */
   135 						int sc = HIWORD(lParam) & 0xFF;
   136 
   137 						if (sc == 0x2A)
   138 							wParam = VK_LSHIFT;
   139 						else
   140 						if (sc == 0x36)
   141 							wParam = VK_RSHIFT;
   142 						else
   143 							wParam = VK_LSHIFT;
   144 					}
   145 					}
   146 					break;
   147 				case VK_MENU:
   148 					if ( lParam&EXTENDED_KEYMASK )
   149 						wParam = VK_RMENU;
   150 					else
   151 						wParam = VK_LMENU;
   152 					break;
   153 			}
   154 #ifdef NO_GETKEYBOARDSTATE
   155 			/* this is the workaround for the missing ToAscii() and ToUnicode() in CE (not necessary at KEYUP!) */
   156 			if ( SDL_TranslateUNICODE ) {
   157 				MSG m;
   158 
   159 				m.hwnd = hwnd;
   160 				m.message = msg;
   161 				m.wParam = wParam;
   162 				m.lParam = lParam;
   163 				m.time = 0;
   164 				if ( TranslateMessage(&m) && PeekMessage(&m, hwnd, 0, WM_USER, PM_NOREMOVE) && (m.message == WM_CHAR) ) {
   165 					GetMessage(&m, hwnd, 0, WM_USER);
   166 			    		wParam = m.wParam;
   167 				}
   168 			}
   169 #endif /* NO_GETKEYBOARDSTATE */
   170 			posted = SDL_PrivateKeyboard(SDL_PRESSED,
   171 				TranslateKey(wParam,HIWORD(lParam),&keysym,1));
   172 		}
   173 		return(0);
   174 
   175 		case WM_SYSKEYUP:
   176 		case WM_KEYUP: {
   177 			SDL_keysym keysym;
   178 
   179 #ifdef SDL_VIDEO_DRIVER_GAPI
   180 			if(this->hidden->gapiInfo)
   181 			{
   182 				// Drop GAPI artifacts
   183 				if (wParam == 0x84 || wParam == 0x5B)
   184 					return 0;
   185 	
   186 				wParam = rotateKey(wParam, this->hidden->gapiInfo->coordinateTransform);
   187 			}
   188 #endif
   189 
   190 			switch (wParam) {
   191 				case VK_CONTROL:
   192 					if ( lParam&EXTENDED_KEYMASK )
   193 						wParam = VK_RCONTROL;
   194 					else
   195 						wParam = VK_LCONTROL;
   196 					break;
   197 				case VK_SHIFT:
   198 					/* EXTENDED trick doesn't work here */
   199 					{
   200 					Uint8 *state = SDL_GetKeyState(NULL);
   201 					if (state[SDLK_LSHIFT] == SDL_PRESSED && !(GetKeyState(VK_LSHIFT) & 0x8000)) {
   202 						wParam = VK_LSHIFT;
   203 					} else if (state[SDLK_RSHIFT] == SDL_PRESSED && !(GetKeyState(VK_RSHIFT) & 0x8000)) {
   204 						wParam = VK_RSHIFT;
   205 					} else {
   206 						/* Win9x */
   207 						int sc = HIWORD(lParam) & 0xFF;
   208 
   209 						if (sc == 0x2A)
   210 							wParam = VK_LSHIFT;
   211 						else
   212 						if (sc == 0x36)
   213 							wParam = VK_RSHIFT;
   214 						else
   215 							wParam = VK_LSHIFT;
   216 					}
   217 					}
   218 					break;
   219 				case VK_MENU:
   220 					if ( lParam&EXTENDED_KEYMASK )
   221 						wParam = VK_RMENU;
   222 					else
   223 						wParam = VK_LMENU;
   224 					break;
   225 			}
   226 			/* Windows only reports keyup for print screen */
   227 			if ( wParam == VK_SNAPSHOT && SDL_GetKeyState(NULL)[SDLK_PRINT] == SDL_RELEASED ) {
   228 				posted = SDL_PrivateKeyboard(SDL_PRESSED,
   229 					TranslateKey(wParam,HIWORD(lParam),&keysym,1));
   230 			}
   231 			posted = SDL_PrivateKeyboard(SDL_RELEASED,
   232 				TranslateKey(wParam,HIWORD(lParam),&keysym,0));
   233 		}
   234 		return(0);
   235 #if defined(SC_SCREENSAVE) && defined(SC_MONITORPOWER)
   236 		case WM_SYSCOMMAND: {
   237 			const DWORD val = (DWORD) (wParam & 0xFFF0);
   238 			if ((val == SC_SCREENSAVE) || (val == SC_MONITORPOWER)) {
   239 				if (this->hidden->dibInfo && !allow_screensaver) {
   240 					/* Note that this doesn't stop anything on Vista
   241 					   if the screensaver has a password. */
   242 					return(0);
   243 				}
   244 			}
   245 		}
   246 		/* Fall through to default processing */
   247 #endif /* SC_SCREENSAVE && SC_MONITORPOWER */
   248 
   249 		default: {
   250 			/* Only post the event if we're watching for it */
   251 			if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
   252 			        SDL_SysWMmsg wmmsg;
   253 
   254 				SDL_VERSION(&wmmsg.version);
   255 				wmmsg.hwnd = hwnd;
   256 				wmmsg.msg = msg;
   257 				wmmsg.wParam = wParam;
   258 				wmmsg.lParam = lParam;
   259 				posted = SDL_PrivateSysWMEvent(&wmmsg);
   260 
   261 			/* DJM: If the user isn't watching for private
   262 				messages in her SDL event loop, then pass it
   263 				along to any win32 specific window proc.
   264 			 */
   265 			} else if (userWindowProc) {
   266 				return CallWindowProc(userWindowProc, hwnd, msg, wParam, lParam);
   267 			}
   268 		}
   269 		break;
   270 	}
   271 	return(DefWindowProc(hwnd, msg, wParam, lParam));
   272 }
   273 
   274 static void DIB_GenerateMouseMotionEvent(void)
   275 {
   276 	extern int mouse_relative;
   277 	extern int posted;
   278 
   279 	POINT mouse;
   280 	GetCursorPos( &mouse );
   281 
   282 	if ( mouse_relative ) {
   283 		POINT center;
   284 		center.x = (SDL_VideoSurface->w/2);
   285 		center.y = (SDL_VideoSurface->h/2);
   286 		ClientToScreen(SDL_Window, &center);
   287 
   288 		mouse.x -= (Sint16)center.x;
   289 		mouse.y -= (Sint16)center.y;
   290 		if ( mouse.x || mouse.y ) {
   291 			SetCursorPos(center.x, center.y);
   292 			posted = SDL_PrivateMouseMotion(0, 1, mouse.x, mouse.y);
   293 		}
   294 	} else if ( SDL_GetAppState() & SDL_APPMOUSEFOCUS ) {
   295 		ScreenToClient(SDL_Window, &mouse);
   296 #ifdef _WIN32_WCE
   297 		if (SDL_VideoSurface)
   298 			GapiTransform(this->hidden->userOrientation, this->hidden->hiresFix, &mouse.x, &mouse.y);
   299 #endif
   300 		posted = SDL_PrivateMouseMotion(0, 0, mouse.x, mouse.y);
   301 	}
   302 }
   303 
   304 void DIB_PumpEvents(_THIS)
   305 {
   306 	MSG msg;
   307 
   308 	while ( PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) ) {
   309 		if ( GetMessage(&msg, NULL, 0, 0) > 0 ) {
   310 			DispatchMessage(&msg);
   311 		}
   312 	}
   313 
   314 	if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) {
   315 		DIB_GenerateMouseMotionEvent( );
   316 	}
   317 }
   318 
   319 static HKL hLayoutUS = NULL;
   320 
   321 void DIB_InitOSKeymap(_THIS)
   322 {
   323 	int	i;
   324 #ifndef _WIN32_WCE
   325 	char	current_layout[KL_NAMELENGTH];
   326 
   327 	GetKeyboardLayoutName(current_layout);
   328 	//printf("Initial Keyboard Layout Name: '%s'\n", current_layout);
   329 
   330 	hLayoutUS = LoadKeyboardLayout("00000409", KLF_NOTELLSHELL);
   331 
   332 	if (!hLayoutUS) {
   333 		//printf("Failed to load US keyboard layout. Using current.\n");
   334 		hLayoutUS = GetKeyboardLayout(0);
   335 	}
   336 	LoadKeyboardLayout(current_layout, KLF_ACTIVATE);
   337 #else
   338 #if _WIN32_WCE >=420
   339 	TCHAR	current_layout[KL_NAMELENGTH];
   340 
   341 	GetKeyboardLayoutName(current_layout);
   342 	//printf("Initial Keyboard Layout Name: '%s'\n", current_layout);
   343 
   344 	hLayoutUS = LoadKeyboardLayout(L"00000409", 0);
   345 
   346 	if (!hLayoutUS) {
   347 		//printf("Failed to load US keyboard layout. Using current.\n");
   348 		hLayoutUS = GetKeyboardLayout(0);
   349 	}
   350 	LoadKeyboardLayout(current_layout, 0);
   351 #endif // _WIN32_WCE >=420
   352 #endif
   353 	/* Map the VK keysyms */
   354 	for ( i=0; i<SDL_arraysize(VK_keymap); ++i )
   355 		VK_keymap[i] = SDLK_UNKNOWN;
   356 
   357 	VK_keymap[VK_BACK] = SDLK_BACKSPACE;
   358 	VK_keymap[VK_TAB] = SDLK_TAB;
   359 	VK_keymap[VK_CLEAR] = SDLK_CLEAR;
   360 	VK_keymap[VK_RETURN] = SDLK_RETURN;
   361 	VK_keymap[VK_PAUSE] = SDLK_PAUSE;
   362 	VK_keymap[VK_ESCAPE] = SDLK_ESCAPE;
   363 	VK_keymap[VK_SPACE] = SDLK_SPACE;
   364 	VK_keymap[VK_APOSTROPHE] = SDLK_QUOTE;
   365 	VK_keymap[VK_COMMA] = SDLK_COMMA;
   366 	VK_keymap[VK_MINUS] = SDLK_MINUS;
   367 	VK_keymap[VK_PERIOD] = SDLK_PERIOD;
   368 	VK_keymap[VK_SLASH] = SDLK_SLASH;
   369 	VK_keymap[VK_0] = SDLK_0;
   370 	VK_keymap[VK_1] = SDLK_1;
   371 	VK_keymap[VK_2] = SDLK_2;
   372 	VK_keymap[VK_3] = SDLK_3;
   373 	VK_keymap[VK_4] = SDLK_4;
   374 	VK_keymap[VK_5] = SDLK_5;
   375 	VK_keymap[VK_6] = SDLK_6;
   376 	VK_keymap[VK_7] = SDLK_7;
   377 	VK_keymap[VK_8] = SDLK_8;
   378 	VK_keymap[VK_9] = SDLK_9;
   379 	VK_keymap[VK_SEMICOLON] = SDLK_SEMICOLON;
   380 	VK_keymap[VK_EQUALS] = SDLK_EQUALS;
   381 	VK_keymap[VK_LBRACKET] = SDLK_LEFTBRACKET;
   382 	VK_keymap[VK_BACKSLASH] = SDLK_BACKSLASH;
   383 	VK_keymap[VK_OEM_102] = SDLK_LESS;
   384 	VK_keymap[VK_RBRACKET] = SDLK_RIGHTBRACKET;
   385 	VK_keymap[VK_GRAVE] = SDLK_BACKQUOTE;
   386 	VK_keymap[VK_BACKTICK] = SDLK_BACKQUOTE;
   387 	VK_keymap[VK_A] = SDLK_a;
   388 	VK_keymap[VK_B] = SDLK_b;
   389 	VK_keymap[VK_C] = SDLK_c;
   390 	VK_keymap[VK_D] = SDLK_d;
   391 	VK_keymap[VK_E] = SDLK_e;
   392 	VK_keymap[VK_F] = SDLK_f;
   393 	VK_keymap[VK_G] = SDLK_g;
   394 	VK_keymap[VK_H] = SDLK_h;
   395 	VK_keymap[VK_I] = SDLK_i;
   396 	VK_keymap[VK_J] = SDLK_j;
   397 	VK_keymap[VK_K] = SDLK_k;
   398 	VK_keymap[VK_L] = SDLK_l;
   399 	VK_keymap[VK_M] = SDLK_m;
   400 	VK_keymap[VK_N] = SDLK_n;
   401 	VK_keymap[VK_O] = SDLK_o;
   402 	VK_keymap[VK_P] = SDLK_p;
   403 	VK_keymap[VK_Q] = SDLK_q;
   404 	VK_keymap[VK_R] = SDLK_r;
   405 	VK_keymap[VK_S] = SDLK_s;
   406 	VK_keymap[VK_T] = SDLK_t;
   407 	VK_keymap[VK_U] = SDLK_u;
   408 	VK_keymap[VK_V] = SDLK_v;
   409 	VK_keymap[VK_W] = SDLK_w;
   410 	VK_keymap[VK_X] = SDLK_x;
   411 	VK_keymap[VK_Y] = SDLK_y;
   412 	VK_keymap[VK_Z] = SDLK_z;
   413 	VK_keymap[VK_DELETE] = SDLK_DELETE;
   414 
   415 	VK_keymap[VK_NUMPAD0] = SDLK_KP0;
   416 	VK_keymap[VK_NUMPAD1] = SDLK_KP1;
   417 	VK_keymap[VK_NUMPAD2] = SDLK_KP2;
   418 	VK_keymap[VK_NUMPAD3] = SDLK_KP3;
   419 	VK_keymap[VK_NUMPAD4] = SDLK_KP4;
   420 	VK_keymap[VK_NUMPAD5] = SDLK_KP5;
   421 	VK_keymap[VK_NUMPAD6] = SDLK_KP6;
   422 	VK_keymap[VK_NUMPAD7] = SDLK_KP7;
   423 	VK_keymap[VK_NUMPAD8] = SDLK_KP8;
   424 	VK_keymap[VK_NUMPAD9] = SDLK_KP9;
   425 	VK_keymap[VK_DECIMAL] = SDLK_KP_PERIOD;
   426 	VK_keymap[VK_DIVIDE] = SDLK_KP_DIVIDE;
   427 	VK_keymap[VK_MULTIPLY] = SDLK_KP_MULTIPLY;
   428 	VK_keymap[VK_SUBTRACT] = SDLK_KP_MINUS;
   429 	VK_keymap[VK_ADD] = SDLK_KP_PLUS;
   430 
   431 	VK_keymap[VK_UP] = SDLK_UP;
   432 	VK_keymap[VK_DOWN] = SDLK_DOWN;
   433 	VK_keymap[VK_RIGHT] = SDLK_RIGHT;
   434 	VK_keymap[VK_LEFT] = SDLK_LEFT;
   435 	VK_keymap[VK_INSERT] = SDLK_INSERT;
   436 	VK_keymap[VK_HOME] = SDLK_HOME;
   437 	VK_keymap[VK_END] = SDLK_END;
   438 	VK_keymap[VK_PRIOR] = SDLK_PAGEUP;
   439 	VK_keymap[VK_NEXT] = SDLK_PAGEDOWN;
   440 
   441 	VK_keymap[VK_F1] = SDLK_F1;
   442 	VK_keymap[VK_F2] = SDLK_F2;
   443 	VK_keymap[VK_F3] = SDLK_F3;
   444 	VK_keymap[VK_F4] = SDLK_F4;
   445 	VK_keymap[VK_F5] = SDLK_F5;
   446 	VK_keymap[VK_F6] = SDLK_F6;
   447 	VK_keymap[VK_F7] = SDLK_F7;
   448 	VK_keymap[VK_F8] = SDLK_F8;
   449 	VK_keymap[VK_F9] = SDLK_F9;
   450 	VK_keymap[VK_F10] = SDLK_F10;
   451 	VK_keymap[VK_F11] = SDLK_F11;
   452 	VK_keymap[VK_F12] = SDLK_F12;
   453 	VK_keymap[VK_F13] = SDLK_F13;
   454 	VK_keymap[VK_F14] = SDLK_F14;
   455 	VK_keymap[VK_F15] = SDLK_F15;
   456 
   457 	VK_keymap[VK_NUMLOCK] = SDLK_NUMLOCK;
   458 	VK_keymap[VK_CAPITAL] = SDLK_CAPSLOCK;
   459 	VK_keymap[VK_SCROLL] = SDLK_SCROLLOCK;
   460 	VK_keymap[VK_RSHIFT] = SDLK_RSHIFT;
   461 	VK_keymap[VK_LSHIFT] = SDLK_LSHIFT;
   462 	VK_keymap[VK_RCONTROL] = SDLK_RCTRL;
   463 	VK_keymap[VK_LCONTROL] = SDLK_LCTRL;
   464 	VK_keymap[VK_RMENU] = SDLK_RALT;
   465 	VK_keymap[VK_LMENU] = SDLK_LALT;
   466 	VK_keymap[VK_RWIN] = SDLK_RSUPER;
   467 	VK_keymap[VK_LWIN] = SDLK_LSUPER;
   468 
   469 	VK_keymap[VK_HELP] = SDLK_HELP;
   470 #ifdef VK_PRINT
   471 	VK_keymap[VK_PRINT] = SDLK_PRINT;
   472 #endif
   473 	VK_keymap[VK_SNAPSHOT] = SDLK_PRINT;
   474 	VK_keymap[VK_CANCEL] = SDLK_BREAK;
   475 	VK_keymap[VK_APPS] = SDLK_MENU;
   476 
   477 	Arrows_keymap[3] = 0x25;
   478 	Arrows_keymap[2] = 0x26;
   479 	Arrows_keymap[1] = 0x27;
   480 	Arrows_keymap[0] = 0x28;
   481 }
   482 
   483 #define EXTKEYPAD(keypad) ((scancode & 0x100)?(mvke):(keypad))
   484 
   485 static int SDL_MapVirtualKey(int scancode, int vkey)
   486 {
   487 #ifndef _WIN32_WCE
   488 	int	mvke  = MapVirtualKeyEx(scancode & 0xFF, 1, hLayoutUS);
   489 #else
   490 	int	mvke  = MapVirtualKey(scancode & 0xFF, 1);
   491 #endif
   492 
   493 	switch(vkey) {
   494 		/* These are always correct */
   495 		case VK_DIVIDE:
   496 		case VK_MULTIPLY:
   497 		case VK_SUBTRACT:
   498 		case VK_ADD:
   499 		case VK_LWIN:
   500 		case VK_RWIN:
   501 		case VK_APPS:
   502 		/* These are already handled */
   503 		case VK_LCONTROL:
   504 		case VK_RCONTROL:
   505 		case VK_LSHIFT:
   506 		case VK_RSHIFT:
   507 		case VK_LMENU:
   508 		case VK_RMENU:
   509 		case VK_SNAPSHOT:
   510 		case VK_PAUSE:
   511 			return vkey;
   512 	}	
   513 	switch(mvke) {
   514 		/* Distinguish between keypad and extended keys */
   515 		case VK_INSERT: return EXTKEYPAD(VK_NUMPAD0);
   516 		case VK_DELETE: return EXTKEYPAD(VK_DECIMAL);
   517 		case VK_END:    return EXTKEYPAD(VK_NUMPAD1);
   518 		case VK_DOWN:   return EXTKEYPAD(VK_NUMPAD2);
   519 		case VK_NEXT:   return EXTKEYPAD(VK_NUMPAD3);
   520 		case VK_LEFT:   return EXTKEYPAD(VK_NUMPAD4);
   521 		case VK_CLEAR:  return EXTKEYPAD(VK_NUMPAD5);
   522 		case VK_RIGHT:  return EXTKEYPAD(VK_NUMPAD6);
   523 		case VK_HOME:   return EXTKEYPAD(VK_NUMPAD7);
   524 		case VK_UP:     return EXTKEYPAD(VK_NUMPAD8);
   525 		case VK_PRIOR:  return EXTKEYPAD(VK_NUMPAD9);
   526 	}
   527 	return mvke?mvke:vkey;
   528 }
   529 
   530 static SDL_keysym *TranslateKey(WPARAM vkey, UINT scancode, SDL_keysym *keysym, int pressed)
   531 {
   532 	/* Set the keysym information */
   533 	keysym->scancode = (unsigned char) scancode;
   534 	keysym->mod = KMOD_NONE;
   535 	keysym->unicode = 0;
   536 	
   537 	if ((vkey == VK_RETURN) && (scancode & 0x100)) {
   538 		/* No VK_ code for the keypad enter key */
   539 		keysym->sym = SDLK_KP_ENTER;
   540 	}
   541 	else {
   542 		keysym->sym = VK_keymap[SDL_MapVirtualKey(scancode, vkey)];
   543 	}
   544 
   545 	if ( pressed && SDL_TranslateUNICODE ) {
   546 #ifdef NO_GETKEYBOARDSTATE
   547 		/* Uh oh, better hope the vkey is close enough.. */
   548 		if((keysym->sym == vkey) || (vkey > 0x7f))
   549 		keysym->unicode = vkey;
   550 #else
   551 		BYTE	keystate[256];
   552 		Uint16	wchars[2];
   553 
   554 		GetKeyboardState(keystate);
   555 		if (SDL_ToUnicode((UINT)vkey, scancode, keystate, wchars, sizeof(wchars)/sizeof(wchars[0]), 0) == 1)
   556 		{
   557 			keysym->unicode = wchars[0];
   558 		}
   559 #endif /* NO_GETKEYBOARDSTATE */
   560 	}
   561 
   562 #if 0
   563 	{
   564 		HKL     hLayoutCurrent = GetKeyboardLayout(0);
   565 		int     sc = scancode & 0xFF;
   566 
   567 		printf("SYM:%d, VK:0x%02X, SC:0x%04X, US:(1:0x%02X, 3:0x%02X), "
   568 			"Current:(1:0x%02X, 3:0x%02X)\n",
   569 			keysym->sym, vkey, scancode,
   570 			MapVirtualKeyEx(sc, 1, hLayoutUS),
   571 			MapVirtualKeyEx(sc, 3, hLayoutUS),
   572 			MapVirtualKeyEx(sc, 1, hLayoutCurrent),
   573 			MapVirtualKeyEx(sc, 3, hLayoutCurrent)
   574 		);
   575 	}
   576 #endif
   577 	return(keysym);
   578 }
   579 
   580 int DIB_CreateWindow(_THIS)
   581 {
   582 	char *windowid = SDL_getenv("SDL_WINDOWID");
   583 
   584 	SDL_RegisterApp(NULL, 0, 0);
   585 
   586 	SDL_windowid = (windowid != NULL);
   587 	if ( SDL_windowid ) {
   588 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
   589 		/* wince 2.1 does not have strtol */
   590 		wchar_t *windowid_t = SDL_malloc((SDL_strlen(windowid) + 1) * sizeof(wchar_t));
   591 		MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, windowid, -1, windowid_t, SDL_strlen(windowid) + 1);
   592 		SDL_Window = (HWND)wcstol(windowid_t, NULL, 0);
   593 		SDL_free(windowid_t);
   594 #else
   595 		SDL_Window = (HWND)SDL_strtoull(windowid, NULL, 0);
   596 #endif
   597 		if ( SDL_Window == NULL ) {
   598 			SDL_SetError("Couldn't get user specified window");
   599 			return(-1);
   600 		}
   601 
   602 		/* DJM: we want all event's for the user specified
   603 			window to be handled by SDL.
   604 		 */
   605 		userWindowProc = (WNDPROCTYPE)GetWindowLongPtr(SDL_Window, GWLP_WNDPROC);
   606 		SetWindowLongPtr(SDL_Window, GWLP_WNDPROC, (LONG_PTR)WinMessage);
   607 	} else {
   608 		SDL_Window = CreateWindow(SDL_Appname, SDL_Appname,
   609                         (WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX),
   610                         CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL, SDL_Instance, NULL);
   611 		if ( SDL_Window == NULL ) {
   612 			SDL_SetError("Couldn't create window");
   613 			return(-1);
   614 		}
   615 		ShowWindow(SDL_Window, SW_HIDE);
   616 	}
   617 
   618 	/* JC 14 Mar 2006
   619 		Flush the message loop or this can cause big problems later
   620 		Especially if the user decides to use dialog boxes or assert()!
   621 	*/
   622 	WIN_FlushMessageQueue();
   623 
   624 	return(0);
   625 }
   626 
   627 void DIB_DestroyWindow(_THIS)
   628 {
   629 	if ( SDL_windowid ) {
   630 		SetWindowLongPtr(SDL_Window, GWLP_WNDPROC, (LONG_PTR)userWindowProc);
   631 	} else {
   632 		DestroyWindow(SDL_Window);
   633 	}
   634 	SDL_UnregisterApp();
   635 
   636 	/* JC 14 Mar 2006
   637 		Flush the message loop or this can cause big problems later
   638 		Especially if the user decides to use dialog boxes or assert()!
   639 	*/
   640 	WIN_FlushMessageQueue();
   641 }