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"
42 ///////////////////////////////////////////////////////////////////////////
44 // INL_KeyService() - Handles a keyboard interrupt (key up/down)
46 ///////////////////////////////////////////////////////////////////////////
50 static boolean special;
54 k = inp(0x60); // Get the scan code
56 // Tell the XT keyboard controller to clear the key
57 outp(0x61,(temp = inp(0x61)) | 0x80);
60 if (k == 0xe0) // Special key prefix
62 else if (k == 0xe1) // Handle Pause key
66 if (k & 0x80) // Break code
70 // DEBUG - handle special keys: ctl-alt-delete, print scrn
77 CurCode = LastScan = k;
87 // DEBUG - make caps lock light work
90 if (Keyboard[sc_LShift] || Keyboard[sc_RShift]) // If shifted
93 if ((c >= 'A') && (c <= 'Z') && CapsLock)
99 if ((c >= 'a') && (c <= 'z') && CapsLock)
110 if (INL_KeyHook && !special)
120 int86(MouseInt,&CPURegs,&CPURegs);
123 ///////////////////////////////////////////////////////////////////////////
125 // INL_GetMouseDelta() - Gets the amount that the mouse has moved from the
128 ///////////////////////////////////////////////////////////////////////////
130 INL_GetMouseDelta(int *x,int *y)
138 ///////////////////////////////////////////////////////////////////////////
140 // INL_GetMouseButtons() - Gets the status of the mouse buttons from the
143 ///////////////////////////////////////////////////////////////////////////
145 INL_GetMouseButtons(void)
151 buttons = CPURegs.x.bx;
155 ///////////////////////////////////////////////////////////////////////////
157 // IN_GetJoyAbs() - Reads the absolute position of the specified joystick
159 ///////////////////////////////////////////////////////////////////////////
161 IN_GetJoyAbs(word joy,word *xp,word *yp)
168 xs = joy? 2 : 0; // Find shift value for x axis
169 xb = 1 << xs; // Use shift value to get x bit mask
170 ys = joy? 3 : 1; // Do the same for y axis
173 // Read the absolute joystick values
176 pushf // Save some registers
179 cli // Make sure an interrupt doesn't screw the timings
184 out dx,al // Clear the resistors
186 mov ah,[xb] // Get masks into registers
189 xor si,si // Clear count registers
191 xor bh,bh // Clear high byte of bx for later
193 push bp // Don't mess up stack frame
197 in al,dx // Get bits indicating whether all are finished
199 dec bp // Check bounding register
200 jz done // We have a silly value - abort
202 mov bl,al // Duplicate the bits
203 and bl,ah // Mask off useless bits (in [xb])
204 add si,bx // Possibly increment count register
205 mov cl,bl // Save for testing later
212 jnz loo // If both bits were 0, drop out
217 mov cl,[xs] // Get the number of bits to shift
218 shr si,cl // and shift the count that many times
223 mov [x],si // Store the values into the variables
228 popf // Restore the registers
235 ///////////////////////////////////////////////////////////////////////////
237 // INL_GetJoyDelta() - Returns the relative movement of the specified
238 // joystick (from +/-127, scaled adaptively)
240 ///////////////////////////////////////////////////////////////////////////
242 INL_GetJoyDelta(word joy,int *dx,int *dy,boolean adaptive)
246 dword TimeCount = *clockdw;
248 static dword lasttime;
250 IN_GetJoyAbs(joy,&x,&y);
253 if (x < def->threshMinX)
255 if (x < def->joyMinX)
258 x = -(x - def->threshMinX);
261 *dx = (x > 127)? -127 : -x;
263 else if (x > def->threshMaxX)
265 if (x > def->joyMaxX)
268 x = x - def->threshMaxX;
271 *dx = (x > 127)? 127 : x;
276 if (y < def->threshMinY)
278 if (y < def->joyMinY)
281 y = -(y - def->threshMinY);
284 *dy = (y > 127)? -127 : -y;
286 else if (y > def->threshMaxY)
288 if (y > def->joyMaxY)
291 y = y - def->threshMaxY;
294 *dy = (y > 127)? 127 : y;
301 time = (TimeCount - lasttime) / 2;
310 lasttime = TimeCount;
313 ///////////////////////////////////////////////////////////////////////////
315 // INL_GetJoyButtons() - Returns the button status of the specified
318 ///////////////////////////////////////////////////////////////////////////
320 INL_GetJoyButtons(word joy)
322 register word result;
324 result = inp(0x201); // Get all the joystick buttons
325 result >>= joy? 6 : 4; // Shift into bits 0-1
326 result &= 3; // Mask off the useless bits
331 ///////////////////////////////////////////////////////////////////////////
333 // IN_GetJoyButtonsDB() - Returns the de-bounced button status of the
334 // specified joystick
336 ///////////////////////////////////////////////////////////////////////////
338 IN_GetJoyButtonsDB(word joy)
340 dword TimeCount = *clockdw;
342 word result1,result2;
346 result1 = INL_GetJoyButtons(joy);
347 lasttime = TimeCount;
348 while(TimeCount == lasttime)
349 result2 = INL_GetJoyButtons(joy);
350 } while(result1 != result2);
354 ///////////////////////////////////////////////////////////////////////////
356 // INL_StartKbd() - Sets up my keyboard stuff for use
358 ///////////////////////////////////////////////////////////////////////////
362 INL_KeyHook = 0; // Clear key hook
366 OldKeyVect = _dos_getvect(KeyInt);
367 _dos_setvect(KeyInt,INL_KeyService);
370 ///////////////////////////////////////////////////////////////////////////
372 // INL_ShutKbd() - Restores keyboard control to the BIOS
374 ///////////////////////////////////////////////////////////////////////////
378 pokeb(0x40,0x17,peekb(0x40,0x17) & 0xfaf0); // Clear ctrl/alt/shift flags
380 _dos_setvect(KeyInt,OldKeyVect);
383 ///////////////////////////////////////////////////////////////////////////
385 // INL_StartMouse() - Detects and sets up the mouse
387 ///////////////////////////////////////////////////////////////////////////
392 if(_dos_getvect(MouseInt))
395 if(CPURegs.x.ax == 0xffff)
401 ///////////////////////////////////////////////////////////////////////////
403 // INL_ShutMouse() - Cleans up after the mouse
405 ///////////////////////////////////////////////////////////////////////////
412 // INL_SetJoyScale() - Sets up scaling values for the specified joystick
415 INL_SetJoyScale(word joy)
420 def->joyMultXL = JoyScaleMax / (def->threshMinX - def->joyMinX);
421 def->joyMultXH = JoyScaleMax / (def->joyMaxX - def->threshMaxX);
422 def->joyMultYL = JoyScaleMax / (def->threshMinY - def->joyMinY);
423 def->joyMultYH = JoyScaleMax / (def->joyMaxY - def->threshMaxY);
426 ///////////////////////////////////////////////////////////////////////////
428 // IN_SetupJoy() - Sets up thresholding values and calls INL_SetJoyScale()
429 // to set up scaling values
431 ///////////////////////////////////////////////////////////////////////////
433 IN_SetupJoy(word joy,word minx,word maxx,word miny,word maxy)
444 def->threshMinX = ((r / 2) - d) + minx;
445 def->threshMaxX = ((r / 2) + d) + minx;
451 def->threshMinY = ((r / 2) - d) + miny;
452 def->threshMaxY = ((r / 2) + d) + miny;
454 INL_SetJoyScale(joy);
457 ///////////////////////////////////////////////////////////////////////////
459 // INL_StartJoy() - Detects & auto-configures the specified joystick
460 // The auto-config assumes the joystick is centered
462 ///////////////////////////////////////////////////////////////////////////
464 INL_StartJoy(word joy)
468 IN_GetJoyAbs(joy,&x,&y);
472 ((x == 0) || (x > MaxJoyValue - 10))
473 || ((y == 0) || (y > MaxJoyValue - 10))
478 IN_SetupJoy(joy,0,x * 2,0,y * 2);
483 ///////////////////////////////////////////////////////////////////////////
485 // INL_ShutJoy() - Cleans up the joystick stuff
487 ///////////////////////////////////////////////////////////////////////////
489 INL_ShutJoy(word joy)
491 JoysPresent[joy] = false;
496 ///////////////////////////////////////////////////////////////////////////
498 // IN_Startup() - Starts up the Input Mgr
500 ///////////////////////////////////////////////////////////////////////////
504 boolean checkjoys,checkmouse;
512 for (i = 1;i < __argc;i++)
514 switch (US_CheckParm(__argv[i],ParmStrings))
526 MousePresent = checkmouse? INL_StartMouse() : false;
528 for (i = 0;i < MaxJoys;i++)
529 JoysPresent[i] = checkjoys? INL_StartJoy(i) : false;
534 ///////////////////////////////////////////////////////////////////////////
536 // IN_Default() - Sets up default conditions for the Input Mgr
538 ///////////////////////////////////////////////////////////////////////////
540 IN_Default(boolean gotit,ControlType in)
545 || ((in == ctrl_Joystick1) && !JoysPresent[0])
546 || ((in == ctrl_Joystick2) && !JoysPresent[1])
547 || ((in == ctrl_Mouse) && !MousePresent)
550 IN_SetControlType(0,in);
553 ///////////////////////////////////////////////////////////////////////////
555 // IN_Shutdown() - Shuts down the Input Mgr
557 ///////////////////////////////////////////////////////////////////////////
567 for (i = 0;i < MaxJoys;i++)
574 ///////////////////////////////////////////////////////////////////////////
576 // IN_SetKeyHook() - Sets the routine that gets called by INL_KeyService()
577 // everytime a real make/break code gets hit
579 ///////////////////////////////////////////////////////////////////////////
581 IN_SetKeyHook(void (*hook)())
586 ///////////////////////////////////////////////////////////////////////////
588 // IN_ClearKeyDown() - Clears the keyboard array
590 ///////////////////////////////////////////////////////////////////////////
592 IN_ClearKeysDown(void)
597 LastASCII = key_None;
598 for (i = 0;i < NumCodes;i++)
602 ///////////////////////////////////////////////////////////////////////////
604 // INL_AdjustCursor() - Internal routine of common code from IN_ReadCursor()
606 ///////////////////////////////////////////////////////////////////////////
608 INL_AdjustCursor(CursorInfo *info,word buttons,int dx,int dy)
610 if (buttons & (1 << 0))
611 info->button0 = true;
612 if (buttons & (1 << 1))
613 info->button1 = true;
619 ///////////////////////////////////////////////////////////////////////////
621 // IN_ReadCursor() - Reads the input devices and fills in the cursor info
624 ///////////////////////////////////////////////////////////////////////////
626 IN_ReadCursor(CursorInfo *info)
632 info->x = info->y = 0;
633 info->button0 = info->button1 = false;
637 buttons = INL_GetMouseButtons();
638 INL_GetMouseDelta(&dx,&dy);
639 INL_AdjustCursor(info,buttons,dx,dy);
642 for (i = 0;i < MaxJoys;i++)
647 buttons = INL_GetJoyButtons(i);
648 INL_GetJoyDelta(i,&dx,&dy,true);
651 INL_AdjustCursor(info,buttons,dx,dy);
656 ///////////////////////////////////////////////////////////////////////////
658 // IN_ReadControl() - Reads the device associated with the specified
659 // player and fills in the control info struct
661 ///////////////////////////////////////////////////////////////////////////
663 IN_ReadControl(int player,ControlInfo *info)
665 boolean realdelta=false; // MDM (GAMERS EDGE)
671 register KeyboardDef *def;
674 mx = my = motion_None;
678 if (DemoMode == demo_Playback)
680 dbyte = DemoBuffer[DemoOffset + 1];
681 my = (dbyte & 3) - 1;
682 mx = ((dbyte >> 2) & 3) - 1;
683 buttons = (dbyte >> 4) & 3;
685 if (!(--DemoBuffer[DemoOffset]))
688 if (DemoOffset >= DemoSize)
689 DemoMode = demo_PlayDone;
694 else if (DemoMode == demo_PlayDone)
695 Quit("Demo playback exceeded");
699 // MDM begin (GAMERS EDGE) - added this block
700 ControlTypeUsed = ctrl_None;
702 // Handle mouse input...
704 if ((MousePresent) && (ControlTypeUsed == ctrl_None))
706 INL_GetMouseDelta(&dx,&dy);
707 buttons = INL_GetMouseButtons();
709 if (dx || dy || buttons)
710 ControlTypeUsed = ctrl_Mouse;
713 // Handle joystick input...
715 if ((JoystickCalibrated) && (ControlTypeUsed == ctrl_None))
717 type = ctrl_Joystick1;
718 INL_GetJoyDelta(type - ctrl_Joystick,&dx,&dy,false);
719 buttons = INL_GetJoyButtons(type - ctrl_Joystick);
721 if (dx || dy || buttons)
722 ControlTypeUsed = ctrl_Joystick;
725 // Handle keyboard input...
727 if (ControlTypeUsed == ctrl_None)
729 type = ctrl_Keyboard1;
730 def = &KbdDefs[type - ctrl_Keyboard];
732 /* if (Keyboard[def->upleft])
733 mx = motion_Left,my = motion_Up;
734 else if (Keyboard[def->upright])
735 mx = motion_Right,my = motion_Up;
736 else if (Keyboard[def->downleft])
737 mx = motion_Left,my = motion_Down;
738 else if (Keyboard[def->downright])
739 mx = motion_Right,my = motion_Down;*/
741 if (Keyboard[def->up])
743 else if (Keyboard[def->down])
746 if (Keyboard[def->left])
748 else if (Keyboard[def->right])
751 if (Keyboard[def->button0])
753 if (Keyboard[def->button1])
756 if (mx || my || buttons)
757 ControlTypeUsed = ctrl_Keyboard;
758 } // MDM end (GAMERS EDGE)
763 mx = (dx < 0)? motion_Left : ((dx > 0)? motion_Right : motion_None);
764 my = (dy < 0)? motion_Up : ((dy > 0)? motion_Down : motion_None);
776 info->button0 = buttons & (1 << 0);
777 info->button1 = buttons & (1 << 1);
778 info->dir = DirTable[((my + 1) * 3) + (mx + 1)];
781 if (DemoMode == demo_Record)
783 // Pack the control info into a byte
784 dbyte = (buttons << 4) | ((mx + 1) << 2) | (my + 1);
788 (DemoBuffer[DemoOffset + 1] == dbyte)
789 && (DemoBuffer[DemoOffset] < 255)
791 (DemoBuffer[DemoOffset])++;
794 if (DemoOffset || DemoBuffer[DemoOffset])
797 if (DemoOffset >= DemoSize)
798 Quit("Demo buffer overflow");
800 DemoBuffer[DemoOffset] = 1;
801 DemoBuffer[DemoOffset + 1] = dbyte;
808 ///////////////////////////////////////////////////////////////////////////
810 // IN_ReadControl() - Reads the device associated with the specified
811 // player and fills in the control info struct
813 ///////////////////////////////////////////////////////////////////////////
815 IN_ReadControl(int player,ControlInfo *info)
823 register KeyboardDef *def;
826 mx = my = motion_None;
830 if (DemoMode == demo_Playback)
832 dbyte = DemoBuffer[DemoOffset + 1];
833 my = (dbyte & 3) - 1;
834 mx = ((dbyte >> 2) & 3) - 1;
835 buttons = (dbyte >> 4) & 3;
837 if (!(--DemoBuffer[DemoOffset]))
840 if (DemoOffset >= DemoSize)
841 DemoMode = demo_PlayDone;
846 else if (DemoMode == demo_PlayDone)
847 Quit("Demo playback exceeded");
851 switch (type = Controls[player])
855 def = &KbdDefs[type - ctrl_Keyboard];
857 /* if (Keyboard[def->upleft])
858 mx = motion_Left,my = motion_Up;
859 else if (Keyboard[def->upright])
860 mx = motion_Right,my = motion_Up;
861 else if (Keyboard[def->downleft])
862 mx = motion_Left,my = motion_Down;
863 else if (Keyboard[def->downright])
864 mx = motion_Right,my = motion_Down;*/
866 if (Keyboard[def->up])
868 else if (Keyboard[def->down])
871 if (Keyboard[def->left])
873 else if (Keyboard[def->right])
876 if (Keyboard[def->button0])
878 if (Keyboard[def->button1])
884 INL_GetJoyDelta(type - ctrl_Joystick,&dx,&dy,false);
885 buttons = INL_GetJoyButtons(type - ctrl_Joystick);
889 INL_GetMouseDelta(&dx,&dy);
890 buttons = INL_GetMouseButtons();
898 mx = (dx < 0)? motion_Left : ((dx > 0)? motion_Right : motion_None);
899 my = (dy < 0)? motion_Up : ((dy > 0)? motion_Down : motion_None);
911 info->button0 = buttons & (1 << 0);
912 info->button1 = buttons & (1 << 1);
913 info->dir = DirTable[((my + 1) * 3) + (mx + 1)];
916 if (DemoMode == demo_Record)
918 // Pack the control info into a byte
919 dbyte = (buttons << 4) | ((mx + 1) << 2) | (my + 1);
923 (DemoBuffer[DemoOffset + 1] == dbyte)
924 && (DemoBuffer[DemoOffset] < 255)
926 (DemoBuffer[DemoOffset])++;
929 if (DemoOffset || DemoBuffer[DemoOffset])
932 if (DemoOffset >= DemoSize)
933 Quit("Demo buffer overflow");
935 DemoBuffer[DemoOffset] = 1;
936 DemoBuffer[DemoOffset + 1] = dbyte;
943 ///////////////////////////////////////////////////////////////////////////
945 // IN_SetControlType() - Sets the control type to be used by the specified
948 ///////////////////////////////////////////////////////////////////////////
950 IN_SetControlType(int player,ControlType type)
952 // DEBUG - check that requested type is present?
953 Controls[player] = type;
957 ///////////////////////////////////////////////////////////////////////////
959 // IN_StartDemoRecord() - Starts the demo recording, using a buffer the
960 // size passed. Returns if the buffer allocation was successful
962 ///////////////////////////////////////////////////////////////////////////
964 IN_StartDemoRecord(word bufsize)
969 MM_GetPtr((memptr *)&DemoBuffer,bufsize);
970 DemoMode = demo_Record;
971 DemoSize = bufsize & ~1;
973 DemoBuffer[0] = DemoBuffer[1] = 0;
978 ///////////////////////////////////////////////////////////////////////////
980 // IN_StartDemoPlayback() - Plays back the demo pointed to of the given size
982 ///////////////////////////////////////////////////////////////////////////
984 IN_StartDemoPlayback(byte /*__segment*/ *buffer,word bufsize)
987 DemoMode = demo_Playback;
988 DemoSize = bufsize & ~1;
992 ///////////////////////////////////////////////////////////////////////////
994 // IN_StopDemo() - Turns off demo mode
996 ///////////////////////////////////////////////////////////////////////////
1000 if ((DemoMode == demo_Record) && DemoOffset)
1003 DemoMode = demo_Off;
1006 ///////////////////////////////////////////////////////////////////////////
1008 // IN_FreeDemoBuffer() - Frees the demo buffer, if it's been allocated
1010 ///////////////////////////////////////////////////////////////////////////
1012 IN_FreeDemoBuffer(void)
1015 MM_FreePtr((memptr *)&DemoBuffer);
1021 ///////////////////////////////////////////////////////////////////////////
1023 // IN_GetScanName() - Returns a string containing the name of the
1024 // specified scan code
1026 ///////////////////////////////////////////////////////////////////////////
1028 IN_GetScanName(ScanCode scan)
1033 for (s = ExtScanCodes,p = ExtScanNames;*s;p++,s++)
1037 return(ScanNames[scan]);
1042 ///////////////////////////////////////////////////////////////////////////
1044 // IN_WaitForKey() - Waits for a scan code, then clears LastScan and
1045 // returns the scan code
1047 ///////////////////////////////////////////////////////////////////////////
1053 while (!(result = LastScan))
1059 ///////////////////////////////////////////////////////////////////////////
1061 // IN_WaitForASCII() - Waits for an ASCII char, then clears LastASCII and
1062 // returns the ASCII value
1064 ///////////////////////////////////////////////////////////////////////////
1066 IN_WaitForASCII(void)
1070 while (!(result = LastASCII))
1076 ///////////////////////////////////////////////////////////////////////////
1078 // IN_AckBack() - Waits for either an ASCII keypress or a button press
1080 ///////////////////////////////////////////////////////////////////////////
1090 if (INL_GetMouseButtons())
1092 while (INL_GetMouseButtons())
1098 for (i = 0;i < MaxJoys;i++)
1102 if (IN_GetJoyButtonsDB(i))
1104 while (IN_GetJoyButtonsDB(i))
1112 IN_ClearKey(LastScan);
1116 ///////////////////////////////////////////////////////////////////////////
1118 // IN_Ack() - Clears user input & then calls IN_AckBack()
1120 ///////////////////////////////////////////////////////////////////////////
1126 IN_ClearKey(LastScan);
1130 while (INL_GetMouseButtons())
1132 for (i = 0;i < MaxJoys;i++)
1134 while (IN_GetJoyButtonsDB(i))
1140 ///////////////////////////////////////////////////////////////////////////
1142 // IN_IsUserInput() - Returns true if a key has been pressed or a button
1145 ///////////////////////////////////////////////////////////////////////////
1147 IN_IsUserInput(void)
1155 if (INL_GetMouseButtons())
1158 for (i = 0;i < MaxJoys;i++)
1160 if (INL_GetJoyButtons(i))
1166 ///////////////////////////////////////////////////////////////////////////
1168 // IN_UserInput() - Waits for the specified delay time (in ticks) or the
1169 // user pressing a key or a mouse button. If the clear flag is set, it
1170 // then either clears the key or waits for the user to let the mouse
1173 ///////////////////////////////////////////////////////////////////////////
1175 IN_UserInput(dword delay,boolean clear)
1177 dword TimeCount = *clockdw;
1180 lasttime = TimeCount;
1183 if (IN_IsUserInput())
1189 } while (TimeCount - lasttime < delay);