crt.pp 29 KB

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