wolf3d

The original open source release of Wolfenstein 3D
Log | Files | Refs

ID_IN.C (22314B)


      1 //
      2 //	ID Engine
      3 //	ID_IN.c - Input Manager
      4 //	v1.0d1
      5 //	By Jason Blochowiak
      6 //
      7 
      8 //
      9 //	This module handles dealing with the various input devices
     10 //
     11 //	Depends on: Memory Mgr (for demo recording), Sound Mgr (for timing stuff),
     12 //				User Mgr (for command line parms)
     13 //
     14 //	Globals:
     15 //		LastScan - The keyboard scan code of the last key pressed
     16 //		LastASCII - The ASCII value of the last key pressed
     17 //	DEBUG - there are more globals
     18 //
     19 
     20 #include "ID_HEADS.H"
     21 #pragma	hdrstop
     22 
     23 #define	KeyInt		9	// The keyboard ISR number
     24 
     25 //
     26 // mouse constants
     27 //
     28 #define	MReset		0
     29 #define	MButtons	3
     30 #define	MDelta		11
     31 
     32 #define	MouseInt	0x33
     33 #define	Mouse(x)	_AX = x,geninterrupt(MouseInt)
     34 
     35 //
     36 // joystick constants
     37 //
     38 #define	JoyScaleMax		32768
     39 #define	JoyScaleShift	8
     40 #define	MaxJoyValue		5000
     41 
     42 /*
     43 =============================================================================
     44 
     45 					GLOBAL VARIABLES
     46 
     47 =============================================================================
     48 */
     49 
     50 //
     51 // configuration variables
     52 //
     53 boolean			MousePresent;
     54 boolean			JoysPresent[MaxJoys];
     55 boolean			JoyPadPresent;
     56 
     57 
     58 // 	Global variables
     59 		boolean		Keyboard[NumCodes];
     60 		boolean		Paused;
     61 		char		LastASCII;
     62 		ScanCode	LastScan;
     63 
     64 		KeyboardDef	KbdDefs = {0x1d,0x38,0x47,0x48,0x49,0x4b,0x4d,0x4f,0x50,0x51};
     65 		JoystickDef	JoyDefs[MaxJoys];
     66 		ControlType	Controls[MaxPlayers];
     67 
     68 		longword	MouseDownCount;
     69 
     70 		Demo		DemoMode = demo_Off;
     71 		byte _seg	*DemoBuffer;
     72 		word		DemoOffset,DemoSize;
     73 
     74 /*
     75 =============================================================================
     76 
     77 					LOCAL VARIABLES
     78 
     79 =============================================================================
     80 */
     81 static	byte        far ASCIINames[] =		// Unshifted ASCII for scan codes
     82 					{
     83 //	 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
     84 	0  ,27 ,'1','2','3','4','5','6','7','8','9','0','-','=',8  ,9  ,	// 0
     85 	'q','w','e','r','t','y','u','i','o','p','[',']',13 ,0  ,'a','s',	// 1
     86 	'd','f','g','h','j','k','l',';',39 ,'`',0  ,92 ,'z','x','c','v',	// 2
     87 	'b','n','m',',','.','/',0  ,'*',0  ,' ',0  ,0  ,0  ,0  ,0  ,0  ,	// 3
     88 	0  ,0  ,0  ,0  ,0  ,0  ,0  ,'7','8','9','-','4','5','6','+','1',	// 4
     89 	'2','3','0',127,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,	// 5
     90 	0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,	// 6
     91 	0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0		// 7
     92 					},
     93 					far ShiftNames[] =		// Shifted ASCII for scan codes
     94 					{
     95 //	 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
     96 	0  ,27 ,'!','@','#','$','%','^','&','*','(',')','_','+',8  ,9  ,	// 0
     97 	'Q','W','E','R','T','Y','U','I','O','P','{','}',13 ,0  ,'A','S',	// 1
     98 	'D','F','G','H','J','K','L',':',34 ,'~',0  ,'|','Z','X','C','V',	// 2
     99 	'B','N','M','<','>','?',0  ,'*',0  ,' ',0  ,0  ,0  ,0  ,0  ,0  ,	// 3
    100 	0  ,0  ,0  ,0  ,0  ,0  ,0  ,'7','8','9','-','4','5','6','+','1',	// 4
    101 	'2','3','0',127,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,	// 5
    102 	0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,	// 6
    103 	0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0   	// 7
    104 					},
    105 					far SpecialNames[] =	// ASCII for 0xe0 prefixed codes
    106 					{
    107 //	 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
    108 	0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,	// 0
    109 	0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,13 ,0  ,0  ,0  ,	// 1
    110 	0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,	// 2
    111 	0  ,0  ,0  ,0  ,0  ,'/',0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,	// 3
    112 	0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,	// 4
    113 	0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,	// 5
    114 	0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,	// 6
    115 	0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0   	// 7
    116 					};
    117 
    118 
    119 static	boolean		IN_Started;
    120 static	boolean		CapsLock;
    121 static	ScanCode	CurCode,LastCode;
    122 
    123 static	Direction	DirTable[] =		// Quick lookup for total direction
    124 					{
    125 						dir_NorthWest,	dir_North,	dir_NorthEast,
    126 						dir_West,		dir_None,	dir_East,
    127 						dir_SouthWest,	dir_South,	dir_SouthEast
    128 					};
    129 
    130 static	void			(*INL_KeyHook)(void);
    131 static	void interrupt	(*OldKeyVect)(void);
    132 
    133 static	char			*ParmStrings[] = {"nojoys","nomouse",nil};
    134 
    135 //	Internal routines
    136 
    137 ///////////////////////////////////////////////////////////////////////////
    138 //
    139 //	INL_KeyService() - Handles a keyboard interrupt (key up/down)
    140 //
    141 ///////////////////////////////////////////////////////////////////////////
    142 static void interrupt
    143 INL_KeyService(void)
    144 {
    145 static	boolean	special;
    146 		byte	k,c,
    147 				temp;
    148 		int		i;
    149 
    150 	k = inportb(0x60);	// Get the scan code
    151 
    152 	// Tell the XT keyboard controller to clear the key
    153 	outportb(0x61,(temp = inportb(0x61)) | 0x80);
    154 	outportb(0x61,temp);
    155 
    156 	if (k == 0xe0)		// Special key prefix
    157 		special = true;
    158 	else if (k == 0xe1)	// Handle Pause key
    159 		Paused = true;
    160 	else
    161 	{
    162 		if (k & 0x80)	// Break code
    163 		{
    164 			k &= 0x7f;
    165 
    166 // DEBUG - handle special keys: ctl-alt-delete, print scrn
    167 
    168 			Keyboard[k] = false;
    169 		}
    170 		else			// Make code
    171 		{
    172 			LastCode = CurCode;
    173 			CurCode = LastScan = k;
    174 			Keyboard[k] = true;
    175 
    176 			if (special)
    177 				c = SpecialNames[k];
    178 			else
    179 			{
    180 				if (k == sc_CapsLock)
    181 				{
    182 					CapsLock ^= true;
    183 					// DEBUG - make caps lock light work
    184 				}
    185 
    186 				if (Keyboard[sc_LShift] || Keyboard[sc_RShift])	// If shifted
    187 				{
    188 					c = ShiftNames[k];
    189 					if ((c >= 'A') && (c <= 'Z') && CapsLock)
    190 						c += 'a' - 'A';
    191 				}
    192 				else
    193 				{
    194 					c = ASCIINames[k];
    195 					if ((c >= 'a') && (c <= 'z') && CapsLock)
    196 						c -= 'a' - 'A';
    197 				}
    198 			}
    199 			if (c)
    200 				LastASCII = c;
    201 		}
    202 
    203 		special = false;
    204 	}
    205 
    206 	if (INL_KeyHook && !special)
    207 		INL_KeyHook();
    208 	outportb(0x20,0x20);
    209 }
    210 
    211 ///////////////////////////////////////////////////////////////////////////
    212 //
    213 //	INL_GetMouseDelta() - Gets the amount that the mouse has moved from the
    214 //		mouse driver
    215 //
    216 ///////////////////////////////////////////////////////////////////////////
    217 static void
    218 INL_GetMouseDelta(int *x,int *y)
    219 {
    220 	Mouse(MDelta);
    221 	*x = _CX;
    222 	*y = _DX;
    223 }
    224 
    225 ///////////////////////////////////////////////////////////////////////////
    226 //
    227 //	INL_GetMouseButtons() - Gets the status of the mouse buttons from the
    228 //		mouse driver
    229 //
    230 ///////////////////////////////////////////////////////////////////////////
    231 static word
    232 INL_GetMouseButtons(void)
    233 {
    234 	word	buttons;
    235 
    236 	Mouse(MButtons);
    237 	buttons = _BX;
    238 	return(buttons);
    239 }
    240 
    241 ///////////////////////////////////////////////////////////////////////////
    242 //
    243 //	IN_GetJoyAbs() - Reads the absolute position of the specified joystick
    244 //
    245 ///////////////////////////////////////////////////////////////////////////
    246 void
    247 IN_GetJoyAbs(word joy,word *xp,word *yp)
    248 {
    249 	byte	xb,yb,
    250 			xs,ys;
    251 	word	x,y;
    252 
    253 	x = y = 0;
    254 	xs = joy? 2 : 0;		// Find shift value for x axis
    255 	xb = 1 << xs;			// Use shift value to get x bit mask
    256 	ys = joy? 3 : 1;		// Do the same for y axis
    257 	yb = 1 << ys;
    258 
    259 // Read the absolute joystick values
    260 asm		pushf				// Save some registers
    261 asm		push	si
    262 asm		push	di
    263 asm		cli					// Make sure an interrupt doesn't screw the timings
    264 
    265 
    266 asm		mov		dx,0x201
    267 asm		in		al,dx
    268 asm		out		dx,al		// Clear the resistors
    269 
    270 asm		mov		ah,[xb]		// Get masks into registers
    271 asm		mov		ch,[yb]
    272 
    273 asm		xor		si,si		// Clear count registers
    274 asm		xor		di,di
    275 asm		xor		bh,bh		// Clear high byte of bx for later
    276 
    277 asm		push	bp			// Don't mess up stack frame
    278 asm		mov		bp,MaxJoyValue
    279 
    280 loop:
    281 asm		in		al,dx		// Get bits indicating whether all are finished
    282 
    283 asm		dec		bp			// Check bounding register
    284 asm		jz		done		// We have a silly value - abort
    285 
    286 asm		mov		bl,al		// Duplicate the bits
    287 asm		and		bl,ah		// Mask off useless bits (in [xb])
    288 asm		add		si,bx		// Possibly increment count register
    289 asm		mov		cl,bl		// Save for testing later
    290 
    291 asm		mov		bl,al
    292 asm		and		bl,ch		// [yb]
    293 asm		add		di,bx
    294 
    295 asm		add		cl,bl
    296 asm		jnz		loop 		// If both bits were 0, drop out
    297 
    298 done:
    299 asm     pop		bp
    300 
    301 asm		mov		cl,[xs]		// Get the number of bits to shift
    302 asm		shr		si,cl		//  and shift the count that many times
    303 
    304 asm		mov		cl,[ys]
    305 asm		shr		di,cl
    306 
    307 asm		mov		[x],si		// Store the values into the variables
    308 asm		mov		[y],di
    309 
    310 asm		pop		di
    311 asm		pop		si
    312 asm		popf				// Restore the registers
    313 
    314 	*xp = x;
    315 	*yp = y;
    316 }
    317 
    318 ///////////////////////////////////////////////////////////////////////////
    319 //
    320 //	INL_GetJoyDelta() - Returns the relative movement of the specified
    321 //		joystick (from +/-127)
    322 //
    323 ///////////////////////////////////////////////////////////////////////////
    324 void INL_GetJoyDelta(word joy,int *dx,int *dy)
    325 {
    326 	word		x,y;
    327 	longword	time;
    328 	JoystickDef	*def;
    329 static	longword	lasttime;
    330 
    331 	IN_GetJoyAbs(joy,&x,&y);
    332 	def = JoyDefs + joy;
    333 
    334 	if (x < def->threshMinX)
    335 	{
    336 		if (x < def->joyMinX)
    337 			x = def->joyMinX;
    338 
    339 		x = -(x - def->threshMinX);
    340 		x *= def->joyMultXL;
    341 		x >>= JoyScaleShift;
    342 		*dx = (x > 127)? -127 : -x;
    343 	}
    344 	else if (x > def->threshMaxX)
    345 	{
    346 		if (x > def->joyMaxX)
    347 			x = def->joyMaxX;
    348 
    349 		x = x - def->threshMaxX;
    350 		x *= def->joyMultXH;
    351 		x >>= JoyScaleShift;
    352 		*dx = (x > 127)? 127 : x;
    353 	}
    354 	else
    355 		*dx = 0;
    356 
    357 	if (y < def->threshMinY)
    358 	{
    359 		if (y < def->joyMinY)
    360 			y = def->joyMinY;
    361 
    362 		y = -(y - def->threshMinY);
    363 		y *= def->joyMultYL;
    364 		y >>= JoyScaleShift;
    365 		*dy = (y > 127)? -127 : -y;
    366 	}
    367 	else if (y > def->threshMaxY)
    368 	{
    369 		if (y > def->joyMaxY)
    370 			y = def->joyMaxY;
    371 
    372 		y = y - def->threshMaxY;
    373 		y *= def->joyMultYH;
    374 		y >>= JoyScaleShift;
    375 		*dy = (y > 127)? 127 : y;
    376 	}
    377 	else
    378 		*dy = 0;
    379 
    380 	lasttime = TimeCount;
    381 }
    382 
    383 ///////////////////////////////////////////////////////////////////////////
    384 //
    385 //	INL_GetJoyButtons() - Returns the button status of the specified
    386 //		joystick
    387 //
    388 ///////////////////////////////////////////////////////////////////////////
    389 static word
    390 INL_GetJoyButtons(word joy)
    391 {
    392 register	word	result;
    393 
    394 	result = inportb(0x201);	// Get all the joystick buttons
    395 	result >>= joy? 6 : 4;	// Shift into bits 0-1
    396 	result &= 3;				// Mask off the useless bits
    397 	result ^= 3;
    398 	return(result);
    399 }
    400 
    401 ///////////////////////////////////////////////////////////////////////////
    402 //
    403 //	IN_GetJoyButtonsDB() - Returns the de-bounced button status of the
    404 //		specified joystick
    405 //
    406 ///////////////////////////////////////////////////////////////////////////
    407 word
    408 IN_GetJoyButtonsDB(word joy)
    409 {
    410 	longword	lasttime;
    411 	word		result1,result2;
    412 
    413 	do
    414 	{
    415 		result1 = INL_GetJoyButtons(joy);
    416 		lasttime = TimeCount;
    417 		while (TimeCount == lasttime)
    418 			;
    419 		result2 = INL_GetJoyButtons(joy);
    420 	} while (result1 != result2);
    421 	return(result1);
    422 }
    423 
    424 ///////////////////////////////////////////////////////////////////////////
    425 //
    426 //	INL_StartKbd() - Sets up my keyboard stuff for use
    427 //
    428 ///////////////////////////////////////////////////////////////////////////
    429 static void
    430 INL_StartKbd(void)
    431 {
    432 	INL_KeyHook = NULL;			// no key hook routine
    433 
    434 	IN_ClearKeysDown();
    435 
    436 	OldKeyVect = getvect(KeyInt);
    437 	setvect(KeyInt,INL_KeyService);
    438 }
    439 
    440 ///////////////////////////////////////////////////////////////////////////
    441 //
    442 //	INL_ShutKbd() - Restores keyboard control to the BIOS
    443 //
    444 ///////////////////////////////////////////////////////////////////////////
    445 static void
    446 INL_ShutKbd(void)
    447 {
    448 	poke(0x40,0x17,peek(0x40,0x17) & 0xfaf0);	// Clear ctrl/alt/shift flags
    449 
    450 	setvect(KeyInt,OldKeyVect);
    451 }
    452 
    453 ///////////////////////////////////////////////////////////////////////////
    454 //
    455 //	INL_StartMouse() - Detects and sets up the mouse
    456 //
    457 ///////////////////////////////////////////////////////////////////////////
    458 static boolean
    459 INL_StartMouse(void)
    460 {
    461 #if 0
    462 	if (getvect(MouseInt))
    463 	{
    464 		Mouse(MReset);
    465 		if (_AX == 0xffff)
    466 			return(true);
    467 	}
    468 	return(false);
    469 #endif
    470  union REGS regs;
    471  unsigned char far *vector;
    472 
    473 
    474  if ((vector=MK_FP(peek(0,0x33*4+2),peek(0,0x33*4)))==NULL)
    475    return false;
    476 
    477  if (*vector == 207)
    478    return false;
    479 
    480  Mouse(MReset);
    481  return true;
    482 }
    483 
    484 ///////////////////////////////////////////////////////////////////////////
    485 //
    486 //	INL_ShutMouse() - Cleans up after the mouse
    487 //
    488 ///////////////////////////////////////////////////////////////////////////
    489 static void
    490 INL_ShutMouse(void)
    491 {
    492 }
    493 
    494 //
    495 //	INL_SetJoyScale() - Sets up scaling values for the specified joystick
    496 //
    497 static void
    498 INL_SetJoyScale(word joy)
    499 {
    500 	JoystickDef	*def;
    501 
    502 	def = &JoyDefs[joy];
    503 	def->joyMultXL = JoyScaleMax / (def->threshMinX - def->joyMinX);
    504 	def->joyMultXH = JoyScaleMax / (def->joyMaxX - def->threshMaxX);
    505 	def->joyMultYL = JoyScaleMax / (def->threshMinY - def->joyMinY);
    506 	def->joyMultYH = JoyScaleMax / (def->joyMaxY - def->threshMaxY);
    507 }
    508 
    509 ///////////////////////////////////////////////////////////////////////////
    510 //
    511 //	IN_SetupJoy() - Sets up thresholding values and calls INL_SetJoyScale()
    512 //		to set up scaling values
    513 //
    514 ///////////////////////////////////////////////////////////////////////////
    515 void
    516 IN_SetupJoy(word joy,word minx,word maxx,word miny,word maxy)
    517 {
    518 	word		d,r;
    519 	JoystickDef	*def;
    520 
    521 	def = &JoyDefs[joy];
    522 
    523 	def->joyMinX = minx;
    524 	def->joyMaxX = maxx;
    525 	r = maxx - minx;
    526 	d = r / 3;
    527 	def->threshMinX = ((r / 2) - d) + minx;
    528 	def->threshMaxX = ((r / 2) + d) + minx;
    529 
    530 	def->joyMinY = miny;
    531 	def->joyMaxY = maxy;
    532 	r = maxy - miny;
    533 	d = r / 3;
    534 	def->threshMinY = ((r / 2) - d) + miny;
    535 	def->threshMaxY = ((r / 2) + d) + miny;
    536 
    537 	INL_SetJoyScale(joy);
    538 }
    539 
    540 ///////////////////////////////////////////////////////////////////////////
    541 //
    542 //	INL_StartJoy() - Detects & auto-configures the specified joystick
    543 //					The auto-config assumes the joystick is centered
    544 //
    545 ///////////////////////////////////////////////////////////////////////////
    546 static boolean
    547 INL_StartJoy(word joy)
    548 {
    549 	word		x,y;
    550 
    551 	IN_GetJoyAbs(joy,&x,&y);
    552 
    553 	if
    554 	(
    555 		((x == 0) || (x > MaxJoyValue - 10))
    556 	||	((y == 0) || (y > MaxJoyValue - 10))
    557 	)
    558 		return(false);
    559 	else
    560 	{
    561 		IN_SetupJoy(joy,0,x * 2,0,y * 2);
    562 		return(true);
    563 	}
    564 }
    565 
    566 ///////////////////////////////////////////////////////////////////////////
    567 //
    568 //	INL_ShutJoy() - Cleans up the joystick stuff
    569 //
    570 ///////////////////////////////////////////////////////////////////////////
    571 static void
    572 INL_ShutJoy(word joy)
    573 {
    574 	JoysPresent[joy] = false;
    575 }
    576 
    577 
    578 ///////////////////////////////////////////////////////////////////////////
    579 //
    580 //	IN_Startup() - Starts up the Input Mgr
    581 //
    582 ///////////////////////////////////////////////////////////////////////////
    583 void
    584 IN_Startup(void)
    585 {
    586 	boolean	checkjoys,checkmouse;
    587 	word	i;
    588 
    589 	if (IN_Started)
    590 		return;
    591 
    592 	checkjoys = true;
    593 	checkmouse = true;
    594 	for (i = 1;i < _argc;i++)
    595 	{
    596 		switch (US_CheckParm(_argv[i],ParmStrings))
    597 		{
    598 		case 0:
    599 			checkjoys = false;
    600 			break;
    601 		case 1:
    602 			checkmouse = false;
    603 			break;
    604 		}
    605 	}
    606 
    607 	INL_StartKbd();
    608 	MousePresent = checkmouse? INL_StartMouse() : false;
    609 
    610 	for (i = 0;i < MaxJoys;i++)
    611 		JoysPresent[i] = checkjoys? INL_StartJoy(i) : false;
    612 
    613 	IN_Started = true;
    614 }
    615 
    616 ///////////////////////////////////////////////////////////////////////////
    617 //
    618 //	IN_Default() - Sets up default conditions for the Input Mgr
    619 //
    620 ///////////////////////////////////////////////////////////////////////////
    621 void
    622 IN_Default(boolean gotit,ControlType in)
    623 {
    624 	if
    625 	(
    626 		(!gotit)
    627 	|| 	((in == ctrl_Joystick1) && !JoysPresent[0])
    628 	|| 	((in == ctrl_Joystick2) && !JoysPresent[1])
    629 	|| 	((in == ctrl_Mouse) && !MousePresent)
    630 	)
    631 		in = ctrl_Keyboard1;
    632 	IN_SetControlType(0,in);
    633 }
    634 
    635 ///////////////////////////////////////////////////////////////////////////
    636 //
    637 //	IN_Shutdown() - Shuts down the Input Mgr
    638 //
    639 ///////////////////////////////////////////////////////////////////////////
    640 void
    641 IN_Shutdown(void)
    642 {
    643 	word	i;
    644 
    645 	if (!IN_Started)
    646 		return;
    647 
    648 	INL_ShutMouse();
    649 	for (i = 0;i < MaxJoys;i++)
    650 		INL_ShutJoy(i);
    651 	INL_ShutKbd();
    652 
    653 	IN_Started = false;
    654 }
    655 
    656 ///////////////////////////////////////////////////////////////////////////
    657 //
    658 //	IN_SetKeyHook() - Sets the routine that gets called by INL_KeyService()
    659 //			everytime a real make/break code gets hit
    660 //
    661 ///////////////////////////////////////////////////////////////////////////
    662 void
    663 IN_SetKeyHook(void (*hook)())
    664 {
    665 	INL_KeyHook = hook;
    666 }
    667 
    668 ///////////////////////////////////////////////////////////////////////////
    669 //
    670 //	IN_ClearKeysDown() - Clears the keyboard array
    671 //
    672 ///////////////////////////////////////////////////////////////////////////
    673 void
    674 IN_ClearKeysDown(void)
    675 {
    676 	int	i;
    677 
    678 	LastScan = sc_None;
    679 	LastASCII = key_None;
    680 	memset (Keyboard,0,sizeof(Keyboard));
    681 }
    682 
    683 
    684 ///////////////////////////////////////////////////////////////////////////
    685 //
    686 //	IN_ReadControl() - Reads the device associated with the specified
    687 //		player and fills in the control info struct
    688 //
    689 ///////////////////////////////////////////////////////////////////////////
    690 void
    691 IN_ReadControl(int player,ControlInfo *info)
    692 {
    693 			boolean		realdelta;
    694 			byte		dbyte;
    695 			word		buttons;
    696 			int			dx,dy;
    697 			Motion		mx,my;
    698 			ControlType	type;
    699 register	KeyboardDef	*def;
    700 
    701 	dx = dy = 0;
    702 	mx = my = motion_None;
    703 	buttons = 0;
    704 
    705 	if (DemoMode == demo_Playback)
    706 	{
    707 		dbyte = DemoBuffer[DemoOffset + 1];
    708 		my = (dbyte & 3) - 1;
    709 		mx = ((dbyte >> 2) & 3) - 1;
    710 		buttons = (dbyte >> 4) & 3;
    711 
    712 		if (!(--DemoBuffer[DemoOffset]))
    713 		{
    714 			DemoOffset += 2;
    715 			if (DemoOffset >= DemoSize)
    716 				DemoMode = demo_PlayDone;
    717 		}
    718 
    719 		realdelta = false;
    720 	}
    721 	else if (DemoMode == demo_PlayDone)
    722 		Quit("Demo playback exceeded");
    723 	else
    724 	{
    725 		switch (type = Controls[player])
    726 		{
    727 		case ctrl_Keyboard:
    728 			def = &KbdDefs;
    729 
    730 			if (Keyboard[def->upleft])
    731 				mx = motion_Left,my = motion_Up;
    732 			else if (Keyboard[def->upright])
    733 				mx = motion_Right,my = motion_Up;
    734 			else if (Keyboard[def->downleft])
    735 				mx = motion_Left,my = motion_Down;
    736 			else if (Keyboard[def->downright])
    737 				mx = motion_Right,my = motion_Down;
    738 
    739 			if (Keyboard[def->up])
    740 				my = motion_Up;
    741 			else if (Keyboard[def->down])
    742 				my = motion_Down;
    743 
    744 			if (Keyboard[def->left])
    745 				mx = motion_Left;
    746 			else if (Keyboard[def->right])
    747 				mx = motion_Right;
    748 
    749 			if (Keyboard[def->button0])
    750 				buttons += 1 << 0;
    751 			if (Keyboard[def->button1])
    752 				buttons += 1 << 1;
    753 			realdelta = false;
    754 			break;
    755 		case ctrl_Joystick1:
    756 		case ctrl_Joystick2:
    757 			INL_GetJoyDelta(type - ctrl_Joystick,&dx,&dy);
    758 			buttons = INL_GetJoyButtons(type - ctrl_Joystick);
    759 			realdelta = true;
    760 			break;
    761 		case ctrl_Mouse:
    762 			INL_GetMouseDelta(&dx,&dy);
    763 			buttons = INL_GetMouseButtons();
    764 			realdelta = true;
    765 			break;
    766 		}
    767 	}
    768 
    769 	if (realdelta)
    770 	{
    771 		mx = (dx < 0)? motion_Left : ((dx > 0)? motion_Right : motion_None);
    772 		my = (dy < 0)? motion_Up : ((dy > 0)? motion_Down : motion_None);
    773 	}
    774 	else
    775 	{
    776 		dx = mx * 127;
    777 		dy = my * 127;
    778 	}
    779 
    780 	info->x = dx;
    781 	info->xaxis = mx;
    782 	info->y = dy;
    783 	info->yaxis = my;
    784 	info->button0 = buttons & (1 << 0);
    785 	info->button1 = buttons & (1 << 1);
    786 	info->button2 = buttons & (1 << 2);
    787 	info->button3 = buttons & (1 << 3);
    788 	info->dir = DirTable[((my + 1) * 3) + (mx + 1)];
    789 
    790 	if (DemoMode == demo_Record)
    791 	{
    792 		// Pack the control info into a byte
    793 		dbyte = (buttons << 4) | ((mx + 1) << 2) | (my + 1);
    794 
    795 		if
    796 		(
    797 			(DemoBuffer[DemoOffset + 1] == dbyte)
    798 		&&	(DemoBuffer[DemoOffset] < 255)
    799 		)
    800 			(DemoBuffer[DemoOffset])++;
    801 		else
    802 		{
    803 			if (DemoOffset || DemoBuffer[DemoOffset])
    804 				DemoOffset += 2;
    805 
    806 			if (DemoOffset >= DemoSize)
    807 				Quit("Demo buffer overflow");
    808 
    809 			DemoBuffer[DemoOffset] = 1;
    810 			DemoBuffer[DemoOffset + 1] = dbyte;
    811 		}
    812 	}
    813 }
    814 
    815 ///////////////////////////////////////////////////////////////////////////
    816 //
    817 //	IN_SetControlType() - Sets the control type to be used by the specified
    818 //		player
    819 //
    820 ///////////////////////////////////////////////////////////////////////////
    821 void
    822 IN_SetControlType(int player,ControlType type)
    823 {
    824 	// DEBUG - check that requested type is present?
    825 	Controls[player] = type;
    826 }
    827 
    828 ///////////////////////////////////////////////////////////////////////////
    829 //
    830 //	IN_WaitForKey() - Waits for a scan code, then clears LastScan and
    831 //		returns the scan code
    832 //
    833 ///////////////////////////////////////////////////////////////////////////
    834 ScanCode
    835 IN_WaitForKey(void)
    836 {
    837 	ScanCode	result;
    838 
    839 	while (!(result = LastScan))
    840 		;
    841 	LastScan = 0;
    842 	return(result);
    843 }
    844 
    845 ///////////////////////////////////////////////////////////////////////////
    846 //
    847 //	IN_WaitForASCII() - Waits for an ASCII char, then clears LastASCII and
    848 //		returns the ASCII value
    849 //
    850 ///////////////////////////////////////////////////////////////////////////
    851 char
    852 IN_WaitForASCII(void)
    853 {
    854 	char		result;
    855 
    856 	while (!(result = LastASCII))
    857 		;
    858 	LastASCII = '\0';
    859 	return(result);
    860 }
    861 
    862 ///////////////////////////////////////////////////////////////////////////
    863 //
    864 //	IN_Ack() - waits for a button or key press.  If a button is down, upon
    865 // calling, it must be released for it to be recognized
    866 //
    867 ///////////////////////////////////////////////////////////////////////////
    868 
    869 boolean	btnstate[8];
    870 
    871 void IN_StartAck(void)
    872 {
    873 	unsigned	i,buttons;
    874 
    875 //
    876 // get initial state of everything
    877 //
    878 	IN_ClearKeysDown();
    879 	memset (btnstate,0,sizeof(btnstate));
    880 
    881 	buttons = IN_JoyButtons () << 4;
    882 	if (MousePresent)
    883 		buttons |= IN_MouseButtons ();
    884 
    885 	for (i=0;i<8;i++,buttons>>=1)
    886 		if (buttons&1)
    887 			btnstate[i] = true;
    888 }
    889 
    890 
    891 boolean IN_CheckAck (void)
    892 {
    893 	unsigned	i,buttons;
    894 
    895 //
    896 // see if something has been pressed
    897 //
    898 	if (LastScan)
    899 		return true;
    900 
    901 	buttons = IN_JoyButtons () << 4;
    902 	if (MousePresent)
    903 		buttons |= IN_MouseButtons ();
    904 
    905 	for (i=0;i<8;i++,buttons>>=1)
    906 		if ( buttons&1 )
    907 		{
    908 			if (!btnstate[i])
    909 				return true;
    910 		}
    911 		else
    912 			btnstate[i]=false;
    913 
    914 	return false;
    915 }
    916 
    917 
    918 void IN_Ack (void)
    919 {
    920 	IN_StartAck ();
    921 
    922 	while (!IN_CheckAck ())
    923 	;
    924 }
    925 
    926 
    927 ///////////////////////////////////////////////////////////////////////////
    928 //
    929 //	IN_UserInput() - Waits for the specified delay time (in ticks) or the
    930 //		user pressing a key or a mouse button. If the clear flag is set, it
    931 //		then either clears the key or waits for the user to let the mouse
    932 //		button up.
    933 //
    934 ///////////////////////////////////////////////////////////////////////////
    935 boolean IN_UserInput(longword delay)
    936 {
    937 	longword	lasttime;
    938 
    939 	lasttime = TimeCount;
    940 	IN_StartAck ();
    941 	do
    942 	{
    943 		if (IN_CheckAck())
    944 			return true;
    945 	} while (TimeCount - lasttime < delay);
    946 	return(false);
    947 }
    948 
    949 //===========================================================================
    950 
    951 /*
    952 ===================
    953 =
    954 = IN_MouseButtons
    955 =
    956 ===================
    957 */
    958 
    959 byte	IN_MouseButtons (void)
    960 {
    961 	if (MousePresent)
    962 	{
    963 		Mouse(MButtons);
    964 		return _BX;
    965 	}
    966 	else
    967 		return 0;
    968 }
    969 
    970 
    971 /*
    972 ===================
    973 =
    974 = IN_JoyButtons
    975 =
    976 ===================
    977 */
    978 
    979 byte	IN_JoyButtons (void)
    980 {
    981 	unsigned joybits;
    982 
    983 	joybits = inportb(0x201);	// Get all the joystick buttons
    984 	joybits >>= 4;				// only the high bits are useful
    985 	joybits ^= 15;				// return with 1=pressed
    986 
    987 	return joybits;
    988 }
    989 
    990