Home | History | Annotate | Download | only in windx5
      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 (at) 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_LESS;
    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 }
    924