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