src/video/windib/SDL_dibevents.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 17 Nov 2009 04:59:13 +0000
branchSDL-1.2
changeset 4384 6800e2560310
parent 4350 4988a4f76a09
child 5886 05fabaf401c9
permissions -rw-r--r--
Fixed bugs #882 and 865, re-opening bug #634

Ronald Lamprecht to SDL

Hi,

Sam Lantinga wrote:

The problem with that fix is that it breaks IME events again. Maybe
we can handle keyboard events differently to prevent this issue?


Spending an hour reading MSDN, analysing SDL and another hour testing the reality on XP I am really wondering how patch r4990 could have ever worked in any situation. It's main effect is to break the unicode translation and causing spurious activation events!

Why does TranslateMessage(&msg) nothing useful? Simply because it does not affect "msg" at all! All keyboard events are dispatched without the slightest change (see MSDN). TranslateMessage() just appends additional WM_CHAR, WM_DEADCHAR, WM_SYSCHAR, WM_SYSDEADCHAR event messages to the queue. But I could not find any SDL event handling routine that catches these events and transforms them to proper SDL keyevents while eliminating the corresponding WM_KEYDOWN, etc. events. Thus any IME input like the '@' generated by "Alt + 6(Numpad) + 4(Numpad)" is simply lost.

But the situation is even worse! Up to r4990 the TranslateKey()/ToUnicode() calls did evaluate dead keys and did deliver proper key events for subsequent key strokes like '´' + 'e' resulting in 'é'. ToUnicode() needs proper key state informations to be able to handle these substitutions. But unfortunatly TranslateMessage() needs the same state information and eats it up while generating the WM_CHAR messages :-( Thus the current 1.2.14 breakes the partial IME support of previous releases, too.

The key state race condition between ToUnicode() and TranslateMessage() requires to avoid any ToUnicode() usage for receiving proper WM_CHAR, etc. messages generated by TranslateMessage(). (Yes - the '@' and 'é' appear as WM_CHAR messages when unicode is switched off).

The spurious SDL activation events are *not* caused by additional WM_ACTIVATE Windows messages! Besides DIB_HandleMessage() SDL_PrivateAppActive() is called by another source which I am not yet aware of - any hints?

Thus I do strongly recommend the deletion of the TranslateMessage(&msg) call as a quick fix.

A proper support of unicode and IME requires a clean SDL keyboard input concept first. Which SDL keyboards events should be transmitted to the app when the user presses '´' + 'e' ? Within the current unicode handling the first key stroke is hidden. Even though ToUnicode() delivers the proper key SDL does ignore it in TranslateKey(). Just the composed key event is transmitted to the app. That is what you expect for text input, but the app can no longer use keys like '^' as a key button because it will never receive a key event for it!

With a given concept it seems to be necessary to regenerate SDL key events out of the WM_CHAR, etc. events and to drop all related direct WM_KEYDOWN, etc. events while the remaining basic WM_KEYDOWN, etc. events would still have to result in SDL key events.

Anyway the source of the spurious WM_ACTIVATE should be located to avoid future trouble.

Greets,

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