src/video/windib/SDL_dibevents.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 29 Jan 2006 07:57:13 +0000
changeset 1282 217f5d5a49e5
parent 1280 f61f045343d3
child 1288 ea3888b472bf
permissions -rw-r--r--
Date: Sat, 15 Jan 2005 02:01:51 +0000 (UTC)
From: jimrandomh
Subject: [SDL] Re: Modifier keys pressed during initialization stick

I wrote a simple test program which initializes SDL, prints the SDL
version number, then prints any keydown and keyup events with their
modifiers. (Source code below). Compilation was done using Visual
Studio 6, release mode.

My test sequence was:
Start a command prompt. Type the name of the test program.
shift down
enter down (program starts)
Wait for window to appear
enter up
shift up
spacebar down
spacebar up

Under Windows 98, the output was correct:
SDL 1.2.8
left shift down
shift-return down
shift-return up
left shift up
space down
space up

Under Windows 2000 and under Windows XP, the output was:
SDL 1.2.8
shift-space down
shift-space up

Since shift was not held at the time space was pressed, this is
incorrect. Similar results were observed with launching in different
ways (including double-clicking in Windows Explorer), so it does not
depend on the launching terminal.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2004 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 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     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 
    23 #ifdef SAVE_RCSID
    24 static char rcsid =
    25  "@(#) $Id$";
    26 #endif
    27 
    28 #include <stdlib.h>
    29 #include <stdio.h>
    30 #include <windows.h>
    31 
    32 #include "SDL_events.h"
    33 #include "SDL_error.h"
    34 #include "SDL_syswm.h"
    35 #include "SDL_sysevents.h"
    36 #include "SDL_events_c.h"
    37 #include "SDL_lowvideo.h"
    38 #include "SDL_dibvideo.h"
    39 #include "SDL_vkeys.h"
    40 
    41 #ifndef WM_APP
    42 #define WM_APP	0x8000
    43 #endif
    44 
    45 #ifdef _WIN32_WCE
    46 #define NO_GETKEYBOARDSTATE
    47 #endif
    48 
    49 /* The translation table from a Microsoft VK keysym to a SDL keysym */
    50 static SDLKey VK_keymap[SDLK_LAST];
    51 static SDL_keysym *TranslateKey(UINT vkey, UINT scancode, SDL_keysym *keysym, int pressed);
    52 
    53 /* Masks for processing the windows KEYDOWN and KEYUP messages */
    54 #define REPEATED_KEYMASK	(1<<30)
    55 #define EXTENDED_KEYMASK	(1<<24)
    56 
    57 /* DJM: If the user setup the window for us, we want to save his window proc,
    58    and give him a chance to handle some messages. */
    59 static WNDPROC 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 LONG
    88  DIB_HandleMessage(_THIS, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    89 {
    90 	extern int posted;
    91 
    92 	switch (msg) {
    93 		case WM_SYSKEYDOWN:
    94 		case WM_KEYDOWN: {
    95 			SDL_keysym keysym;
    96 
    97 #ifdef _WIN32_WCE
    98 			// Drop GAPI artefacts
    99 			if (wParam == 0x84 || wParam == 0x5B)
   100 				return 0;
   101 
   102 			// Rotate key if necessary
   103 			if (this->hidden->orientation != SDL_ORIENTATION_UP)
   104 				wParam = rotateKey(wParam, this->hidden->orientation);	
   105 #endif 
   106 			/* Ignore repeated keys */
   107 			if ( lParam&REPEATED_KEYMASK ) {
   108 				return(0);
   109 			}
   110 			switch (wParam) {
   111 				case VK_CONTROL:
   112 					if ( lParam&EXTENDED_KEYMASK )
   113 						wParam = VK_RCONTROL;
   114 					else
   115 						wParam = VK_LCONTROL;
   116 					break;
   117 				case VK_SHIFT:
   118 					/* EXTENDED trick doesn't work here */
   119 					{
   120 					Uint8 *state = SDL_GetKeyState(NULL);
   121 					if (state[SDLK_LSHIFT] == SDL_RELEASED && (GetKeyState(VK_LSHIFT) & 0x8000)) {
   122 						wParam = VK_LSHIFT;
   123 					} else if (state[SDLK_RSHIFT] == SDL_RELEASED && (GetKeyState(VK_RSHIFT) & 0x8000)) {
   124 						wParam = VK_RSHIFT;
   125 					} else {
   126 						/* Probably a key repeat */
   127 						return(0);
   128 					}
   129 					}
   130 					break;
   131 				case VK_MENU:
   132 					if ( lParam&EXTENDED_KEYMASK )
   133 						wParam = VK_RMENU;
   134 					else
   135 						wParam = VK_LMENU;
   136 					break;
   137 			}
   138 #ifdef NO_GETKEYBOARDSTATE
   139 			/* this is the workaround for the missing ToAscii() and ToUnicode() in CE (not necessary at KEYUP!) */
   140 			if ( SDL_TranslateUNICODE ) {
   141 				MSG m;
   142 
   143 				m.hwnd = hwnd;
   144 				m.message = msg;
   145 				m.wParam = wParam;
   146 				m.lParam = lParam;
   147 				m.time = 0;
   148 				if ( TranslateMessage(&m) && PeekMessage(&m, hwnd, 0, WM_USER, PM_NOREMOVE) && (m.message == WM_CHAR) ) {
   149 					GetMessage(&m, hwnd, 0, WM_USER);
   150 			    		wParam = m.wParam;
   151 				}
   152 			}
   153 #endif /* NO_GETKEYBOARDSTATE */
   154 			posted = SDL_PrivateKeyboard(SDL_PRESSED,
   155 				TranslateKey(wParam,HIWORD(lParam),&keysym,1));
   156 		}
   157 		return(0);
   158 
   159 		case WM_SYSKEYUP:
   160 		case WM_KEYUP: {
   161 			SDL_keysym keysym;
   162 
   163 #ifdef _WIN32_WCE
   164 			// Drop GAPI artefacts
   165 			if (wParam == 0x84 || wParam == 0x5B)
   166 				return 0;
   167 
   168 			// Rotate key if necessary
   169 			if (this->hidden->orientation != SDL_ORIENTATION_UP)
   170 				wParam = rotateKey(wParam, this->hidden->orientation);	
   171 #endif
   172 
   173 			switch (wParam) {
   174 				case VK_CONTROL:
   175 					if ( lParam&EXTENDED_KEYMASK )
   176 						wParam = VK_RCONTROL;
   177 					else
   178 						wParam = VK_LCONTROL;
   179 					break;
   180 				case VK_SHIFT:
   181 					/* EXTENDED trick doesn't work here */
   182 					{
   183 					Uint8 *state = SDL_GetKeyState(NULL);
   184 					if (state[SDLK_LSHIFT] == SDL_PRESSED && !(GetKeyState(VK_LSHIFT) & 0x8000)) {
   185 						wParam = VK_LSHIFT;
   186 					} else if (state[SDLK_RSHIFT] == SDL_PRESSED && !(GetKeyState(VK_RSHIFT) & 0x8000)) {
   187 						wParam = VK_RSHIFT;
   188 					} else {
   189 						/* Probably a key repeat */
   190 						return(0);
   191 					}
   192 					}
   193 					break;
   194 				case VK_MENU:
   195 					if ( lParam&EXTENDED_KEYMASK )
   196 						wParam = VK_RMENU;
   197 					else
   198 						wParam = VK_LMENU;
   199 					break;
   200 			}
   201 			posted = SDL_PrivateKeyboard(SDL_RELEASED,
   202 				TranslateKey(wParam,HIWORD(lParam),&keysym,0));
   203 		}
   204 		return(0);
   205 
   206 #if defined(SC_SCREENSAVE) && defined(SC_MONITORPOWER)
   207 		case WM_SYSCOMMAND: {
   208 			if ((wParam&0xFFF0)==SC_SCREENSAVE ||
   209 				(wParam&0xFFF0)==SC_MONITORPOWER)
   210 					return(0);
   211 		}
   212 		/* Fall through to default processing */
   213 #endif /* SC_SCREENSAVE && SC_MONITORPOWER */
   214 
   215 		default: {
   216 			/* Only post the event if we're watching for it */
   217 			if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
   218 			        SDL_SysWMmsg wmmsg;
   219 
   220 				SDL_VERSION(&wmmsg.version);
   221 				wmmsg.hwnd = hwnd;
   222 				wmmsg.msg = msg;
   223 				wmmsg.wParam = wParam;
   224 				wmmsg.lParam = lParam;
   225 				posted = SDL_PrivateSysWMEvent(&wmmsg);
   226 
   227 			/* DJM: If the user isn't watching for private
   228 				messages in her SDL event loop, then pass it
   229 				along to any win32 specific window proc.
   230 			 */
   231 			} else if (userWindowProc) {
   232 				return CallWindowProc(userWindowProc, hwnd, msg, wParam, lParam);
   233 			}
   234 		}
   235 		break;
   236 	}
   237 	return(DefWindowProc(hwnd, msg, wParam, lParam));
   238 }
   239 
   240 void DIB_PumpEvents(_THIS)
   241 {
   242 	MSG msg;
   243 
   244 	while ( PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) ) {
   245 		if ( GetMessage(&msg, NULL, 0, 0) > 0 ) {
   246 			DispatchMessage(&msg);
   247 		}
   248 	}
   249 }
   250 
   251 void DIB_InitOSKeymap(_THIS)
   252 {
   253 	int i;
   254 
   255 	/* Map the VK keysyms */
   256 	for ( i=0; i<SDL_TABLESIZE(VK_keymap); ++i )
   257 		VK_keymap[i] = SDLK_UNKNOWN;
   258 
   259 	VK_keymap[VK_BACK] = SDLK_BACKSPACE;
   260 	VK_keymap[VK_TAB] = SDLK_TAB;
   261 	VK_keymap[VK_CLEAR] = SDLK_CLEAR;
   262 	VK_keymap[VK_RETURN] = SDLK_RETURN;
   263 	VK_keymap[VK_PAUSE] = SDLK_PAUSE;
   264 	VK_keymap[VK_ESCAPE] = SDLK_ESCAPE;
   265 	VK_keymap[VK_SPACE] = SDLK_SPACE;
   266 	VK_keymap[VK_APOSTROPHE] = SDLK_QUOTE;
   267 	VK_keymap[VK_COMMA] = SDLK_COMMA;
   268 	VK_keymap[VK_MINUS] = SDLK_MINUS;
   269 	VK_keymap[VK_PERIOD] = SDLK_PERIOD;
   270 	VK_keymap[VK_SLASH] = SDLK_SLASH;
   271 	VK_keymap[VK_0] = SDLK_0;
   272 	VK_keymap[VK_1] = SDLK_1;
   273 	VK_keymap[VK_2] = SDLK_2;
   274 	VK_keymap[VK_3] = SDLK_3;
   275 	VK_keymap[VK_4] = SDLK_4;
   276 	VK_keymap[VK_5] = SDLK_5;
   277 	VK_keymap[VK_6] = SDLK_6;
   278 	VK_keymap[VK_7] = SDLK_7;
   279 	VK_keymap[VK_8] = SDLK_8;
   280 	VK_keymap[VK_9] = SDLK_9;
   281 	VK_keymap[VK_SEMICOLON] = SDLK_SEMICOLON;
   282 	VK_keymap[VK_EQUALS] = SDLK_EQUALS;
   283 	VK_keymap[VK_LBRACKET] = SDLK_LEFTBRACKET;
   284 	VK_keymap[VK_BACKSLASH] = SDLK_BACKSLASH;
   285 	VK_keymap[VK_OEM_102] = SDLK_LESS;
   286 	VK_keymap[VK_RBRACKET] = SDLK_RIGHTBRACKET;
   287 	VK_keymap[VK_GRAVE] = SDLK_BACKQUOTE;
   288 	VK_keymap[VK_BACKTICK] = SDLK_BACKQUOTE;
   289 	VK_keymap[VK_A] = SDLK_a;
   290 	VK_keymap[VK_B] = SDLK_b;
   291 	VK_keymap[VK_C] = SDLK_c;
   292 	VK_keymap[VK_D] = SDLK_d;
   293 	VK_keymap[VK_E] = SDLK_e;
   294 	VK_keymap[VK_F] = SDLK_f;
   295 	VK_keymap[VK_G] = SDLK_g;
   296 	VK_keymap[VK_H] = SDLK_h;
   297 	VK_keymap[VK_I] = SDLK_i;
   298 	VK_keymap[VK_J] = SDLK_j;
   299 	VK_keymap[VK_K] = SDLK_k;
   300 	VK_keymap[VK_L] = SDLK_l;
   301 	VK_keymap[VK_M] = SDLK_m;
   302 	VK_keymap[VK_N] = SDLK_n;
   303 	VK_keymap[VK_O] = SDLK_o;
   304 	VK_keymap[VK_P] = SDLK_p;
   305 	VK_keymap[VK_Q] = SDLK_q;
   306 	VK_keymap[VK_R] = SDLK_r;
   307 	VK_keymap[VK_S] = SDLK_s;
   308 	VK_keymap[VK_T] = SDLK_t;
   309 	VK_keymap[VK_U] = SDLK_u;
   310 	VK_keymap[VK_V] = SDLK_v;
   311 	VK_keymap[VK_W] = SDLK_w;
   312 	VK_keymap[VK_X] = SDLK_x;
   313 	VK_keymap[VK_Y] = SDLK_y;
   314 	VK_keymap[VK_Z] = SDLK_z;
   315 	VK_keymap[VK_DELETE] = SDLK_DELETE;
   316 
   317 	VK_keymap[VK_NUMPAD0] = SDLK_KP0;
   318 	VK_keymap[VK_NUMPAD1] = SDLK_KP1;
   319 	VK_keymap[VK_NUMPAD2] = SDLK_KP2;
   320 	VK_keymap[VK_NUMPAD3] = SDLK_KP3;
   321 	VK_keymap[VK_NUMPAD4] = SDLK_KP4;
   322 	VK_keymap[VK_NUMPAD5] = SDLK_KP5;
   323 	VK_keymap[VK_NUMPAD6] = SDLK_KP6;
   324 	VK_keymap[VK_NUMPAD7] = SDLK_KP7;
   325 	VK_keymap[VK_NUMPAD8] = SDLK_KP8;
   326 	VK_keymap[VK_NUMPAD9] = SDLK_KP9;
   327 	VK_keymap[VK_DECIMAL] = SDLK_KP_PERIOD;
   328 	VK_keymap[VK_DIVIDE] = SDLK_KP_DIVIDE;
   329 	VK_keymap[VK_MULTIPLY] = SDLK_KP_MULTIPLY;
   330 	VK_keymap[VK_SUBTRACT] = SDLK_KP_MINUS;
   331 	VK_keymap[VK_ADD] = SDLK_KP_PLUS;
   332 
   333 	VK_keymap[VK_UP] = SDLK_UP;
   334 	VK_keymap[VK_DOWN] = SDLK_DOWN;
   335 	VK_keymap[VK_RIGHT] = SDLK_RIGHT;
   336 	VK_keymap[VK_LEFT] = SDLK_LEFT;
   337 	VK_keymap[VK_INSERT] = SDLK_INSERT;
   338 	VK_keymap[VK_HOME] = SDLK_HOME;
   339 	VK_keymap[VK_END] = SDLK_END;
   340 	VK_keymap[VK_PRIOR] = SDLK_PAGEUP;
   341 	VK_keymap[VK_NEXT] = SDLK_PAGEDOWN;
   342 
   343 	VK_keymap[VK_F1] = SDLK_F1;
   344 	VK_keymap[VK_F2] = SDLK_F2;
   345 	VK_keymap[VK_F3] = SDLK_F3;
   346 	VK_keymap[VK_F4] = SDLK_F4;
   347 	VK_keymap[VK_F5] = SDLK_F5;
   348 	VK_keymap[VK_F6] = SDLK_F6;
   349 	VK_keymap[VK_F7] = SDLK_F7;
   350 	VK_keymap[VK_F8] = SDLK_F8;
   351 	VK_keymap[VK_F9] = SDLK_F9;
   352 	VK_keymap[VK_F10] = SDLK_F10;
   353 	VK_keymap[VK_F11] = SDLK_F11;
   354 	VK_keymap[VK_F12] = SDLK_F12;
   355 	VK_keymap[VK_F13] = SDLK_F13;
   356 	VK_keymap[VK_F14] = SDLK_F14;
   357 	VK_keymap[VK_F15] = SDLK_F15;
   358 
   359 	VK_keymap[VK_NUMLOCK] = SDLK_NUMLOCK;
   360 	VK_keymap[VK_CAPITAL] = SDLK_CAPSLOCK;
   361 	VK_keymap[VK_SCROLL] = SDLK_SCROLLOCK;
   362 	VK_keymap[VK_RSHIFT] = SDLK_RSHIFT;
   363 	VK_keymap[VK_LSHIFT] = SDLK_LSHIFT;
   364 	VK_keymap[VK_RCONTROL] = SDLK_RCTRL;
   365 	VK_keymap[VK_LCONTROL] = SDLK_LCTRL;
   366 	VK_keymap[VK_RMENU] = SDLK_RALT;
   367 	VK_keymap[VK_LMENU] = SDLK_LALT;
   368 	VK_keymap[VK_RWIN] = SDLK_RSUPER;
   369 	VK_keymap[VK_LWIN] = SDLK_LSUPER;
   370 
   371 	VK_keymap[VK_HELP] = SDLK_HELP;
   372 #ifdef VK_PRINT
   373 	VK_keymap[VK_PRINT] = SDLK_PRINT;
   374 #endif
   375 	VK_keymap[VK_SNAPSHOT] = SDLK_PRINT;
   376 	VK_keymap[VK_CANCEL] = SDLK_BREAK;
   377 	VK_keymap[VK_APPS] = SDLK_MENU;
   378 }
   379 
   380 static SDL_keysym *TranslateKey(UINT vkey, UINT scancode, SDL_keysym *keysym, int pressed)
   381 {
   382 	/* Set the keysym information */
   383 	keysym->scancode = (unsigned char) scancode;
   384 	keysym->sym = VK_keymap[vkey];
   385 	keysym->mod = KMOD_NONE;
   386 	keysym->unicode = 0;
   387 	if ( pressed && SDL_TranslateUNICODE ) {
   388 #ifdef NO_GETKEYBOARDSTATE
   389 		/* Uh oh, better hope the vkey is close enough.. */
   390 		keysym->unicode = vkey;
   391 #else
   392 		BYTE	keystate[256];
   393 		Uint16	wchars[2];
   394 
   395 		GetKeyboardState(keystate);
   396 		if (SDL_ToUnicode(vkey, scancode, keystate, wchars, sizeof(wchars)/sizeof(wchars[0]), 0) == 1)
   397 		{
   398 			keysym->unicode = wchars[0];
   399 		}
   400 #endif /* NO_GETKEYBOARDSTATE */
   401 	}
   402 	return(keysym);
   403 }
   404 
   405 int DIB_CreateWindow(_THIS)
   406 {
   407 	char *windowid = getenv("SDL_WINDOWID");
   408 
   409 #ifndef CS_BYTEALIGNCLIENT
   410 #define CS_BYTEALIGNCLIENT	0
   411 #endif
   412 	SDL_RegisterApp("SDL_app", CS_BYTEALIGNCLIENT, 0);
   413 
   414 	SDL_windowid = (windowid != NULL);
   415 	if ( SDL_windowid ) {
   416 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
   417 		/* wince 2.1 does not have strtol */
   418 		wchar_t *windowid_t = malloc((strlen(windowid) + 1) * sizeof(wchar_t));
   419 		MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, windowid, -1, windowid_t, strlen(windowid) + 1);
   420 		SDL_Window = (HWND)wcstol(windowid_t, NULL, 0);
   421 		free(windowid_t);
   422 #else
   423 		SDL_Window = (HWND)strtol(windowid, NULL, 0);
   424 #endif
   425 		if ( SDL_Window == NULL ) {
   426 			SDL_SetError("Couldn't get user specified window");
   427 			return(-1);
   428 		}
   429 
   430 		/* DJM: we want all event's for the user specified
   431 			window to be handled by SDL.
   432 		 */
   433 		userWindowProc = (WNDPROC)GetWindowLong(SDL_Window, GWL_WNDPROC);
   434 		SetWindowLong(SDL_Window, GWL_WNDPROC, (LONG)WinMessage);
   435 	} else {
   436 		SDL_Window = CreateWindow(SDL_Appname, SDL_Appname,
   437                         (WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX),
   438                         CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL, SDL_Instance, NULL);
   439 		if ( SDL_Window == NULL ) {
   440 			SDL_SetError("Couldn't create window");
   441 			return(-1);
   442 		}
   443 		ShowWindow(SDL_Window, SW_HIDE);
   444 	}
   445 	return(0);
   446 }
   447 
   448 void DIB_DestroyWindow(_THIS)
   449 {
   450 	if ( SDL_windowid ) {
   451 		SetWindowLong(SDL_Window, GWL_WNDPROC, (LONG)userWindowProc);
   452 	} else {
   453 		DestroyWindow(SDL_Window);
   454 	}
   455 }