crt.pp 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526
  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. if s[i]=#8 then
  419. begin
  420. if CurrX>1 then
  421. dec(CurrX);
  422. end
  423. else
  424. begin
  425. ConsoleBuf^[idx+CurrX].ch:=s[i];
  426. ConsoleBuf^[idx+CurrX].attr:=TextAttr;
  427. inc(CurrX);
  428. if CurrX>ScreenWidth then
  429. CurrX:=ScreenWidth;
  430. end;
  431. end;
  432. Function WinMinX: Longint;
  433. {
  434. Current Minimum X coordinate
  435. }
  436. Begin
  437. WinMinX:=(WindMin and $ff)+1;
  438. End;
  439. Function WinMinY: Longint;
  440. {
  441. Current Minimum Y Coordinate
  442. }
  443. Begin
  444. WinMinY:=(WindMin shr 8)+1;
  445. End;
  446. Function WinMaxX: Longint;
  447. {
  448. Current Maximum X coordinate
  449. }
  450. Begin
  451. WinMaxX:=(WindMax and $ff)+1;
  452. End;
  453. Function WinMaxY: Longint;
  454. {
  455. Current Maximum Y coordinate;
  456. }
  457. Begin
  458. WinMaxY:=(WindMax shr 8) + 1;
  459. End;
  460. Function FullWin:boolean;
  461. {
  462. Full Screen 80x25? Window(1,1,80,25) is used, allows faster routines
  463. }
  464. begin
  465. FullWin:=(WinMinX=1) and (WinMinY=1) and
  466. (WinMaxX=ScreenWidth) and (WinMaxY=ScreenHeight);
  467. end;
  468. procedure LineWrite(const temp:String);
  469. {
  470. Write a Line to the screen, doesn't write on 80,25 under Dos
  471. the Current CurrX is set to WinMax. NO MEMORY UPDATE!
  472. }
  473. begin
  474. CurrX:=WinMaxX+1;
  475. if (CurrX>=ScreenWidth) then
  476. CurrX:=WinMaxX;
  477. ttySendStr(Temp);
  478. end;
  479. procedure DoEmptyLine(y,xl,xh:longint);
  480. {
  481. Write an Empty line at Row Y from Col Xl to XH, Memory is also updated
  482. }
  483. var
  484. len : longint;
  485. begin
  486. ttyGotoXY(xl,y);
  487. len:=xh-xl+1;
  488. LineWrite(Space(len));
  489. FillWord(ConsoleBuf^[(y-1)*ScreenWidth+xl-1],len,(TextAttr shl 8)+ord(' '));
  490. end;
  491. procedure DoScrollLine(y1,y2,xl,xh:longint);
  492. {
  493. Move Line y1 to y2, use only columns Xl-Xh, Memory is updated also
  494. }
  495. var
  496. Temp : string;
  497. idx,
  498. OldAttr,
  499. x,attr : longint;
  500. begin
  501. ttyGotoXY(xl,y2);
  502. { precalc ConsoleBuf[] y-offset }
  503. idx:=(y1-1)*ScreenWidth-1;
  504. { update screen }
  505. OldAttr:=$ff;
  506. Temp:='';
  507. For x:=xl To xh Do
  508. Begin
  509. attr:=ConsoleBuf^[idx+x].attr;
  510. if (attr<>OldAttr) and (not Redir) then
  511. begin
  512. temp:=temp+Attr2Ansi(Attr,OldAttr);
  513. OldAttr:=Attr;
  514. end;
  515. Temp:=Temp+ConsoleBuf^[idx+x].ch;
  516. if (x=xh) or (length(Temp)>240) then
  517. begin
  518. LineWrite(Temp);
  519. Temp:='';
  520. end;
  521. End;
  522. {Update memory copy}
  523. Move(ConsoleBuf^[(y1-1)*ScreenWidth+xl-1],ConsoleBuf^[(y2-1)*ScreenWidth+xl-1],(xh-xl+1)*2);
  524. end;
  525. Procedure TextColor(Color: Byte);
  526. {
  527. Switch foregroundcolor
  528. }
  529. Begin
  530. ttyColor((Color and $8f) or (TextAttr and $70));
  531. End;
  532. Procedure TextBackground(Color: Byte);
  533. {
  534. Switch backgroundcolor
  535. }
  536. Begin
  537. ttyColor((Color shl 4) or (TextAttr and $0f));
  538. End;
  539. Procedure HighVideo;
  540. {
  541. Set highlighted output.
  542. }
  543. Begin
  544. TextColor(TextAttr Or $08);
  545. End;
  546. Procedure LowVideo;
  547. {
  548. Set normal output
  549. }
  550. Begin
  551. TextColor(TextAttr And $77);
  552. End;
  553. Procedure NormVideo;
  554. {
  555. Set normal back and foregroundcolors.
  556. }
  557. Begin
  558. TextColor(7);
  559. TextBackGround(0);
  560. End;
  561. Procedure GotoXy(X: Byte; Y: Byte);
  562. {
  563. Go to coordinates X,Y in the current window.
  564. }
  565. Begin
  566. If (X>0) and (X<=WinMaxX- WinMinX+1) and
  567. (Y>0) and (Y<=WinMaxY-WinMinY+1) Then
  568. Begin
  569. Inc(X,WinMinX-1);
  570. Inc(Y,WinMinY-1);
  571. ttyGotoXY(x,y);
  572. End;
  573. End;
  574. Procedure Window(X1, Y1, X2, Y2: Byte);
  575. {
  576. Set screen window to the specified coordinates.
  577. }
  578. Begin
  579. if (X1>X2) or (X2>ScreenWidth) or
  580. (Y1>Y2) or (Y2>ScreenHeight) then
  581. exit;
  582. WindMin:=((Y1-1) Shl 8)+(X1-1);
  583. WindMax:=((Y2-1) Shl 8)+(X2-1);
  584. GoToXY(1,1);
  585. End;
  586. Procedure ClrScr;
  587. {
  588. Clear the current window, and set the cursor on x1,y1
  589. }
  590. Var
  591. CY,i : Longint;
  592. oldflush : boolean;
  593. Begin
  594. { See if color has changed }
  595. if OldTextAttr<>TextAttr then
  596. begin
  597. i:=TextAttr;
  598. TextAttr:=OldTextAttr;
  599. ttyColor(i);
  600. end;
  601. oldflush:=ttySetFlush(Flushing);
  602. if FullWin then
  603. begin
  604. if not Redir then
  605. ttySendStr(#27'[H'#27'[2J');
  606. CurrX:=1;
  607. CurrY:=1;
  608. FillWord(ConsoleBuf^,ScreenWidth*ScreenHeight,(TextAttr shl 8)+ord(' '));
  609. end
  610. else
  611. begin
  612. For Cy:=WinMinY To WinMaxY Do
  613. DoEmptyLine(Cy,WinMinX,WinMaxX);
  614. GoToXY(1,1);
  615. end;
  616. ttySetFlush(oldflush);
  617. End;
  618. Procedure ClrEol;
  619. {
  620. Clear from current position to end of line.
  621. }
  622. var
  623. len,i : longint;
  624. IsLastLine : boolean;
  625. Begin
  626. { See if color has changed }
  627. if OldTextAttr<>TextAttr then
  628. begin
  629. i:=TextAttr;
  630. TextAttr:=OldTextAttr;
  631. ttyColor(i);
  632. end;
  633. if FullWin or (WinMaxX = ScreenWidth) then
  634. begin
  635. if not Redir then
  636. ttySendStr(#27'[K');
  637. end
  638. else
  639. begin
  640. { Tweak windmax so no scrolling happends }
  641. len:=WinMaxX-CurrX+1;
  642. IsLastLine:=false;
  643. if CurrY=WinMaxY then
  644. begin
  645. inc(WindMax,$0203);
  646. IsLastLine:=true;
  647. end;
  648. ttySendStr(Space(len));
  649. if IsLastLine then
  650. dec(WindMax,$0203);
  651. ttyGotoXY(0,0);
  652. end;
  653. End;
  654. Function WhereX: Byte;
  655. {
  656. Return current X-position of cursor.
  657. }
  658. Begin
  659. WhereX:=CurrX-WinMinX+1;
  660. End;
  661. Function WhereY: Byte;
  662. {
  663. Return current Y-position of cursor.
  664. }
  665. Begin
  666. WhereY:=CurrY-WinMinY+1;
  667. End;
  668. Procedure ScrollScrnRegionUp(xl,yl,xh,yh, count: longint);
  669. {
  670. Scroll the indicated region count lines up. The empty lines are filled
  671. with blanks in the current color. The screen position is restored
  672. afterwards.
  673. }
  674. Var
  675. y,oldx,oldy : byte;
  676. oldflush : boolean;
  677. Begin
  678. oldflush:=ttySetFlush(Flushing);
  679. oldx:=CurrX;
  680. oldy:=CurrY;
  681. {Scroll}
  682. For y:=yl to yh-count do
  683. DoScrollLine(y+count,y,xl,xh);
  684. {Restore TextAttr}
  685. ttySendStr(Attr2Ansi(TextAttr,$ff));
  686. {Fill the rest with empty lines}
  687. for y:=yh-count+1 to yh do
  688. DoEmptyLine(y,xl,xh);
  689. {Restore current position}
  690. ttyGotoXY(OldX,OldY);
  691. ttySetFlush(oldflush);
  692. End;
  693. Procedure ScrollScrnRegionDown(xl,yl,xh,yh, count: longint);
  694. {
  695. Scroll the indicated region count lines down. The empty lines are filled
  696. with blanks in the current color. The screen position is restored
  697. afterwards.
  698. }
  699. Var
  700. y,oldx,oldy : byte;
  701. oldflush : boolean;
  702. Begin
  703. oldflush:=ttySetFlush(Flushing);
  704. oldx:=CurrX;
  705. oldy:=CurrY;
  706. {Scroll}
  707. for y:=yh downto yl+count do
  708. DoScrollLine(y-count,y,xl,xh);
  709. {Restore TextAttr}
  710. ttySendStr(Attr2Ansi(TextAttr,$ff));
  711. {Fill the rest with empty lines}
  712. for y:=yl to yl+count-1 do
  713. DoEmptyLine(y,xl,xh);
  714. {Restore current position}
  715. ttyGotoXY(OldX,OldY);
  716. ttySetFlush(oldflush);
  717. End;
  718. {*************************************************************************
  719. KeyBoard
  720. *************************************************************************}
  721. Const
  722. KeyBufferSize = 20;
  723. var
  724. KeyBuffer : Array[0..KeyBufferSize-1] of Char;
  725. KeyPut,
  726. KeySend : longint;
  727. Procedure PushKey(Ch:char);
  728. Var
  729. Tmp : Longint;
  730. Begin
  731. Tmp:=KeyPut;
  732. Inc(KeyPut);
  733. If KeyPut>=KeyBufferSize Then
  734. KeyPut:=0;
  735. If KeyPut<>KeySend Then
  736. KeyBuffer[Tmp]:=Ch
  737. Else
  738. KeyPut:=Tmp;
  739. End;
  740. Function PopKey:char;
  741. Begin
  742. If KeyPut<>KeySend Then
  743. Begin
  744. PopKey:=KeyBuffer[KeySend];
  745. Inc(KeySend);
  746. If KeySend>=KeyBufferSize Then
  747. KeySend:=0;
  748. End
  749. Else
  750. PopKey:=#0;
  751. End;
  752. Procedure PushExt(b:byte);
  753. begin
  754. PushKey(#0);
  755. PushKey(chr(b));
  756. end;
  757. const
  758. AltKeyStr : string[38]='qwertyuiopasdfghjklzxcvbnm1234567890-=';
  759. AltCodeStr : string[38]=#016#017#018#019#020#021#022#023#024#025#030#031#032#033#034#035#036#037#038+
  760. #044#045#046#047#048#049#050#120#121#122#123#124#125#126#127#128#129#130#131;
  761. Function FAltKey(ch:char):byte;
  762. var
  763. Idx : longint;
  764. Begin
  765. Idx:=Pos(ch,AltKeyStr);
  766. if Idx>0 then
  767. FAltKey:=byte(AltCodeStr[Idx])
  768. else
  769. FAltKey:=0;
  770. End;
  771. Function KeyPressed:Boolean;
  772. var
  773. fdsin : fdSet;
  774. Begin
  775. if (KeySend<>KeyPut) or (InCnt>0) then
  776. KeyPressed:=true
  777. else
  778. begin
  779. FD_Zero(fdsin);
  780. fd_Set(TTYin,fdsin);
  781. Keypressed:=(Select(TTYIn+1,@fdsin,nil,nil,0)>0);
  782. end;
  783. End;
  784. Function ReadKey:char;
  785. Var
  786. ch : char;
  787. OldState,
  788. State : longint;
  789. Begin
  790. {Check Buffer first}
  791. if KeySend<>KeyPut then
  792. begin
  793. ReadKey:=PopKey;
  794. exit;
  795. end;
  796. {Wait for Key}
  797. repeat
  798. until keypressed;
  799. ch:=ttyRecvChar;
  800. {Esc Found ?}
  801. If (ch=#27) then
  802. begin
  803. State:=1;
  804. Delay(10);
  805. while (State<>0) and (KeyPressed) do
  806. begin
  807. ch:=ttyRecvChar;
  808. OldState:=State;
  809. State:=0;
  810. case OldState of
  811. 1 : begin {Esc}
  812. case ch of
  813. 'a'..'z',
  814. '0'..'9',
  815. '-','=' : PushExt(FAltKey(ch));
  816. #10 : PushKey(#10);
  817. '[' : State:=2;
  818. else
  819. begin
  820. PushKey(ch);
  821. PushKey(#27);
  822. end;
  823. end;
  824. end;
  825. 2 : begin {Esc[}
  826. case ch of
  827. '[' : State:=3;
  828. 'A' : PushExt(72);
  829. 'B' : PushExt(80);
  830. 'C' : PushExt(77);
  831. 'D' : PushExt(75);
  832. 'G' : PushKey('5');
  833. 'H' : PushExt(71);
  834. 'K' : PushExt(79);
  835. '1' : State:=4;
  836. '2' : State:=5;
  837. '3' : PushExt(83);
  838. '4' : PushExt(79);
  839. '5' : PushExt(73);
  840. '6' : PushExt(81);
  841. else
  842. begin
  843. PushKey(ch);
  844. PushKey('[');
  845. PushKey(#27);
  846. end;
  847. end;
  848. if ch in ['3'..'6'] then
  849. State:=255;
  850. end;
  851. 3 : begin {Esc[[}
  852. case ch of
  853. 'A' : PushExt(59);
  854. 'B' : PushExt(60);
  855. 'C' : PushExt(61);
  856. 'D' : PushExt(62);
  857. 'E' : PushExt(63);
  858. end;
  859. end;
  860. 4 : begin
  861. case ch of
  862. '~' : PushExt(71);
  863. '7' : PushExt(64);
  864. '8' : PushExt(65);
  865. '9' : PushExt(66);
  866. end;
  867. if (Ch<>'~') then
  868. State:=255;
  869. end;
  870. 5 : begin
  871. case ch of
  872. '~' : PushExt(82);
  873. '0' : pushExt(67);
  874. '1' : PushExt(68);
  875. '3' : PushExt(133);
  876. '4' : PushExt(134);
  877. end;
  878. if (Ch<>'~') then
  879. State:=255;
  880. end;
  881. 255 : ;
  882. end;
  883. if State<>0 then
  884. Delay(10);
  885. end;
  886. if State=1 then
  887. PushKey(ch);
  888. end
  889. else
  890. Begin
  891. case ch of
  892. #127 : PushExt(83);
  893. else
  894. PushKey(ch);
  895. end;
  896. End;
  897. ReadKey:=PopKey;
  898. End;
  899. Procedure Delay(DTime: Word);
  900. {
  901. Wait for DTime milliseconds.
  902. }
  903. Begin
  904. Select(0,nil,nil,nil,DTime);
  905. End;
  906. {****************************************************************************
  907. Write(ln)/Read(ln) support
  908. ****************************************************************************}
  909. procedure DoLn;
  910. begin
  911. if CurrY=WinMaxY then
  912. begin
  913. if FullWin then
  914. begin
  915. ttySendStr(#10#13);
  916. CurrX:=WinMinX;
  917. CurrY:=WinMaxY;
  918. end
  919. else
  920. begin
  921. ScrollScrnRegionUp(WinMinX,WinMinY,WinMaxX,WinMaxY,1);
  922. ttyGotoXY(WinMinX,WinMaxY);
  923. end;
  924. end
  925. else
  926. ttyGotoXY(WinMinX,CurrY+1);
  927. end;
  928. var
  929. Lastansi : boolean;
  930. AnsiCode : string[32];
  931. Procedure DoWrite(const s:String);
  932. {
  933. Write string to screen, parse most common AnsiCodes
  934. }
  935. var
  936. found,
  937. OldFlush : boolean;
  938. x,y,
  939. i,j,
  940. SendBytes : longint;
  941. function AnsiPara(var hstr:string):byte;
  942. var
  943. k,j : longint;
  944. code : word;
  945. begin
  946. j:=pos(';',hstr);
  947. if j=0 then
  948. j:=length(hstr);
  949. val(copy(hstr,3,j-3),k,code);
  950. Delete(hstr,3,j-2);
  951. if k=0 then
  952. k:=1;
  953. AnsiPara:=k;
  954. end;
  955. procedure SendText;
  956. var
  957. LeftX : longint;
  958. begin
  959. while (SendBytes>0) do
  960. begin
  961. LeftX:=WinMaxX-CurrX+1;
  962. if (SendBytes>LeftX) or (CurrX+SendBytes=81) then
  963. begin
  964. ttyWrite(Copy(s,i-SendBytes,LeftX));
  965. dec(SendBytes,LeftX);
  966. DoLn;
  967. end
  968. else
  969. begin
  970. ttyWrite(Copy(s,i-SendBytes,SendBytes));
  971. SendBytes:=0;
  972. end;
  973. end;
  974. end;
  975. begin
  976. oldflush:=ttySetFlush(Flushing);
  977. { Support textattr:= changing }
  978. if OldTextAttr<>TextAttr then
  979. begin
  980. i:=TextAttr;
  981. TextAttr:=OldTextAttr;
  982. ttyColor(i);
  983. end;
  984. { write the stuff }
  985. SendBytes:=0;
  986. i:=1;
  987. while (i<=length(s)) do
  988. begin
  989. if (s[i]=#27) or (LastAnsi) then
  990. begin
  991. SendText;
  992. LastAnsi:=false;
  993. j:=i;
  994. found:=false;
  995. while (j<=length(s)) and (not found) do
  996. begin
  997. found:=not (s[j] in [#27,'[','0'..'9',';','?']);
  998. inc(j);
  999. end;
  1000. Ansicode:=AnsiCode+Copy(s,i,j-i);
  1001. if found then
  1002. begin
  1003. case AnsiCode[length(AnsiCode)] of
  1004. 'm' : ttyColor(Ansi2Attr(AnsiCode,TextAttr));
  1005. 'H' : begin {No other way :( Coz First Para=Y}
  1006. y:=AnsiPara(AnsiCode);
  1007. x:=AnsiPara(AnsiCode);
  1008. GotoXY(y,x);
  1009. end;
  1010. 'J' : if AnsiPara(AnsiCode)=2 then
  1011. ClrScr;
  1012. 'K' : ClrEol;
  1013. 'A' : GotoXY(CurrX,Max(CurrY-AnsiPara(AnsiCode),WinMinY));
  1014. 'B' : GotoXY(CurrX,Min(CurrY+AnsiPara(AnsiCode),WinMaxY));
  1015. 'C' : GotoXY(Min(CurrX+AnsiPara(AnsiCode),WinMaxX),CurrY);
  1016. 'D' : GotoXY(Max(CurrX-AnsiPara(AnsiCode),WinMinX),CurrY);
  1017. 'h' : ; {Stupid Thedraw [?7h Code}
  1018. else
  1019. found:=false;
  1020. end;
  1021. end
  1022. else
  1023. begin
  1024. LastAnsi:=true;
  1025. found:=true;
  1026. end;
  1027. {Clear AnsiCode?}
  1028. if not LastAnsi then
  1029. AnsiCode:='';
  1030. {Increase Idx or SendBytes}
  1031. if found then
  1032. i:=j-1
  1033. else
  1034. inc(SendBytes);
  1035. end
  1036. else
  1037. begin
  1038. LastAnsi:=false;
  1039. case s[i] of
  1040. #13 : begin {CR}
  1041. SendText;
  1042. ttyGotoXY(WinMinX,CurrY);
  1043. end;
  1044. #10 : begin {NL}
  1045. SendText;
  1046. DoLn;
  1047. end;
  1048. #9 : begin {Tab}
  1049. SendText;
  1050. ttyWrite(Space(9-((CurrX-1) and $08)));
  1051. end;
  1052. #8 : begin {BackSpace}
  1053. SendText;
  1054. ttyWrite(#8);
  1055. end;
  1056. else
  1057. inc(SendBytes);
  1058. end;
  1059. end;
  1060. inc(i);
  1061. end;
  1062. if SendBytes>0 then
  1063. SendText;
  1064. ttySetFlush(oldFLush);
  1065. end;
  1066. Function CrtWrite(Var F: TextRec): Integer;
  1067. {
  1068. Top level write function for CRT
  1069. }
  1070. Var
  1071. Temp : String;
  1072. Begin
  1073. Move(F.BufPTR^[0],Temp[1],F.BufPos);
  1074. temp[0]:=chr(F.BufPos);
  1075. DoWrite(Temp);
  1076. F.BufPos:=0;
  1077. CrtWrite:=0;
  1078. End;
  1079. Function CrtRead(Var F: TextRec): Integer;
  1080. {
  1081. Read from CRT associated file.
  1082. }
  1083. var
  1084. i : longint;
  1085. Begin
  1086. F.BufEnd:=fdRead(F.Handle, F.BufPtr^, F.BufSize);
  1087. { fix #13 only's -> #10 to overcome terminal setting }
  1088. for i:=1to F.BufEnd do
  1089. begin
  1090. if (F.BufPtr^[i-1]=#13) and (F.BufPtr^[i]<>#10) then
  1091. F.BufPtr^[i-1]:=#10;
  1092. end;
  1093. F.BufPos:=F.BufEnd;
  1094. CrtWrite(F);
  1095. CrtRead:=0;
  1096. End;
  1097. Function CrtReturn:Integer;
  1098. Begin
  1099. CrtReturn:=0;
  1100. end;
  1101. Function CrtClose(Var F: TextRec): Integer;
  1102. {
  1103. Close CRT associated file.
  1104. }
  1105. Begin
  1106. F.Mode:=fmClosed;
  1107. CrtClose:=0;
  1108. End;
  1109. Function CrtOpen(Var F: TextRec): Integer;
  1110. {
  1111. Open CRT associated file.
  1112. }
  1113. Begin
  1114. If F.Mode=fmOutput Then
  1115. begin
  1116. TextRec(F).InOutFunc:=@CrtWrite;
  1117. TextRec(F).FlushFunc:=@CrtWrite;
  1118. end
  1119. Else
  1120. begin
  1121. F.Mode:=fmInput;
  1122. TextRec(F).InOutFunc:=@CrtRead;
  1123. TextRec(F).FlushFunc:=@CrtReturn;
  1124. end;
  1125. TextRec(F).CloseFunc:=@CrtClose;
  1126. CrtOpen:=0;
  1127. End;
  1128. procedure AssignCrt(var F: Text);
  1129. {
  1130. Assign a file to the console. All output on file goes to console instead.
  1131. }
  1132. begin
  1133. Assign(F,'');
  1134. TextRec(F).OpenFunc:=@CrtOpen;
  1135. end;
  1136. {******************************************************************************
  1137. High Level Functions
  1138. ******************************************************************************}
  1139. Procedure DelLine;
  1140. {
  1141. Delete current line. Scroll subsequent lines up
  1142. }
  1143. Begin
  1144. ScrollScrnRegionUp(WinMinX, CurrY, WinMaxX, WinMaxY, 1);
  1145. End;
  1146. Procedure InsLine;
  1147. {
  1148. Insert line at current cursor position. Scroll subsequent lines down.
  1149. }
  1150. Begin
  1151. ScrollScrnRegionDown(WinMinX, CurrY, WinMaxX, WinMaxY, 1);
  1152. End;
  1153. Procedure Sound(Hz: Word);
  1154. {
  1155. Does nothing under linux
  1156. }
  1157. begin
  1158. end;
  1159. Procedure NoSound;
  1160. {
  1161. Does nothing under linux
  1162. }
  1163. begin
  1164. end;
  1165. Procedure TextMode(Mode: Integer);
  1166. {
  1167. Only Clears Screen under linux
  1168. }
  1169. begin
  1170. ClrScr;
  1171. end;
  1172. {******************************************************************************
  1173. Initialization
  1174. ******************************************************************************}
  1175. var
  1176. OldIO : TermIos;
  1177. Procedure SetRawMode(b:boolean);
  1178. Var
  1179. Tio : Termios;
  1180. Begin
  1181. if b then
  1182. begin
  1183. TCGetAttr(1,Tio);
  1184. OldIO:=Tio;
  1185. CFMakeRaw(Tio);
  1186. end
  1187. else
  1188. Tio:=OldIO;
  1189. TCSetAttr(1,TCSANOW,Tio);
  1190. End;
  1191. procedure GetXY(var x,y:byte);
  1192. var
  1193. fds : fdSet;
  1194. i,j,
  1195. readed : longint;
  1196. buf : array[0..255] of char;
  1197. s : string[16];
  1198. begin
  1199. x:=0;
  1200. y:=0;
  1201. s:=#27'[6n';
  1202. fdWrite(0,s[1],length(s));
  1203. FD_Zero(fds);
  1204. FD_Set(1,fds);
  1205. if (Select(2,@fds,nil,nil,1000)>0) then
  1206. begin
  1207. readed:=fdRead(1,buf,sizeof(buf));
  1208. i:=0;
  1209. while (i+4<readed) and (buf[i]<>#27) and (buf[i+1]<>'[') do
  1210. inc(i);
  1211. if i+4<readed then
  1212. begin
  1213. s[1]:=#16;
  1214. move(buf[i+2],s[1],16);
  1215. i:=Pos(';',s);
  1216. if i>0 then
  1217. begin
  1218. Val(Copy(s,1,i-1),y);
  1219. j:=Pos('R',s);
  1220. if j=0 then
  1221. j:=length(s)+1;
  1222. Val(Copy(s,i+1,j-i),x);
  1223. end;
  1224. end;
  1225. end;
  1226. end;
  1227. Procedure GetConsoleBuf;
  1228. var
  1229. WinInfo : TWinSize;
  1230. begin
  1231. if Assigned(ConsoleBuf) then
  1232. FreeMem(ConsoleBuf,ScreenHeight*ScreenWidth*2);
  1233. if (not Redir) and IOCtl(TextRec(Output).Handle,TIOCGWINSZ,@Wininfo) then
  1234. begin
  1235. ScreenWidth:=Wininfo.ws_col;
  1236. ScreenHeight:=Wininfo.ws_row;
  1237. end
  1238. else
  1239. begin
  1240. ScreenWidth:=80;
  1241. ScreenHeight:=25;
  1242. end;
  1243. GetMem(ConsoleBuf,ScreenHeight*ScreenWidth*2);
  1244. FillChar(ConsoleBuf^,ScreenHeight*ScreenWidth*2,0);
  1245. end;
  1246. Procedure CrtExit;
  1247. {
  1248. We need to restore normal keyboard mode upon exit !!
  1249. }
  1250. Begin
  1251. ttyFlushOutput;
  1252. SetRawMode(False);
  1253. { remove console buf }
  1254. if Assigned(ConsoleBuf) then
  1255. FreeMem(ConsoleBuf,ScreenHeight*ScreenWidth*2);
  1256. ExitProc:=ExitSave;
  1257. End;
  1258. Begin
  1259. {Hook Exit}
  1260. ExitSave:=ExitProc;
  1261. ExitProc:=@CrtExit;
  1262. { Redirect the standard output }
  1263. assigncrt(Output);
  1264. Rewrite(Output);
  1265. TextRec(Output).Handle:=StdOutputHandle;
  1266. assigncrt(Input);
  1267. Reset(Input);
  1268. TextRec(Input).Handle:=StdInputHandle;
  1269. { Are we redirected to a file ? }
  1270. Redir:=not IsAtty(TextRec(Output).Handle);
  1271. { Get Size of terminal }
  1272. GetConsoleBuf;
  1273. {Get Current X&Y or Reset to Home}
  1274. if Redir then
  1275. begin
  1276. CurrX:=1;
  1277. CurrY:=1;
  1278. end
  1279. else
  1280. begin
  1281. { Set default Terminal Settings }
  1282. SetRawMode(True);
  1283. { Get current X,Y if not set already }
  1284. GetXY(CurrX,CurrY);
  1285. if (CurrX=0) then
  1286. begin
  1287. CurrX:=1;
  1288. CurrY:=1;
  1289. ttySendStr(#27'[H');
  1290. end;
  1291. {Reset Attribute (TextAttr=7 at startup)}
  1292. ttySendStr(#27'[m');
  1293. end;
  1294. End.
  1295. {
  1296. $Log$
  1297. Revision 1.11 1998-10-30 12:11:51 peter
  1298. * fixed fullwi, which did not check for 1,1
  1299. Revision 1.10 1998/10/27 11:13:27 peter
  1300. * fixed ttyWrite() with #8
  1301. Revision 1.9 1998/10/15 08:31:53 peter
  1302. + get winsize at startup
  1303. + ConsoleBuf to interface
  1304. Revision 1.8 1998/08/28 11:00:20 peter
  1305. * fixed #8 writing
  1306. Revision 1.7 1998/07/04 11:17:18 peter
  1307. * fixes for window (from "Heinz Ziegenhorn" <[email protected]>)
  1308. Revision 1.6 1998/06/19 16:51:50 peter
  1309. * added #13 -> #10 translation for CrtRead to overcome readln probs
  1310. Revision 1.5 1998/06/19 14:47:52 michael
  1311. + Enter key maps again to #13
  1312. Revision 1.4 1998/05/06 12:35:26 michael
  1313. + Removed log from before restored version.
  1314. Revision 1.3 1998/04/16 07:49:11 michael
  1315. * fixed bug. Clrscr and Clreol didn't take change in textattr in account.
  1316. Revision 1.2 1998/04/05 13:56:54 peter
  1317. - fixed mouse to compile with $i386_att
  1318. + linux crt supports redirecting (not Esc-codes anymore)
  1319. }