src/video/windx5/SDL_dx5events.c
author Sam Lantinga
Sun, 21 Sep 2003 18:40:51 +0000
changeset 721 ab0656314eef
parent 717 42ed44b2c8b6
child 769 b8d311d90021
permissions -rw-r--r--
Date: Thu, 18 Sep 2003 14:24:35 -0400
From: Scott Watson
Subject: [SDL] Improper Windows message routine calling

If this hasn't been caught yet, there's an improper method of calling a
user's window message routine in the various SDL_xxevents.c files.

Calling it improperly can cause a crash under at least XP.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  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 /* CAUTION!!!!  If you modify this file, check ../windib/SDL_sysevents.c */
    29 
    30 #include "directx.h"
    31 
    32 #include <stdio.h>
    33 #include "SDL_events.h"
    34 #include "SDL_video.h"
    35 #include "SDL_error.h"
    36 #include "SDL_syswm.h"
    37 #include "SDL_sysevents.h"
    38 #include "SDL_events_c.h"
    39 #include "SDL_lowvideo.h"
    40 #include "SDL_dx5video.h"
    41 
    42 #ifndef WM_APP
    43 #define WM_APP	0x8000
    44 #endif
    45 
    46 #ifdef _WIN32_WCE
    47 #define NO_GETKEYBOARDSTATE
    48 #endif
    49 
    50 /* The keyboard and mouse device input */
    51 #define MAX_INPUTS	16		/* Maximum of 16-1 input devices */
    52 #define INPUT_QSIZE	512		/* Buffer up to 512 input messages */
    53 
    54 static LPDIRECTINPUT dinput = NULL;
    55 static LPDIRECTINPUTDEVICE2 SDL_DIdev[MAX_INPUTS];
    56 static HANDLE               SDL_DIevt[MAX_INPUTS];
    57 static void (*SDL_DIfun[MAX_INPUTS])(const int, DIDEVICEOBJECTDATA *);
    58 static int SDL_DIndev = 0;
    59 static int mouse_lost;
    60 static int mouse_pressed;
    61 static int mouse_buttons_swapped = 0;
    62 
    63 /* The translation table from a DirectInput scancode to an SDL keysym */
    64 static SDLKey DIK_keymap[256];
    65 static SDL_keysym *TranslateKey(UINT scancode, SDL_keysym *keysym, int pressed);
    66 
    67 /* DJM: If the user setup the window for us, we want to save his window proc,
    68    and give him a chance to handle some messages. */
    69 static WNDPROC userWindowProc = NULL;
    70 
    71 /* Convert a DirectInput return code to a text message */
    72 static void SetDIerror(char *function, int code)
    73 {
    74 	static char *error;
    75 	static char  errbuf[1024];
    76 
    77 	errbuf[0] = 0;
    78 	switch (code) {
    79                 case DIERR_GENERIC:
    80                         error = "Undefined error!";
    81                         break;
    82 		case DIERR_OLDDIRECTINPUTVERSION:
    83 			error = "Your version of DirectInput needs upgrading";
    84 			break;
    85 		case DIERR_INVALIDPARAM:
    86                         error = "Invalid parameters";
    87                         break;
    88                 case DIERR_OUTOFMEMORY:
    89                         error = "Out of memory";
    90                         break;
    91 		case DIERR_DEVICENOTREG:
    92 			error = "Device not registered";
    93 			break;
    94 		case DIERR_NOINTERFACE:
    95 			error = "Interface not supported";
    96 			break;
    97 		case DIERR_NOTINITIALIZED:
    98 			error = "Device not initialized";
    99 			break;
   100 		default:
   101 			sprintf(errbuf, "%s: Unknown DirectInput error: 0x%x",
   102 								function, code);
   103 			break;
   104 	}
   105 	if ( ! errbuf[0] ) {
   106 		sprintf(errbuf, "%s: %s", function, error);
   107 	}
   108 	SDL_SetError("%s", errbuf);
   109 	return;
   110 }
   111 
   112 /* Initialize DirectInput
   113    Note:  If NONEXCLUSIVE access is requested for the devices, normal 
   114           windows input messages will continue to be generated for that
   115           input device, in addition to DirectInput messages.
   116  */
   117 static void handle_keyboard(const int numevents, DIDEVICEOBJECTDATA *events);
   118 static void handle_mouse(const int numevents, DIDEVICEOBJECTDATA *events);
   119 struct {
   120 	char *name;
   121 	REFGUID guid;
   122 	LPCDIDATAFORMAT format;
   123 	DWORD win_level;
   124 	DWORD raw_level;
   125 	void (*fun)(const int numevents, DIDEVICEOBJECTDATA *events);
   126 } inputs[] = {
   127 	{ "keyboard",
   128 		&GUID_SysKeyboard, &c_dfDIKeyboard,
   129 		(DISCL_FOREGROUND|DISCL_NONEXCLUSIVE),
   130 		(DISCL_FOREGROUND|DISCL_NONEXCLUSIVE), handle_keyboard },
   131 	{ "mouse",
   132 		&GUID_SysMouse, &c_dfDIMouse,
   133 		(DISCL_FOREGROUND|DISCL_NONEXCLUSIVE),
   134 		(DISCL_FOREGROUND|DISCL_EXCLUSIVE), handle_mouse },
   135 	{ NULL, NULL, NULL, 0, 0, NULL }
   136 };
   137 	
   138 static int DX5_DInputInit(_THIS)
   139 {
   140 	int         i;
   141 	LPDIRECTINPUTDEVICE device;
   142 	HRESULT     result;
   143 	DIPROPDWORD dipdw;
   144 
   145 	/* Create the DirectInput object */
   146 	result = DInputCreate(SDL_Instance, DIRECTINPUT_VERSION,
   147 							&dinput, NULL);
   148 	if ( result != DI_OK ) {
   149 		SetDIerror("DirectInputCreate", result);
   150 		return(-1);
   151 	}
   152 
   153 	/* Create all of our registered input devices */
   154 	SDL_DIndev = 0;
   155 	for ( i=0; inputs[i].name; ++i ) {
   156 		/* Create the DirectInput device */
   157 		result = IDirectInput_CreateDevice(dinput, inputs[i].guid,
   158 								&device, NULL);
   159 		if ( result != DI_OK ) {
   160 			SetDIerror("DirectInput::CreateDevice", result);
   161 			return(-1);
   162 		}
   163 		result = IDirectInputDevice_QueryInterface(device,
   164 			&IID_IDirectInputDevice2, (LPVOID *)&SDL_DIdev[i]);
   165 		IDirectInputDevice_Release(device);
   166 		if ( result != DI_OK ) {
   167 			SetDIerror("DirectInputDevice::QueryInterface", result);
   168 			return(-1);
   169 		}
   170 		result = IDirectInputDevice2_SetCooperativeLevel(SDL_DIdev[i],
   171 					SDL_Window, inputs[i].win_level);
   172 		if ( result != DI_OK ) {
   173 			SetDIerror("DirectInputDevice::SetCooperativeLevel",
   174 									result);
   175 			return(-1);
   176 		}
   177 		result = IDirectInputDevice2_SetDataFormat(SDL_DIdev[i],
   178 							inputs[i].format);
   179 		if ( result != DI_OK ) {
   180 			SetDIerror("DirectInputDevice::SetDataFormat", result);
   181 			return(-1);
   182 		}
   183 
   184 		/* Set buffered input -- we aren't polling */
   185 		memset(&dipdw, 0, sizeof(dipdw));
   186 		dipdw.diph.dwSize = sizeof(dipdw);
   187 		dipdw.diph.dwHeaderSize = sizeof(dipdw.diph);
   188 		dipdw.diph.dwObj = 0;
   189 		dipdw.diph.dwHow = DIPH_DEVICE;
   190 		dipdw.dwData = INPUT_QSIZE;
   191 		result = IDirectInputDevice2_SetProperty(SDL_DIdev[i],
   192 						DIPROP_BUFFERSIZE, &dipdw.diph);
   193 		if ( result != DI_OK ) {
   194 			SetDIerror("DirectInputDevice::SetProperty", result);
   195 			return(-1);
   196 		}
   197 
   198 		/* Create an event to be signaled when input is ready */
   199 		SDL_DIevt[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
   200 		if ( SDL_DIevt[i] == NULL ) {
   201 			SDL_SetError("Couldn't create DirectInput event");
   202 			return(-1);
   203 		}
   204 		result = IDirectInputDevice2_SetEventNotification(SDL_DIdev[i],
   205 								SDL_DIevt[i]);
   206 		if ( result != DI_OK ) {
   207 			SetDIerror("DirectInputDevice::SetEventNotification",
   208 									result);
   209 			return(-1);
   210 		}
   211 		SDL_DIfun[i] = inputs[i].fun;
   212 
   213 		/* Acquire the device for input */
   214 		IDirectInputDevice2_Acquire(SDL_DIdev[i]);
   215 
   216 		/* Increment the number of devices we have */
   217 		++SDL_DIndev;
   218 	}
   219 	mouse_pressed = 0;
   220 	mouse_buttons_swapped = GetSystemMetrics(SM_SWAPBUTTON);
   221 
   222 	/* DirectInput is ready! */
   223 	return(0);
   224 }
   225 
   226 /* Clean up DirectInput */
   227 static void DX5_DInputQuit(_THIS)
   228 {
   229 	int i;
   230 
   231 	if ( dinput != NULL ) {
   232 		/* Close and release all DirectInput devices */
   233 		for ( i=0; i<MAX_INPUTS; ++i ) {
   234 			if ( SDL_DIdev[i] != NULL ) {
   235 				IDirectInputDevice2_Unacquire(SDL_DIdev[i]);
   236 				IDirectInputDevice2_SetEventNotification(
   237 							SDL_DIdev[i], NULL);
   238 				if ( SDL_DIevt[i] != NULL ) {
   239 					CloseHandle(SDL_DIevt[i]);
   240 					SDL_DIevt[i] = NULL;
   241 				}
   242 				IDirectInputDevice2_Release(SDL_DIdev[i]);
   243 				SDL_DIdev[i] = NULL;
   244 			}
   245 		}
   246 		/* Release DirectInput */
   247 		IDirectInput_Release(dinput);
   248 		dinput = NULL;
   249 	}
   250 }
   251 
   252 /* Flag to tell SDL whether or not we queued an event */
   253 static int posted = 0;
   254 
   255 /* Input event handler functions */
   256 static void handle_keyboard(const int numevents, DIDEVICEOBJECTDATA *keybuf)
   257 {
   258 	int i;
   259 	SDL_keysym keysym;
   260 
   261 	/* Translate keyboard messages */
   262 	for ( i=0; i<numevents; ++i ) {
   263 		if ( keybuf[i].dwData & 0x80 ) {
   264 			posted = SDL_PrivateKeyboard(SDL_PRESSED,
   265 				    TranslateKey(keybuf[i].dwOfs, &keysym, 1));
   266 		} else {
   267 			posted = SDL_PrivateKeyboard(SDL_RELEASED,
   268 				    TranslateKey(keybuf[i].dwOfs, &keysym, 0));
   269 		}
   270 	}
   271 }
   272 static void handle_mouse(const int numevents, DIDEVICEOBJECTDATA *ptrbuf)
   273 {
   274 	int i;
   275 	Sint16 xrel, yrel;
   276 	Uint8 state;
   277 	Uint8 button;
   278 	DWORD timestamp = 0;
   279 
   280 	/* Sanity check. Mailing list reports this being NULL unexpectedly. */
   281 	if (SDL_PublicSurface == NULL) {
   282 		return;
   283 	}
   284 
   285 	/* If we are in windowed mode, Windows is taking care of the mouse */
   286 	if (  (SDL_PublicSurface->flags & SDL_OPENGL) ||
   287 	     !(SDL_PublicSurface->flags & SDL_FULLSCREEN) ) {
   288 		return;
   289 	}
   290 
   291 	/* If the mouse was lost, regain some sense of mouse state */
   292 	if ( mouse_lost ) {
   293 		POINT mouse_pos;
   294 		Uint8 old_state;
   295 		Uint8 new_state;
   296 
   297 		/* Set ourselves up with the current cursor position */
   298 		GetCursorPos(&mouse_pos);
   299 		ScreenToClient(SDL_Window, &mouse_pos);
   300 		posted = SDL_PrivateMouseMotion(0, 0,
   301 				(Sint16)mouse_pos.x, (Sint16)mouse_pos.y);
   302 
   303 		/* Check for mouse button changes */
   304 		old_state = SDL_GetMouseState(NULL, NULL);
   305 		new_state = 0;
   306 		{ /* Get the new DirectInput button state for the mouse */
   307 			DIMOUSESTATE distate;
   308 			HRESULT result;
   309 
   310 			result=IDirectInputDevice2_GetDeviceState(SDL_DIdev[1],
   311 						sizeof(distate), &distate);
   312 			if ( result != DI_OK ) {
   313 				/* Try again next time */
   314 				SetDIerror(
   315 				"IDirectInputDevice2::GetDeviceState", result);
   316 				return;
   317 			}
   318 			for ( i=3; i>=0; --i ) {
   319 				if ( (distate.rgbButtons[i]&0x80) == 0x80 ) {
   320 					new_state |= 0x01;
   321 				}
   322 				new_state <<= 1;
   323 			}
   324 		}
   325 		for ( i=0; i<8; ++i ) {
   326 			if ( (old_state&0x01) != (new_state&0x01) ) {
   327 				button = (Uint8)(i+1);
   328 				/* Button #2 on two button mice is button 3
   329 				   (the middle button is button 2)
   330 				 */
   331 				if ( button == 2 ) {
   332 					button = 3;
   333 				} else
   334 				if ( button == 3 ) {
   335 					button = 2;
   336 				}
   337 				if ( new_state & 0x01 ) {
   338 					/* Grab mouse so we get mouse-up */
   339 					if ( ++mouse_pressed > 0 ) {
   340 						SetCapture(SDL_Window);
   341 					}
   342 					state = SDL_PRESSED;
   343 				} else {
   344 					/* Release mouse after all mouse-ups */
   345 					if ( --mouse_pressed <= 0 ) {
   346 						ReleaseCapture();
   347 						mouse_pressed = 0;
   348 					}
   349 					state = SDL_RELEASED;
   350 				}
   351 				if ( mouse_buttons_swapped ) {
   352 					if ( button == 1 ) button = 3;
   353 					else
   354 					if ( button == 3 ) button = 1;
   355 				}
   356 				posted = SDL_PrivateMouseButton(state, button,
   357 									0, 0);
   358 			}
   359 			old_state >>= 1;
   360 			new_state >>= 1;
   361 		}
   362 		mouse_lost = 0;
   363 		return;
   364 	}
   365 
   366 	/* Translate mouse messages */
   367 	xrel = 0;
   368 	yrel = 0;
   369 	for ( i=0; i<(int)numevents; ++i ) {
   370 		switch (ptrbuf[i].dwOfs) {
   371 			case DIMOFS_X:
   372 				if ( timestamp != ptrbuf[i].dwTimeStamp ) {
   373 					if ( xrel || yrel ) {
   374 						posted = SDL_PrivateMouseMotion(
   375 								0, 1, xrel, yrel);
   376 						xrel = 0;
   377 						yrel = 0;
   378 					}
   379 					timestamp = ptrbuf[i].dwTimeStamp;
   380 				}
   381 				xrel += (Sint16)ptrbuf[i].dwData;
   382 				break;
   383 			case DIMOFS_Y:
   384 				if ( timestamp != ptrbuf[i].dwTimeStamp ) {
   385 					if ( xrel || yrel ) {
   386 						posted = SDL_PrivateMouseMotion(
   387 								0, 1, xrel, yrel);
   388 						xrel = 0;
   389 						yrel = 0;
   390 					}
   391 					timestamp = ptrbuf[i].dwTimeStamp;
   392 				}
   393 				yrel += (Sint16)ptrbuf[i].dwData;
   394 				break;
   395 			case DIMOFS_Z:
   396 				if ( xrel || yrel ) {
   397 					posted = SDL_PrivateMouseMotion(
   398 							0, 1, xrel, yrel);
   399 					xrel = 0;
   400 					yrel = 0;
   401 				}
   402 				timestamp = 0;
   403 				if((int)ptrbuf[i].dwData > 0)
   404 					button = SDL_BUTTON_WHEELUP;
   405 				else
   406 					button = SDL_BUTTON_WHEELDOWN;
   407 				posted = SDL_PrivateMouseButton(
   408 						SDL_PRESSED, button, 0, 0);
   409 				posted |= SDL_PrivateMouseButton(
   410 						SDL_RELEASED, button, 0, 0);
   411 				break;
   412 			case DIMOFS_BUTTON0:
   413 			case DIMOFS_BUTTON1:
   414 			case DIMOFS_BUTTON2:
   415 			case DIMOFS_BUTTON3:
   416 				if ( xrel || yrel ) {
   417 					posted = SDL_PrivateMouseMotion(
   418 							0, 1, xrel, yrel);
   419 					xrel = 0;
   420 					yrel = 0;
   421 				}
   422 				timestamp = 0;
   423 				button = (Uint8)(ptrbuf[i].dwOfs-DIMOFS_BUTTON0)+1;
   424 				/* Button #2 on two button mice is button 3
   425 				   (the middle button is button 2)
   426 				 */
   427 				if ( button == 2 ) {
   428 					button = 3;
   429 				} else
   430 				if ( button == 3 ) {
   431 					button = 2;
   432 				}
   433 				if ( ptrbuf[i].dwData & 0x80 ) {
   434 					/* Grab mouse so we get mouse-up */
   435 					if ( ++mouse_pressed > 0 ) {
   436 						SetCapture(SDL_Window);
   437 					}
   438 					state = SDL_PRESSED;
   439 				} else {
   440 					/* Release mouse after all mouse-ups */
   441 					if ( --mouse_pressed <= 0 ) {
   442 						ReleaseCapture();
   443 						mouse_pressed = 0;
   444 					}
   445 					state = SDL_RELEASED;
   446 				}
   447 				if ( mouse_buttons_swapped ) {
   448 					if ( button == 1 ) button = 3;
   449 					else
   450 					if ( button == 3 ) button = 1;
   451 				}
   452 				posted = SDL_PrivateMouseButton(state, button,
   453 									0, 0);
   454 				break;
   455 		}
   456 	}
   457 	if ( xrel || yrel ) {
   458 		posted = SDL_PrivateMouseMotion( 0, 1, xrel, yrel);
   459 	}
   460 }
   461 
   462 /* The main Win32 event handler */
   463 LONG
   464  DX5_HandleMessage(_THIS, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
   465 {
   466 	switch (msg) {
   467 #ifdef WM_ACTIVATEAPP
   468 		case WM_ACTIVATEAPP: {
   469 			int i, active;
   470 
   471 			active = (wParam && (GetForegroundWindow() == hwnd));
   472 			if ( active ) {
   473 				for ( i=0; SDL_DIdev[i]; ++i ) {
   474 					IDirectInputDevice2_Acquire(
   475 								SDL_DIdev[i]);
   476 				}
   477 			} else {
   478 				for ( i=0; SDL_DIdev[i]; ++i ) {
   479 					IDirectInputDevice2_Unacquire(
   480 								SDL_DIdev[i]);
   481 				}
   482 				mouse_lost = 1;
   483 			}
   484 		}
   485 		break;
   486 #endif /* WM_ACTIVATEAPP */
   487 
   488 #ifdef WM_DISPLAYCHANGE
   489 		case WM_DISPLAYCHANGE: {
   490 			WORD BitsPerPixel;
   491 			WORD SizeX, SizeY;
   492 
   493 			/* Ack!  The display changed size and/or depth! */
   494 			SizeX = LOWORD(lParam);
   495 			SizeY = HIWORD(lParam);
   496 			BitsPerPixel = wParam;
   497 			/* We cause this message when we go fullscreen */
   498 		}
   499 		break;
   500 #endif /* WM_DISPLAYCHANGE */
   501 
   502 		/* The keyboard is handled via DirectInput */
   503 		case WM_SYSKEYUP:
   504 		case WM_SYSKEYDOWN:
   505 		case WM_KEYUP:
   506 		case WM_KEYDOWN: {
   507 			/* Ignore windows keyboard messages */;
   508 		}
   509 		return(0);
   510 
   511 #if defined(SC_SCREENSAVE) || defined(SC_MONITORPOWER)
   512 		/* Don't allow screen savers or monitor power downs.
   513 		   This is because they quietly clear DirectX surfaces.
   514 		   It would be better to allow the application to
   515 		   decide whether or not to blow these off, but the
   516 		   semantics of SDL_PrivateSysWMEvent() don't allow
   517 		   the application that choice.
   518 		 */
   519 		case WM_SYSCOMMAND: {
   520 			if ((wParam&0xFFF0)==SC_SCREENSAVE || 
   521 			    (wParam&0xFFF0)==SC_MONITORPOWER)
   522 				return(0);
   523 		}
   524 		/* Fall through to default processing */
   525 
   526 #endif /* SC_SCREENSAVE || SC_MONITORPOWER */
   527 
   528 		default: {
   529 			/* Only post the event if we're watching for it */
   530 			if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
   531 			        SDL_SysWMmsg wmmsg;
   532 
   533 				SDL_VERSION(&wmmsg.version);
   534 				wmmsg.hwnd = hwnd;
   535 				wmmsg.msg = msg;
   536 				wmmsg.wParam = wParam;
   537 				wmmsg.lParam = lParam;
   538 				posted = SDL_PrivateSysWMEvent(&wmmsg);
   539 
   540 			/* DJM: If the user isn't watching for private
   541 				messages in her SDL event loop, then pass it
   542 				along to any win32 specific window proc.
   543 			 */
   544 			} else if (userWindowProc) {
   545 				return CallWindowProc(userWindowProc, hwnd, msg, wParam, lParam);
   546 			}
   547 		}
   548 		break;
   549 	}
   550 	return(DefWindowProc(hwnd, msg, wParam, lParam));
   551 }
   552 
   553 /* This function checks the windows message queue and DirectInput and returns
   554    1 if there was input, 0 if there was no input, or -1 if the application has
   555    posted a quit message.
   556 */
   557 static int DX5_CheckInput(_THIS, int timeout, BOOL processInput)
   558 {
   559 	MSG msg;
   560 	int      i;
   561 	HRESULT  result;
   562 	DWORD    event;
   563 
   564 	/* Check the normal windows queue (highest preference) */
   565 	posted = 0;
   566 	while ( ! posted &&
   567 	        PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) ) {
   568 		if ( GetMessage(&msg, NULL, 0, 0) > 0 ) {
   569 			DispatchMessage(&msg);
   570 		} else {
   571 			return(-1);
   572 		}
   573 	}
   574 	if ( posted ) {
   575 		return(1);
   576 	}
   577 
   578 	/* Pump the DirectInput flow */
   579 	if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) {
   580 		for ( i=0; i<SDL_DIndev; ++i ) {
   581 			result = IDirectInputDevice2_Poll(SDL_DIdev[i]);
   582 			if ( (result == DIERR_INPUTLOST) ||
   583 					(result == DIERR_NOTACQUIRED) ) {
   584 				if ( strcmp(inputs[i].name, "mouse") == 0 ) {
   585 					mouse_lost = 1;
   586 				}
   587 				IDirectInputDevice2_Acquire(SDL_DIdev[i]);
   588 				IDirectInputDevice2_Poll(SDL_DIdev[i]);
   589 			}
   590 		}
   591 	}
   592 
   593 	/* Wait for messages and input events */
   594 	event = MsgWaitForMultipleObjects(SDL_DIndev, SDL_DIevt, FALSE,
   595 							timeout, QS_ALLEVENTS);
   596 	if ((event >= WAIT_OBJECT_0) && (event < (WAIT_OBJECT_0+SDL_DIndev))) {
   597 		DWORD numevents;
   598 		DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
   599 
   600 		event -= WAIT_OBJECT_0;
   601 		numevents = INPUT_QSIZE;
   602 		result = IDirectInputDevice2_GetDeviceData(
   603 				SDL_DIdev[event], sizeof(DIDEVICEOBJECTDATA),
   604 							evtbuf, &numevents, 0);
   605 		if ( (result == DIERR_INPUTLOST) ||
   606 					(result == DIERR_NOTACQUIRED) ) {
   607 			if ( strcmp(inputs[event].name, "mouse") == 0 ) {
   608 				mouse_lost = 1;
   609 			}
   610 			IDirectInputDevice2_Acquire(SDL_DIdev[event]);
   611 			result = IDirectInputDevice2_GetDeviceData(
   612 				SDL_DIdev[event], sizeof(DIDEVICEOBJECTDATA),
   613 							evtbuf, &numevents, 0);
   614 		}
   615 		/* Handle the events */
   616 		if ( result == DI_OK && processInput ) {
   617 			/* Note: This can post multiple events to event queue
   618 			 */
   619 			(*SDL_DIfun[event])((int)numevents, evtbuf);
   620 			return(1);
   621 		}
   622 	}
   623 	if ( event != WAIT_TIMEOUT ) {
   624 		/* Maybe there was a windows message? */
   625 		if ( PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) ) {
   626 			if ( GetMessage(&msg, NULL, 0, 0) > 0 ) {
   627 				DispatchMessage(&msg);
   628 			} else {
   629 				return(-1);
   630 			}
   631 			return(1);
   632 		}
   633 	}
   634 	return(0);
   635 }
   636 
   637 /* Change cooperative level based on whether or not we are fullscreen */
   638 void DX5_DInputReset(_THIS, int fullscreen)
   639 {
   640 	DWORD level;
   641 	int i;
   642 	HRESULT result;
   643 
   644 	for ( i=0; i<MAX_INPUTS; ++i ) {
   645 		if ( SDL_DIdev[i] != NULL ) {
   646 			if ( fullscreen ) {
   647 				level = inputs[i].raw_level;
   648 			} else {
   649 				level = inputs[i].win_level;
   650 			}
   651 			IDirectInputDevice2_Unacquire(SDL_DIdev[i]);
   652 			result = IDirectInputDevice2_SetCooperativeLevel(
   653 					SDL_DIdev[i], SDL_Window, level);
   654 			IDirectInputDevice2_Acquire(SDL_DIdev[i]);
   655 			if ( result != DI_OK ) {
   656 				SetDIerror(
   657 			"DirectInputDevice::SetCooperativeLevel", result);
   658 			}
   659 		}
   660 	}
   661 	mouse_lost = 1;
   662 
   663 	/* Flush pending input */
   664 	DX5_CheckInput(this, 0, FALSE);
   665 }
   666 
   667 void DX5_PumpEvents(_THIS)
   668 {
   669 	/* Wait for messages and DirectInput */
   670 	while ( DX5_CheckInput(this, 0, TRUE) > 0 ) {
   671 		/* Loop and check again */;
   672 	}
   673 }
   674 
   675 void DX5_InitOSKeymap(_THIS)
   676 {
   677 #ifndef DIK_PAUSE
   678 #define DIK_PAUSE	0xC5
   679 #endif
   680 #ifndef DIK_OEM_102
   681 #define DIK_OEM_102	0x56	/* < > | on UK/Germany keyboards */
   682 #endif
   683 	int i;
   684 
   685 	/* Map the DIK scancodes to SDL keysyms */
   686 	for ( i=0; i<SDL_TABLESIZE(DIK_keymap); ++i )
   687 		DIK_keymap[i] = 0;
   688 
   689 	/* Defined DIK_* constants */
   690 	DIK_keymap[DIK_ESCAPE] = SDLK_ESCAPE;
   691 	DIK_keymap[DIK_1] = SDLK_1;
   692 	DIK_keymap[DIK_2] = SDLK_2;
   693 	DIK_keymap[DIK_3] = SDLK_3;
   694 	DIK_keymap[DIK_4] = SDLK_4;
   695 	DIK_keymap[DIK_5] = SDLK_5;
   696 	DIK_keymap[DIK_6] = SDLK_6;
   697 	DIK_keymap[DIK_7] = SDLK_7;
   698 	DIK_keymap[DIK_8] = SDLK_8;
   699 	DIK_keymap[DIK_9] = SDLK_9;
   700 	DIK_keymap[DIK_0] = SDLK_0;
   701 	DIK_keymap[DIK_MINUS] = SDLK_MINUS;
   702 	DIK_keymap[DIK_EQUALS] = SDLK_EQUALS;
   703 	DIK_keymap[DIK_BACK] = SDLK_BACKSPACE;
   704 	DIK_keymap[DIK_TAB] = SDLK_TAB;
   705 	DIK_keymap[DIK_Q] = SDLK_q;
   706 	DIK_keymap[DIK_W] = SDLK_w;
   707 	DIK_keymap[DIK_E] = SDLK_e;
   708 	DIK_keymap[DIK_R] = SDLK_r;
   709 	DIK_keymap[DIK_T] = SDLK_t;
   710 	DIK_keymap[DIK_Y] = SDLK_y;
   711 	DIK_keymap[DIK_U] = SDLK_u;
   712 	DIK_keymap[DIK_I] = SDLK_i;
   713 	DIK_keymap[DIK_O] = SDLK_o;
   714 	DIK_keymap[DIK_P] = SDLK_p;
   715 	DIK_keymap[DIK_LBRACKET] = SDLK_LEFTBRACKET;
   716 	DIK_keymap[DIK_RBRACKET] = SDLK_RIGHTBRACKET;
   717 	DIK_keymap[DIK_RETURN] = SDLK_RETURN;
   718 	DIK_keymap[DIK_LCONTROL] = SDLK_LCTRL;
   719 	DIK_keymap[DIK_A] = SDLK_a;
   720 	DIK_keymap[DIK_S] = SDLK_s;
   721 	DIK_keymap[DIK_D] = SDLK_d;
   722 	DIK_keymap[DIK_F] = SDLK_f;
   723 	DIK_keymap[DIK_G] = SDLK_g;
   724 	DIK_keymap[DIK_H] = SDLK_h;
   725 	DIK_keymap[DIK_J] = SDLK_j;
   726 	DIK_keymap[DIK_K] = SDLK_k;
   727 	DIK_keymap[DIK_L] = SDLK_l;
   728 	DIK_keymap[DIK_SEMICOLON] = SDLK_SEMICOLON;
   729 	DIK_keymap[DIK_APOSTROPHE] = SDLK_QUOTE;
   730 	DIK_keymap[DIK_GRAVE] = SDLK_BACKQUOTE;
   731 	DIK_keymap[DIK_LSHIFT] = SDLK_LSHIFT;
   732 	DIK_keymap[DIK_BACKSLASH] = SDLK_BACKSLASH;
   733 	DIK_keymap[DIK_OEM_102] = SDLK_BACKSLASH;
   734 	DIK_keymap[DIK_Z] = SDLK_z;
   735 	DIK_keymap[DIK_X] = SDLK_x;
   736 	DIK_keymap[DIK_C] = SDLK_c;
   737 	DIK_keymap[DIK_V] = SDLK_v;
   738 	DIK_keymap[DIK_B] = SDLK_b;
   739 	DIK_keymap[DIK_N] = SDLK_n;
   740 	DIK_keymap[DIK_M] = SDLK_m;
   741 	DIK_keymap[DIK_COMMA] = SDLK_COMMA;
   742 	DIK_keymap[DIK_PERIOD] = SDLK_PERIOD;
   743 	DIK_keymap[DIK_SLASH] = SDLK_SLASH;
   744 	DIK_keymap[DIK_RSHIFT] = SDLK_RSHIFT;
   745 	DIK_keymap[DIK_MULTIPLY] = SDLK_KP_MULTIPLY;
   746 	DIK_keymap[DIK_LMENU] = SDLK_LALT;
   747 	DIK_keymap[DIK_SPACE] = SDLK_SPACE;
   748 	DIK_keymap[DIK_CAPITAL] = SDLK_CAPSLOCK;
   749 	DIK_keymap[DIK_F1] = SDLK_F1;
   750 	DIK_keymap[DIK_F2] = SDLK_F2;
   751 	DIK_keymap[DIK_F3] = SDLK_F3;
   752 	DIK_keymap[DIK_F4] = SDLK_F4;
   753 	DIK_keymap[DIK_F5] = SDLK_F5;
   754 	DIK_keymap[DIK_F6] = SDLK_F6;
   755 	DIK_keymap[DIK_F7] = SDLK_F7;
   756 	DIK_keymap[DIK_F8] = SDLK_F8;
   757 	DIK_keymap[DIK_F9] = SDLK_F9;
   758 	DIK_keymap[DIK_F10] = SDLK_F10;
   759 	DIK_keymap[DIK_NUMLOCK] = SDLK_NUMLOCK;
   760 	DIK_keymap[DIK_SCROLL] = SDLK_SCROLLOCK;
   761 	DIK_keymap[DIK_NUMPAD7] = SDLK_KP7;
   762 	DIK_keymap[DIK_NUMPAD8] = SDLK_KP8;
   763 	DIK_keymap[DIK_NUMPAD9] = SDLK_KP9;
   764 	DIK_keymap[DIK_SUBTRACT] = SDLK_KP_MINUS;
   765 	DIK_keymap[DIK_NUMPAD4] = SDLK_KP4;
   766 	DIK_keymap[DIK_NUMPAD5] = SDLK_KP5;
   767 	DIK_keymap[DIK_NUMPAD6] = SDLK_KP6;
   768 	DIK_keymap[DIK_ADD] = SDLK_KP_PLUS;
   769 	DIK_keymap[DIK_NUMPAD1] = SDLK_KP1;
   770 	DIK_keymap[DIK_NUMPAD2] = SDLK_KP2;
   771 	DIK_keymap[DIK_NUMPAD3] = SDLK_KP3;
   772 	DIK_keymap[DIK_NUMPAD0] = SDLK_KP0;
   773 	DIK_keymap[DIK_DECIMAL] = SDLK_KP_PERIOD;
   774 	DIK_keymap[DIK_F11] = SDLK_F11;
   775 	DIK_keymap[DIK_F12] = SDLK_F12;
   776 
   777 	DIK_keymap[DIK_F13] = SDLK_F13;
   778 	DIK_keymap[DIK_F14] = SDLK_F14;
   779 	DIK_keymap[DIK_F15] = SDLK_F15;
   780 
   781 	DIK_keymap[DIK_NUMPADEQUALS] = SDLK_KP_EQUALS;
   782 	DIK_keymap[DIK_NUMPADENTER] = SDLK_KP_ENTER;
   783 	DIK_keymap[DIK_RCONTROL] = SDLK_RCTRL;
   784 	DIK_keymap[DIK_DIVIDE] = SDLK_KP_DIVIDE;
   785 	DIK_keymap[DIK_SYSRQ] = SDLK_SYSREQ;
   786 	DIK_keymap[DIK_RMENU] = SDLK_RALT;
   787 	DIK_keymap[DIK_PAUSE] = SDLK_PAUSE;
   788 	DIK_keymap[DIK_HOME] = SDLK_HOME;
   789 	DIK_keymap[DIK_UP] = SDLK_UP;
   790 	DIK_keymap[DIK_PRIOR] = SDLK_PAGEUP;
   791 	DIK_keymap[DIK_LEFT] = SDLK_LEFT;
   792 	DIK_keymap[DIK_RIGHT] = SDLK_RIGHT;
   793 	DIK_keymap[DIK_END] = SDLK_END;
   794 	DIK_keymap[DIK_DOWN] = SDLK_DOWN;
   795 	DIK_keymap[DIK_NEXT] = SDLK_PAGEDOWN;
   796 	DIK_keymap[DIK_INSERT] = SDLK_INSERT;
   797 	DIK_keymap[DIK_DELETE] = SDLK_DELETE;
   798 	DIK_keymap[DIK_LWIN] = SDLK_LMETA;
   799 	DIK_keymap[DIK_RWIN] = SDLK_RMETA;
   800 	DIK_keymap[DIK_APPS] = SDLK_MENU;
   801 }
   802 
   803 static SDL_keysym *TranslateKey(UINT scancode, SDL_keysym *keysym, int pressed)
   804 {
   805 	/* Set the keysym information */
   806 	keysym->scancode = (unsigned char)scancode;
   807 	keysym->sym = DIK_keymap[scancode];
   808 	keysym->mod = KMOD_NONE;
   809 	keysym->unicode = 0;
   810 	if ( pressed && SDL_TranslateUNICODE ) { /* Someday use ToUnicode() */
   811 		UINT vkey;
   812 #ifndef NO_GETKEYBOARDSTATE
   813 		BYTE keystate[256];
   814 		BYTE chars[2];
   815 #endif
   816 
   817 		vkey = MapVirtualKey(scancode, 1);
   818 #ifdef NO_GETKEYBOARDSTATE
   819 		/* Uh oh, better hope the vkey is close enough.. */
   820 		keysym->unicode = vkey;
   821 #else
   822 		GetKeyboardState(keystate);
   823 		if ( ToAscii(vkey,scancode,keystate,(WORD *)chars,0) == 1 ) {
   824 			keysym->unicode = chars[0];
   825 		}
   826 #endif
   827 	}
   828 	return(keysym);
   829 }
   830 
   831 int DX5_CreateWindow(_THIS)
   832 {
   833 	int i;
   834 
   835 	/* Clear out DirectInput variables in case we fail */
   836 	for ( i=0; i<MAX_INPUTS; ++i ) {
   837 		SDL_DIdev[i] = NULL;
   838 		SDL_DIevt[i] = NULL;
   839 		SDL_DIfun[i] = NULL;
   840 	}
   841 
   842 #ifndef CS_BYTEALIGNCLIENT
   843 #define CS_BYTEALIGNCLIENT	0
   844 #endif
   845 	SDL_RegisterApp("SDL_app", CS_BYTEALIGNCLIENT, 0);
   846 	if ( SDL_windowid ) {
   847 		SDL_Window = (HWND)strtol(SDL_windowid, NULL, 0);
   848 
   849 		/* DJM: we want all event's for the user specified
   850 		   window to be handled by SDL.
   851 		 */
   852 		if (SDL_Window) {
   853 			userWindowProc = (WNDPROC)GetWindowLong(SDL_Window, GWL_WNDPROC);
   854 			SetWindowLong(SDL_Window, GWL_WNDPROC, (LONG)WinMessage);
   855 		}
   856 	} else {
   857 		SDL_Window = CreateWindow(SDL_Appname, SDL_Appname,
   858                         (WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX),
   859                                  0, 0, 0, 0, NULL, NULL, SDL_Instance, NULL);
   860 		if ( SDL_Window == NULL ) {
   861 			SDL_SetError("Couldn't create window");
   862 			return(-1);
   863 		}
   864 		ShowWindow(SDL_Window, SW_HIDE);
   865 	}
   866 
   867 	/* Initialize DirectInput */
   868 	if ( DX5_DInputInit(this) < 0 ) {
   869 		return(-1);
   870 	}
   871 
   872 	/* Ready to roll */
   873 	return(0);
   874 }
   875 
   876 void DX5_DestroyWindow(_THIS)
   877 {
   878 	/* Close down DirectInput */
   879 	DX5_DInputQuit(this);
   880 
   881 	/* Destroy our window */
   882 	DestroyWindow(SDL_Window);
   883 }