{ $Id$ This file is part of the Free Pascal run time library. Copyright (c) 1993,97 by Michael Van Canneyt, member of the Free Pascal development team. See the file COPYING.FPC, included in this distribution, for details about the copyright. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. **********************************************************************} unit Crt; Interface Const { Controlling consts } Flushing=false; {if true then don't buffer output} ScreenWidth = 80; ScreenHeight = 25; { CRT modes } BW40 = 0; { 40x25 B/W on Color Adapter } CO40 = 1; { 40x25 Color on Color Adapter } BW80 = 2; { 80x25 B/W on Color Adapter } CO80 = 3; { 80x25 Color on Color Adapter } Mono = 7; { 80x25 on Monochrome Adapter } Font8x8 = 256; { Add-in for ROM font } { Mode constants for 3.0 compatibility } C40 = CO40; C80 = CO80; { Foreground and background color constants } Black = 0; Blue = 1; Green = 2; Cyan = 3; Red = 4; Magenta = 5; Brown = 6; LightGray = 7; { Foreground color constants } DarkGray = 8; LightBlue = 9; LightGreen = 10; LightCyan = 11; LightRed = 12; LightMagenta = 13; Yellow = 14; White = 15; { Add-in for blinking } Blink = 128; {Other Defaults} TextAttr : Byte = $07; LastMode : Word = 3; WindMin : Word = $0; WindMax : Word = $184f; var CheckBreak, CheckEOF, CheckSnow, DirectVideo: Boolean; Procedure AssignCrt(Var F: Text); Function KeyPressed: Boolean; Function ReadKey: Char; Procedure TextMode(Mode: Integer); Procedure Window(X1, Y1, X2, Y2: Byte); Procedure GoToXy(X: Byte; Y: Byte); Function WhereX: Byte; Function WhereY: Byte; Procedure ClrScr; Procedure ClrEol; Procedure InsLine; Procedure DelLine; Procedure TextColor(Color: Byte); Procedure TextBackground(Color: Byte); Procedure LowVideo; Procedure HighVideo; Procedure NormVideo; Procedure Delay(DTime: Word); Procedure Sound(Hz: Word); Procedure NoSound; Implementation uses Linux; { The definitions of TextRec and FileRec are in separate files. } {$i textrec.inc} {$i filerec.inc} Const OldTextAttr : byte = $07; Type TScreen=Array[1..ScreenHeight,1..ScreenWidth] of char; TScreenColors=Array[1..ScreenHeight,1..ScreenWidth] of byte; Var Scrn : TScreen; ScrnCol : TScreenColors; CurrX,CurrY : Byte; ExitSave : Pointer; {***************************************************************************** Some Handy Functions Not in the System.PP *****************************************************************************} Function Str(l:longint):string; { Return a String of the longint } var hstr : string[32]; begin System.Str(l,hstr); Str:=hstr; end; Function Max(l1,l2:longint):longint; { Return the maximum of l1 and l2 } begin if l1>l2 then Max:=l1 else Max:=l2; end; Function Min(l1,l2:longint):longint; { Return the minimum of l1 and l2 } begin if l1ox then begin XY2Ansi:=#27'['+Str(x-ox)+'C'; exit; end else begin XY2Ansi:=#27'['+Str(ox-x)+'D'; exit; end; end; if x=ox then begin if y>oy then begin XY2Ansi:=#27'['+Str(y-oy)+'B'; exit; end else begin XY2Ansi:=#27'['+Str(oy-y)+'A'; exit; end; end; if (x=1) and (oy+1=y) then XY2Ansi:=#13#10 else XY2Ansi:=#27'['+Str(y)+';'+Str(x)+'H'; End; const AnsiTbl : string[8]='04261537'; Function Attr2Ansi(Attr,OAttr:byte):string; { Convert Attr to an Ansi String, the Optimal code is calculate with use of the old OAttr } var hstr : string[16]; OFg,OBg,Fg,Bg : byte; procedure AddSep(ch:char); begin if length(hstr)>0 then hstr:=hstr+';'; hstr:=hstr+ch; end; begin if Attr=OAttr then begin Attr2Ansi:=''; exit; end; Hstr:=''; Fg:=Attr and $f; Bg:=Attr shr 4; OFg:=Attr and $f; OBg:=Attr shr 4; if (OFg<>7) or (Fg=7) or ((OFg>7) and (Fg<8)) or ((OBg>7) and (Bg<8)) then begin hstr:='0'; OFg:=7; OBg:=0; end; if (Fg>7) and (OFg<8) then begin AddSep('1'); OFg:=OFg or 8; end; if (Bg and 8)<>(OBg and 8) then begin AddSep('5'); OBg:=OBg or 8; end; if (Fg<>OFg) then begin AddSep('3'); hstr:=hstr+AnsiTbl[(Fg and 7)+1]; end; if (Bg<>OBg) then begin AddSep('4'); hstr:=hstr+AnsiTbl[(Bg and 7)+1]; end; if hstr='0' then hstr:=''; Attr2Ansi:=#27'['+hstr+'m'; end; Function Ansi2Attr(Const HStr:String;oattr:byte):byte; { Convert an Escape sequence to an attribute value, uses Oattr as the last color written } var i,j : byte; begin i:=2; if (Length(HStr)<3) or (Hstr[1]<>#27) or (Hstr[2]<>'[') then i:=255; while (i0 then OAttr:=(OAttr and $f8) or (j-1); end; '4' : begin inc(i); j:=pos(Hstr[i],AnsiTbl); if j>0 then OAttr:=(OAttr and $8f) or ((j-1) shl 4); end; 'm' : i:=length(HStr); end; end; Ansi2Attr:=OAttr; end; {***************************************************************************** Buffered StdIn/StdOut IO *****************************************************************************} const ttyIn=0; {Handles for stdin/stdout} ttyOut=1; ttyFlush:boolean=true; {Buffered Input/Output} InSize=256; OutSize=1024; var InBuf : array[0..InSize-1] of char; InCnt, InHead, InTail : longint; OutBuf : array[0..OutSize-1] of char; OutCnt : longint; {Flush Output Buffer} procedure ttyFlushOutput; begin if OutCnt>0 then begin fdWrite(ttyOut,OutBuf,OutCnt); OutCnt:=0; end; end; Function ttySetFlush(b:boolean):boolean; begin ttySetFlush:=ttyFlush; ttyFlush:=b; if ttyFlush then ttyFlushOutput; end; {Send Char to Remote} Procedure ttySendChar(c:char); Begin if OutCnt=OutSize) then ttyFlushOutput; End; {Send String to Remote} procedure ttySendStr(const hstr:string); var i : word; begin for i:=1to length(hstr) do ttySendChar(hstr[i]); if ttyFlush then ttyFlushOutput; end; {Get Char from Remote} function ttyRecvChar:char; var Readed,i : word; begin {Buffer Empty? Yes, Input from StdIn} if (InHead=InTail) then begin {Calc Amount of Chars to Read} i:=InSize-InHead; if InTail>InHead then i:=InTail-InHead; {Read} Readed:=fdRead(TTYIn,InBuf[InHead],i); {Increase Counters} inc(InCnt,Readed); inc(InHead,Readed); {Wrap if End has Reached} if InHead>=InSize then InHead:=0; end; {Check Buffer} if (InCnt=0) then ttyRecvChar:=#0 else begin ttyRecvChar:=InBuf[InTail]; dec(InCnt); inc(InTail); if InTail>=InSize then InTail:=0; end; end; {***************************************************************************** Screen Routines not Window Depended *****************************************************************************} procedure ttyGotoXY(x,y:byte); { Goto XY on the Screen, if a value is 0 the goto the current postion of that value and always recalc the ansicode for it } begin if x=0 then begin x:=CurrX; CurrX:=$ff; end; if y=0 then begin y:=CurrY; CurrY:=$ff; end; ttySendStr(XY2Ansi(x,y,CurrX,CurrY)); CurrX:=x; CurrY:=y; end; procedure ttyColor(a:byte); { Set Attribute to A, only output if not the last attribute is set } begin if a<>TextAttr then begin ttySendStr(Attr2Ansi(a,TextAttr)); TextAttr:=a; OldTextAttr:=a; end; end; procedure ttyWrite(const s:string); { Write a string to the output, memory copy and Current X&Y are also updated } var i : word; begin ttySendStr(s); {Update MemCopy} for i:=1to length(s) do begin Scrn[CurrY,CurrX]:=s[i]; ScrnCol[CurrY,CurrX]:=TextAttr; inc(CurrX); if CurrX>ScreenWidth then CurrX:=ScreenWidth; end; end; Function WinMinX: Byte; { Current Minimum X coordinate } Begin WinMinX:=(WindMin and $ff)+1; End; Function WinMinY: Byte; { Current Minimum Y Coordinate } Begin WinMinY:=(WindMin shr 8)+1; End; Function WinMaxX: Byte; { Current Maximum X coordinate } Begin WinMaxX:=(WindMax and $ff)+1; End; Function WinMaxY: Byte; { Current Maximum Y coordinate; } Begin WinMaxY:=(WindMax shr 8) + 1; End; Function FullWin:boolean; { Full Screen 80x25? Window(1,1,80,25) is used, allows faster routines } begin FullWin:=(WindMax-WindMin=$184f); end; procedure LineWrite(temp:String); { Write a Line to the screen, doesn't write on 80,25 under Dos the Current CurrX is set to WinMax. NO MEMORY UPDATE! } begin CurrX:=WinMaxX+1; if (CurrX>=ScreenWidth) then CurrX:=WinMaxX; ttySendStr(Temp); end; procedure DoEmptyLine(y,xl,xh:byte); { Write an Empty line at Row Y from Col Xl to XH, Memory is also updated } begin ttyGotoXY(xl,y); LineWrite(Space(xh-xl+1)); FillChar(Scrn[y],ScreenWidth,' '); FillChar(ScrnCol[y],ScreenWidth,TextAttr); end; procedure DoScrollLine(y1,y2,xl,xh:byte); { Move Line y1 to y2, use only columns Xl-Xh, Memory is updated also } var Temp : string; OldAttr, x,attr : byte; begin ttyGotoXY(xl,y2); OldAttr:=$ff; Temp:=''; For x:=xl To xh Do Begin attr:=ScrnCol[y1,x]; if attr<>OldAttr then begin temp:=temp+Attr2Ansi(Attr,OldAttr); OldAttr:=Attr; end; Temp:=Temp+Scrn[y1,x]; if (x=xh) or (length(Temp)>240) then begin LineWrite(Temp); Temp:=''; end; End; {Update memory copy} Move(Scrn[y1,1],Scrn[y2,1],ScreenWidth); Move(ScrnCol[y1,1],ScrnCol[y2,1],ScreenWidth); end; Procedure TextColor(Color: Byte); { Switch foregroundcolor } Begin ttyColor((Color and $8f) or (TextAttr and $70)); End; Procedure TextBackground(Color: Byte); { Switch backgroundcolor } Begin ttyColor((Color shl 4) or (TextAttr and $0f)); End; Procedure HighVideo; { Set highlighted output. } Begin TextColor(TextAttr Or $08); End; Procedure LowVideo; { Set normal output } Begin TextColor(TextAttr And $77); End; Procedure NormVideo; { Set normal back and foregroundcolors. } Begin TextColor(7); TextBackGround(0); End; Procedure GotoXy(X: Byte; Y: Byte); { Go to coordinates X,Y in the current window. } Begin If (X>0) and (X<=WinMaxX- WinMinX+1) and (Y>0) and (Y<=WinMaxY-WinMinY+1) Then Begin Inc(X,WinMinX-1); Inc(Y,WinMinY-1); ttyGotoXY(x,y); End; End; Procedure Window(X1, Y1, X2, Y2: Byte); { Set screen window to the specified coordinates. } Begin if (X1>X2) or (X2>ScreenWidth) or (Y1>Y2) or (Y2>ScreenHeight) then exit; WindMin:=((Y1-1) Shl 8)+(X1-1); WindMax:=((Y2-1) Shl 8)+(X2-1); GoToXY(1,1); End; Procedure ClrScr; { Clear the current window, and set the cursor on x1,y1 } Var CY : Integer; oldflush : boolean; Begin oldflush:=ttySetFlush(Flushing); if FullWin then begin ttySendStr(#27'[H'#27'[2J'); CurrX:=1; CurrY:=1; FillChar(Scrn,sizeof(Scrn),' '); FillChar(ScrnCol,sizeof(ScrnCol),TextAttr); end else begin For Cy:=WinMinY To WinMaxY Do DoEmptyLine(Cy,WinMinX,WinMaxX); GoToXY(1,1); end; ttySetFlush(oldflush); End; Procedure ClrEol; { Clear from current position to end of line. } Begin if FullWin then ttySendStr(#27'[K') else begin ttySendStr(Space(WinMaxX-CurrX)); ttyGotoXY(0,CurrY); end; End; Function WhereX: Byte; { Return current X-position of cursor. } Begin WhereX:=CurrX-WinMinX+1; End; Function WhereY: Byte; { Return current Y-position of cursor. } Begin WhereY:=CurrY-WinMinY+1; End; Procedure ScrollScrnRegionUp(xl,yl,xh,yh, count: Byte); { Scroll the indicated region count lines up. The empty lines are filled with blanks in the current color. The screen position is restored afterwards. } Var y,oldx,oldy : byte; oldflush : boolean; Begin oldflush:=ttySetFlush(Flushing); oldx:=CurrX; oldy:=CurrY; {Scroll} For y:=yl to yh-count do DoScrollLine(y+count,y,xl,xh); {Restore TextAttr} ttySendStr(Attr2Ansi(TextAttr,$ff)); {Fill the rest with empty lines} for y:=yh-count+1 to yh do DoEmptyLine(y,xl,xh); {Restore current position} ttyGotoXY(OldX,OldY); ttySetFlush(oldflush); End; Procedure ScrollScrnRegionDown(xl,yl,xh,yh, count: Byte); { Scroll the indicated region count lines down. The empty lines are filled with blanks in the current color. The screen position is restored afterwards. } Var y,oldx,oldy : byte; oldflush : boolean; Begin oldflush:=ttySetFlush(Flushing); oldx:=CurrX; oldy:=CurrY; {Scroll} for y:=yh downto yl+count do DoScrollLine(y-count,y,xl,xh); {Restore TextAttr} ttySendStr(Attr2Ansi(TextAttr,$ff)); {Fill the rest with empty lines} for y:=yl to yl+count-1 do DoEmptyLine(y,xl,xh); {Restore current position} ttyGotoXY(OldX,OldY); ttySetFlush(oldflush); End; Procedure ScrollWindow(xl,yl,xh,yh : Byte; count: LongInt); { Scroll the indicated region up or down, depending on the sign of count. } begin If ((xl>xh) or (xh>ScreenWidth)) or ((yl>yh) or (yl>ScreenHeight)) or (abs(Count)>yh-yl+1) then exit; If count<0 then ScrollScrnRegionDown (xl,yl,xh,yh,abs(count)) else ScrollScrnRegionUp (xl,yl,xh,yh,count); end; {************************************************************************* KeyBoard *************************************************************************} Const KeyBufferSize = 20; var KeyBuffer : Array[0..KeyBufferSize-1] of Char; KeyPut, KeySend : Byte; Procedure PushKey(Ch:char); Var Tmp : Word; Begin Tmp:=KeyPut; Inc(KeyPut); If KeyPut>=KeyBufferSize Then KeyPut:=0; If KeyPut<>KeySend Then KeyBuffer[Tmp]:=Ch Else KeyPut:=Tmp; End; Function PopKey:char; Begin If KeyPut<>KeySend Then Begin PopKey:=KeyBuffer[KeySend]; Inc(KeySend); If KeySend>=KeyBufferSize Then KeySend:=0; End Else PopKey:=#0; End; Procedure PushExt(b:byte); begin PushKey(#0); PushKey(chr(b)); end; const AltKeyStr : string[38]='qwertyuiopasdfghjklzxcvbnm1234567890-='; AltCodeStr : string[38]=#016#017#018#019#020#021#022#023#024#025#030#031#032#033#034#035#036#037#038+ #044#045#046#047#048#049#050#120#121#122#123#124#125#126#127#128#129#130#131; Function FAltKey(ch:char):byte; var Idx : byte; Begin Idx:=Pos(ch,AltKeyStr); if Idx>0 then FAltKey:=byte(AltCodeStr[Idx]) else FAltKey:=0; End; Function KeyPressed:Boolean; var fdsin : fdSet; Begin if (KeySend<>KeyPut) or (InCnt>0) then KeyPressed:=true else begin FD_Zero(fdsin); fd_Set(TTYin,fdsin); Keypressed:=(Select(TTYIn+1,@fdsin,nil,nil,0)>0); end; End; Function ReadKey:char; Var ch : char; OldState, State : Word; Begin {Check Buffer first} if KeySend<>KeyPut then begin ReadKey:=PopKey; exit; end; {Wait for Key} repeat until keypressed; ch:=ttyRecvChar; {Esc Found ?} If (ch=#27) then begin State:=1; Delay(10); while (State<>0) and (KeyPressed) do begin ch:=ttyRecvChar; OldState:=State; State:=0; case OldState of 1 : begin {Esc} case ch of 'a'..'z', '0'..'9', '-','=' : PushExt(FAltKey(ch)); #10 : PushKey(#10); '[' : State:=2; else begin PushKey(ch); PushKey(#27); end; end; end; 2 : begin {Esc[} case ch of '[' : State:=3; 'A' : PushExt(72); 'B' : PushExt(80); 'C' : PushExt(77); 'D' : PushExt(75); 'G' : PushKey('5'); 'H' : PushExt(71); 'K' : PushExt(79); '1' : State:=4; '2' : State:=5; '3' : PushExt(83); '4' : PushExt(79); '5' : PushExt(73); '6' : PushExt(81); else begin PushKey(ch); PushKey('['); PushKey(#27); end; end; if ch in ['3'..'6'] then State:=255; end; 3 : begin {Esc[[} case ch of 'A' : PushExt(59); 'B' : PushExt(60); 'C' : PushExt(61); 'D' : PushExt(62); 'E' : PushExt(63); end; end; 4 : begin case ch of '~' : PushExt(71); '7' : PushExt(64); '8' : PushExt(65); '9' : PushExt(66); end; if (Ch<>'~') then State:=255; end; 5 : begin case ch of '~' : PushExt(82); '0' : pushExt(67); '1' : PushExt(68); '3' : PushExt(133); '4' : PushExt(134); end; if (Ch<>'~') then State:=255; end; 255 : ; end; if State<>0 then Delay(10); end; if State=1 then PushKey(ch); end else Begin case ch of #127 : PushExt(83); else PushKey(ch); end; End; ReadKey:=PopKey; End; Procedure Delay(DTime: Word); { Wait for DTime milliseconds. } Begin Select(0,nil,nil,nil,DTime); End; {**************************************************************************** HighLevel Crt Functions ****************************************************************************} procedure DoLn; begin if CurrY=WinMaxY then begin if FullWin then begin ttySendStr(#10#13); CurrX:=WinMinX; CurrY:=WinMaxY; end else begin ScrollScrnRegionUp(WinMinX,WinMinY,WinMaxX,WinMaxY,1); ttyGotoXY(WinMinX,WinMaxY); end; end else ttyGotoXY(WinMinX,CurrY+1); end; var Lastansi : boolean; AnsiCode : string[32]; Procedure DoWrite(const s:String); { Write string to screen, parse most common AnsiCodes } var found, OldFlush : boolean; x,y : byte; i,j, SendBytes : word; function AnsiPara(var hstr:string):byte; var k,j : byte; code : word; begin j:=pos(';',hstr); if j=0 then j:=length(hstr); val(copy(hstr,3,j-3),k,code); Delete(hstr,3,j-2); if k=0 then k:=1; AnsiPara:=k; end; procedure SendText; var LeftX : word; begin while (SendBytes>0) do begin LeftX:=WinMaxX-CurrX+1; if (SendBytes>LeftX) or (CurrX+SendBytes=81) then begin ttyWrite(Copy(s,i-SendBytes,LeftX)); dec(SendBytes,LeftX); DoLn; end else begin ttyWrite(Copy(s,i-SendBytes,SendBytes)); SendBytes:=0; end; end; end; begin oldflush:=ttySetFlush(Flushing); { Support textattr:= changing } if OldTextAttr<>TextAttr then begin i:=TextAttr; TextAttr:=OldTextAttr; ttyColor(i); end; { write the stuff } SendBytes:=0; i:=1; while (i<=length(s)) do begin if (s[i]=#27) or (LastAnsi) then begin SendText; LastAnsi:=false; j:=i; found:=false; while (j<=length(s)) and (not found) do begin found:=not (s[j] in [#27,'[','0'..'9',';','?']); inc(j); end; Ansicode:=AnsiCode+Copy(s,i,j-i); if found then begin case AnsiCode[length(AnsiCode)] of 'm' : ttyColor(Ansi2Attr(AnsiCode,TextAttr)); 'H' : begin {No other way :( Coz First Para=Y} y:=AnsiPara(AnsiCode); x:=AnsiPara(AnsiCode); GotoXY(y,x); end; 'J' : if AnsiPara(AnsiCode)=2 then ClrScr; 'K' : ClrEol; 'A' : GotoXY(CurrX,Max(CurrY-AnsiPara(AnsiCode),WinMinY)); 'B' : GotoXY(CurrX,Min(CurrY+AnsiPara(AnsiCode),WinMaxY)); 'C' : GotoXY(Min(CurrX+AnsiPara(AnsiCode),WinMaxX),CurrY); 'D' : GotoXY(Max(CurrX-AnsiPara(AnsiCode),WinMinX),CurrY); 'h' : ; {Stupid Thedraw [?7h Code} else found:=false; end; end else begin LastAnsi:=true; found:=true; end; {Clear AnsiCode?} if not LastAnsi then AnsiCode:=''; {Increase Idx or SendBytes} if found then i:=j-1 else inc(SendBytes); end else begin LastAnsi:=false; case s[i] of #13 : begin {CR} SendText; ttyGotoXY(WinMinX,CurrY); end; #10 : begin {NL} SendText; DoLn; end; #9 : begin {Tab} SendText; ttyWrite(Space(9-((CurrX-1) and $08))); end; else inc(SendBytes); end; end; inc(i); end; if SendBytes>0 then SendText; ttySetFlush(oldFLush); end; Function CrtWrite(Var F: TextRec): Integer; { Top level write function for CRT } Var Temp : String; Begin Move(F.BufPTR^[0],Temp[1],F.BufPos); temp[0]:=chr(F.BufPos); DoWrite(Temp); F.BufPos:=0; CrtWrite:=0; End; Function CrtClose(Var F: TextRec): Integer; { Close CRT associated file. } Begin F.Mode:=fmClosed; CrtClose:=0; End; Function CrtOpen(Var F: TextRec): Integer; { Open CRT associated file. } Begin If F.Mode = fmOutput Then CrtOpen:=0 Else CrtOpen:=5; End; Function CrtRead(Var F: TextRec): Integer; { Read from CRT associated file. } Begin F.BufEnd:=fdRead(LongInt(F.Handle), F.BufPtr^, F.BufSize); F.BufPos:=F.BufEnd; CrtWrite(F); CrtRead:=0; End; Function CrtInOut(Var F: TextRec): Integer; { InOut function for CRT associated file. } Begin Case F.Mode of fmInput: CrtInOut:=CrtRead(F); fmOutput: CrtInOut:=CrtWrite(F); End; End; Procedure AssignCrt(Var F: Text); { Assign a file to the console. All output on file goes to console instead. } Begin TextRec(F).Mode:=fmClosed; TextRec(F).BufSize:=SizeOf(TextBuf); TextRec(F).BufPtr:=@TextRec(F).Buffer; TextRec(F).BufPos:=0; TextRec(F).OpenFunc:=@CrtOpen; TextRec(F).InOutFunc:=@CrtInOut; TextRec(F).FlushFunc:=@CrtWrite; TextRec(F).CloseFunc:=@CrtClose; TextRec(F).Name[0]:='.'; TextRec(F).Name[1]:=#0; End; Procedure DelLine; { Delete current line. Scroll subsequent lines up } Begin ScrollScrnRegionUp(WinMinX, CurrY, WinMaxX, WinMaxY, 1); End; Procedure InsLine; { Insert line at current cursor position. Scroll subsequent lines down. } Begin ScrollScrnRegionDown(WinMinX, CurrY, WinMaxX, WinMaxY, 1); End; Procedure Sound(Hz: Word); { Does nothing under linux } begin end; Procedure NoSound; { Does nothing under linux } begin end; Procedure TextMode(Mode: Integer); { Only Clears Screen under linux } begin ClrScr; end; {****************************************************************************** Initialization ******************************************************************************} var OldIO : TermIos; Procedure SetRawMode(b:boolean); Var Tio : Termios; Begin if b then begin TCGetAttr(1,Tio); OldIO:=Tio; CFMakeRaw(Tio); Tio.C_IFlag:=Tio.C_IFlag or ICRNL; end else Tio:=OldIO; TCSetAttr(1,TCSANOW,Tio); End; procedure GetXY(var x,y:byte); var fds : fdSet; i,j, readed : longint; buf : array[0..255] of char; s : string[16]; begin x:=0; y:=0; s:=#27'[6n'; fdWrite(0,s[1],length(s)); FD_Zero(fds); FD_Set(1,fds); if (Select(2,@fds,nil,nil,1000)>0) then begin readed:=fdRead(1,buf,sizeof(buf)); i:=0; while (i+4#27) and (buf[i+1]<>'[') do inc(i); if i+40 then begin Val(Copy(s,1,i-1),y); j:=Pos('R',s); if j=0 then j:=length(s)+1; Val(Copy(s,i+1,j-i),x); end; end; end; end; Procedure CrtExit; { We need to restore normal keyboard mode upon exit !! } Begin ttyFlushOutput; SetRawMode(False); ExitProc:=ExitSave; End; Begin {Hook Exit} ExitSave:=ExitProc; ExitProc:=@CrtExit; {Assign Input and Output to Crt} AssignCrt(Output); AssignCrt(Input); TextRec(Output).Mode:=fmOutput; TextRec(Input).Mode:=fmInput; {Set default Terminal Settings} SetRawMode(True); {Get Current X&Y or Reset to Home} GetXY(CurrX,CurrY); if (CurrX=0) then begin CurrX:=1; CurrY:=1; ttySendStr(#27'[H'); end; {Reset Attribute (TextAttr=7 at startup)} ttySendStr(#27'[m'); End. { $Log$ Revision 1.1 1998-03-25 11:18:43 root Initial revision Revision 1.10 1998/03/16 23:38:52 peter + support for textattr:= setting between writes Revision 1.9 1998/01/26 12:00:45 michael + Added log at the end revision 1.8 date: 1998/01/20 00:18:14; author: peter; state: Exp; lines: +2 -2 * column 80 works now the same as under dos (wraps to next line) ---------------------------- revision 1.7 date: 1998/01/19 10:04:02; author: michael; state: Exp; lines: +2 -2 * Bugfix from Peter Vreman. ---------------------------- revision 1.6 date: 1998/01/05 13:43:17; author: michael; state: Exp; lines: +129 -109 * Minor bugfixes, bugs appeared when making/compiling examples. (by Peter Vreman) ---------------------------- revision 1.5 date: 1997/12/28 17:53:04; author: michael; state: Exp; lines: +52 -4 * Bug fixed : CR now sends CR/LF; importat for Readln. (Peter Vreman fixed this) * GetXY function now tries to read initial conditions. ---------------------------- revision 1.4 date: 1997/12/19 15:22:14; author: michael; state: Exp; lines: +10 -22 * changed setrawmode to use termios functions in linux unit. ---------------------------- revision 1.3 date: 1997/12/15 12:44:56; author: michael; state: Exp; lines: +6 -1 * added key handling for xterm. ---------------------------- revision 1.2 date: 1997/12/01 12:31:14; author: michael; state: Exp; lines: +12 -16 + Added copyright reference in header. ---------------------------- revision 1.1 date: 1997/11/27 08:33:54; author: michael; state: Exp; Initial revision ---------------------------- revision 1.1.1.1 date: 1997/11/27 08:33:54; author: michael; state: Exp; lines: +0 -0 FPC RTL CVS start ============================================================================= Pre CVS Log: Version Date What/who ------- ---- ------- 0.1 96/97 Written by Mark May (mmay@ndaco.com) Major overhaul to improve screen output performance by Michael Van Canneyt (michael@tfdec1.fys.kuleuven.ac.be) Also added some documentation. Balazs Scheidler changed color handling to lookup-table 0.2 7/97 changes by Hans-Peter Zorn to make key-handling work in an xterm. Alt-key becomes ESC + Key. 0.3 10/97 Modified by Matthias K"oppe : Fixed key decoding for function keys F6..F12 0.4 11/97 Modified by Peter Vreman Optimised keyboard handling. 0.5 11/97 Modified by Peter Vreman Inplemented bigger buffer for output, ANSI codes are handled too. Unit now depends on linux unit only. 0.6 01/98 Modified by Peter Vreman Implemented missing function/procedures, the interface is now 100% the same BP7. The screen is not cleared at startup anymore. The cursor stays at the current position. }