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