]> 4ch.mooo.com Git - 16.git/blob - src/lib/16_in.c
wwww merging~
[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 static 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 static 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 ///////////////////////////////////////////////////////////////////////////
656 //
657 //      IN_ReadControl() - Reads the device associated with the specified
658 //              player and fills in the control info struct
659 //
660 ///////////////////////////////////////////////////////////////////////////
661 void
662 IN_ReadControl(int player,ControlInfo *info)
663 {
664                         boolean         realdelta=false;                                // MDM (GAMERS EDGE)
665                         byte            dbyte;
666                         word            buttons;
667                         int                     dx,dy;
668                         Motion          mx,my;
669                         ControlType     type;
670 register        KeyboardDef     *def;
671
672         dx = dy = 0;
673         mx = my = motion_None;
674         buttons = 0;
675
676 #if DEMO0
677         if (DemoMode == demo_Playback)
678         {
679                 dbyte = DemoBuffer[DemoOffset + 1];
680                 my = (dbyte & 3) - 1;
681                 mx = ((dbyte >> 2) & 3) - 1;
682                 buttons = (dbyte >> 4) & 3;
683
684                 if (!(--DemoBuffer[DemoOffset]))
685                 {
686                         DemoOffset += 2;
687                         if (DemoOffset >= DemoSize)
688                                 DemoMode = demo_PlayDone;
689                 }
690
691                 realdelta = false;
692         }
693         else if (DemoMode == demo_PlayDone)
694                 Quit("Demo playback exceeded");
695         else
696 #endif
697         {
698                                                                                                                         // MDM begin (GAMERS EDGE) - added this block
699                 ControlTypeUsed = ctrl_None;
700
701                 // Handle mouse input...
702                 //
703                 if ((MousePresent) && (ControlTypeUsed == ctrl_None))
704                 {
705                         INL_GetMouseDelta(&dx,&dy);
706                         buttons = INL_GetMouseButtons();
707                         realdelta = true;
708                         if (dx || dy || buttons)
709                                 ControlTypeUsed = ctrl_Mouse;
710                 }
711
712                 // Handle joystick input...
713                 //
714                 if ((JoystickCalibrated) && (ControlTypeUsed == ctrl_None))
715                 {
716                         type = ctrl_Joystick1;
717                         INL_GetJoyDelta(type - ctrl_Joystick,&dx,&dy,false);
718                         buttons = INL_GetJoyButtons(type - ctrl_Joystick);
719                         realdelta = true;
720                         if (dx || dy || buttons)
721                                 ControlTypeUsed = ctrl_Joystick;
722                 }
723
724                 // Handle keyboard input...
725                 //
726                 if (ControlTypeUsed == ctrl_None)
727                 {
728                         type = ctrl_Keyboard1;
729                         def = &KbdDefs[type - ctrl_Keyboard];
730
731                         if (Keyboard[def->upleft])
732                                 mx = motion_Left,my = motion_Up;
733                         else if (Keyboard[def->upright])
734                                 mx = motion_Right,my = motion_Up;
735                         else if (Keyboard[def->downleft])
736                                 mx = motion_Left,my = motion_Down;
737                         else if (Keyboard[def->downright])
738                                 mx = motion_Right,my = motion_Down;
739
740                         if (Keyboard[def->up])
741                                 my = motion_Up;
742                         else if (Keyboard[def->down])
743                                 my = motion_Down;
744
745                         if (Keyboard[def->left])
746                                 mx = motion_Left;
747                         else if (Keyboard[def->right])
748                                 mx = motion_Right;
749
750                         if (Keyboard[def->button0])
751                                 buttons += 1 << 0;
752                         if (Keyboard[def->button1])
753                                 buttons += 1 << 1;
754                         realdelta = false;
755                         if (mx || my || buttons)
756                                 ControlTypeUsed = ctrl_Keyboard;
757                 }                                                                                                       // MDM end (GAMERS EDGE)
758         }
759
760         if (realdelta)
761         {
762                 mx = (dx < 0)? motion_Left : ((dx > 0)? motion_Right : motion_None);
763                 my = (dy < 0)? motion_Up : ((dy > 0)? motion_Down : motion_None);
764         }
765         else
766         {
767                 dx = mx * 127;
768                 dy = my * 127;
769         }
770
771         info->x = dx;
772         info->xaxis = mx;
773         info->y = dy;
774         info->yaxis = my;
775         info->button0 = buttons & (1 << 0);
776         info->button1 = buttons & (1 << 1);
777         info->dir = DirTable[((my + 1) * 3) + (mx + 1)];
778
779 #if DEMO0
780         if (DemoMode == demo_Record)
781         {
782                 // Pack the control info into a byte
783                 dbyte = (buttons << 4) | ((mx + 1) << 2) | (my + 1);
784
785                 if
786                 (
787                         (DemoBuffer[DemoOffset + 1] == dbyte)
788                 &&      (DemoBuffer[DemoOffset] < 255)
789                 )
790                         (DemoBuffer[DemoOffset])++;
791                 else
792                 {
793                         if (DemoOffset || DemoBuffer[DemoOffset])
794                                 DemoOffset += 2;
795
796                         if (DemoOffset >= DemoSize)
797                                 Quit("Demo buffer overflow");
798
799                         DemoBuffer[DemoOffset] = 1;
800                         DemoBuffer[DemoOffset + 1] = dbyte;
801                 }
802         }
803 #endif
804 }
805
806 #if 0
807 ///////////////////////////////////////////////////////////////////////////
808 //
809 //      IN_ReadControl() - Reads the device associated with the specified
810 //              player and fills in the control info struct
811 //
812 ///////////////////////////////////////////////////////////////////////////
813 void
814 IN_ReadControl(int player,ControlInfo *info)
815 {
816                         boolean         realdelta;
817                         byte            dbyte;
818                         word            buttons;
819                         int                     dx,dy;
820                         Motion          mx,my;
821                         ControlType     type;
822 register        KeyboardDef     *def;
823
824         dx = dy = 0;
825         mx = my = motion_None;
826         buttons = 0;
827
828 #if DEMO0
829         if (DemoMode == demo_Playback)
830         {
831                 dbyte = DemoBuffer[DemoOffset + 1];
832                 my = (dbyte & 3) - 1;
833                 mx = ((dbyte >> 2) & 3) - 1;
834                 buttons = (dbyte >> 4) & 3;
835
836                 if (!(--DemoBuffer[DemoOffset]))
837                 {
838                         DemoOffset += 2;
839                         if (DemoOffset >= DemoSize)
840                                 DemoMode = demo_PlayDone;
841                 }
842
843                 realdelta = false;
844         }
845         else if (DemoMode == demo_PlayDone)
846                 Quit("Demo playback exceeded");
847         else
848 #endif
849         {
850                 switch (type = Controls[player])
851                 {
852                 case ctrl_Keyboard1:
853                 case ctrl_Keyboard2:
854                         def = &KbdDefs[type - ctrl_Keyboard];
855
856                         if (Keyboard[def->upleft])
857                                 mx = motion_Left,my = motion_Up;
858                         else if (Keyboard[def->upright])
859                                 mx = motion_Right,my = motion_Up;
860                         else if (Keyboard[def->downleft])
861                                 mx = motion_Left,my = motion_Down;
862                         else if (Keyboard[def->downright])
863                                 mx = motion_Right,my = motion_Down;
864
865                         if (Keyboard[def->up])
866                                 my = motion_Up;
867                         else if (Keyboard[def->down])
868                                 my = motion_Down;
869
870                         if (Keyboard[def->left])
871                                 mx = motion_Left;
872                         else if (Keyboard[def->right])
873                                 mx = motion_Right;
874
875                         if (Keyboard[def->button0])
876                                 buttons += 1 << 0;
877                         if (Keyboard[def->button1])
878                                 buttons += 1 << 1;
879                         realdelta = false;
880                         break;
881                 case ctrl_Joystick1:
882                 case ctrl_Joystick2:
883                         INL_GetJoyDelta(type - ctrl_Joystick,&dx,&dy,false);
884                         buttons = INL_GetJoyButtons(type - ctrl_Joystick);
885                         realdelta = true;
886                         break;
887                 case ctrl_Mouse:
888                         INL_GetMouseDelta(&dx,&dy);
889                         buttons = INL_GetMouseButtons();
890                         realdelta = true;
891                         break;
892                 }
893         }
894
895         if (realdelta)
896         {
897                 mx = (dx < 0)? motion_Left : ((dx > 0)? motion_Right : motion_None);
898                 my = (dy < 0)? motion_Up : ((dy > 0)? motion_Down : motion_None);
899         }
900         else
901         {
902                 dx = mx * 127;
903                 dy = my * 127;
904         }
905
906         info->x = dx;
907         info->xaxis = mx;
908         info->y = dy;
909         info->yaxis = my;
910         info->button0 = buttons & (1 << 0);
911         info->button1 = buttons & (1 << 1);
912         info->dir = DirTable[((my + 1) * 3) + (mx + 1)];
913
914 #if DEMO0
915         if (DemoMode == demo_Record)
916         {
917                 // Pack the control info into a byte
918                 dbyte = (buttons << 4) | ((mx + 1) << 2) | (my + 1);
919
920                 if
921                 (
922                         (DemoBuffer[DemoOffset + 1] == dbyte)
923                 &&      (DemoBuffer[DemoOffset] < 255)
924                 )
925                         (DemoBuffer[DemoOffset])++;
926                 else
927                 {
928                         if (DemoOffset || DemoBuffer[DemoOffset])
929                                 DemoOffset += 2;
930
931                         if (DemoOffset >= DemoSize)
932                                 Quit("Demo buffer overflow");
933
934                         DemoBuffer[DemoOffset] = 1;
935                         DemoBuffer[DemoOffset + 1] = dbyte;
936                 }
937         }
938 #endif
939 }
940 #endif
941
942 ///////////////////////////////////////////////////////////////////////////
943 //
944 //      IN_SetControlType() - Sets the control type to be used by the specified
945 //              player
946 //
947 ///////////////////////////////////////////////////////////////////////////
948 void
949 IN_SetControlType(int player,ControlType type)
950 {
951         // DEBUG - check that requested type is present?
952         Controls[player] = type;
953 }
954
955 #if DEMO0
956 ///////////////////////////////////////////////////////////////////////////
957 //
958 //      IN_StartDemoRecord() - Starts the demo recording, using a buffer the
959 //              size passed. Returns if the buffer allocation was successful
960 //
961 ///////////////////////////////////////////////////////////////////////////
962 boolean
963 IN_StartDemoRecord(word bufsize)
964 {
965         if (!bufsize)
966                 return(false);
967
968         MM_GetPtr((memptr *)&DemoBuffer,bufsize);
969         DemoMode = demo_Record;
970         DemoSize = bufsize & ~1;
971         DemoOffset = 0;
972         DemoBuffer[0] = DemoBuffer[1] = 0;
973
974         return(true);
975 }
976
977 ///////////////////////////////////////////////////////////////////////////
978 //
979 //      IN_StartDemoPlayback() - Plays back the demo pointed to of the given size
980 //
981 ///////////////////////////////////////////////////////////////////////////
982 void
983 IN_StartDemoPlayback(byte /*__segment*/ *buffer,word bufsize)
984 {
985         DemoBuffer = buffer;
986         DemoMode = demo_Playback;
987         DemoSize = bufsize & ~1;
988         DemoOffset = 0;
989 }
990
991 ///////////////////////////////////////////////////////////////////////////
992 //
993 //      IN_StopDemo() - Turns off demo mode
994 //
995 ///////////////////////////////////////////////////////////////////////////
996 void
997 IN_StopDemo(void)
998 {
999         if ((DemoMode == demo_Record) && DemoOffset)
1000                 DemoOffset += 2;
1001
1002         DemoMode = demo_Off;
1003 }
1004
1005 ///////////////////////////////////////////////////////////////////////////
1006 //
1007 //      IN_FreeDemoBuffer() - Frees the demo buffer, if it's been allocated
1008 //
1009 ///////////////////////////////////////////////////////////////////////////
1010 void
1011 IN_FreeDemoBuffer(void)
1012 {
1013         if (DemoBuffer)
1014                 MM_FreePtr((memptr *)&DemoBuffer);
1015 }
1016 #endif
1017
1018
1019 #if 0
1020 ///////////////////////////////////////////////////////////////////////////
1021 //
1022 //      IN_GetScanName() - Returns a string containing the name of the
1023 //              specified scan code
1024 //
1025 ///////////////////////////////////////////////////////////////////////////
1026 byte *
1027 IN_GetScanName(ScanCode scan)
1028 {
1029         byte            **p;
1030         ScanCode        far *s;
1031
1032         for (s = ExtScanCodes,p = ExtScanNames;*s;p++,s++)
1033                 if (*s == scan)
1034                         return(*p);
1035
1036         return(ScanNames[scan]);
1037 }
1038 #endif
1039
1040
1041 ///////////////////////////////////////////////////////////////////////////
1042 //
1043 //      IN_WaitForKey() - Waits for a scan code, then clears LastScan and
1044 //              returns the scan code
1045 //
1046 ///////////////////////////////////////////////////////////////////////////
1047 ScanCode
1048 IN_WaitForKey(void)
1049 {
1050         ScanCode        result;
1051
1052         while (!(result = LastScan))
1053                 ;
1054         LastScan = 0;
1055         return(result);
1056 }
1057
1058 ///////////////////////////////////////////////////////////////////////////
1059 //
1060 //      IN_WaitForASCII() - Waits for an ASCII char, then clears LastASCII and
1061 //              returns the ASCII value
1062 //
1063 ///////////////////////////////////////////////////////////////////////////
1064 char
1065 IN_WaitForASCII(void)
1066 {
1067         char            result;
1068
1069         while (!(result = LastASCII))
1070                 ;
1071         LastASCII = '\0';
1072         return(result);
1073 }
1074
1075 ///////////////////////////////////////////////////////////////////////////
1076 //
1077 //      IN_AckBack() - Waits for either an ASCII keypress or a button press
1078 //
1079 ///////////////////////////////////////////////////////////////////////////
1080 void
1081 IN_AckBack(void)
1082 {
1083         word    i;
1084
1085         while (!LastScan)
1086         {
1087                 if (MousePresent)
1088                 {
1089                         if (INL_GetMouseButtons())
1090                         {
1091                                 while (INL_GetMouseButtons())
1092                                         ;
1093                                 return;
1094                         }
1095                 }
1096
1097                 for (i = 0;i < MaxJoys;i++)
1098                 {
1099                         if (JoysPresent[i])
1100                         {
1101                                 if (IN_GetJoyButtonsDB(i))
1102                                 {
1103                                         while (IN_GetJoyButtonsDB(i))
1104                                                 ;
1105                                         return;
1106                                 }
1107                         }
1108                 }
1109         }
1110
1111         IN_ClearKey(LastScan);
1112         LastScan = sc_None;
1113 }
1114
1115 ///////////////////////////////////////////////////////////////////////////
1116 //
1117 //      IN_Ack() - Clears user input & then calls IN_AckBack()
1118 //
1119 ///////////////////////////////////////////////////////////////////////////
1120 void
1121 IN_Ack(void)
1122 {
1123         word    i;
1124
1125         IN_ClearKey(LastScan);
1126         LastScan = sc_None;
1127
1128         if (MousePresent)
1129                 while (INL_GetMouseButtons())
1130                                         ;
1131         for (i = 0;i < MaxJoys;i++)
1132                 if (JoysPresent[i])
1133                         while (IN_GetJoyButtonsDB(i))
1134                                 ;
1135
1136         IN_AckBack();
1137 }
1138
1139 ///////////////////////////////////////////////////////////////////////////
1140 //
1141 //      IN_IsUserInput() - Returns true if a key has been pressed or a button
1142 //              is down
1143 //
1144 ///////////////////////////////////////////////////////////////////////////
1145 boolean
1146 IN_IsUserInput(void)
1147 {
1148         boolean result;
1149         word    i;
1150
1151         result = LastScan;
1152
1153         if (MousePresent)
1154                 if (INL_GetMouseButtons())
1155                         result = true;
1156
1157         for (i = 0;i < MaxJoys;i++)
1158                 if (JoysPresent[i])
1159                         if (INL_GetJoyButtons(i))
1160                                 result = true;
1161
1162         return(result);
1163 }
1164
1165 ///////////////////////////////////////////////////////////////////////////
1166 //
1167 //      IN_UserInput() - Waits for the specified delay time (in ticks) or the
1168 //              user pressing a key or a mouse button. If the clear flag is set, it
1169 //              then either clears the key or waits for the user to let the mouse
1170 //              button up.
1171 //
1172 ///////////////////////////////////////////////////////////////////////////
1173 boolean
1174 IN_UserInput(dword delay,boolean clear)
1175 {
1176         dword TimeCount = *clockdw;
1177         dword   lasttime;
1178
1179         lasttime = TimeCount;
1180         do
1181         {
1182                 if (IN_IsUserInput())
1183                 {
1184                         if (clear)
1185                                 IN_AckBack();
1186                         return(true);
1187                 }
1188         } while (TimeCount - lasttime < delay);
1189         return(false);
1190 }