home *** CD-ROM | disk | FTP | other *** search
- UNIT TSRUnit; {Create TSR programs with Turbo Pascal 5.0 & TSRUnit}
-
- {$B-,F-,I+,R-,S+} {Set compiler directives to normal values.}
-
- INTERFACE {=======================================================}
- {
- The author and any distributor of this software assume no responsi-
- bility for damages resulting from this software or its use due to
- errors, omissions, incompatibility with other software or with
- hardware, or misuse; and specifically disclaim any implied warranty
- of fitness for any particular purpose or application.
- }
- USES DOS, CRT;
- CONST
- {*** Shift key combination codes. }
- AltKey = 8; CtrlKey = 4; LeftKey = 2; RightKey = 1;
-
- TSRVersion : WORD = $0204; {Low byte.High byte = 2.04 }
-
- TYPE
- String80 = STRING[80];
- ChrWords = RECORD CASE INTEGER OF
- 1: ( W: WORD );
- 2: ( C: CHAR; A: BYTE );
- END;
- LineWords = ARRAY[1..80] OF ChrWords;
- WordFuncs = FUNCTION : WORD;
-
- VAR
- TSRScrPtr : POINTER; {Pointer to saved screen image. }
- TSRChrPtr : POINTER; {Pointer to first character to insert. }
- TSRMode : BYTE; {Video mode --------- before TSR popped up.}
- TSRWidth : BYTE; {Number of screen columns-- " " " " .}
- TSRPage : BYTE; {Active video page number-- " " " " .}
- TSRColumn : BYTE; {Cursor column number ----- " " " " .}
- TSRRow : BYTE; {Cursor row number -------- " " " " .}
- {
- ** Procedure for installing the TSR program. }
- PROCEDURE TSRInstall( TSRName : STRING; {Name or title for TSR. }
- TSRFunc : WordFuncs;{Ptr to FUNCTION to call}
- ShiftComb: BYTE; {Hot key--shift key comb}
- KeyChr : CHAR ); {Hot Key--character key.}
- {
- ShiftComb and KeyChr specify the default hot keys for the TSR.
- ShiftComb may be created by adding or ORing the constants AltKey,
- CtrlKey, LeftKey, and RightKey together. KeyChr may be
- characters 0-9 and A-Z.
-
- The default hot keys may be overridden when the TSR is installed
- by specifying optional parameters on the command line. The
- parameter format is:
- [/A] [/C] [/R] [/L] [/"[K["]]]
- The square brackets surround optional items--do not include them.
- Any characters between parameters are ignored. The order of the
- characters does not matter; however, the shift keys specified are
- cummulative and the last character key "K" specified is the used.
- }
- {
- ** Functions for checking status of printer LPT1. }
- FUNCTION PrinterOkay: BOOLEAN; {Returns TRUE if printer is okay.}
- FUNCTION PrinterStatus: BYTE; {Returns status of printer.
- Definition of status byte bits (1 & 2 are not used), if set then:
- Bit: -- 7 --- ---- 6 ---- -- 5 --- -- 4 --- -- 3 -- --- 0 ---
- Not busy Acknowledge No paper Selected I/O Err. Timed-out
- }
- {
- ** Routines for obtaining one row of screen characters. }
- FUNCTION ScreenLineStr( Row: BYTE ): String80; {Returns char. str.}
- PROCEDURE ScreenLine( Row: BYTE; VAR Line: LineWords; {Returns }
- VAR Words: BYTE ); {chr & color}
-
- IMPLEMENTATION {==================================================}
- VAR
- BuffSize, InitCMode : WORD;
- NpxFlag : BOOLEAN;
- Buffer : ARRAY[0..8191] OF WORD;
- NpxState : ARRAY[0..93] OF BYTE;
- RetrnVal, InitVideo : BYTE;
- TheirFunc : WordFuncs;
-
- CONST {Offsets to items contained in PROCEDURE Asm. }
- UnSafe = 0; Flg = 1; Key = 2; Shft = 3;
- StkOfs = 4; StkSs = 6; DosSp = 8; DosSs = 10;
- Prev = 12; Flg9 = 13; InsNumb = 14;
- Dos21 = $10; Dos25 = Dos21+4; Dos26 = Dos25+4;
- Bios9 = Dos26+4; Bios16 = Bios9+4; DosTab = Bios16+4;
- Our21 = DosTab+99; Our25 = Our21+51; Our26 = Our25+27;
- Our09 = Our26+27; Our16 = Our09+127+8; InsChr = Our16+180-8;
- PopUp = InsChr+4;
-
- PROCEDURE Asm; {Inline code--data storage and intercept routines. }
- INTERRUPT;
- BEGIN
- INLINE(
- {*** Storage for interrupt vectors. }
- {Dos21: } >0/>0/ {DOS func. intr vector. }
- {Dos25: } >0/>0/ {DOS abs. disk read intr. vector. }
- {Dos26: } >0/>0/ {DOS abs. sector write intr.vector. }
- {Bios9: } >0/>0/ {BIOS key stroke intr. vector. }
- {Bios16: } >0/>0/ {BIOS buffered keybd. input intr.vect.}
-
- {DosTab: ARRAY[0..98] OF BYTE = {Non-reetrant DOS functions.}
- 0/0/0/0/0/0/0/0/ 0/0/0/0/0/1/1/1/ 1/1/1/1/1/1/1/1/
- 1/1/1/1/1/1/1/1/ 1/1/1/1/1/1/0/1/ 1/1/1/1/1/1/1/0/
- 1/0/0/0/0/0/1/1/ 1/1/1/1/1/1/1/1/ 1/1/1/1/1/1/1/1/
- 0/0/0/0/0/0/1/1/ 0/0/0/0/1/0/1/1/ 0/1/1/1/1/0/0/0/ 0/0/0/
-
- {*** OurIntr21 ******* Intercept routine for DOS Function Intr.***}
- { 0} $9C/ { PUSHF ;Save flags. }
- { 1} $FB/ { STI ;Enable interrupts. }
- { 2} $80/$FC/$63/ { CMP AH,63H ;Assume unsafe if new }
- { 5} $73/<22-7/ { JNB IncF ;function--skip table.}
- { 7} $50/ { PUSH AX ;Save registers. }
- { 8} $53/ { PUSH BX ;Load offset to table.}
- { 9} $BB/>DosTab/ { MOV BX,[DosTab] }
- { 12} $8A/$C4/ { MOV AL,AH ;Load table entry }
- { 14} $2E/ { CS: ;index. }
- { 15} $D7/ { XLAT ;Get value from table.}
- { 16} $3C/$00/ { CMP AL,0 ;If TRUE then set flag}
- { 18} $5B/ { POP BX ;Restore registers. }
- { 19} $58/ { POP AX ; }
- { 20} $74/$17/ { JZ JmpDos21 ;Jump to orig. intr. }
- { 22} $2E/ {IncF: CS: ; }
- { 23} $FE/$06/>UnSafe/ { INC [UnSafe] ;Set UnSafe flag. }
- { 27} $9D/ { POPF ;Restore flags. }
- { 28} $9C/ { PUSHF ; }
- { 29} $2E/ { CS: ; }
- { 30} $FF/$1E/>Dos21/ { CALL FAR [Dos21] ;Call orig. intr. }
- { 34} $FB/ { STI ;Enable interrupts. }
- { 35} $9C/ { PUSHF ;Save flags. }
- { 36} $2E/ { CS: ; }
- { 37} $FE/$0E/>UnSafe/ { DEC [UnSafe] ;Clear UnSafe flag. }
- { 41} $9D/ { POPF ;Restore flags. }
- { 42} $CA/$02/$00/ { RETF 2 ;Return & remove flag.}
-
- { 45} $9D/ {JmpDos21: POPF ;Restore flags. }
- { 46} $2E/ { CS: ; }
- { 47} $FF/$2E/>Dos21/ { JMP FAR [Dos21] ;Jump to orig. intr. }
- { 51}
- {*** OurIntr25 ********** Intercept routine for DOS Abs. Read *** }
- { 0} $9C/ { PUSHF ;Save flags. }
- { 1} $2E/ { CS: ; }
- { 2} $FE/$06/>UnSafe/ { INC [UnSafe] ;Set UnSafe flag. }
- { 6} $9D/ { POPF ;Restore flags. }
- { 7} $9C/ { PUSHF ; }
- { 8} $2E/ { CS: ; }
- { 9} $FF/$1E/>Dos25/ { CALL FAR [Dos25] ;Call DOS abs. read. }
- { 13} $68/>Our25+19/ { PUSH Our25+19 ;Clean up stack with- }
- { 16} $C2/$02/$00/ { RET 2 ;out changing flags. }
- { 19} $9C/ { PUSHF ;Save flags. }
- { 20} $2E/ { CS: ; }
- { 21} $FE/$0E/>UnSafe/ { DEC [UnSafe] ;Clear UnSafe flag. }
- { 25} $9D/ { POPF ;Restore flags. Leave}
- { 26} $CB/ { RETF ;old flags on the stk.}
- { 27}
- {*** OurIntr26 ********** Intercept routine for DOS Abs. Write ***}
- { 0} $9C/ { PUSHF ;Save flags. }
- { 1} $2E/ { CS: ; }
- { 2} $FE/$06/>UnSafe/ { INC [UnSafe] ;Set UnSafe flag. }
- { 6} $9D/ { POPF ;Restore flags. }
- { 7} $9C/ { PUSHF ; }
- { 8} $2E/ { CS: ; }
- { 9} $FF/$1E/>Dos26/ { CALL FAR [Dos26] ;Call DOS abs. write. }
- { 13} $68/>Our26+19/ { PUSH Our26+19 ;Clean up stack with- }
- { 16} $C2/$02/$00/ { RET 2 ;out changing flags. }
- { 19} $9C/ { PUSHF ;Save flags. }
- { 20} $2E/ { CS: ; }
- { 21} $FE/$0E/>UnSafe/ { DEC [UnSafe] ;Clear UnSafe flag. }
- { 25} $9D/ { POPF ;Restore flags. Leave}
- { 26} $CB/ { RETF ;old flags on the stk.}
- { 27}
-
- {*** OurIntr9 ********** Intercept for BIOS Hardware Keyboard Intr}
- { 0} $9C/ { PUSHF ;Entry point. }
- { 1} $FB/ { STI ;Enable interrupts. }
- { 2} $1E/ { PUSH DS ; }
- { 3} $0E/ { PUSH CS ;DS := CS; }
- { 4} $1F/ { POP DS ; }
- { 5} $50/ { PUSH AX ;Preserve AX on stack.}
- { 6} $31/$C0/ { XOR AX,AX ;Set AH to 0. }
- { 8} $E4/$60/ { IN AL,60h ;Read byte from keybd }
- { 10} $3C/$E0/ { CMP AL,0E0h ;If multi-byte codes, }
- { 12} $74/<75-14/ { JE Sfx ;then jump and set }
- { 14} $3C/$F0/ { CMP AL,0F0h ;multi-byte flag, Flg9}
- { 16} $74/<75-18/ { JE Sfx ; }
- { 18} $80/$3E/>Flg9/$00/ { CMP [Flg9],0 ;Exit if part of }
- { 23} $75/<77-25/ { JNZ Cfx ;multi-byte code. }
- { 25} $3A/$06/>Key/ { CMP AL,[Key] ;Exit if key pressed }
- { 29} $75/<88-31/ { JNE PreExit ;is not hot key. }
-
- { 31} $50/ { PUSH AX ;Hot key was pressed, }
- { 32} $06/ { PUSH ES ;check shift key }
- { 33} $B8/$40/$00/ { MOV AX,0040h ;status byte. First }
- { 36} $8E/$C0/ { MOV ES,AX ;load BIOS segment. }
- { 38} $26/ { ES: ; }
- { 39} $A0/>$0017/ { MOV AL,[0017h] ;AL:= Shift key status}
- { 42} $07/ { POP ES ;Restore ES register. }
- { 43} $24/$0F/ { AND AL,0Fh ;Clear unwanted bits. }
- { 45} $3A/$06/>Shft/ { CMP AL,[Shft] ;Exit if not hot key }
- { 49} $58/ { POP AX ;shift key combination}
- { 50} $75/<88-52/ { JNE PreExit ;(Restore AX first). }
-
- { ;Hot Keys encountered.}
- { 52} $3A/$06/>Prev/ { CMP AL,[Prev] ;Discard repeated hot }
- { 56} $74/<107-58/ { JE Discard ;key codes. }
- { 58} $A2/>Prev/ { MOV [Prev],AL ;Update Prev. }
- { 61} $F6/$06/>Flg/3/ { TEST [Flg],3 ;If Flg set, keep key }
- { 66} $75/<99-68/ { JNZ JmpBios9 ;& exit to orig. BIOS }
- { 68} $80/$0E/>Flg/1/ { OR [Flg],1 ;9. Else set flag and}
- { 73} $EB/<107-75/ { JMP SHORT Discard;discard key stroke. }
-
- { 75} $B4/$01/ {Sfx: MOV AH,1 ;Load AH with set flag}
- { 77} $88/$26/>Flg9/ {Cfx: MOV [Flg9],AH ;Save multi-byte flag.}
- { 81} $C6/$06/>Prev/$FF/ { MOV [Prev],0FFh ;Change prev key byte.}
- { 86} $EB/<99-88/ { JMP SHORT JmpBios9 }
-
- { 88} $3C/$FF/ {PreExit: CMP AL,0FFh ;Update previous key }
- { 90} $74/<99-92/ { JE JmpBios9 ;unless key is buffer-}
- { 92} $3C/$00/ { CMP AL,0 ;full code--a 00h }
- { 94} $74/<99-96/ { JZ JmpBios9 ;0FFh }
- { 96} $A2/>Prev/ { MOV [Prev],AL ;Update previous key. }
-
- { 99} $58/ {JmpBios9: POP AX ;Restore registers and}
- {100} $1F/ { POP DS ;flags. }
- {101} $9D/ { POPF ; }
- {102} $2E/ { CS: ; }
- {103} $FF/$2E/>Bios9/ { JMP [Bios9] ;Exit to orig. intr 9.}
-
- {107} $E4/$61/ {Discard: IN AL,61h ;Clear key from buffer}
- {109} $8A/$E0/ { MOV AH,AL ;by resetting keyboard}
- {111} $0C/$80/ { OR AL,80h ;port and sending EOI }
- {113} $E6/$61/ { OUT 61h,AL ;to intr. handler }
- {115} $86/$E0/ { XCHG AH,AL ;telling it that the }
- {117} $E6/$61/ { OUT 61h,AL ;key has been }
- {119} $B0/$20/ { MOV AL,20h ;processed. }
- {121} $E6/$20/ { OUT 20h,AL ; }
- {123} $58/ { POP AX ;Restore registers and}
- {124} $1F/ { POP DS ;flags. }
- {125} $9D/ { POPF ; }
- {126} $CF/ { IRET ;Return from interrupt}
- {127}
-
- {*** OurIntr16 ***** Intercept routine for Buffered Keyboard Input}
- { 0} $58/ {JmpBios16: POP AX ;Restore AX, DS, and }
- { 1} $1F/ { POP DS ;FLAGS registers then }
- { 2} $9D/ { POPF ;exit to orig. BIOS }
- { 3} $2E/ { CS: ;intr. 16h routine. }
- { 4} $FF/$2E/>Bios16/ { JMP [Bios16] ; }
-
- { 8} $9C/ {OurIntr16: PUSHF ;Preserve FLAGS. }
- { 9} $FB/ { STI ;Enable interrupts. }
- { 10} $1E/ { PUSH DS ;Preserve DS and AX }
- { 11} $50/ { PUSH AX ;registers. }
- { 12} $0E/ { PUSH CS ;DS := CS; }
- { 13} $1F/ { POP DS ; }
- { 14} $F6/$C4/$EF/ { TEST AH,EFh ;Jmp if not read char.}
- { 17} $75/<48-19/ { JNZ C3 ;request. }
-
- {*** Intercept loop for Read Key service.}
- { 19} $F6/$06/>Flg/1/ {C1: TEST [Flg],1 ;If pop up Flg bit is }
- { 24} $74/<29-26/ { JZ C2 ;set then call INLINE }
- { 26} $E8/>122-29/ { CALL ToPopUp ;pop up routine. }
- { 29} $F6/$06/>Flg/16/{C2: TEST [Flg],10h ;Jmp if insert flg set}
- { 34} $75/<48-36/ { JNZ C3 ; }
- { 36} $FE/$C4/ { INC AH ;Use orig. BIOS }
- { 38} $9C/ { PUSHF ;service to check for }
- { 39} $FA/ { CLI ;character ready. }
- { 40} $FF/$1E/>Bios16/ { CALL FAR [Bios16];Disable interrupts. }
- { 44} $58/ { POP AX ;Restore AX and save }
- { 45} $50/ { PUSH AX ;it again. }
- { 46} $74/<19-48/ { JZ C1 ;Loop until chr. ready}
-
- { 48} $F6/$06/>Flg/17/{C3: TEST [Flg],11h ;Exit if neither bit }
- { 53} $74/<-55/ { JZ JmpBios16 ;of Flg is set. }
- { 55} $F6/$06/>Flg/$01/ { TEST [Flg],1 ;If pop up Flg bit is }
- { 60} $74/<65-62/ { JZ C4 ;set then call INLINE }
- { 62} $E8/>122-65/ { CALL ToPopUp ;pop up routine. }
- { 65} $F6/$06/>Flg/$10/{C4:TEST [Flg],10h ;Exit unless have }
- { 70} $74/<-72/ { JZ JmpBios16 ;characters to insert.}
- { 72} $F6/$C4/$EE/ { TEST AH,0EEh ;If request is not a }
- { 75} $75/<-77/ { JNZ JmpBios16 ;chr. request, exit. }
-
- {*** Insert a character. }
- { 77} $58/ { POP AX ;AX := BIOS service no}
- { 78} $53/ { PUSH BX ;Save BX and ES. }
- { 79} $06/ { PUSH ES ; }
- { 80} $C4/$1E/>InsChr/ { LES BX,[InsChr] ;PTR(ES,BX) := InsChr;}
- { 84} $26/ { ES: ;AL := InsChr^; }
- { 85} $8A/$07/ { MOV AL,[BX] ; }
- { 87} $07/ { POP ES ;Restore ES and BX. }
- { 88} $5B/ { POP BX ; }
- { 89} $F6/$C4/$01/ { TEST AH,01h ;IF AH IN [$01,$11] }
- { 92} $B4/$00/ { MOV AH,00h ; THEN ReportOnly; }
- { 94} $75/<114-96/ { JNZ ReportOnly ;Set Scan code to 0. }
- { 96} $FE/$06/>InsChr/ { INC [InsChr] ;Inc( InsChr ); }
- {100} $FF/$0E/>InsNumb/ { DEC [InsNumb] ;Dec( InsNumb ); }
- {104} $75/<111-106/ { JNZ SkipReset ;IF InsNumb = 0 THEN }
- {106} $80/$26/>Flg/$EF/ { AND [Flg],0EFh ; Clear insert chr flg}
- {111} $1F/ {SkipReset: POP DS ;Restore BX, DS, and }
- {112} $9D/ { POPF ;FLAGS, then return }
- {113} $CF/ { IRET ;from interrupt. }
-
- {114} $1F/ {ReportOnly: POP DS ;Report char. ready. }
- {115} $9D/ { POPF ;Restore DS and FLAGS.}
- {116} $50/ { PUSH AX ;Clear zero flag bit }
- {117} $40/ { INC AX ;to indicate a }
- {118} $58/ { POP AX ;character ready. }
- {119} $CA/>0002/ { RETF 2 ;Exit & discard FLAGS }
-
- {*** Interface to PopUpCode Routine. }
- {122} $50/ {ToPopUp: PUSH AX ;Save AX. }
- {123} $FA/ { CLI ;Disable interrupts. }
- {124} $F6/$06/>UnSafe/$FF/{TEST [UnSafe],0FFh ;IF UnSafe <> 0 }
- {129} $75/<177-131/ { JNZ PP2 ; THEN Return. }
- {131} $A0/>Flg/ { MOV AL,[Flg] ;Set in-use bit; clear}
- {134} $24/$FE/ { AND AL,0FEh ;pop up bit of Flg. }
- {136} $0C/$02/ { OR AL,2 ;Flg := (Flg AND $FE) }
- {138} $A2/>Flg/ { MOV [Flg],AL ; OR 2; }
- { ;**Switch to our stack}
- {141} $A1/>StkOfs/ { MOV AX,[StkOfs] ;Load top of our stack}
- {144} $87/$C4/ { XCHG AX,SP ;Exchange it with }
- {146} $A3/>DosSp/ { MOV [DosSp],AX ;stk.ptr, save old SP.}
- {149} $8C/$16/>DosSs/ { MOV [DosSs],SS ;Save old SS. }
- {153} $8E/$16/>StkSs/ { MOV SS,[StkSs] ;Replace SS with our }
- {157} $FB/ { STI ;SS. Enable interrupts}
-
- {158} $9C/ { PUSHF ;Interrupt call to pop}
- {159} $FF/$1E/>PopUp/ { CALL FAR [PopUp] ;up TSR routine. }
-
- {163} $FA/ { CLI ;Disable interrupts. }
- {164} $8B/$26/>DosSp/ { MOV SP,[DosSp] ;Restore stack ptr }
- {168} $8E/$16/>DosSs/ { MOV SS,[DosSs] ;SS:SP. Clear in-use }
- {172} $80/$26/>Flg/$FD/ { AND [Flg],0FDh ;bit of Flg. }
-
- {177} $FB/ {PP2: STI ;Enable interrupts. }
- {178} $58/ { POP AX ;Restore AX. }
- {179} $C3 ); { RET ;Return. }
- {180}
- END; {Asm.} {END corresponds to 12 bytes of code--used for storage}
-
- PROCEDURE PopUpCode; {Interface between the BIOS intercept }
- INTERRUPT; {routines and your TSR function. }
- CONST BSeg = $0040; VBiosOfs = $49;
- TYPE
- VideoRecs = RECORD
- VideoMode : BYTE;
- NumbCol, ScreenSize, MemoryOfs : WORD;
- CursorArea : ARRAY[0..7] OF WORD;
- CursorMode : WORD;
- CurrentPage : BYTE;
- VideoBoardAddr : WORD;
- CurrentMode, CurrentColor : BYTE;
- END;
- VAR
- Regs : Registers;
- VideoRec : VideoRecs;
- KeyLock : BYTE;
- ScrnSeg, NumbChr : WORD;
- BEGIN
- SwapVectors; {Set T.P. intr. vectors.}
- Move( Ptr(BSeg,VBiosOfs)^, VideoRec, {Get Video BIOS info. }
- SizeOf(VideoRec) );
- WITH VideoRec, Regs DO BEGIN
- IF (VideoMode > 7) OR {Abort pop up if unable}
- (ScreenSize > BuffSize) THEN BEGIN {to save screen image. }
- SwapVectors; {Restore intr. vectors.}
- Exit;
- END;
- KeyLock := Mem[BSeg:$0017]; {Save lock key states. }
- IF VideoMode = 7 THEN ScrnSeg := $B000 {Save screen--supports }
- ELSE ScrnSeg := $B800; {text, MGA & CGA modes.}
- Move( PTR( ScrnSeg, MemoryOfs )^, Buffer, ScreenSize );
- AX := InitVideo; {If in graphics mode, }
- IF (VideoMode >=4) {switch to text mode. }
- AND (VideoMode <= 6) THEN Intr( $10, Regs );
- AX := $0500; {Select display page 0.}
- Intr( $10, Regs );
- CX := InitCMode; {Set cursor size. }
- AH := 1;
- Intr( $10, Regs );
-
- TSRMode := VideoMode; {Fill global variables }
- TSRWidth := NumbCol; {with current information}
- TSRPage := CurrentPage;
- TSRColumn := Succ( Lo( CursorArea[CurrentPage] ) );
- TSRRow := Succ( Hi( CursorArea[CurrentPage] ) );
-
- IF NpxFlag THEN {Save co-processor state.}
- INLINE( $98/ $DD/$36/>NpxState ); {WAIT FSAVE [NpxState] }
- {
- *** Call user's program and save return code--no. char. to insert.
- }
- NumbChr := TheirFunc;
- MemW[CSeg:InsNumb] := NumbChr;
- IF NumbChr > 0 THEN BEGIN {Have char. to insert.}
- MemL[CSeg:InsChr] := LONGINT( TSRChrPtr );
- Mem[CSeg:Flg] := Mem[CSeg:Flg] OR $10;
- END;
- {
- *** Pop TSR back down--Restore computer to previous state.
- }
- IF NpxFlag THEN {Restore co-prcssr state.}
- INLINE( $98/ $DD/$36/>NpxState ); {WAIT FSAVE [NpxState] }
-
- Mem[BSeg:$17] := {Restore key lock status.}
- (Mem[BSeg:$17] AND $0F) OR (KeyLock AND $F0);
-
- IF Mem[BSeg:VBiosOfs] <> VideoMode THEN BEGIN
- AX := VideoMode; {Restore video mode. }
- Intr( $10, Regs );
- END;
- AH := 1; CX := CursorMode; {Restore cursor size. }
- Intr( $10, Regs );
- AH := 5; AL := CurrentPage; {Restore active page. }
- Intr( $10, Regs );
- AH := 2; BH := CurrentPage; {Restore cursor positon. }
- DX := CursorArea[CurrentPage];
- Intr( $10, Regs ); {Restore screen image. }
- Move( Buffer, PTR( ScrnSeg, MemoryOfs )^, ScreenSize );
-
- SwapVectors; {Restore non-T.P. vectors.}
- END;
- END; {PopUp.}
- {
- ***** Printer Functions:
- }
- FUNCTION PrinterStatus: BYTE; {Returns status of LPT1.}
- { Definition of status byte bits (1 & 2 are not used), if set then:
- Bit: -- 7 --- ---- 6 ---- -- 5 --- -- 4 --- -- 3 -- --- 0 ---
- Not busy Acknowledge No paper Selected I/O Err. Timed-out
- }
- VAR Regs : Registers;
- BEGIN
- WITH Regs DO BEGIN
- AH := 2; DX := 0; {Load BIOS function and printer number. }
- Intr( $17, Regs ); {Call BIOS printer services. }
- PrinterStatus := AH; {Return with printer status byte. }
- END;
- END; {PrinterStatus.}
-
- FUNCTION PrinterOkay: BOOLEAN; {Returns TRUE if printer is okay. }
- VAR S : BYTE;
- BEGIN
- S := PrinterStatus;
- IF ((S AND $10) <> 0) AND ((S AND $29) = 0) THEN
- PrinterOkay := TRUE
- ELSE PrinterOkay := FALSE;
- END; {PrinterOkay.}
- {
- ***** Procedures to obtain contents of saved screen image.
- }
- PROCEDURE ScreenLine( Row: BYTE; VAR Line: LineWords;
- VAR Words: BYTE );
- BEGIN
- Words := 40; {Determine screen line size.}
- IF TSRMode > 1 THEN Words := Words*2; {Get line's }
- Move( Buffer[Pred(Row)*Words], Line, Words*2 ); {characters and }
- END; {ScreenLine.} {colors. }
-
- FUNCTION ScreenLineStr( Row: BYTE ): String80; {Returns just chars}
- VAR
- Words, i : BYTE;
- LineWord : LineWords;
- Line : String80;
- BEGIN
- ScreenLine( Row, LineWord, Words ); {Get chars & attributes. }
- Line := ''; {Move characters to string}
- FOR i := 1 TO Words DO Insert( LineWord[i].C, Line, i );
- ScreenLineStr := Line;
- END; {ScreenString.}
- {
- ***** TSR Installation procedure.
- }
- PROCEDURE TSRInstall( TSRName: STRING; TSRFunc: WordFuncs;
- ShiftComb: BYTE; KeyChr: CHAR );
- CONST
- ScanChr = '+1234567890++++QWERTYUIOP++++ASDFGHJKL+++++ZXCVBNM';
- CombChr = 'RLCA"';
- VAR
- PlistPtr : ^STRING;
- i, j, k : WORD;
- Regs : Registers;
- Comb, ScanCode : BYTE;
- BEGIN
- IF Ofs( Asm ) <> 0 THEN EXIT; {Offset of Asm must be 0}
- MemW[CSeg:StkSs] := SSeg; {Save pointer to top of }
- MemW[CSeg:StkOfs] := Sptr + 562; {TSR's stack. }
- MemL[CSeg:PopUp] := LONGINT(@PopUpCode); {Save PopUpCode addr. }
- TheirFunc := TSRFunc; {& their TSR func. addr.}
- Writeln('Installing Stay-Resident program: ',TSRName );
- {
- ***** Save intercepted interrupt vectors: $09, $16, $21, $25, $26.
- }
- GetIntVec( $09, POINTER( MemL[CSeg:Bios9] ) );
- GetIntVec( $16, POINTER( MemL[CSeg:Bios16] ) );
- GetIntVec( $21, POINTER( MemL[CSeg:Dos21] ) );
- GetIntVec( $25, POINTER( MemL[CSeg:Dos25] ) );
- GetIntVec( $26, POINTER( MemL[CSeg:Dos26] ) );
- {
- ***** Get equipment list and video mode.
- }
- WITH Regs DO BEGIN
- Intr( $11, Regs ); {Check equipment list for }
- NpxFlag := (AL AND 2) = 2; {math co-processor. }
- AH := 15; {Get current video mode }
- Intr( $10, Regs ); {and save it for when TSR }
- InitVideo := AL; {is activated. }
- AH := 3; BH := 0; {Get current cursor size }
- Intr( $10, Regs ); {and save it for when TSR }
- InitCMode := CX; {is activated. }
- END; {WITH Regs}
- {
- ***** Get info. on buffer for saving screen image.
- }
- BuffSize := SizeOf( Buffer );
- TSRScrPtr := @Buffer;
- {
- *** Determine activation key combination.
- }
- Comb := 0; i := 1; {Create ptr to }
- PlistPtr := Ptr( PrefixSeg, $80 ); {parameter list. }
- WHILE i < Length( PlistPtr^ ) DO BEGIN {Check for parameters.}
- IF PlistPtr^[i] = '/' THEN BEGIN {Process parameter. }
- Inc( i );
- j := Pos( UpCase( PlistPtr^[i] ), CombChr );
- IF (j > 0) AND (j < 5) THEN Comb := Comb OR (1 SHL Pred(j))
- ELSE IF j <> 0 THEN BEGIN {New activation char. }
- Inc( i ); k := Succ( i );
- IF i > Length(PlistPtr^) THEN KeyChr := #0
- ELSE BEGIN
- IF ((k <= Length(PlistPtr^)) AND (PlistPtr^[k] = '"'))
- OR (PlistPtr^[i] <> '"') THEN KeyChr := PlistPtr^[i]
- ELSE KeyChr := #0;
- END; {ELSE BEGIN}
- END; {ELSE IF ... BEGIN}
- END; {IF PlistPtr^[i] = '/'}
- Inc( i );
- END; {WHILE ...}
- IF Comb = 0 THEN Comb := ShiftComb; {Use default combination. }
- IF Comb = 0 THEN Comb := AltKey; {No default, use [Alt] key.}
- ScanCode := Pos( UpCase( KeyChr ), ScanChr ); {Convert char. to}
- IF ScanCode < 2 THEN BEGIN {scan code. }
- ScanCode := 2; KeyChr := '1';
- END;
- Mem[CSeg:Shft] := Comb; {Store shift key combination}
- Mem[CSeg:Key] := ScanCode; {and scan code. }
- {
- *** Output an installation message: Memory used & activation code.
- }
- Writeln( 'Memory used is approximately ',
- ( ($1000 + Seg(FreePtr^) - PrefixSeg)/64.0):7:1,' K (K=1024).');
- Writeln(
- 'Activate program by pressing the following keys simultaneously:');
- IF (Comb AND 1) <> 0 THEN Write(' [Right Shift]');
- IF (Comb AND 2) <> 0 THEN Write(' [Left Shift]');
- IF (Comb AND 4) <> 0 THEN Write(' [Ctrl]');
- IF (Comb AND 8) <> 0 THEN Write(' [Alt]');
- Writeln(' and "', KeyChr, '".');
- {
- *** Intercept orig. interrupt vectors; Then exit and stay-resident.
- }
- SetIntVec( $21, Ptr( CSeg, Our21 ) );
- SetIntVec( $25, Ptr( CSeg, Our25 ) );
- SetIntVec( $26, Ptr( CSeg, Our26 ) );
- SetIntVec( $16, Ptr( CSeg, Our16 ) );
- SetIntVec( $09, Ptr( CSeg, Our09 ) );
- SwapVectors; {Save turbo intr.vectors.}
- MemW[CSeg:UnSafe] := 0; {Allow TSR to pop up. }
- Keep( 0 ); {Exit and stay-resident. }
- END; {TSRInstall.}
- END. {TSRUnit.}