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