{
Here is my unit for a screen saver - totally self contained with mouse support
as well (Moving the mouse will reset the screensaver time delay as well, and
placing the mouse in top right corner will blank the screen!)
}
unit blanker;

interface

const
blank_screen     : boolean=true;            {True=blank the screen.         }
blank_screen_now : boolean=false;           {True=blank screen immediately. }
count            : integer = 0;             {To keep track of our calls.    }
screen_cond      : boolean=false;           {True=screen is blanked.        }

var
 rows,columns:byte;

function mouseinbox(x1,y1,x2,y2,butt:word):boolean;

implementation

uses dos,bmouse;   { NOTE : bmouse is in MOUSE.SWG.  SWAG SUPPORT TEAM }

var
 OldInt9       : Procedure;
 OldInt1c      : pointer;
 ExitSave      : pointer;
 r             : Registers;
 loop          : byte;
 x             : array[1..30] of byte;
 y             : array[1..30] of byte;
 xystar        : array[1..30] of char;

{$F+}

{****************************************************************************}
{*                                                                          *}
{*                            MouseinBox Procedure                          *}
{*                                                                          *}
{****************************************************************************}
function mouseinbox(x1,y1,x2,y2,butt:word):boolean;
var
 a1, b1, c : word ;
begin
 ms_read(a1,b1,c);
 a1:=(a1 div 8) + 1;
 b1:=(b1 div 8) + 1;
 if ((a1>=x1) and (a1<=x2) and (b1>=y1) and (b1<=y2) and (c=butt)) then
    mouseinbox:=true
 else
    mouseinbox:=false;
end;



{****************************************************************************}
{*                                                                          *}
{*                       Draw the stars on video page 1                     *}
{*                                                                          *}
{****************************************************************************}
Procedure stars;
begin
 for loop:=1 to 30 do
 begin
    if ((random(80)<10) and (ord(xystar[loop])=15)) then
    begin
       xystar[loop]:=' ';
    end;
    if ((random(80)<5) and (xystar[loop]='ù')) then
    begin
       xystar[loop]:=chr(15);
    end;
    if ((random(80)<5) and (xystar[loop]='ú')) then
    begin
       xystar[loop]:='ù';
    end;
    if ((random(80)<20) and (xystar[loop]=' ') and (x[loop]=0) and
(y[loop]=0)) then
    begin
       x[loop]:=random(rows);
       y[loop]:=random(columns);
       xystar[loop]:='ú';
    end;
 end;
 for loop:=1 to 30 do
 begin
    r.ah:=$02;
    r.bh:=$01;
    r.dh:=x[loop];
    r.dl:=y[loop];
    intr($10,r);

    r.al:=ord(xystar[loop]);
    r.ah:=$09;
    r.bl:=7;
    r.bh:=$01;
    r.cx:=01;
    intr($10,r);
    if xystar[loop]=' ' then
    begin
       x[loop]:=0;
       y[loop]:=0;
    end;
 end;
end;

{****************************************************************************}
{*                                                                          *}
{*                       Initialize the stars Procedure                     *}
{*                                                                          *}
{****************************************************************************}
Procedure starsinit;
begin
 for loop:=1 to 20 do xystar[loop]:=' ';
 stars;
end;

{****************************************************************************}
{*                                                                          *}
{*                        Check timer & blank the screen                    *}
{*                                                                          *}
{****************************************************************************}
procedure blank; interrupt;
                                            {This will be called every clock}
                                            {tick by hardware interrupt $08.}
