OSDN Git Service

got 8086 port of wolf3d to work and sod to work
[proj16/16.git] / 16 / sod8086 / id_in.c
1 //\r
2 //      ID Engine\r
3 //      ID_IN.c - Input Manager\r
4 //      v1.0d1\r
5 //      By Jason Blochowiak\r
6 //\r
7 \r
8 //\r
9 //      This module handles dealing with the various input devices\r
10 //\r
11 //      Depends on: Memory Mgr (for demo recording), Sound Mgr (for timing stuff),\r
12 //                              User Mgr (for command line parms)\r
13 //\r
14 //      Globals:\r
15 //              LastScan - The keyboard scan code of the last key pressed\r
16 //              LastASCII - The ASCII value of the last key pressed\r
17 //      DEBUG - there are more globals\r
18 //\r
19 \r
20 #include "ID_HEADS.H"\r
21 #pragma hdrstop\r
22 \r
23 #define KeyInt          9       // The keyboard ISR number\r
24 \r
25 //\r
26 // mouse constants\r
27 //\r
28 #define MReset          0\r
29 #define MButtons        3\r
30 #define MDelta          11\r
31 \r
32 #define MouseInt        0x33\r
33 #define Mouse(x)        _AX = x,geninterrupt(MouseInt)\r
34 \r
35 //\r
36 // joystick constants\r
37 //\r
38 #define JoyScaleMax             32768\r
39 #define JoyScaleShift   8\r
40 #define MaxJoyValue             5000\r
41 \r
42 /*\r
43 =============================================================================\r
44 \r
45                                         GLOBAL VARIABLES\r
46 \r
47 =============================================================================\r
48 */\r
49 \r
50 //\r
51 // configuration variables\r
52 //\r
53 boolean                 MousePresent;\r
54 boolean                 JoysPresent[MaxJoys];\r
55 boolean                 JoyPadPresent;\r
56 \r
57 \r
58 //      Global variables\r
59                 boolean         Keyboard[NumCodes];\r
60                 boolean         Paused;\r
61                 char            LastASCII;\r
62                 ScanCode        LastScan;\r
63 \r
64                 KeyboardDef     KbdDefs = {0x1d,0x38,0x47,0x48,0x49,0x4b,0x4d,0x4f,0x50,0x51};\r
65                 JoystickDef     JoyDefs[MaxJoys];\r
66                 ControlType     Controls[MaxPlayers];\r
67 \r
68                 longword        MouseDownCount;\r
69 \r
70                 Demo            DemoMode = demo_Off;\r
71                 byte _seg       *DemoBuffer;\r
72                 word            DemoOffset,DemoSize;\r
73 \r
74 /*\r
75 =============================================================================\r
76 \r
77                                         LOCAL VARIABLES\r
78 \r
79 =============================================================================\r
80 */\r
81 static  byte        far ASCIINames[] =          // Unshifted ASCII for scan codes\r
82                                         {\r
83 //       0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F\r
84         0  ,27 ,'1','2','3','4','5','6','7','8','9','0','-','=',8  ,9  ,        // 0\r
85         'q','w','e','r','t','y','u','i','o','p','[',']',13 ,0  ,'a','s',        // 1\r
86         'd','f','g','h','j','k','l',';',39 ,'`',0  ,92 ,'z','x','c','v',        // 2\r
87         'b','n','m',',','.','/',0  ,'*',0  ,' ',0  ,0  ,0  ,0  ,0  ,0  ,        // 3\r
88         0  ,0  ,0  ,0  ,0  ,0  ,0  ,'7','8','9','-','4','5','6','+','1',        // 4\r
89         '2','3','0',127,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,        // 5\r
90         0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,        // 6\r
91         0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0           // 7\r
92                                         },\r
93                                         far ShiftNames[] =              // Shifted ASCII for scan codes\r
94                                         {\r
95 //       0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F\r
96         0  ,27 ,'!','@','#','$','%','^','&','*','(',')','_','+',8  ,9  ,        // 0\r
97         'Q','W','E','R','T','Y','U','I','O','P','{','}',13 ,0  ,'A','S',        // 1\r
98         'D','F','G','H','J','K','L',':',34 ,'~',0  ,'|','Z','X','C','V',        // 2\r
99         'B','N','M','<','>','?',0  ,'*',0  ,' ',0  ,0  ,0  ,0  ,0  ,0  ,        // 3\r
100         0  ,0  ,0  ,0  ,0  ,0  ,0  ,'7','8','9','-','4','5','6','+','1',        // 4\r
101         '2','3','0',127,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,        // 5\r
102         0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,        // 6\r
103         0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0           // 7\r
104                                         },\r
105                                         far SpecialNames[] =    // ASCII for 0xe0 prefixed codes\r
106                                         {\r
107 //       0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F\r
108         0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,        // 0\r
109         0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,13 ,0  ,0  ,0  ,        // 1\r
110         0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,        // 2\r
111         0  ,0  ,0  ,0  ,0  ,'/',0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,        // 3\r
112         0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,        // 4\r
113         0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,        // 5\r
114         0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,        // 6\r
115         0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0           // 7\r
116                                         };\r
117 \r
118 \r
119 static  boolean         IN_Started;\r
120 static  boolean         CapsLock;\r
121 static  ScanCode        CurCode,LastCode;\r
122 \r
123 static  Direction       DirTable[] =            // Quick lookup for total direction\r
124                                         {\r
125                                                 dir_NorthWest,  dir_North,      dir_NorthEast,\r
126                                                 dir_West,               dir_None,       dir_East,\r
127                                                 dir_SouthWest,  dir_South,      dir_SouthEast\r
128                                         };\r
129 \r
130 static  void                    (*INL_KeyHook)(void);\r
131 static  void interrupt  (*OldKeyVect)(void);\r
132 \r
133 static  char                    *ParmStrings[] = {"nojoys","nomouse",nil};\r
134 \r
135 //      Internal routines\r
136 \r
137 ///////////////////////////////////////////////////////////////////////////\r
138 //\r
139 //      INL_KeyService() - Handles a keyboard interrupt (key up/down)\r
140 //\r
141 ///////////////////////////////////////////////////////////////////////////\r
142 static void interrupt\r
143 INL_KeyService(void)\r
144 {\r
145 static  boolean special;\r
146                 byte    k,c,\r
147                                 temp;\r
148                 int             i;\r
149 \r
150         k = inportb(0x60);      // Get the scan code\r
151 \r
152         // Tell the XT keyboard controller to clear the key\r
153         outportb(0x61,(temp = inportb(0x61)) | 0x80);\r
154         outportb(0x61,temp);\r
155 \r
156         if (k == 0xe0)          // Special key prefix\r
157                 special = true;\r
158         else if (k == 0xe1)     // Handle Pause key\r
159                 Paused = true;\r
160         else\r
161         {\r
162                 if (k & 0x80)   // Break code\r
163                 {\r
164                         k &= 0x7f;\r
165 \r
166 // DEBUG - handle special keys: ctl-alt-delete, print scrn\r
167 \r
168                         Keyboard[k] = false;\r
169                 }\r
170                 else                    // Make code\r
171                 {\r
172                         LastCode = CurCode;\r
173                         CurCode = LastScan = k;\r
174                         Keyboard[k] = true;\r
175 \r
176                         if (special)\r
177                                 c = SpecialNames[k];\r
178                         else\r
179                         {\r
180                                 if (k == sc_CapsLock)\r
181                                 {\r
182                                         CapsLock ^= true;\r
183                                         // DEBUG - make caps lock light work\r
184                                 }\r
185 \r
186                                 if (Keyboard[sc_LShift] || Keyboard[sc_RShift]) // If shifted\r
187                                 {\r
188                                         c = ShiftNames[k];\r
189                                         if ((c >= 'A') && (c <= 'Z') && CapsLock)\r
190                                                 c += 'a' - 'A';\r
191                                 }\r
192                                 else\r
193                                 {\r
194                                         c = ASCIINames[k];\r
195                                         if ((c >= 'a') && (c <= 'z') && CapsLock)\r
196                                                 c -= 'a' - 'A';\r
197                                 }\r
198                         }\r
199                         if (c)\r
200                                 LastASCII = c;\r
201                 }\r
202 \r
203                 special = false;\r
204         }\r
205 \r
206         if (INL_KeyHook && !special)\r
207                 INL_KeyHook();\r
208         outportb(0x20,0x20);\r
209 }\r
210 \r
211 ///////////////////////////////////////////////////////////////////////////\r
212 //\r
213 //      INL_GetMouseDelta() - Gets the amount that the mouse has moved from the\r
214 //              mouse driver\r
215 //\r
216 ///////////////////////////////////////////////////////////////////////////\r
217 static void\r
218 INL_GetMouseDelta(int *x,int *y)\r
219 {\r
220         Mouse(MDelta);\r
221         *x = _CX;\r
222         *y = _DX;\r
223 }\r
224 \r
225 ///////////////////////////////////////////////////////////////////////////\r
226 //\r
227 //      INL_GetMouseButtons() - Gets the status of the mouse buttons from the\r
228 //              mouse driver\r
229 //\r
230 ///////////////////////////////////////////////////////////////////////////\r
231 static word\r
232 INL_GetMouseButtons(void)\r
233 {\r
234         word    buttons;\r
235 \r
236         Mouse(MButtons);\r
237         buttons = _BX;\r
238         return(buttons);\r
239 }\r
240 \r
241 ///////////////////////////////////////////////////////////////////////////\r
242 //\r
243 //      IN_GetJoyAbs() - Reads the absolute position of the specified joystick\r
244 //\r
245 ///////////////////////////////////////////////////////////////////////////\r
246 void\r
247 IN_GetJoyAbs(word joy,word *xp,word *yp)\r
248 {\r
249         byte    xb,yb,\r
250                         xs,ys;\r
251         word    x,y;\r
252 \r
253         x = y = 0;\r
254         xs = joy? 2 : 0;                // Find shift value for x axis\r
255         xb = 1 << xs;                   // Use shift value to get x bit mask\r
256         ys = joy? 3 : 1;                // Do the same for y axis\r
257         yb = 1 << ys;\r
258 \r
259 // Read the absolute joystick values\r
260 asm             pushf                           // Save some registers\r
261 asm             push    si\r
262 asm             push    di\r
263 asm             cli                                     // Make sure an interrupt doesn't screw the timings\r
264 \r
265 \r
266 asm             mov             dx,0x201\r
267 asm             in              al,dx\r
268 asm             out             dx,al           // Clear the resistors\r
269 \r
270 asm             mov             ah,[xb]         // Get masks into registers\r
271 asm             mov             ch,[yb]\r
272 \r
273 asm             xor             si,si           // Clear count registers\r
274 asm             xor             di,di\r
275 asm             xor             bh,bh           // Clear high byte of bx for later\r
276 \r
277 asm             push    bp                      // Don't mess up stack frame\r
278 asm             mov             bp,MaxJoyValue\r
279 \r
280 loop:\r
281 asm             in              al,dx           // Get bits indicating whether all are finished\r
282 \r
283 asm             dec             bp                      // Check bounding register\r
284 asm             jz              done            // We have a silly value - abort\r
285 \r
286 asm             mov             bl,al           // Duplicate the bits\r
287 asm             and             bl,ah           // Mask off useless bits (in [xb])\r
288 asm             add             si,bx           // Possibly increment count register\r
289 asm             mov             cl,bl           // Save for testing later\r
290 \r
291 asm             mov             bl,al\r
292 asm             and             bl,ch           // [yb]\r
293 asm             add             di,bx\r
294 \r
295 asm             add             cl,bl\r
296 asm             jnz             loop            // If both bits were 0, drop out\r
297 \r
298 done:\r
299 asm     pop             bp\r
300 \r
301 asm             mov             cl,[xs]         // Get the number of bits to shift\r
302 asm             shr             si,cl           //  and shift the count that many times\r
303 \r
304 asm             mov             cl,[ys]\r
305 asm             shr             di,cl\r
306 \r
307 asm             mov             [x],si          // Store the values into the variables\r
308 asm             mov             [y],di\r
309 \r
310 asm             pop             di\r
311 asm             pop             si\r
312 asm             popf                            // Restore the registers\r
313 \r
314         *xp = x;\r
315         *yp = y;\r
316 }\r
317 \r
318 ///////////////////////////////////////////////////////////////////////////\r
319 //\r
320 //      INL_GetJoyDelta() - Returns the relative movement of the specified\r
321 //              joystick (from +/-127)\r
322 //\r
323 ///////////////////////////////////////////////////////////////////////////\r
324 void INL_GetJoyDelta(word joy,int *dx,int *dy)\r
325 {\r
326         word            x,y;\r
327         longword        time;\r
328         JoystickDef     *def;\r
329 static  longword        lasttime;\r
330 \r
331         IN_GetJoyAbs(joy,&x,&y);\r
332         def = JoyDefs + joy;\r
333 \r
334         if (x < def->threshMinX)\r
335         {\r
336                 if (x < def->joyMinX)\r
337                         x = def->joyMinX;\r
338 \r
339                 x = -(x - def->threshMinX);\r
340                 x *= def->joyMultXL;\r
341                 x >>= JoyScaleShift;\r
342                 *dx = (x > 127)? -127 : -x;\r
343         }\r
344         else if (x > def->threshMaxX)\r
345         {\r
346                 if (x > def->joyMaxX)\r
347                         x = def->joyMaxX;\r
348 \r
349                 x = x - def->threshMaxX;\r
350                 x *= def->joyMultXH;\r
351                 x >>= JoyScaleShift;\r
352                 *dx = (x > 127)? 127 : x;\r
353         }\r
354         else\r
355                 *dx = 0;\r
356 \r
357         if (y < def->threshMinY)\r
358         {\r
359                 if (y < def->joyMinY)\r
360                         y = def->joyMinY;\r
361 \r
362                 y = -(y - def->threshMinY);\r
363                 y *= def->joyMultYL;\r
364                 y >>= JoyScaleShift;\r
365                 *dy = (y > 127)? -127 : -y;\r
366         }\r
367         else if (y > def->threshMaxY)\r
368         {\r
369                 if (y > def->joyMaxY)\r
370                         y = def->joyMaxY;\r
371 \r
372                 y = y - def->threshMaxY;\r
373                 y *= def->joyMultYH;\r
374                 y >>= JoyScaleShift;\r
375                 *dy = (y > 127)? 127 : y;\r
376         }\r
377         else\r
378                 *dy = 0;\r
379 \r
380         lasttime = TimeCount;\r
381 }\r
382 \r
383 ///////////////////////////////////////////////////////////////////////////\r
384 //\r
385 //      INL_GetJoyButtons() - Returns the button status of the specified\r
386 //              joystick\r
387 //\r
388 ///////////////////////////////////////////////////////////////////////////\r
389 static word\r
390 INL_GetJoyButtons(word joy)\r
391 {\r
392 register        word    result;\r
393 \r
394         result = inportb(0x201);        // Get all the joystick buttons\r
395         result >>= joy? 6 : 4;  // Shift into bits 0-1\r
396         result &= 3;                            // Mask off the useless bits\r
397         result ^= 3;\r
398         return(result);\r
399 }\r
400 \r
401 ///////////////////////////////////////////////////////////////////////////\r
402 //\r
403 //      IN_GetJoyButtonsDB() - Returns the de-bounced button status of the\r
404 //              specified joystick\r
405 //\r
406 ///////////////////////////////////////////////////////////////////////////\r
407 word\r
408 IN_GetJoyButtonsDB(word joy)\r
409 {\r
410         longword        lasttime;\r
411         word            result1,result2;\r
412 \r
413         do\r
414         {\r
415                 result1 = INL_GetJoyButtons(joy);\r
416                 lasttime = TimeCount;\r
417                 while (TimeCount == lasttime)\r
418                         ;\r
419                 result2 = INL_GetJoyButtons(joy);\r
420         } while (result1 != result2);\r
421         return(result1);\r
422 }\r
423 \r
424 ///////////////////////////////////////////////////////////////////////////\r
425 //\r
426 //      INL_StartKbd() - Sets up my keyboard stuff for use\r
427 //\r
428 ///////////////////////////////////////////////////////////////////////////\r
429 static void\r
430 INL_StartKbd(void)\r
431 {\r
432         INL_KeyHook = NULL;                     // no key hook routine\r
433 \r
434         IN_ClearKeysDown();\r
435 \r
436         OldKeyVect = getvect(KeyInt);\r
437         setvect(KeyInt,INL_KeyService);\r
438 }\r
439 \r
440 ///////////////////////////////////////////////////////////////////////////\r
441 //\r
442 //      INL_ShutKbd() - Restores keyboard control to the BIOS\r
443 //\r
444 ///////////////////////////////////////////////////////////////////////////\r
445 static void\r
446 INL_ShutKbd(void)\r
447 {\r
448         poke(0x40,0x17,peek(0x40,0x17) & 0xfaf0);       // Clear ctrl/alt/shift flags\r
449 \r
450         setvect(KeyInt,OldKeyVect);\r
451 }\r
452 \r
453 ///////////////////////////////////////////////////////////////////////////\r
454 //\r
455 //      INL_StartMouse() - Detects and sets up the mouse\r
456 //\r
457 ///////////////////////////////////////////////////////////////////////////\r
458 static boolean\r
459 INL_StartMouse(void)\r
460 {\r
461 #if 0\r
462         if (getvect(MouseInt))\r
463         {\r
464                 Mouse(MReset);\r
465                 if (_AX == 0xffff)\r
466                         return(true);\r
467         }\r
468         return(false);\r
469 #endif\r
470  union REGS regs;\r
471  unsigned char far *vector;\r
472 \r
473 \r
474  if ((vector=MK_FP(peek(0,0x33*4+2),peek(0,0x33*4)))==NULL)\r
475    return false;\r
476 \r
477  if (*vector == 207)\r
478    return false;\r
479 \r
480  Mouse(MReset);\r
481  return true;\r
482 }\r
483 \r
484 ///////////////////////////////////////////////////////////////////////////\r
485 //\r
486 //      INL_ShutMouse() - Cleans up after the mouse\r
487 //\r
488 ///////////////////////////////////////////////////////////////////////////\r
489 static void\r
490 INL_ShutMouse(void)\r
491 {\r
492 }\r
493 \r
494 //\r
495 //      INL_SetJoyScale() - Sets up scaling values for the specified joystick\r
496 //\r
497 static void\r
498 INL_SetJoyScale(word joy)\r
499 {\r
500         JoystickDef     *def;\r
501 \r
502         def = &JoyDefs[joy];\r
503         def->joyMultXL = JoyScaleMax / (def->threshMinX - def->joyMinX);\r
504         def->joyMultXH = JoyScaleMax / (def->joyMaxX - def->threshMaxX);\r
505         def->joyMultYL = JoyScaleMax / (def->threshMinY - def->joyMinY);\r
506         def->joyMultYH = JoyScaleMax / (def->joyMaxY - def->threshMaxY);\r
507 }\r
508 \r
509 ///////////////////////////////////////////////////////////////////////////\r
510 //\r
511 //      IN_SetupJoy() - Sets up thresholding values and calls INL_SetJoyScale()\r
512 //              to set up scaling values\r
513 //\r
514 ///////////////////////////////////////////////////////////////////////////\r
515 void\r
516 IN_SetupJoy(word joy,word minx,word maxx,word miny,word maxy)\r
517 {\r
518         word            d,r;\r
519         JoystickDef     *def;\r
520 \r
521         def = &JoyDefs[joy];\r
522 \r
523         def->joyMinX = minx;\r
524         def->joyMaxX = maxx;\r
525         r = maxx - minx;\r
526         d = r / 3;\r
527         def->threshMinX = ((r / 2) - d) + minx;\r
528         def->threshMaxX = ((r / 2) + d) + minx;\r
529 \r
530         def->joyMinY = miny;\r
531         def->joyMaxY = maxy;\r
532         r = maxy - miny;\r
533         d = r / 3;\r
534         def->threshMinY = ((r / 2) - d) + miny;\r
535         def->threshMaxY = ((r / 2) + d) + miny;\r
536 \r
537         INL_SetJoyScale(joy);\r
538 }\r
539 \r
540 ///////////////////////////////////////////////////////////////////////////\r
541 //\r
542 //      INL_StartJoy() - Detects & auto-configures the specified joystick\r
543 //                                      The auto-config assumes the joystick is centered\r
544 //\r
545 ///////////////////////////////////////////////////////////////////////////\r
546 static boolean\r
547 INL_StartJoy(word joy)\r
548 {\r
549         word            x,y;\r
550 \r
551         IN_GetJoyAbs(joy,&x,&y);\r
552 \r
553         if\r
554         (\r
555                 ((x == 0) || (x > MaxJoyValue - 10))\r
556         ||      ((y == 0) || (y > MaxJoyValue - 10))\r
557         )\r
558                 return(false);\r
559         else\r
560         {\r
561                 IN_SetupJoy(joy,0,x * 2,0,y * 2);\r
562                 return(true);\r
563         }\r
564 }\r
565 \r
566 ///////////////////////////////////////////////////////////////////////////\r
567 //\r
568 //      INL_ShutJoy() - Cleans up the joystick stuff\r
569 //\r
570 ///////////////////////////////////////////////////////////////////////////\r
571 static void\r
572 INL_ShutJoy(word joy)\r
573 {\r
574         JoysPresent[joy] = false;\r
575 }\r
576 \r
577 \r
578 ///////////////////////////////////////////////////////////////////////////\r
579 //\r
580 //      IN_Startup() - Starts up the Input Mgr\r
581 //\r
582 ///////////////////////////////////////////////////////////////////////////\r
583 void\r
584 IN_Startup(void)\r
585 {\r
586         boolean checkjoys,checkmouse;\r
587         word    i;\r
588 \r
589         if (IN_Started)\r
590                 return;\r
591 \r
592         checkjoys = true;\r
593         checkmouse = true;\r
594         for (i = 1;i < _argc;i++)\r
595         {\r
596                 switch (US_CheckParm(_argv[i],ParmStrings))\r
597                 {\r
598                 case 0:\r
599                         checkjoys = false;\r
600                         break;\r
601                 case 1:\r
602                         checkmouse = false;\r
603                         break;\r
604                 }\r
605         }\r
606 \r
607         INL_StartKbd();\r
608         MousePresent = checkmouse? INL_StartMouse() : false;\r
609 \r
610         for (i = 0;i < MaxJoys;i++)\r
611                 JoysPresent[i] = checkjoys? INL_StartJoy(i) : false;\r
612 \r
613         IN_Started = true;\r
614 }\r
615 \r
616 ///////////////////////////////////////////////////////////////////////////\r
617 //\r
618 //      IN_Default() - Sets up default conditions for the Input Mgr\r
619 //\r
620 ///////////////////////////////////////////////////////////////////////////\r
621 void\r
622 IN_Default(boolean gotit,ControlType in)\r
623 {\r
624         if\r
625         (\r
626                 (!gotit)\r
627         ||      ((in == ctrl_Joystick1) && !JoysPresent[0])\r
628         ||      ((in == ctrl_Joystick2) && !JoysPresent[1])\r
629         ||      ((in == ctrl_Mouse) && !MousePresent)\r
630         )\r
631                 in = ctrl_Keyboard1;\r
632         IN_SetControlType(0,in);\r
633 }\r
634 \r
635 ///////////////////////////////////////////////////////////////////////////\r
636 //\r
637 //      IN_Shutdown() - Shuts down the Input Mgr\r
638 //\r
639 ///////////////////////////////////////////////////////////////////////////\r
640 void\r
641 IN_Shutdown(void)\r
642 {\r
643         word    i;\r
644 \r
645         if (!IN_Started)\r
646                 return;\r
647 \r
648         INL_ShutMouse();\r
649         for (i = 0;i < MaxJoys;i++)\r
650                 INL_ShutJoy(i);\r
651         INL_ShutKbd();\r
652 \r
653         IN_Started = false;\r
654 }\r
655 \r
656 ///////////////////////////////////////////////////////////////////////////\r
657 //\r
658 //      IN_SetKeyHook() - Sets the routine that gets called by INL_KeyService()\r
659 //                      everytime a real make/break code gets hit\r
660 //\r
661 ///////////////////////////////////////////////////////////////////////////\r
662 void\r
663 IN_SetKeyHook(void (*hook)())\r
664 {\r
665         INL_KeyHook = hook;\r
666 }\r
667 \r
668 ///////////////////////////////////////////////////////////////////////////\r
669 //\r
670 //      IN_ClearKeysDown() - Clears the keyboard array\r
671 //\r
672 ///////////////////////////////////////////////////////////////////////////\r
673 void\r
674 IN_ClearKeysDown(void)\r
675 {\r
676         int     i;\r
677 \r
678         LastScan = sc_None;\r
679         LastASCII = key_None;\r
680         memset (Keyboard,0,sizeof(Keyboard));\r
681 }\r
682 \r
683 \r
684 ///////////////////////////////////////////////////////////////////////////\r
685 //\r
686 //      IN_ReadControl() - Reads the device associated with the specified\r
687 //              player and fills in the control info struct\r
688 //\r
689 ///////////////////////////////////////////////////////////////////////////\r
690 void\r
691 IN_ReadControl(int player,ControlInfo *info)\r
692 {\r
693                         boolean         realdelta;\r
694                         byte            dbyte;\r
695                         word            buttons;\r
696                         int                     dx,dy;\r
697                         Motion          mx,my;\r
698                         ControlType     type;\r
699 register        KeyboardDef     *def;\r
700 \r
701         dx = dy = 0;\r
702         mx = my = motion_None;\r
703         buttons = 0;\r
704 \r
705         if (DemoMode == demo_Playback)\r
706         {\r
707                 dbyte = DemoBuffer[DemoOffset + 1];\r
708                 my = (dbyte & 3) - 1;\r
709                 mx = ((dbyte >> 2) & 3) - 1;\r
710                 buttons = (dbyte >> 4) & 3;\r
711 \r
712                 if (!(--DemoBuffer[DemoOffset]))\r
713                 {\r
714                         DemoOffset += 2;\r
715                         if (DemoOffset >= DemoSize)\r
716                                 DemoMode = demo_PlayDone;\r
717                 }\r
718 \r
719                 realdelta = false;\r
720         }\r
721         else if (DemoMode == demo_PlayDone)\r
722                 Quit("Demo playback exceeded");\r
723         else\r
724         {\r
725                 switch (type = Controls[player])\r
726                 {\r
727                 case ctrl_Keyboard:\r
728                         def = &KbdDefs;\r
729 \r
730                         if (Keyboard[def->upleft])\r
731                                 mx = motion_Left,my = motion_Up;\r
732                         else if (Keyboard[def->upright])\r
733                                 mx = motion_Right,my = motion_Up;\r
734                         else if (Keyboard[def->downleft])\r
735                                 mx = motion_Left,my = motion_Down;\r
736                         else if (Keyboard[def->downright])\r
737                                 mx = motion_Right,my = motion_Down;\r
738 \r
739                         if (Keyboard[def->up])\r
740                                 my = motion_Up;\r
741                         else if (Keyboard[def->down])\r
742                                 my = motion_Down;\r
743 \r
744                         if (Keyboard[def->left])\r
745                                 mx = motion_Left;\r
746                         else if (Keyboard[def->right])\r
747                                 mx = motion_Right;\r
748 \r
749                         if (Keyboard[def->button0])\r
750                                 buttons += 1 << 0;\r
751                         if (Keyboard[def->button1])\r
752                                 buttons += 1 << 1;\r
753                         realdelta = false;\r
754                         break;\r
755                 case ctrl_Joystick1:\r
756                 case ctrl_Joystick2:\r
757                         INL_GetJoyDelta(type - ctrl_Joystick,&dx,&dy);\r
758                         buttons = INL_GetJoyButtons(type - ctrl_Joystick);\r
759                         realdelta = true;\r
760                         break;\r
761                 case ctrl_Mouse:\r
762                         INL_GetMouseDelta(&dx,&dy);\r
763                         buttons = INL_GetMouseButtons();\r
764                         realdelta = true;\r
765                         break;\r
766                 }\r
767         }\r
768 \r
769         if (realdelta)\r
770         {\r
771                 mx = (dx < 0)? motion_Left : ((dx > 0)? motion_Right : motion_None);\r
772                 my = (dy < 0)? motion_Up : ((dy > 0)? motion_Down : motion_None);\r
773         }\r
774         else\r
775         {\r
776                 dx = mx * 127;\r
777                 dy = my * 127;\r
778         }\r
779 \r
780         info->x = dx;\r
781         info->xaxis = mx;\r
782         info->y = dy;\r
783         info->yaxis = my;\r
784         info->button0 = buttons & (1 << 0);\r
785         info->button1 = buttons & (1 << 1);\r
786         info->button2 = buttons & (1 << 2);\r
787         info->button3 = buttons & (1 << 3);\r
788         info->dir = DirTable[((my + 1) * 3) + (mx + 1)];\r
789 \r
790         if (DemoMode == demo_Record)\r
791         {\r
792                 // Pack the control info into a byte\r
793                 dbyte = (buttons << 4) | ((mx + 1) << 2) | (my + 1);\r
794 \r
795                 if\r
796                 (\r
797                         (DemoBuffer[DemoOffset + 1] == dbyte)\r
798                 &&      (DemoBuffer[DemoOffset] < 255)\r
799                 )\r
800                         (DemoBuffer[DemoOffset])++;\r
801                 else\r
802                 {\r
803                         if (DemoOffset || DemoBuffer[DemoOffset])\r
804                                 DemoOffset += 2;\r
805 \r
806                         if (DemoOffset >= DemoSize)\r
807                                 Quit("Demo buffer overflow");\r
808 \r
809                         DemoBuffer[DemoOffset] = 1;\r
810                         DemoBuffer[DemoOffset + 1] = dbyte;\r
811                 }\r
812         }\r
813 }\r
814 \r
815 ///////////////////////////////////////////////////////////////////////////\r
816 //\r
817 //      IN_SetControlType() - Sets the control type to be used by the specified\r
818 //              player\r
819 //\r
820 ///////////////////////////////////////////////////////////////////////////\r
821 void\r
822 IN_SetControlType(int player,ControlType type)\r
823 {\r
824         // DEBUG - check that requested type is present?\r
825         Controls[player] = type;\r
826 }\r
827 \r
828 ///////////////////////////////////////////////////////////////////////////\r
829 //\r
830 //      IN_WaitForKey() - Waits for a scan code, then clears LastScan and\r
831 //              returns the scan code\r
832 //\r
833 ///////////////////////////////////////////////////////////////////////////\r
834 ScanCode\r
835 IN_WaitForKey(void)\r
836 {\r
837         ScanCode        result;\r
838 \r
839         while (!(result = LastScan))\r
840                 ;\r
841         LastScan = 0;\r
842         return(result);\r
843 }\r
844 \r
845 ///////////////////////////////////////////////////////////////////////////\r
846 //\r
847 //      IN_WaitForASCII() - Waits for an ASCII char, then clears LastASCII and\r
848 //              returns the ASCII value\r
849 //\r
850 ///////////////////////////////////////////////////////////////////////////\r
851 char\r
852 IN_WaitForASCII(void)\r
853 {\r
854         char            result;\r
855 \r
856         while (!(result = LastASCII))\r
857                 ;\r
858         LastASCII = '\0';\r
859         return(result);\r
860 }\r
861 \r
862 ///////////////////////////////////////////////////////////////////////////\r
863 //\r
864 //      IN_Ack() - waits for a button or key press.  If a button is down, upon\r
865 // calling, it must be released for it to be recognized\r
866 //\r
867 ///////////////////////////////////////////////////////////////////////////\r
868 \r
869 boolean btnstate[8];\r
870 \r
871 void IN_StartAck(void)\r
872 {\r
873         unsigned        i,buttons;\r
874 \r
875 //\r
876 // get initial state of everything\r
877 //\r
878         IN_ClearKeysDown();\r
879         memset (btnstate,0,sizeof(btnstate));\r
880 \r
881         buttons = IN_JoyButtons () << 4;\r
882         if (MousePresent)\r
883                 buttons |= IN_MouseButtons ();\r
884 \r
885         for (i=0;i<8;i++,buttons>>=1)\r
886                 if (buttons&1)\r
887                         btnstate[i] = true;\r
888 }\r
889 \r
890 \r
891 boolean IN_CheckAck (void)\r
892 {\r
893         unsigned        i,buttons;\r
894 \r
895 //\r
896 // see if something has been pressed\r
897 //\r
898         if (LastScan)\r
899                 return true;\r
900 \r
901         buttons = IN_JoyButtons () << 4;\r
902         if (MousePresent)\r
903                 buttons |= IN_MouseButtons ();\r
904 \r
905         for (i=0;i<8;i++,buttons>>=1)\r
906                 if ( buttons&1 )\r
907                 {\r
908                         if (!btnstate[i])\r
909                                 return true;\r
910                 }\r
911                 else\r
912                         btnstate[i]=false;\r
913 \r
914         return false;\r
915 }\r
916 \r
917 \r
918 void IN_Ack (void)\r
919 {\r
920         IN_StartAck ();\r
921 \r
922         while (!IN_CheckAck ())\r
923         ;\r
924 }\r
925 \r
926 \r
927 ///////////////////////////////////////////////////////////////////////////\r
928 //\r
929 //      IN_UserInput() - Waits for the specified delay time (in ticks) or the\r
930 //              user pressing a key or a mouse button. If the clear flag is set, it\r
931 //              then either clears the key or waits for the user to let the mouse\r
932 //              button up.\r
933 //\r
934 ///////////////////////////////////////////////////////////////////////////\r
935 boolean IN_UserInput(longword delay)\r
936 {\r
937         longword        lasttime;\r
938 \r
939         lasttime = TimeCount;\r
940         IN_StartAck ();\r
941         do\r
942         {\r
943                 if (IN_CheckAck())\r
944                         return true;\r
945         } while (TimeCount - lasttime < delay);\r
946         return(false);\r
947 }\r
948 \r
949 //===========================================================================\r
950 \r
951 /*\r
952 ===================\r
953 =\r
954 = IN_MouseButtons\r
955 =\r
956 ===================\r
957 */\r
958 \r
959 byte    IN_MouseButtons (void)\r
960 {\r
961         if (MousePresent)\r
962         {\r
963                 Mouse(MButtons);\r
964                 return _BX;\r
965         }\r
966         else\r
967                 return 0;\r
968 }\r
969 \r
970 \r
971 /*\r
972 ===================\r
973 =\r
974 = IN_JoyButtons\r
975 =\r
976 ===================\r
977 */\r
978 \r
979 byte    IN_JoyButtons (void)\r
980 {\r
981         unsigned joybits;\r
982 \r
983         joybits = inportb(0x201);       // Get all the joystick buttons\r
984         joybits >>= 4;                          // only the high bits are useful\r
985         joybits ^= 15;                          // return with 1=pressed\r
986 \r
987         return joybits;\r
988 }\r
989 \r
990 \r