crt.pp 29 KB

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