3 // ID_IN.c - Input Manager
\r
5 // By Jason Blochowiak
\r
6 // Open Watcom port by sparky4
\r
10 // This module handles dealing with the various input devices
\r
12 // Depends on: Memory Mgr (for demo recording), Sound Mgr (for timing stuff),
\r
13 // User Mgr (for command line parms)
\r
16 // LastScan - The keyboard scan code of the last key pressed
\r
17 // LastASCII - The ASCII value of the last key pressed
\r
18 // DEBUG - there are more globals
\r
21 #include "src/lib/16_in__.h"
\r
24 #define KeyInt 9 // The keyboard ISR number
\r
33 #define MouseInt 0x33
\r
34 #define Mouse(x) _AX = x,geninterrupt(MouseInt)
\r
37 // joystick constants
\r
39 #define JoyScaleMax 32768
\r
40 #define JoyScaleShift 8
\r
41 #define MaxJoyValue 5000
\r
44 =============================================================================
\r
48 =============================================================================
\r
52 // configuration variables
\r
54 boolean MousePresent;
\r
55 boolean JoysPresent[MaxJoys];
\r
56 boolean JoyPadPresent;
\r
60 boolean Keyboard[NumCodes];
\r
65 KeyboardDef KbdDefs = {{0x1d,0x38,0x47,0x48,0x49,0x4b,0x4d,0x4f,0x50,0x51}};
\r
66 JoystickDef JoyDefs[MaxJoys];
\r
67 ControlType Controls[MaxPlayers];
\r
69 dword MouseDownCount;
\r
71 Demo DemoMode = demo_Off;
\r
72 byte _seg *DemoBuffer;
\r
73 word DemoOffset,DemoSize;
\r
76 =============================================================================
\r
80 =============================================================================
\r
82 static byte far ASCIINames[] = // Unshifted ASCII for scan codes
\r
84 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
\r
85 0 ,27 ,'1','2','3','4','5','6','7','8','9','0','-','=',8 ,9 , // 0
\r
86 'q','w','e','r','t','y','u','i','o','p','[',']',13 ,0 ,'a','s', // 1
\r
87 'd','f','g','h','j','k','l',';',39 ,'`',0 ,92 ,'z','x','c','v', // 2
\r
88 'b','n','m',',','.','/',0 ,'*',0 ,' ',0 ,0 ,0 ,0 ,0 ,0 , // 3
\r
89 0 ,0 ,0 ,0 ,0 ,0 ,0 ,'7','8','9','-','4','5','6','+','1', // 4
\r
90 '2','3','0',127,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 5
\r
91 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 6
\r
92 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 // 7
\r
94 far ShiftNames[] = // Shifted ASCII for scan codes
\r
96 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
\r
97 0 ,27 ,'!','@','#','$','%','^','&','*','(',')','_','+',8 ,9 , // 0
\r
98 'Q','W','E','R','T','Y','U','I','O','P','{','}',13 ,0 ,'A','S', // 1
\r
99 'D','F','G','H','J','K','L',':',34 ,'~',0 ,'|','Z','X','C','V', // 2
\r
100 'B','N','M','<','>','?',0 ,'*',0 ,' ',0 ,0 ,0 ,0 ,0 ,0 , // 3
\r
101 0 ,0 ,0 ,0 ,0 ,0 ,0 ,'7','8','9','-','4','5','6','+','1', // 4
\r
102 '2','3','0',127,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 5
\r
103 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 6
\r
104 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 // 7
\r
106 far SpecialNames[] = // ASCII for 0xe0 prefixed codes
\r
108 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
\r
109 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 0
\r
110 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,13 ,0 ,0 ,0 , // 1
\r
111 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 2
\r
112 0 ,0 ,0 ,0 ,0 ,'/',0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 3
\r
113 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 4
\r
114 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 5
\r
115 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 6
\r
116 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 // 7
\r
120 static boolean IN_Started;
\r
121 static boolean CapsLock;
\r
122 static ScanCode CurCode,LastCode;
\r
124 static Direction DirTable[] = // Quick lookup for total direction
\r
126 dir_NorthWest, dir_North, dir_NorthEast,
\r
127 dir_West, dir_None, dir_East,
\r
128 dir_SouthWest, dir_South, dir_SouthEast
\r
131 static void (*INL_KeyHook)(void);
\r
132 static void interrupt (*OldKeyVect)(void);
\r
134 static char *ParmStrings[] = {"nojoys","nomouse",nil};
\r
136 // Internal routines
\r
138 ///////////////////////////////////////////////////////////////////////////
\r
140 // INL_KeyService() - Handles a keyboard interrupt (key up/down)
\r
142 ///////////////////////////////////////////////////////////////////////////
\r
143 static void interrupt
\r
144 INL_KeyService(void)
\r
146 static boolean special;
\r
151 k = inp(0x60); // Get the scan code
\r
153 // Tell the XT keyboard controller to clear the key
\r
154 outportb(0x61,(temp = inp(0x61)) | 0x80);
\r
155 outportb(0x61,temp);
\r
157 if (k == 0xe0) // Special key prefix
\r
159 else if (k == 0xe1) // Handle Pause key
\r
163 if (k & 0x80) // Break code
\r
167 // DEBUG - handle special keys: ctl-alt-delete, print scrn
\r
169 Keyboard[k] = false;
\r
173 LastCode = CurCode;
\r
174 CurCode = LastScan = k;
\r
175 Keyboard[k] = true;
\r
178 c = SpecialNames[k];
\r
181 if (k == sc_CapsLock)
\r
184 // DEBUG - make caps lock light work
\r
187 if (Keyboard[sc_LShift] || Keyboard[sc_RShift]) // If shifted
\r
190 if ((c >= 'A') && (c <= 'Z') && CapsLock)
\r
196 if ((c >= 'a') && (c <= 'z') && CapsLock)
\r
207 if (INL_KeyHook && !special)
\r
209 outportb(0x20,0x20);
\r
212 ///////////////////////////////////////////////////////////////////////////
\r
214 // INL_GetMouseDelta() - Gets the amount that the mouse has moved from the
\r
217 ///////////////////////////////////////////////////////////////////////////
\r
219 INL_GetMouseDelta(int *x,int *y)
\r
226 ///////////////////////////////////////////////////////////////////////////
\r
228 // INL_GetMouseButtons() - Gets the status of the mouse buttons from the
\r
231 ///////////////////////////////////////////////////////////////////////////
\r
233 INL_GetMouseButtons(void)
\r
242 ///////////////////////////////////////////////////////////////////////////
\r
244 // IN_GetJoyAbs() - Reads the absolute position of the specified joystick
\r
246 ///////////////////////////////////////////////////////////////////////////
\r
248 IN_GetJoyAbs(word joy,word *xp,word *yp)
\r
255 xs = joy? 2 : 0; // Find shift value for x axis
\r
256 xb = 1 << xs; // Use shift value to get x bit mask
\r
257 ys = joy? 3 : 1; // Do the same for y axis
\r
260 // Read the absolute joystick values
\r
261 asm pushf // Save some registers
\r
264 asm cli // Make sure an interrupt doesn't screw the timings
\r
269 asm out dx,al // Clear the resistors
\r
271 asm mov ah,[xb] // Get masks into registers
\r
274 asm xor si,si // Clear count registers
\r
276 asm xor bh,bh // Clear high byte of bx for later
\r
278 asm push bp // Don't mess up stack frame
\r
279 asm mov bp,MaxJoyValue
\r
282 asm in al,dx // Get bits indicating whether all are finished
\r
284 asm dec bp // Check bounding register
\r
285 asm jz done // We have a silly value - abort
\r
287 asm mov bl,al // Duplicate the bits
\r
288 asm and bl,ah // Mask off useless bits (in [xb])
\r
289 asm add si,bx // Possibly increment count register
\r
290 asm mov cl,bl // Save for testing later
\r
293 asm and bl,ch // [yb]
\r
297 asm jnz loop // If both bits were 0, drop out
\r
302 asm mov cl,[xs] // Get the number of bits to shift
\r
303 asm shr si,cl // and shift the count that many times
\r
308 asm mov [x],si // Store the values into the variables
\r
313 asm popf // Restore the registers
\r
319 ///////////////////////////////////////////////////////////////////////////
\r
321 // INL_GetJoyDelta() - Returns the relative movement of the specified
\r
322 // joystick (from +/-127)
\r
324 ///////////////////////////////////////////////////////////////////////////
\r
325 void INL_GetJoyDelta(word joy,int *dx,int *dy)
\r
330 static dword lasttime;
\r
332 IN_GetJoyAbs(joy,&x,&y);
\r
333 def = JoyDefs + joy;
\r
335 if (x < def->threshMinX)
\r
337 if (x < def->joyMinX)
\r
340 x = -(x - def->threshMinX);
\r
341 x *= def->joyMultXL;
\r
342 x >>= JoyScaleShift;
\r
343 *dx = (x > 127)? -127 : -x;
\r
345 else if (x > def->threshMaxX)
\r
347 if (x > def->joyMaxX)
\r
350 x = x - def->threshMaxX;
\r
351 x *= def->joyMultXH;
\r
352 x >>= JoyScaleShift;
\r
353 *dx = (x > 127)? 127 : x;
\r
358 if (y < def->threshMinY)
\r
360 if (y < def->joyMinY)
\r
363 y = -(y - def->threshMinY);
\r
364 y *= def->joyMultYL;
\r
365 y >>= JoyScaleShift;
\r
366 *dy = (y > 127)? -127 : -y;
\r
368 else if (y > def->threshMaxY)
\r
370 if (y > def->joyMaxY)
\r
373 y = y - def->threshMaxY;
\r
374 y *= def->joyMultYH;
\r
375 y >>= JoyScaleShift;
\r
376 *dy = (y > 127)? 127 : y;
\r
381 lasttime = TimeCount;
\r
384 ///////////////////////////////////////////////////////////////////////////
\r
386 // INL_GetJoyButtons() - Returns the button status of the specified
\r
389 ///////////////////////////////////////////////////////////////////////////
\r
391 INL_GetJoyButtons(word joy)
\r
393 register word result;
\r
395 result = inp(0x201); // Get all the joystick buttons
\r
396 result >>= joy? 6 : 4; // Shift into bits 0-1
\r
397 result &= 3; // Mask off the useless bits
\r
402 ///////////////////////////////////////////////////////////////////////////
\r
404 // IN_GetJoyButtonsDB() - Returns the de-bounced button status of the
\r
405 // specified joystick
\r
407 ///////////////////////////////////////////////////////////////////////////
\r
409 IN_GetJoyButtonsDB(word joy)
\r
412 word result1,result2;
\r
416 result1 = INL_GetJoyButtons(joy);
\r
417 lasttime = TimeCount;
\r
418 while (TimeCount == lasttime)
\r
420 result2 = INL_GetJoyButtons(joy);
\r
421 } while (result1 != result2);
\r
425 ///////////////////////////////////////////////////////////////////////////
\r
427 // INL_StartKbd() - Sets up my keyboard stuff for use
\r
429 ///////////////////////////////////////////////////////////////////////////
\r
433 INL_KeyHook = NULL; // no key hook routine
\r
435 IN_ClearKeysDown();
\r
437 OldKeyVect = getvect(KeyInt);
\r
438 setvect(KeyInt,INL_KeyService);
\r
441 ///////////////////////////////////////////////////////////////////////////
\r
443 // INL_ShutKbd() - Restores keyboard control to the BIOS
\r
445 ///////////////////////////////////////////////////////////////////////////
\r
449 poke(0x40,0x17,peek(0x40,0x17) & 0xfaf0); // Clear ctrl/alt/shift flags
\r
451 setvect(KeyInt,OldKeyVect);
\r
454 ///////////////////////////////////////////////////////////////////////////
\r
456 // INL_StartMouse() - Detects and sets up the mouse
\r
458 ///////////////////////////////////////////////////////////////////////////
\r
460 INL_StartMouse(void)
\r
463 if (getvect(MouseInt))
\r
472 unsigned char far *vector;
\r
475 if ((vector=MK_FP(peek(0,0x33*4+2),peek(0,0x33*4)))==NULL)
\r
478 if (*vector == 207)
\r
485 ///////////////////////////////////////////////////////////////////////////
\r
487 // INL_ShutMouse() - Cleans up after the mouse
\r
489 ///////////////////////////////////////////////////////////////////////////
\r
491 INL_ShutMouse(void)
\r
496 // INL_SetJoyScale() - Sets up scaling values for the specified joystick
\r
499 INL_SetJoyScale(word joy)
\r
503 def = &JoyDefs[joy];
\r
504 def->joyMultXL = JoyScaleMax / (def->threshMinX - def->joyMinX);
\r
505 def->joyMultXH = JoyScaleMax / (def->joyMaxX - def->threshMaxX);
\r
506 def->joyMultYL = JoyScaleMax / (def->threshMinY - def->joyMinY);
\r
507 def->joyMultYH = JoyScaleMax / (def->joyMaxY - def->threshMaxY);
\r
510 ///////////////////////////////////////////////////////////////////////////
\r
512 // IN_SetupJoy() - Sets up thresholding values and calls INL_SetJoyScale()
\r
513 // to set up scaling values
\r
515 ///////////////////////////////////////////////////////////////////////////
\r
517 IN_SetupJoy(word joy,word minx,word maxx,word miny,word maxy)
\r
522 def = &JoyDefs[joy];
\r
524 def->joyMinX = minx;
\r
525 def->joyMaxX = maxx;
\r
528 def->threshMinX = ((r / 2) - d) + minx;
\r
529 def->threshMaxX = ((r / 2) + d) + minx;
\r
531 def->joyMinY = miny;
\r
532 def->joyMaxY = maxy;
\r
535 def->threshMinY = ((r / 2) - d) + miny;
\r
536 def->threshMaxY = ((r / 2) + d) + miny;
\r
538 INL_SetJoyScale(joy);
\r
541 ///////////////////////////////////////////////////////////////////////////
\r
543 // INL_StartJoy() - Detects & auto-configures the specified joystick
\r
544 // The auto-config assumes the joystick is centered
\r
546 ///////////////////////////////////////////////////////////////////////////
\r
548 INL_StartJoy(word joy)
\r
552 IN_GetJoyAbs(joy,&x,&y);
\r
556 ((x == 0) || (x > MaxJoyValue - 10))
\r
557 || ((y == 0) || (y > MaxJoyValue - 10))
\r
562 IN_SetupJoy(joy,0,x * 2,0,y * 2);
\r
567 ///////////////////////////////////////////////////////////////////////////
\r
569 // INL_ShutJoy() - Cleans up the joystick stuff
\r
571 ///////////////////////////////////////////////////////////////////////////
\r
573 INL_ShutJoy(word joy)
\r
575 JoysPresent[joy] = false;
\r
579 ///////////////////////////////////////////////////////////////////////////
\r
581 // IN_Startup() - Starts up the Input Mgr
\r
583 ///////////////////////////////////////////////////////////////////////////
\r
587 boolean checkjoys,checkmouse;
\r
595 for (i = 1;i < _argc;i++)
\r
597 switch (US_CheckParm(_argv[i],ParmStrings))
\r
603 checkmouse = false;
\r
609 MousePresent = checkmouse? INL_StartMouse() : false;
\r
611 for (i = 0;i < MaxJoys;i++)
\r
612 JoysPresent[i] = checkjoys? INL_StartJoy(i) : false;
\r
617 ///////////////////////////////////////////////////////////////////////////
\r
619 // IN_Default() - Sets up default conditions for the Input Mgr
\r
621 ///////////////////////////////////////////////////////////////////////////
\r
623 IN_Default(boolean gotit,ControlType in)
\r
628 || ((in == ctrl_Joystick1) && !JoysPresent[0])
\r
629 || ((in == ctrl_Joystick2) && !JoysPresent[1])
\r
630 || ((in == ctrl_Mouse) && !MousePresent)
\r
632 in = ctrl_Keyboard1;
\r
633 IN_SetControlType(0,in);
\r
636 ///////////////////////////////////////////////////////////////////////////
\r
638 // IN_Shutdown() - Shuts down the Input Mgr
\r
640 ///////////////////////////////////////////////////////////////////////////
\r
650 for (i = 0;i < MaxJoys;i++)
\r
654 IN_Started = false;
\r
657 ///////////////////////////////////////////////////////////////////////////
\r
659 // IN_SetKeyHook() - Sets the routine that gets called by INL_KeyService()
\r
660 // everytime a real make/break code gets hit
\r
662 ///////////////////////////////////////////////////////////////////////////
\r
664 IN_SetKeyHook(void (*hook)())
\r
666 INL_KeyHook = hook;
\r
669 ///////////////////////////////////////////////////////////////////////////
\r
671 // IN_ClearKeysDown() - Clears the keyboard array
\r
673 ///////////////////////////////////////////////////////////////////////////
\r
675 IN_ClearKeysDown(void)
\r
679 LastScan = sc_None;
\r
680 LastASCII = key_None;
\r
681 memset (Keyboard,0,sizeof(Keyboard));
\r
685 ///////////////////////////////////////////////////////////////////////////
\r
687 // IN_ReadControl() - Reads the device associated with the specified
\r
688 // player and fills in the control info struct
\r
690 ///////////////////////////////////////////////////////////////////////////
\r
692 IN_ReadControl(int player,CursorInfo *info)
\r
700 register KeyboardDef *def;
\r
703 mx = my = motion_None;
\r
706 if (DemoMode == demo_Playback)
\r
708 dbyte = DemoBuffer[DemoOffset + 1];
\r
709 my = (dbyte & 3) - 1;
\r
710 mx = ((dbyte >> 2) & 3) - 1;
\r
711 buttons = (dbyte >> 4) & 3;
\r
713 if (!(--DemoBuffer[DemoOffset]))
\r
716 if (DemoOffset >= DemoSize)
\r
717 DemoMode = demo_PlayDone;
\r
722 else if (DemoMode == demo_PlayDone)
\r
723 Quit("Demo playback exceeded");
\r
726 switch (type = Controls[player])
\r
728 case ctrl_Keyboard:
\r
731 if (Keyboard[def->upleft])
\r
732 mx = motion_Left,my = motion_Up;
\r
733 else if (Keyboard[def->upright])
\r
734 mx = motion_Right,my = motion_Up;
\r
735 else if (Keyboard[def->downleft])
\r
736 mx = motion_Left,my = motion_Down;
\r
737 else if (Keyboard[def->downright])
\r
738 mx = motion_Right,my = motion_Down;
\r
740 if (Keyboard[def->up])
\r
742 else if (Keyboard[def->down])
\r
745 if (Keyboard[def->left])
\r
747 else if (Keyboard[def->right])
\r
750 if (Keyboard[def->button0])
\r
752 if (Keyboard[def->button1])
\r
756 case ctrl_Joystick1:
\r
757 case ctrl_Joystick2:
\r
758 INL_GetJoyDelta(type - ctrl_Joystick,&dx,&dy);
\r
759 buttons = INL_GetJoyButtons(type - ctrl_Joystick);
\r
763 INL_GetMouseDelta(&dx,&dy);
\r
764 buttons = INL_GetMouseButtons();
\r
772 mx = (dx < 0)? motion_Left : ((dx > 0)? motion_Right : motion_None);
\r
773 my = (dy < 0)? motion_Up : ((dy > 0)? motion_Down : motion_None);
\r
785 info->button0 = buttons & (1 << 0);
\r
786 info->button1 = buttons & (1 << 1);
\r
787 info->button2 = buttons & (1 << 2);
\r
788 info->button3 = buttons & (1 << 3);
\r
789 info->dir = DirTable[((my + 1) * 3) + (mx + 1)];
\r
791 if (DemoMode == demo_Record)
\r
793 // Pack the control info into a byte
\r
794 dbyte = (buttons << 4) | ((mx + 1) << 2) | (my + 1);
\r
798 (DemoBuffer[DemoOffset + 1] == dbyte)
\r
799 && (DemoBuffer[DemoOffset] < 255)
\r
801 (DemoBuffer[DemoOffset])++;
\r
804 if (DemoOffset || DemoBuffer[DemoOffset])
\r
807 if (DemoOffset >= DemoSize)
\r
808 Quit("Demo buffer overflow");
\r
810 DemoBuffer[DemoOffset] = 1;
\r
811 DemoBuffer[DemoOffset + 1] = dbyte;
\r
816 ///////////////////////////////////////////////////////////////////////////
\r
818 // IN_SetControlType() - Sets the control type to be used by the specified
\r
821 ///////////////////////////////////////////////////////////////////////////
\r
823 IN_SetControlType(int player,ControlType type)
\r
825 // DEBUG - check that requested type is present?
\r
826 Controls[player] = type;
\r
829 ///////////////////////////////////////////////////////////////////////////
\r
831 // IN_WaitForKey() - Waits for a scan code, then clears LastScan and
\r
832 // returns the scan code
\r
834 ///////////////////////////////////////////////////////////////////////////
\r
836 IN_WaitForKey(void)
\r
840 while (!(result = LastScan))
\r
846 ///////////////////////////////////////////////////////////////////////////
\r
848 // IN_WaitForASCII() - Waits for an ASCII char, then clears LastASCII and
\r
849 // returns the ASCII value
\r
851 ///////////////////////////////////////////////////////////////////////////
\r
853 IN_WaitForASCII(void)
\r
857 while (!(result = LastASCII))
\r
863 ///////////////////////////////////////////////////////////////////////////
\r
865 // IN_Ack() - waits for a button or key press. If a button is down, upon
\r
866 // calling, it must be released for it to be recognized
\r
868 ///////////////////////////////////////////////////////////////////////////
\r
870 boolean btnstate[8];
\r
872 void IN_StartAck(void)
\r
874 unsigned i,buttons;
\r
877 // get initial state of everything
\r
879 IN_ClearKeysDown();
\r
880 memset (btnstate,0,sizeof(btnstate));
\r
882 buttons = IN_JoyButtons () << 4;
\r
884 buttons |= IN_MouseButtons ();
\r
886 for (i=0;i<8;i++,buttons>>=1)
\r
888 btnstate[i] = true;
\r
892 boolean IN_CheckAck (void)
\r
894 unsigned i,buttons;
\r
897 // see if something has been pressed
\r
902 buttons = IN_JoyButtons () << 4;
\r
904 buttons |= IN_MouseButtons ();
\r
906 for (i=0;i<8;i++,buttons>>=1)
\r
923 while (!IN_CheckAck ())
\r
928 ///////////////////////////////////////////////////////////////////////////
\r
930 // IN_UserInput() - Waits for the specified delay time (in ticks) or the
\r
931 // user pressing a key or a mouse button. If the clear flag is set, it
\r
932 // then either clears the key or waits for the user to let the mouse
\r
935 ///////////////////////////////////////////////////////////////////////////
\r
936 boolean IN_UserInput(dword delay)
\r
940 lasttime = TimeCount;
\r
946 } while (TimeCount - lasttime < delay);
\r
950 //===========================================================================
\r
953 ===================
\r
957 ===================
\r
960 byte IN_MouseButtons (void)
\r
973 ===================
\r
977 ===================
\r
980 byte IN_JoyButtons (void)
\r
984 joybits = inp(0x201); // Get all the joystick buttons
\r
985 joybits >>= 4; // only the high bits are useful
\r
986 joybits ^= 15; // return with 1=pressed
\r