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