crt.pp 35 KB

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