返回
{***************************************************************}
{***               FVision Unit Version1.0                   ***}
{***                    蓝蚂蚁工作室                         ***}
{***************************************************************}
{***                内存驻留程序支持单元                     ***}
{***************************************************************}
{$V-,I-,R-,F+}
UNIT TSRU;
INTERFACE
USES
    DOS,CRT;
CONST
    OLDSTACKSS:WORD=0;                 {SS保存被中断程序内容}
    OLDSTACKSP:WORD=0;                 {SP保存被中断程序内容}
    OURSTACKSEG:WORD=0;                {SS保存本程序内容}
    OURSTACKSP:WORD=0;                 {SP保存本程序内容}

{STACKSW指示中断是否从本TSR发出}
{-1    :在本TSR外,转换栈}
{0     :在本TSR内,不转换栈}
    STACKSW:INTEGER=-1;
    ENDDOS:WORD=0;

CONST
    SCANCODE:BYTE=0;           {用于定义热键}
    KEYMASK :BYTE=0;           {是扫描码}

VAR
   {保存原中断指针}
   TIMERVEC,
   KBDVEC,
   OLD28VEC,
   OLDCRITVEC : POINTER;
   DOSSEG : WORD;
   DOSBUSY : WORD;
   OLDDTASEG,
   OLDDTAOFS,
   OURDTASEG,
   OURDTAOFS : WORD;
   SAVEBREAK : BYTE;
   POPRTN : POINTER;
   TSR_BYTE,
   TSR_VEC : BYTE;
   TSR_PSP : WORD;
   INT_PSP : WORD;
   PSPARRAY : ARRAY[1..2] OF WORD;
   PSP_COUNTER : BYTE;
   OLD_INTTABLE,NEW_INTTABLE:ARRAY[0..1023] OF BYTE;
CONST
   TIMERINT=$1C;
   KBDINT=$09;
   INT28INT=$28;
   CRITINT=$24;
   POPFLAG:BOOLEAN=FALSE;
   RUNNING:BOOLEAN=FALSE;
   TSROFF :BOOLEAN=FALSE;
   unrelease:boolean=false;

PROCEDURE  CALLOLDINT(SUB:POINTER);
PROCEDURE  POPSETUP(PR:POINTER;SC,KM:BYTE);
PROCEDURE  BEGINPOP;
PROCEDURE  ENDPOP;
PROCEDURE  INSTALL_INT;
FUNCTION   TSREXIT:BOOLEAN;
FUNCTION   DUPCHECK(VAR S:STRING; RTN:POINTER):BYTE;
PROCEDURE  BEGININT;
 INLINE($FF/$06/STACKSW/
        $75/$10/
        $8C/$16/OLDSTACKSS/
        $89/$26/OLDSTACKSP/
        $8E/$16/OURSTACKSEG/
        $8B/$26/OURSTACKSP);
PROCEDURE  ENDINT;
 INLINE($FF/$0E/STACKSW/
        $7D/$08/
        $8E/$16/OLDSTACKSS/
        $8B/$26/OLDSTACKSP);
PROCEDURE  CLI;    INLINE($FA);
PROCEDURE  STI;    INLINE($FB);
PROCEDURE  CALLPOP(SUB:POINTER);


IMPLEMENTATION
PROCEDURE  NEWCRIT(FLAGS,CS,IP,AX,BX,CX,DX,SI,DI,DS,ES,BP:WORD);INTERRUPT;
BEGIN
   AX:=0;
END;

PROCEDURE  SAVESTACK;
BEGIN
   OURSTACKSEG:=SSEG;
   INLINE($89/$26/OURSTACKSP);
END;

PROCEDURE  CALLPOP(SUB:POINTER);
BEGIN
   INLINE($FF/$5E/$06);
END;

PROCEDURE  CALLOLDINT(SUB:POINTER);
BEGIN
   INLINE($9C/
          $FF/$5E/$06);
END;

PROCEDURE  NEW28(FLAGS,CS,IP,AX,BX,CX,DX,SI,DI,DS,ES,BP:WORD);INTERRUPT;
BEGIN
   CLI;
   BEGININT;
   STI;
   CALLOLDINT(OLD28VEC);
   IF ((POPFLAG) AND (MEM[DOSSEG:DOSBUSY]<>0)) THEN
      BEGIN
         PORT[$20]:=$20;
         POPFLAG:=FALSE;
         unrelease:=false;
         beginpop;
         CALLPOP(POPRTN);
         endpop;
      END;
      CLI;
      ENDINT;
      STI;
