
UNIT MultiKey;

INTERFACE

VAR
  KeyStat : Array[1..127] OF ShortInt;
  { 0 (not physically down)
    1 (that sucker's down)
   -1 (it's being held, don't repeat) }

PROCEDURE EnableMultiKey;
PROCEDURE DisableMultiKey;

IMPLEMENTATION

USES Dos;

VAR
  OldKbdInt       : Pointer;
  OldCtrlBreakInt : Pointer;
  OldKeyExitProc  : Pointer;

PROCEDURE ClearKeyValues;
VAR
  keyclearcounter : Byte;
BEGIN
  FOR keyclearcounter := 1 TO 127 DO KeyStat[keyclearcounter] := 0;
END;

PROCEDURE NewKeyExitProc; Far;
BEGIN
  SetIntVec($09, OldKbdInt);
  SetIntVec($1B, OldCtrlBreakInt);
  ExitProc := OldKeyExitProc;
END;

PROCEDURE NewCtrlBreakInt; Interrupt;
{ it is important that the new Ctrl-Break handler does *nothing* }
BEGIN
END;

PROCEDURE NewKbdInt; Interrupt;
VAR
  p60 : Byte;
BEGIN
  p60 := Port[$60];
  Port[$61] := Port[$61] OR 128;         {/ keyboard    \}
  Port[$61] := Port[$61] AND (NOT 128);  {\ acknowledge /}
  IF (p60 > 0) THEN BEGIN
    IF (p60 > 127) THEN
      KeyStat[p60 AND 127] := 0
    ELSE
      IF (KeyStat[p60] = 0) THEN Inc(KeyStat[p60]);
  END;
  ASM CLI; END;                           {disable hardware ints}
  MemW[$0040:$001A] := MemW[$0040:$001C]; {clear buffer}
  ASM STI; END;                           {restore hardware ints}
  Port[$20] := $20;                       { send EOI to PIC }
END;

PROCEDURE EnableMultiKey;
BEGIN
  SetIntVec($09, Addr(NewKbdInt));
END;

PROCEDURE DisableMultiKey;
BEGIN
  SetIntVec($09, OldKbdInt);
END;


BEGIN  { unit initialization }
  GetIntVec($1B, OldCtrlBreakInt);
  SetIntVec($1B, Addr(NewCtrlBreakInt));
  ClearKeyValues;
  OldKeyExitProc := ExitProc;
  ExitProc := Addr(NewKeyExitProc);
  GetIntVec($09, OldKbdInt);
  EnableMultiKey;
END.

