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