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