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