]> 4ch.mooo.com Git - 16.git/blob - src/lib/16_in.c
inputest~
[16.git] / src / lib / 16_in.c
1 /* Catacomb Armageddon Source Code
2  * Copyright (C) 1993-2014 Flat Rock Software
3  *
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.
8  *
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.
13  *
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.
17  */
18
19 //
20 //      ID Engine
21 //      ID_IN.c - Input Manager
22 //      v1.0d1
23 //      By Jason Blochowiak
24 //
25
26 //
27 //      This module handles dealing with the various input devices
28 //
29 //      Depends on: Memory Mgr (for demo recording), Sound Mgr (for timing stuff),
30 //                              User Mgr (for command line parms)
31 //
32 //      Globals:
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
36 //
37
38 #include "src/lib/16_in.h"
39
40 //      Internal routines
41
42 ///////////////////////////////////////////////////////////////////////////
43 //
44 //      INL_KeyService() - Handles a keyboard interrupt (key up/down)
45 //
46 ///////////////////////////////////////////////////////////////////////////
47 void interrupt
48 INL_KeyService(void)
49 {
50 static  boolean special;
51                 byte    k,c,
52                                 temp;
53
54         k = inp(0x60);  // Get the scan code
55
56         // Tell the XT keyboard controller to clear the key
57         outp(0x61,(temp = inp(0x61)) | 0x80);
58         outp(0x61,temp);
59
60         if (k == 0xe0)          // Special key prefix
61                 special = true;
62         else if (k == 0xe1)     // Handle Pause key
63                 Paused = true;
64         else
65         {
66                 if (k & 0x80)   // Break code
67                 {
68                         k &= 0x7f;
69
70 // DEBUG - handle special keys: ctl-alt-delete, print scrn
71
72                         Keyboard[k] = false;
73                 }
74                 else                    // Make code
75                 {
76                         LastCode = CurCode;
77                         CurCode = LastScan = k;
78                         Keyboard[k] = true;
79
80                         if (special)
81                                 c = SpecialNames[k];
82                         else
83                         {
84                                 if (k == sc_CapsLock)
85                                 {
86                                         CapsLock ^= true;
87                                         // DEBUG - make caps lock light work
88                                 }
89
90                                 if (Keyboard[sc_LShift] || Keyboard[sc_RShift]) // If shifted
91                                 {
92                                         c = ShiftNames[k];
93                                         if ((c >= 'A') && (c <= 'Z') && CapsLock)
94                                                 c += 'a' - 'A';
95                                 }
96                                 else
97                                 {
98                                         c = ASCIINames[k];
99                                         if ((c >= 'a') && (c <= 'z') && CapsLock)
100                                                 c -= 'a' - 'A';
101                                 }
102                         }
103                         if (c)
104                                 LastASCII = c;
105                 }
106
107                 special = false;
108         }
109
110         if (INL_KeyHook && !special)
111                 INL_KeyHook();
112         outp(0x20,0x20);
113 }
114
115 void
116 Mouse(int x)
117 {
118         union REGS CPURegs;
119         x = CPURegs.x.ax;
120         int86(MouseInt,&CPURegs,&CPURegs);
121 }
122
123 ///////////////////////////////////////////////////////////////////////////
124 //
125 //      INL_GetMouseDelta() - Gets the amount that the mouse has moved from the
126 //              mouse driver
127 //
128 ///////////////////////////////////////////////////////////////////////////
129 static void
130 INL_GetMouseDelta(int *x,int *y)
131 {
132         union REGS CPURegs;
133         Mouse(MDelta);
134         *x = CPURegs.x.cx;
135         *y = CPURegs.x.dx;
136 }
137
138 ///////////////////////////////////////////////////////////////////////////
139 //
140 //      INL_GetMouseButtons() - Gets the status of the mouse buttons from the
141 //              mouse driver
142 //
143 ///////////////////////////////////////////////////////////////////////////
144 static word
145 INL_GetMouseButtons(void)
146 {
147         union REGS CPURegs;
148         word    buttons;
149
150         Mouse(MButtons);
151         buttons = CPURegs.x.bx;
152         return(buttons);
153 }
154
155 ///////////////////////////////////////////////////////////////////////////
156 //
157 //      IN_GetJoyAbs() - Reads the absolute position of the specified joystick
158 //
159 ///////////////////////////////////////////////////////////////////////////
160 void
161 IN_GetJoyAbs(word joy,word *xp,word *yp)
162 {
163         byte    xb,yb,
164                         xs,ys;
165         word    x,y;
166
167         x = y = 0;
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
171         yb = 1 << ys;
172
173 // Read the absolute joystick values
174         __asm
175         {
176                 pushf                           // Save some registers
177                 push    si
178                 push    di
179                 cli                                     // Make sure an interrupt doesn't screw the timings
180
181
182                 mov             dx,0x201
183                 in              al,dx
184                 out             dx,al           // Clear the resistors
185
186                 mov             ah,[xb]         // Get masks into registers
187                 mov             ch,[yb]
188
189                 xor             si,si           // Clear count registers
190                 xor             di,di
191                 xor             bh,bh           // Clear high byte of bx for later
192
193                 push    bp                      // Don't mess up stack frame
194                 mov             bp,MaxJoyValue
195
196 loo:
197                 in              al,dx           // Get bits indicating whether all are finished
198
199                 dec             bp                      // Check bounding register
200                 jz              done            // We have a silly value - abort
201
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
206
207                 mov             bl,al
208                 and             bl,ch           // [yb]
209                 add             di,bx
210
211                 add             cl,bl
212                 jnz             loo             // If both bits were 0, drop out
213
214 done:
215                 pop             bp
216
217                 mov             cl,[xs]         // Get the number of bits to shift
218                 shr             si,cl           //  and shift the count that many times
219
220                 mov             cl,[ys]
221                 shr             di,cl
222
223                 mov             [x],si          // Store the values into the variables
224                 mov             [y],di
225
226                 pop             di
227                 pop             si
228                 popf                            // Restore the registers
229         }
230
231         *xp = x;
232         *yp = y;
233 }
234
235 ///////////////////////////////////////////////////////////////////////////
236 //
237 //      INL_GetJoyDelta() - Returns the relative movement of the specified
238 //              joystick (from +/-127, scaled adaptively)
239 //
240 ///////////////////////////////////////////////////////////////////////////
241 static void
242 INL_GetJoyDelta(word joy,int *dx,int *dy,boolean adaptive)
243 {
244         word            x,y;
245         dword   time;
246         dword TimeCount = *clockdw;
247         JoystickDef     *def;
248 static  dword   lasttime;
249
250         IN_GetJoyAbs(joy,&x,&y);
251         def = JoyDefs + joy;
252
253         if (x < def->threshMinX)
254         {
255                 if (x < def->joyMinX)
256                         x = def->joyMinX;
257
258                 x = -(x - def->threshMinX);
259                 x *= def->joyMultXL;
260                 x >>= JoyScaleShift;
261                 *dx = (x > 127)? -127 : -x;
262         }
263         else if (x > def->threshMaxX)
264         {
265                 if (x > def->joyMaxX)
266                         x = def->joyMaxX;
267
268                 x = x - def->threshMaxX;
269                 x *= def->joyMultXH;
270                 x >>= JoyScaleShift;
271                 *dx = (x > 127)? 127 : x;
272         }
273         else
274                 *dx = 0;
275
276         if (y < def->threshMinY)
277         {
278                 if (y < def->joyMinY)
279                         y = def->joyMinY;
280
281                 y = -(y - def->threshMinY);
282                 y *= def->joyMultYL;
283                 y >>= JoyScaleShift;
284                 *dy = (y > 127)? -127 : -y;
285         }
286         else if (y > def->threshMaxY)
287         {
288                 if (y > def->joyMaxY)
289                         y = def->joyMaxY;
290
291                 y = y - def->threshMaxY;
292                 y *= def->joyMultYH;
293                 y >>= JoyScaleShift;
294                 *dy = (y > 127)? 127 : y;
295         }
296         else
297                 *dy = 0;
298
299         if (adaptive)
300         {
301                 time = (TimeCount - lasttime) / 2;
302                 if (time)
303                 {
304                         if (time > 8)
305                                 time = 8;
306                         *dx *= time;
307                         *dy *= time;
308                 }
309         }
310         lasttime = TimeCount;
311 }
312
313 ///////////////////////////////////////////////////////////////////////////
314 //
315 //      INL_GetJoyButtons() - Returns the button status of the specified
316 //              joystick
317 //
318 ///////////////////////////////////////////////////////////////////////////
319 static word
320 INL_GetJoyButtons(word joy)
321 {
322 register        word    result;
323
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
327         result ^= 3;
328         return(result);
329 }
330
331 ///////////////////////////////////////////////////////////////////////////
332 //
333 //      IN_GetJoyButtonsDB() - Returns the de-bounced button status of the
334 //              specified joystick
335 //
336 ///////////////////////////////////////////////////////////////////////////
337 word
338 IN_GetJoyButtonsDB(word joy)
339 {
340         dword TimeCount = *clockdw;
341         dword   lasttime;
342         word            result1,result2;
343
344         do
345         {
346                 result1 = INL_GetJoyButtons(joy);
347                 lasttime = TimeCount;
348                 while(TimeCount == lasttime)
349                 result2 = INL_GetJoyButtons(joy);
350         } while(result1 != result2);
351         return(result1);
352 }
353
354 ///////////////////////////////////////////////////////////////////////////
355 //
356 //      INL_StartKbd() - Sets up my keyboard stuff for use
357 //
358 ///////////////////////////////////////////////////////////////////////////
359 static void
360 INL_StartKbd(void)
361 {
362         INL_KeyHook = 0;        // Clear key hook
363
364         IN_ClearKeysDown();
365
366         OldKeyVect = _dos_getvect(KeyInt);
367         _dos_setvect(KeyInt,INL_KeyService);
368 }
369
370 ///////////////////////////////////////////////////////////////////////////
371 //
372 //      INL_ShutKbd() - Restores keyboard control to the BIOS
373 //
374 ///////////////////////////////////////////////////////////////////////////
375 static void
376 INL_ShutKbd(void)
377 {
378         pokeb(0x40,0x17,peekb(0x40,0x17) & 0xfaf0);     // Clear ctrl/alt/shift flags
379
380         _dos_setvect(KeyInt,OldKeyVect);
381 }
382
383 ///////////////////////////////////////////////////////////////////////////
384 //
385 //      INL_StartMouse() - Detects and sets up the mouse
386 //
387 ///////////////////////////////////////////////////////////////////////////
388 static boolean
389 INL_StartMouse(void)
390 {
391         union REGS CPURegs;
392         if(_dos_getvect(MouseInt))
393         {
394                 Mouse(MReset);
395                 if(CPURegs.x.ax == 0xffff)
396                         return(true);
397         }
398         return(false);
399 }
400
401 ///////////////////////////////////////////////////////////////////////////
402 //
403 //      INL_ShutMouse() - Cleans up after the mouse
404 //
405 ///////////////////////////////////////////////////////////////////////////
406 static void
407 INL_ShutMouse(void)
408 {
409 }
410
411 //
412 //      INL_SetJoyScale() - Sets up scaling values for the specified joystick
413 //
414 static void
415 INL_SetJoyScale(word joy)
416 {
417         JoystickDef     *def;
418
419         def = &JoyDefs[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);
424 }
425
426 ///////////////////////////////////////////////////////////////////////////
427 //
428 //      IN_SetupJoy() - Sets up thresholding values and calls INL_SetJoyScale()
429 //              to set up scaling values
430 //
431 ///////////////////////////////////////////////////////////////////////////
432 void
433 IN_SetupJoy(word joy,word minx,word maxx,word miny,word maxy)
434 {
435         word            d,r;
436         JoystickDef     *def;
437
438         def = &JoyDefs[joy];
439
440         def->joyMinX = minx;
441         def->joyMaxX = maxx;
442         r = maxx - minx;
443         d = r / 5;
444         def->threshMinX = ((r / 2) - d) + minx;
445         def->threshMaxX = ((r / 2) + d) + minx;
446
447         def->joyMinY = miny;
448         def->joyMaxY = maxy;
449         r = maxy - miny;
450         d = r / 5;
451         def->threshMinY = ((r / 2) - d) + miny;
452         def->threshMaxY = ((r / 2) + d) + miny;
453
454         INL_SetJoyScale(joy);
455 }
456
457 ///////////////////////////////////////////////////////////////////////////
458 //
459 //      INL_StartJoy() - Detects & auto-configures the specified joystick
460 //                                      The auto-config assumes the joystick is centered
461 //
462 ///////////////////////////////////////////////////////////////////////////
463 static boolean
464 INL_StartJoy(word joy)
465 {
466         word            x,y;
467
468         IN_GetJoyAbs(joy,&x,&y);
469
470         if
471         (
472                 ((x == 0) || (x > MaxJoyValue - 10))
473         ||      ((y == 0) || (y > MaxJoyValue - 10))
474         )
475                 return(false);
476         else
477         {
478                 IN_SetupJoy(joy,0,x * 2,0,y * 2);
479                 return(true);
480         }
481 }
482
483 ///////////////////////////////////////////////////////////////////////////
484 //
485 //      INL_ShutJoy() - Cleans up the joystick stuff
486 //
487 ///////////////////////////////////////////////////////////////////////////
488 static void
489 INL_ShutJoy(word joy)
490 {
491         JoysPresent[joy] = false;
492 }
493
494 //      Public routines
495
496 ///////////////////////////////////////////////////////////////////////////
497 //
498 //      IN_Startup() - Starts up the Input Mgr
499 //
500 ///////////////////////////////////////////////////////////////////////////
501 void
502 IN_Startup(void)
503 {
504         boolean checkjoys,checkmouse;
505         word    i;
506
507         if (IN_Started)
508                 return;
509
510         checkjoys = true;
511         checkmouse = true;
512         for (i = 1;i < __argc;i++)
513         {
514                 switch (US_CheckParm(__argv[i],ParmStrings))
515                 {
516                 case 0:
517                         checkjoys = false;
518                         break;
519                 case 1:
520                         checkmouse = false;
521                         break;
522                 }
523         }
524
525         INL_StartKbd();
526         MousePresent = checkmouse? INL_StartMouse() : false;
527
528         for (i = 0;i < MaxJoys;i++)
529                 JoysPresent[i] = checkjoys? INL_StartJoy(i) : false;
530
531         IN_Started = true;
532 }
533
534 ///////////////////////////////////////////////////////////////////////////
535 //
536 //      IN_Default() - Sets up default conditions for the Input Mgr
537 //
538 ///////////////////////////////////////////////////////////////////////////
539 void
540 IN_Default(boolean gotit,ControlType in)
541 {
542         if
543         (
544                 (!gotit)
545         ||      ((in == ctrl_Joystick1) && !JoysPresent[0])
546         ||      ((in == ctrl_Joystick2) && !JoysPresent[1])
547         ||      ((in == ctrl_Mouse) && !MousePresent)
548         )
549                 in = ctrl_Keyboard1;
550         IN_SetControlType(0,in);
551 }
552
553 ///////////////////////////////////////////////////////////////////////////
554 //
555 //      IN_Shutdown() - Shuts down the Input Mgr
556 //
557 ///////////////////////////////////////////////////////////////////////////
558 void
559 IN_Shutdown(void)
560 {
561         word    i;
562
563         if (!IN_Started)
564                 return;
565
566         INL_ShutMouse();
567         for (i = 0;i < MaxJoys;i++)
568                 INL_ShutJoy(i);
569         INL_ShutKbd();
570
571         IN_Started = false;
572 }
573
574 ///////////////////////////////////////////////////////////////////////////
575 //
576 //      IN_SetKeyHook() - Sets the routine that gets called by INL_KeyService()
577 //                      everytime a real make/break code gets hit
578 //
579 ///////////////////////////////////////////////////////////////////////////
580 void
581 IN_SetKeyHook(void (*hook)())
582 {
583         INL_KeyHook = hook;
584 }
585
586 ///////////////////////////////////////////////////////////////////////////
587 //
588 //      IN_ClearKeyDown() - Clears the keyboard array
589 //
590 ///////////////////////////////////////////////////////////////////////////
591 void
592 IN_ClearKeysDown(void)
593 {
594         int     i;
595
596         LastScan = sc_None;
597         LastASCII = key_None;
598         for (i = 0;i < NumCodes;i++)
599                 Keyboard[i] = false;
600 }
601
602 ///////////////////////////////////////////////////////////////////////////
603 //
604 //      INL_AdjustCursor() - Internal routine of common code from IN_ReadCursor()
605 //
606 ///////////////////////////////////////////////////////////////////////////
607 static void
608 INL_AdjustCursor(CursorInfo *info,word buttons,int dx,int dy)
609 {
610         if (buttons & (1 << 0))
611                 info->button0 = true;
612         if (buttons & (1 << 1))
613                 info->button1 = true;
614
615         info->x += dx;
616         info->y += dy;
617 }
618
619 ///////////////////////////////////////////////////////////////////////////
620 //
621 //      IN_ReadCursor() - Reads the input devices and fills in the cursor info
622 //              struct
623 //
624 ///////////////////////////////////////////////////////////////////////////
625 void
626 IN_ReadCursor(CursorInfo *info)
627 {
628         word    i,
629                         buttons;
630         int             dx,dy;
631
632         info->x = info->y = 0;
633         info->button0 = info->button1 = false;
634
635         if (MousePresent)
636         {
637                 buttons = INL_GetMouseButtons();
638                 INL_GetMouseDelta(&dx,&dy);
639                 INL_AdjustCursor(info,buttons,dx,dy);
640         }
641
642         for (i = 0;i < MaxJoys;i++)
643         {
644                 if (!JoysPresent[i])
645                         continue;
646
647                 buttons = INL_GetJoyButtons(i);
648                 INL_GetJoyDelta(i,&dx,&dy,true);
649                 dx /= 64;
650                 dy /= 64;
651                 INL_AdjustCursor(info,buttons,dx,dy);
652         }
653 }
654
655 #ifndef DOMO
656 ///////////////////////////////////////////////////////////////////////////
657 //
658 //      IN_ReadControl() - Reads the device associated with the specified
659 //              player and fills in the control info struct
660 //
661 ///////////////////////////////////////////////////////////////////////////
662 void
663 IN_ReadControl(int player,ControlInfo *info)
664 {
665                         boolean         realdelta=false;                                // MDM (GAMERS EDGE)
666                         byte            dbyte;
667                         word            buttons;
668                         int                     dx,dy;
669                         Motion          mx,my;
670                         ControlType     type;
671 register        KeyboardDef     *def;
672
673         dx = dy = 0;
674         mx = my = motion_None;
675         buttons = 0;
676
677 #if DEMO0
678         if (DemoMode == demo_Playback)
679         {
680                 dbyte = DemoBuffer[DemoOffset + 1];
681                 my = (dbyte & 3) - 1;
682                 mx = ((dbyte >> 2) & 3) - 1;
683                 buttons = (dbyte >> 4) & 3;
684
685                 if (!(--DemoBuffer[DemoOffset]))
686                 {
687                         DemoOffset += 2;
688                         if (DemoOffset >= DemoSize)
689                                 DemoMode = demo_PlayDone;
690                 }
691
692                 realdelta = false;
693         }
694         else if (DemoMode == demo_PlayDone)
695                 Quit("Demo playback exceeded");
696         else
697 #endif
698         {
699                                                                                                                         // MDM begin (GAMERS EDGE) - added this block
700                 ControlTypeUsed = ctrl_None;
701
702                 // Handle mouse input...
703                 //
704                 if ((MousePresent) && (ControlTypeUsed == ctrl_None))
705                 {
706                         INL_GetMouseDelta(&dx,&dy);
707                         buttons = INL_GetMouseButtons();
708                         realdelta = true;
709                         if (dx || dy || buttons)
710                                 ControlTypeUsed = ctrl_Mouse;
711                 }
712
713                 // Handle joystick input...
714                 //
715                 if ((JoystickCalibrated) && (ControlTypeUsed == ctrl_None))
716                 {
717                         type = ctrl_Joystick1;
718                         INL_GetJoyDelta(type - ctrl_Joystick,&dx,&dy,false);
719                         buttons = INL_GetJoyButtons(type - ctrl_Joystick);
720                         realdelta = true;
721                         if (dx || dy || buttons)
722                                 ControlTypeUsed = ctrl_Joystick;
723                 }
724
725                 // Handle keyboard input...
726                 //
727                 if (ControlTypeUsed == ctrl_None)
728                 {
729                         type = ctrl_Keyboard1;
730                         def = &KbdDefs[type - ctrl_Keyboard];
731
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;*/
740
741                         if (Keyboard[def->up])
742                                 my = motion_Up;
743                         else if (Keyboard[def->down])
744                                 my = motion_Down;
745
746                         if (Keyboard[def->left])
747                                 mx = motion_Left;
748                         else if (Keyboard[def->right])
749                                 mx = motion_Right;
750
751                         if (Keyboard[def->button0])
752                                 buttons += 1 << 0;
753                         if (Keyboard[def->button1])
754                                 buttons += 1 << 1;
755                         realdelta = false;
756                         if (mx || my || buttons)
757                                 ControlTypeUsed = ctrl_Keyboard;
758                 }                                                                                                       // MDM end (GAMERS EDGE)
759         }
760
761         if (realdelta)
762         {
763                 mx = (dx < 0)? motion_Left : ((dx > 0)? motion_Right : motion_None);
764                 my = (dy < 0)? motion_Up : ((dy > 0)? motion_Down : motion_None);
765         }
766         else
767         {
768                 dx = mx * 127;
769                 dy = my * 127;
770         }
771
772         info->x = dx;
773         info->xaxis = mx;
774         info->y = dy;
775         info->yaxis = my;
776         info->button0 = buttons & (1 << 0);
777         info->button1 = buttons & (1 << 1);
778         info->dir = DirTable[((my + 1) * 3) + (mx + 1)];
779
780 #if DEMO0
781         if (DemoMode == demo_Record)
782         {
783                 // Pack the control info into a byte
784                 dbyte = (buttons << 4) | ((mx + 1) << 2) | (my + 1);
785
786                 if
787                 (
788                         (DemoBuffer[DemoOffset + 1] == dbyte)
789                 &&      (DemoBuffer[DemoOffset] < 255)
790                 )
791                         (DemoBuffer[DemoOffset])++;
792                 else
793                 {
794                         if (DemoOffset || DemoBuffer[DemoOffset])
795                                 DemoOffset += 2;
796
797                         if (DemoOffset >= DemoSize)
798                                 Quit("Demo buffer overflow");
799
800                         DemoBuffer[DemoOffset] = 1;
801                         DemoBuffer[DemoOffset + 1] = dbyte;
802                 }
803         }
804 #endif
805 }
806
807 #else
808 ///////////////////////////////////////////////////////////////////////////
809 //
810 //      IN_ReadControl() - Reads the device associated with the specified
811 //              player and fills in the control info struct
812 //
813 ///////////////////////////////////////////////////////////////////////////
814 void
815 IN_ReadControl(int player,ControlInfo *info)
816 {
817                         boolean         realdelta;
818                         byte            dbyte;
819                         word            buttons;
820                         int                     dx,dy;
821                         Motion          mx,my;
822                         ControlType     type;
823 register        KeyboardDef     *def;
824
825         dx = dy = 0;
826         mx = my = motion_None;
827         buttons = 0;
828
829 #if DEMO0
830         if (DemoMode == demo_Playback)
831         {
832                 dbyte = DemoBuffer[DemoOffset + 1];
833                 my = (dbyte & 3) - 1;
834                 mx = ((dbyte >> 2) & 3) - 1;
835                 buttons = (dbyte >> 4) & 3;
836
837                 if (!(--DemoBuffer[DemoOffset]))
838                 {
839                         DemoOffset += 2;
840                         if (DemoOffset >= DemoSize)
841                                 DemoMode = demo_PlayDone;
842                 }
843
844                 realdelta = false;
845         }
846         else if (DemoMode == demo_PlayDone)
847                 Quit("Demo playback exceeded");
848         else
849 #endif
850         {
851                 switch (type = Controls[player])
852                 {
853                 case ctrl_Keyboard1:
854                 case ctrl_Keyboard2:
855                         def = &KbdDefs[type - ctrl_Keyboard];
856
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;*/
865
866                         if (Keyboard[def->up])
867                                 my = motion_Up;
868                         else if (Keyboard[def->down])
869                                 my = motion_Down;
870
871                         if (Keyboard[def->left])
872                                 mx = motion_Left;
873                         else if (Keyboard[def->right])
874                                 mx = motion_Right;
875
876                         if (Keyboard[def->button0])
877                                 buttons += 1 << 0;
878                         if (Keyboard[def->button1])
879                                 buttons += 1 << 1;
880                         realdelta = false;
881                         break;
882                 case ctrl_Joystick1:
883                 case ctrl_Joystick2:
884                         INL_GetJoyDelta(type - ctrl_Joystick,&dx,&dy,false);
885                         buttons = INL_GetJoyButtons(type - ctrl_Joystick);
886                         realdelta = true;
887                         break;
888                 case ctrl_Mouse:
889                         INL_GetMouseDelta(&dx,&dy);
890                         buttons = INL_GetMouseButtons();
891                         realdelta = true;
892                         break;
893                 }
894         }
895
896         if (realdelta)
897         {
898                 mx = (dx < 0)? motion_Left : ((dx > 0)? motion_Right : motion_None);
899                 my = (dy < 0)? motion_Up : ((dy > 0)? motion_Down : motion_None);
900         }
901         else
902         {
903                 dx = mx * 127;
904                 dy = my * 127;
905         }
906
907         info->x = dx;
908         info->xaxis = mx;
909         info->y = dy;
910         info->yaxis = my;
911         info->button0 = buttons & (1 << 0);
912         info->button1 = buttons & (1 << 1);
913         info->dir = DirTable[((my + 1) * 3) + (mx + 1)];
914
915 #if DEMO0
916         if (DemoMode == demo_Record)
917         {
918                 // Pack the control info into a byte
919                 dbyte = (buttons << 4) | ((mx + 1) << 2) | (my + 1);
920
921                 if
922                 (
923                         (DemoBuffer[DemoOffset + 1] == dbyte)
924                 &&      (DemoBuffer[DemoOffset] < 255)
925                 )
926                         (DemoBuffer[DemoOffset])++;
927                 else
928                 {
929                         if (DemoOffset || DemoBuffer[DemoOffset])
930                                 DemoOffset += 2;
931
932                         if (DemoOffset >= DemoSize)
933                                 Quit("Demo buffer overflow");
934
935                         DemoBuffer[DemoOffset] = 1;
936                         DemoBuffer[DemoOffset + 1] = dbyte;
937                 }
938         }
939 #endif
940 }
941 #endif
942
943 ///////////////////////////////////////////////////////////////////////////
944 //
945 //      IN_SetControlType() - Sets the control type to be used by the specified
946 //              player
947 //
948 ///////////////////////////////////////////////////////////////////////////
949 void
950 IN_SetControlType(int player,ControlType type)
951 {
952         // DEBUG - check that requested type is present?
953         Controls[player] = type;
954 }
955
956 #if DEMO0
957 ///////////////////////////////////////////////////////////////////////////
958 //
959 //      IN_StartDemoRecord() - Starts the demo recording, using a buffer the
960 //              size passed. Returns if the buffer allocation was successful
961 //
962 ///////////////////////////////////////////////////////////////////////////
963 boolean
964 IN_StartDemoRecord(word bufsize)
965 {
966         if (!bufsize)
967                 return(false);
968
969         MM_GetPtr((memptr *)&DemoBuffer,bufsize);
970         DemoMode = demo_Record;
971         DemoSize = bufsize & ~1;
972         DemoOffset = 0;
973         DemoBuffer[0] = DemoBuffer[1] = 0;
974
975         return(true);
976 }
977
978 ///////////////////////////////////////////////////////////////////////////
979 //
980 //      IN_StartDemoPlayback() - Plays back the demo pointed to of the given size
981 //
982 ///////////////////////////////////////////////////////////////////////////
983 void
984 IN_StartDemoPlayback(byte /*__segment*/ *buffer,word bufsize)
985 {
986         DemoBuffer = buffer;
987         DemoMode = demo_Playback;
988         DemoSize = bufsize & ~1;
989         DemoOffset = 0;
990 }
991
992 ///////////////////////////////////////////////////////////////////////////
993 //
994 //      IN_StopDemo() - Turns off demo mode
995 //
996 ///////////////////////////////////////////////////////////////////////////
997 void
998 IN_StopDemo(void)
999 {
1000         if ((DemoMode == demo_Record) && DemoOffset)
1001                 DemoOffset += 2;
1002
1003         DemoMode = demo_Off;
1004 }
1005
1006 ///////////////////////////////////////////////////////////////////////////
1007 //
1008 //      IN_FreeDemoBuffer() - Frees the demo buffer, if it's been allocated
1009 //
1010 ///////////////////////////////////////////////////////////////////////////
1011 void
1012 IN_FreeDemoBuffer(void)
1013 {
1014         if (DemoBuffer)
1015                 MM_FreePtr((memptr *)&DemoBuffer);
1016 }
1017 #endif
1018
1019
1020 #if 0
1021 ///////////////////////////////////////////////////////////////////////////
1022 //
1023 //      IN_GetScanName() - Returns a string containing the name of the
1024 //              specified scan code
1025 //
1026 ///////////////////////////////////////////////////////////////////////////
1027 byte *
1028 IN_GetScanName(ScanCode scan)
1029 {
1030         byte            **p;
1031         ScanCode        far *s;
1032
1033         for (s = ExtScanCodes,p = ExtScanNames;*s;p++,s++)
1034                 if (*s == scan)
1035                         return(*p);
1036
1037         return(ScanNames[scan]);
1038 }
1039 #endif
1040
1041
1042 ///////////////////////////////////////////////////////////////////////////
1043 //
1044 //      IN_WaitForKey() - Waits for a scan code, then clears LastScan and
1045 //              returns the scan code
1046 //
1047 ///////////////////////////////////////////////////////////////////////////
1048 ScanCode
1049 IN_WaitForKey(void)
1050 {
1051         ScanCode        result;
1052
1053         while (!(result = LastScan))
1054                 ;
1055         LastScan = 0;
1056         return(result);
1057 }
1058
1059 ///////////////////////////////////////////////////////////////////////////
1060 //
1061 //      IN_WaitForASCII() - Waits for an ASCII char, then clears LastASCII and
1062 //              returns the ASCII value
1063 //
1064 ///////////////////////////////////////////////////////////////////////////
1065 char
1066 IN_WaitForASCII(void)
1067 {
1068         char            result;
1069
1070         while (!(result = LastASCII))
1071                 ;
1072         LastASCII = '\0';
1073         return(result);
1074 }
1075
1076 ///////////////////////////////////////////////////////////////////////////
1077 //
1078 //      IN_AckBack() - Waits for either an ASCII keypress or a button press
1079 //
1080 ///////////////////////////////////////////////////////////////////////////
1081 void
1082 IN_AckBack(void)
1083 {
1084         word    i;
1085
1086         while (!LastScan)
1087         {
1088                 if (MousePresent)
1089                 {
1090                         if (INL_GetMouseButtons())
1091                         {
1092                                 while (INL_GetMouseButtons())
1093                                         ;
1094                                 return;
1095                         }
1096                 }
1097
1098                 for (i = 0;i < MaxJoys;i++)
1099                 {
1100                         if (JoysPresent[i])
1101                         {
1102                                 if (IN_GetJoyButtonsDB(i))
1103                                 {
1104                                         while (IN_GetJoyButtonsDB(i))
1105                                                 ;
1106                                         return;
1107                                 }
1108                         }
1109                 }
1110         }
1111
1112         IN_ClearKey(LastScan);
1113         LastScan = sc_None;
1114 }
1115
1116 ///////////////////////////////////////////////////////////////////////////
1117 //
1118 //      IN_Ack() - Clears user input & then calls IN_AckBack()
1119 //
1120 ///////////////////////////////////////////////////////////////////////////
1121 void
1122 IN_Ack(void)
1123 {
1124         word    i;
1125
1126         IN_ClearKey(LastScan);
1127         LastScan = sc_None;
1128
1129         if (MousePresent)
1130                 while (INL_GetMouseButtons())
1131                                         ;
1132         for (i = 0;i < MaxJoys;i++)
1133                 if (JoysPresent[i])
1134                         while (IN_GetJoyButtonsDB(i))
1135                                 ;
1136
1137         IN_AckBack();
1138 }
1139
1140 ///////////////////////////////////////////////////////////////////////////
1141 //
1142 //      IN_IsUserInput() - Returns true if a key has been pressed or a button
1143 //              is down
1144 //
1145 ///////////////////////////////////////////////////////////////////////////
1146 boolean
1147 IN_IsUserInput(void)
1148 {
1149         boolean result;
1150         word    i;
1151
1152         result = LastScan;
1153
1154         if (MousePresent)
1155                 if (INL_GetMouseButtons())
1156                         result = true;
1157
1158         for (i = 0;i < MaxJoys;i++)
1159                 if (JoysPresent[i])
1160                         if (INL_GetJoyButtons(i))
1161                                 result = true;
1162
1163         return(result);
1164 }
1165
1166 ///////////////////////////////////////////////////////////////////////////
1167 //
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
1171 //              button up.
1172 //
1173 ///////////////////////////////////////////////////////////////////////////
1174 boolean
1175 IN_UserInput(dword delay,boolean clear)
1176 {
1177         dword TimeCount = *clockdw;
1178         dword   lasttime;
1179
1180         lasttime = TimeCount;
1181         do
1182         {
1183                 if (IN_IsUserInput())
1184                 {
1185                         if (clear)
1186                                 IN_AckBack();
1187                         return(true);
1188                 }
1189         } while (TimeCount - lasttime < delay);
1190         return(false);
1191 }