]> 4ch.mooo.com Git - 16.git/blob - 16/cawat/ID_IN.C
7b4421e94ee64d2288bf884b44603a898e3a11b6
[16.git] / 16 / cawat / ID_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"
39 #include "id_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 _seg       *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 = inportb(0x60);      // Get the scan code\r
165 \r
166         // Tell the XT keyboard controller to clear the key\r
167         outportb(0x61,(temp = inportb(0x61)) | 0x80);\r
168         outportb(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         outportb(0x20,0x20);\r
223 }\r
224 \r
225 ///////////////////////////////////////////////////////////////////////////\r
226 //\r
227 //      INL_GetMouseDelta() - Gets the amount that the mouse has moved from the\r
228 //              mouse driver\r
229 //\r
230 ///////////////////////////////////////////////////////////////////////////\r
231 static void\r
232 INL_GetMouseDelta(int *x,int *y)\r
233 {\r
234         Mouse(MDelta);\r
235         *x = _CX;\r
236         *y = _DX;\r
237 }\r
238 \r
239 ///////////////////////////////////////////////////////////////////////////\r
240 //\r
241 //      INL_GetMouseButtons() - Gets the status of the mouse buttons from the\r
242 //              mouse driver\r
243 //\r
244 ///////////////////////////////////////////////////////////////////////////\r
245 static word\r
246 INL_GetMouseButtons(void)\r
247 {\r
248         word    buttons;\r
249 \r
250         Mouse(MButtons);\r
251         buttons = _BX;\r
252         return(buttons);\r
253 }\r
254 \r
255 ///////////////////////////////////////////////////////////////////////////\r
256 //\r
257 //      IN_GetJoyAbs() - Reads the absolute position of the specified joystick\r
258 //\r
259 ///////////////////////////////////////////////////////////////////////////\r
260 void\r
261 IN_GetJoyAbs(word joy,word *xp,word *yp)\r
262 {\r
263         byte    xb,yb,\r
264                         xs,ys;\r
265         word    x,y;\r
266 \r
267         x = y = 0;\r
268         xs = joy? 2 : 0;                // Find shift value for x axis\r
269         xb = 1 << xs;                   // Use shift value to get x bit mask\r
270         ys = joy? 3 : 1;                // Do the same for y axis\r
271         yb = 1 << ys;\r
272 \r
273 // Read the absolute joystick values\r
274 asm             pushf                           // Save some registers\r
275 asm             push    si\r
276 asm             push    di\r
277 asm             cli                                     // Make sure an interrupt doesn't screw the timings\r
278 \r
279 \r
280 asm             mov             dx,0x201\r
281 asm             in              al,dx\r
282 asm             out             dx,al           // Clear the resistors\r
283 \r
284 asm             mov             ah,[xb]         // Get masks into registers\r
285 asm             mov             ch,[yb]\r
286 \r
287 asm             xor             si,si           // Clear count registers\r
288 asm             xor             di,di\r
289 asm             xor             bh,bh           // Clear high byte of bx for later\r
290 \r
291 asm             push    bp                      // Don't mess up stack frame\r
292 asm             mov             bp,MaxJoyValue\r
293 \r
294 loop:\r
295 asm             in              al,dx           // Get bits indicating whether all are finished\r
296 \r
297 asm             dec             bp                      // Check bounding register\r
298 asm             jz              done            // We have a silly value - abort\r
299 \r
300 asm             mov             bl,al           // Duplicate the bits\r
301 asm             and             bl,ah           // Mask off useless bits (in [xb])\r
302 asm             add             si,bx           // Possibly increment count register\r
303 asm             mov             cl,bl           // Save for testing later\r
304 \r
305 asm             mov             bl,al\r
306 asm             and             bl,ch           // [yb]\r
307 asm             add             di,bx\r
308 \r
309 asm             add             cl,bl\r
310 asm             jnz             loop            // If both bits were 0, drop out\r
311 \r
312 done:\r
313 asm     pop             bp\r
314 \r
315 asm             mov             cl,[xs]         // Get the number of bits to shift\r
316 asm             shr             si,cl           //  and shift the count that many times\r
317 \r
318 asm             mov             cl,[ys]\r
319 asm             shr             di,cl\r
320 \r
321 asm             mov             [x],si          // Store the values into the variables\r
322 asm             mov             [y],di\r
323 \r
324 asm             pop             di\r
325 asm             pop             si\r
326 asm             popf                            // Restore the registers\r
327 \r
328         *xp = x;\r
329         *yp = y;\r
330 }\r
331 \r
332 ///////////////////////////////////////////////////////////////////////////\r
333 //\r
334 //      INL_GetJoyDelta() - Returns the relative movement of the specified\r
335 //              joystick (from +/-127, scaled adaptively)\r
336 //\r
337 ///////////////////////////////////////////////////////////////////////////\r
338 static void\r
339 INL_GetJoyDelta(word joy,int *dx,int *dy,boolean adaptive)\r
340 {\r
341         word            x,y;\r
342         longword        time;\r
343         JoystickDef     *def;\r
344 static  longword        lasttime;\r
345 \r
346         IN_GetJoyAbs(joy,&x,&y);\r
347         def = JoyDefs + joy;\r
348 \r
349         if (x < def->threshMinX)\r
350         {\r
351                 if (x < def->joyMinX)\r
352                         x = def->joyMinX;\r
353 \r
354                 x = -(x - def->threshMinX);\r
355                 x *= def->joyMultXL;\r
356                 x >>= JoyScaleShift;\r
357                 *dx = (x > 127)? -127 : -x;\r
358         }\r
359         else if (x > def->threshMaxX)\r
360         {\r
361                 if (x > def->joyMaxX)\r
362                         x = def->joyMaxX;\r
363 \r
364                 x = x - def->threshMaxX;\r
365                 x *= def->joyMultXH;\r
366                 x >>= JoyScaleShift;\r
367                 *dx = (x > 127)? 127 : x;\r
368         }\r
369         else\r
370                 *dx = 0;\r
371 \r
372         if (y < def->threshMinY)\r
373         {\r
374                 if (y < def->joyMinY)\r
375                         y = def->joyMinY;\r
376 \r
377                 y = -(y - def->threshMinY);\r
378                 y *= def->joyMultYL;\r
379                 y >>= JoyScaleShift;\r
380                 *dy = (y > 127)? -127 : -y;\r
381         }\r
382         else if (y > def->threshMaxY)\r
383         {\r
384                 if (y > def->joyMaxY)\r
385                         y = def->joyMaxY;\r
386 \r
387                 y = y - def->threshMaxY;\r
388                 y *= def->joyMultYH;\r
389                 y >>= JoyScaleShift;\r
390                 *dy = (y > 127)? 127 : y;\r
391         }\r
392         else\r
393                 *dy = 0;\r
394 \r
395         if (adaptive)\r
396         {\r
397                 time = (TimeCount - lasttime) / 2;\r
398                 if (time)\r
399                 {\r
400                         if (time > 8)\r
401                                 time = 8;\r
402                         *dx *= time;\r
403                         *dy *= time;\r
404                 }\r
405         }\r
406         lasttime = TimeCount;\r
407 }\r
408 \r
409 ///////////////////////////////////////////////////////////////////////////\r
410 //\r
411 //      INL_GetJoyButtons() - Returns the button status of the specified\r
412 //              joystick\r
413 //\r
414 ///////////////////////////////////////////////////////////////////////////\r
415 static word\r
416 INL_GetJoyButtons(word joy)\r
417 {\r
418 register        word    result;\r
419 \r
420         result = inportb(0x201);        // Get all the joystick buttons\r
421         result >>= joy? 6 : 4;  // Shift into bits 0-1\r
422         result &= 3;                            // Mask off the useless bits\r
423         result ^= 3;\r
424         return(result);\r
425 }\r
426 \r
427 ///////////////////////////////////////////////////////////////////////////\r
428 //\r
429 //      IN_GetJoyButtonsDB() - Returns the de-bounced button status of the\r
430 //              specified joystick\r
431 //\r
432 ///////////////////////////////////////////////////////////////////////////\r
433 word\r
434 IN_GetJoyButtonsDB(word joy)\r
435 {\r
436         longword        lasttime;\r
437         word            result1,result2;\r
438 \r
439         do\r
440         {\r
441                 result1 = INL_GetJoyButtons(joy);\r
442                 lasttime = TimeCount;\r
443                 while (TimeCount == lasttime)\r
444                         ;\r
445                 result2 = INL_GetJoyButtons(joy);\r
446         } while (result1 != result2);\r
447         return(result1);\r
448 }\r
449 \r
450 ///////////////////////////////////////////////////////////////////////////\r
451 //\r
452 //      INL_StartKbd() - Sets up my keyboard stuff for use\r
453 //\r
454 ///////////////////////////////////////////////////////////////////////////\r
455 static void\r
456 INL_StartKbd(void)\r
457 {\r
458         INL_KeyHook = 0;        // Clear key hook\r
459 \r
460         IN_ClearKeysDown();\r
461 \r
462         OldKeyVect = getvect(KeyInt);\r
463         setvect(KeyInt,INL_KeyService);\r
464 }\r
465 \r
466 ///////////////////////////////////////////////////////////////////////////\r
467 //\r
468 //      INL_ShutKbd() - Restores keyboard control to the BIOS\r
469 //\r
470 ///////////////////////////////////////////////////////////////////////////\r
471 static void\r
472 INL_ShutKbd(void)\r
473 {\r
474         poke(0x40,0x17,peek(0x40,0x17) & 0xfaf0);       // Clear ctrl/alt/shift flags\r
475 \r
476         setvect(KeyInt,OldKeyVect);\r
477 }\r
478 \r
479 ///////////////////////////////////////////////////////////////////////////\r
480 //\r
481 //      INL_StartMouse() - Detects and sets up the mouse\r
482 //\r
483 ///////////////////////////////////////////////////////////////////////////\r
484 static boolean\r
485 INL_StartMouse(void)\r
486 {\r
487         if (getvect(MouseInt))\r
488         {\r
489                 Mouse(MReset);\r
490                 if (_AX == 0xffff)\r
491                         return(true);\r
492         }\r
493         return(false);\r
494 }\r
495 \r
496 ///////////////////////////////////////////////////////////////////////////\r
497 //\r
498 //      INL_ShutMouse() - Cleans up after the mouse\r
499 //\r
500 ///////////////////////////////////////////////////////////////////////////\r
501 static void\r
502 INL_ShutMouse(void)\r
503 {\r
504 }\r
505 \r
506 //\r
507 //      INL_SetJoyScale() - Sets up scaling values for the specified joystick\r
508 //\r
509 static void\r
510 INL_SetJoyScale(word joy)\r
511 {\r
512         JoystickDef     *def;\r
513 \r
514         def = &JoyDefs[joy];\r
515         def->joyMultXL = JoyScaleMax / (def->threshMinX - def->joyMinX);\r
516         def->joyMultXH = JoyScaleMax / (def->joyMaxX - def->threshMaxX);\r
517         def->joyMultYL = JoyScaleMax / (def->threshMinY - def->joyMinY);\r
518         def->joyMultYH = JoyScaleMax / (def->joyMaxY - def->threshMaxY);\r
519 }\r
520 \r
521 ///////////////////////////////////////////////////////////////////////////\r
522 //\r
523 //      IN_SetupJoy() - Sets up thresholding values and calls INL_SetJoyScale()\r
524 //              to set up scaling values\r
525 //\r
526 ///////////////////////////////////////////////////////////////////////////\r
527 void\r
528 IN_SetupJoy(word joy,word minx,word maxx,word miny,word maxy)\r
529 {\r
530         word            d,r;\r
531         JoystickDef     *def;\r
532 \r
533         def = &JoyDefs[joy];\r
534 \r
535         def->joyMinX = minx;\r
536         def->joyMaxX = maxx;\r
537         r = maxx - minx;\r
538         d = r / 5;\r
539         def->threshMinX = ((r / 2) - d) + minx;\r
540         def->threshMaxX = ((r / 2) + d) + minx;\r
541 \r
542         def->joyMinY = miny;\r
543         def->joyMaxY = maxy;\r
544         r = maxy - miny;\r
545         d = r / 5;\r
546         def->threshMinY = ((r / 2) - d) + miny;\r
547         def->threshMaxY = ((r / 2) + d) + miny;\r
548 \r
549         INL_SetJoyScale(joy);\r
550 }\r
551 \r
552 ///////////////////////////////////////////////////////////////////////////\r
553 //\r
554 //      INL_StartJoy() - Detects & auto-configures the specified joystick\r
555 //                                      The auto-config assumes the joystick is centered\r
556 //\r
557 ///////////////////////////////////////////////////////////////////////////\r
558 static boolean\r
559 INL_StartJoy(word joy)\r
560 {\r
561         word            x,y;\r
562 \r
563         IN_GetJoyAbs(joy,&x,&y);\r
564 \r
565         if\r
566         (\r
567                 ((x == 0) || (x > MaxJoyValue - 10))\r
568         ||      ((y == 0) || (y > MaxJoyValue - 10))\r
569         )\r
570                 return(false);\r
571         else\r
572         {\r
573                 IN_SetupJoy(joy,0,x * 2,0,y * 2);\r
574                 return(true);\r
575         }\r
576 }\r
577 \r
578 ///////////////////////////////////////////////////////////////////////////\r
579 //\r
580 //      INL_ShutJoy() - Cleans up the joystick stuff\r
581 //\r
582 ///////////////////////////////////////////////////////////////////////////\r
583 static void\r
584 INL_ShutJoy(word joy)\r
585 {\r
586         JoysPresent[joy] = false;\r
587 }\r
588 \r
589 //      Public routines\r
590 \r
591 ///////////////////////////////////////////////////////////////////////////\r
592 //\r
593 //      IN_Startup() - Starts up the Input Mgr\r
594 //\r
595 ///////////////////////////////////////////////////////////////////////////\r
596 void\r
597 IN_Startup(void)\r
598 {\r
599         boolean checkjoys,checkmouse;\r
600         word    i;\r
601 \r
602         if (IN_Started)\r
603                 return;\r
604 \r
605         checkjoys = true;\r
606         checkmouse = true;\r
607         for (i = 1;i < _argc;i++)\r
608         {\r
609                 switch (US_CheckParm(_argv[i],ParmStrings))\r
610                 {\r
611                 case 0:\r
612                         checkjoys = false;\r
613                         break;\r
614                 case 1:\r
615                         checkmouse = false;\r
616                         break;\r
617                 }\r
618         }\r
619 \r
620         INL_StartKbd();\r
621         MousePresent = checkmouse? INL_StartMouse() : false;\r
622 \r
623         for (i = 0;i < MaxJoys;i++)\r
624                 JoysPresent[i] = checkjoys? INL_StartJoy(i) : false;\r
625 \r
626         IN_Started = true;\r
627 }\r
628 \r
629 ///////////////////////////////////////////////////////////////////////////\r
630 //\r
631 //      IN_Default() - Sets up default conditions for the Input Mgr\r
632 //\r
633 ///////////////////////////////////////////////////////////////////////////\r
634 void\r
635 IN_Default(boolean gotit,ControlType in)\r
636 {\r
637         if\r
638         (\r
639                 (!gotit)\r
640         ||      ((in == ctrl_Joystick1) && !JoysPresent[0])\r
641         ||      ((in == ctrl_Joystick2) && !JoysPresent[1])\r
642         ||      ((in == ctrl_Mouse) && !MousePresent)\r
643         )\r
644                 in = ctrl_Keyboard1;\r
645         IN_SetControlType(0,in);\r
646 }\r
647 \r
648 ///////////////////////////////////////////////////////////////////////////\r
649 //\r
650 //      IN_Shutdown() - Shuts down the Input Mgr\r
651 //\r
652 ///////////////////////////////////////////////////////////////////////////\r
653 void\r
654 IN_Shutdown(void)\r
655 {\r
656         word    i;\r
657 \r
658         if (!IN_Started)\r
659                 return;\r
660 \r
661         INL_ShutMouse();\r
662         for (i = 0;i < MaxJoys;i++)\r
663                 INL_ShutJoy(i);\r
664         INL_ShutKbd();\r
665 \r
666         IN_Started = false;\r
667 }\r
668 \r
669 ///////////////////////////////////////////////////////////////////////////\r
670 //\r
671 //      IN_SetKeyHook() - Sets the routine that gets called by INL_KeyService()\r
672 //                      everytime a real make/break code gets hit\r
673 //\r
674 ///////////////////////////////////////////////////////////////////////////\r
675 void\r
676 IN_SetKeyHook(void (*hook)())\r
677 {\r
678         INL_KeyHook = hook;\r
679 }\r
680 \r
681 ///////////////////////////////////////////////////////////////////////////\r
682 //\r
683 //      IN_ClearKeyDown() - Clears the keyboard array\r
684 //\r
685 ///////////////////////////////////////////////////////////////////////////\r
686 void\r
687 IN_ClearKeysDown(void)\r
688 {\r
689         int     i;\r
690 \r
691         LastScan = sc_None;\r
692         LastASCII = key_None;\r
693         for (i = 0;i < NumCodes;i++)\r
694                 Keyboard[i] = false;\r
695 }\r
696 \r
697 ///////////////////////////////////////////////////////////////////////////\r
698 //\r
699 //      INL_AdjustCursor() - Internal routine of common code from IN_ReadCursor()\r
700 //\r
701 ///////////////////////////////////////////////////////////////////////////\r
702 static void\r
703 INL_AdjustCursor(CursorInfo *info,word buttons,int dx,int dy)\r
704 {\r
705         if (buttons & (1 << 0))\r
706                 info->button0 = true;\r
707         if (buttons & (1 << 1))\r
708                 info->button1 = true;\r
709 \r
710         info->x += dx;\r
711         info->y += dy;\r
712 }\r
713 \r
714 ///////////////////////////////////////////////////////////////////////////\r
715 //\r
716 //      IN_ReadCursor() - Reads the input devices and fills in the cursor info\r
717 //              struct\r
718 //\r
719 ///////////////////////////////////////////////////////////////////////////\r
720 void\r
721 IN_ReadCursor(CursorInfo *info)\r
722 {\r
723         word    i,\r
724                         buttons;\r
725         int             dx,dy;\r
726 \r
727         info->x = info->y = 0;\r
728         info->button0 = info->button1 = false;\r
729 \r
730         if (MousePresent)\r
731         {\r
732                 buttons = INL_GetMouseButtons();\r
733                 INL_GetMouseDelta(&dx,&dy);\r
734                 INL_AdjustCursor(info,buttons,dx,dy);\r
735         }\r
736 \r
737         for (i = 0;i < MaxJoys;i++)\r
738         {\r
739                 if (!JoysPresent[i])\r
740                         continue;\r
741 \r
742                 buttons = INL_GetJoyButtons(i);\r
743                 INL_GetJoyDelta(i,&dx,&dy,true);\r
744                 dx /= 64;\r
745                 dy /= 64;\r
746                 INL_AdjustCursor(info,buttons,dx,dy);\r
747         }\r
748 }\r
749 \r
750 ///////////////////////////////////////////////////////////////////////////\r
751 //\r
752 //      IN_ReadControl() - Reads the device associated with the specified\r
753 //              player and fills in the control info struct\r
754 //\r
755 ///////////////////////////////////////////////////////////////////////////\r
756 void\r
757 IN_ReadControl(int player,ControlInfo *info)\r
758 {\r
759                         boolean         realdelta=false;                                // MDM (GAMERS EDGE)\r
760                         byte            dbyte;\r
761                         word            buttons;\r
762                         int                     dx,dy;\r
763                         Motion          mx,my;\r
764                         ControlType     type;\r
765 register        KeyboardDef     *def;\r
766 \r
767         dx = dy = 0;\r
768         mx = my = motion_None;\r
769         buttons = 0;\r
770 \r
771 #if 0\r
772         if (DemoMode == demo_Playback)\r
773         {\r
774                 dbyte = DemoBuffer[DemoOffset + 1];\r
775                 my = (dbyte & 3) - 1;\r
776                 mx = ((dbyte >> 2) & 3) - 1;\r
777                 buttons = (dbyte >> 4) & 3;\r
778 \r
779                 if (!(--DemoBuffer[DemoOffset]))\r
780                 {\r
781                         DemoOffset += 2;\r
782                         if (DemoOffset >= DemoSize)\r
783                                 DemoMode = demo_PlayDone;\r
784                 }\r
785 \r
786                 realdelta = false;\r
787         }\r
788         else if (DemoMode == demo_PlayDone)\r
789                 Quit("Demo playback exceeded");\r
790         else\r
791 #endif\r
792         {\r
793                                                                                                                         // MDM begin (GAMERS EDGE) - added this block\r
794                 ControlTypeUsed = ctrl_None;\r
795 \r
796                 // Handle mouse input...\r
797                 //\r
798                 if ((MousePresent) && (ControlTypeUsed == ctrl_None))\r
799                 {\r
800                         INL_GetMouseDelta(&dx,&dy);\r
801                         buttons = INL_GetMouseButtons();\r
802                         realdelta = true;\r
803                         if (dx || dy || buttons)\r
804                                 ControlTypeUsed = ctrl_Mouse;\r
805                 }\r
806 \r
807                 // Handle joystick input...\r
808                 //\r
809                 if ((JoystickCalibrated) && (ControlTypeUsed == ctrl_None))\r
810                 {\r
811                         type = ctrl_Joystick1;\r
812                         INL_GetJoyDelta(type - ctrl_Joystick,&dx,&dy,false);\r
813                         buttons = INL_GetJoyButtons(type - ctrl_Joystick);\r
814                         realdelta = true;\r
815                         if (dx || dy || buttons)\r
816                                 ControlTypeUsed = ctrl_Joystick;\r
817                 }\r
818 \r
819                 // Handle keyboard input...\r
820                 //\r
821                 if (ControlTypeUsed == ctrl_None)\r
822                 {\r
823                         type = ctrl_Keyboard1;\r
824                         def = &KbdDefs[type - ctrl_Keyboard];\r
825 \r
826                         if (Keyboard[def->upleft])\r
827                                 mx = motion_Left,my = motion_Up;\r
828                         else if (Keyboard[def->upright])\r
829                                 mx = motion_Right,my = motion_Up;\r
830                         else if (Keyboard[def->downleft])\r
831                                 mx = motion_Left,my = motion_Down;\r
832                         else if (Keyboard[def->downright])\r
833                                 mx = motion_Right,my = motion_Down;\r
834 \r
835                         if (Keyboard[def->up])\r
836                                 my = motion_Up;\r
837                         else if (Keyboard[def->down])\r
838                                 my = motion_Down;\r
839 \r
840                         if (Keyboard[def->left])\r
841                                 mx = motion_Left;\r
842                         else if (Keyboard[def->right])\r
843                                 mx = motion_Right;\r
844 \r
845                         if (Keyboard[def->button0])\r
846                                 buttons += 1 << 0;\r
847                         if (Keyboard[def->button1])\r
848                                 buttons += 1 << 1;\r
849                         realdelta = false;\r
850                         if (mx || my || buttons)\r
851                                 ControlTypeUsed = ctrl_Keyboard;\r
852                 }                                                                                                       // MDM end (GAMERS EDGE)\r
853         }\r
854 \r
855         if (realdelta)\r
856         {\r
857                 mx = (dx < 0)? motion_Left : ((dx > 0)? motion_Right : motion_None);\r
858                 my = (dy < 0)? motion_Up : ((dy > 0)? motion_Down : motion_None);\r
859         }\r
860         else\r
861         {\r
862                 dx = mx * 127;\r
863                 dy = my * 127;\r
864         }\r
865 \r
866         info->x = dx;\r
867         info->xaxis = mx;\r
868         info->y = dy;\r
869         info->yaxis = my;\r
870         info->button0 = buttons & (1 << 0);\r
871         info->button1 = buttons & (1 << 1);\r
872         info->dir = DirTable[((my + 1) * 3) + (mx + 1)];\r
873 \r
874 #if 0\r
875         if (DemoMode == demo_Record)\r
876         {\r
877                 // Pack the control info into a byte\r
878                 dbyte = (buttons << 4) | ((mx + 1) << 2) | (my + 1);\r
879 \r
880                 if\r
881                 (\r
882                         (DemoBuffer[DemoOffset + 1] == dbyte)\r
883                 &&      (DemoBuffer[DemoOffset] < 255)\r
884                 )\r
885                         (DemoBuffer[DemoOffset])++;\r
886                 else\r
887                 {\r
888                         if (DemoOffset || DemoBuffer[DemoOffset])\r
889                                 DemoOffset += 2;\r
890 \r
891                         if (DemoOffset >= DemoSize)\r
892                                 Quit("Demo buffer overflow");\r
893 \r
894                         DemoBuffer[DemoOffset] = 1;\r
895                         DemoBuffer[DemoOffset + 1] = dbyte;\r
896                 }\r
897         }\r
898 #endif\r
899 }\r
900 \r
901 #if 0\r
902 ///////////////////////////////////////////////////////////////////////////\r
903 //\r
904 //      IN_ReadControl() - Reads the device associated with the specified\r
905 //              player and fills in the control info struct\r
906 //\r
907 ///////////////////////////////////////////////////////////////////////////\r
908 void\r
909 IN_ReadControl(int player,ControlInfo *info)\r
910 {\r
911                         boolean         realdelta;\r
912                         byte            dbyte;\r
913                         word            buttons;\r
914                         int                     dx,dy;\r
915                         Motion          mx,my;\r
916                         ControlType     type;\r
917 register        KeyboardDef     *def;\r
918 \r
919         dx = dy = 0;\r
920         mx = my = motion_None;\r
921         buttons = 0;\r
922 \r
923 #if 0\r
924         if (DemoMode == demo_Playback)\r
925         {\r
926                 dbyte = DemoBuffer[DemoOffset + 1];\r
927                 my = (dbyte & 3) - 1;\r
928                 mx = ((dbyte >> 2) & 3) - 1;\r
929                 buttons = (dbyte >> 4) & 3;\r
930 \r
931                 if (!(--DemoBuffer[DemoOffset]))\r
932                 {\r
933                         DemoOffset += 2;\r
934                         if (DemoOffset >= DemoSize)\r
935                                 DemoMode = demo_PlayDone;\r
936                 }\r
937 \r
938                 realdelta = false;\r
939         }\r
940         else if (DemoMode == demo_PlayDone)\r
941                 Quit("Demo playback exceeded");\r
942         else\r
943 #endif\r
944         {\r
945                 switch (type = Controls[player])\r
946                 {\r
947                 case ctrl_Keyboard1:\r
948                 case ctrl_Keyboard2:\r
949                         def = &KbdDefs[type - ctrl_Keyboard];\r
950 \r
951                         if (Keyboard[def->upleft])\r
952                                 mx = motion_Left,my = motion_Up;\r
953                         else if (Keyboard[def->upright])\r
954                                 mx = motion_Right,my = motion_Up;\r
955                         else if (Keyboard[def->downleft])\r
956                                 mx = motion_Left,my = motion_Down;\r
957                         else if (Keyboard[def->downright])\r
958                                 mx = motion_Right,my = motion_Down;\r
959 \r
960                         if (Keyboard[def->up])\r
961                                 my = motion_Up;\r
962                         else if (Keyboard[def->down])\r
963                                 my = motion_Down;\r
964 \r
965                         if (Keyboard[def->left])\r
966                                 mx = motion_Left;\r
967                         else if (Keyboard[def->right])\r
968                                 mx = motion_Right;\r
969 \r
970                         if (Keyboard[def->button0])\r
971                                 buttons += 1 << 0;\r
972                         if (Keyboard[def->button1])\r
973                                 buttons += 1 << 1;\r
974                         realdelta = false;\r
975                         break;\r
976                 case ctrl_Joystick1:\r
977                 case ctrl_Joystick2:\r
978                         INL_GetJoyDelta(type - ctrl_Joystick,&dx,&dy,false);\r
979                         buttons = INL_GetJoyButtons(type - ctrl_Joystick);\r
980                         realdelta = true;\r
981                         break;\r
982                 case ctrl_Mouse:\r
983                         INL_GetMouseDelta(&dx,&dy);\r
984                         buttons = INL_GetMouseButtons();\r
985                         realdelta = true;\r
986                         break;\r
987                 }\r
988         }\r
989 \r
990         if (realdelta)\r
991         {\r
992                 mx = (dx < 0)? motion_Left : ((dx > 0)? motion_Right : motion_None);\r
993                 my = (dy < 0)? motion_Up : ((dy > 0)? motion_Down : motion_None);\r
994         }\r
995         else\r
996         {\r
997                 dx = mx * 127;\r
998                 dy = my * 127;\r
999         }\r
1000 \r
1001         info->x = dx;\r
1002         info->xaxis = mx;\r
1003         info->y = dy;\r
1004         info->yaxis = my;\r
1005         info->button0 = buttons & (1 << 0);\r
1006         info->button1 = buttons & (1 << 1);\r
1007         info->dir = DirTable[((my + 1) * 3) + (mx + 1)];\r
1008 \r
1009 #if 0\r
1010         if (DemoMode == demo_Record)\r
1011         {\r
1012                 // Pack the control info into a byte\r
1013                 dbyte = (buttons << 4) | ((mx + 1) << 2) | (my + 1);\r
1014 \r
1015                 if\r
1016                 (\r
1017                         (DemoBuffer[DemoOffset + 1] == dbyte)\r
1018                 &&      (DemoBuffer[DemoOffset] < 255)\r
1019                 )\r
1020                         (DemoBuffer[DemoOffset])++;\r
1021                 else\r
1022                 {\r
1023                         if (DemoOffset || DemoBuffer[DemoOffset])\r
1024                                 DemoOffset += 2;\r
1025 \r
1026                         if (DemoOffset >= DemoSize)\r
1027                                 Quit("Demo buffer overflow");\r
1028 \r
1029                         DemoBuffer[DemoOffset] = 1;\r
1030                         DemoBuffer[DemoOffset + 1] = dbyte;\r
1031                 }\r
1032         }\r
1033 #endif\r
1034 }\r
1035 #endif\r
1036 \r
1037 ///////////////////////////////////////////////////////////////////////////\r
1038 //\r
1039 //      IN_SetControlType() - Sets the control type to be used by the specified\r
1040 //              player\r
1041 //\r
1042 ///////////////////////////////////////////////////////////////////////////\r
1043 void\r
1044 IN_SetControlType(int player,ControlType type)\r
1045 {\r
1046         // DEBUG - check that requested type is present?\r
1047         Controls[player] = type;\r
1048 }\r
1049 \r
1050 #if 0\r
1051 ///////////////////////////////////////////////////////////////////////////\r
1052 //\r
1053 //      IN_StartDemoRecord() - Starts the demo recording, using a buffer the\r
1054 //              size passed. Returns if the buffer allocation was successful\r
1055 //\r
1056 ///////////////////////////////////////////////////////////////////////////\r
1057 boolean\r
1058 IN_StartDemoRecord(word bufsize)\r
1059 {\r
1060         if (!bufsize)\r
1061                 return(false);\r
1062 \r
1063         MM_GetPtr((memptr *)&DemoBuffer,bufsize);\r
1064         DemoMode = demo_Record;\r
1065         DemoSize = bufsize & ~1;\r
1066         DemoOffset = 0;\r
1067         DemoBuffer[0] = DemoBuffer[1] = 0;\r
1068 \r
1069         return(true);\r
1070 }\r
1071 \r
1072 ///////////////////////////////////////////////////////////////////////////\r
1073 //\r
1074 //      IN_StartDemoPlayback() - Plays back the demo pointed to of the given size\r
1075 //\r
1076 ///////////////////////////////////////////////////////////////////////////\r
1077 void\r
1078 IN_StartDemoPlayback(byte /*_1seg*/ *buffer,word bufsize)\r
1079 {\r
1080         DemoBuffer = buffer;\r
1081         DemoMode = demo_Playback;\r
1082         DemoSize = bufsize & ~1;\r
1083         DemoOffset = 0;\r
1084 }\r
1085 \r
1086 ///////////////////////////////////////////////////////////////////////////\r
1087 //\r
1088 //      IN_StopDemo() - Turns off demo mode\r
1089 //\r
1090 ///////////////////////////////////////////////////////////////////////////\r
1091 void\r
1092 IN_StopDemo(void)\r
1093 {\r
1094         if ((DemoMode == demo_Record) && DemoOffset)\r
1095                 DemoOffset += 2;\r
1096 \r
1097         DemoMode = demo_Off;\r
1098 }\r
1099 \r
1100 ///////////////////////////////////////////////////////////////////////////\r
1101 //\r
1102 //      IN_FreeDemoBuffer() - Frees the demo buffer, if it's been allocated\r
1103 //\r
1104 ///////////////////////////////////////////////////////////////////////////\r
1105 void\r
1106 IN_FreeDemoBuffer(void)\r
1107 {\r
1108         if (DemoBuffer)\r
1109                 MM_FreePtr((memptr *)&DemoBuffer);\r
1110 }\r
1111 #endif\r
1112 \r
1113 \r
1114 #if 0\r
1115 ///////////////////////////////////////////////////////////////////////////\r
1116 //\r
1117 //      IN_GetScanName() - Returns a string containing the name of the\r
1118 //              specified scan code\r
1119 //\r
1120 ///////////////////////////////////////////////////////////////////////////\r
1121 byte *\r
1122 IN_GetScanName(ScanCode scan)\r
1123 {\r
1124         byte            **p;\r
1125         ScanCode        far *s;\r
1126 \r
1127         for (s = ExtScanCodes,p = ExtScanNames;*s;p++,s++)\r
1128                 if (*s == scan)\r
1129                         return(*p);\r
1130 \r
1131         return(ScanNames[scan]);\r
1132 }\r
1133 #endif\r
1134 \r
1135 \r
1136 ///////////////////////////////////////////////////////////////////////////\r
1137 //\r
1138 //      IN_WaitForKey() - Waits for a scan code, then clears LastScan and\r
1139 //              returns the scan code\r
1140 //\r
1141 ///////////////////////////////////////////////////////////////////////////\r
1142 ScanCode\r
1143 IN_WaitForKey(void)\r
1144 {\r
1145         ScanCode        result;\r
1146 \r
1147         while (!(result = LastScan))\r
1148                 ;\r
1149         LastScan = 0;\r
1150         return(result);\r
1151 }\r
1152 \r
1153 ///////////////////////////////////////////////////////////////////////////\r
1154 //\r
1155 //      IN_WaitForASCII() - Waits for an ASCII char, then clears LastASCII and\r
1156 //              returns the ASCII value\r
1157 //\r
1158 ///////////////////////////////////////////////////////////////////////////\r
1159 char\r
1160 IN_WaitForASCII(void)\r
1161 {\r
1162         char            result;\r
1163 \r
1164         while (!(result = LastASCII))\r
1165                 ;\r
1166         LastASCII = '\0';\r
1167         return(result);\r
1168 }\r
1169 \r
1170 ///////////////////////////////////////////////////////////////////////////\r
1171 //\r
1172 //      IN_AckBack() - Waits for either an ASCII keypress or a button press\r
1173 //\r
1174 ///////////////////////////////////////////////////////////////////////////\r
1175 void\r
1176 IN_AckBack(void)\r
1177 {\r
1178         word    i;\r
1179 \r
1180         while (!LastScan)\r
1181         {\r
1182                 if (MousePresent)\r
1183                 {\r
1184                         if (INL_GetMouseButtons())\r
1185                         {\r
1186                                 while (INL_GetMouseButtons())\r
1187                                         ;\r
1188                                 return;\r
1189                         }\r
1190                 }\r
1191 \r
1192                 for (i = 0;i < MaxJoys;i++)\r
1193                 {\r
1194                         if (JoysPresent[i])\r
1195                         {\r
1196                                 if (IN_GetJoyButtonsDB(i))\r
1197                                 {\r
1198                                         while (IN_GetJoyButtonsDB(i))\r
1199                                                 ;\r
1200                                         return;\r
1201                                 }\r
1202                         }\r
1203                 }\r
1204         }\r
1205 \r
1206         IN_ClearKey(LastScan);\r
1207         LastScan = sc_None;\r
1208 }\r
1209 \r
1210 ///////////////////////////////////////////////////////////////////////////\r
1211 //\r
1212 //      IN_Ack() - Clears user input & then calls IN_AckBack()\r
1213 //\r
1214 ///////////////////////////////////////////////////////////////////////////\r
1215 void\r
1216 IN_Ack(void)\r
1217 {\r
1218         word    i;\r
1219 \r
1220         IN_ClearKey(LastScan);\r
1221         LastScan = sc_None;\r
1222 \r
1223         if (MousePresent)\r
1224                 while (INL_GetMouseButtons())\r
1225                                         ;\r
1226         for (i = 0;i < MaxJoys;i++)\r
1227                 if (JoysPresent[i])\r
1228                         while (IN_GetJoyButtonsDB(i))\r
1229                                 ;\r
1230 \r
1231         IN_AckBack();\r
1232 }\r
1233 \r
1234 ///////////////////////////////////////////////////////////////////////////\r
1235 //\r
1236 //      IN_IsUserInput() - Returns true if a key has been pressed or a button\r
1237 //              is down\r
1238 //\r
1239 ///////////////////////////////////////////////////////////////////////////\r
1240 boolean\r
1241 IN_IsUserInput(void)\r
1242 {\r
1243         boolean result;\r
1244         word    i;\r
1245 \r
1246         result = LastScan;\r
1247 \r
1248         if (MousePresent)\r
1249                 if (INL_GetMouseButtons())\r
1250                         result = true;\r
1251 \r
1252         for (i = 0;i < MaxJoys;i++)\r
1253                 if (JoysPresent[i])\r
1254                         if (INL_GetJoyButtons(i))\r
1255                                 result = true;\r
1256 \r
1257         return(result);\r
1258 }\r
1259 \r
1260 ///////////////////////////////////////////////////////////////////////////\r
1261 //\r
1262 //      IN_UserInput() - Waits for the specified delay time (in ticks) or the\r
1263 //              user pressing a key or a mouse button. If the clear flag is set, it\r
1264 //              then either clears the key or waits for the user to let the mouse\r
1265 //              button up.\r
1266 //\r
1267 ///////////////////////////////////////////////////////////////////////////\r
1268 boolean\r
1269 IN_UserInput(longword delay,boolean clear)\r
1270 {\r
1271         longword        lasttime;\r
1272 \r
1273         lasttime = TimeCount;\r
1274         do\r
1275         {\r
1276                 if (IN_IsUserInput())\r
1277                 {\r
1278                         if (clear)\r
1279                                 IN_AckBack();\r
1280                         return(true);\r
1281                 }\r
1282         } while (TimeCount - lasttime < delay);\r
1283         return(false);\r
1284 }\r