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

unit Scrnsavr;
{$F+}
(*************************************************************************)
(*                        Screen Saver                                   *)
(*                                                                       *)
(*  Written by Jay A. Key -- Oct 1993                                    *)
(*  Code may be modified and used freely.  Please mention my name        *)
(*  somewhere in your docs or in the program itself.                     *)
(*                                                                       *)
(*  Self contained unit to install a text-mode screen saver in Turbo     *)
(*  Pascal programs.  Simply include the following line in your code.    *)
(*    uses ScrnSavr;                                                     *)
(*                                                                       *)
(*  It will initialize itself automatically, and will remove itself      *)
(*  upon exit from your program, graceful exit or not.  Functions        *)
(*  SetTimeOut and SetDelay are included if you wish to modify the       *)
(*  default values.                                                      *)
(*                                                                       *)
(*  Warning: will not properly save and restore screens while running    *)
(*  under the Turbo Pascal IDE.  Runs great from DOS.                    *)
(*************************************************************************)

interface

uses
  Dos, Crt;

function  NumRows : byte;          {Returns number of rows in current screen}
function  ColorAdaptor : boolean;  {TRUE if color video card installed}
procedure SetTimeOut(T : integer); {Delay(seconds) before activation}
procedure SetDelay(T : integer);   {Interval between iterations}

implementation

type
  VideoArray = array [1..2000] of word;  {buffer to save video screen}

var
  Timer     : word;
  Waiting   : boolean;
  OldInt15,                  {Keyboard interrupt}
  OldInt1C,                  {Timer interrupt}
  OldInt23,                  {Cntl-C/Cntl-Break handler}
  ExitSave  : pointer;
  Position,
  Cursor    : integer; {save and restore cursor positions}
  VideoSave : VideoArray;
  VideoMem  : ^VideoArray;
  TimeOut,
  Delay     : integer;

procedure JumpToPriorIsr(p : pointer);
{Originally written by Brook Monroe, "An ISR Clock", pg. 64,
 PC Techniques Aug/Sep 1992}
inline($5b/$58/$87/$5e/$0e/$87/$46/$10/$89/$ec/$5d/$07/$1f/
       $5f/$5e/$5a/$59/$cb);

function ColorAdaptor : boolean; assembler;
asm
  int 11                   {BIOS call - get equipment list}
  and al,$0010             {mask off all but bit 4}
  xor al,$0010             {flip bit 4 - return val is in al}
end;

function NumRows : byte; assembler;  {returns number of displayable rows}
asm
  mov ax,$40
  mov es,ax
  mov ax,$84
  mov di,ax
  mov al,[es:di]           {byte at [$40:$84] is number of rows in display}
end;

procedure HideCursor; assembler;
asm
  mov ah,$03
  xor bh,bh
  int $10               {video interrupt}
  mov Position,dx       {save cursor position}
  mov Cursor,cx         {and type}
  mov ah,$01
  mov ch,$20
  int $10               {video interrupt - hide cursor}
end;

procedure RestoreCursor; assembler;
asm
  mov ah,$02
  xor bh,bh
  mov dx,Position       {get old position}
  int $10               {video interrupt - restore cursor position}
  mov cx,Cursor         {get old cursor type}
  mov ah,$01
  int $10               {video interrupt - restore cursor type}
end;

procedure RestoreScreen;
begin
  VideoMem^ := VideoSave;  {Copy saved image back onto video memory}
  RestoreCursor;
end;

procedure SaveScreen;
begin
  VideoSave := VideoMem^;  {Copy video memory to array}
  HideCursor;
end;

procedure DispMsg;  {simple stub-out for displaying YOUR message(s),
                     pictures, etc...use your imagination!!!}
begin
  ClrScr;
  GotoXY(random(50), random(23));
  writeln('This would normally be something witty!');
end;

procedure NewInt15(Flags,CS,IP,AX,BX,CX,DX,
                   SI,DI,DS,ES,BP:WORD); interrupt; {keyboard handler}
begin
  Timer := 0;                     {Reset timer}
  if Waiting then                 {Screen saver activated?}
  begin
    RestoreScreen;                {Restore saved screen image}
    Waiting := FALSE;             {De-activate screen saver}
    Flags   := (Flags and $FFFE); {Tell BIOS to ignore current keystroke}
  end
  else
    JumpToPriorISR(OldInt15);   {call original int 15}
end;

procedure NewInt1C; interrupt;    {timer interrupt}
begin
  Inc(Timer);                 {Increment timer}
  if Timer > TimeOut then     {No key hit for TimeOut seconds?}
  begin
    Waiting := TRUE;          {Activate screen saver}
    SaveScreen;               {Save image of video memory}
    DispMsg;                  {Display your own message}
    Timer := 0;               {Reset timer}
  end;
  if waiting then             {Is saver already active?}
  begin
    if Timer > Delay then     {Time for next message?}
    begin
      Timer := 0;             {Reset timer}
      DispMsg;                {Display next message}
    end;
  end;
  JumpToPriorISR(OldInt1C);   {Chain to old timer interrupt}
end;

procedure ResetIntVectors;    {Restores Intrrupt vectors to orig. values}
begin
  SetIntVec($15, OldInt15);
  SetIntVec($1C, OldInt1C);
  SetIntVec($23, OldInt23);
end;

procedure NewInt23; interrupt;{Called to handle cntl-c/brk}
begin
  ResetIntVectors;            {Restore old interrupt vectors}
  JumpToPriorISR(OldInt23);   {Chain to original int 23h}
end;

procedure MyExit; far;        {exit code for unit}
begin
  ResetIntVectors;            {Restore old interrupt vectors}
  ExitProc := ExitSave;       {Restore old exit code}
end;

procedure SetVideoAddress;    {Returns pointer to text video memory}
begin
  if ColorAdaptor then
    VideoMem := ptr($B000, $0000)
  else
    VideoMem := ptr($B800, $0000);
end;

procedure SetTimeOut(T : integer); {Set delay(seconds) before activation}
begin
  TimeOut := Round(T * 18.2);
end;

procedure SetDelay(T : integer);  {Set interval between iterations}
begin
  Delay := Round(T * 18.2);
end;

{Initialize unit}
begin
  SetVideoAddress;             {Set up address for video memory}
  Waiting  := FALSE;            {Screen saver initially OFF}
  Timer    := 0;                  {Reset timer}
  ExitSave := ExitProc;        {Save old exit routine}
  ExitProc := @MyExit;         {Install own exit routine}
  {Install user defined int vectors}
  GetIntVec($15, OldInt15);     {Keyboard handler}
  SetIntVec($15, @NewInt15);
  GetIntVec($1c, OldInt1C);     {Timer int}
  SetIntVec($1c, @NewInt1C);
  GetIntVec($23, OldInt23);     {Cntl-C/Brk handler}
  SetIntVec($23, @NewInt23);
  SetTimeOut(120);
  SetDelay(15);
end.


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