crt.pp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629
  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. '7' : PushExt(64);
  871. '8' : PushExt(65);
  872. '9' : PushExt(66);
  873. end;
  874. if (Ch<>'~') then
  875. State:=255;
  876. end;
  877. 5 : begin {Esc[2}
  878. case ch of
  879. '~' : PushExt(82);
  880. '0' : pushExt(67);
  881. '1' : PushExt(68);
  882. '3' : PushExt(133); {F11}
  883. {Esc[23~ is also shift-F1,shift-F11}
  884. '4' : PushExt(134); {F12}
  885. {Esc[24~ is also shift-F2,shift-F12}
  886. '5' : PushExt(86); {Shift-F3}
  887. '6' : PushExt(87); {Shift-F4}
  888. '8' : PushExt(88); {Shift-F5}
  889. '9' : PushExt(89); {Shift-F6}
  890. end;
  891. if (Ch<>'~') then
  892. State:=255;
  893. end;
  894. 6 : begin {Esc[3}
  895. case ch of
  896. '~' : PushExt(83); {Del}
  897. '1' : PushExt(90); {Shift-F7}
  898. '2' : PushExt(91); {Shift-F8}
  899. '3' : PushExt(92); {Shift-F9}
  900. '4' : PushExt(93); {Shift-F10}
  901. end;
  902. if (Ch<>'~') then
  903. State:=255;
  904. end;
  905. {$ifdef Unix}
  906. 7 : begin {Esc[O}
  907. case ch of
  908. 'A' : PushExt(72);
  909. 'B' : PushExt(80);
  910. 'C' : PushExt(77);
  911. 'D' : PushExt(75);
  912. end;
  913. end;
  914. {$endif}
  915. 255 : ;
  916. end;
  917. if State<>0 then
  918. Delay(10);
  919. end;
  920. if State=1 then
  921. PushKey(ch);
  922. end;
  923. #127: PushKey(#8);
  924. else PushKey(ch);
  925. End;
  926. ReadKey:=PopKey;
  927. End;
  928. Procedure Delay(MS: Word);
  929. {
  930. Wait for DTime milliseconds.
  931. }
  932. Begin
  933. fpSelect(0,nil,nil,nil,MS);
  934. End;
  935. {****************************************************************************
  936. Write(ln)/Read(ln) support
  937. ****************************************************************************}
  938. procedure DoLn;
  939. begin
  940. if CurrY=WindMaxY then
  941. begin
  942. if FullWin then
  943. begin
  944. ttySendStr(#10#13);
  945. CurrX:=WindMinX;
  946. CurrY:=WindMaxY;
  947. end
  948. else
  949. begin
  950. ScrollScrnRegionUp(WindMinX,WindMinY,WindMaxX,WindMaxY,1);
  951. ttyGotoXY(WindMinX,WindMaxY);
  952. end;
  953. end
  954. else
  955. ttyGotoXY(WindMinX,CurrY+1);
  956. end;
  957. var
  958. Lastansi : boolean;
  959. AnsiCode : string;
  960. Procedure DoWrite(const s:String);
  961. {
  962. Write string to screen, parse most common AnsiCodes
  963. }
  964. var
  965. found,
  966. OldFlush : boolean;
  967. x,y,
  968. i,j,
  969. SendBytes : longint;
  970. function AnsiPara(var hstr:string):byte;
  971. var
  972. k,j : longint;
  973. code : word;
  974. begin
  975. j:=pos(';',hstr);
  976. if j=0 then
  977. j:=length(hstr);
  978. val(copy(hstr,3,j-3),k,code);
  979. Delete(hstr,3,j-2);
  980. if k=0 then
  981. k:=1;
  982. AnsiPara:=k;
  983. end;
  984. procedure SendText;
  985. var
  986. LeftX : longint;
  987. begin
  988. while (SendBytes>0) do
  989. begin
  990. LeftX:=WindMaxX-CurrX+1;
  991. if (SendBytes>LeftX) then
  992. begin
  993. ttyWrite(Copy(s,i-SendBytes,LeftX));
  994. dec(SendBytes,LeftX);
  995. DoLn;
  996. end
  997. else
  998. begin
  999. ttyWrite(Copy(s,i-SendBytes,SendBytes));
  1000. SendBytes:=0;
  1001. end;
  1002. end;
  1003. end;
  1004. begin
  1005. oldflush:=ttySetFlush(Flushing);
  1006. { Support textattr:= changing }
  1007. if OldTextAttr<>TextAttr then
  1008. begin
  1009. i:=TextAttr;
  1010. TextAttr:=OldTextAttr;
  1011. ttyColor(i);
  1012. end;
  1013. { write the stuff }
  1014. SendBytes:=0;
  1015. i:=1;
  1016. while (i<=length(s)) do
  1017. begin
  1018. if (s[i]=#27) or (LastAnsi) then
  1019. begin
  1020. SendText;
  1021. LastAnsi:=false;
  1022. j:=i;
  1023. found:=false;
  1024. while (j<=length(s)) and (not found) do
  1025. begin
  1026. found:=not (s[j] in [#27,'[','0'..'9',';','?']);
  1027. inc(j);
  1028. end;
  1029. Ansicode:=AnsiCode+Copy(s,i,j-i);
  1030. if found then
  1031. begin
  1032. case AnsiCode[length(AnsiCode)] of
  1033. 'm' : ttyColor(Ansi2Attr(AnsiCode,TextAttr));
  1034. 'H' : begin {No other way :( Coz First Para=Y}
  1035. y:=AnsiPara(AnsiCode);
  1036. x:=AnsiPara(AnsiCode);
  1037. GotoXY(x,y);
  1038. end;
  1039. 'J' : if AnsiPara(AnsiCode)=2 then
  1040. ClrScr;
  1041. 'K' : ClrEol;
  1042. 'A' : GotoXY(CurrX,Max(CurrY-AnsiPara(AnsiCode),WindMinY));
  1043. 'B' : GotoXY(CurrX,Min(CurrY+AnsiPara(AnsiCode),WindMaxY));
  1044. 'C' : GotoXY(Min(CurrX+AnsiPara(AnsiCode),WindMaxX),CurrY);
  1045. 'D' : GotoXY(Max(CurrX-AnsiPara(AnsiCode),WindMinX),CurrY);
  1046. 'h' : ; {Stupid Thedraw [?7h Code}
  1047. else
  1048. found:=false;
  1049. end;
  1050. end
  1051. else
  1052. begin
  1053. LastAnsi:=true;
  1054. found:=true;
  1055. end;
  1056. {Clear AnsiCode?}
  1057. if not LastAnsi then
  1058. AnsiCode:='';
  1059. {Increase Idx or SendBytes}
  1060. if found then
  1061. i:=j-1
  1062. else
  1063. inc(SendBytes);
  1064. end
  1065. else
  1066. begin
  1067. LastAnsi:=false;
  1068. case s[i] of
  1069. #13 : begin {CR}
  1070. SendText;
  1071. ttyGotoXY(WindMinX,CurrY);
  1072. end;
  1073. #10 : begin {NL}
  1074. SendText;
  1075. DoLn;
  1076. end;
  1077. #9 : begin {Tab}
  1078. SendText;
  1079. ttyWrite(Space(9-((CurrX-1) and $08)));
  1080. end;
  1081. #8 : begin {BackSpace}
  1082. SendText;
  1083. ttyWrite(#8);
  1084. end;
  1085. else
  1086. inc(SendBytes);
  1087. end;
  1088. end;
  1089. inc(i);
  1090. end;
  1091. if SendBytes>0 then
  1092. SendText;
  1093. ttySetFlush(oldFLush);
  1094. end;
  1095. Function CrtWrite(Var F: TextRec): Integer;
  1096. {
  1097. Top level write function for CRT
  1098. }
  1099. Var
  1100. Temp : String;
  1101. idx,i : Longint;
  1102. oldflush : boolean;
  1103. Begin
  1104. oldflush:=ttySetFlush(Flushing);
  1105. idx:=0;
  1106. while (F.BufPos>0) do
  1107. begin
  1108. i:=F.BufPos;
  1109. if i>255 then
  1110. i:=255;
  1111. Move(F.BufPTR^[idx],Temp[1],i);
  1112. SetLength(Temp,i);
  1113. DoWrite(Temp);
  1114. dec(F.BufPos,i);
  1115. inc(idx,i);
  1116. end;
  1117. ttySetFlush(oldFLush);
  1118. CrtWrite:=0;
  1119. End;
  1120. Function CrtRead(Var F: TextRec): Integer;
  1121. {
  1122. Read from CRT associated file.
  1123. }
  1124. var
  1125. c : char;
  1126. i : longint;
  1127. Begin
  1128. if isATTY(F.Handle)=1 then
  1129. begin
  1130. F.BufPos := 0;
  1131. i := 0;
  1132. repeat
  1133. c := readkey;
  1134. case c of
  1135. { ignore special keys }
  1136. #0:
  1137. c:= readkey;
  1138. { Backspace }
  1139. #8:
  1140. if i > 0 then
  1141. begin
  1142. if not(OutputRedir or InputRedir) then
  1143. write(#8#32#8);
  1144. dec(i);
  1145. end;
  1146. { Unhandled extended key }
  1147. #27:;
  1148. { CR }
  1149. #13:
  1150. begin
  1151. F.BufPtr^[i] := #10;
  1152. if not(OutputRedir or InputRedir) then
  1153. write(#10);
  1154. inc(i);
  1155. end;
  1156. else
  1157. begin
  1158. if not(OutputRedir or InputRedir) then
  1159. write(c);
  1160. F.BufPtr^[i] := c;
  1161. inc(i);
  1162. end;
  1163. end;
  1164. until (c in [#10,#13]) or (i >= F.BufSize);
  1165. F.BufEnd := i;
  1166. CrtRead := 0;
  1167. exit;
  1168. end;
  1169. F.BufEnd:=fpRead(F.Handle, F.BufPtr^, F.BufSize);
  1170. { fix #13 only's -> #10 to overcome terminal setting }
  1171. for i:=1to F.BufEnd do
  1172. begin
  1173. if (F.BufPtr^[i-1]=#13) and (F.BufPtr^[i]<>#10) then
  1174. F.BufPtr^[i-1]:=#10;
  1175. end;
  1176. F.BufPos:=F.BufEnd;
  1177. if not(OutputRedir or InputRedir) then
  1178. CrtWrite(F)
  1179. else F.BufPos := 0;
  1180. CrtRead:=0;
  1181. End;
  1182. Function CrtReturn(Var F:TextRec):Integer;
  1183. Begin
  1184. CrtReturn:=0;
  1185. end;
  1186. Function CrtClose(Var F: TextRec): Integer;
  1187. {
  1188. Close CRT associated file.
  1189. }
  1190. Begin
  1191. F.Mode:=fmClosed;
  1192. CrtClose:=0;
  1193. End;
  1194. Function CrtOpen(Var F: TextRec): Integer;
  1195. {
  1196. Open CRT associated file.
  1197. }
  1198. Begin
  1199. If F.Mode=fmOutput Then
  1200. begin
  1201. TextRec(F).InOutFunc:=@CrtWrite;
  1202. TextRec(F).FlushFunc:=@CrtWrite;
  1203. end
  1204. Else
  1205. begin
  1206. F.Mode:=fmInput;
  1207. TextRec(F).InOutFunc:=@CrtRead;
  1208. TextRec(F).FlushFunc:=@CrtReturn;
  1209. end;
  1210. TextRec(F).CloseFunc:=@CrtClose;
  1211. CrtOpen:=0;
  1212. End;
  1213. procedure AssignCrt(var F: Text);
  1214. {
  1215. Assign a file to the console. All output on file goes to console instead.
  1216. }
  1217. begin
  1218. Assign(F,'');
  1219. TextRec(F).OpenFunc:=@CrtOpen;
  1220. end;
  1221. {******************************************************************************
  1222. High Level Functions
  1223. ******************************************************************************}
  1224. Procedure DelLine;
  1225. {
  1226. Delete current line. Scroll subsequent lines up
  1227. }
  1228. Begin
  1229. ScrollScrnRegionUp(WindMinX, CurrY, WindMaxX, WindMaxY, 1);
  1230. End;
  1231. Procedure InsLine;
  1232. {
  1233. Insert line at current cursor position. Scroll subsequent lines down.
  1234. }
  1235. Begin
  1236. ScrollScrnRegionDown(WindMinX, CurrY, WindMaxX, WindMaxY, 1);
  1237. End;
  1238. {$ifdef linux}
  1239. {$define havekiocsound}
  1240. const KIOCSOUND = $4B2F; // start sound generation (0 for off)
  1241. {$else}
  1242. {$ifdef FreeBSD}
  1243. const KIOCSOUND =$20004b3f;
  1244. {$define havekiocsound}
  1245. {$endif}
  1246. {$endif}
  1247. // ioctl might fail e.g. in putty. A redirect check is not enough,
  1248. // needs check for physical console too.
  1249. Procedure Sound(Hz: Word);
  1250. begin
  1251. {$ifdef havekiocsound}
  1252. if (not OutputRedir) and (hz>0) then
  1253. fpIoctl(TextRec(Output).Handle, KIOCSOUND, Pointer(1193180 div Hz));
  1254. {$endif}
  1255. end;
  1256. Procedure NoSound;
  1257. begin
  1258. {$ifdef havekiocsound}
  1259. if not OutputRedir then
  1260. fpIoctl(TextRec(Output).Handle, KIOCSOUND, nil);
  1261. {$endif}
  1262. end;
  1263. Procedure TextMode (Mode: word);
  1264. {
  1265. Only Clears Screen under linux}
  1266. begin
  1267. ClrScr;
  1268. end;
  1269. {******************************************************************************
  1270. Extra
  1271. ******************************************************************************}
  1272. procedure CursorBig;
  1273. begin
  1274. ttySendStr(#27'[?17;0;64c');
  1275. end;
  1276. procedure CursorOn;
  1277. begin
  1278. ttySendStr(#27'[?2c');
  1279. end;
  1280. procedure CursorOff;
  1281. begin
  1282. ttySendStr(#27'[?1c');
  1283. end;
  1284. {******************************************************************************
  1285. Initialization
  1286. ******************************************************************************}
  1287. var
  1288. OldIO : termio.TermIos;
  1289. inputRaw, outputRaw: boolean;
  1290. procedure saveRawSettings(const tio: termio.termios);
  1291. Begin
  1292. with tio do
  1293. begin
  1294. inputRaw :=
  1295. ((c_iflag and (IGNBRK or BRKINT or PARMRK or ISTRIP or
  1296. INLCR or IGNCR or ICRNL or IXON)) = 0) and
  1297. ((c_lflag and (ECHO or ECHONL or ICANON or ISIG or IEXTEN)) = 0);
  1298. outPutRaw :=
  1299. ((c_oflag and OPOST) = 0) and
  1300. ((c_cflag and (CSIZE or PARENB)) = 0) and
  1301. ((c_cflag and CS8) <> 0);
  1302. end;
  1303. end;
  1304. procedure restoreRawSettings(tio: termio.termios);
  1305. begin
  1306. with tio do
  1307. begin
  1308. if inputRaw then
  1309. begin
  1310. c_iflag := c_iflag and (not (IGNBRK or BRKINT or PARMRK or ISTRIP or
  1311. INLCR or IGNCR or ICRNL or IXON));
  1312. c_lflag := c_lflag and
  1313. (not (ECHO or ECHONL or ICANON or ISIG or IEXTEN));
  1314. end;
  1315. if outPutRaw then
  1316. begin
  1317. c_oflag := c_oflag and not(OPOST);
  1318. c_cflag := c_cflag and not(CSIZE or PARENB) or CS8;
  1319. end;
  1320. end;
  1321. end;
  1322. Procedure SetRawMode(b:boolean);
  1323. Var
  1324. Tio : Termios;
  1325. Begin
  1326. if b then
  1327. begin
  1328. TCGetAttr(1,Tio);
  1329. SaveRawSettings(Tio);
  1330. OldIO:=Tio;
  1331. CFMakeRaw(Tio);
  1332. end
  1333. else
  1334. begin
  1335. RestoreRawSettings(OldIO);
  1336. Tio:=OldIO;
  1337. end;
  1338. TCSetAttr(1,TCSANOW,Tio);
  1339. End;
  1340. procedure GetXY(var x,y:byte);
  1341. var
  1342. fds : tfdSet;
  1343. i,j,
  1344. readed : longint;
  1345. buf : array[0..255] of char;
  1346. s : string[16];
  1347. begin
  1348. x:=0;
  1349. y:=0;
  1350. s:=#27'[6n';
  1351. fpWrite(0,s[1],length(s));
  1352. fpFD_ZERO(fds);
  1353. fpFD_SET(1,fds);
  1354. if (fpSelect(2,@fds,nil,nil,1000)>0) then
  1355. begin
  1356. readed:=fpRead(1,buf,sizeof(buf));
  1357. i:=0;
  1358. while (i+5<readed) and (buf[i]<>#27) and (buf[i+1]<>'[') do
  1359. inc(i);
  1360. if i+5<readed then
  1361. begin
  1362. s:=space(16);
  1363. move(buf[i+2],s[1],16);
  1364. i:=Pos(';',s);
  1365. if i>0 then
  1366. begin
  1367. Val(Copy(s,1,i-1),y);
  1368. j:=Pos('R',s);
  1369. if j=0 then
  1370. j:=length(s);
  1371. Val(Copy(s,i+1,j-(i+1)),x);
  1372. end;
  1373. end;
  1374. end;
  1375. end;
  1376. Procedure GetConsoleBuf;
  1377. var
  1378. WinInfo : TWinSize;
  1379. begin
  1380. if Assigned(ConsoleBuf) then
  1381. FreeMem(ConsoleBuf,ScreenHeight*ScreenWidth*2);
  1382. ScreenWidth:=0;
  1383. ScreenHeight:=0;
  1384. if (not OutputRedir) and (fpIOCtl(TextRec(Output).Handle,TIOCGWINSZ,@Wininfo)>=0) then
  1385. begin
  1386. ScreenWidth:=Wininfo.ws_col;
  1387. ScreenHeight:=Wininfo.ws_row;
  1388. end;
  1389. // Set some arbitrary defaults which make some sense...
  1390. If (ScreenWidth=0) then
  1391. ScreenWidth:=80;
  1392. If (ScreenHeight=0) then
  1393. ScreenHeight:=25;
  1394. GetMem(ConsoleBuf,ScreenHeight*ScreenWidth*2);
  1395. FillChar(ConsoleBuf^,ScreenHeight*ScreenWidth*2,0);
  1396. end;
  1397. Initialization
  1398. { Redirect the standard output }
  1399. assigncrt(Output);
  1400. Rewrite(Output);
  1401. TextRec(Output).Handle:=StdOutputHandle;
  1402. assigncrt(Input);
  1403. Reset(Input);
  1404. TextRec(Input).Handle:=StdInputHandle;
  1405. { Are we redirected to a file ? }
  1406. OutputRedir:= IsAtty(TextRec(Output).Handle)<>1;
  1407. { does the input come from another console or from a file? }
  1408. InputRedir :=
  1409. (IsAtty(TextRec(Input).Handle)<>1) or
  1410. (not OutputRedir and
  1411. (TTYName(TextRec(Input).Handle) <> TTYName(TextRec(Output).Handle)));
  1412. { Get Size of terminal and set WindMax to the window }
  1413. GetConsoleBuf;
  1414. WindMinX:=1;
  1415. WindMinY:=1;
  1416. WindMaxX:=ScreenWidth;
  1417. WindMaxY:=ScreenHeight;
  1418. WindMax:=((ScreenHeight-1) Shl 8)+(ScreenWidth-1);
  1419. {Get Current X&Y or Reset to Home}
  1420. if OutputRedir then
  1421. begin
  1422. CurrX:=1;
  1423. CurrY:=1;
  1424. end
  1425. else
  1426. begin
  1427. { Set default Terminal Settings }
  1428. SetRawMode(True);
  1429. { Get current X,Y if not set already }
  1430. GetXY(CurrX,CurrY);
  1431. if (CurrX=0) then
  1432. begin
  1433. CurrX:=1;
  1434. CurrY:=1;
  1435. ttySendStr(#27'[H');
  1436. end;
  1437. {Reset Attribute (TextAttr=7 at startup)}
  1438. ttySendStr(#27'[m');
  1439. end;
  1440. Finalization
  1441. ttyFlushOutput;
  1442. if not OutputRedir then
  1443. SetRawMode(False);
  1444. { remove console buf }
  1445. if Assigned(ConsoleBuf) then
  1446. FreeMem(ConsoleBuf,ScreenHeight*ScreenWidth*2);
  1447. End.