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