crt.pp 35 KB

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