src/video/windib/SDL_dibevents.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 29 Feb 2008 13:55:44 +0000
branchSDL-1.2
changeset 4139 568c9b3c0167
parent 3981 b0d021cf41b6
child 4159 a1b03ba2fcd0
permissions -rw-r--r--
* Added configure option --enable-screensaver, to allow enabling the screensaver by default.
* Use XResetScreenSaver() instead of disabling screensaver entirely.

Full discussion summary from Erik on the SDL mailing list:

Current behaviour
=================

SDL changes the user's display power management settings without
permission from the user and without telling the user.

The interface that it uses to do so is DPMSDisable/DPMSEnable, which
should only ever be used by configuration utilities like KControl, never
by normal application programs, let alone by the libraries that they
use. Using an interface that is not at all intended for what SDL tries
to achieve means that it will not work as it should. Firstly, the power
management is completely disabled during the whole lifetime of the SDL
program, not only when it should be. Secondly, it makes SDL
non-reentrant, meaning that things will break when multiple SDL programs
are clients of the same X server simultaneously. Thirdly, no cleanup
mechanism ensures that the setting is restored if the client does not do
that (for example if it crashes).

In addition to that, this interface is broken on xorg,
[http://bugs.freedesktop.org/show_bug.cgi?id=13962], so what SDL tries
to do does not work at all on that implementation of the X Window
System. (The reason that the DPMSEnable works in KControl is that it
calls DPMSSetTimeout immediately after,
[http://websvn.kde.org/tags/KDE/3.5.9/kdebase/kcontrol/energy/energy.cpp?annotate=774532#l343]).


The problems that the current behaviour causes
==============================================
1. Information leak. When the user is away, someone might see what the
user has on the display when the user counts on the screensaver
preventing this. This does not even require physical access to the
workstation, it is enough to see it from a distance.
2. Draining battery. An SDL program that runs on a laptop will quickly
drain the battery while the user is away. The system will soon shut down
and require recharging before being usable again, while it should in
fact have consumed very little energy if the user's settings would have
been obeyed.
3. Wasting energy. Even if battery issues are not considered, energy as
such is wasted.
4. Display wear. The display may be worn out.


The problems that the current behaviour tries to solve
======================================================

1. Preventing screensaver while playing movies.
Many SDL applications are media players. They have reasons to prevent
screensavers from being activated while a movie is being played. When a
user clicks on the play button it can be interpreted as saying "play
this movie, but do not turn off the display while playing it, because I
will watch it even though I do not interact with the system".

2. Preventing screensaver when some input bypasses X.
Sometimes SDL uses input from another source than the X server, so
that the X server is bypassed. This obviously breaks the screensaver
handling. SDL tries to work around that.

3. Preventing screensaver when all input bypasses X.
There is something called Direct Graphics Access mode, where a
program takes control of both the display and the input devices from the
X server. This obviously means that the X server can not handle the
screensaver alone, since screensaver handling depends on input handling.
SDL does not do what it should to help the X server to handle the
screensaver. Nor does SDL take care of screeensaver handling itself. SDL
simply disables the screensaver completely.


How the problems should be solved
=================================

The correct way for an application program to prevent the screensaver
under X is to call XResetScreenSaver. This was recently discovered and
implemented by the mplayer developers,
[http://svn.mplayerhq.hu/mplayer?view=rev&revision=25637]. SDL needs to
wrap this in an API call (SDL_ResetScreenSaver) and implement it for the
other video targets (if they do not have a corresponding call, SDL
should do what it takes on that particular target, for example sending
fake key events).

1. When a movie is played, the player should reset the screensaver when
the animation is advanced to a new frame. The same applies to anything
similar, like slideshows.

2. When the X server is handling input, it must handle all input
(keyboards, mice, gamepads, ...). This is necessary, not only to be able
to handle the screensaver, but also so that it can send the events to
the correct (the currently active) client. If there is an input device
that the X server can not handle for some reason (such as lack of Plug
and Play capability), the program that handles the device as a
workaround must simulate what would happen if the X server would have
handled the device, by calling XResetScreenSaver when input is received
from the device.

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