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