crt.pp 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1993,97 by Michael Van Canneyt,
  5. member of the Free Pascal development team.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit Crt;
  13. Interface
  14. Const
  15. { Controlling consts }
  16. Flushing=false; {if true then don't buffer output}
  17. ScreenWidth = 80;
  18. ScreenHeight = 25;
  19. { CRT modes }
  20. BW40 = 0; { 40x25 B/W on Color Adapter }
  21. CO40 = 1; { 40x25 Color on Color Adapter }
  22. BW80 = 2; { 80x25 B/W on Color Adapter }
  23. CO80 = 3; { 80x25 Color on Color Adapter }
  24. Mono = 7; { 80x25 on Monochrome Adapter }
  25. Font8x8 = 256; { Add-in for ROM font }
  26. { Mode constants for 3.0 compatibility }
  27. C40 = CO40;
  28. C80 = CO80;
  29. { Foreground and background color constants }
  30. Black = 0;
  31. Blue = 1;
  32. Green = 2;
  33. Cyan = 3;
  34. Red = 4;
  35. Magenta = 5;
  36. Brown = 6;
  37. LightGray = 7;
  38. { Foreground color constants }
  39. DarkGray = 8;
  40. LightBlue = 9;
  41. LightGreen = 10;
  42. LightCyan = 11;
  43. LightRed = 12;
  44. LightMagenta = 13;
  45. Yellow = 14;
  46. White = 15;
  47. { Add-in for blinking }
  48. Blink = 128;
  49. {Other Defaults}
  50. TextAttr : Byte = $07;
  51. LastMode : Word = 3;
  52. WindMin : Word = $0;
  53. WindMax : Word = $184f;
  54. var
  55. CheckBreak,
  56. CheckEOF,
  57. CheckSnow,
  58. DirectVideo: Boolean;
  59. Procedure AssignCrt(Var F: Text);
  60. Function KeyPressed: Boolean;
  61. Function ReadKey: Char;
  62. Procedure TextMode(Mode: Integer);
  63. Procedure Window(X1, Y1, X2, Y2: Byte);
  64. Procedure GoToXy(X: Byte; Y: Byte);
  65. Function WhereX: Byte;
  66. Function WhereY: Byte;
  67. Procedure ClrScr;
  68. Procedure ClrEol;
  69. Procedure InsLine;
  70. Procedure DelLine;
  71. Procedure TextColor(Color: Byte);
  72. Procedure TextBackground(Color: Byte);
  73. Procedure LowVideo;
  74. Procedure HighVideo;
  75. Procedure NormVideo;
  76. Procedure Delay(DTime: Word);
  77. Procedure Sound(Hz: Word);
  78. Procedure NoSound;
  79. Implementation
  80. uses Linux;
  81. {
  82. The definitions of TextRec and FileRec are in separate files.
  83. }
  84. {$i textrec.inc}
  85. {$i filerec.inc}
  86. Const
  87. OldTextAttr : byte = $07;
  88. Type
  89. TScreen=Array[1..ScreenHeight,1..ScreenWidth] of char;
  90. TScreenColors=Array[1..ScreenHeight,1..ScreenWidth] of byte;
  91. Var
  92. Scrn : TScreen;
  93. ScrnCol : TScreenColors;
  94. CurrX,CurrY : Byte;
  95. ExitSave : Pointer;
  96. Redir : boolean; { is the output being redirected (not a TTY) }
  97. {*****************************************************************************
  98. Some Handy Functions Not in the System.PP
  99. *****************************************************************************}
  100. Function Str(l:longint):string;
  101. {
  102. Return a String of the longint
  103. }
  104. var
  105. hstr : string[32];
  106. begin
  107. System.Str(l,hstr);
  108. Str:=hstr;
  109. end;
  110. Function Max(l1,l2:longint):longint;
  111. {
  112. Return the maximum of l1 and l2
  113. }
  114. begin
  115. if l1>l2 then
  116. Max:=l1
  117. else
  118. Max:=l2;
  119. end;
  120. Function Min(l1,l2:longint):longint;
  121. {
  122. Return the minimum of l1 and l2
  123. }
  124. begin
  125. if l1<l2 then
  126. Min:=l1
  127. else
  128. Min:=l2;
  129. end;
  130. {*****************************************************************************
  131. Optimal AnsiString Conversion Routines
  132. *****************************************************************************}
  133. Function XY2Ansi(x,y,ox,oy:byte):String;
  134. {
  135. Returns a string with the escape sequences to go to X,Y on the screen
  136. }
  137. Begin
  138. if y=oy then
  139. begin
  140. if x=ox then
  141. begin
  142. XY2Ansi:='';
  143. exit;
  144. end;
  145. if x=1 then
  146. begin
  147. XY2Ansi:=#13;
  148. exit;
  149. end;
  150. if x>ox then
  151. begin
  152. XY2Ansi:=#27'['+Str(x-ox)+'C';
  153. exit;
  154. end
  155. else
  156. begin
  157. XY2Ansi:=#27'['+Str(ox-x)+'D';
  158. exit;
  159. end;
  160. end;
  161. if x=ox then
  162. begin
  163. if y>oy then
  164. begin
  165. XY2Ansi:=#27'['+Str(y-oy)+'B';
  166. exit;
  167. end
  168. else
  169. begin
  170. XY2Ansi:=#27'['+Str(oy-y)+'A';
  171. exit;
  172. end;
  173. end;
  174. if (x=1) and (oy+1=y) then
  175. XY2Ansi:=#13#10
  176. else
  177. XY2Ansi:=#27'['+Str(y)+';'+Str(x)+'H';
  178. End;
  179. const
  180. AnsiTbl : string[8]='04261537';
  181. Function Attr2Ansi(Attr,OAttr:byte):string;
  182. {
  183. Convert Attr to an Ansi String, the Optimal code is calculate
  184. with use of the old OAttr
  185. }
  186. var
  187. hstr : string[16];
  188. OFg,OBg,Fg,Bg : byte;
  189. procedure AddSep(ch:char);
  190. begin
  191. if length(hstr)>0 then
  192. hstr:=hstr+';';
  193. hstr:=hstr+ch;
  194. end;
  195. begin
  196. if Attr=OAttr then
  197. begin
  198. Attr2Ansi:='';
  199. exit;
  200. end;
  201. Hstr:='';
  202. Fg:=Attr and $f;
  203. Bg:=Attr shr 4;
  204. OFg:=Attr and $f;
  205. OBg:=Attr shr 4;
  206. if (OFg<>7) or (Fg=7) or ((OFg>7) and (Fg<8)) or ((OBg>7) and (Bg<8)) then
  207. begin
  208. hstr:='0';
  209. OFg:=7;
  210. OBg:=0;
  211. end;
  212. if (Fg>7) and (OFg<8) then
  213. begin
  214. AddSep('1');
  215. OFg:=OFg or 8;
  216. end;
  217. if (Bg and 8)<>(OBg and 8) then
  218. begin
  219. AddSep('5');
  220. OBg:=OBg or 8;
  221. end;
  222. if (Fg<>OFg) then
  223. begin
  224. AddSep('3');
  225. hstr:=hstr+AnsiTbl[(Fg and 7)+1];
  226. end;
  227. if (Bg<>OBg) then
  228. begin
  229. AddSep('4');
  230. hstr:=hstr+AnsiTbl[(Bg and 7)+1];
  231. end;
  232. if hstr='0' then
  233. hstr:='';
  234. Attr2Ansi:=#27'['+hstr+'m';
  235. end;
  236. Function Ansi2Attr(Const HStr:String;oattr:byte):byte;
  237. {
  238. Convert an Escape sequence to an attribute value, uses Oattr as the last
  239. color written
  240. }
  241. var
  242. i,j : byte;
  243. begin
  244. i:=2;
  245. if (Length(HStr)<3) or (Hstr[1]<>#27) or (Hstr[2]<>'[') then
  246. i:=255;
  247. while (i<length(Hstr)) do
  248. begin
  249. inc(i);
  250. case Hstr[i] of
  251. '0' : OAttr:=7;
  252. '1' : OAttr:=OAttr or $8;
  253. '5' : OAttr:=OAttr or $80;
  254. '3' : begin
  255. inc(i);
  256. j:=pos(Hstr[i],AnsiTbl);
  257. if j>0 then
  258. OAttr:=(OAttr and $f8) or (j-1);
  259. end;
  260. '4' : begin
  261. inc(i);
  262. j:=pos(Hstr[i],AnsiTbl);
  263. if j>0 then
  264. OAttr:=(OAttr and $8f) or ((j-1) shl 4);
  265. end;
  266. 'm' : i:=length(HStr);
  267. end;
  268. end;
  269. Ansi2Attr:=OAttr;
  270. end;
  271. {*****************************************************************************
  272. Buffered StdIn/StdOut IO
  273. *****************************************************************************}
  274. const
  275. ttyIn=0; {Handles for stdin/stdout}
  276. ttyOut=1;
  277. ttyFlush:boolean=true;
  278. {Buffered Input/Output}
  279. InSize=256;
  280. OutSize=1024;
  281. var
  282. InBuf : array[0..InSize-1] of char;
  283. InCnt,
  284. InHead,
  285. InTail : longint;
  286. OutBuf : array[0..OutSize-1] of char;
  287. OutCnt : longint;
  288. {Flush Output Buffer}
  289. procedure ttyFlushOutput;
  290. begin
  291. if OutCnt>0 then
  292. begin
  293. fdWrite(ttyOut,OutBuf,OutCnt);
  294. OutCnt:=0;
  295. end;
  296. end;
  297. Function ttySetFlush(b:boolean):boolean;
  298. begin
  299. ttySetFlush:=ttyFlush;
  300. ttyFlush:=b;
  301. if ttyFlush then
  302. ttyFlushOutput;
  303. end;
  304. {Send Char to Remote}
  305. Procedure ttySendChar(c:char);
  306. Begin
  307. if OutCnt<OutSize then
  308. begin
  309. OutBuf[OutCnt]:=c;
  310. inc(OutCnt);
  311. end;
  312. {Full ?}
  313. if (OutCnt>=OutSize) then
  314. ttyFlushOutput;
  315. End;
  316. {Send String to Remote}
  317. procedure ttySendStr(const hstr:string);
  318. var
  319. i : word;
  320. begin
  321. for i:=1to length(hstr) do
  322. ttySendChar(hstr[i]);
  323. if ttyFlush then
  324. ttyFlushOutput;
  325. end;
  326. {Get Char from Remote}
  327. function ttyRecvChar:char;
  328. var
  329. Readed,i : word;
  330. begin
  331. {Buffer Empty? Yes, Input from StdIn}
  332. if (InHead=InTail) then
  333. begin
  334. {Calc Amount of Chars to Read}
  335. i:=InSize-InHead;
  336. if InTail>InHead then
  337. i:=InTail-InHead;
  338. {Read}
  339. Readed:=fdRead(TTYIn,InBuf[InHead],i);
  340. {Increase Counters}
  341. inc(InCnt,Readed);
  342. inc(InHead,Readed);
  343. {Wrap if End has Reached}
  344. if InHead>=InSize then
  345. InHead:=0;
  346. end;
  347. {Check Buffer}
  348. if (InCnt=0) then
  349. ttyRecvChar:=#0
  350. else
  351. begin
  352. ttyRecvChar:=InBuf[InTail];
  353. dec(InCnt);
  354. inc(InTail);
  355. if InTail>=InSize then
  356. InTail:=0;
  357. end;
  358. end;
  359. {*****************************************************************************
  360. Screen Routines not Window Depended
  361. *****************************************************************************}
  362. procedure ttyGotoXY(x,y:byte);
  363. {
  364. Goto XY on the Screen, if a value is 0 the goto the current
  365. postion of that value and always recalc the ansicode for it
  366. }
  367. begin
  368. if x=0 then
  369. begin
  370. x:=CurrX;
  371. CurrX:=$ff;
  372. end;
  373. if y=0 then
  374. begin
  375. y:=CurrY;
  376. CurrY:=$ff;
  377. end;
  378. if Redir then
  379. begin
  380. if longint(y)-longint(CurrY)=1 then
  381. ttySendStr(#10);
  382. end
  383. else
  384. ttySendStr(XY2Ansi(x,y,CurrX,CurrY));
  385. CurrX:=x;
  386. CurrY:=y;
  387. end;
  388. procedure ttyColor(a:byte);
  389. {
  390. Set Attribute to A, only output if not the last attribute is set
  391. }
  392. begin
  393. if a<>TextAttr then
  394. begin
  395. if not Redir then
  396. ttySendStr(Attr2Ansi(a,TextAttr));
  397. TextAttr:=a;
  398. OldTextAttr:=a;
  399. end;
  400. end;
  401. procedure ttyWrite(const s:string);
  402. {
  403. Write a string to the output, memory copy and Current X&Y are also updated
  404. }
  405. var
  406. i : word;
  407. begin
  408. ttySendStr(s);
  409. {Update MemCopy}
  410. for i:=1to length(s) do
  411. begin
  412. Scrn[CurrY,CurrX]:=s[i];
  413. ScrnCol[CurrY,CurrX]:=TextAttr;
  414. inc(CurrX);
  415. if CurrX>ScreenWidth then
  416. CurrX:=ScreenWidth;
  417. end;
  418. end;
  419. Function WinMinX: Byte;
  420. {
  421. Current Minimum X coordinate
  422. }
  423. Begin
  424. WinMinX:=(WindMin and $ff)+1;
  425. End;
  426. Function WinMinY: Byte;
  427. {
  428. Current Minimum Y Coordinate
  429. }
  430. Begin
  431. WinMinY:=(WindMin shr 8)+1;
  432. End;
  433. Function WinMaxX: Byte;
  434. {
  435. Current Maximum X coordinate
  436. }
  437. Begin
  438. WinMaxX:=(WindMax and $ff)+1;
  439. End;
  440. Function WinMaxY: Byte;
  441. {
  442. Current Maximum Y coordinate;
  443. }
  444. Begin
  445. WinMaxY:=(WindMax shr 8) + 1;
  446. End;
  447. Function FullWin:boolean;
  448. {
  449. Full Screen 80x25? Window(1,1,80,25) is used, allows faster routines
  450. }
  451. begin
  452. FullWin:=(WindMax-WindMin=$184f);
  453. end;
  454. procedure LineWrite(temp:String);
  455. {
  456. Write a Line to the screen, doesn't write on 80,25 under Dos
  457. the Current CurrX is set to WinMax. NO MEMORY UPDATE!
  458. }
  459. begin
  460. CurrX:=WinMaxX+1;
  461. if (CurrX>=ScreenWidth) then
  462. CurrX:=WinMaxX;
  463. ttySendStr(Temp);
  464. end;
  465. procedure DoEmptyLine(y,xl,xh:byte);
  466. {
  467. Write an Empty line at Row Y from Col Xl to XH, Memory is also updated
  468. }
  469. begin
  470. ttyGotoXY(xl,y);
  471. LineWrite(Space(xh-xl+1));
  472. FillChar(Scrn[y],ScreenWidth,' ');
  473. FillChar(ScrnCol[y],ScreenWidth,TextAttr);
  474. end;
  475. procedure DoScrollLine(y1,y2,xl,xh:byte);
  476. {
  477. Move Line y1 to y2, use only columns Xl-Xh, Memory is updated also
  478. }
  479. var
  480. Temp : string;
  481. OldAttr,
  482. x,attr : byte;
  483. begin
  484. ttyGotoXY(xl,y2);
  485. OldAttr:=$ff;
  486. Temp:='';
  487. For x:=xl To xh Do
  488. Begin
  489. attr:=ScrnCol[y1,x];
  490. if attr<>OldAttr then
  491. begin
  492. temp:=temp+Attr2Ansi(Attr,OldAttr);
  493. OldAttr:=Attr;
  494. end;
  495. Temp:=Temp+Scrn[y1,x];
  496. if (x=xh) or (length(Temp)>240) then
  497. begin
  498. LineWrite(Temp);
  499. Temp:='';
  500. end;
  501. End;
  502. {Update memory copy}
  503. Move(Scrn[y1,1],Scrn[y2,1],ScreenWidth);
  504. Move(ScrnCol[y1,1],ScrnCol[y2,1],ScreenWidth);
  505. end;
  506. Procedure TextColor(Color: Byte);
  507. {
  508. Switch foregroundcolor
  509. }
  510. Begin
  511. ttyColor((Color and $8f) or (TextAttr and $70));
  512. End;
  513. Procedure TextBackground(Color: Byte);
  514. {
  515. Switch backgroundcolor
  516. }
  517. Begin
  518. ttyColor((Color shl 4) or (TextAttr and $0f));
  519. End;
  520. Procedure HighVideo;
  521. {
  522. Set highlighted output.
  523. }
  524. Begin
  525. TextColor(TextAttr Or $08);
  526. End;
  527. Procedure LowVideo;
  528. {
  529. Set normal output
  530. }
  531. Begin
  532. TextColor(TextAttr And $77);
  533. End;
  534. Procedure NormVideo;
  535. {
  536. Set normal back and foregroundcolors.
  537. }
  538. Begin
  539. TextColor(7);
  540. TextBackGround(0);
  541. End;
  542. Procedure GotoXy(X: Byte; Y: Byte);
  543. {
  544. Go to coordinates X,Y in the current window.
  545. }
  546. Begin
  547. If (X>0) and (X<=WinMaxX- WinMinX+1) and
  548. (Y>0) and (Y<=WinMaxY-WinMinY+1) Then
  549. Begin
  550. Inc(X,WinMinX-1);
  551. Inc(Y,WinMinY-1);
  552. ttyGotoXY(x,y);
  553. End;
  554. End;
  555. Procedure Window(X1, Y1, X2, Y2: Byte);
  556. {
  557. Set screen window to the specified coordinates.
  558. }
  559. Begin
  560. if (X1>X2) or (X2>ScreenWidth) or
  561. (Y1>Y2) or (Y2>ScreenHeight) then
  562. exit;
  563. WindMin:=((Y1-1) Shl 8)+(X1-1);
  564. WindMax:=((Y2-1) Shl 8)+(X2-1);
  565. GoToXY(1,1);
  566. End;
  567. Procedure ClrScr;
  568. {
  569. Clear the current window, and set the cursor on x1,y1
  570. }
  571. Var
  572. CY : Integer;
  573. oldflush : boolean;
  574. Begin
  575. oldflush:=ttySetFlush(Flushing);
  576. if FullWin then
  577. begin
  578. if not Redir then
  579. ttySendStr(#27'[H'#27'[2J');
  580. CurrX:=1;
  581. CurrY:=1;
  582. FillChar(Scrn,sizeof(Scrn),' ');
  583. FillChar(ScrnCol,sizeof(ScrnCol),TextAttr);
  584. end
  585. else
  586. begin
  587. For Cy:=WinMinY To WinMaxY Do
  588. DoEmptyLine(Cy,WinMinX,WinMaxX);
  589. GoToXY(1,1);
  590. end;
  591. ttySetFlush(oldflush);
  592. End;
  593. Procedure ClrEol;
  594. {
  595. Clear from current position to end of line.
  596. }
  597. Begin
  598. if FullWin then
  599. begin
  600. if not Redir then
  601. ttySendStr(#27'[K');
  602. end
  603. else
  604. begin
  605. ttySendStr(Space(WinMaxX-CurrX));
  606. ttyGotoXY(0,CurrY);
  607. end;
  608. End;
  609. Function WhereX: Byte;
  610. {
  611. Return current X-position of cursor.
  612. }
  613. Begin
  614. WhereX:=CurrX-WinMinX+1;
  615. End;
  616. Function WhereY: Byte;
  617. {
  618. Return current Y-position of cursor.
  619. }
  620. Begin
  621. WhereY:=CurrY-WinMinY+1;
  622. End;
  623. Procedure ScrollScrnRegionUp(xl,yl,xh,yh, count: Byte);
  624. {
  625. Scroll the indicated region count lines up. The empty lines are filled
  626. with blanks in the current color. The screen position is restored
  627. afterwards.
  628. }
  629. Var
  630. y,oldx,oldy : byte;
  631. oldflush : boolean;
  632. Begin
  633. oldflush:=ttySetFlush(Flushing);
  634. oldx:=CurrX;
  635. oldy:=CurrY;
  636. {Scroll}
  637. For y:=yl to yh-count do
  638. DoScrollLine(y+count,y,xl,xh);
  639. {Restore TextAttr}
  640. ttySendStr(Attr2Ansi(TextAttr,$ff));
  641. {Fill the rest with empty lines}
  642. for y:=yh-count+1 to yh do
  643. DoEmptyLine(y,xl,xh);
  644. {Restore current position}
  645. ttyGotoXY(OldX,OldY);
  646. ttySetFlush(oldflush);
  647. End;
  648. Procedure ScrollScrnRegionDown(xl,yl,xh,yh, count: Byte);
  649. {
  650. Scroll the indicated region count lines down. The empty lines are filled
  651. with blanks in the current color. The screen position is restored
  652. afterwards.
  653. }
  654. Var
  655. y,oldx,oldy : byte;
  656. oldflush : boolean;
  657. Begin
  658. oldflush:=ttySetFlush(Flushing);
  659. oldx:=CurrX;
  660. oldy:=CurrY;
  661. {Scroll}
  662. for y:=yh downto yl+count do
  663. DoScrollLine(y-count,y,xl,xh);
  664. {Restore TextAttr}
  665. ttySendStr(Attr2Ansi(TextAttr,$ff));
  666. {Fill the rest with empty lines}
  667. for y:=yl to yl+count-1 do
  668. DoEmptyLine(y,xl,xh);
  669. {Restore current position}
  670. ttyGotoXY(OldX,OldY);
  671. ttySetFlush(oldflush);
  672. End;
  673. Procedure ScrollWindow(xl,yl,xh,yh : Byte; count: LongInt);
  674. {
  675. Scroll the indicated region up or down, depending on the sign
  676. of count.
  677. }
  678. begin
  679. If ((xl>xh) or (xh>ScreenWidth)) or
  680. ((yl>yh) or (yl>ScreenHeight)) or
  681. (abs(Count)>yh-yl+1) then
  682. exit;
  683. If count<0 then
  684. ScrollScrnRegionDown (xl,yl,xh,yh,abs(count))
  685. else
  686. ScrollScrnRegionUp (xl,yl,xh,yh,count);
  687. end;
  688. {*************************************************************************
  689. KeyBoard
  690. *************************************************************************}
  691. Const
  692. KeyBufferSize = 20;
  693. var
  694. KeyBuffer : Array[0..KeyBufferSize-1] of Char;
  695. KeyPut,
  696. KeySend : Byte;
  697. Procedure PushKey(Ch:char);
  698. Var
  699. Tmp : Word;
  700. Begin
  701. Tmp:=KeyPut;
  702. Inc(KeyPut);
  703. If KeyPut>=KeyBufferSize Then
  704. KeyPut:=0;
  705. If KeyPut<>KeySend Then
  706. KeyBuffer[Tmp]:=Ch
  707. Else
  708. KeyPut:=Tmp;
  709. End;
  710. Function PopKey:char;
  711. Begin
  712. If KeyPut<>KeySend Then
  713. Begin
  714. PopKey:=KeyBuffer[KeySend];
  715. Inc(KeySend);
  716. If KeySend>=KeyBufferSize Then
  717. KeySend:=0;
  718. End
  719. Else
  720. PopKey:=#0;
  721. End;
  722. Procedure PushExt(b:byte);
  723. begin
  724. PushKey(#0);
  725. PushKey(chr(b));
  726. end;
  727. const
  728. AltKeyStr : string[38]='qwertyuiopasdfghjklzxcvbnm1234567890-=';
  729. AltCodeStr : string[38]=#016#017#018#019#020#021#022#023#024#025#030#031#032#033#034#035#036#037#038+
  730. #044#045#046#047#048#049#050#120#121#122#123#124#125#126#127#128#129#130#131;
  731. Function FAltKey(ch:char):byte;
  732. var
  733. Idx : byte;
  734. Begin
  735. Idx:=Pos(ch,AltKeyStr);
  736. if Idx>0 then
  737. FAltKey:=byte(AltCodeStr[Idx])
  738. else
  739. FAltKey:=0;
  740. End;
  741. Function KeyPressed:Boolean;
  742. var
  743. fdsin : fdSet;
  744. Begin
  745. if (KeySend<>KeyPut) or (InCnt>0) then
  746. KeyPressed:=true
  747. else
  748. begin
  749. FD_Zero(fdsin);
  750. fd_Set(TTYin,fdsin);
  751. Keypressed:=(Select(TTYIn+1,@fdsin,nil,nil,0)>0);
  752. end;
  753. End;
  754. Function ReadKey:char;
  755. Var
  756. ch : char;
  757. OldState,
  758. State : Word;
  759. Begin
  760. {Check Buffer first}
  761. if KeySend<>KeyPut then
  762. begin
  763. ReadKey:=PopKey;
  764. exit;
  765. end;
  766. {Wait for Key}
  767. repeat
  768. until keypressed;
  769. ch:=ttyRecvChar;
  770. {Esc Found ?}
  771. If (ch=#27) then
  772. begin
  773. State:=1;
  774. Delay(10);
  775. while (State<>0) and (KeyPressed) do
  776. begin
  777. ch:=ttyRecvChar;
  778. OldState:=State;
  779. State:=0;
  780. case OldState of
  781. 1 : begin {Esc}
  782. case ch of
  783. 'a'..'z',
  784. '0'..'9',
  785. '-','=' : PushExt(FAltKey(ch));
  786. #10 : PushKey(#10);
  787. '[' : State:=2;
  788. else
  789. begin
  790. PushKey(ch);
  791. PushKey(#27);
  792. end;
  793. end;
  794. end;
  795. 2 : begin {Esc[}
  796. case ch of
  797. '[' : State:=3;
  798. 'A' : PushExt(72);
  799. 'B' : PushExt(80);
  800. 'C' : PushExt(77);
  801. 'D' : PushExt(75);
  802. 'G' : PushKey('5');
  803. 'H' : PushExt(71);
  804. 'K' : PushExt(79);
  805. '1' : State:=4;
  806. '2' : State:=5;
  807. '3' : PushExt(83);
  808. '4' : PushExt(79);
  809. '5' : PushExt(73);
  810. '6' : PushExt(81);
  811. else
  812. begin
  813. PushKey(ch);
  814. PushKey('[');
  815. PushKey(#27);
  816. end;
  817. end;
  818. if ch in ['3'..'6'] then
  819. State:=255;
  820. end;
  821. 3 : begin {Esc[[}
  822. case ch of
  823. 'A' : PushExt(59);
  824. 'B' : PushExt(60);
  825. 'C' : PushExt(61);
  826. 'D' : PushExt(62);
  827. 'E' : PushExt(63);
  828. end;
  829. end;
  830. 4 : begin
  831. case ch of
  832. '~' : PushExt(71);
  833. '7' : PushExt(64);
  834. '8' : PushExt(65);
  835. '9' : PushExt(66);
  836. end;
  837. if (Ch<>'~') then
  838. State:=255;
  839. end;
  840. 5 : begin
  841. case ch of
  842. '~' : PushExt(82);
  843. '0' : pushExt(67);
  844. '1' : PushExt(68);
  845. '3' : PushExt(133);
  846. '4' : PushExt(134);
  847. end;
  848. if (Ch<>'~') then
  849. State:=255;
  850. end;
  851. 255 : ;
  852. end;
  853. if State<>0 then
  854. Delay(10);
  855. end;
  856. if State=1 then
  857. PushKey(ch);
  858. end
  859. else
  860. Begin
  861. case ch of
  862. #127 : PushExt(83);
  863. else
  864. PushKey(ch);
  865. end;
  866. End;
  867. ReadKey:=PopKey;
  868. End;
  869. Procedure Delay(DTime: Word);
  870. {
  871. Wait for DTime milliseconds.
  872. }
  873. Begin
  874. Select(0,nil,nil,nil,DTime);
  875. End;
  876. {****************************************************************************
  877. HighLevel Crt Functions
  878. ****************************************************************************}
  879. procedure DoLn;
  880. begin
  881. if CurrY=WinMaxY then
  882. begin
  883. if FullWin then
  884. begin
  885. ttySendStr(#10#13);
  886. CurrX:=WinMinX;
  887. CurrY:=WinMaxY;
  888. end
  889. else
  890. begin
  891. ScrollScrnRegionUp(WinMinX,WinMinY,WinMaxX,WinMaxY,1);
  892. ttyGotoXY(WinMinX,WinMaxY);
  893. end;
  894. end
  895. else
  896. ttyGotoXY(WinMinX,CurrY+1);
  897. end;
  898. var
  899. Lastansi : boolean;
  900. AnsiCode : string[32];
  901. Procedure DoWrite(const s:String);
  902. {
  903. Write string to screen, parse most common AnsiCodes
  904. }
  905. var
  906. found,
  907. OldFlush : boolean;
  908. x,y : byte;
  909. i,j,
  910. SendBytes : word;
  911. function AnsiPara(var hstr:string):byte;
  912. var
  913. k,j : byte;
  914. code : word;
  915. begin
  916. j:=pos(';',hstr);
  917. if j=0 then
  918. j:=length(hstr);
  919. val(copy(hstr,3,j-3),k,code);
  920. Delete(hstr,3,j-2);
  921. if k=0 then
  922. k:=1;
  923. AnsiPara:=k;
  924. end;
  925. procedure SendText;
  926. var
  927. LeftX : word;
  928. begin
  929. while (SendBytes>0) do
  930. begin
  931. LeftX:=WinMaxX-CurrX+1;
  932. if (SendBytes>LeftX) or (CurrX+SendBytes=81) then
  933. begin
  934. ttyWrite(Copy(s,i-SendBytes,LeftX));
  935. dec(SendBytes,LeftX);
  936. DoLn;
  937. end
  938. else
  939. begin
  940. ttyWrite(Copy(s,i-SendBytes,SendBytes));
  941. SendBytes:=0;
  942. end;
  943. end;
  944. end;
  945. begin
  946. oldflush:=ttySetFlush(Flushing);
  947. { Support textattr:= changing }
  948. if OldTextAttr<>TextAttr then
  949. begin
  950. i:=TextAttr;
  951. TextAttr:=OldTextAttr;
  952. ttyColor(i);
  953. end;
  954. { write the stuff }
  955. SendBytes:=0;
  956. i:=1;
  957. while (i<=length(s)) do
  958. begin
  959. if (s[i]=#27) or (LastAnsi) then
  960. begin
  961. SendText;
  962. LastAnsi:=false;
  963. j:=i;
  964. found:=false;
  965. while (j<=length(s)) and (not found) do
  966. begin
  967. found:=not (s[j] in [#27,'[','0'..'9',';','?']);
  968. inc(j);
  969. end;
  970. Ansicode:=AnsiCode+Copy(s,i,j-i);
  971. if found then
  972. begin
  973. case AnsiCode[length(AnsiCode)] of
  974. 'm' : ttyColor(Ansi2Attr(AnsiCode,TextAttr));
  975. 'H' : begin {No other way :( Coz First Para=Y}
  976. y:=AnsiPara(AnsiCode);
  977. x:=AnsiPara(AnsiCode);
  978. GotoXY(y,x);
  979. end;
  980. 'J' : if AnsiPara(AnsiCode)=2 then
  981. ClrScr;
  982. 'K' : ClrEol;
  983. 'A' : GotoXY(CurrX,Max(CurrY-AnsiPara(AnsiCode),WinMinY));
  984. 'B' : GotoXY(CurrX,Min(CurrY+AnsiPara(AnsiCode),WinMaxY));
  985. 'C' : GotoXY(Min(CurrX+AnsiPara(AnsiCode),WinMaxX),CurrY);
  986. 'D' : GotoXY(Max(CurrX-AnsiPara(AnsiCode),WinMinX),CurrY);
  987. 'h' : ; {Stupid Thedraw [?7h Code}
  988. else
  989. found:=false;
  990. end;
  991. end
  992. else
  993. begin
  994. LastAnsi:=true;
  995. found:=true;
  996. end;
  997. {Clear AnsiCode?}
  998. if not LastAnsi then
  999. AnsiCode:='';
  1000. {Increase Idx or SendBytes}
  1001. if found then
  1002. i:=j-1
  1003. else
  1004. inc(SendBytes);
  1005. end
  1006. else
  1007. begin
  1008. LastAnsi:=false;
  1009. case s[i] of
  1010. #13 : begin {CR}
  1011. SendText;
  1012. ttyGotoXY(WinMinX,CurrY);
  1013. end;
  1014. #10 : begin {NL}
  1015. SendText;
  1016. DoLn;
  1017. end;
  1018. #9 : begin {Tab}
  1019. SendText;
  1020. ttyWrite(Space(9-((CurrX-1) and $08)));
  1021. end;
  1022. else
  1023. inc(SendBytes);
  1024. end;
  1025. end;
  1026. inc(i);
  1027. end;
  1028. if SendBytes>0 then
  1029. SendText;
  1030. ttySetFlush(oldFLush);
  1031. end;
  1032. Function CrtWrite(Var F: TextRec): Integer;
  1033. {
  1034. Top level write function for CRT
  1035. }
  1036. Var
  1037. Temp : String;
  1038. Begin
  1039. Move(F.BufPTR^[0],Temp[1],F.BufPos);
  1040. temp[0]:=chr(F.BufPos);
  1041. DoWrite(Temp);
  1042. F.BufPos:=0;
  1043. CrtWrite:=0;
  1044. End;
  1045. Function CrtClose(Var F: TextRec): Integer;
  1046. {
  1047. Close CRT associated file.
  1048. }
  1049. Begin
  1050. F.Mode:=fmClosed;
  1051. CrtClose:=0;
  1052. End;
  1053. Function CrtOpen(Var F: TextRec): Integer;
  1054. {
  1055. Open CRT associated file.
  1056. }
  1057. Begin
  1058. If F.Mode = fmOutput Then
  1059. CrtOpen:=0
  1060. Else
  1061. CrtOpen:=5;
  1062. End;
  1063. Function CrtRead(Var F: TextRec): Integer;
  1064. {
  1065. Read from CRT associated file.
  1066. }
  1067. Begin
  1068. F.BufEnd:=fdRead(F.Handle, F.BufPtr^, F.BufSize);
  1069. F.BufPos:=F.BufEnd;
  1070. CrtWrite(F);
  1071. CrtRead:=0;
  1072. End;
  1073. Function CrtInOut(Var F: TextRec): Integer;
  1074. {
  1075. InOut function for CRT associated file.
  1076. }
  1077. Begin
  1078. Case F.Mode of
  1079. fmInput: CrtInOut:=CrtRead(F);
  1080. fmOutput: CrtInOut:=CrtWrite(F);
  1081. End;
  1082. End;
  1083. Procedure AssignCrt(Var F: Text);
  1084. {
  1085. Assign a file to the console. All output on file goes to console instead.
  1086. }
  1087. Begin
  1088. TextRec(F).Mode:=fmClosed;
  1089. TextRec(F).BufSize:=SizeOf(TextBuf);
  1090. TextRec(F).BufPtr:=@TextRec(F).Buffer;
  1091. TextRec(F).BufPos:=0;
  1092. TextRec(F).OpenFunc:=@CrtOpen;
  1093. TextRec(F).InOutFunc:=@CrtInOut;
  1094. TextRec(F).FlushFunc:=@CrtWrite;
  1095. TextRec(F).CloseFunc:=@CrtClose;
  1096. TextRec(F).Name[0]:='.';
  1097. TextRec(F).Name[1]:=#0;
  1098. End;
  1099. Procedure DelLine;
  1100. {
  1101. Delete current line. Scroll subsequent lines up
  1102. }
  1103. Begin
  1104. ScrollScrnRegionUp(WinMinX, CurrY, WinMaxX, WinMaxY, 1);
  1105. End;
  1106. Procedure InsLine;
  1107. {
  1108. Insert line at current cursor position. Scroll subsequent lines down.
  1109. }
  1110. Begin
  1111. ScrollScrnRegionDown(WinMinX, CurrY, WinMaxX, WinMaxY, 1);
  1112. End;
  1113. Procedure Sound(Hz: Word);
  1114. {
  1115. Does nothing under linux
  1116. }
  1117. begin
  1118. end;
  1119. Procedure NoSound;
  1120. {
  1121. Does nothing under linux
  1122. }
  1123. begin
  1124. end;
  1125. Procedure TextMode(Mode: Integer);
  1126. {
  1127. Only Clears Screen under linux
  1128. }
  1129. begin
  1130. ClrScr;
  1131. end;
  1132. {******************************************************************************
  1133. Initialization
  1134. ******************************************************************************}
  1135. var
  1136. OldIO : TermIos;
  1137. Procedure SetRawMode(b:boolean);
  1138. Var
  1139. Tio : Termios;
  1140. Begin
  1141. if b then
  1142. begin
  1143. TCGetAttr(1,Tio);
  1144. OldIO:=Tio;
  1145. CFMakeRaw(Tio);
  1146. Tio.C_IFlag:=Tio.C_IFlag or ICRNL;
  1147. end
  1148. else
  1149. Tio:=OldIO;
  1150. TCSetAttr(1,TCSANOW,Tio);
  1151. End;
  1152. procedure GetXY(var x,y:byte);
  1153. var
  1154. fds : fdSet;
  1155. i,j,
  1156. readed : longint;
  1157. buf : array[0..255] of char;
  1158. s : string[16];
  1159. begin
  1160. x:=0;
  1161. y:=0;
  1162. s:=#27'[6n';
  1163. fdWrite(0,s[1],length(s));
  1164. FD_Zero(fds);
  1165. FD_Set(1,fds);
  1166. if (Select(2,@fds,nil,nil,1000)>0) then
  1167. begin
  1168. readed:=fdRead(1,buf,sizeof(buf));
  1169. i:=0;
  1170. while (i+4<readed) and (buf[i]<>#27) and (buf[i+1]<>'[') do
  1171. inc(i);
  1172. if i+4<readed then
  1173. begin
  1174. s[1]:=#16;
  1175. move(buf[i+2],s[1],16);
  1176. i:=Pos(';',s);
  1177. if i>0 then
  1178. begin
  1179. Val(Copy(s,1,i-1),y);
  1180. j:=Pos('R',s);
  1181. if j=0 then
  1182. j:=length(s)+1;
  1183. Val(Copy(s,i+1,j-i),x);
  1184. end;
  1185. end;
  1186. end;
  1187. end;
  1188. Procedure CrtExit;
  1189. {
  1190. We need to restore normal keyboard mode upon exit !!
  1191. }
  1192. Begin
  1193. ttyFlushOutput;
  1194. SetRawMode(False);
  1195. ExitProc:=ExitSave;
  1196. End;
  1197. Begin
  1198. {Hook Exit}
  1199. ExitSave:=ExitProc;
  1200. ExitProc:=@CrtExit;
  1201. {Assign Input and Output to Crt}
  1202. AssignCrt(Output);
  1203. AssignCrt(Input);
  1204. TextRec(Output).Mode:=fmOutput;
  1205. TextRec(Input).Mode:=fmInput;
  1206. Redir:=not IsAtty(TextRec(Output).Handle);
  1207. {Set default Terminal Settings}
  1208. SetRawMode(True);
  1209. {Get Current X&Y or Reset to Home}
  1210. if Redir then
  1211. begin
  1212. CurrX:=1;
  1213. CurrY:=1;
  1214. end
  1215. else
  1216. begin
  1217. GetXY(CurrX,CurrY);
  1218. if (CurrX=0) then
  1219. begin
  1220. CurrX:=1;
  1221. CurrY:=1;
  1222. ttySendStr(#27'[H');
  1223. end;
  1224. {Reset Attribute (TextAttr=7 at startup)}
  1225. ttySendStr(#27'[m');
  1226. end;
  1227. End.
  1228. {
  1229. $Log$
  1230. Revision 1.2 1998-04-05 13:56:54 peter
  1231. - fixed mouse to compile with $i386_att
  1232. + linux crt supports redirecting (not Esc-codes anymore)
  1233. Revision 1.1.1.1 1998/03/25 11:18:43 root
  1234. * Restored version
  1235. Revision 1.10 1998/03/16 23:38:52 peter
  1236. + support for textattr:= setting between writes
  1237. Revision 1.9 1998/01/26 12:00:45 michael
  1238. + Added log at the end
  1239. revision 1.8
  1240. date: 1998/01/20 00:18:14; author: peter; state: Exp; lines: +2 -2
  1241. * column 80 works now the same as under dos (wraps to next line)
  1242. ----------------------------
  1243. revision 1.7
  1244. date: 1998/01/19 10:04:02; author: michael; state: Exp; lines: +2 -2
  1245. * Bugfix from Peter Vreman.
  1246. ----------------------------
  1247. revision 1.6
  1248. date: 1998/01/05 13:43:17; author: michael; state: Exp; lines: +129 -109
  1249. * Minor bugfixes, bugs appeared when making/compiling examples.
  1250. (by Peter Vreman)
  1251. ----------------------------
  1252. revision 1.5
  1253. date: 1997/12/28 17:53:04; author: michael; state: Exp; lines: +52 -4
  1254. * Bug fixed : CR now sends CR/LF; importat for Readln. (Peter Vreman fixed
  1255. this)
  1256. * GetXY function now tries to read initial conditions.
  1257. ----------------------------
  1258. revision 1.4
  1259. date: 1997/12/19 15:22:14; author: michael; state: Exp; lines: +10 -22
  1260. * changed setrawmode to use termios functions in linux unit.
  1261. ----------------------------
  1262. revision 1.3
  1263. date: 1997/12/15 12:44:56; author: michael; state: Exp; lines: +6 -1
  1264. * added key handling for xterm.
  1265. ----------------------------
  1266. revision 1.2
  1267. date: 1997/12/01 12:31:14; author: michael; state: Exp; lines: +12 -16
  1268. + Added copyright reference in header.
  1269. ----------------------------
  1270. revision 1.1
  1271. date: 1997/11/27 08:33:54; author: michael; state: Exp;
  1272. Initial revision
  1273. ----------------------------
  1274. revision 1.1.1.1
  1275. date: 1997/11/27 08:33:54; author: michael; state: Exp; lines: +0 -0
  1276. FPC RTL CVS start
  1277. =============================================================================
  1278. Pre CVS Log:
  1279. Version Date What/who
  1280. ------- ---- -------
  1281. 0.1 96/97 Written by Mark May ([email protected])
  1282. Major overhaul to improve screen output performance by
  1283. Michael Van Canneyt ([email protected])
  1284. Also added some documentation.
  1285. Balazs Scheidler changed color handling to lookup-table
  1286. 0.2 7/97 changes by Hans-Peter Zorn <[email protected]>
  1287. to make key-handling work in an xterm.
  1288. Alt-key becomes ESC + Key.
  1289. 0.3 10/97 Modified by Matthias K"oppe
  1290. <[email protected]> :
  1291. Fixed key decoding for function keys F6..F12
  1292. 0.4 11/97 Modified by Peter Vreman <[email protected]>
  1293. Optimised keyboard handling.
  1294. 0.5 11/97 Modified by Peter Vreman <[email protected]>
  1295. Inplemented bigger buffer for output, ANSI codes
  1296. are handled too.
  1297. Unit now depends on linux unit only.
  1298. 0.6 01/98 Modified by Peter Vreman
  1299. Implemented missing function/procedures, the interface
  1300. is now 100% the same BP7.
  1301. The screen is not cleared at startup anymore. The
  1302. cursor stays at the current position.
  1303. }