END;

PROCEDURE  CLOCK(FLAGS,CS,IP,AX,BX,CX,DX,SI,DI,DS,ES,BP:WORD);INTERRUPT;
BEGIN
   CLI;
   BEGININT;
   STI;
   CALLOLDINT(TIMERVEC);
   IF ((POPFLAG) AND (MEM[DOSSEG:DOSBUSY]=0)) THEN
      BEGIN
         PORT[$20]:=$20;
         POPFLAG:=FALSE;
         unrelease:=true;
         beginpop;
         CALLPOP(POPRTN);
         endpop;
      END;
      CLI;
      ENDINT;
      STI;
END;

PROCEDURE  KEYBOARD(FLAGS,CS,IP,AX,BX,CX,DX,SI,DI,DS,ES,BP:WORD);INTERRUPT;
LABEL
     TSRDOWN,KEYEXIT;
BEGIN
   CLI;
   BEGININT;
   STI;
   IF TSROFF THEN  GOTO TSRDOWN;
   IF (PORT[$60]=SCANCODE) THEN
      BEGIN
         IF (MEM[$0000:$0417] AND KEYMASK)=KEYMASK THEN
            BEGIN
               TSR_BYTE:=PORT[$61];
               PORT[$61]:=TSR_BYTE OR $80;
               PORT[$61]:=TSR_BYTE;
               CLI;
               PORT[$20]:=$20;
               STI;
               IF NOT RUNNING THEN POPFLAG:=TRUE;
               GOTO KEYEXIT;
            END;
      END;
   TSRDOWN:
   CALLOLDINT(KBDVEC);
   KEYEXIT:
   CLI;
   ENDINT;
   STI;
END;

PROCEDURE  INSTALL_INT;
BEGIN
   SETINTVEC(TIMERINT,@CLOCK);
   SETINTVEC(KBDINT,@KEYBOARD);
   SETINTVEC(INT28INT,@NEW28);
   IF STACKSW=-1 THEN SETINTVEC($1B,SAVEINT1B);
END;

PROCEDURE  REL_MEM;
VAR R:REGISTERS;
BEGIN
   WHILE (MEM[ENDDOS:0]=$4D) DO
     BEGIN
       IF (MEMW[ENDDOS:1]=TSR_PSP) THEN
          BEGIN
            R.AH:=$49;
            R.ES:=ENDDOS+1;
            MSDOS(R);
          END;
       ENDDOS:=ENDDOS+MEMW[ENDDOS:3]+1;
     END;
END;

FUNCTION   TSREXIT:BOOLEAN;
VAR P,Q,R,S,T:POINTER;
BEGIN
   GETINTVEC(TIMERINT,P);
   GETINTVEC(KBDINT,Q);
   GETINTVEC(INT28INT,R);
   IF (P=@CLOCK) AND (Q=@KEYBOARD) AND (R=@NEW28) THEN
      BEGIN
        SETINTVEC(TIMERINT,TIMERVEC);
        SETINTVEC(KBDINT,KBDVEC);
        SETINTVEC(INT28INT,OLD28VEC);
        T:=NIL;
        SETINTVEC(TSR_VEC,T);
        REL_MEM;
        TSREXIT:=TRUE;
      END  ELSE
      BEGIN
        TSREXIT:=FALSE;
        TSROFF :=TRUE;
      END;
END;

PROCEDURE  POPSETUP(PR:POINTER;SC,KM:BYTE);
VAR
   R:REGISTERS;
   ARD:WORD;
   I:INTEGER;
