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

    {
    TSRUNIT v1.10
    Copyright (c) 1995 Nir Sofer, All rights reserved
    For using with Turbo Pascal 6.0/7.0

    You are allowed to copy, modify and share this program with others. But when
    you give TSRUNIT source code to other people (or upload it to a BBS) always
    give them the whole original files which is included in TSRUNIT package.

    For questions, comments or bugs report: Send me a message by one of the
    following ways:

    1. Internet: nir@netvision.net.il
    2. FidoNet:  Nir Sofer, at 2:403/138.0
    3. Ordinary mail:

      Nir Sofer
      5 Shderot Hashoshanim St.
      52583 Ramat Gan
      ISRAEL

    All mail will be answered. If you don't get a reply after a week, please
    send it again. Mail may be lost somethimes...

    READ TSRUNIT.DOC BEFORE USING THIS UNIT !

    New in this version:

    * Problems with MS-DOS 6.xx fixed by adding INT28 support.
    * Check if the TSR has already installed before.
    * The type of TsrProcedue variable is a procedure instead of pointer, so you
      don't have to add @ operator.
    * Consts for all keyboard flags and keyboard scan codes.
    * The TsrProcedure variable automatically assigned by InstallTsr procedure

    }

    unit tsrunit;
    {$s-,r-}

    interface
    type
      ProcedureType = procedure;
    const
      TSRUNITsignature = $DAAD;
      RightShift = 1;
      LeftShift  = 2;
      Ctrl       = 4;
      Alt        = 8;

      _esc  = 1;     _a    = 30;     _f7    = 65;
      _1    = 2;     _s    = 31;     _f8    = 66;
      _2    = 3;     _d    = 32;     _f9    = 67;
      _3    = 4;     _f    = 33;     _f10   = 68;
      _4    = 5;     _g    = 34;     _numlock = 69;
      _5    = 6;     _h    = 35;     _scrlock = 70;
      _6    = 7;     _j    = 36;     _home    = 71;
      _7    = 8;     _k    = 37;     _up = 72;
      _8    = 9;     _l    = 38;     _pgup     = 73;
      _9    = 10;    _lshift = 42;   _left     = 75;
      _0    = 11;    _z    = 44;     _right    = 77;
      _minus = 12;   _x    = 45;     _end      = 79;
      _plus  = 13;   _c    = 46;     _down     = 80;
      _bksp  = 14;   _v    = 47;     _pgdn     = 81;
      _tab   = 15;   _b    = 48;     _insert   = 82;
      _q      = 16;  _n    = 49;     _delete   = 83;
      _w      = 17;  _m    = 50;
      _e      = 18;  _rshift = 54;
      _r      = 19;  _alt    = 56;
      _t      = 20;  _space  = 57;
      _y      = 21;  _capslock = 58;
      _u      = 22;  _f1  = 59;
      _i      = 23;  _f2  = 60;
      _o      = 24;  _f3  = 61;
      _p      = 25;  _f4  = 62;
      _enter  = 28;  _f5  = 63;
      _ctrl   = 29;  _f6  = 64;

    var
      keysc         : byte;    {Keyboard scan code variable}
      keyflag       : byte;  {Keyboard flag variable}
      TsrProcedure  : ProcedureType;
      UserSignature : word;
      SignatureReturn : word;
    procedure SetUserSignature(Check,Return:word);
    procedure InstallTsr(tsrproc: ProcedureType);  {Make your program resident}
    procedure RemoveTsr;   {Remove your resident program}
    function CheckIntVectors:boolean; {Check if interrupt vectors are still
                             ours, if yes you are allowed to remove your TSR}
    function InstallationCheck:boolean;

    implementation
    uses dos;
    var
      old08,old09,old10,old1b,old24,old28,turbo24:pointer;
      indosflag,currint:pointer;
      active,request,idle:byte;
      savesp,savess:word;
      busyflag:byte;
    {$f+}
    {**********************************************************************}
    procedure int1b;assembler;
    asm
      iret   {Cancel CTRL-BREAK interrupt}
    end;
    {**********************************************************************}
    procedure int10;assembler;
    asm
                    jmp     @cont1
    @localds:
                    nop
                    nop       {Reserved for ds value}
    @localint10:
                    nop
                    nop
                    nop
                    nop       {Reserved for old int10 address}

    @cont1:
                    push    ds
                    mov     ds,word ptr [cs:@localds]
                    inc     busyflag
                    pop     ds
                    pushf
                    call    dword ptr [cs:@localint10]  {Call old interrupt}
                    push    ds
                    mov     ds,word ptr [cs:@localds]
                    cmp     ax,tsrunitsignature
                    je      @TsrUnitCall
    @cont100:
                    dec     busyflag
                    pop     ds
                    iret
    @TsrUnitCall:
                    cmp     bx,UserSignature
                    jne     @cont100
                    mov     cx,SignatureReturn
                    jmp     @cont100
    end;
    {**********************************************************************}
    procedure swap1;
    begin     {Swap vectors before running TsrProcedure}
      getintvec($1b,old1b);
      setintvec($1b,@int1b);
      getintvec($24,old24);
      setintvec($24,turbo24);
    end;
    {**********************************************************************}
    procedure swap2;
    begin     {Swap vectors after running TsrProcedure}
      setintvec($24,old24);
      setintvec($1b,old1b);
    end;
    {**********************************************************************}
    procedure activate;assembler;
    asm
                    jmp     @start
    @localss:
                    nop
                    nop   {Reserved for ss value}
    @localsp:
                    nop
                    nop   {Reserved for sp value}
    @start:
                    cmp     request,1      {Request by INT09 ?}
                    jne     @notrequested
                    cmp     idle,1
                    je      @cont500
                    les     di,indosflag
                    cmp     word ptr [es:di],0   {Check indos flag}
                    jne     @notrequested
    @cont500:
                    cmp     busyflag,0           {INT10 busy ?}
                    jne     @notrequested
                    mov     active,1             {The tsr is active now}
                    mov     request,0
                    mov     savess,ss
                    mov     savesp,sp
                    cli
                    mov     ss,word ptr [cs:@localss]
                    mov     sp,word ptr [cs:@localsp]  {Set ss and sp registers of TP}
                    sti
                    push    bx
                    push    cx
                    push    dx
                    push    si
                    push    bp
                    call    [swap1]  {Swap CTRL-BREAK and critical error handler vectors}
                    call    [TsrProcedure]       {call your procedure}
                    call    [swap2]  {Swap CTRL-BREAK and critical error handler vectors}
                    pop     bp
                    pop     si
                    pop     dx
                    pop     cx
                    pop     bx
                    cli
                    mov     ss,savess
                    mov     sp,savesp                  {Set old ss and sp registers}
                    sti
                    mov     active,0

    @notrequested:
    end;
    {**********************************************************************}
    procedure int28;assembler;
    asm
                    jmp     @cont1
    @localds:
                    nop
                    nop
    @localint28:
                    nop
                    nop
                    nop
                    nop
    @cont1:
                    push    es
                    push    ds
                    push    ax
                    push    di

                    push    ds
                    mov     ds,word ptr [cs:@localds]
                    inc     idle
                    pop     ds
                    pushf
                    call    dword ptr [cs:@localint28]  {Call old interrupt}
                    mov     ds,word ptr [cs:@localds]
                    call    activate
                    dec     idle
                    pop     di
                    pop     ax
                    pop     ds
                    pop     es
                    iret

    end;
    {**********************************************************************}
    procedure int08;assembler;
    asm
                    jmp     @cont1
    @localds:
                    nop
                    nop   {Reserved for ds value}

    @cont1:
                    push    es
                    push    ds
                    push    ax
                    push    di
                    mov     ds,word ptr [cs:@localds]
                    pushf
                    call    [old08]  {Call old interrupt}
                    call    activate
                    pop     di
                    pop     ax
                    pop     ds
                    pop     es
                    iret
    end;
    {**********************************************************************}
    procedure int09;assembler;
    asm
                    jmp     @cont1
    @localds:
                    nop
                    nop       {Reserved for ds value}

    @cont1:
                    push    es
                    push    ax
                    push    ds
                    mov     ds,word ptr [cs:@localds]
                    pushf
                    call    [old09]  {Call old INT09}
                    in      al,60h
                    cmp     al,keysc   {Check scan code key}
                    jne     @notourkey
                    xor     ax,ax
                    mov     es,ax
                    mov     al,[es:1047]
                    and     al,keyflag
                    cmp     al,keyflag   {Check alt\ctrl\shift keys}
                    jne     @notourkey
                    cmp     active,1   {Check if already active}
                    je      @notourkey
                    mov     request,1  {Request activity}

    @notourkey:
                    pop     ds
                    pop     ax
                    pop     es
                    iret
    end;
    {**********************************************************************}
    procedure InstallTsr(tsrproc: ProcedureType);
    begin
      TsrProcedure:=tsrproc;
      getintvec($28,old28);
      getintvec($8,old08);
      getintvec($9,old09);
      getintvec($10,old10);
      getintvec($24,turbo24);  {Get interrupt vectors}
      memw[seg(int10):ofs(int10)+4]:=memw[seg(old10):ofs(old10)];
      memw[seg(int10):ofs(int10)+6]:=memw[seg(old10):ofs(old10)+2];
      memw[seg(int28):ofs(int28)+4]:=memw[seg(old28):ofs(old28)];
      memw[seg(int28):ofs(int28)+6]:=memw[seg(old28):ofs(old28)+2];
    {Put interrupt $10 address in INT10 procedure}
      memw[seg(activate):ofs(activate)+4]:=sptr;
    {Save stack pointer for using when TSR is active}
      setintvec($8,@int08);
      setintvec($9,@int09);
      setintvec($10,@int10);
      setintvec($28,@int28);
    {Set new interrupt vectors}
      asm
                    mov     dx,prefixseg
                    mov     es,dx
                    mov     ax,[es:$2c]
                    cmp     ax,0
                    jz      @cont
                    mov     es,ax
                    mov     ah,$49
                    int     $21  {Release environment block}
    @cont:
      end;
      swapvectors; {Swap TP vectors with old vectors}
      keep(0);  {Terminate and stay resident}
    end;
    {**********************************************************************}
    function CheckIntVectors:boolean;
    {If CheckIntVectors=false, do not remove the tsr !!}
    begin
      CheckIntVectors:=false;
      getintvec($8,currint);
      if currint<>@int08 then exit;
      getintvec($9,currint);
      if currint<>@int09 then exit;
      getintvec($10,currint);
      if currint<>@int10 then exit;
      CheckIntVectors:=true;
    end;
    {**********************************************************************}
    procedure RemoveTsr;
    begin
      setintvec($8,old08);
      setintvec($9,old09);
      setintvec($10,old10);
      setintvec($1b,old1b);
      setintvec($28,old28);
    {set old interrupt vectors}
      asm
        mov    dx,prefixseg
        mov    es,dx
        mov    ah,$49
        int    $21    {Release memory block}
      end;
      asm
        mov    ax,$4c00
        int    $21     {Terminate program}
      end;
    end;
    {**********************************************************************}
    procedure SetUserSignature(Check,Return:word);assembler;
    asm
      mov   ax,check
      mov   UserSignature,ax {The value to send to INT 10h}
      mov   ax,return
      mov   SignatureReturn,ax  {The value that INT 10h will return}
    end;
    {**********************************************************************}
    function InstallationCheck:boolean;assembler;
    asm
      mov   ax,TSRUNITsignature
      mov   bx,UserSignature
      xor   cx,cx
      int   010h
      xor   al,al
      cmp   cx,SignatureReturn {Did you get the return value}
      jne   @tend
      mov   al,1               {If yes, your TSR already installed !}
    @tend:
    end;
    {**********************************************************************}
    begin
      setusersignature($eeaa,$aaff);
      busyflag:=0;
      idle:=0;
      memw[seg(int08):ofs(int08)+2]:=dseg;
      memw[seg(int09):ofs(int09)+2]:=dseg;
      memw[seg(int10):ofs(int10)+2]:=dseg;
      memw[seg(int28):ofs(int28)+2]:=dseg;
      memw[seg(activate):ofs(activate)+2]:=sseg;
    {Set local data segments}
      keysc:=_a;
      keyflag:=Alt + Ctrl; {Default key combination}
      active:=0;
      request:=0;
      asm
        mov   ah,$34
        int   $21
        mov   ax,es
        sub   bx,1
        sbb   ax,0
        mov   word ptr [indosflag],bx
        mov   word ptr [indosflag+2],ax  {Get indos flag address}
      end;
    end.

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