1 /* Catacomb Apocalypse Source Code
\r
2 * Copyright (C) 1993-2014 Flat Rock Software
\r
4 * This program is free software; you can redistribute it and/or modify
\r
5 * it under the terms of the GNU General Public License as published by
\r
6 * the Free Software Foundation; either version 2 of the License, or
\r
7 * (at your option) any later version.
\r
9 * This program is distributed in the hope that it will be useful,
\r
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
12 * GNU General Public License for more details.
\r
14 * You should have received a copy of the GNU General Public License along
\r
15 * with this program; if not, write to the Free Software Foundation, Inc.,
\r
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\r
21 // ID_IN.c - Input Manager
23 // By Jason Blochowiak
24 // Open Watcom port by sparky4
28 // This module handles dealing with the various input devices
30 // Depends on: Memory Mgr (for demo recording), Sound Mgr (for timing stuff),
31 // User Mgr (for command line parms)
34 // LastScan - The keyboard scan code of the last key pressed
35 // LastASCII - The ASCII value of the last key pressed
36 // DEBUG - there are more globals
39 #include "src/lib/16_in.h"
42 =============================================================================
\r
46 =============================================================================
\r
49 // boolean JoystickCalibrated=false; // MDM (GAMERS EDGE) - added
\r
50 // ControlType ControlTypeUsed; // MDM (GAMERS EDGE) - added
\r
51 boolean Keyboard[NumCodes];
\r
56 //KeyboardDef KbdDefs = {0x1d,0x38,0x47,0x48,0x49,0x4b,0x4d,0x4f,0x50,0x51};
\r
57 JoystickDef JoyDefs[MaxJoys];
\r
58 ControlType Controls[MaxPlayers];
\r
63 ///////////////////////////////////////////////////////////////////////////
65 // INL_KeyService() - Handles a keyboard interrupt (key up/down)
67 ///////////////////////////////////////////////////////////////////////////
71 static boolean special;
75 k = inp(0x60); // Get the scan code
77 // Tell the XT keyboard controller to clear the key
78 outp(0x61,(temp = inp(0x61)) | 0x80);
81 if (k == 0xe0) // Special key prefix
83 else if (k == 0xe1) // Handle Pause key
87 if (k & 0x80) // Break code
91 // DEBUG - handle special keys: ctl-alt-delete, print scrn
98 CurCode = LastScan = k;
105 if (k == sc_CapsLock)
108 // DEBUG - make caps lock light work
111 if (Keyboard[sc_LShift] || Keyboard[sc_RShift]) // If shifted
114 if ((c >= 'A') && (c <= 'Z') && CapsLock)
120 if ((c >= 'a') && (c <= 'z') && CapsLock)
131 if (INL_KeyHook && !special)
134 printf("%c %x %u\n", c, k, Keyboard[k]);
144 int86(MouseInt,&CPURegs,&CPURegs);
147 ///////////////////////////////////////////////////////////////////////////
149 // INL_GetMouseDelta() - Gets the amount that the mouse has moved from the
152 ///////////////////////////////////////////////////////////////////////////
154 INL_GetMouseDelta(int *x,int *y)
162 ///////////////////////////////////////////////////////////////////////////
164 // INL_GetMouseButtons() - Gets the status of the mouse buttons from the
167 ///////////////////////////////////////////////////////////////////////////
169 INL_GetMouseButtons(void)
175 buttons = CPURegs.x.bx;
179 ///////////////////////////////////////////////////////////////////////////
181 // IN_GetJoyAbs() - Reads the absolute position of the specified joystick
183 ///////////////////////////////////////////////////////////////////////////
185 IN_GetJoyAbs(word joy,word *xp,word *yp)
192 xs = joy? 2 : 0; // Find shift value for x axis
193 xb = 1 << xs; // Use shift value to get x bit mask
194 ys = joy? 3 : 1; // Do the same for y axis
197 // Read the absolute joystick values
200 pushf // Save some registers
203 cli // Make sure an interrupt doesn't screw the timings
208 out dx,al // Clear the resistors
210 mov ah,[xb] // Get masks into registers
213 xor si,si // Clear count registers
215 xor bh,bh // Clear high byte of bx for later
217 push bp // Don't mess up stack frame
221 in al,dx // Get bits indicating whether all are finished
223 dec bp // Check bounding register
224 jz done // We have a silly value - abort
226 mov bl,al // Duplicate the bits
227 and bl,ah // Mask off useless bits (in [xb])
228 add si,bx // Possibly increment count register
229 mov cl,bl // Save for testing later
236 jnz loo // If both bits were 0, drop out
241 mov cl,[xs] // Get the number of bits to shift
242 shr si,cl // and shift the count that many times
247 mov [x],si // Store the values into the variables
252 popf // Restore the registers
259 ///////////////////////////////////////////////////////////////////////////
261 // INL_GetJoyDelta() - Returns the relative movement of the specified
262 // joystick (from +/-127, scaled adaptively)
264 ///////////////////////////////////////////////////////////////////////////
266 INL_GetJoyDelta(word joy,int *dx,int *dy,boolean adaptive)
270 dword TimeCount = *clockdw;
272 static dword lasttime;
274 IN_GetJoyAbs(joy,&x,&y);
277 if (x < def->threshMinX)
279 if (x < def->joyMinX)
282 x = -(x - def->threshMinX);
285 *dx = (x > 127)? -127 : -x;
287 else if (x > def->threshMaxX)
289 if (x > def->joyMaxX)
292 x = x - def->threshMaxX;
295 *dx = (x > 127)? 127 : x;
300 if (y < def->threshMinY)
302 if (y < def->joyMinY)
305 y = -(y - def->threshMinY);
308 *dy = (y > 127)? -127 : -y;
310 else if (y > def->threshMaxY)
312 if (y > def->joyMaxY)
315 y = y - def->threshMaxY;
318 *dy = (y > 127)? 127 : y;
325 time = (TimeCount - lasttime) / 2;
334 lasttime = TimeCount;
337 ///////////////////////////////////////////////////////////////////////////
339 // INL_GetJoyButtons() - Returns the button status of the specified
342 ///////////////////////////////////////////////////////////////////////////
344 INL_GetJoyButtons(word joy)
346 register word result;
348 result = inp(0x201); // Get all the joystick buttons
349 result >>= joy? 6 : 4; // Shift into bits 0-1
350 result &= 3; // Mask off the useless bits
355 ///////////////////////////////////////////////////////////////////////////
357 // IN_GetJoyButtonsDB() - Returns the de-bounced button status of the
358 // specified joystick
360 ///////////////////////////////////////////////////////////////////////////
362 IN_GetJoyButtonsDB(word joy)
364 dword TimeCount = *clockdw;
366 word result1,result2;
370 result1 = INL_GetJoyButtons(joy);
371 lasttime = TimeCount;
372 while(TimeCount == lasttime)
373 result2 = INL_GetJoyButtons(joy);
374 } while(result1 != result2);
378 ///////////////////////////////////////////////////////////////////////////
380 // INL_StartKbd() - Sets up my keyboard stuff for use
382 ///////////////////////////////////////////////////////////////////////////
386 INL_KeyHook = 0; // Clear key hook
390 OldKeyVect = _dos_getvect(KeyInt);
391 _dos_setvect(KeyInt,INL_KeyService);
394 ///////////////////////////////////////////////////////////////////////////
396 // INL_ShutKbd() - Restores keyboard control to the BIOS
398 ///////////////////////////////////////////////////////////////////////////
402 pokeb(0x40,0x17,peekb(0x40,0x17) & 0xfaf0); // Clear ctrl/alt/shift flags
404 _dos_setvect(KeyInt,OldKeyVect);
407 ///////////////////////////////////////////////////////////////////////////
409 // INL_StartMouse() - Detects and sets up the mouse
411 ///////////////////////////////////////////////////////////////////////////
416 if(_dos_getvect(MouseInt))
419 if(CPURegs.x.ax == 0xffff)
425 ///////////////////////////////////////////////////////////////////////////
427 // INL_ShutMouse() - Cleans up after the mouse
429 ///////////////////////////////////////////////////////////////////////////
436 // INL_SetJoyScale() - Sets up scaling values for the specified joystick
439 INL_SetJoyScale(word joy)
444 def->joyMultXL = JoyScaleMax / (def->threshMinX - def->joyMinX);
445 def->joyMultXH = JoyScaleMax / (def->joyMaxX - def->threshMaxX);
446 def->joyMultYL = JoyScaleMax / (def->threshMinY - def->joyMinY);
447 def->joyMultYH = JoyScaleMax / (def->joyMaxY - def->threshMaxY);
450 ///////////////////////////////////////////////////////////////////////////
452 // IN_SetupJoy() - Sets up thresholding values and calls INL_SetJoyScale()
453 // to set up scaling values
455 ///////////////////////////////////////////////////////////////////////////
457 IN_SetupJoy(word joy,word minx,word maxx,word miny,word maxy)
468 def->threshMinX = ((r / 2) - d) + minx;
469 def->threshMaxX = ((r / 2) + d) + minx;
475 def->threshMinY = ((r / 2) - d) + miny;
476 def->threshMaxY = ((r / 2) + d) + miny;
478 INL_SetJoyScale(joy);
481 ///////////////////////////////////////////////////////////////////////////
483 // INL_StartJoy() - Detects & auto-configures the specified joystick
484 // The auto-config assumes the joystick is centered
486 ///////////////////////////////////////////////////////////////////////////
488 INL_StartJoy(word joy)
492 IN_GetJoyAbs(joy,&x,&y);
496 ((x == 0) || (x > MaxJoyValue - 10))
497 || ((y == 0) || (y > MaxJoyValue - 10))
502 IN_SetupJoy(joy,0,x * 2,0,y * 2);
507 ///////////////////////////////////////////////////////////////////////////
509 // INL_ShutJoy() - Cleans up the joystick stuff
511 ///////////////////////////////////////////////////////////////////////////
513 INL_ShutJoy(word joy)
515 JoysPresent[joy] = false;
520 ///////////////////////////////////////////////////////////////////////////
522 // IN_Startup() - Starts up the Input Mgr
524 ///////////////////////////////////////////////////////////////////////////
528 boolean checkjoys,checkmouse;
536 for (i = 1;i < __argc;i++)
538 switch (US_CheckParm(__argv[i],ParmStringsIN))
550 MousePresent = checkmouse? INL_StartMouse() : false;
552 for (i = 0;i < MaxJoys;i++)
553 JoysPresent[i] = checkjoys? INL_StartJoy(i) : false;
558 ///////////////////////////////////////////////////////////////////////////
560 // IN_Default() - Sets up default conditions for the Input Mgr
562 ///////////////////////////////////////////////////////////////////////////
564 IN_Default(boolean gotit,ControlType in)
569 || ((in == ctrl_Joystick1) && !JoysPresent[0])
570 || ((in == ctrl_Joystick2) && !JoysPresent[1])
571 || ((in == ctrl_Mouse) && !MousePresent)
574 IN_SetControlType(0,in);
577 ///////////////////////////////////////////////////////////////////////////
579 // IN_Shutdown() - Shuts down the Input Mgr
581 ///////////////////////////////////////////////////////////////////////////
591 for (i = 0;i < MaxJoys;i++)
598 ///////////////////////////////////////////////////////////////////////////
600 // IN_SetKeyHook() - Sets the routine that gets called by INL_KeyService()
601 // everytime a real make/break code gets hit
603 ///////////////////////////////////////////////////////////////////////////
605 IN_SetKeyHook(void (*hook)())
610 ///////////////////////////////////////////////////////////////////////////
612 // IN_ClearKeyDown() - Clears the keyboard array
614 ///////////////////////////////////////////////////////////////////////////
616 IN_ClearKeysDown(void)
621 LastASCII = key_None;
622 memset (Keyboard,0,sizeof(Keyboard));
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);
678 ///////////////////////////////////////////////////////////////////////////
680 // IN_ReadControl() - Reads the device associated with the specified
681 // player and fills in the control info struct
683 ///////////////////////////////////////////////////////////////////////////
685 IN_ReadControl(int player,CursorInfo *info)
693 register KeyboardDef *def;
696 mx = my = motion_None;
700 if (DemoMode == demo_Playback)
702 dbyte = DemoBuffer[DemoOffset + 1];
703 my = (dbyte & 3) - 1;
704 mx = ((dbyte >> 2) & 3) - 1;
705 buttons = (dbyte >> 4) & 3;
707 if (!(--DemoBuffer[DemoOffset]))
710 if (DemoOffset >= DemoSize)
711 DemoMode = demo_PlayDone;
716 else if (DemoMode == demo_PlayDone)
717 Quit("Demo playback exceeded");
721 switch (type = Controls[player])
725 def = &KbdDefs[type - ctrl_Keyboard];
727 /* if (Keyboard[def->upleft])
728 mx = motion_Left,my = motion_Up;
729 else if (Keyboard[def->upright])
730 mx = motion_Right,my = motion_Up;
731 else if (Keyboard[def->downleft])
732 mx = motion_Left,my = motion_Down;
733 else if (Keyboard[def->downright])
734 mx = motion_Right,my = motion_Down;*/
736 if (Keyboard[def->up])
738 else if (Keyboard[def->down])
741 if (Keyboard[def->left])
743 else if (Keyboard[def->right])
746 if (Keyboard[def->button0])
748 if (Keyboard[def->button1])
754 INL_GetJoyDelta(type - ctrl_Joystick,&dx,&dy,false);
755 buttons = INL_GetJoyButtons(type - ctrl_Joystick);
759 INL_GetMouseDelta(&dx,&dy);
760 buttons = INL_GetMouseButtons();
774 mx = (dx < 0)? motion_Left : ((dx > 0)? motion_Right : motion_None);
775 my = (dy < 0)? motion_Up : ((dy > 0)? motion_Down : motion_None);
787 info->button0 = buttons & (1 << 0);
788 info->button1 = buttons & (1 << 1);
789 info->button2 = buttons & (1 << 2);
790 info->button3 = buttons & (1 << 3);
791 info->dir = DirTable[((my + 1) * 3) + (mx + 1)];
794 if (DemoMode == demo_Record)
796 // Pack the control info into a byte
797 dbyte = (buttons << 4) | ((mx + 1) << 2) | (my + 1);
801 (DemoBuffer[DemoOffset + 1] == dbyte)
802 && (DemoBuffer[DemoOffset] < 255)
804 (DemoBuffer[DemoOffset])++;
807 if (DemoOffset || DemoBuffer[DemoOffset])
810 if (DemoOffset >= DemoSize)
811 Quit("Demo buffer overflow");
813 DemoBuffer[DemoOffset] = 1;
814 DemoBuffer[DemoOffset + 1] = dbyte;
820 ///////////////////////////////////////////////////////////////////////////
822 // IN_SetControlType() - Sets the control type to be used by the specified
825 ///////////////////////////////////////////////////////////////////////////
827 IN_SetControlType(int player,ControlType type)
829 // DEBUG - check that requested type is present?
830 Controls[player] = type;
834 ///////////////////////////////////////////////////////////////////////////
836 // IN_StartDemoRecord() - Starts the demo recording, using a buffer the
837 // size passed. Returns if the buffer allocation was successful
839 ///////////////////////////////////////////////////////////////////////////
841 IN_StartDemoRecord(word bufsize)
846 MM_GetPtr((memptr *)&DemoBuffer,bufsize);
847 DemoMode = demo_Record;
848 DemoSize = bufsize & ~1;
850 DemoBuffer[0] = DemoBuffer[1] = 0;
855 ///////////////////////////////////////////////////////////////////////////
857 // IN_StartDemoPlayback() - Plays back the demo pointed to of the given size
859 ///////////////////////////////////////////////////////////////////////////
861 IN_StartDemoPlayback(byte /*__segment*/ *buffer,word bufsize)
864 DemoMode = demo_Playback;
865 DemoSize = bufsize & ~1;
869 ///////////////////////////////////////////////////////////////////////////
871 // IN_StopDemo() - Turns off demo mode
873 ///////////////////////////////////////////////////////////////////////////
877 if ((DemoMode == demo_Record) && DemoOffset)
883 ///////////////////////////////////////////////////////////////////////////
885 // IN_FreeDemoBuffer() - Frees the demo buffer, if it's been allocated
887 ///////////////////////////////////////////////////////////////////////////
889 IN_FreeDemoBuffer(void)
892 MM_FreePtr((memptr *)&DemoBuffer);
897 ///////////////////////////////////////////////////////////////////////////
899 // IN_GetScanName() - Returns a string containing the name of the
900 // specified scan code
902 ///////////////////////////////////////////////////////////////////////////
904 IN_GetScanName(ScanCode scan)
909 for (s = ExtScanCodes,p = ExtScanNames;*s;p++,s++)
913 return(ScanNames[scan]);
916 ///////////////////////////////////////////////////////////////////////////
918 // IN_WaitForKey() - Waits for a scan code, then clears LastScan and
919 // returns the scan code
921 ///////////////////////////////////////////////////////////////////////////
927 while (!(result = LastScan))
933 ///////////////////////////////////////////////////////////////////////////
935 // IN_WaitForASCII() - Waits for an ASCII char, then clears LastASCII and
936 // returns the ASCII value
938 ///////////////////////////////////////////////////////////////////////////
940 IN_WaitForASCII(void)
944 while (!(result = LastASCII))
950 ///////////////////////////////////////////////////////////////////////////
952 // IN_AckBack() - Waits for either an ASCII keypress or a button press
954 ///////////////////////////////////////////////////////////////////////////
964 if (INL_GetMouseButtons())
966 while (INL_GetMouseButtons())
972 for (i = 0;i < MaxJoys;i++)
976 if (IN_GetJoyButtonsDB(i))
978 while (IN_GetJoyButtonsDB(i))
986 IN_ClearKey(LastScan);
990 ///////////////////////////////////////////////////////////////////////////
992 // IN_Ack() - Clears user input & then calls IN_AckBack()
994 ///////////////////////////////////////////////////////////////////////////
1000 IN_ClearKey(LastScan);
1004 while (INL_GetMouseButtons())
1006 for (i = 0;i < MaxJoys;i++)
1008 while (IN_GetJoyButtonsDB(i))
1014 ///////////////////////////////////////////////////////////////////////////
1016 // IN_IsUserInput() - Returns true if a key has been pressed or a button
1019 ///////////////////////////////////////////////////////////////////////////
1021 IN_IsUserInput(void)
1029 if (INL_GetMouseButtons())
1032 for (i = 0;i < MaxJoys;i++)
1034 if (INL_GetJoyButtons(i))
1040 ///////////////////////////////////////////////////////////////////////////
1042 // IN_UserInput() - Waits for the specified delay time (in ticks) or the
1043 // user pressing a key or a mouse button. If the clear flag is set, it
1044 // then either clears the key or waits for the user to let the mouse
1047 ///////////////////////////////////////////////////////////////////////////
1049 IN_UserInput(dword delay,boolean clear)
1051 dword TimeCount = *clockdw;
1054 lasttime = TimeCount;
1057 if (IN_IsUserInput())
1063 } while (TimeCount - lasttime < delay);
1067 boolean IN_qb(byte kee)
1069 if(Keyboard[kee]==true) return 1;