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 ///////////////////////////////////////////////////////////////////////////
43 // INL_KeyService() - Handles a keyboard interrupt (key up/down)
45 ///////////////////////////////////////////////////////////////////////////
49 static boolean special;
53 k = inp(0x60); // Get the scan code
55 // Tell the XT keyboard controller to clear the key
56 outp(0x61,(temp = inp(0x61)) | 0x80);
59 if (k == 0xe0) // Special key prefix
61 else if (k == 0xe1) // Handle Pause key
65 if (k & 0x80) // Break code
69 // DEBUG - handle special keys: ctl-alt-delete, print scrn
76 CurCode = LastScan = k;
86 // DEBUG - make caps lock light work
89 if (Keyboard[sc_LShift] || Keyboard[sc_RShift]) // If shifted
92 if ((c >= 'A') && (c <= 'Z') && CapsLock)
98 if ((c >= 'a') && (c <= 'z') && CapsLock)
109 if (INL_KeyHook && !special)
112 printf("%c %x %u\n", c, k, Keyboard[k]);
122 int86(MouseInt,&CPURegs,&CPURegs);
125 ///////////////////////////////////////////////////////////////////////////
127 // INL_GetMouseDelta() - Gets the amount that the mouse has moved from the
130 ///////////////////////////////////////////////////////////////////////////
132 INL_GetMouseDelta(int *x,int *y)
140 ///////////////////////////////////////////////////////////////////////////
142 // INL_GetMouseButtons() - Gets the status of the mouse buttons from the
145 ///////////////////////////////////////////////////////////////////////////
147 INL_GetMouseButtons(void)
153 buttons = CPURegs.x.bx;
157 ///////////////////////////////////////////////////////////////////////////
159 // IN_GetJoyAbs() - Reads the absolute position of the specified joystick
161 ///////////////////////////////////////////////////////////////////////////
163 IN_GetJoyAbs(word joy,word *xp,word *yp)
170 xs = joy? 2 : 0; // Find shift value for x axis
171 xb = 1 << xs; // Use shift value to get x bit mask
172 ys = joy? 3 : 1; // Do the same for y axis
175 // Read the absolute joystick values
178 pushf // Save some registers
181 cli // Make sure an interrupt doesn't screw the timings
186 out dx,al // Clear the resistors
188 mov ah,[xb] // Get masks into registers
191 xor si,si // Clear count registers
193 xor bh,bh // Clear high byte of bx for later
195 push bp // Don't mess up stack frame
199 in al,dx // Get bits indicating whether all are finished
201 dec bp // Check bounding register
202 jz done // We have a silly value - abort
204 mov bl,al // Duplicate the bits
205 and bl,ah // Mask off useless bits (in [xb])
206 add si,bx // Possibly increment count register
207 mov cl,bl // Save for testing later
214 jnz loo // If both bits were 0, drop out
219 mov cl,[xs] // Get the number of bits to shift
220 shr si,cl // and shift the count that many times
225 mov [x],si // Store the values into the variables
230 popf // Restore the registers
237 ///////////////////////////////////////////////////////////////////////////
239 // INL_GetJoyDelta() - Returns the relative movement of the specified
240 // joystick (from +/-127, scaled adaptively)
242 ///////////////////////////////////////////////////////////////////////////
244 INL_GetJoyDelta(word joy,int *dx,int *dy,boolean adaptive)
248 dword TimeCount = *clockdw;
250 static dword lasttime;
252 IN_GetJoyAbs(joy,&x,&y);
255 if (x < def->threshMinX)
257 if (x < def->joyMinX)
260 x = -(x - def->threshMinX);
263 *dx = (x > 127)? -127 : -x;
265 else if (x > def->threshMaxX)
267 if (x > def->joyMaxX)
270 x = x - def->threshMaxX;
273 *dx = (x > 127)? 127 : x;
278 if (y < def->threshMinY)
280 if (y < def->joyMinY)
283 y = -(y - def->threshMinY);
286 *dy = (y > 127)? -127 : -y;
288 else if (y > def->threshMaxY)
290 if (y > def->joyMaxY)
293 y = y - def->threshMaxY;
296 *dy = (y > 127)? 127 : y;
303 time = (TimeCount - lasttime) / 2;
312 lasttime = TimeCount;
315 ///////////////////////////////////////////////////////////////////////////
317 // INL_GetJoyButtons() - Returns the button status of the specified
320 ///////////////////////////////////////////////////////////////////////////
322 INL_GetJoyButtons(word joy)
324 register word result;
326 result = inp(0x201); // Get all the joystick buttons
327 result >>= joy? 6 : 4; // Shift into bits 0-1
328 result &= 3; // Mask off the useless bits
333 ///////////////////////////////////////////////////////////////////////////
335 // IN_GetJoyButtonsDB() - Returns the de-bounced button status of the
336 // specified joystick
338 ///////////////////////////////////////////////////////////////////////////
340 IN_GetJoyButtonsDB(word joy)
342 dword TimeCount = *clockdw;
344 word result1,result2;
348 result1 = INL_GetJoyButtons(joy);
349 lasttime = TimeCount;
350 while(TimeCount == lasttime)
351 result2 = INL_GetJoyButtons(joy);
352 } while(result1 != result2);
356 ///////////////////////////////////////////////////////////////////////////
358 // INL_StartKbd() - Sets up my keyboard stuff for use
360 ///////////////////////////////////////////////////////////////////////////
364 INL_KeyHook = 0; // Clear key hook
368 OldKeyVect = _dos_getvect(KeyInt);
369 _dos_setvect(KeyInt,INL_KeyService);
372 ///////////////////////////////////////////////////////////////////////////
374 // INL_ShutKbd() - Restores keyboard control to the BIOS
376 ///////////////////////////////////////////////////////////////////////////
380 pokeb(0x40,0x17,peekb(0x40,0x17) & 0xfaf0); // Clear ctrl/alt/shift flags
382 _dos_setvect(KeyInt,OldKeyVect);
385 ///////////////////////////////////////////////////////////////////////////
387 // INL_StartMouse() - Detects and sets up the mouse
389 ///////////////////////////////////////////////////////////////////////////
394 if(_dos_getvect(MouseInt))
397 if(CPURegs.x.ax == 0xffff)
403 ///////////////////////////////////////////////////////////////////////////
405 // INL_ShutMouse() - Cleans up after the mouse
407 ///////////////////////////////////////////////////////////////////////////
414 // INL_SetJoyScale() - Sets up scaling values for the specified joystick
417 INL_SetJoyScale(word joy)
422 def->joyMultXL = JoyScaleMax / (def->threshMinX - def->joyMinX);
423 def->joyMultXH = JoyScaleMax / (def->joyMaxX - def->threshMaxX);
424 def->joyMultYL = JoyScaleMax / (def->threshMinY - def->joyMinY);
425 def->joyMultYH = JoyScaleMax / (def->joyMaxY - def->threshMaxY);
428 ///////////////////////////////////////////////////////////////////////////
430 // IN_SetupJoy() - Sets up thresholding values and calls INL_SetJoyScale()
431 // to set up scaling values
433 ///////////////////////////////////////////////////////////////////////////
435 IN_SetupJoy(word joy,word minx,word maxx,word miny,word maxy)
446 def->threshMinX = ((r / 2) - d) + minx;
447 def->threshMaxX = ((r / 2) + d) + minx;
453 def->threshMinY = ((r / 2) - d) + miny;
454 def->threshMaxY = ((r / 2) + d) + miny;
456 INL_SetJoyScale(joy);
459 ///////////////////////////////////////////////////////////////////////////
461 // INL_StartJoy() - Detects & auto-configures the specified joystick
462 // The auto-config assumes the joystick is centered
464 ///////////////////////////////////////////////////////////////////////////
466 INL_StartJoy(word joy)
470 IN_GetJoyAbs(joy,&x,&y);
474 ((x == 0) || (x > MaxJoyValue - 10))
475 || ((y == 0) || (y > MaxJoyValue - 10))
480 IN_SetupJoy(joy,0,x * 2,0,y * 2);
485 ///////////////////////////////////////////////////////////////////////////
487 // INL_ShutJoy() - Cleans up the joystick stuff
489 ///////////////////////////////////////////////////////////////////////////
491 INL_ShutJoy(word joy)
493 JoysPresent[joy] = false;
498 ///////////////////////////////////////////////////////////////////////////
500 // IN_Startup() - Starts up the Input Mgr
502 ///////////////////////////////////////////////////////////////////////////
506 boolean checkjoys,checkmouse;
514 for (i = 1;i < __argc;i++)
516 switch (US_CheckParm(__argv[i],ParmStrings))
528 MousePresent = checkmouse? INL_StartMouse() : false;
530 for (i = 0;i < MaxJoys;i++)
531 JoysPresent[i] = checkjoys? INL_StartJoy(i) : false;
536 ///////////////////////////////////////////////////////////////////////////
538 // IN_Default() - Sets up default conditions for the Input Mgr
540 ///////////////////////////////////////////////////////////////////////////
542 IN_Default(boolean gotit,ControlType in)
547 || ((in == ctrl_Joystick1) && !JoysPresent[0])
548 || ((in == ctrl_Joystick2) && !JoysPresent[1])
549 || ((in == ctrl_Mouse) && !MousePresent)
552 IN_SetControlType(0,in);
555 ///////////////////////////////////////////////////////////////////////////
557 // IN_Shutdown() - Shuts down the Input Mgr
559 ///////////////////////////////////////////////////////////////////////////
569 for (i = 0;i < MaxJoys;i++)
576 ///////////////////////////////////////////////////////////////////////////
578 // IN_SetKeyHook() - Sets the routine that gets called by INL_KeyService()
579 // everytime a real make/break code gets hit
581 ///////////////////////////////////////////////////////////////////////////
583 IN_SetKeyHook(void (*hook)())
588 ///////////////////////////////////////////////////////////////////////////
590 // IN_ClearKeyDown() - Clears the keyboard array
592 ///////////////////////////////////////////////////////////////////////////
594 IN_ClearKeysDown(void)
599 LastASCII = key_None;
600 for (i = 0;i < NumCodes;i++)
604 ///////////////////////////////////////////////////////////////////////////
606 // INL_AdjustCursor() - Internal routine of common code from IN_ReadCursor()
608 ///////////////////////////////////////////////////////////////////////////
610 INL_AdjustCursor(CursorInfo *info,word buttons,int dx,int dy)
612 if (buttons & (1 << 0))
613 info->button0 = true;
614 if (buttons & (1 << 1))
615 info->button1 = true;
621 ///////////////////////////////////////////////////////////////////////////
623 // IN_ReadCursor() - Reads the input devices and fills in the cursor info
626 ///////////////////////////////////////////////////////////////////////////
628 IN_ReadCursor(CursorInfo *info)
634 info->x = info->y = 0;
635 info->button0 = info->button1 = false;
639 buttons = INL_GetMouseButtons();
640 INL_GetMouseDelta(&dx,&dy);
641 INL_AdjustCursor(info,buttons,dx,dy);
644 for (i = 0;i < MaxJoys;i++)
649 buttons = INL_GetJoyButtons(i);
650 INL_GetJoyDelta(i,&dx,&dy,true);
653 INL_AdjustCursor(info,buttons,dx,dy);
658 ///////////////////////////////////////////////////////////////////////////
660 // IN_ReadControl() - Reads the device associated with the specified
661 // player and fills in the control info struct
663 ///////////////////////////////////////////////////////////////////////////
665 IN_ReadControl(int player,ControlInfo *info)
667 boolean realdelta=false; // MDM (GAMERS EDGE)
673 register KeyboardDef *def;
676 mx = my = motion_None;
680 if (DemoMode == demo_Playback)
682 dbyte = DemoBuffer[DemoOffset + 1];
683 my = (dbyte & 3) - 1;
684 mx = ((dbyte >> 2) & 3) - 1;
685 buttons = (dbyte >> 4) & 3;
687 if (!(--DemoBuffer[DemoOffset]))
690 if (DemoOffset >= DemoSize)
691 DemoMode = demo_PlayDone;
696 else if (DemoMode == demo_PlayDone)
697 Quit("Demo playback exceeded");
701 // MDM begin (GAMERS EDGE) - added this block
702 ControlTypeUsed = ctrl_None;
704 // Handle mouse input...
706 if ((MousePresent) && (ControlTypeUsed == ctrl_None))
708 INL_GetMouseDelta(&dx,&dy);
709 buttons = INL_GetMouseButtons();
711 if (dx || dy || buttons)
712 ControlTypeUsed = ctrl_Mouse;
715 // Handle joystick input...
717 if ((JoystickCalibrated) && (ControlTypeUsed == ctrl_None))
719 type = ctrl_Joystick1;
720 INL_GetJoyDelta(type - ctrl_Joystick,&dx,&dy,false);
721 buttons = INL_GetJoyButtons(type - ctrl_Joystick);
723 if (dx || dy || buttons)
724 ControlTypeUsed = ctrl_Joystick;
727 // Handle keyboard input...
729 if (ControlTypeUsed == ctrl_None)
731 type = ctrl_Keyboard1;
732 def = &KbdDefs[type - ctrl_Keyboard];
734 /* if (Keyboard[def->upleft])
735 mx = motion_Left,my = motion_Up;
736 else if (Keyboard[def->upright])
737 mx = motion_Right,my = motion_Up;
738 else if (Keyboard[def->downleft])
739 mx = motion_Left,my = motion_Down;
740 else if (Keyboard[def->downright])
741 mx = motion_Right,my = motion_Down;*/
743 if (Keyboard[def->up])
745 else if (Keyboard[def->down])
748 if (Keyboard[def->left])
750 else if (Keyboard[def->right])
753 if (Keyboard[def->button0])
755 if (Keyboard[def->button1])
758 if (mx || my || buttons)
759 ControlTypeUsed = ctrl_Keyboard;
760 } // MDM end (GAMERS EDGE)
765 mx = (dx < 0)? motion_Left : ((dx > 0)? motion_Right : motion_None);
766 my = (dy < 0)? motion_Up : ((dy > 0)? motion_Down : motion_None);
778 info->button0 = buttons & (1 << 0);
779 info->button1 = buttons & (1 << 1);
780 info->dir = DirTable[((my + 1) * 3) + (mx + 1)];
783 if (DemoMode == demo_Record)
785 // Pack the control info into a byte
786 dbyte = (buttons << 4) | ((mx + 1) << 2) | (my + 1);
790 (DemoBuffer[DemoOffset + 1] == dbyte)
791 && (DemoBuffer[DemoOffset] < 255)
793 (DemoBuffer[DemoOffset])++;
796 if (DemoOffset || DemoBuffer[DemoOffset])
799 if (DemoOffset >= DemoSize)
800 Quit("Demo buffer overflow");
802 DemoBuffer[DemoOffset] = 1;
803 DemoBuffer[DemoOffset + 1] = dbyte;
810 ///////////////////////////////////////////////////////////////////////////
812 // IN_ReadControl() - Reads the device associated with the specified
813 // player and fills in the control info struct
815 ///////////////////////////////////////////////////////////////////////////
817 IN_ReadControl(int player,ControlInfo *info)
825 register KeyboardDef *def;
828 mx = my = motion_None;
832 if (DemoMode == demo_Playback)
834 dbyte = DemoBuffer[DemoOffset + 1];
835 my = (dbyte & 3) - 1;
836 mx = ((dbyte >> 2) & 3) - 1;
837 buttons = (dbyte >> 4) & 3;
839 if (!(--DemoBuffer[DemoOffset]))
842 if (DemoOffset >= DemoSize)
843 DemoMode = demo_PlayDone;
848 else if (DemoMode == demo_PlayDone)
849 Quit("Demo playback exceeded");
853 switch (type = Controls[player])
857 def = &KbdDefs[type - ctrl_Keyboard];
859 /* if (Keyboard[def->upleft])
860 mx = motion_Left,my = motion_Up;
861 else if (Keyboard[def->upright])
862 mx = motion_Right,my = motion_Up;
863 else if (Keyboard[def->downleft])
864 mx = motion_Left,my = motion_Down;
865 else if (Keyboard[def->downright])
866 mx = motion_Right,my = motion_Down;*/
868 if (Keyboard[def->up])
870 else if (Keyboard[def->down])
873 if (Keyboard[def->left])
875 else if (Keyboard[def->right])
878 if (Keyboard[def->button0])
880 if (Keyboard[def->button1])
886 INL_GetJoyDelta(type - ctrl_Joystick,&dx,&dy,false);
887 buttons = INL_GetJoyButtons(type - ctrl_Joystick);
891 INL_GetMouseDelta(&dx,&dy);
892 buttons = INL_GetMouseButtons();
900 mx = (dx < 0)? motion_Left : ((dx > 0)? motion_Right : motion_None);
901 my = (dy < 0)? motion_Up : ((dy > 0)? motion_Down : motion_None);
913 info->button0 = buttons & (1 << 0);
914 info->button1 = buttons & (1 << 1);
915 info->dir = DirTable[((my + 1) * 3) + (mx + 1)];
918 if (DemoMode == demo_Record)
920 // Pack the control info into a byte
921 dbyte = (buttons << 4) | ((mx + 1) << 2) | (my + 1);
925 (DemoBuffer[DemoOffset + 1] == dbyte)
926 && (DemoBuffer[DemoOffset] < 255)
928 (DemoBuffer[DemoOffset])++;
931 if (DemoOffset || DemoBuffer[DemoOffset])
934 if (DemoOffset >= DemoSize)
935 Quit("Demo buffer overflow");
937 DemoBuffer[DemoOffset] = 1;
938 DemoBuffer[DemoOffset + 1] = dbyte;
945 ///////////////////////////////////////////////////////////////////////////
947 // IN_SetControlType() - Sets the control type to be used by the specified
950 ///////////////////////////////////////////////////////////////////////////
952 IN_SetControlType(int player,ControlType type)
954 // DEBUG - check that requested type is present?
955 Controls[player] = type;
959 ///////////////////////////////////////////////////////////////////////////
961 // IN_StartDemoRecord() - Starts the demo recording, using a buffer the
962 // size passed. Returns if the buffer allocation was successful
964 ///////////////////////////////////////////////////////////////////////////
966 IN_StartDemoRecord(word bufsize)
971 MM_GetPtr((memptr *)&DemoBuffer,bufsize);
972 DemoMode = demo_Record;
973 DemoSize = bufsize & ~1;
975 DemoBuffer[0] = DemoBuffer[1] = 0;
980 ///////////////////////////////////////////////////////////////////////////
982 // IN_StartDemoPlayback() - Plays back the demo pointed to of the given size
984 ///////////////////////////////////////////////////////////////////////////
986 IN_StartDemoPlayback(byte /*__segment*/ *buffer,word bufsize)
989 DemoMode = demo_Playback;
990 DemoSize = bufsize & ~1;
994 ///////////////////////////////////////////////////////////////////////////
996 // IN_StopDemo() - Turns off demo mode
998 ///////////////////////////////////////////////////////////////////////////
1002 if ((DemoMode == demo_Record) && DemoOffset)
1005 DemoMode = demo_Off;
1008 ///////////////////////////////////////////////////////////////////////////
1010 // IN_FreeDemoBuffer() - Frees the demo buffer, if it's been allocated
1012 ///////////////////////////////////////////////////////////////////////////
1014 IN_FreeDemoBuffer(void)
1017 MM_FreePtr((memptr *)&DemoBuffer);
1023 ///////////////////////////////////////////////////////////////////////////
1025 // IN_GetScanName() - Returns a string containing the name of the
1026 // specified scan code
1028 ///////////////////////////////////////////////////////////////////////////
1030 IN_GetScanName(ScanCode scan)
1035 for (s = ExtScanCodes,p = ExtScanNames;*s;p++,s++)
1039 return(ScanNames[scan]);
1044 ///////////////////////////////////////////////////////////////////////////
1046 // IN_WaitForKey() - Waits for a scan code, then clears LastScan and
1047 // returns the scan code
1049 ///////////////////////////////////////////////////////////////////////////
1055 while (!(result = LastScan))
1061 ///////////////////////////////////////////////////////////////////////////
1063 // IN_WaitForASCII() - Waits for an ASCII char, then clears LastASCII and
1064 // returns the ASCII value
1066 ///////////////////////////////////////////////////////////////////////////
1068 IN_WaitForASCII(void)
1072 while (!(result = LastASCII))
1078 ///////////////////////////////////////////////////////////////////////////
1080 // IN_AckBack() - Waits for either an ASCII keypress or a button press
1082 ///////////////////////////////////////////////////////////////////////////
1092 if (INL_GetMouseButtons())
1094 while (INL_GetMouseButtons())
1100 for (i = 0;i < MaxJoys;i++)
1104 if (IN_GetJoyButtonsDB(i))
1106 while (IN_GetJoyButtonsDB(i))
1114 IN_ClearKey(LastScan);
1118 ///////////////////////////////////////////////////////////////////////////
1120 // IN_Ack() - Clears user input & then calls IN_AckBack()
1122 ///////////////////////////////////////////////////////////////////////////
1128 IN_ClearKey(LastScan);
1132 while (INL_GetMouseButtons())
1134 for (i = 0;i < MaxJoys;i++)
1136 while (IN_GetJoyButtonsDB(i))
1142 ///////////////////////////////////////////////////////////////////////////
1144 // IN_IsUserInput() - Returns true if a key has been pressed or a button
1147 ///////////////////////////////////////////////////////////////////////////
1149 IN_IsUserInput(void)
1157 if (INL_GetMouseButtons())
1160 for (i = 0;i < MaxJoys;i++)
1162 if (INL_GetJoyButtons(i))
1168 ///////////////////////////////////////////////////////////////////////////
1170 // IN_UserInput() - Waits for the specified delay time (in ticks) or the
1171 // user pressing a key or a mouse button. If the clear flag is set, it
1172 // then either clears the key or waits for the user to let the mouse
1175 ///////////////////////////////////////////////////////////////////////////
1177 IN_UserInput(dword delay,boolean clear)
1179 dword TimeCount = *clockdw;
1182 lasttime = TimeCount;
1185 if (IN_IsUserInput())
1191 } while (TimeCount - lasttime < delay);
1195 boolean IN_qb(byte kee)
1197 if(Keyboard[kee]==true) return 1;