begin
 if screen_cond then stars;
 asm cli end;
 if blank_screen then inc(count);
 if ((blank_screen_now) and (blank_screen)) then count:=180;
 if (count >= 180) then                    {Ticks till Screen is blanked.  }
                                            {Time is 18.2 TICKS/SEC, or 1092}
                                            {Per minute, so                 }
                                            {2 Mins = 2184,                 }
                                            {3 Mins = 3276,                 }
                                            {4 Mins = 4368,                 }
                                            {5 Mins = 5460,                 }
                                            {6 Mins = 6552,                 }
                                            {7 Mins = 7644,                 }
                                            {8 Mins = 8736,                 }
                                            {9 Mins = 9828,                 }
                                            {10 Mins = 10920,               }
                                            {20 Mins = 21840,               }
                                            {30 Mins = 32760, which is      }
                                            {maximum limit of Integer       }
                                            {variable used.                 }
 begin
    count       := 0;                       {Equality check and assignment  }
                                            {faster than mod.               }
    asm
    mov AX,$02                              {Turn mouse off.                }
    Int $33

    mov ah,$03                              {Turn the cursor off            }
    mov bh,$00
    int $10
    or ch,$20
    mov ah,$01
    int $10

    mov ah,$05                              {Swaps to video page 1          }
    mov al,$01
    int $10
    end;
    if not screen_cond then starsinit;
    screen_cond:=true;
 end
 else
 begin
    asm
    mov ax,$0006                            {Check for Mouse Button press.  }
    int $33
    cmp bx,0
    je @Test2
    mov count,0
 @test2:
    mov ax,$000b                            {Check for mouse movement.      }
    int $33
    cmp cx,0
    jz @test3
    mov count,0
 @test3:
    cmp dx,0
    jz @test4
    mov count,0
 @test4:
    end;
    if ((count=0) and (screen_cond)) then
    begin
       asm
       mov ah,$05                           {Restore the first video page   }
       mov al,$00;
       int $10

       mov ah,$03                           {Turn the cursor on             }
       mov bh,$00
       int $10
       and ch,$DF
       mov ah,$01
       int $10

       mov AX,$01                           {Turn mouse on                  }
       Int $33
       end;
       screen_cond:=false;
    end;
 end;
 asm
 sti
 pushf                                      {Push flags to set up for IRET. }
 call OldInt1c;                             {Call old ISR entry point.      }
 end;
end;

{****************************************************************************}
{*                                                                          *}
{*                         New Interrupt 9 Procedure                        *}
{*                                                                          *}
{****************************************************************************}
Procedure NewInt9; Interrupt;
Begin
 blank_screen_now:=false;
 if (mouseinbox(80,1,80,1,0))=true then
 asm
 mov ax,0004
 mov cx,630
 mov dx,1
 int $33
 end;
 count:=-1;                                 {Set to -1 because the blank    }
                                            {procedure will increment before}
                                            {it tests, so to get it to 0, it}
                                            {must be set to -1.             }
 asm
 pushf                                      {Push flags to set up for IRET. }
 call OldInt9;                              {Call old ISR entry point.      }
 end;
End;


{****************************************************************************}
{*                                                                          *}
{*                  Reset everything at the end of the unit                 *}
{*                                                                          *}
{****************************************************************************}
procedure ClockExitProc;
                                            {This procedure is VERY         }
                                            {important as you have hooked an}
                                            {interrupt and therefore if this}
                                            {is omitted when the unit is    }
                                            {terminated your system will    }
                                            {crash in an unpredictable and  }
                                            {possibly damaging way.         }
begin
 ExitProc := ExitSave;
 SetIntVec($1c,OldInt1c);                   {This "unhooks" the timer vector}
 SetIntVec($09, Addr(OldInt9));             {This restores normal keyboard  }
                                            {routines.                      }

end;
{$F-}


{****************************************************************************}
{*                                                                          *}
{*                        Unit Initializing procedure                       *}
{*                                                                          *}
{****************************************************************************}
procedure Initialise;
var
 mode : byte absolute $40:$49;
begin
 asm
 mov ah,$05                                 {Swap to video page 1, clear the}
 mov al,$01                                 {screen by scrolling it, then   }
 int $10                                    {return to video page 0.        }

 mov ah,$06
 mov al,$00
 mov bx,$00
 int $10

 mov ah,$05                                 {Restore the first video page   }
 mov al,$00
 int $10
 end;
 GetIntVec($09, Addr(OldInt9));             {These two lines activate the   }
 SetIntVec($09, Addr(NewInt9));             {new keyboard routine handler.  }
 GetIntVec($1c,OldInt1c);                   {Get old timer vector & save it.}
 ExitSave := ExitProc;                      {Save old exit procedure.       }
 ExitProc := @ClockExitProc;                {Setup a new exit procedure.    }
 SetIntVec($1c,@blank);                     {Hook the timer vector to the   }
                                            {new procedure.                 }
end;


{****************************************************************************}
{*                                                                          *}
{*                           Main program starts here                       *}
{*                                                                          *}
{****************************************************************************}
begin
 Initialise;
 Rows:=(mem[$0040:$0084]) + 1;              {Find the size from memory      }
 Columns:=mem[$0040:$004a];
 if rows   =0 then rows   :=25;             {If it could not find anything  }
 if columns=0 then columns:=80;             {assume 25*80 mode.             }
end.

