home *** CD-ROM | disk | FTP | other *** search
/ 100 af Verdens Bedste Spil / 100Spil.iso / dos / wolf3d / source / wolfsrc.1 / ID_IN.C < prev    next >
C/C++ Source or Header  |  1993-02-04  |  23KB  |  991 lines

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