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