crt.pp 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Michael Van Canneyt and Peter Vreman,
  4. members of the Free Pascal development team.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit Crt;
  12. Interface
  13. {$i crth.inc}
  14. Const
  15. { Controlling consts }
  16. Flushing = false; {if true then don't buffer output}
  17. ConsoleMaxX = 1024;
  18. ConsoleMaxY = 1024;
  19. ScreenHeight : longint = 25;
  20. ScreenWidth : longint = 80;
  21. Type
  22. TCharAttr=packed record
  23. ch : char;
  24. attr : byte;
  25. end;
  26. TConsoleBuf=Array[0..ConsoleMaxX*ConsoleMaxY-1] of TCharAttr;
  27. PConsoleBuf=^TConsoleBuf;
  28. var
  29. ConsoleBuf : PConsoleBuf;
  30. Implementation
  31. uses BaseUnix ,unix, termio;
  32. {
  33. The definitions of TextRec and FileRec are in separate files.
  34. }
  35. {$i textrec.inc}
  36. Const
  37. OldTextAttr : byte = $07;
  38. Var
  39. CurrX,CurrY : Byte;
  40. OutputRedir, InputRedir : boolean; { is the output/input being redirected (not a TTY) }
  41. WinMinX,
  42. WinMinY,
  43. WinMaxX,
  44. WinMaxY : Longint;
  45. {*****************************************************************************
  46. Some Handy Functions Not in the System.PP
  47. *****************************************************************************}
  48. Function Str(l:longint):string;
  49. {
  50. Return a String of the longint
  51. }
  52. var
  53. hstr : string[32];
  54. begin
  55. System.Str(l,hstr);
  56. Str:=hstr;
  57. end;
  58. Function Max(l1,l2:longint):longint;
  59. {
  60. Return the maximum of l1 and l2
  61. }
  62. begin
  63. if l1>l2 then
  64. Max:=l1
  65. else
  66. Max:=l2;
  67. end;
  68. Function Min(l1,l2:longint):longint;
  69. {
  70. Return the minimum of l1 and l2
  71. }
  72. begin
  73. if l1<l2 then
  74. Min:=l1
  75. else
  76. Min:=l2;
  77. end;
  78. {*****************************************************************************
  79. Optimal AnsiString Conversion Routines
  80. *****************************************************************************}
  81. Function XY2Ansi(x,y,ox,oy:longint):String;
  82. {
  83. Returns a string with the escape sequences to go to X,Y on the screen
  84. }
  85. Begin
  86. if y=oy then
  87. begin
  88. if x=ox then
  89. begin
  90. // this workaround should improve behaviour on some terminals.
  91. // debian bug 216057 but I also observed this with video on FreeBSD
  92. if x=screenwidth then
  93. XY2Ansi:=#27'['+Str(y)+';'+Str(x)+'H'
  94. else
  95. // end workaround
  96. XY2Ansi:='';
  97. exit;
  98. end;
  99. {$ifdef Linux} // linux CRT shortcut
  100. if x=1 then
  101. begin
  102. XY2Ansi:=#13;
  103. exit;
  104. end;
  105. {$endif}
  106. if x>ox then
  107. begin
  108. XY2Ansi:=#27'['+Str(x-ox)+'C';
  109. exit;
  110. end
  111. else
  112. begin
  113. XY2Ansi:=#27'['+Str(ox-x)+'D';
  114. exit;
  115. end;
  116. end;
  117. if x=ox then
  118. begin
  119. if y>oy then
  120. begin
  121. XY2Ansi:=#27'['+Str(y-oy)+'B';
  122. exit;
  123. end
  124. else
  125. begin
  126. XY2Ansi:=#27'['+Str(oy-y)+'A';
  127. exit;
  128. end;
  129. end;
  130. {$ifdef Linux} // this shortcut isn't for everybody
  131. if (x=1) and (oy+1=y) then
  132. XY2Ansi:=#13#10
  133. else
  134. {$endif}
  135. XY2Ansi:=#27'['+Str(y)+';'+Str(x)+'H';
  136. End;
  137. const
  138. AnsiTbl : string[8]='04261537';
  139. Function Attr2Ansi(Attr,OAttr:longint):string;
  140. {
  141. Convert Attr to an Ansi String, the Optimal code is calculate
  142. with use of the old OAttr
  143. }
  144. var
  145. hstr : string[16];
  146. OFg,OBg,Fg,Bg : longint;
  147. procedure AddSep(ch:char);
  148. begin
  149. if length(hstr)>0 then
  150. hstr:=hstr+';';
  151. hstr:=hstr+ch;
  152. end;
  153. begin
  154. if Attr=OAttr then
  155. begin
  156. Attr2Ansi:='';
  157. exit;
  158. end;
  159. Hstr:='';
  160. Fg:=Attr and $f;
  161. Bg:=Attr shr 4;
  162. OFg:=OAttr and $f;
  163. OBg:=OAttr shr 4;
  164. if (OFg<>7) or (Fg=7) or ((OFg>7) and (Fg<8)) or ((OBg>7) and (Bg<8)) then
  165. begin
  166. hstr:='0';
  167. OFg:=7;
  168. OBg:=0;
  169. end;
  170. if (Fg>7) and (OFg<8) then
  171. begin
  172. AddSep('1');
  173. OFg:=OFg or 8;
  174. end;
  175. if (Bg and 8)<>(OBg and 8) then
  176. begin
  177. AddSep('5');
  178. OBg:=OBg or 8;
  179. end;
  180. if (Fg<>OFg) then
  181. begin
  182. AddSep('3');
  183. hstr:=hstr+AnsiTbl[(Fg and 7)+1];
  184. end;
  185. if (Bg<>OBg) then
  186. begin
  187. AddSep('4');
  188. hstr:=hstr+AnsiTbl[(Bg and 7)+1];
  189. end;
  190. if hstr='0' then
  191. hstr:='';
  192. Attr2Ansi:=#27'['+hstr+'m';
  193. end;
  194. Function Ansi2Attr(Const HStr:String;oattr:longint):longint;
  195. {
  196. Convert an Escape sequence to an attribute value, uses Oattr as the last
  197. color written
  198. }
  199. var
  200. i,j : longint;
  201. begin
  202. i:=2;
  203. if (Length(HStr)<3) or (Hstr[1]<>#27) or (Hstr[2]<>'[') then
  204. i:=255;
  205. while (i<length(Hstr)) do
  206. begin
  207. inc(i);
  208. case Hstr[i] of
  209. '0' : OAttr:=7;
  210. '1' : OAttr:=OAttr or $8;
  211. '5' : OAttr:=OAttr or $80;
  212. '3' : begin
  213. inc(i);
  214. j:=pos(Hstr[i],AnsiTbl);
  215. if j>0 then
  216. OAttr:=(OAttr and $f8) or (j-1);
  217. end;
  218. '4' : begin
  219. inc(i);
  220. j:=pos(Hstr[i],AnsiTbl);
  221. if j>0 then
  222. OAttr:=(OAttr and $8f) or ((j-1) shl 4);
  223. end;
  224. 'm' : i:=length(HStr);
  225. end;
  226. end;
  227. Ansi2Attr:=OAttr;
  228. end;
  229. {*****************************************************************************
  230. Buffered StdIn/StdOut IO
  231. *****************************************************************************}
  232. const
  233. ttyIn=0; {Handles for stdin/stdout}
  234. ttyOut=1;
  235. ttyFlush:boolean=true;
  236. {Buffered Input/Output}
  237. InSize=256;
  238. OutSize=1024;
  239. var
  240. InBuf : array[0..InSize-1] of char;
  241. InCnt,
  242. InHead,
  243. InTail : longint;
  244. OutBuf : array[0..OutSize-1] of char;
  245. OutCnt : longint;
  246. {Flush Output Buffer}
  247. procedure ttyFlushOutput;
  248. begin
  249. if OutCnt>0 then
  250. begin
  251. fpWrite(ttyOut,OutBuf,OutCnt);
  252. OutCnt:=0;
  253. end;
  254. end;
  255. Function ttySetFlush(b:boolean):boolean;
  256. begin
  257. ttySetFlush:=ttyFlush;
  258. ttyFlush:=b;
  259. if ttyFlush then
  260. ttyFlushOutput;
  261. end;
  262. {Send Char to Remote}
  263. Procedure ttySendChar(c:char);
  264. Begin
  265. if OutCnt<OutSize then
  266. begin
  267. OutBuf[OutCnt]:=c;
  268. inc(OutCnt);
  269. end;
  270. {Full ?}
  271. if (OutCnt>=OutSize) then
  272. ttyFlushOutput;
  273. End;
  274. {Send String to Remote}
  275. procedure ttySendStr(const hstr:string);
  276. var
  277. i : longint;
  278. begin
  279. for i:=1to length(hstr) do
  280. ttySendChar(hstr[i]);
  281. if ttyFlush then
  282. ttyFlushOutput;
  283. end;
  284. {Get Char from Remote}
  285. function ttyRecvChar:char;
  286. var
  287. Readed,i : longint;
  288. begin
  289. {Buffer Empty? Yes, Input from StdIn}
  290. if (InHead=InTail) then
  291. begin
  292. {Calc Amount of Chars to Read}
  293. i:=InSize-InHead;
  294. if InTail>InHead then
  295. i:=InTail-InHead;
  296. {Read}
  297. Readed:=fpread(TTYIn,InBuf[InHead],i);
  298. {Increase Counters}
  299. inc(InCnt,Readed);
  300. inc(InHead,Readed);
  301. {Wrap if End has Reached}
  302. if InHead>=InSize then
  303. InHead:=0;
  304. end;
  305. {Check Buffer}
  306. if (InCnt=0) then
  307. ttyRecvChar:=#0
  308. else
  309. begin
  310. ttyRecvChar:=InBuf[InTail];
  311. dec(InCnt);
  312. inc(InTail);
  313. if InTail>=InSize then
  314. InTail:=0;
  315. end;
  316. end;
  317. {*****************************************************************************
  318. Screen Routines not Window Depended
  319. *****************************************************************************}
  320. procedure ttyGotoXY(x,y:longint);
  321. {
  322. Goto XY on the Screen, if a value is 0 the goto the current
  323. postion of that value and always recalc the ansicode for it
  324. }
  325. begin
  326. if x=0 then
  327. begin
  328. x:=CurrX;
  329. CurrX:=$ff;
  330. end;
  331. if y=0 then
  332. begin
  333. y:=CurrY;
  334. CurrY:=$ff;
  335. end;
  336. if OutputRedir then
  337. begin
  338. if longint(y)-longint(CurrY)=1 then
  339. ttySendStr(#10);
  340. end
  341. else
  342. ttySendStr(XY2Ansi(x,y,CurrX,CurrY));
  343. CurrX:=x;
  344. CurrY:=y;
  345. end;
  346. procedure ttyColor(a:longint);
  347. {
  348. Set Attribute to A, only output if not the last attribute is set
  349. }
  350. begin
  351. if a<>OldTextAttr then
  352. begin
  353. if not OutputRedir then
  354. ttySendStr(Attr2Ansi(a,OldTextAttr));
  355. TextAttr:=a;
  356. OldTextAttr:=a;
  357. end;
  358. end;
  359. procedure ttyWrite(const s:string);
  360. {
  361. Write a string to the output, memory copy and Current X&Y are also updated
  362. }
  363. var
  364. idx,i : longint;
  365. begin
  366. ttySendStr(s);
  367. {Update MemCopy}
  368. idx:=(CurrY-1)*ScreenWidth-1;
  369. for i:=1to length(s) do
  370. if s[i]=#8 then
  371. begin
  372. if CurrX>1 then
  373. dec(CurrX);
  374. end
  375. else
  376. begin
  377. ConsoleBuf^[idx+CurrX].ch:=s[i];
  378. ConsoleBuf^[idx+CurrX].attr:=TextAttr;
  379. inc(CurrX);
  380. if CurrX>ScreenWidth then
  381. CurrX:=ScreenWidth;
  382. end;
  383. end;
  384. Function FullWin:boolean;
  385. {
  386. Full Screen 80x25? Window(1,1,80,25) is used, allows faster routines
  387. }
  388. begin
  389. FullWin:=(WinMinX=1) and (WinMinY=1) and
  390. (WinMaxX=ScreenWidth) and (WinMaxY=ScreenHeight);
  391. end;
  392. procedure LineWrite(const temp:String);
  393. {
  394. Write a Line to the screen, doesn't write on 80,25 under Dos
  395. the Current CurrX is set to WinMax. NO MEMORY UPDATE!
  396. }
  397. begin
  398. CurrX:=WinMaxX+1;
  399. ttySendStr(Temp);
  400. end;
  401. Procedure DoEmptyLine(y,xl,xh:Longint);
  402. {
  403. Write an empty line at row Y from column Xl to Xh. Memory is also updated.
  404. }
  405. Var
  406. len : Longint;
  407. blank_with_attribute : TCharAttr;
  408. Begin
  409. ttyGotoXY(xl,y);
  410. len:=xh-xl+1;
  411. LineWrite(Space(len));
  412. blank_with_attribute.ch:=' ';
  413. blank_with_attribute.attr:=TextAttr;
  414. FillWord(ConsoleBuf^[(y-1)*ScreenWidth+xl-1],len,word(blank_with_attribute));
  415. End;
  416. procedure DoScrollLine(y1,y2,xl,xh:longint);
  417. {
  418. Move Line y1 to y2, use only columns Xl-Xh, Memory is updated also
  419. }
  420. var
  421. Temp : string;
  422. idx,
  423. OldAttr,
  424. x,attr : longint;
  425. begin
  426. ttyGotoXY(xl,y2);
  427. { precalc ConsoleBuf[] y-offset }
  428. idx:=(y1-1)*ScreenWidth-1;
  429. { update screen }
  430. OldAttr:=$ff;
  431. Temp:='';
  432. For x:=xl To xh Do
  433. Begin
  434. attr:=ConsoleBuf^[idx+x].attr;
  435. if (attr<>OldAttr) and (not OutputRedir) then
  436. begin
  437. temp:=temp+Attr2Ansi(Attr,OldAttr);
  438. OldAttr:=Attr;
  439. end;
  440. Temp:=Temp+ConsoleBuf^[idx+x].ch;
  441. if (x=xh) or (length(Temp)>240) then
  442. begin
  443. LineWrite(Temp);
  444. Temp:='';
  445. end;
  446. End;
  447. {Update memory copy}
  448. Move(ConsoleBuf^[(y1-1)*ScreenWidth+xl-1],ConsoleBuf^[(y2-1)*ScreenWidth+xl-1],(xh-xl+1)*2);
  449. end;
  450. Procedure TextColor(Color: Byte);
  451. {
  452. Switch foregroundcolor
  453. }
  454. var AddBlink : byte;
  455. Begin
  456. If (Color>15) Then
  457. AddBlink:=Blink
  458. else
  459. AddBlink:=0;
  460. ttyColor((Color and $f) or (TextAttr and $70) or AddBlink);
  461. End;
  462. Procedure TextBackground(Color: Byte);
  463. {
  464. Switch backgroundcolor
  465. }
  466. Begin
  467. TextAttr:=((Color shl 4) and ($f0 and not Blink)) or (TextAttr and ($0f OR Blink));
  468. ttyColor(TextAttr);
  469. End;
  470. Procedure HighVideo;
  471. {
  472. Set highlighted output.
  473. }
  474. Begin
  475. TextColor(TextAttr Or $08);
  476. End;
  477. Procedure LowVideo;
  478. {
  479. Set normal output
  480. }
  481. Begin
  482. TextColor(TextAttr And $77);
  483. End;
  484. Procedure NormVideo;
  485. {
  486. Set normal back and foregroundcolors.
  487. }
  488. Begin
  489. TextColor(7);
  490. TextBackGround(0);
  491. End;
  492. Procedure GotoXy(X: Byte; Y: Byte);
  493. {
  494. Go to coordinates X,Y in the current window.
  495. }
  496. Begin
  497. If (X>0) and (X<=WinMaxX- WinMinX+1) and
  498. (Y>0) and (Y<=WinMaxY-WinMinY+1) Then
  499. Begin
  500. Inc(X,WinMinX-1);
  501. Inc(Y,WinMinY-1);
  502. ttyGotoXY(x,y);
  503. End;
  504. End;
  505. Procedure Window(X1, Y1, X2, Y2: Byte);
  506. {
  507. Set screen window to the specified coordinates.
  508. }
  509. Begin
  510. if (X1>X2) or (X2>ScreenWidth) or
  511. (Y1>Y2) or (Y2>ScreenHeight) then
  512. exit;
  513. WinMinX:=X1;
  514. WinMaxX:=X2;
  515. WinMinY:=Y1;
  516. WinMaxY:=Y2;
  517. WindMin:=((Y1-1) Shl 8)+(X1-1);
  518. WindMax:=((Y2-1) Shl 8)+(X2-1);
  519. GoToXY(1,1);
  520. End;
  521. Procedure ClrScr;
  522. {
  523. Clear the current window, and set the cursor on 1,1
  524. }
  525. Var
  526. CY,i : Longint;
  527. oldflush : boolean;
  528. blank_with_attribute : TCharAttr;
  529. Begin
  530. { See if color has changed }
  531. if OldTextAttr<>TextAttr then
  532. begin
  533. i:=TextAttr;
  534. TextAttr:=OldTextAttr;
  535. ttyColor(i);
  536. end;
  537. oldflush:=ttySetFlush(Flushing);
  538. if FullWin then
  539. begin
  540. if not OutputRedir then
  541. ttySendStr(#27'[H'#27'[2J');
  542. CurrX:=1;
  543. CurrY:=1;
  544. blank_with_attribute.ch := ' ';
  545. blank_with_attribute.attr := TextAttr;
  546. FillWord(ConsoleBuf^,ScreenWidth*ScreenHeight,word(blank_with_attribute));
  547. end
  548. else
  549. begin
  550. For Cy:=WinMinY To WinMaxY Do
  551. DoEmptyLine(Cy,WinMinX,WinMaxX);
  552. GoToXY(1,1);
  553. end;
  554. ttySetFlush(oldflush);
  555. End;
  556. Procedure ClrEol;
  557. {
  558. Clear from current position to end of line.
  559. }
  560. var
  561. len,i : longint;
  562. IsLastLine : boolean;
  563. Begin
  564. { See if color has changed }
  565. if OldTextAttr<>TextAttr then
  566. begin
  567. i:=TextAttr;
  568. TextAttr:=OldTextAttr;
  569. ttyColor(i);
  570. end;
  571. if FullWin or (WinMaxX = ScreenWidth) then
  572. begin
  573. if not OutputRedir then
  574. ttySendStr(#27'[K');
  575. end
  576. else
  577. begin
  578. { Tweak winmaxx and winmaxy so no scrolling happends }
  579. len:=WinMaxX-CurrX+1;
  580. IsLastLine:=false;
  581. if CurrY=WinMaxY then
  582. begin
  583. inc(WinMaxX,3);
  584. inc(WinMaxY,2);
  585. IsLastLine:=true;
  586. end;
  587. ttySendStr(Space(len));
  588. if IsLastLine then
  589. begin
  590. dec(WinMaxX,3);
  591. dec(WinMaxY,2);
  592. end;
  593. ttyGotoXY(0,0);
  594. end;
  595. End;
  596. Function WhereX: Byte;
  597. {
  598. Return current X-position of cursor.
  599. }
  600. Begin
  601. WhereX:=CurrX-WinMinX+1;
  602. End;
  603. Function WhereY: Byte;
  604. {
  605. Return current Y-position of cursor.
  606. }
  607. Begin
  608. WhereY:=CurrY-WinMinY+1;
  609. End;
  610. Procedure ScrollScrnRegionUp(xl,yl,xh,yh, count: longint);
  611. {
  612. Scroll the indicated region count lines up. The empty lines are filled
  613. with blanks in the current color. The screen position is restored
  614. afterwards.
  615. }
  616. Var
  617. y,oldx,oldy : byte;
  618. oldflush : boolean;
  619. Begin
  620. oldflush:=ttySetFlush(Flushing);
  621. oldx:=CurrX;
  622. oldy:=CurrY;
  623. {Scroll}
  624. For y:=yl to yh-count do
  625. DoScrollLine(y+count,y,xl,xh);
  626. {Restore TextAttr}
  627. ttySendStr(Attr2Ansi(TextAttr,$ff));
  628. {Fill the rest with empty lines}
  629. for y:=yh-count+1 to yh do
  630. DoEmptyLine(y,xl,xh);
  631. {Restore current position}
  632. ttyGotoXY(OldX,OldY);
  633. ttySetFlush(oldflush);
  634. End;
  635. Procedure ScrollScrnRegionDown(xl,yl,xh,yh, count: longint);
  636. {
  637. Scroll the indicated region count lines down. The empty lines are filled
  638. with blanks in the current color. The screen position is restored
  639. afterwards.
  640. }
  641. Var
  642. y,oldx,oldy : byte;
  643. oldflush : boolean;
  644. Begin
  645. oldflush:=ttySetFlush(Flushing);
  646. oldx:=CurrX;
  647. oldy:=CurrY;
  648. {Scroll}
  649. for y:=yh downto yl+count do
  650. DoScrollLine(y-count,y,xl,xh);
  651. {Restore TextAttr}
  652. ttySendStr(Attr2Ansi(TextAttr,$ff));
  653. {Fill the rest with empty lines}
  654. for y:=yl to yl+count-1 do
  655. DoEmptyLine(y,xl,xh);
  656. {Restore current position}
  657. ttyGotoXY(OldX,OldY);
  658. ttySetFlush(oldflush);
  659. End;
  660. {*************************************************************************
  661. KeyBoard
  662. *************************************************************************}
  663. Const
  664. KeyBufferSize = 20;
  665. var
  666. KeyBuffer : Array[0..KeyBufferSize-1] of Char;
  667. KeyPut,
  668. KeySend : longint;
  669. Procedure PushKey(Ch:char);
  670. Var
  671. Tmp : Longint;
  672. Begin
  673. Tmp:=KeyPut;
  674. Inc(KeyPut);
  675. If KeyPut>=KeyBufferSize Then
  676. KeyPut:=0;
  677. If KeyPut<>KeySend Then
  678. KeyBuffer[Tmp]:=Ch
  679. Else
  680. KeyPut:=Tmp;
  681. End;
  682. Function PopKey:char;
  683. Begin
  684. If KeyPut<>KeySend Then
  685. Begin
  686. PopKey:=KeyBuffer[KeySend];
  687. Inc(KeySend);
  688. If KeySend>=KeyBufferSize Then
  689. KeySend:=0;
  690. End
  691. Else
  692. PopKey:=#0;
  693. End;
  694. Procedure PushExt(b:byte);
  695. begin
  696. PushKey(#0);
  697. PushKey(chr(b));
  698. end;
  699. const
  700. AltKeyStr : string[38]='qwertyuiopasdfghjklzxcvbnm1234567890-=';
  701. AltCodeStr : string[38]=#016#017#018#019#020#021#022#023#024#025#030#031#032#033#034#035#036#037#038+
  702. #044#045#046#047#048#049#050#120#121#122#123#124#125#126#127#128#129#130#131;
  703. Function FAltKey(ch:char):byte;
  704. var
  705. Idx : longint;
  706. Begin
  707. Idx:=Pos(ch,AltKeyStr);
  708. if Idx>0 then
  709. FAltKey:=byte(AltCodeStr[Idx])
  710. else
  711. FAltKey:=0;
  712. End;
  713. { This one doesn't care about keypresses already processed by readkey }
  714. { and waiting in the KeyBuffer, only about waiting keypresses at the }
  715. { TTYLevel (including ones that are waiting in the TTYRecvChar buffer) }
  716. function sysKeyPressed: boolean;
  717. var
  718. fdsin : tfdSet;
  719. begin
  720. if (InCnt>0) then
  721. sysKeyPressed:=true
  722. else
  723. begin
  724. fpFD_ZERO(fdsin);
  725. fpFD_SET(TTYin,fdsin);
  726. sysKeypressed:=(fpSelect(TTYIn+1,@fdsin,nil,nil,0)>0);
  727. end;
  728. end;
  729. Function KeyPressed:Boolean;
  730. Begin
  731. Keypressed := (KeySend<>KeyPut) or sysKeyPressed;
  732. End;
  733. Function ReadKey:char;
  734. Var
  735. ch : char;
  736. OldState,
  737. State : longint;
  738. FDS : TFDSet;
  739. Begin
  740. {Check Buffer first}
  741. if KeySend<>KeyPut then
  742. begin
  743. ReadKey:=PopKey;
  744. exit;
  745. end;
  746. {Wait for Key}
  747. { Only if none are waiting! (JM) }
  748. if not sysKeyPressed then
  749. begin
  750. FpFD_ZERO (FDS);
  751. fpFD_SET (0,FDS);
  752. fpSelect (1,@FDS,nil,nil,nil);
  753. end;
  754. ch:=ttyRecvChar;
  755. {Esc Found ?}
  756. CASE ch OF
  757. #27: begin
  758. State:=1;
  759. Delay(10);
  760. { This has to be sysKeyPressed and not "keyPressed", since after }
  761. { one iteration keyPressed will always be true because of the }
  762. { pushKey commands (JM) }
  763. while (State<>0) and (sysKeyPressed) 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. {$IFDEF Unix}
  777. 'O': State:=7;
  778. {$ENDIF}
  779. else
  780. begin
  781. PushKey(ch);
  782. PushKey(#27);
  783. end;
  784. end;
  785. end;
  786. 2 : begin {Esc[}
  787. case ch of
  788. '[' : State:=3;
  789. 'A' : PushExt(72);
  790. 'B' : PushExt(80);
  791. 'C' : PushExt(77);
  792. 'D' : PushExt(75);
  793. {$IFDEF FREEBSD}
  794. {'E' - Center key, not handled in DOS TP7}
  795. 'F' : PushExt(79); {End}
  796. 'G': PushExt(81); {PageDown}
  797. {$ELSE}
  798. 'G' : PushKey('5'); {Center key, Linux}
  799. {$ENDIF}
  800. 'H' : PushExt(71);
  801. {$IFDEF FREEBSD}
  802. 'I' : PushExt(73); {PageUp}
  803. {$ENDIF}
  804. 'K' : PushExt(79);
  805. {$IFDEF FREEBSD}
  806. 'L' : PushExt(82); {Insert - Deekoo}
  807. 'M' : PushExt(59); {F1-F10 - Deekoo}
  808. 'N' : PushExt(60); {F2}
  809. 'O' : PushExt(61); {F3}
  810. 'P' : PushExt(62); {F4}
  811. 'Q' : PushExt(63); {F5}
  812. 'R' : PushExt(64); {F6}
  813. 'S' : PushExt(65); {F7}
  814. 'T' : PushExt(66); {F8}
  815. 'U' : PushExt(67); {F9}
  816. 'V' : PushExt(68); {F10}
  817. {Not sure if TP/BP handles F11 and F12 like this normally;
  818. In pcemu, a TP7 executable handles 'em this way, though.}
  819. 'W' : PushExt(133); {F11}
  820. 'X' : PushExt(134); {F12}
  821. 'Y' : PushExt(84); {Shift-F1}
  822. 'Z' : PushExt(85); {Shift-F2}
  823. 'a' : PushExt(86); {Shift-F3}
  824. 'b' : PushExt(87); {Shift-F4}
  825. 'c' : PushExt(88); {Shift-F5}
  826. 'd' : PushExt(89); {Shift-F6}
  827. 'e' : PushExt(90); {Shift-F7}
  828. 'f' : PushExt(91); {Shift-F8}
  829. 'g' : PushExt(92); {Shift-F9}
  830. 'h' : PushExt(93); {Shift-F10}
  831. 'i' : PushExt(135); {Shift-F11}
  832. 'j' : PushExt(136); {Shift-F12}
  833. 'k' : PushExt(94); {Ctrl-F1}
  834. 'l' : PushExt(95);
  835. 'm' : PushExt(96);
  836. 'n' : PushExt(97);
  837. 'o' : PushExt(98);
  838. 'p' : PushExt(99);
  839. 'q' : PushExt(100);
  840. 'r' : PushExt(101);
  841. 's' : PushExt(102);
  842. 't' : PushExt(103); {Ctrl-F10}
  843. 'u' : PushExt(137); {Ctrl-F11}
  844. 'v' : PushExt(138); {Ctrl-F12}
  845. {$ENDIF}
  846. '1' : State:=4;
  847. '2' : State:=5;
  848. '3' : State:=6;
  849. '4' : PushExt(79);
  850. '5' : PushExt(73);
  851. '6' : PushExt(81);
  852. else
  853. begin
  854. PushKey(ch);
  855. PushKey('[');
  856. PushKey(#27);
  857. end;
  858. end;
  859. if ch in ['4'..'6'] then
  860. State:=255;
  861. end;
  862. 3 : begin {Esc[[}
  863. case ch of
  864. 'A' : PushExt(59);
  865. 'B' : PushExt(60);
  866. 'C' : PushExt(61);
  867. 'D' : PushExt(62);
  868. 'E' : PushExt(63);
  869. end;
  870. end;
  871. 4 : begin {Esc[1}
  872. case ch of
  873. '~' : PushExt(71);
  874. '7' : PushExt(64);
  875. '8' : PushExt(65);
  876. '9' : PushExt(66);
  877. end;
  878. if (Ch<>'~') then
  879. State:=255;
  880. end;
  881. 5 : begin {Esc[2}
  882. case ch of
  883. '~' : PushExt(82);
  884. '0' : pushExt(67);
  885. '1' : PushExt(68);
  886. '3' : PushExt(133); {F11}
  887. {Esc[23~ is also shift-F1,shift-F11}
  888. '4' : PushExt(134); {F12}
  889. {Esc[24~ is also shift-F2,shift-F12}
  890. '5' : PushExt(86); {Shift-F3}
  891. '6' : PushExt(87); {Shift-F4}
  892. '8' : PushExt(88); {Shift-F5}
  893. '9' : PushExt(89); {Shift-F6}
  894. end;
  895. if (Ch<>'~') then
  896. State:=255;
  897. end;
  898. 6 : begin {Esc[3}
  899. case ch of
  900. '~' : PushExt(83); {Del}
  901. '1' : PushExt(90); {Shift-F7}
  902. '2' : PushExt(91); {Shift-F8}
  903. '3' : PushExt(92); {Shift-F9}
  904. '4' : PushExt(93); {Shift-F10}
  905. end;
  906. if (Ch<>'~') then
  907. State:=255;
  908. end;
  909. {$ifdef Unix}
  910. 7 : begin {Esc[O}
  911. case ch of
  912. 'A' : PushExt(72);
  913. 'B' : PushExt(80);
  914. 'C' : PushExt(77);
  915. 'D' : PushExt(75);
  916. end;
  917. end;
  918. {$endif}
  919. 255 : ;
  920. end;
  921. if State<>0 then
  922. Delay(10);
  923. end;
  924. if State=1 then
  925. PushKey(ch);
  926. end;
  927. #127: PushKey(#8);
  928. else PushKey(ch);
  929. End;
  930. ReadKey:=PopKey;
  931. End;
  932. Procedure Delay(MS: Word);
  933. {
  934. Wait for DTime milliseconds.
  935. }
  936. Begin
  937. fpSelect(0,nil,nil,nil,MS);
  938. End;
  939. {****************************************************************************
  940. Write(ln)/Read(ln) support
  941. ****************************************************************************}
  942. procedure DoLn;
  943. begin
  944. if CurrY=WinMaxY then
  945. begin
  946. if FullWin then
  947. begin
  948. ttySendStr(#10#13);
  949. CurrX:=WinMinX;
  950. CurrY:=WinMaxY;
  951. end
  952. else
  953. begin
  954. ScrollScrnRegionUp(WinMinX,WinMinY,WinMaxX,WinMaxY,1);
  955. ttyGotoXY(WinMinX,WinMaxY);
  956. end;
  957. end
  958. else
  959. ttyGotoXY(WinMinX,CurrY+1);
  960. end;
  961. var
  962. Lastansi : boolean;
  963. AnsiCode : string;
  964. Procedure DoWrite(const s:String);
  965. {
  966. Write string to screen, parse most common AnsiCodes
  967. }
  968. var
  969. found,
  970. OldFlush : boolean;
  971. x,y,
  972. i,j,
  973. SendBytes : longint;
  974. function AnsiPara(var hstr:string):byte;
  975. var
  976. k,j : longint;
  977. code : word;
  978. begin
  979. j:=pos(';',hstr);
  980. if j=0 then
  981. j:=length(hstr);
  982. val(copy(hstr,3,j-3),k,code);
  983. Delete(hstr,3,j-2);
  984. if k=0 then
  985. k:=1;
  986. AnsiPara:=k;
  987. end;
  988. procedure SendText;
  989. var
  990. LeftX : longint;
  991. begin
  992. while (SendBytes>0) do
  993. begin
  994. LeftX:=WinMaxX-CurrX+1;
  995. if (SendBytes>LeftX) then
  996. begin
  997. ttyWrite(Copy(s,i-SendBytes,LeftX));
  998. dec(SendBytes,LeftX);
  999. DoLn;
  1000. end
  1001. else
  1002. begin
  1003. ttyWrite(Copy(s,i-SendBytes,SendBytes));
  1004. SendBytes:=0;
  1005. end;
  1006. end;
  1007. end;
  1008. begin
  1009. oldflush:=ttySetFlush(Flushing);
  1010. { Support textattr:= changing }
  1011. if OldTextAttr<>TextAttr then
  1012. begin
  1013. i:=TextAttr;
  1014. TextAttr:=OldTextAttr;
  1015. ttyColor(i);
  1016. end;
  1017. { write the stuff }
  1018. SendBytes:=0;
  1019. i:=1;
  1020. while (i<=length(s)) do
  1021. begin
  1022. if (s[i]=#27) or (LastAnsi) then
  1023. begin
  1024. SendText;
  1025. LastAnsi:=false;
  1026. j:=i;
  1027. found:=false;
  1028. while (j<=length(s)) and (not found) do
  1029. begin
  1030. found:=not (s[j] in [#27,'[','0'..'9',';','?']);
  1031. inc(j);
  1032. end;
  1033. Ansicode:=AnsiCode+Copy(s,i,j-i);
  1034. if found then
  1035. begin
  1036. case AnsiCode[length(AnsiCode)] of
  1037. 'm' : ttyColor(Ansi2Attr(AnsiCode,TextAttr));
  1038. 'H' : begin {No other way :( Coz First Para=Y}
  1039. y:=AnsiPara(AnsiCode);
  1040. x:=AnsiPara(AnsiCode);
  1041. GotoXY(x,y);
  1042. end;
  1043. 'J' : if AnsiPara(AnsiCode)=2 then
  1044. ClrScr;
  1045. 'K' : ClrEol;
  1046. 'A' : GotoXY(CurrX,Max(CurrY-AnsiPara(AnsiCode),WinMinY));
  1047. 'B' : GotoXY(CurrX,Min(CurrY+AnsiPara(AnsiCode),WinMaxY));
  1048. 'C' : GotoXY(Min(CurrX+AnsiPara(AnsiCode),WinMaxX),CurrY);
  1049. 'D' : GotoXY(Max(CurrX-AnsiPara(AnsiCode),WinMinX),CurrY);
  1050. 'h' : ; {Stupid Thedraw [?7h Code}
  1051. else
  1052. found:=false;
  1053. end;
  1054. end
  1055. else
  1056. begin
  1057. LastAnsi:=true;
  1058. found:=true;
  1059. end;
  1060. {Clear AnsiCode?}
  1061. if not LastAnsi then
  1062. AnsiCode:='';
  1063. {Increase Idx or SendBytes}
  1064. if found then
  1065. i:=j-1
  1066. else
  1067. inc(SendBytes);
  1068. end
  1069. else
  1070. begin
  1071. LastAnsi:=false;
  1072. case s[i] of
  1073. #13 : begin {CR}
  1074. SendText;
  1075. ttyGotoXY(WinMinX,CurrY);
  1076. end;
  1077. #10 : begin {NL}
  1078. SendText;
  1079. DoLn;
  1080. end;
  1081. #9 : begin {Tab}
  1082. SendText;
  1083. ttyWrite(Space(9-((CurrX-1) and $08)));
  1084. end;
  1085. #8 : begin {BackSpace}
  1086. SendText;
  1087. ttyWrite(#8);
  1088. end;
  1089. else
  1090. inc(SendBytes);
  1091. end;
  1092. end;
  1093. inc(i);
  1094. end;
  1095. if SendBytes>0 then
  1096. SendText;
  1097. ttySetFlush(oldFLush);
  1098. end;
  1099. Function CrtWrite(Var F: TextRec): Integer;
  1100. {
  1101. Top level write function for CRT
  1102. }
  1103. Var
  1104. Temp : String;
  1105. idx,i : Longint;
  1106. oldflush : boolean;
  1107. Begin
  1108. oldflush:=ttySetFlush(Flushing);
  1109. idx:=0;
  1110. while (F.BufPos>0) do
  1111. begin
  1112. i:=F.BufPos;
  1113. if i>255 then
  1114. i:=255;
  1115. Move(F.BufPTR^[idx],Temp[1],i);
  1116. SetLength(Temp,i);
  1117. DoWrite(Temp);
  1118. dec(F.BufPos,i);
  1119. inc(idx,i);
  1120. end;
  1121. ttySetFlush(oldFLush);
  1122. CrtWrite:=0;
  1123. End;
  1124. Function CrtRead(Var F: TextRec): Integer;
  1125. {
  1126. Read from CRT associated file.
  1127. }
  1128. var
  1129. c : char;
  1130. i : longint;
  1131. Begin
  1132. if isATTY(F.Handle)<>-1 then
  1133. begin
  1134. F.BufPos := 0;
  1135. i := 0;
  1136. repeat
  1137. c := readkey;
  1138. case c of
  1139. { ignore special keys }
  1140. #0:
  1141. c:= readkey;
  1142. { Backspace }
  1143. #8:
  1144. if i > 0 then
  1145. begin
  1146. if not(OutputRedir or InputRedir) then
  1147. write(#8#32#8);
  1148. dec(i);
  1149. end;
  1150. { Unhandled extended key }
  1151. #27:;
  1152. { CR }
  1153. #13:
  1154. begin
  1155. F.BufPtr^[i] := #10;
  1156. if not(OutputRedir or InputRedir) then
  1157. write(#10);
  1158. inc(i);
  1159. end;
  1160. else
  1161. begin
  1162. if not(OutputRedir or InputRedir) then
  1163. write(c);
  1164. F.BufPtr^[i] := c;
  1165. inc(i);
  1166. end;
  1167. end;
  1168. until (c in [#10,#13]) or (i >= F.BufSize);
  1169. F.BufEnd := i;
  1170. CrtRead := 0;
  1171. exit;
  1172. end;
  1173. F.BufEnd:=fpRead(F.Handle, F.BufPtr^, F.BufSize);
  1174. { fix #13 only's -> #10 to overcome terminal setting }
  1175. for i:=1to F.BufEnd do
  1176. begin
  1177. if (F.BufPtr^[i-1]=#13) and (F.BufPtr^[i]<>#10) then
  1178. F.BufPtr^[i-1]:=#10;
  1179. end;
  1180. F.BufPos:=F.BufEnd;
  1181. if not(OutputRedir or InputRedir) then
  1182. CrtWrite(F)
  1183. else F.BufPos := 0;
  1184. CrtRead:=0;
  1185. End;
  1186. Function CrtReturn(Var F:TextRec):Integer;
  1187. Begin
  1188. CrtReturn:=0;
  1189. end;
  1190. Function CrtClose(Var F: TextRec): Integer;
  1191. {
  1192. Close CRT associated file.
  1193. }
  1194. Begin
  1195. F.Mode:=fmClosed;
  1196. CrtClose:=0;
  1197. End;
  1198. Function CrtOpen(Var F: TextRec): Integer;
  1199. {
  1200. Open CRT associated file.
  1201. }
  1202. Begin
  1203. If F.Mode=fmOutput Then
  1204. begin
  1205. TextRec(F).InOutFunc:=@CrtWrite;
  1206. TextRec(F).FlushFunc:=@CrtWrite;
  1207. end
  1208. Else
  1209. begin
  1210. F.Mode:=fmInput;
  1211. TextRec(F).InOutFunc:=@CrtRead;
  1212. TextRec(F).FlushFunc:=@CrtReturn;
  1213. end;
  1214. TextRec(F).CloseFunc:=@CrtClose;
  1215. CrtOpen:=0;
  1216. End;
  1217. procedure AssignCrt(var F: Text);
  1218. {
  1219. Assign a file to the console. All output on file goes to console instead.
  1220. }
  1221. begin
  1222. Assign(F,'');
  1223. TextRec(F).OpenFunc:=@CrtOpen;
  1224. end;
  1225. {******************************************************************************
  1226. High Level Functions
  1227. ******************************************************************************}
  1228. Procedure DelLine;
  1229. {
  1230. Delete current line. Scroll subsequent lines up
  1231. }
  1232. Begin
  1233. ScrollScrnRegionUp(WinMinX, CurrY, WinMaxX, WinMaxY, 1);
  1234. End;
  1235. Procedure InsLine;
  1236. {
  1237. Insert line at current cursor position. Scroll subsequent lines down.
  1238. }
  1239. Begin
  1240. ScrollScrnRegionDown(WinMinX, CurrY, WinMaxX, WinMaxY, 1);
  1241. End;
  1242. const
  1243. KIOCSOUND = $4B2F; // start sound generation (0 for off)
  1244. Procedure Sound(Hz: Word);
  1245. begin
  1246. if not OutputRedir then
  1247. fpIoctl(TextRec(Output).Handle, KIOCSOUND, Pointer(1193180 div Hz));
  1248. end;
  1249. Procedure NoSound;
  1250. begin
  1251. if not OutputRedir then
  1252. fpIoctl(TextRec(Output).Handle, KIOCSOUND, nil);
  1253. end;
  1254. Procedure TextMode (Mode: word);
  1255. {
  1256. Only Clears Screen under linux}
  1257. begin
  1258. ClrScr;
  1259. end;
  1260. {******************************************************************************
  1261. Extra
  1262. ******************************************************************************}
  1263. procedure CursorBig;
  1264. begin
  1265. ttySendStr(#27'[?17;0;64c');
  1266. end;
  1267. procedure CursorOn;
  1268. begin
  1269. ttySendStr(#27'[?2c');
  1270. end;
  1271. procedure CursorOff;
  1272. begin
  1273. ttySendStr(#27'[?1c');
  1274. end;
  1275. {******************************************************************************
  1276. Initialization
  1277. ******************************************************************************}
  1278. var
  1279. OldIO : termio.TermIos;
  1280. inputRaw, outputRaw: boolean;
  1281. procedure saveRawSettings(const tio: termio.termios);
  1282. Begin
  1283. with tio do
  1284. begin
  1285. inputRaw :=
  1286. ((c_iflag and (IGNBRK or BRKINT or PARMRK or ISTRIP or
  1287. INLCR or IGNCR or ICRNL or IXON)) = 0) and
  1288. ((c_lflag and (ECHO or ECHONL or ICANON or ISIG or IEXTEN)) = 0);
  1289. outPutRaw :=
  1290. ((c_oflag and OPOST) = 0) and
  1291. ((c_cflag and (CSIZE or PARENB)) = 0) and
  1292. ((c_cflag and CS8) <> 0);
  1293. end;
  1294. end;
  1295. procedure restoreRawSettings(tio: termio.termios);
  1296. begin
  1297. with tio do
  1298. begin
  1299. if inputRaw then
  1300. begin
  1301. c_iflag := c_iflag and (not (IGNBRK or BRKINT or PARMRK or ISTRIP or
  1302. INLCR or IGNCR or ICRNL or IXON));
  1303. c_lflag := c_lflag and
  1304. (not (ECHO or ECHONL or ICANON or ISIG or IEXTEN));
  1305. end;
  1306. if outPutRaw then
  1307. begin
  1308. c_oflag := c_oflag and not(OPOST);
  1309. c_cflag := c_cflag and not(CSIZE or PARENB) or CS8;
  1310. end;
  1311. end;
  1312. end;
  1313. Procedure SetRawMode(b:boolean);
  1314. Var
  1315. Tio : Termios;
  1316. Begin
  1317. if b then
  1318. begin
  1319. TCGetAttr(1,Tio);
  1320. SaveRawSettings(Tio);
  1321. OldIO:=Tio;
  1322. CFMakeRaw(Tio);
  1323. end
  1324. else
  1325. begin
  1326. RestoreRawSettings(OldIO);
  1327. Tio:=OldIO;
  1328. end;
  1329. TCSetAttr(1,TCSANOW,Tio);
  1330. End;
  1331. procedure GetXY(var x,y:byte);
  1332. var
  1333. fds : tfdSet;
  1334. i,j,
  1335. readed : longint;
  1336. buf : array[0..255] of char;
  1337. s : string[16];
  1338. begin
  1339. x:=0;
  1340. y:=0;
  1341. s:=#27'[6n';
  1342. fpWrite(0,s[1],length(s));
  1343. fpFD_ZERO(fds);
  1344. fpFD_SET(1,fds);
  1345. if (fpSelect(2,@fds,nil,nil,1000)>0) then
  1346. begin
  1347. readed:=fpRead(1,buf,sizeof(buf));
  1348. i:=0;
  1349. while (i+5<readed) and (buf[i]<>#27) and (buf[i+1]<>'[') do
  1350. inc(i);
  1351. if i+5<readed then
  1352. begin
  1353. s:=space(16);
  1354. move(buf[i+2],s[1],16);
  1355. i:=Pos(';',s);
  1356. if i>0 then
  1357. begin
  1358. Val(Copy(s,1,i-1),y);
  1359. j:=Pos('R',s);
  1360. if j=0 then
  1361. j:=length(s);
  1362. Val(Copy(s,i+1,j-(i+1)),x);
  1363. end;
  1364. end;
  1365. end;
  1366. end;
  1367. Procedure GetConsoleBuf;
  1368. var
  1369. WinInfo : TWinSize;
  1370. begin
  1371. if Assigned(ConsoleBuf) then
  1372. FreeMem(ConsoleBuf,ScreenHeight*ScreenWidth*2);
  1373. ScreenWidth:=0;
  1374. ScreenHeight:=0;
  1375. if (not OutputRedir) and (fpIOCtl(TextRec(Output).Handle,TIOCGWINSZ,@Wininfo)>=0) then
  1376. begin
  1377. ScreenWidth:=Wininfo.ws_col;
  1378. ScreenHeight:=Wininfo.ws_row;
  1379. end;
  1380. // Set some arbitrary defaults which make some sense...
  1381. If (ScreenWidth=0) then
  1382. ScreenWidth:=80;
  1383. If (ScreenHeight=0) then
  1384. ScreenHeight:=25;
  1385. GetMem(ConsoleBuf,ScreenHeight*ScreenWidth*2);
  1386. FillChar(ConsoleBuf^,ScreenHeight*ScreenWidth*2,0);
  1387. end;
  1388. Initialization
  1389. { Redirect the standard output }
  1390. assigncrt(Output);
  1391. Rewrite(Output);
  1392. TextRec(Output).Handle:=StdOutputHandle;
  1393. assigncrt(Input);
  1394. Reset(Input);
  1395. TextRec(Input).Handle:=StdInputHandle;
  1396. { Are we redirected to a file ? }
  1397. OutputRedir:= IsAtty(TextRec(Output).Handle)=-1;
  1398. { does the input come from another console or from a file? }
  1399. InputRedir :=
  1400. (IsAtty(TextRec(Input).Handle)=-1) or
  1401. (not OutputRedir and
  1402. (TTYName(TextRec(Input).Handle) <> TTYName(TextRec(Output).Handle)));
  1403. { Get Size of terminal and set WindMax to the window }
  1404. GetConsoleBuf;
  1405. WinMinX:=1;
  1406. WinMinY:=1;
  1407. WinMaxX:=ScreenWidth;
  1408. WinMaxY:=ScreenHeight;
  1409. WindMax:=((ScreenHeight-1) Shl 8)+(ScreenWidth-1);
  1410. {Get Current X&Y or Reset to Home}
  1411. if OutputRedir then
  1412. begin
  1413. CurrX:=1;
  1414. CurrY:=1;
  1415. end
  1416. else
  1417. begin
  1418. { Set default Terminal Settings }
  1419. SetRawMode(True);
  1420. { Get current X,Y if not set already }
  1421. GetXY(CurrX,CurrY);
  1422. if (CurrX=0) then
  1423. begin
  1424. CurrX:=1;
  1425. CurrY:=1;
  1426. ttySendStr(#27'[H');
  1427. end;
  1428. {Reset Attribute (TextAttr=7 at startup)}
  1429. ttySendStr(#27'[m');
  1430. end;
  1431. Finalization
  1432. ttyFlushOutput;
  1433. if not OutputRedir then
  1434. SetRawMode(False);
  1435. { remove console buf }
  1436. if Assigned(ConsoleBuf) then
  1437. FreeMem(ConsoleBuf,ScreenHeight*ScreenWidth*2);
  1438. End.