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

    UNIT KeyIntr;  { support for INT 09 16 routines } { Turbo Pascal 5.5+ }

    INTERFACE

    Type
      InterruptProcedure = Procedure;

    Const
      BiosDataSegment = $40;

    Procedure DisableInterrupts; Inline($FA);   { CLI }
    Procedure EnableInterrupts;  Inline($FB);   { STI }
    Procedure CallInterrupt(P : Pointer);

    Function AltPressed : Boolean;
    Function ControlPressed : Boolean;
    Function ShiftPressed : Boolean;

    Procedure EOI;                      { end of interrupt to 8259 }
    Function  ReadScanCode : Byte;       { read keyboard }
    Procedure ResetKeyboard;            { prepare for next key }
                                         { put key in buffer for INT 16 }
    Function StoreKey(Scan, Key : Byte) : Boolean;

    IMPLEMENTATION

    Type
      TwoBytesPtr = ^TwoBytes;
      TwoBytes = Record  { one key in the keyboard buffer }
        KeyCode,
        ScanCode : Byte;
      End;

    Var
      KeyState       : Word Absolute BiosDataSegment : $17;
      KeyBufferHead  : Word Absolute BiosDataSegment : $1A;
      KeyBufferTail  : Word Absolute BiosDataSegment : $1C;
      KeyBufferStart : Word Absolute BiosDataSegment : $80;
      KeyBufferEnd   : Word Absolute BiosDataSegment : $82;

    Procedure CallInterrupt(P : Pointer);
    Begin
      Inline($9C);           { PUSHF }
      InterruptProcedure(P);
    End;

    Function AltPressed : Boolean;
    Begin
      AltPressed := (KeyState and 8) <> 0;
    End;

    Function ControlPressed : Boolean;
    Begin
      ControlPressed := (KeyState and 4) <> 0;
    End;

    Function ShiftPressed : Boolean;
    Begin
      ShiftPressed := (KeyState and 3) <> 0;
    End;

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

    Function ReadScanCode : Byte;
    Var
      N : Byte;
    Begin
      N := Port[$60];     { $FF means keyboard overrun }
      ReadScanCode := N;
    End;

    Procedure ResetKeyboard;      { prepare for next key }
    Var
      N : Byte;
    Begin
      N := Port[$61];
      Port[$61] := (N or $80);
      Port[$61] := N;
    End;

    Function StoreKey(Scan, Key : Byte) : Boolean;
    Var                { put key in buffer that INT 16 reads }
      P : TwoBytesPtr;
      N : Word;
    Begin
      DisableInterrupts;

      N := KeyBufferTail;
      P := Ptr(BiosDataSegment, N);

      Inc(N, 2);
      If(N = KeyBufferEnd) then        { end of the circular buffer }
        N := KeyBufferStart;
      If(N = KeyBufferHead) then       { buffer full }
      Begin
        EnableInterrupts;
        StoreKey := False;
      End
      Else
      Begin
        P^.KeyCode := Key;
        P^.ScanCode := Scan;             { store key in circular buffer }
        KeyBufferTail := N;              { advance tail pointer }
        EnableInterrupts;
        StoreKey := True;
      End;
    End;

    END.

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