1 /* Catacomb Armageddon Source Code
2 * Copyright (C) 1993-2014 Flat Rock Software
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 // ID_IN.c - Input Manager
23 // By Jason Blochowiak
27 // This module handles dealing with the various input devices
29 // Depends on: Memory Mgr (for demo recording), Sound Mgr (for timing stuff),
30 // User Mgr (for command line parms)
33 // LastScan - The keyboard scan code of the last key pressed
34 // LastASCII - The ASCII value of the last key pressed
35 // DEBUG - there are more globals
38 #include "src/lib/16_in.h"
41 =============================================================================
\r
45 =============================================================================
\r
48 boolean JoystickCalibrated=false; // MDM (GAMERS EDGE) - added
\r
49 ControlType ControlTypeUsed; // MDM (GAMERS EDGE) - added
\r
50 boolean Keyboard[NumCodes];
\r
55 //KeyboardDef KbdDefs = {0x1d,0x38,0x47,0x48,0x49,0x4b,0x4d,0x4f,0x50,0x51};
\r
56 JoystickDef JoyDefs[MaxJoys];
\r
57 ControlType Controls[MaxPlayers];
\r
62 ///////////////////////////////////////////////////////////////////////////
64 // INL_KeyService() - Handles a keyboard interrupt (key up/down)
66 ///////////////////////////////////////////////////////////////////////////
70 static boolean special;
74 k = inp(0x60); // Get the scan code
76 // Tell the XT keyboard controller to clear the key
77 outp(0x61,(temp = inp(0x61)) | 0x80);
80 if (k == 0xe0) // Special key prefix
82 else if (k == 0xe1) // Handle Pause key
86 if (k & 0x80) // Break code
90 // DEBUG - handle special keys: ctl-alt-delete, print scrn
97 CurCode = LastScan = k;
104 if (k == sc_CapsLock)
107 // DEBUG - make caps lock light work
110 if (Keyboard[sc_LShift] || Keyboard[sc_RShift]) // If shifted
113 if ((c >= 'A') && (c <= 'Z') && CapsLock)
119 if ((c >= 'a') && (c <= 'z') && CapsLock)
130 if (INL_KeyHook && !special)
133 printf("%c %x %u\n", c, k, Keyboard[k]);
143 int86(MouseInt,&CPURegs,&CPURegs);
146 ///////////////////////////////////////////////////////////////////////////
148 // INL_GetMouseDelta() - Gets the amount that the mouse has moved from the
151 ///////////////////////////////////////////////////////////////////////////
153 INL_GetMouseDelta(int *x,int *y)
161 ///////////////////////////////////////////////////////////////////////////
163 // INL_GetMouseButtons() - Gets the status of the mouse buttons from the
166 ///////////////////////////////////////////////////////////////////////////
168 INL_GetMouseButtons(void)
174 buttons = CPURegs.x.bx;
178 ///////////////////////////////////////////////////////////////////////////
180 // IN_GetJoyAbs() - Reads the absolute position of the specified joystick
182 ///////////////////////////////////////////////////////////////////////////
184 IN_GetJoyAbs(word joy,word *xp,word *yp)
191 xs = joy? 2 : 0; // Find shift value for x axis
192 xb = 1 << xs; // Use shift value to get x bit mask
193 ys = joy? 3 : 1; // Do the same for y axis
196 // Read the absolute joystick values
199 pushf // Save some registers
202 cli // Make sure an interrupt doesn't screw the timings
207 out dx,al // Clear the resistors
209 mov ah,[xb] // Get masks into registers
212 xor si,si // Clear count registers
214 xor bh,bh // Clear high byte of bx for later
216 push bp // Don't mess up stack frame
220 in al,dx // Get bits indicating whether all are finished
222 dec bp // Check bounding register
223 jz done // We have a silly value - abort
225 mov bl,al // Duplicate the bits
226 and bl,ah // Mask off useless bits (in [xb])
227 add si,bx // Possibly increment count register
228 mov cl,bl // Save for testing later
235 jnz loo // If both bits were 0, drop out
240 mov cl,[xs] // Get the number of bits to shift
241 shr si,cl // and shift the count that many times
246 mov [x],si // Store the values into the variables
251 popf // Restore the registers
258 ///////////////////////////////////////////////////////////////////////////
260 // INL_GetJoyDelta() - Returns the relative movement of the specified
261 // joystick (from +/-127, scaled adaptively)
263 ///////////////////////////////////////////////////////////////////////////
265 INL_GetJoyDelta(word joy,int *dx,int *dy,boolean adaptive)
269 dword TimeCount = *clockdw;
271 static dword lasttime;
273 IN_GetJoyAbs(joy,&x,&y);
276 if (x < def->threshMinX)
278 if (x < def->joyMinX)
281 x = -(x - def->threshMinX);
284 *dx = (x > 127)? -127 : -x;
286 else if (x > def->threshMaxX)
288 if (x > def->joyMaxX)
291 x = x - def->threshMaxX;
294 *dx = (x > 127)? 127 : x;
299 if (y < def->threshMinY)
301 if (y < def->joyMinY)
304 y = -(y - def->threshMinY);
307 *dy = (y > 127)? -127 : -y;
309 else if (y > def->threshMaxY)
311 if (y > def->joyMaxY)
314 y = y - def->threshMaxY;
317 *dy = (y > 127)? 127 : y;
324 time = (TimeCount - lasttime) / 2;
333 lasttime = TimeCount;
336 ///////////////////////////////////////////////////////////////////////////
338 // INL_GetJoyButtons() - Returns the button status of the specified
341 ///////////////////////////////////////////////////////////////////////////
343 INL_GetJoyButtons(word joy)
345 register word result;
347 result = inp(0x201); // Get all the joystick buttons
348 result >>= joy? 6 : 4; // Shift into bits 0-1
349 result &= 3; // Mask off the useless bits
354 ///////////////////////////////////////////////////////////////////////////
356 // IN_GetJoyButtonsDB() - Returns the de-bounced button status of the
357 // specified joystick
359 ///////////////////////////////////////////////////////////////////////////
361 IN_GetJoyButtonsDB(word joy)
363 dword TimeCount = *clockdw;
365 word result1,result2;
369 result1 = INL_GetJoyButtons(joy);
370 lasttime = TimeCount;
371 while(TimeCount == lasttime)
372 result2 = INL_GetJoyButtons(joy);
373 } while(result1 != result2);
377 ///////////////////////////////////////////////////////////////////////////
379 // INL_StartKbd() - Sets up my keyboard stuff for use
381 ///////////////////////////////////////////////////////////////////////////
385 INL_KeyHook = 0; // Clear key hook
389 OldKeyVect = _dos_getvect(KeyInt);
390 _dos_setvect(KeyInt,INL_KeyService);
393 ///////////////////////////////////////////////////////////////////////////
395 // INL_ShutKbd() - Restores keyboard control to the BIOS
397 ///////////////////////////////////////////////////////////////////////////
401 pokeb(0x40,0x17,peekb(0x40,0x17) & 0xfaf0); // Clear ctrl/alt/shift flags
403 _dos_setvect(KeyInt,OldKeyVect);
406 ///////////////////////////////////////////////////////////////////////////
408 // INL_StartMouse() - Detects and sets up the mouse
410 ///////////////////////////////////////////////////////////////////////////
415 if(_dos_getvect(MouseInt))
418 if(CPURegs.x.ax == 0xffff)
424 ///////////////////////////////////////////////////////////////////////////
426 // INL_ShutMouse() - Cleans up after the mouse
428 ///////////////////////////////////////////////////////////////////////////
435 // INL_SetJoyScale() - Sets up scaling values for the specified joystick
438 INL_SetJoyScale(word joy)
443 def->joyMultXL = JoyScaleMax / (def->threshMinX - def->joyMinX);
444 def->joyMultXH = JoyScaleMax / (def->joyMaxX - def->threshMaxX);
445 def->joyMultYL = JoyScaleMax / (def->threshMinY - def->joyMinY);
446 def->joyMultYH = JoyScaleMax / (def->joyMaxY - def->threshMaxY);
449 ///////////////////////////////////////////////////////////////////////////
451 // IN_SetupJoy() - Sets up thresholding values and calls INL_SetJoyScale()
452 // to set up scaling values
454 ///////////////////////////////////////////////////////////////////////////
456 IN_SetupJoy(word joy,word minx,word maxx,word miny,word maxy)
467 def->threshMinX = ((r / 2) - d) + minx;
468 def->threshMaxX = ((r / 2) + d) + minx;
474 def->threshMinY = ((r / 2) - d) + miny;
475 def->threshMaxY = ((r / 2) + d) + miny;
477 INL_SetJoyScale(joy);
480 ///////////////////////////////////////////////////////////////////////////
482 // INL_StartJoy() - Detects & auto-configures the specified joystick
483 // The auto-config assumes the joystick is centered
485 ///////////////////////////////////////////////////////////////////////////
487 INL_StartJoy(word joy)
491 IN_GetJoyAbs(joy,&x,&y);
495 ((x == 0) || (x > MaxJoyValue - 10))
496 || ((y == 0) || (y > MaxJoyValue - 10))
501 IN_SetupJoy(joy,0,x * 2,0,y * 2);
506 ///////////////////////////////////////////////////////////////////////////
508 // INL_ShutJoy() - Cleans up the joystick stuff
510 ///////////////////////////////////////////////////////////////////////////
512 INL_ShutJoy(word joy)
514 JoysPresent[joy] = false;
519 ///////////////////////////////////////////////////////////////////////////
521 // IN_Startup() - Starts up the Input Mgr
523 ///////////////////////////////////////////////////////////////////////////
527 boolean checkjoys,checkmouse;
535 for (i = 1;i < __argc;i++)
537 switch (US_CheckParm(__argv[i],ParmStrings))
549 MousePresent = checkmouse? INL_StartMouse() : false;
551 for (i = 0;i < MaxJoys;i++)
552 JoysPresent[i] = checkjoys? INL_StartJoy(i) : false;
557 ///////////////////////////////////////////////////////////////////////////
559 // IN_Default() - Sets up default conditions for the Input Mgr
561 ///////////////////////////////////////////////////////////////////////////
563 IN_Default(boolean gotit,ControlType in)
568 || ((in == ctrl_Joystick1) && !JoysPresent[0])
569 || ((in == ctrl_Joystick2) && !JoysPresent[1])
570 || ((in == ctrl_Mouse) && !MousePresent)
573 IN_SetControlType(0,in);
576 ///////////////////////////////////////////////////////////////////////////
578 // IN_Shutdown() - Shuts down the Input Mgr
580 ///////////////////////////////////////////////////////////////////////////
590 for (i = 0;i < MaxJoys;i++)
597 ///////////////////////////////////////////////////////////////////////////
599 // IN_SetKeyHook() - Sets the routine that gets called by INL_KeyService()
600 // everytime a real make/break code gets hit
602 ///////////////////////////////////////////////////////////////////////////
604 IN_SetKeyHook(void (*hook)())
609 ///////////////////////////////////////////////////////////////////////////
611 // IN_ClearKeyDown() - Clears the keyboard array
613 ///////////////////////////////////////////////////////////////////////////
615 IN_ClearKeysDown(void)
620 LastASCII = key_None;
621 for (i = 0;i < NumCodes;i++)
625 ///////////////////////////////////////////////////////////////////////////
627 // INL_AdjustCursor() - Internal routine of common code from IN_ReadCursor()
629 ///////////////////////////////////////////////////////////////////////////
631 INL_AdjustCursor(CursorInfo *info,word buttons,int dx,int dy)
633 if (buttons & (1 << 0))
634 info->button0 = true;
635 if (buttons & (1 << 1))
636 info->button1 = true;
642 ///////////////////////////////////////////////////////////////////////////
644 // IN_ReadCursor() - Reads the input devices and fills in the cursor info
647 ///////////////////////////////////////////////////////////////////////////
649 IN_ReadCursor(CursorInfo *info)
655 info->x = info->y = 0;
656 info->button0 = info->button1 = false;
660 buttons = INL_GetMouseButtons();
661 INL_GetMouseDelta(&dx,&dy);
662 INL_AdjustCursor(info,buttons,dx,dy);
665 for (i = 0;i < MaxJoys;i++)
670 buttons = INL_GetJoyButtons(i);
671 INL_GetJoyDelta(i,&dx,&dy,true);
674 INL_AdjustCursor(info,buttons,dx,dy);
679 ///////////////////////////////////////////////////////////////////////////
681 // IN_ReadControl() - Reads the device associated with the specified
682 // player and fills in the control info struct
684 ///////////////////////////////////////////////////////////////////////////
686 IN_ReadControl(int player,ControlInfo *info)
688 boolean realdelta=false; // MDM (GAMERS EDGE)
694 register KeyboardDef *def;
697 mx = my = motion_None;
701 if (DemoMode == demo_Playback)
703 dbyte = DemoBuffer[DemoOffset + 1];
704 my = (dbyte & 3) - 1;
705 mx = ((dbyte >> 2) & 3) - 1;
706 buttons = (dbyte >> 4) & 3;
708 if (!(--DemoBuffer[DemoOffset]))
711 if (DemoOffset >= DemoSize)
712 DemoMode = demo_PlayDone;
717 else if (DemoMode == demo_PlayDone)
718 Quit("Demo playback exceeded");
722 // MDM begin (GAMERS EDGE) - added this block
723 ControlTypeUsed = ctrl_None;
725 // Handle mouse input...
727 if ((MousePresent) && (ControlTypeUsed == ctrl_None))
729 INL_GetMouseDelta(&dx,&dy);
730 buttons = INL_GetMouseButtons();
732 if (dx || dy || buttons)
733 ControlTypeUsed = ctrl_Mouse;
736 // Handle joystick input...
738 if ((JoystickCalibrated) && (ControlTypeUsed == ctrl_None))
740 type = ctrl_Joystick1;
741 INL_GetJoyDelta(type - ctrl_Joystick,&dx,&dy,false);
742 buttons = INL_GetJoyButtons(type - ctrl_Joystick);
744 if (dx || dy || buttons)
745 ControlTypeUsed = ctrl_Joystick;
748 // Handle keyboard input...
750 if (ControlTypeUsed == ctrl_None)
752 type = ctrl_Keyboard1;
753 def = &KbdDefs[type - ctrl_Keyboard];
755 /* if (Keyboard[def->upleft])
756 mx = motion_Left,my = motion_Up;
757 else if (Keyboard[def->upright])
758 mx = motion_Right,my = motion_Up;
759 else if (Keyboard[def->downleft])
760 mx = motion_Left,my = motion_Down;
761 else if (Keyboard[def->downright])
762 mx = motion_Right,my = motion_Down;*/
764 if (Keyboard[def->up])
766 else if (Keyboard[def->down])
769 if (Keyboard[def->left])
771 else if (Keyboard[def->right])
774 if (Keyboard[def->button0])
776 if (Keyboard[def->button1])
779 if (mx || my || buttons)
780 ControlTypeUsed = ctrl_Keyboard;
781 } // MDM end (GAMERS EDGE)
786 mx = (dx < 0)? motion_Left : ((dx > 0)? motion_Right : motion_None);
787 my = (dy < 0)? motion_Up : ((dy > 0)? motion_Down : motion_None);
799 info->button0 = buttons & (1 << 0);
800 info->button1 = buttons & (1 << 1);
801 info->dir = DirTable[((my + 1) * 3) + (mx + 1)];
804 if (DemoMode == demo_Record)
806 // Pack the control info into a byte
807 dbyte = (buttons << 4) | ((mx + 1) << 2) | (my + 1);
811 (DemoBuffer[DemoOffset + 1] == dbyte)
812 && (DemoBuffer[DemoOffset] < 255)
814 (DemoBuffer[DemoOffset])++;
817 if (DemoOffset || DemoBuffer[DemoOffset])
820 if (DemoOffset >= DemoSize)
821 Quit("Demo buffer overflow");
823 DemoBuffer[DemoOffset] = 1;
824 DemoBuffer[DemoOffset + 1] = dbyte;
831 ///////////////////////////////////////////////////////////////////////////
833 // IN_ReadControl() - Reads the device associated with the specified
834 // player and fills in the control info struct
836 ///////////////////////////////////////////////////////////////////////////
838 IN_ReadControl(int player,ControlInfo *info)
846 register KeyboardDef *def;
849 mx = my = motion_None;
853 if (DemoMode == demo_Playback)
855 dbyte = DemoBuffer[DemoOffset + 1];
856 my = (dbyte & 3) - 1;
857 mx = ((dbyte >> 2) & 3) - 1;
858 buttons = (dbyte >> 4) & 3;
860 if (!(--DemoBuffer[DemoOffset]))
863 if (DemoOffset >= DemoSize)
864 DemoMode = demo_PlayDone;
869 else if (DemoMode == demo_PlayDone)
870 Quit("Demo playback exceeded");
874 switch (type = Controls[player])
878 def = &KbdDefs[type - ctrl_Keyboard];
880 /* if (Keyboard[def->upleft])
881 mx = motion_Left,my = motion_Up;
882 else if (Keyboard[def->upright])
883 mx = motion_Right,my = motion_Up;
884 else if (Keyboard[def->downleft])
885 mx = motion_Left,my = motion_Down;
886 else if (Keyboard[def->downright])
887 mx = motion_Right,my = motion_Down;*/
889 if (Keyboard[def->up])
891 else if (Keyboard[def->down])
894 if (Keyboard[def->left])
896 else if (Keyboard[def->right])
899 if (Keyboard[def->button0])
901 if (Keyboard[def->button1])
907 INL_GetJoyDelta(type - ctrl_Joystick,&dx,&dy,false);
908 buttons = INL_GetJoyButtons(type - ctrl_Joystick);
912 INL_GetMouseDelta(&dx,&dy);
913 buttons = INL_GetMouseButtons();
921 mx = (dx < 0)? motion_Left : ((dx > 0)? motion_Right : motion_None);
922 my = (dy < 0)? motion_Up : ((dy > 0)? motion_Down : motion_None);
934 info->button0 = buttons & (1 << 0);
935 info->button1 = buttons & (1 << 1);
936 info->dir = DirTable[((my + 1) * 3) + (mx + 1)];
939 if (DemoMode == demo_Record)
941 // Pack the control info into a byte
942 dbyte = (buttons << 4) | ((mx + 1) << 2) | (my + 1);
946 (DemoBuffer[DemoOffset + 1] == dbyte)
947 && (DemoBuffer[DemoOffset] < 255)
949 (DemoBuffer[DemoOffset])++;
952 if (DemoOffset || DemoBuffer[DemoOffset])
955 if (DemoOffset >= DemoSize)
956 Quit("Demo buffer overflow");
958 DemoBuffer[DemoOffset] = 1;
959 DemoBuffer[DemoOffset + 1] = dbyte;
966 ///////////////////////////////////////////////////////////////////////////
968 // IN_SetControlType() - Sets the control type to be used by the specified
971 ///////////////////////////////////////////////////////////////////////////
973 IN_SetControlType(int player,ControlType type)
975 // DEBUG - check that requested type is present?
976 Controls[player] = type;
980 ///////////////////////////////////////////////////////////////////////////
982 // IN_StartDemoRecord() - Starts the demo recording, using a buffer the
983 // size passed. Returns if the buffer allocation was successful
985 ///////////////////////////////////////////////////////////////////////////
987 IN_StartDemoRecord(word bufsize)
992 MM_GetPtr((memptr *)&DemoBuffer,bufsize);
993 DemoMode = demo_Record;
994 DemoSize = bufsize & ~1;
996 DemoBuffer[0] = DemoBuffer[1] = 0;
1001 ///////////////////////////////////////////////////////////////////////////
1003 // IN_StartDemoPlayback() - Plays back the demo pointed to of the given size
1005 ///////////////////////////////////////////////////////////////////////////
1007 IN_StartDemoPlayback(byte /*__segment*/ *buffer,word bufsize)
1009 DemoBuffer = buffer;
1010 DemoMode = demo_Playback;
1011 DemoSize = bufsize & ~1;
1015 ///////////////////////////////////////////////////////////////////////////
1017 // IN_StopDemo() - Turns off demo mode
1019 ///////////////////////////////////////////////////////////////////////////
1023 if ((DemoMode == demo_Record) && DemoOffset)
1026 DemoMode = demo_Off;
1029 ///////////////////////////////////////////////////////////////////////////
1031 // IN_FreeDemoBuffer() - Frees the demo buffer, if it's been allocated
1033 ///////////////////////////////////////////////////////////////////////////
1035 IN_FreeDemoBuffer(void)
1038 MM_FreePtr((memptr *)&DemoBuffer);
1044 ///////////////////////////////////////////////////////////////////////////
1046 // IN_GetScanName() - Returns a string containing the name of the
1047 // specified scan code
1049 ///////////////////////////////////////////////////////////////////////////
1051 IN_GetScanName(ScanCode scan)
1056 for (s = ExtScanCodes,p = ExtScanNames;*s;p++,s++)
1060 return(ScanNames[scan]);
1065 ///////////////////////////////////////////////////////////////////////////
1067 // IN_WaitForKey() - Waits for a scan code, then clears LastScan and
1068 // returns the scan code
1070 ///////////////////////////////////////////////////////////////////////////
1076 while (!(result = LastScan))
1082 ///////////////////////////////////////////////////////////////////////////
1084 // IN_WaitForASCII() - Waits for an ASCII char, then clears LastASCII and
1085 // returns the ASCII value
1087 ///////////////////////////////////////////////////////////////////////////
1089 IN_WaitForASCII(void)
1093 while (!(result = LastASCII))
1099 ///////////////////////////////////////////////////////////////////////////
1101 // IN_AckBack() - Waits for either an ASCII keypress or a button press
1103 ///////////////////////////////////////////////////////////////////////////
1113 if (INL_GetMouseButtons())
1115 while (INL_GetMouseButtons())
1121 for (i = 0;i < MaxJoys;i++)
1125 if (IN_GetJoyButtonsDB(i))
1127 while (IN_GetJoyButtonsDB(i))
1135 IN_ClearKey(LastScan);
1139 ///////////////////////////////////////////////////////////////////////////
1141 // IN_Ack() - Clears user input & then calls IN_AckBack()
1143 ///////////////////////////////////////////////////////////////////////////
1149 IN_ClearKey(LastScan);
1153 while (INL_GetMouseButtons())
1155 for (i = 0;i < MaxJoys;i++)
1157 while (IN_GetJoyButtonsDB(i))
1163 ///////////////////////////////////////////////////////////////////////////
1165 // IN_IsUserInput() - Returns true if a key has been pressed or a button
1168 ///////////////////////////////////////////////////////////////////////////
1170 IN_IsUserInput(void)
1178 if (INL_GetMouseButtons())
1181 for (i = 0;i < MaxJoys;i++)
1183 if (INL_GetJoyButtons(i))
1189 ///////////////////////////////////////////////////////////////////////////
1191 // IN_UserInput() - Waits for the specified delay time (in ticks) or the
1192 // user pressing a key or a mouse button. If the clear flag is set, it
1193 // then either clears the key or waits for the user to let the mouse
1196 ///////////////////////////////////////////////////////////////////////////
1198 IN_UserInput(dword delay,boolean clear)
1200 dword TimeCount = *clockdw;
1203 lasttime = TimeCount;
1206 if (IN_IsUserInput())
1212 } while (TimeCount - lasttime < delay);
1216 boolean IN_qb(byte kee)
1218 if(Keyboard[kee]==true) return 1;