home *** CD-ROM | disk | FTP | other *** search
- UNIT IOSTUFF;
- INTERFACE
- USES CRT,DOS;
- TYPE
- AnyStr = String[80];
- ShortStr = String[20];
- LongStr = String[160];
- Map = Record
- ScrCh : Char;
- ScrAt : Byte;
- End;
- Screen = Array[1..25,1..80] of Map;
- VAR
- Color : Boolean;
- CS : Screen Absolute $B800:0000;
- MS : Screen Absolute $B000:0000;
- PROCEDURE MoveToScreen(Var Source,Dest; Len: Integer);
- PROCEDURE MoveFromScreen(Var Source,Dest; Len: Integer);
- PROCEDURE SaveScreen(NS:Integer);
- PROCEDURE RestoreScreen(NS:Integer);
- PROCEDURE SavePartScreen(X1,Y1,X2,Y2:Integer);
- PROCEDURE RestorePartScreen(X1,Y1,X2,Y2:Integer);
- PROCEDURE SetColor(F,B:integer);
- PROCEDURE WriteSt(St:AnyStr;X,Y:Integer);
- PROCEDURE WriteCh(Ch:Char;X,Y:Integer);
- PROCEDURE FillScr(Ch:Char);
- FUNCTION ReadFromScr(X,Y,Len:Integer):AnyStr;
- FUNCTION GetCh(X,Y:Integer):Char;
- PROCEDURE Border(X1,Y1,X2,Y2: Integer; Header:AnyStr);
- PROCEDURE SBorder(X1,Y1,X2,Y2: Integer; Header:AnyStr);
- PROCEDURE Beep;
- PROCEDURE Linecursor;
- PROCEDURE BigCursor;
- PROCEDURE HideCursor;
- PROCEDURE ShowCursor;
- IMPLEMENTATION
- VAR
- ScreenHold : Array[0..5] of Screen;
- PartHold : Screen;
- R : Registers;
- NS : Integer;
- {======================================================================}
- PROCEDURE CheckColorAdapter;
-
- { Checks for the existence of a Color adapter. Sets Color variable }
- { to true if it finds the CGA else sets Color to false. Color is }
- { an external variable that can be checked anywhere in your program }
- { to verify if a CGA is present or not. }
-
- BEGIN
- If (Mem[0000:1040] and 48) <> 48 { Check memory at 1040 }
- then Color := true
- else Color := False;
- END;
-
- {======================================================================}
- PROCEDURE MoveToScreen(Var Source,Dest; Len: Integer);
-
- { Similar to Turbo Move but assumes the destination is in video }
- { memory and thus writes only during retrace to avoid snow. }
- { These are used only in Save and Restore Screen routines below. }
- { These routines are very fast and can be used as the basic }
- { building blocks for other direct screen IO. I have used Turbo }
- { Pascals regular Write routines whereever possible because they }
- { are sufficiently fast and much more understandable and stable. }
-
- Begin
- Len:=Len Shr 1;
- Inline($1E/$55/$BA/$DA/$03/$C5/$B6/ Source /$C4/$BE/ Dest /$8B/$8E/
- Len /$FC/$AD/$89/$C5/$B4/$09/$EC/$D0/$D8/$72/$FB/$FA/$EC/
- $20/$E0/$74/$FB/$89/$E8/$AB/$FB/$E2/$EA/$5D/$1F);
- End;
-
- {======================================================================}
- PROCEDURE MoveFromScreen(Var Source,Dest; Len: Integer);
-
- { Similar to Turbo Move but assumes the source is in video }
- { memory and thus writes only during retrace to avoid snow. }
-
- Begin
- Len:=Len Shr 1;
- Inline($1E/$55/$BA/$DA/$03/$C5/$B6/ Source /$C4/$BE/ Dest /$8B/$8E/
- Len /$FC/$EC/$D0/$D8/$72/$FB/$FA/$EC/$D0/$D8/$73/$FB/$AD/
- $FB/$AB/$E2/$F0/$5D/$1F);
- End;
-
- {======================================================================}
- PROCEDURE SaveScreen(NS:Integer);
- BEGIN
- If Color then MoveFromScreen(CS,ScreenHold[NS],4000)
- else Move(MS,ScreenHold[NS],4000);
- END;
-
- {======================================================================}
- PROCEDURE RestoreScreen(NS:Integer);
- BEGIN
- If Color then MoveToScreen(ScreenHold[NS],CS,4000)
- else Move(ScreenHold[NS],MS,4000);
- END;
-
- {======================================================================}
- PROCEDURE SavePartScreen(X1,Y1,X2,Y2:Integer);
- VAR
- II,XLen : Integer;
- BEGIN
- XLen := (X2-X1+1)*2;
- For II := Y1 to Y2 do begin
- If Color then MoveFromScreen(CS[II,X1],ScreenHold[0,II,X1],XLen) { avoid snow }
- else Move(MS[II,X1],ScreenHold[0,II,X1],XLen);
- End;
- END;
-
- {======================================================================}
- PROCEDURE RestorePartScreen(X1,Y1,X2,Y2:Integer);
- VAR
- II,XLen : Integer;
- BEGIN
- XLen := (X2-X1+1)*2;
- For II := Y1 to Y2 do begin
- If Color then MoveToScreen(ScreenHold[0,II,X1],CS[II,X1],XLen) { avoid snow }
- else Move(ScreenHold[0,II,X1],MS[II,X1],XLen);
- End;
- END;
-
- {======================================================================}
- PROCEDURE SetColor(F,B:integer);
-
- { This sets variable TextAttr in Unit CRT to the colors F and B }
- { The approach is equivalent to TextColor(F); TextBackground(B);}
- { except blink is handled directly (any B > 7)}
-
- BEGIN
- TextAttr := F + B * 16;
- END;
-
- {======================================================================}
- PROCEDURE WriteSt(St:AnyStr;X,Y:Integer);
-
- { Much output is strings. This routine saves all the GOTOXYs}
-
- BEGIN
- GoToXY(X,Y);
- Write(St);
- END;
-
- {======================================================================}
- PROCEDURE WriteCh(Ch:Char;X,Y:Integer);
-
- { Service 9, Intr 10 is used because it will write the "unwriteable" }
- { low numbered ASCII characters like #07, which produces a beep if }
- { written with a regular Write statement }
-
- BEGIN
- GoToXY(X,Y); { Put cursor at location }
- R.AH := $09; { Load A Hi with Service 9 }
- R.BL := TextAttr; { Load B Lo with Attribute }
- R.BH := 0; { Load B Hi with Screen 0 }
- R.AL := Ord(Ch); { Load A Lo with Character to write }
- R.CX := 1; { Load C with number of times to write (1) }
- Intr($10,R); { Do Interrupt 10 }
-
- END;
-
- {======================================================================}
- PROCEDURE WriteManyCh(Ch:Char;X,Y,Num:Integer);
-
- { Like WriteCh above except repeats the character Num times. }
-
- BEGIN
- GoToXY(X,Y);
- R.AH := $09;
- R.BL := TextAttr;
- R.BH := 0;
- R.AL := Ord(Ch);
- R.CX := Num;
- Intr($10,R);
-
- END;
-
- {======================================================================}
- PROCEDURE FillScr(Ch:Char);
-
- { Fills the screen with the character passed }
-
- BEGIN
- GoToXY(1,1);
- R.AH := $09;
- R.BL := TextAttr;
- R.BH := 0;
- R.AL := Ord(Ch);
- R.CX := 2000;
- Intr($10,R);
-
- END;
-
- {======================================================================}
- FUNCTION ReadFromScr(X,Y,Len:Integer):AnyStr;
-
- { Uses service 8 of Intr 10 to read a string off the screen }
- { The cursor tends to flicker across the screen if this routine }
- { is used continuously so the cursor is turned off while it is }
- { working by flipping bit 5 of the top scan line to 1 }
-
- VAR
- TempStr : AnyStr;
- II,L : Integer;
- BEGIN
- { turn off the cursor }
- R.AX := $0300; { Service 3 }
- Intr($10,R); { Interrupt 10 to get cursor scan lines}
- R.CX := R.CX or $2000; { Set bit 5 of top scan line to 1 }
- R.AX := $0100; { Service 1 }
- Intr($10,R); { Interrupt 10 to turn off }
-
- L := 0;
- For II := 1 to Len Do Begin
- GoToXY(X+II-1,Y); { Locate cursor }
-
- { Read a character from the screen }
- R.AX := $0800; { Service 8 }
- R.BH := 0; { Screen 0 }
- Intr($10,R); { Interrupt 10 }
- TempStr[II] := Chr(R.AL); { Char returned in AL }
- If TempStr[II] <> ' ' then L := II { if non blank remember length }
- End;
- { flip the cursor back on }
- R.AX := $0300; { Service 3 again }
- Intr($10,R); { Interrupt 10 to get scan lines }
- R.CX := R.CX and $DFFF; { Flip bit 5 of top scan line to 0 }
- R.AX := $0100; { Service 1 }
- Intr($10,R); {Interrupt 10 to turn on cursor }
-
- TempStr[0] := Chr(L); { Set the string length to last non blank char. }
- ReadFromScr := TempStr; { Set function result to temporary string }
- END;
- {======================================================================}
- FUNCTION GetCh(X,Y:Integer):Char;
-
- { Reads a character from the screen using service 8, Intr 10 }
-
- BEGIN
-
- GoToXY(X,Y); { Locate the cursor }
-
- R.AX := $0800; { Service 8 }
- R.BH := 0; { Screen 0 }
- Intr($10,R); { Interrupt 10 }
- GetCh := Chr(R.AL); { Character returned in AL }
-
- END;
-
- {======================================================================}
- PROCEDURE Border(X1,Y1,X2,Y2: Integer; Header:AnyStr);
-
- { Prints a double line box border on the screen with corners at }
- { X1,Y1 and X2,Y2. The Header will be center on the top. }
-
- VAR Indx : Integer;
- BEGIN
- WriteCh('╔',X1,Y1); { Upper left corner }
- WriteManyCh('═',X1+1,Y1,X2-X1-1); { Top }
- WriteCh('╗',X2,Y1); { Upper right corner }
- For Indx := Y1+1 to Y2-1 do { Both sides }
- Begin
- WriteCh('║',X1,Indx);
- WriteCh('║',X2,Indx);
- End;
- WriteCh('╚',X1,Y2); { lower left corner }
- WriteManyCh('═',X1+1,Y2,X2-X1-1); { bottom }
- WriteCh('╝',X2,Y2); { lower right corner }
- If Header > '' then { Center header }
- WriteSt('╡'+Header+'╞',X1+(X2-X1) div 2-((Length(Header)+1) div 2),Y1);
- END;
-
- {======================================================================}
- PROCEDURE SBorder(X1,Y1,X2,Y2: Integer; Header:AnyStr);
-
- { Prints a single line box border on the screen with corners at }
- { X1,Y1 and X2,Y2. The Header will be centered on the top. }
-
- VAR Indx : Integer;
- BEGIN
- WriteCh('┌',X1,Y1); { Upper left corner }
- WriteManyCh('─',X1+1,Y1,X2-X1-1); { Top }
- WriteCh('┐',X2,Y1); { Upper right corner }
- For Indx := Y1+1 to Y2-1 do { Both sides }
- Begin
- WriteCh('│',X1,Indx);
- WriteCh('│',X2,Indx);
- End;
- WriteCh('└',X1,Y2); { lower left corner }
- WriteManyCh('─',X1+1,Y2,X2-X1-1); { bottom }
- WriteCh('┘',X2,Y2); { lower right corner }
- If Header > '' then { Center header }
- WriteSt('┤'+Header+'├',X1+(X2-X1) div 2-((Length(Header)+1) div 2),Y1);
- END;
-
- {======================================================================}
- PROCEDURE Beep;
- BEGIN
- Sound(550); Delay(200); Nosound;
- END;
-
- {======================================================================}
- PROCEDURE Linecursor;
-
- { Sets the cursor to two lines. Checks type of adapter because }
- { Monochrome has more scan lines than CGA/EGA }
-
- Begin
- R.AX := $0100; { Service 1 }
- If (Mem[0000:1040]and 48)<>48 { Check for CGA }
- then R.CX := $0607 { Color Adapter }
- else R.CX := $0C0D; { Mono Adapter }
- Intr($10,R); { Interrupt 10 }
- End;
-
- {======================================================================}
- PROCEDURE Bigcursor;
-
- { Sets the cursor to a large block to signify insert. As above }
- { checks adapter }
- Begin
- R.AX := $0100; { Service 1 }
- If (Mem[0000:1040]and 48)<>48 { Check for CGA }
- then R.CX := $0107 { Color Adapter }
- else R.CX := $010D; { Mono Adapter }
- Intr($10,R); { Interrupt 10 }
- End;
-
- {======================================================================}
- PROCEDURE HideCursor;
-
- { Turns cursor off by flipping bit 5 of top scan line to 1. }
- { This is a better cursor hiding technique than moving it off }
- { the screen because you can still do GoToXY and the cursor is }
- { invisible. }
-
- BEGIN
- R.AX := $0300; { Service 3 }
- Intr($10,R); { Intr 10. Get scan lines}
- R.CX := R.CX or $2000; { Set bit 5 to 1}
- R.AX := $0100; { Service 1 }
- Intr($10,R); { Intr 10 resets cursor}
- END;
-
- {======================================================================}
- PROCEDURE ShowCursor;
- { Turns cursor on by flipping bit 5 of Top Scan Line back to 0 }
-
- BEGIN
- R.AX := $0300; { Service 3 }
- Intr($10,R); { Intr 10. Get scan lines}
- R.CX := R.CX and $DFFF; { Set bit 5 to 0}
- R.AX := $0100; { Service 1 }
- Intr($10,R); { Intr 10 resets cursor}
- END;
-
- {======================================================================}
-
- BEGIN {Initilization}
- CheckColorAdapter;
- END. {OF UNIT}