[Back to KEYBOARD SWAG index] [Back to Main SWAG index] [Original]

    {
    >     I need help on reading the keyboard in a specific way, I need to
    > read it as a whole not a key at a time. I need to do this for
    > the games I make, I have to ba able to hold down one key to
    > perform a Function and then hold down another key and scan both
    > keys at the same time but to perform 2 different Functions. For
    > instance, if I hold down the left arrow key to make a Character
    > run I should be able to hold down the space bar to make him
    > fire a gun at the same time.
    >     I would Really appreciate any help anyone could give me With this.

    Grab this (TWOKEYS.PAS) and the next 2 messages (KEYINTR.PAS and POLL.PAS).
    }

    Program TwoKeys;

    Uses
      Crt, Poll ;  { polled keyboard handler }

    { ----- this Program will probably hang a debugger ----- }

    Var
      X, Y : Byte ;

    begin
      ClrScr ;
      X := 40 ;
      Y := 12 ;

      WriteLn( 'Hit keys A S  and  1 2 on the keypad' ) ;
      WriteLn( ' -- Esc to stop' ) ;

      While not KeyTable[ EscKey ] do
      begin
        GotoXY( X, Y ) ;
        Write( ' ' ) ;

        { poll the KeyTable }
        If KeyTable[ endKey ] and ( X > 1 ) then  Dec( X ) ;
        If KeyTable[ DownKey ] and ( X < 80 ) then  Inc( X ) ;
        If KeyTable[ aKey ] and ( Y > 4 ) then  Dec( Y ) ;
        If KeyTable[ sKey ] and ( Y < 24 ) then  Inc( Y ) ;

        GotoXY( X, Y ) ;
        Write( chr( 1 ) ) ;
        Delay( 10 ) ;
      end ;
    end.

    Unit KeyIntr ;  { support For INT 09 routines }

    Interface

    Procedure CLI ; Inline( $FA ) ; { disable interrupts }
    Procedure STI ; Inline( $FB ) ; { enable interrupts }

    { cannot be used outside an interrupt Procedure }
    Procedure JumpInterrupt( p : Pointer ) ;
    Inline(
      $5B/$58/                         { POP  BX, AX   AX:BX = p }
      $89/$EC/                         { MOV  SP, BP             }
      $87/$46/$10/                     { XCHG AX, [BP+10H]       }
      $87/$5E/$0E/                     { XCHG BX, [BP+0EH]       }
      $5D/$07/$1F/$5F/$5E/             { POP  BP, ES, DS, DI, SI }
      $5A/$59/                         { POP  DX, CX             }
      $FA/                             { CLI                     }
      $CB ) ;                          { RETF          jmp far p }

    Function Control_Pressed : Boolean ;

    Procedure EOI ;
    { end of interrupt to 8259 }

    Function ReadScanCode : Byte ;
    { read keyboard }

    Procedure ResetKeyboard ;
    { prepare For next key }

    Procedure StoreKey( Scan, Key : Byte );
    { put key in buffer For INT 16 }

    Implementation

    Uses
      Crt ;  { Sound, NoSound }

    Type
      Address = Record                  { used in Pointer manipulation }
        Offset : Word ;
        Segment : Word ;
      end ;
    Const
      BiosDataSegment = $40 ;

    Var
      KeyState       : Word Absolute BiosDataSegment:$0017 ;
      KeyBufferHead  : Word Absolute BiosDataSegment:$001A ;
      KeyBufferTail  : Word Absolute BiosDataSegment:$001C ;
      KeyBufferStart : Word Absolute BiosDataSegment:$0080 ;
      KeyBufferend   : Word Absolute BiosDataSegment:$0082 ;

    Function Control_Pressed : Boolean ;
    begin
      Control_Pressed := ( KeyState and  4 ) = 4 ;
    end;

    Procedure EOI ;
    { end of interrupt to 8259 interrupt controller }
    begin
      CLI ;
      Port[$20] := $20 ;
    end ;

    Function ReadScanCode : Byte ;
    begin
      ReadScanCode := Port[$60] ;
    end ;

    Procedure ResetKeyboard ;
    { prepare For next key }
    Var
      N : Byte ;
    begin
      N := Port[$61] ;
      Port[$61] := ( N or $80 ) ;
      Port[$61] := N ;
    end ;

    Procedure StoreKey( Scan, Key : Byte ) ;
    Var
    { put key in buffer that INT 16 reads }
      P : ^Word ;
      N : Word ;
    begin
      address(P).segment := BiosDataSegment ;
      N := KeyBufferTail ;
      address(P).offset := N ;
      Inc( N, 2 ) ;                      { advance Pointer two Bytes }
      If( N = KeyBufferend ) then        { end of the circular buffer }
         N := KeyBufferStart ;
      If( N = KeyBufferHead ) then       { buffer full }
      begin
        EOI ;               { EOI must be done before Exit            }
        Sound( 2200 ) ;     {    but before anything that takes a lot }
        Delay( 80 ) ;       {     of time and can be interrupted      }
        NoSound ;
      end
      Else
      begin          { high Byte is scan code, low is ASCII }
        P^ := Scan * $100 + Key ;       { store key in circular buffer }
        KeyBufferTail := N ;            { advance tail Pointer }
        EOI ;
      end ;
    end ;

    end.

    Unit POLL ;         { polled keyboard handler }
                        { does not support F11 or F12 keys } Interface

    Const
      EscKey = 1 ;    { key codes }
      aKey = 30 ;
      sKey = 31 ;
      endKey = 79 ;
      DownKey = 80 ;

    Var
      KeyTable : Array[ 1..127 ] of Boolean ;

    { KeyTable[ x ] is True when key x is pressed and stays True Until key
      x is released }

    Implementation

    Uses
      Dos, KeyIntr ;  { keyboard interrupt support }

    Var
      OldInt09 : Pointer ;
      ExitSave : Pointer ;

    Procedure RestoreInt09 ; Far;
    begin
      ExitProc := ExitSave ;
      SetIntVec( $09, OldInt09 ) ;
    end ;

    Procedure NewInt09 ; interrupt ; Far;
    Var
      ScanCode : Byte ;
      KeyCode : Byte ;
    begin
      STI ;
      ScanCode := ReadScanCode ;
      KeyCode := ScanCode and $7F ;        { strip make/break bit }
      KeyTable[ KeyCode ] := ( ScanCode and $80 ) = 0 ;
      ResetKeyboard ;
      EOI ;
    end ;

    Var
      N : Byte ;

    begin
      ExitSave := ExitProc ;
      ExitProc := addr( RestoreInt09 ) ;

      For N := 1 to 127 do   { no key pressed }
        KeyTable[ N ] := False ;

      GetIntVec( $09, OldInt09 ) ;
      SetIntVec( $09, addr( NewInt09 ) ) ;
    end.

[Back to KEYBOARD SWAG index] [Back to Main SWAG index] [Original]