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
54 //ScanCode LastScan;
\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
60 //dword MouseDownCount;
63 ///////////////////////////////////////////////////////////////////////////
65 // INL_KeyService() - Handles a keyboard interrupt (key up/down)
67 ///////////////////////////////////////////////////////////////////////////
69 INL_KeyService(inconfig *in)
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
93 in->Keyboard[k] = false;
97 in->LastCode = in->CurCode;
98 in->CurCode = in->LastScan = k;
99 in->Keyboard[k] = true;
105 if (k == sc_CapsLock)
107 in->CapsLock ^= true;
108 // DEBUG - make caps lock light work
111 if (in->Keyboard[sc_LShift] || in->Keyboard[sc_RShift]) // If shifted
114 if ((c >= 'A') && (c <= 'Z') && in->CapsLock)
120 if ((c >= 'a') && (c <= 'z') && in->CapsLock)
131 if (INL_KeyHook && !special)
134 printf("%c %x %u\n", c, k, in->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, inconfig *in)
270 dword TimeCount = *clockdw;
272 static dword lasttime;
274 IN_GetJoyAbs(joy,&x,&y);
275 def = in->JoyDefs + joy;
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 ///////////////////////////////////////////////////////////////////////////
384 INL_StartKbd(inconfig *in)
386 INL_KeyHook = 0; // Clear key hook
388 IN_ClearKeysDown(in);
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, inconfig *in)
443 def = &(in->JoyDefs[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, inconfig *in)
462 def = &(in->JoyDefs[joy]);
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, in);
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, inconfig *in)
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, in);
507 ///////////////////////////////////////////////////////////////////////////
509 // INL_ShutJoy() - Cleans up the joystick stuff
511 ///////////////////////////////////////////////////////////////////////////
513 INL_ShutJoy(word joy, inconfig *in)
515 in->JoysPresent[joy] = false;
520 ///////////////////////////////////////////////////////////////////////////
522 // IN_Startup() - Starts up the Input Mgr
524 ///////////////////////////////////////////////////////////////////////////
526 IN_Startup(inconfig *in)
528 boolean checkjoys,checkmouse;
536 for (i = 1;i < __argc;i++)
538 switch (US_CheckParm(__argv[i],ParmStringsIN))
550 in->MousePresent = checkmouse? INL_StartMouse() : false;
552 for (i = 0;i < MaxJoys;i++)
553 in->JoysPresent[i] = checkjoys? INL_StartJoy(i, in) : false;
555 in->IN_Started = true;
558 ///////////////////////////////////////////////////////////////////////////
560 // IN_Default() - Sets up default conditions for the Input Mgr
562 ///////////////////////////////////////////////////////////////////////////
564 IN_Default(boolean gotit,player_t *player,ControlType nt, inconfig *in)
569 || ((nt == ctrl_Joystick1) && !in->JoysPresent[0])
570 || ((nt == ctrl_Joystick2) && !in->JoysPresent[1])
571 || ((nt == ctrl_Mouse) && !in->MousePresent)
572 || ((nt == ctrl_Joypad1) && !in->JoyPadPresent[0])
573 || ((nt == ctrl_Joypad2) && !in->JoyPadPresent[1])
576 IN_SetControlType(0,player,nt);
579 ///////////////////////////////////////////////////////////////////////////
581 // IN_Shutdown() - Shuts down the Input Mgr
583 ///////////////////////////////////////////////////////////////////////////
585 IN_Shutdown(inconfig *in)
593 for (i = 0;i < MaxJoys;i++)
597 in->IN_Started = false;
600 ///////////////////////////////////////////////////////////////////////////
602 // IN_SetKeyHook() - Sets the routine that gets called by INL_KeyService()
603 // everytime a real make/break code gets hit
605 ///////////////////////////////////////////////////////////////////////////
607 IN_SetKeyHook(void (*hook)())
612 ///////////////////////////////////////////////////////////////////////////
614 // IN_ClearKeyDown() - Clears the keyboard array
616 ///////////////////////////////////////////////////////////////////////////
618 IN_ClearKeysDown(inconfig *in)
622 in->LastScan = sc_None;
623 in->LastASCII = key_None;
624 memset (in->Keyboard,0,sizeof(in->Keyboard));
627 ///////////////////////////////////////////////////////////////////////////
629 // INL_AdjustCursor() - Internal routine of common code from IN_ReadCursor()
631 ///////////////////////////////////////////////////////////////////////////
633 INL_AdjustCursor(CursorInfo *info,word buttons,int dx,int dy)
635 if (buttons & (1 << 0))
636 info->button0 = true;
637 if (buttons & (1 << 1))
638 info->button1 = true;
644 ///////////////////////////////////////////////////////////////////////////
646 // IN_ReadCursor() - Reads the input devices and fills in the cursor info
649 ///////////////////////////////////////////////////////////////////////////
651 IN_ReadCursor(CursorInfo *info)
657 info->x = info->y = 0;
658 info->button0 = info->button1 = false;
662 buttons = INL_GetMouseButtons();
663 INL_GetMouseDelta(&dx,&dy);
664 INL_AdjustCursor(info,buttons,dx,dy);
667 for (i = 0;i < MaxJoys;i++)
672 buttons = INL_GetJoyButtons(i);
673 INL_GetJoyDelta(i,&dx,&dy,true);
676 INL_AdjustCursor(info,buttons,dx,dy);
680 ///////////////////////////////////////////////////////////////////////////
682 // IN_ReadControl() - Reads the device associated with the specified
683 // player and fills in the control info struct
685 ///////////////////////////////////////////////////////////////////////////
687 IN_ReadControl(int playnum,player_t *player)
695 register KeyboardDef *def;
698 mx = my = motion_None;
702 if (DemoMode == demo_Playback)
704 dbyte = DemoBuffer[DemoOffset + 1];
705 my = (dbyte & 3) - 1;
706 mx = ((dbyte >> 2) & 3) - 1;
707 buttons = (dbyte >> 4) & 3;
709 if (!(--DemoBuffer[DemoOffset]))
712 if (DemoOffset >= DemoSize)
713 DemoMode = demo_PlayDone;
718 else if (DemoMode == demo_PlayDone)
719 Quit("Demo playback exceeded");
723 switch (type = player[playnum]->Controls)
727 def = player[playnum]->KbdDefs[type - ctrl_Keyboard];
729 /* if (Keyboard[def->upleft])
730 mx = motion_Left,my = motion_Up;
731 else if (Keyboard[def->upright])
732 mx = motion_Right,my = motion_Up;
733 else if (Keyboard[def->downleft])
734 mx = motion_Left,my = motion_Down;
735 else if (Keyboard[def->downright])
736 mx = motion_Right,my = motion_Down;*/
738 if (Keyboard[def->up])
740 else if (Keyboard[def->down])
743 if (Keyboard[def->left])
745 else if (Keyboard[def->right])
748 if (Keyboard[def->button0])
750 if (Keyboard[def->button1])
756 INL_GetJoyDelta(type - ctrl_Joystick,&dx,&dy,false);
757 buttons = INL_GetJoyButtons(type - ctrl_Joystick);
761 INL_GetMouseDelta(&dx,&dy);
762 buttons = INL_GetMouseButtons();
776 mx = (dx < 0)? motion_Left : ((dx > 0)? motion_Right : motion_None);
777 my = (dy < 0)? motion_Up : ((dy > 0)? motion_Down : motion_None);
785 player[playnum]->info.x = dx;
786 player[playnum]->info.xaxis = mx;
787 player[playnum]->info.y = dy;
788 player[playnum]->info.yaxis = my;
789 player[playnum]->info.button0 = buttons & (1 << 0);
790 player[playnum]->info.button1 = buttons & (1 << 1);
791 player[playnum]->info.button2 = buttons & (1 << 2);
792 player[playnum]->info.button3 = buttons & (1 << 3);
793 player[playnum]->info.dir = DirTable[((my + 1) * 3) + (mx + 1)];
796 if (DemoMode == demo_Record)
798 // Pack the control info into a byte
799 dbyte = (buttons << 4) | ((mx + 1) << 2) | (my + 1);
803 (DemoBuffer[DemoOffset + 1] == dbyte)
804 && (DemoBuffer[DemoOffset] < 255)
806 (DemoBuffer[DemoOffset])++;
809 if (DemoOffset || DemoBuffer[DemoOffset])
812 if (DemoOffset >= DemoSize)
813 Quit("Demo buffer overflow");
815 DemoBuffer[DemoOffset] = 1;
816 DemoBuffer[DemoOffset + 1] = dbyte;
822 ///////////////////////////////////////////////////////////////////////////
824 // IN_SetControlType() - Sets the control type to be used by the specified
827 ///////////////////////////////////////////////////////////////////////////
829 IN_SetControlType(word playnum,player_t *player,ControlType type)
831 // DEBUG - check that requested type is present?
832 player[playnum]->Controls = type;
836 ///////////////////////////////////////////////////////////////////////////
838 // IN_StartDemoRecord() - Starts the demo recording, using a buffer the
839 // size passed. Returns if the buffer allocation was successful
841 ///////////////////////////////////////////////////////////////////////////
843 IN_StartDemoRecord(word bufsize)
848 MM_GetPtr((memptr *)&DemoBuffer,bufsize);
849 DemoMode = demo_Record;
850 DemoSize = bufsize & ~1;
852 DemoBuffer[0] = DemoBuffer[1] = 0;
857 ///////////////////////////////////////////////////////////////////////////
859 // IN_StartDemoPlayback() - Plays back the demo pointed to of the given size
861 ///////////////////////////////////////////////////////////////////////////
863 IN_StartDemoPlayback(byte /*__segment*/ *buffer,word bufsize)
866 DemoMode = demo_Playback;
867 DemoSize = bufsize & ~1;
871 ///////////////////////////////////////////////////////////////////////////
873 // IN_StopDemo() - Turns off demo mode
875 ///////////////////////////////////////////////////////////////////////////
879 if ((DemoMode == demo_Record) && DemoOffset)
885 ///////////////////////////////////////////////////////////////////////////
887 // IN_FreeDemoBuffer() - Frees the demo buffer, if it's been allocated
889 ///////////////////////////////////////////////////////////////////////////
891 IN_FreeDemoBuffer(void)
894 MM_FreePtr((memptr *)&DemoBuffer);
899 ///////////////////////////////////////////////////////////////////////////
901 // IN_GetScanName() - Returns a string containing the name of the
902 // specified scan code
904 ///////////////////////////////////////////////////////////////////////////
906 IN_GetScanName(ScanCode scan)
911 for (s = ExtScanCodes,p = ExtScanNames;*s;p++,s++)
915 return(ScanNames[scan]);
918 ///////////////////////////////////////////////////////////////////////////
920 // IN_WaitForKey() - Waits for a scan code, then clears LastScan and
921 // returns the scan code
923 ///////////////////////////////////////////////////////////////////////////
929 while (!(result = LastScan))
935 ///////////////////////////////////////////////////////////////////////////
937 // IN_WaitForASCII() - Waits for an ASCII char, then clears LastASCII and
938 // returns the ASCII value
940 ///////////////////////////////////////////////////////////////////////////
942 IN_WaitForASCII(void)
946 while (!(result = LastASCII))
952 ///////////////////////////////////////////////////////////////////////////
954 // IN_AckBack() - Waits for either an ASCII keypress or a button press
956 ///////////////////////////////////////////////////////////////////////////
966 if (INL_GetMouseButtons())
968 while (INL_GetMouseButtons())
974 for (i = 0;i < MaxJoys;i++)
978 if (IN_GetJoyButtonsDB(i))
980 while (IN_GetJoyButtonsDB(i))
988 IN_ClearKey(LastScan);
992 ///////////////////////////////////////////////////////////////////////////
994 // IN_Ack() - Clears user input & then calls IN_AckBack()
996 ///////////////////////////////////////////////////////////////////////////
1002 IN_ClearKey(LastScan);
1006 while (INL_GetMouseButtons())
1008 for (i = 0;i < MaxJoys;i++)
1010 while (IN_GetJoyButtonsDB(i))
1016 ///////////////////////////////////////////////////////////////////////////
1018 // IN_IsUserInput() - Returns true if a key has been pressed or a button
1021 ///////////////////////////////////////////////////////////////////////////
1023 IN_IsUserInput(void)
1031 if (INL_GetMouseButtons())
1034 for (i = 0;i < MaxJoys;i++)
1036 if (INL_GetJoyButtons(i))
1042 ///////////////////////////////////////////////////////////////////////////
1044 // IN_UserInput() - Waits for the specified delay time (in ticks) or the
1045 // user pressing a key or a mouse button. If the clear flag is set, it
1046 // then either clears the key or waits for the user to let the mouse
1049 ///////////////////////////////////////////////////////////////////////////
1051 IN_UserInput(dword delay,boolean clear)
1053 dword TimeCount = *clockdw;
1056 lasttime = TimeCount;
1059 if (IN_IsUserInput())
1065 } while (TimeCount - lasttime < delay);
1069 boolean IN_qb(byte kee)
1071 if(Keyboard[kee]==true) return 1;