{ints.inc by K.Lammassaari 1998} {Source must be compiled with start addr $3000 or higher. In old TP 3.0 you can (to save memory !) use startaddress $2200. Remember to change values of Hooked and addr of _IntTbl ! Also If You use DOSPLAY services, you must change address of MBHook to $2100 and SeeHook to $2120 MBHook amd SeeHook are in dosplay.inc; } { Contains following procedures and functions: Function SetInterrupt(ProcAddr:Integer):Byte; - Sets an interrupt. ProcAddr := Addr(MyInterrupt procedure); - Returns a number for the interrupt service routine (1... ) - REM !!Interrupt service routine MUST NOT contain any entries to DOS. Otherwise the internal stack of dos will be overwritten. Most of the standard TurboPascal I/O routines contain DOS entry. You must use rewritten direct code to do I/O. For example FastWrite.. - SetInterrupt returns the required IntNumber. - Discards ROM interrupt services. To obtain them use function SetRomInterrupt. - REM some TP standard routines access ROM, thus rom interrupt is occasionally accessed. Procedure DisableInterrupt(IntNumber:Byte); - SetInterrupt returns the required IntNumber. Procedure EnableInterrupt(IntNumber:Byte); - SetInterrupt returns the required IntNumber. Function SetRomInterrupt:Byte; - Reconnects the standard DOS/ROM interrupt services. - Returns a number of interrupt (1...) Procedure RemoveInterrupts; - Well,,, removes all user interrupt services. Back to normal state. - IF YOU FORGET TO SE THIS AT THE END OF YOUR PROGRAM, the computer will crash :-) } Const PushAll :Array[0..14] Of Byte =($f3,$f5,$c5,$d5,$e5, $d9, $f5,$c5,$d5,$e5, $dd,$e5,$fd,$e5,0); Const PopAll :Array[0..16] Of Byte =($db,$99, $fd,$e1,$dd,$e1, $e1,$d1,$c1,$f1,$d9, $e1,$d1,$c1,$f1,$fb, $c9); Hooked :Integer = $2ea0 ; {In TP3.0 this value can be $20f0 } Var IntJmp :Integer Absolute $39; _IntTbl :Array[0..20,0..2] Of Byte Absolute $2ea0; {In TP 3.0 this can be $20f0 } IntTbl :Array[0..20] Of Integer; {Stores set interrupts } Int38 :Array[0..2] Of Byte Absolute $0038; StoreInt:Array[0..2] Of Byte; FirstFreeIntTableEntry :Byte; Function SetInterrupt(ProcAddr:Integer):Byte; {Returns the nbr of interrupt 1..20} {The parameter 'ProcAddr' contains address of the interrupt service routine} {It MUST not contain any entries to DOS. Otherwise the internal stack of dos would be overwritten. REM ! Most of the standard I/O routines contain DOS entry , You must use rewritten direct code to do I/O.} Var Temp :Integer; Begin Inline($f3); {DI} Temp := ProcAddr; If IntJmp <> Hooked Then Begin FillChar(_IntTbl,SizeOf(_IntTbl),0); {Clear interrupt table } FillChar(IntTbl,SizeOf(IntTbl),0); {Clear mirror table } Move(Int38,StoreInt,3); Move(PushAll,_IntTbl[0,0],SizeOf(PushAll)); {15 bytes = 0..4 items of _IntTbl} _IntTbl[5,0] := $cd; Move(Temp,_IntTbl[5,1],2); Move(PopAll,_IntTbl[6,0],SizeOf(PopAll)); FirstFreeIntTableEntry := 6; IntJmp := Hooked; IntTbl[0] := 1;IntTbl[IntTbl[0]] := ProcAddr; SetInterrupt := 1; End Else Begin _IntTbl[FirstFreeIntTableEntry,0] := $cd; Move(Temp,_IntTbl[FirstFreeIntTableEntry,1],2); FirstFreeIntTableEntry := FirstFreeIntTableEntry +1; Move(PopAll,_IntTbl[FirstFreeIntTableEntry,0],SizeOf(PopAll)); IntTbl[0] := IntTbl[0]+1;IntTbl[IntTbl[0]] := ProcAddr; SetInterrupt := IntTbl[0]; End; Inline($FB); End; Procedure DisableInterrupt(IntNumber:Byte); Var i :Byte; Begin Inline($f3); If (IntNumber < 1) Or (IntNumber > IntTbl[0]) Then Exit; {Illegal value} FillChar(_IntTbl[4+IntNumber,0],3,0); Inline($fb); End; Procedure EnableInterrupt(IntNumber:Byte); Var i :Byte; Begin Inline($f3); If (IntNumber < 1) Or (IntNumber > IntTbl[0]) Then Exit; {Illegal value} _IntTbl[4+IntNumber,0] := $cd; Move(IntTbl[IntNumber],_IntTbl[4+IntNumber,1],2); Inline($fb); End; Function SetRomInterrupt:Byte; Begin SetRomInterrupt := SetInterrupt(Storeint[1]+StoreInt[2]*256); End; Procedure RemoveInterrupts; Begin Inline($f3); Move(StoreInt,Int38,3); Inline($fb); End;