home *** CD-ROM | disk | FTP | other *** search
- {
- Program: QT (Quick Time)
-
- Version: 1.00
- Date: January 10, 1988
-
- Language: Borland Turbo Pascal v4.0
- Environment: IBM/PC compatible, MS-DOS v2.0 or higher
-
- A memory-resident program to display the current time. The program was
- tested on an 8Mhz Kaypro PC, with a Hercules Monochrome Graphics Adapter.
-
- Copyright (c) 1988 by Scott Robert Ladd.
-
- Permission is granted to use this program, or portions thereof, for
- both commercial and non-commercial purposes. All other rights are
- reserved to the original author.
- }
- {$M 1024,0,0}
- {$V-,R-,S-,B-}
-
- program Receipt; uses Crt, Dos;
-
- type
- Screen = array [0..24,0..79] of word;
-
- var
- { storage for storing the old addresses of captured interrupts}
- Int09_Vec : pointer;
- Int11_Vec : pointer;
- Int28_Vec : pointer;
-
- { the codes used in CX to determine if this TSR is already installed}
- InstCode1 : word;
- InstCode2 : word;
-
- { in undocumented InDos flag, which indicates when DOS can be interrupted}
- InDosFlag : ^word;
-
- { the word in low memory where the Shift-Alt-Ctrl status is stored }
- Kbd_Status : word absolute $0000:$0417;
-
- { the equipment list word in low memory }
- EquipList : word absolute $0000:$0410;
-
- { set to true when TSR is already activated }
- Busy : boolean;
-
- { register pack used when calling system interrupts with Intr }
- Regs : Registers;
-
- { the physical and stored original video screens }
- Video_Display : ^Screen;
- Old_Display : Screen;
-
- { original video mode }
- Old_Mode : byte;
-
- { original cursor position }
- Old_X, Old_Y : byte; { from WhereX and WhereY }
- VCoord, HCoord : byte; { from the 6845 }
-
- { old cursor type to be restored when cursor is turned back on }
- OldCursor : word;
-
- { variables to save both the Turbo stack and the original stack }
- TurboSS, TurboSP : word;
- OrigSS : word;
-
- const
- { the keystroke which activates this TSR -- ALT & Left-SHIFT}
- Activate : word = $000A;
-
- { set of valid text modes }
- TextModes : set of byte = [0,1,2,3,7];
-
- {
- CallInt : Calls an interrupt function based on a a pointer containing the
- function address.
- }
- procedure CallInt(p : pointer);
- begin
- inline($9C/ { PUSHF }
- $FF/$5E/$04); { CALL FAR [BP+4] }
- end;
-
- {
- GetMode : Returns the current video display mode.
- }
- function GetMode : byte;
- begin
- Regs.AX := $0F00;
- Intr($10,Regs);
- GetMode := Regs.AL;
- end;
-
- {
- SetMode : Sets the video display mode.
- }
- procedure SetMode (Mode : byte);
- begin
- Regs.AH := 0;
- Regs.AL := Mode;
- Intr($10,Regs);
- end;
-
- {
- SaveScr : Loads the current display into an internal buffer for restoration
- when the TSR exits.
- }
- procedure SaveScr;
- begin
- { save the current video mode }
- Old_Mode := GetMode;
- { Save the cursor (BIOS) }
- Old_X := WhereX;
- Old_Y := WhereY;
- { Save the cursor (6845) }
- Port[$03B4] := 14;
- HCoord := Port[$03B5];
- Port[$03B4] := 15;
- VCoord := Port[$03B5];
- { Make a copy of the original display buffer }
- Old_Display := Video_Display^;
- end; {SaveScr}
-
- {
- RestScr : Restores the screen previously saved by SaveScr.
- }
- procedure RestScr;
- begin
- { restore the video mode }
- SetMode(Old_Mode);
- { Yes, I know this causes "snow" on CGA systems -- but only for a very
- split second when restoring the old display. }
- Video_Display^ := Old_Display;
- { Restore the cursor for the BIOS }
- GotoXY(Old_X,Old_Y);
- { Restore the cursor for the 6845 }
- Port[$03B4] := 14;
- Port[$03B5] := HCoord;
- Port[$03B4] := 15;
- Port[$03B5] := VCoord;
- end; {RestScr}
-
- {
- CursorOn : Restores the cursor to the definition stored in OldCursor.
- }
- procedure CursorOn;
- begin
- Regs.AH := 1;
- Regs.CX := OldCursor;
- Intr($10,Regs);
- end;
-
- {
- CursorOff : Stores the current cursor definition in OldCursor, and then
- makes the cursor invisible.
- }
- procedure CursorOff;
- begin
- Regs.AH := 3;
- Intr($10,Regs);
- OldCursor := Regs.CX;
-
- Regs.AH := 1;
- Regs.CX := $2000; { bit 5 of CH set on, blanks cursor! }
- Intr($10,Regs);
- end;
-
- {
- Process: This is the main program, where the TSR actually does its work.
- For this example, it displays the time continuously in the
- upper left hand corner of the screen, until a key is pressed.
- }
- procedure Process;
- var
- Hr, Min, Sec, Mil : word;
- Ch : char;
- begin
- CursorOff;
- repeat
- GetTime(Hr,Min,Sec,Mil);
- GotoXY(1,1);
- Writeln('┌──────────┐');
- Write('│ ',Hr:2,':');
- if Min > 9 then
- Write(Min:2)
- else
- Write('0',Min:1);
- if Sec > 9 then
- Write(':',Sec:2)
- else
- Write(':0',Sec:1);
- Writeln(' │');
- Writeln('└──────────┘');
- until KeyPressed;
- Ch := ReadKey;
- CursorOn;
- end; {Process}
-
- {
- DeInstall : sets the interrupt vectors back to their original settings, and
- removes the TSR from memory.
- }
- procedure DeInstall;
- var
- EnvSegPtr : ^word;
- begin
- { save the interrupted program's stack segment and pointer }
- { restore QT's stack segment and pointer }
- inline (
- $8C/$16/OrigSS/ { MOV OrigSS, SS }
- $8E/$16/TurboSS/ { MOV SS, TurboSS }
- $8B/$26/TurboSP { MOV SP, TurboSP }
- );
-
- { Restore the original cursor and screen }
- CursorOn;
- RestScr;
-
- SetIntVec($28,Int28_Vec); { restore INT 28 (DOS idle)}
- SetIntVec($11,Int11_Vec); { restore INT 11 (BIOS equipment)}
- SetIntVec($09,Int09_Vec); { restore INT 9 (BIOS keyboard)}
-
- { make a pointer to the Environment Segment stored in the PSP }
- EnvSegPtr := Ptr(PrefixSeg,44);
-
- { deallocate the local environment block }
- Regs.AX := $4900;
- Regs.ES := EnvSegPtr^;
- Intr($21,Regs);
-
- { deallocate this program's memory block }
- Regs.AX := $4900;
- Regs.ES := PrefixSeg;
- Intr($21,Regs);
-
- { restore the stack of the interrupted program }
- inline (
- $8E/$16/OrigSS { MOV SS, OrigSS }
- );
-
- { exit to DOS }
- Halt(0);
- end;
-
- {
- Int28 : This is the DOS idle interrupt, called when DOS isn't doing anything.
- We capture it, and every time it's invoked, we check to see if the
- "hot key" has been pressed. This is an undocumented DOS interrupt.
- }
- procedure Int28;
- interrupt;
- begin
- inline($FA); {CLI -- stop interrupts for a while}
- CallInt(Int28_Vec); { call the original interrupt function first }
- { if the TSR is active, and the hot key is pressed, deinstall TSR }
- if (Busy) and (Kbd_Status = Activate) then
- begin
- DeInstall;
- end;
- { if the TSR isn't active, and the hot key is pressed, and ...}
- if (not Busy) and (Kbd_Status = Activate) {and (GetMode in TextModes)} then
- begin
- Busy := true; { the TSR is now marked as activated }
- { save the interrupted program's stack segment and pointer }
- { restore QT's stack segment and pointer }
- inline (
- $8C/$16/OrigSS/ { MOV OrigSS, SS }
- $8E/$16/TurboSS/ { MOV SS, TurboSS }
- $8B/$26/TurboSP { MOV SP, TurboSP }
- );
- SaveScr; { save the current display }
- Process; { The actual TSR }
- RestScr; { restore the display }
- { restore the stack of the interrupted program }
- inline (
- $8E/$16/OrigSS { MOV SS, OrigSS }
- );
- Busy := false; { the TSR is no longer active }
- end;
- inline($FB); {STI -- restart interrupts}
- end; {Int28}
-
- {
- Int11 : Is used normally by the system to retrieve the equipment list word.
- We use it to determine if this TSR is already loaded; if CX is equal
- to InstCode1, we set it to InstCode2, which is then returned. Since
- CX is not used by Int11, and we load the returned AX register with
- the equipment list word from low memory, the operation should be
- transparent to other programs.
- }
- procedure Int11(Flags,CS,IP,AX,BX,CX,DX,SI,DI,DS,ES,BP : word);
- interrupt;
- begin
- { if the CX register contains the special installation check code,
- return the OK in CX }
- CallInt(Int11_Vec);
- if (CX = InstCode1) then
- CX := InstCode2;
- inline($FB); {STI}
- { load AX with equipment list word (which is what int 11 normally does)}
- AX := EquipList;
- end; {Int11}
-
- {
- Int09 : This is the standard BIOS keyboard function interrupt. We chain to
- it, and watch for the "hot_key" to appear.
- }
- procedure Int09;
- interrupt;
- begin
- inline($FA); {CLI -- stop interrupts for a while}
- CallInt(Int09_Vec); { call the original keyboard interrupt }
- { if the TSR is active, and the hot key is pressed, deinstall TSR }
- if (Busy) and (Kbd_Status = Activate) then
- begin
- DeInstall;
- end;
- { if the TSR isn't active, the hot key is pressed, and DOS isn't busy...}
- if (not Busy) and (Kbd_Status = Activate)
- and (InDosFlag^ = 0) {and (GetMode in TextModes)} then
- begin
- Busy := true; { flag TSR as active }
- { save the interrupted program's stack segment and pointer, and }
- { restore QT's stack segment and pointer }
- inline (
- $8C/$16/OrigSS/ { MOV OrigSS, SS }
- $8E/$16/TurboSS/ { MOV SS, TurboSS }
- $8B/$26/TurboSP { MOV SP, TurboSP }
- );
- SaveScr; { save the current display }
- Process; { The actual TSR }
- RestScr; { restore the display }
- { restore the stack of the interrupted program }
- inline (
- $8E/$16/OrigSS { MOV SS, OrigSS }
- );
- Busy := false; {TSR is no longer active }
- end;
- inline($FB); {STI}
- end; {Int09}
-
- {
- Initialize : This function checks to see if the TSR is already resident before
- proceding with installation. It then chains to the three captured
- interrupts (hex 28, 11, and 9), and initializes some global
- variables.
- }
- function Initialize : boolean;
- begin
- { assign the special activation test codes }
- InstCode1 := $5154; {QT}
- InstCode2 := $4F4B; {OK}
-
- { check to see if TSR is already installed }
- Regs.CX := InstCode1;
- Intr($11,Regs);
- if (Regs.CX = InstCode2) then
- begin
- Initialize := false;
- exit;
- end;
-
- { get the video mode, and select the proper buffer for save / restore }
- if (7 = GetMode) then
- Video_Display := Ptr($B000,0)
- else
- Video_Display := Ptr($B800,0);
-
- { capture INT 28 (DOS idle)}
- GetIntVec($28,Int28_Vec);
- SetIntVec($28,@Int28);
-
- { capture INT 11 (BIOS equipment)}
- GetIntVec($11,Int11_Vec);
- SetIntVec($11,@Int11);
-
- { capture INT 9 (BIOS keyboard)}
- GetIntVec($09,Int09_Vec);
- SetIntVec($09,@Int09);
-
- { locate the DOS InDOS flag }
- Regs.AX := $3400;
- Intr($21,Regs);
- InDosFlag := Ptr(Regs.ES,Regs.BX);
-
- { save the location and status of QT's stack }
- TurboSS := SSeg;
- TurboSP := SPtr;
-
- Busy := false;
-
- Initialize := true;
- end; {Initialize}
-
- begin
- { a quick heading }
- Writeln('QT -- Quick Time Display (a TSR)');
- Writeln;
-
- if Initialize then
- begin
- Writeln('Program installed');
- Keep(0); { Turbo Pascal TSR call }
- end
- else
- begin
- Writeln(^G,'Unable to install program. Sorry!');
- Exit;
- end;
-
- end. {QT}