BEGIN
  SCANCODE:=SC;
  KEYMASK:=KM;
  POPRTN:=PR;
  CHECKBREAK:=FALSE;
  OURSTACKSEG:=SSEG;
  INLINE($89/$26/OURSTACKSP);
  R.AH:=$34;
  MSDOS(R);
  DOSSEG:=R.ES;
  DOSBUSY:=R.BX;
   R.AH:=$2F;
   MSDOS(R);
   OURDTASEG:=R.ES;
   OURDTAOFS:=R.BX;
   R.AH:=$51;
   MSDOS(R);
   TSR_PSP:=R.BX;
   R.AH:=$52;
   MSDOS(R);
   ENDDOS:=MEMW[R.ES:R.BX-2];
  PSP_COUNTER:=0;
  ARD:=0;
  WHILE (PSP_COUNTER<2) AND ((DOSSEG SHL 4 + ARD)<(ENDDOS SHL 4)) DO
    BEGIN
      IF MEMW[DOSSEG:ARD]=TSR_PSP+1 THEN
      BEGIN
         PSP_COUNTER:=PSP_COUNTER+1;
         PSPARRAY[PSP_COUNTER]:=ARD;
         R.AH:=$50;
         R.BX:=TSR_PSP;
         MSDOS(R);
      END;
      ARD:=ARD+1;
    END;
  GETINTVEC(TIMERINT,TIMERVEC);
  GETINTVEC(KBDINT,KBDVEC);
  GETINTVEC(INT28INT,OLD28VEC);
  MOVE(PTR(0,0)^,OLD_INTTABLE,1024);
END;

PROCEDURE  RESIDENTPSP;
VAR I:BYTE;
    R:REGISTERS;
BEGIN
  R.AH:=$51;
  MSDOS(R);
  INT_PSP:=R.BX;
  FOR I:=1 TO PSP_COUNTER DO
      MEMW[DOSSEG:PSPARRAY[I]]:=TSR_PSP;
END;

PROCEDURE  RESTOREPSP;
VAR I:BYTE;
BEGIN
  FOR I:=1 TO PSP_COUNTER DO
      MEMW[DOSSEG:PSPARRAY[I]]:=INT_PSP;
END;

PROCEDURE  BEGINPOP;
VAR R:REGISTERS;
BEGIN
   RUNNING:=TRUE;
   MOVE(PTR(0,0)^,NEW_INTTABLE,1024);
   MOVE(OLD_INTTABLE,PTR(0,0)^,1024);
   R.AH:=$2F;
   MSDOS(R);
   OLDDTASEG:=R.ES;
   OLDDTAOFS:=R.BX;
   R.AH:=$1A;
   R.DS:=OURDTASEG;
   R.DX:=OURDTAOFS;
   MSDOS(R);
   R.AX:=$3300;
   MSDOS(R);
   SAVEBREAK:=R.DL;
   R.AX:=$3301;
   R.DL:=0;
   MSDOS(R);
   GETINTVEC(CRITINT,OLDCRITVEC);
   SETINTVEC(CRITINT,@NEWCRIT);
   RESIDENTPSP;
END;

PROCEDURE  ENDPOP;
VAR R:REGISTERS;
BEGIN
   RUNNING:=FALSE;
   R.AH:=$1A;
   R.DS:=OLDDTASEG;
   R.DX:=OLDDTAOFS;
   MSDOS(R);
   R.AX:=$3301;
   R.DL:=SAVEBREAK;
   MSDOS(R);
   SETINTVEC(CRITINT,OLDCRITVEC);
   MOVE(NEW_INTTABLE,PTR(0,0)^,1024);
   RESTOREPSP;
END;

FUNCTION   DUPCHECK(VAR S:STRING; RTN:POINTER):BYTE;
VAR
   VEC:WORD;
   DIF:WORD;
   PTR:POINTER;
   PTRARR:ARRAY[1..2] OF INTEGER ABSOLUTE PTR;
   PTNARR:ARRAY[1..2] OF INTEGER ABSOLUTE RTN;
   I:BYTE;
   ST:STRING;
BEGIN
   DIF:=DSEG-PTNARR[2];
   FOR VEC:=$60 TO $67 DO
   BEGIN
      GETINTVEC(VEC,PTR);
      IF PTR=NIL THEN
         BEGIN
           SETINTVEC(VEC,RTN);
           TSR_VEC:=VEC;
           DUPCHECK:=0;
           EXIT;
         END;
      MOVE(MEM[PTRARR[2]+DIF:OFS(S)],ST,LENGTH(S)+1);
      IF ST=S THEN
         BEGIN
           DUPCHECK:=VEC;
           EXIT;
         END;
   END;
END;
END.