crt.pp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641
  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. ttySendStr(Temp);
  401. end;
  402. Procedure DoEmptyLine(y,xl,xh:Longint);
  403. {
  404. Write an empty line at row Y from column Xl to Xh. Memory is also updated.
  405. }
  406. Var
  407. len : Longint;
  408. blank_with_attribute : TCharAttr;
  409. Begin
  410. ttyGotoXY(xl,y);
  411. len:=xh-xl+1;
  412. LineWrite(Space(len));
  413. blank_with_attribute.ch:=' ';
  414. blank_with_attribute.attr:=TextAttr;
  415. FillWord(ConsoleBuf^[(y-1)*ScreenWidth+xl-1],len,word(blank_with_attribute));
  416. End;
  417. procedure DoScrollLine(y1,y2,xl,xh:longint);
  418. {
  419. Move Line y1 to y2, use only columns Xl-Xh, Memory is updated also
  420. }
  421. var
  422. Temp : string;
  423. idx,
  424. OldAttr,
  425. x,attr : longint;
  426. begin
  427. ttyGotoXY(xl,y2);
  428. { precalc ConsoleBuf[] y-offset }
  429. idx:=(y1-1)*ScreenWidth-1;
  430. { update screen }
  431. OldAttr:=$ff;
  432. Temp:='';
  433. For x:=xl To xh Do
  434. Begin
  435. attr:=ConsoleBuf^[idx+x].attr;
  436. if (attr<>OldAttr) and (not OutputRedir) then
  437. begin
  438. temp:=temp+Attr2Ansi(Attr,OldAttr);
  439. OldAttr:=Attr;
  440. end;
  441. Temp:=Temp+ConsoleBuf^[idx+x].ch;
  442. if (x=xh) or (length(Temp)>240) then
  443. begin
  444. LineWrite(Temp);
  445. Temp:='';
  446. end;
  447. End;
  448. {Update memory copy}
  449. Move(ConsoleBuf^[(y1-1)*ScreenWidth+xl-1],ConsoleBuf^[(y2-1)*ScreenWidth+xl-1],(xh-xl+1)*2);
  450. end;
  451. Procedure TextColor(Color: Byte);
  452. {
  453. Switch foregroundcolor
  454. }
  455. var AddBlink : byte;
  456. Begin
  457. If (Color>15) Then
  458. AddBlink:=Blink
  459. else
  460. AddBlink:=0;
  461. ttyColor((Color and $f) or (TextAttr and $70) or AddBlink);
  462. End;
  463. Procedure TextBackground(Color: Byte);
  464. {
  465. Switch backgroundcolor
  466. }
  467. Begin
  468. TextAttr:=((Color shl 4) and ($f0 and not Blink)) or (TextAttr and ($0f OR Blink));
  469. ttyColor(TextAttr);
  470. End;
  471. Procedure HighVideo;
  472. {
  473. Set highlighted output.
  474. }
  475. Begin
  476. TextColor(TextAttr Or $08);
  477. End;
  478. Procedure LowVideo;
  479. {
  480. Set normal output
  481. }
  482. Begin
  483. TextColor(TextAttr And $77);
  484. End;
  485. Procedure NormVideo;
  486. {
  487. Set normal back and foregroundcolors.
  488. }
  489. Begin
  490. TextColor(7);
  491. TextBackGround(0);
  492. End;
  493. Procedure GotoXy(X: Byte; Y: Byte);
  494. {
  495. Go to coordinates X,Y in the current window.
  496. }
  497. Begin
  498. If (X>0) and (X<=WinMaxX- WinMinX+1) and
  499. (Y>0) and (Y<=WinMaxY-WinMinY+1) Then
  500. Begin
  501. Inc(X,WinMinX-1);
  502. Inc(Y,WinMinY-1);
  503. ttyGotoXY(x,y);
  504. End;
  505. End;
  506. Procedure Window(X1, Y1, X2, Y2: Byte);
  507. {
  508. Set screen window to the specified coordinates.
  509. }
  510. Begin
  511. if (X1>X2) or (X2>ScreenWidth) or
  512. (Y1>Y2) or (Y2>ScreenHeight) then
  513. exit;
  514. WinMinX:=X1;
  515. WinMaxX:=X2;
  516. WinMinY:=Y1;
  517. WinMaxY:=Y2;
  518. WindMin:=((Y1-1) Shl 8)+(X1-1);
  519. WindMax:=((Y2-1) Shl 8)+(X2-1);
  520. GoToXY(1,1);
  521. End;
  522. Procedure ClrScr;
  523. {
  524. Clear the current window, and set the cursor on 1,1
  525. }
  526. Var
  527. CY,i : Longint;
  528. oldflush : boolean;
  529. blank_with_attribute : TCharAttr;
  530. Begin
  531. { See if color has changed }
  532. if OldTextAttr<>TextAttr then
  533. begin
  534. i:=TextAttr;
  535. TextAttr:=OldTextAttr;
  536. ttyColor(i);
  537. end;
  538. oldflush:=ttySetFlush(Flushing);
  539. if FullWin then
  540. begin
  541. if not OutputRedir then
  542. ttySendStr(#27'[H'#27'[2J');
  543. CurrX:=1;
  544. CurrY:=1;
  545. blank_with_attribute.ch := ' ';
  546. blank_with_attribute.attr := TextAttr;
  547. FillWord(ConsoleBuf^,ScreenWidth*ScreenHeight,word(blank_with_attribute));
  548. end
  549. else
  550. begin
  551. For Cy:=WinMinY To WinMaxY Do
  552. DoEmptyLine(Cy,WinMinX,WinMaxX);
  553. GoToXY(1,1);
  554. end;
  555. ttySetFlush(oldflush);
  556. End;
  557. Procedure ClrEol;
  558. {
  559. Clear from current position to end of line.
  560. }
  561. var
  562. len,i : longint;
  563. IsLastLine : boolean;
  564. Begin
  565. { See if color has changed }
  566. if OldTextAttr<>TextAttr then
  567. begin
  568. i:=TextAttr;
  569. TextAttr:=OldTextAttr;
  570. ttyColor(i);
  571. end;
  572. if FullWin or (WinMaxX = ScreenWidth) then
  573. begin
  574. if not OutputRedir then
  575. ttySendStr(#27'[K');
  576. end
  577. else
  578. begin
  579. { Tweak winmaxx and winmaxy so no scrolling happends }
  580. len:=WinMaxX-CurrX+1;
  581. IsLastLine:=false;
  582. if CurrY=WinMaxY then
  583. begin
  584. inc(WinMaxX,3);
  585. inc(WinMaxY,2);
  586. IsLastLine:=true;
  587. end;
  588. ttySendStr(Space(len));
  589. if IsLastLine then
  590. begin
  591. dec(WinMaxX,3);
  592. dec(WinMaxY,2);
  593. end;
  594. ttyGotoXY(0,0);
  595. end;
  596. End;
  597. Function WhereX: Byte;
  598. {
  599. Return current X-position of cursor.
  600. }
  601. Begin
  602. WhereX:=CurrX-WinMinX+1;
  603. End;
  604. Function WhereY: Byte;
  605. {
  606. Return current Y-position of cursor.
  607. }
  608. Begin
  609. WhereY:=CurrY-WinMinY+1;
  610. End;
  611. Procedure ScrollScrnRegionUp(xl,yl,xh,yh, count: longint);
  612. {
  613. Scroll the indicated region count lines up. The empty lines are filled
  614. with blanks in the current color. The screen position is restored
  615. afterwards.
  616. }
  617. Var
  618. y,oldx,oldy : byte;
  619. oldflush : boolean;
  620. Begin
  621. oldflush:=ttySetFlush(Flushing);
  622. oldx:=CurrX;
  623. oldy:=CurrY;
  624. {Scroll}
  625. For y:=yl to yh-count do
  626. DoScrollLine(y+count,y,xl,xh);
  627. {Restore TextAttr}
  628. ttySendStr(Attr2Ansi(TextAttr,$ff));
  629. {Fill the rest with empty lines}
  630. for y:=yh-count+1 to yh do
  631. DoEmptyLine(y,xl,xh);
  632. {Restore current position}
  633. ttyGotoXY(OldX,OldY);
  634. ttySetFlush(oldflush);
  635. End;
  636. Procedure ScrollScrnRegionDown(xl,yl,xh,yh, count: longint);
  637. {
  638. Scroll the indicated region count lines down. The empty lines are filled
  639. with blanks in the current color. The screen position is restored
  640. afterwards.
  641. }
  642. Var
  643. y,oldx,oldy : byte;
  644. oldflush : boolean;
  645. Begin
  646. oldflush:=ttySetFlush(Flushing);
  647. oldx:=CurrX;
  648. oldy:=CurrY;
  649. {Scroll}
  650. for y:=yh downto yl+count do
  651. DoScrollLine(y-count,y,xl,xh);
  652. {Restore TextAttr}
  653. ttySendStr(Attr2Ansi(TextAttr,$ff));
  654. {Fill the rest with empty lines}
  655. for y:=yl to yl+count-1 do
  656. DoEmptyLine(y,xl,xh);
  657. {Restore current position}
  658. ttyGotoXY(OldX,OldY);
  659. ttySetFlush(oldflush);
  660. End;
  661. {*************************************************************************
  662. KeyBoard
  663. *************************************************************************}
  664. Const
  665. KeyBufferSize = 20;
  666. var
  667. KeyBuffer : Array[0..KeyBufferSize-1] of Char;
  668. KeyPut,
  669. KeySend : longint;
  670. Procedure PushKey(Ch:char);
  671. Var
  672. Tmp : Longint;
  673. Begin
  674. Tmp:=KeyPut;
  675. Inc(KeyPut);
  676. If KeyPut>=KeyBufferSize Then
  677. KeyPut:=0;
  678. If KeyPut<>KeySend Then
  679. KeyBuffer[Tmp]:=Ch
  680. Else
  681. KeyPut:=Tmp;
  682. End;
  683. Function PopKey:char;
  684. Begin
  685. If KeyPut<>KeySend Then
  686. Begin
  687. PopKey:=KeyBuffer[KeySend];
  688. Inc(KeySend);
  689. If KeySend>=KeyBufferSize Then
  690. KeySend:=0;
  691. End
  692. Else
  693. PopKey:=#0;
  694. End;
  695. Procedure PushExt(b:byte);
  696. begin
  697. PushKey(#0);
  698. PushKey(chr(b));
  699. end;
  700. const
  701. AltKeyStr : string[38]='qwertyuiopasdfghjklzxcvbnm1234567890-=';
  702. AltCodeStr : string[38]=#016#017#018#019#020#021#022#023#024#025#030#031#032#033#034#035#036#037#038+
  703. #044#045#046#047#048#049#050#120#121#122#123#124#125#126#127#128#129#130#131;
  704. Function FAltKey(ch:char):byte;
  705. var
  706. Idx : longint;
  707. Begin
  708. Idx:=Pos(ch,AltKeyStr);
  709. if Idx>0 then
  710. FAltKey:=byte(AltCodeStr[Idx])
  711. else
  712. FAltKey:=0;
  713. End;
  714. { This one doesn't care about keypresses already processed by readkey }
  715. { and waiting in the KeyBuffer, only about waiting keypresses at the }
  716. { TTYLevel (including ones that are waiting in the TTYRecvChar buffer) }
  717. function sysKeyPressed: boolean;
  718. var
  719. fdsin : tfdSet;
  720. begin
  721. if (InCnt>0) then
  722. sysKeyPressed:=true
  723. else
  724. begin
  725. fpFD_ZERO(fdsin);
  726. fpFD_SET(TTYin,fdsin);
  727. sysKeypressed:=(fpSelect(TTYIn+1,@fdsin,nil,nil,0)>0);
  728. end;
  729. end;
  730. Function KeyPressed:Boolean;
  731. Begin
  732. Keypressed := (KeySend<>KeyPut) or sysKeyPressed;
  733. End;
  734. Function ReadKey:char;
  735. Var
  736. ch : char;
  737. OldState,
  738. State : longint;
  739. FDS : TFDSet;
  740. Begin
  741. {Check Buffer first}
  742. if KeySend<>KeyPut then
  743. begin
  744. ReadKey:=PopKey;
  745. exit;
  746. end;
  747. {Wait for Key}
  748. { Only if none are waiting! (JM) }
  749. if not sysKeyPressed then
  750. begin
  751. FpFD_ZERO (FDS);
  752. fpFD_SET (0,FDS);
  753. fpSelect (1,@FDS,nil,nil,nil);
  754. end;
  755. ch:=ttyRecvChar;
  756. {Esc Found ?}
  757. CASE ch OF
  758. #27: begin
  759. State:=1;
  760. Delay(10);
  761. { This has to be sysKeyPressed and not "keyPressed", since after }
  762. { one iteration keyPressed will always be true because of the }
  763. { pushKey commands (JM) }
  764. while (State<>0) and (sysKeyPressed) do
  765. begin
  766. ch:=ttyRecvChar;
  767. OldState:=State;
  768. State:=0;
  769. case OldState of
  770. 1 : begin {Esc}
  771. case ch of
  772. 'a'..'z',
  773. '0'..'9',
  774. '-','=' : PushExt(FAltKey(ch));
  775. #10 : PushKey(#10);
  776. '[' : State:=2;
  777. {$IFDEF Unix}
  778. 'O': State:=7;
  779. {$ENDIF}
  780. else
  781. begin
  782. PushKey(ch);
  783. PushKey(#27);
  784. end;
  785. end;
  786. end;
  787. 2 : begin {Esc[}
  788. case ch of
  789. '[' : State:=3;
  790. 'A' : PushExt(72);
  791. 'B' : PushExt(80);
  792. 'C' : PushExt(77);
  793. 'D' : PushExt(75);
  794. {$IFDEF FREEBSD}
  795. {'E' - Center key, not handled in DOS TP7}
  796. 'F' : PushExt(79); {End}
  797. 'G': PushExt(81); {PageDown}
  798. {$ELSE}
  799. 'G' : PushKey('5'); {Center key, Linux}
  800. {$ENDIF}
  801. 'H' : PushExt(71);
  802. {$IFDEF FREEBSD}
  803. 'I' : PushExt(73); {PageUp}
  804. {$ENDIF}
  805. 'K' : PushExt(79);
  806. {$IFDEF FREEBSD}
  807. 'L' : PushExt(82); {Insert - Deekoo}
  808. 'M' : PushExt(59); {F1-F10 - Deekoo}
  809. 'N' : PushExt(60); {F2}
  810. 'O' : PushExt(61); {F3}
  811. 'P' : PushExt(62); {F4}
  812. 'Q' : PushExt(63); {F5}
  813. 'R' : PushExt(64); {F6}
  814. 'S' : PushExt(65); {F7}
  815. 'T' : PushExt(66); {F8}
  816. 'U' : PushExt(67); {F9}
  817. 'V' : PushExt(68); {F10}
  818. {Not sure if TP/BP handles F11 and F12 like this normally;
  819. In pcemu, a TP7 executable handles 'em this way, though.}
  820. 'W' : PushExt(133); {F11}
  821. 'X' : PushExt(134); {F12}
  822. 'Y' : PushExt(84); {Shift-F1}
  823. 'Z' : PushExt(85); {Shift-F2}
  824. 'a' : PushExt(86); {Shift-F3}
  825. 'b' : PushExt(87); {Shift-F4}
  826. 'c' : PushExt(88); {Shift-F5}
  827. 'd' : PushExt(89); {Shift-F6}
  828. 'e' : PushExt(90); {Shift-F7}
  829. 'f' : PushExt(91); {Shift-F8}
  830. 'g' : PushExt(92); {Shift-F9}
  831. 'h' : PushExt(93); {Shift-F10}
  832. 'i' : PushExt(135); {Shift-F11}
  833. 'j' : PushExt(136); {Shift-F12}
  834. 'k' : PushExt(94); {Ctrl-F1}
  835. 'l' : PushExt(95);
  836. 'm' : PushExt(96);
  837. 'n' : PushExt(97);
  838. 'o' : PushExt(98);
  839. 'p' : PushExt(99);
  840. 'q' : PushExt(100);
  841. 'r' : PushExt(101);
  842. 's' : PushExt(102);
  843. 't' : PushExt(103); {Ctrl-F10}
  844. 'u' : PushExt(137); {Ctrl-F11}
  845. 'v' : PushExt(138); {Ctrl-F12}
  846. {$ENDIF}
  847. '1' : State:=4;
  848. '2' : State:=5;
  849. '3' : State:=6;
  850. '4' : PushExt(79);
  851. '5' : PushExt(73);
  852. '6' : PushExt(81);
  853. else
  854. begin
  855. PushKey(ch);
  856. PushKey('[');
  857. PushKey(#27);
  858. end;
  859. end;
  860. if ch in ['4'..'6'] then
  861. State:=255;
  862. end;
  863. 3 : begin {Esc[[}
  864. case ch of
  865. 'A' : PushExt(59);
  866. 'B' : PushExt(60);
  867. 'C' : PushExt(61);
  868. 'D' : PushExt(62);
  869. 'E' : PushExt(63);
  870. end;
  871. end;
  872. 4 : begin {Esc[1}
  873. case ch of
  874. '~' : PushExt(71);
  875. '7' : PushExt(64);
  876. '8' : PushExt(65);
  877. '9' : PushExt(66);
  878. end;
  879. if (Ch<>'~') then
  880. State:=255;
  881. end;
  882. 5 : begin {Esc[2}
  883. case ch of
  884. '~' : PushExt(82);
  885. '0' : pushExt(67);
  886. '1' : PushExt(68);
  887. '3' : PushExt(133); {F11}
  888. {Esc[23~ is also shift-F1,shift-F11}
  889. '4' : PushExt(134); {F12}
  890. {Esc[24~ is also shift-F2,shift-F12}
  891. '5' : PushExt(86); {Shift-F3}
  892. '6' : PushExt(87); {Shift-F4}
  893. '8' : PushExt(88); {Shift-F5}
  894. '9' : PushExt(89); {Shift-F6}
  895. end;
  896. if (Ch<>'~') then
  897. State:=255;
  898. end;
  899. 6 : begin {Esc[3}
  900. case ch of
  901. '~' : PushExt(83); {Del}
  902. '1' : PushExt(90); {Shift-F7}
  903. '2' : PushExt(91); {Shift-F8}
  904. '3' : PushExt(92); {Shift-F9}
  905. '4' : PushExt(93); {Shift-F10}
  906. end;
  907. if (Ch<>'~') then
  908. State:=255;
  909. end;
  910. {$ifdef Unix}
  911. 7 : begin {Esc[O}
  912. case ch of
  913. 'A' : PushExt(72);
  914. 'B' : PushExt(80);
  915. 'C' : PushExt(77);
  916. 'D' : PushExt(75);
  917. end;
  918. end;
  919. {$endif}
  920. 255 : ;
  921. end;
  922. if State<>0 then
  923. Delay(10);
  924. end;
  925. if State=1 then
  926. PushKey(ch);
  927. end;
  928. #127: PushKey(#8);
  929. else PushKey(ch);
  930. End;
  931. ReadKey:=PopKey;
  932. End;
  933. Procedure Delay(MS: Word);
  934. {
  935. Wait for DTime milliseconds.
  936. }
  937. Begin
  938. fpSelect(0,nil,nil,nil,MS);
  939. End;
  940. {****************************************************************************
  941. Write(ln)/Read(ln) support
  942. ****************************************************************************}
  943. procedure DoLn;
  944. begin
  945. if CurrY=WinMaxY then
  946. begin
  947. if FullWin then
  948. begin
  949. ttySendStr(#10#13);
  950. CurrX:=WinMinX;
  951. CurrY:=WinMaxY;
  952. end
  953. else
  954. begin
  955. ScrollScrnRegionUp(WinMinX,WinMinY,WinMaxX,WinMaxY,1);
  956. ttyGotoXY(WinMinX,WinMaxY);
  957. end;
  958. end
  959. else
  960. ttyGotoXY(WinMinX,CurrY+1);
  961. end;
  962. var
  963. Lastansi : boolean;
  964. AnsiCode : string;
  965. Procedure DoWrite(const s:String);
  966. {
  967. Write string to screen, parse most common AnsiCodes
  968. }
  969. var
  970. found,
  971. OldFlush : boolean;
  972. x,y,
  973. i,j,
  974. SendBytes : longint;
  975. function AnsiPara(var hstr:string):byte;
  976. var
  977. k,j : longint;
  978. code : word;
  979. begin
  980. j:=pos(';',hstr);
  981. if j=0 then
  982. j:=length(hstr);
  983. val(copy(hstr,3,j-3),k,code);
  984. Delete(hstr,3,j-2);
  985. if k=0 then
  986. k:=1;
  987. AnsiPara:=k;
  988. end;
  989. procedure SendText;
  990. var
  991. LeftX : longint;
  992. begin
  993. while (SendBytes>0) do
  994. begin
  995. LeftX:=WinMaxX-CurrX+1;
  996. if (SendBytes>LeftX) then
  997. begin
  998. ttyWrite(Copy(s,i-SendBytes,LeftX));
  999. dec(SendBytes,LeftX);
  1000. DoLn;
  1001. end
  1002. else
  1003. begin
  1004. ttyWrite(Copy(s,i-SendBytes,SendBytes));
  1005. SendBytes:=0;
  1006. end;
  1007. end;
  1008. end;
  1009. begin
  1010. oldflush:=ttySetFlush(Flushing);
  1011. { Support textattr:= changing }
  1012. if OldTextAttr<>TextAttr then
  1013. begin
  1014. i:=TextAttr;
  1015. TextAttr:=OldTextAttr;
  1016. ttyColor(i);
  1017. end;
  1018. { write the stuff }
  1019. SendBytes:=0;
  1020. i:=1;
  1021. while (i<=length(s)) do
  1022. begin
  1023. if (s[i]=#27) or (LastAnsi) then
  1024. begin
  1025. SendText;
  1026. LastAnsi:=false;
  1027. j:=i;
  1028. found:=false;
  1029. while (j<=length(s)) and (not found) do
  1030. begin
  1031. found:=not (s[j] in [#27,'[','0'..'9',';','?']);
  1032. inc(j);
  1033. end;
  1034. Ansicode:=AnsiCode+Copy(s,i,j-i);
  1035. if found then
  1036. begin
  1037. case AnsiCode[length(AnsiCode)] of
  1038. 'm' : ttyColor(Ansi2Attr(AnsiCode,TextAttr));
  1039. 'H' : begin {No other way :( Coz First Para=Y}
  1040. y:=AnsiPara(AnsiCode);
  1041. x:=AnsiPara(AnsiCode);
  1042. GotoXY(x,y);
  1043. end;
  1044. 'J' : if AnsiPara(AnsiCode)=2 then
  1045. ClrScr;
  1046. 'K' : ClrEol;
  1047. 'A' : GotoXY(CurrX,Max(CurrY-AnsiPara(AnsiCode),WinMinY));
  1048. 'B' : GotoXY(CurrX,Min(CurrY+AnsiPara(AnsiCode),WinMaxY));
  1049. 'C' : GotoXY(Min(CurrX+AnsiPara(AnsiCode),WinMaxX),CurrY);
  1050. 'D' : GotoXY(Max(CurrX-AnsiPara(AnsiCode),WinMinX),CurrY);
  1051. 'h' : ; {Stupid Thedraw [?7h Code}
  1052. else
  1053. found:=false;
  1054. end;
  1055. end
  1056. else
  1057. begin
  1058. LastAnsi:=true;
  1059. found:=true;
  1060. end;
  1061. {Clear AnsiCode?}
  1062. if not LastAnsi then
  1063. AnsiCode:='';
  1064. {Increase Idx or SendBytes}
  1065. if found then
  1066. i:=j-1
  1067. else
  1068. inc(SendBytes);
  1069. end
  1070. else
  1071. begin
  1072. LastAnsi:=false;
  1073. case s[i] of
  1074. #13 : begin {CR}
  1075. SendText;
  1076. ttyGotoXY(WinMinX,CurrY);
  1077. end;
  1078. #10 : begin {NL}
  1079. SendText;
  1080. DoLn;
  1081. end;
  1082. #9 : begin {Tab}
  1083. SendText;
  1084. ttyWrite(Space(9-((CurrX-1) and $08)));
  1085. end;
  1086. #8 : begin {BackSpace}
  1087. SendText;
  1088. ttyWrite(#8);
  1089. end;
  1090. else
  1091. inc(SendBytes);
  1092. end;
  1093. end;
  1094. inc(i);
  1095. end;
  1096. if SendBytes>0 then
  1097. SendText;
  1098. ttySetFlush(oldFLush);
  1099. end;
  1100. Function CrtWrite(Var F: TextRec): Integer;
  1101. {
  1102. Top level write function for CRT
  1103. }
  1104. Var
  1105. Temp : String;
  1106. idx,i : Longint;
  1107. oldflush : boolean;
  1108. Begin
  1109. oldflush:=ttySetFlush(Flushing);
  1110. idx:=0;
  1111. while (F.BufPos>0) do
  1112. begin
  1113. i:=F.BufPos;
  1114. if i>255 then
  1115. i:=255;
  1116. Move(F.BufPTR^[idx],Temp[1],i);
  1117. SetLength(Temp,i);
  1118. DoWrite(Temp);
  1119. dec(F.BufPos,i);
  1120. inc(idx,i);
  1121. end;
  1122. ttySetFlush(oldFLush);
  1123. CrtWrite:=0;
  1124. End;
  1125. Function CrtRead(Var F: TextRec): Integer;
  1126. {
  1127. Read from CRT associated file.
  1128. }
  1129. var
  1130. c : char;
  1131. i : longint;
  1132. Begin
  1133. if isATTY(F.Handle)<>-1 then
  1134. begin
  1135. F.BufPos := 0;
  1136. i := 0;
  1137. repeat
  1138. c := readkey;
  1139. case c of
  1140. { ignore special keys }
  1141. #0:
  1142. c:= readkey;
  1143. { Backspace }
  1144. #8:
  1145. if i > 0 then
  1146. begin
  1147. if not(OutputRedir or InputRedir) then
  1148. write(#8#32#8);
  1149. dec(i);
  1150. end;
  1151. { Unhandled extended key }
  1152. #27:;
  1153. { CR }
  1154. #13:
  1155. begin
  1156. F.BufPtr^[i] := #10;
  1157. if not(OutputRedir or InputRedir) then
  1158. write(#10);
  1159. inc(i);
  1160. end;
  1161. else
  1162. begin
  1163. if not(OutputRedir or InputRedir) then
  1164. write(c);
  1165. F.BufPtr^[i] := c;
  1166. inc(i);
  1167. end;
  1168. end;
  1169. until (c in [#10,#13]) or (i >= F.BufSize);
  1170. F.BufEnd := i;
  1171. CrtRead := 0;
  1172. exit;
  1173. end;
  1174. F.BufEnd:=fpRead(F.Handle, F.BufPtr^, F.BufSize);
  1175. { fix #13 only's -> #10 to overcome terminal setting }
  1176. for i:=1to F.BufEnd do
  1177. begin
  1178. if (F.BufPtr^[i-1]=#13) and (F.BufPtr^[i]<>#10) then
  1179. F.BufPtr^[i-1]:=#10;
  1180. end;
  1181. F.BufPos:=F.BufEnd;
  1182. if not(OutputRedir or InputRedir) then
  1183. CrtWrite(F)
  1184. else F.BufPos := 0;
  1185. CrtRead:=0;
  1186. End;
  1187. Function CrtReturn(Var F:TextRec):Integer;
  1188. Begin
  1189. CrtReturn:=0;
  1190. end;
  1191. Function CrtClose(Var F: TextRec): Integer;
  1192. {
  1193. Close CRT associated file.
  1194. }
  1195. Begin
  1196. F.Mode:=fmClosed;
  1197. CrtClose:=0;
  1198. End;
  1199. Function CrtOpen(Var F: TextRec): Integer;
  1200. {
  1201. Open CRT associated file.
  1202. }
  1203. Begin
  1204. If F.Mode=fmOutput Then
  1205. begin
  1206. TextRec(F).InOutFunc:=@CrtWrite;
  1207. TextRec(F).FlushFunc:=@CrtWrite;
  1208. end
  1209. Else
  1210. begin
  1211. F.Mode:=fmInput;
  1212. TextRec(F).InOutFunc:=@CrtRead;
  1213. TextRec(F).FlushFunc:=@CrtReturn;
  1214. end;
  1215. TextRec(F).CloseFunc:=@CrtClose;
  1216. CrtOpen:=0;
  1217. End;
  1218. procedure AssignCrt(var F: Text);
  1219. {
  1220. Assign a file to the console. All output on file goes to console instead.
  1221. }
  1222. begin
  1223. Assign(F,'');
  1224. TextRec(F).OpenFunc:=@CrtOpen;
  1225. end;
  1226. {******************************************************************************
  1227. High Level Functions
  1228. ******************************************************************************}
  1229. Procedure DelLine;
  1230. {
  1231. Delete current line. Scroll subsequent lines up
  1232. }
  1233. Begin
  1234. ScrollScrnRegionUp(WinMinX, CurrY, WinMaxX, WinMaxY, 1);
  1235. End;
  1236. Procedure InsLine;
  1237. {
  1238. Insert line at current cursor position. Scroll subsequent lines down.
  1239. }
  1240. Begin
  1241. ScrollScrnRegionDown(WinMinX, CurrY, WinMaxX, WinMaxY, 1);
  1242. End;
  1243. const
  1244. KIOCSOUND = $4B2F; // start sound generation (0 for off)
  1245. Procedure Sound(Hz: Word);
  1246. begin
  1247. if not OutputRedir then
  1248. fpIoctl(TextRec(Output).Handle, KIOCSOUND, Pointer(1193180 div Hz));
  1249. end;
  1250. Procedure NoSound;
  1251. begin
  1252. if not OutputRedir then
  1253. fpIoctl(TextRec(Output).Handle, KIOCSOUND, nil);
  1254. end;
  1255. Procedure TextMode (Mode: word);
  1256. {
  1257. Only Clears Screen under linux}
  1258. begin
  1259. ClrScr;
  1260. end;
  1261. {******************************************************************************
  1262. Extra
  1263. ******************************************************************************}
  1264. procedure CursorBig;
  1265. begin
  1266. ttySendStr(#27'[?17;0;64c');
  1267. end;
  1268. procedure CursorOn;
  1269. begin
  1270. ttySendStr(#27'[?2c');
  1271. end;
  1272. procedure CursorOff;
  1273. begin
  1274. ttySendStr(#27'[?1c');
  1275. end;
  1276. {******************************************************************************
  1277. Initialization
  1278. ******************************************************************************}
  1279. var
  1280. OldIO : termio.TermIos;
  1281. inputRaw, outputRaw: boolean;
  1282. procedure saveRawSettings(const tio: termio.termios);
  1283. Begin
  1284. with tio do
  1285. begin
  1286. inputRaw :=
  1287. ((c_iflag and (IGNBRK or BRKINT or PARMRK or ISTRIP or
  1288. INLCR or IGNCR or ICRNL or IXON)) = 0) and
  1289. ((c_lflag and (ECHO or ECHONL or ICANON or ISIG or IEXTEN)) = 0);
  1290. outPutRaw :=
  1291. ((c_oflag and OPOST) = 0) and
  1292. ((c_cflag and (CSIZE or PARENB)) = 0) and
  1293. ((c_cflag and CS8) <> 0);
  1294. end;
  1295. end;
  1296. procedure restoreRawSettings(tio: termio.termios);
  1297. begin
  1298. with tio do
  1299. begin
  1300. if inputRaw then
  1301. begin
  1302. c_iflag := c_iflag and (not (IGNBRK or BRKINT or PARMRK or ISTRIP or
  1303. INLCR or IGNCR or ICRNL or IXON));
  1304. c_lflag := c_lflag and
  1305. (not (ECHO or ECHONL or ICANON or ISIG or IEXTEN));
  1306. end;
  1307. if outPutRaw then
  1308. begin
  1309. c_oflag := c_oflag and not(OPOST);
  1310. c_cflag := c_cflag and not(CSIZE or PARENB) or CS8;
  1311. end;
  1312. end;
  1313. end;
  1314. Procedure SetRawMode(b:boolean);
  1315. Var
  1316. Tio : Termios;
  1317. Begin
  1318. if b then
  1319. begin
  1320. TCGetAttr(1,Tio);
  1321. SaveRawSettings(Tio);
  1322. OldIO:=Tio;
  1323. CFMakeRaw(Tio);
  1324. end
  1325. else
  1326. begin
  1327. RestoreRawSettings(OldIO);
  1328. Tio:=OldIO;
  1329. end;
  1330. TCSetAttr(1,TCSANOW,Tio);
  1331. End;
  1332. procedure GetXY(var x,y:byte);
  1333. var
  1334. fds : tfdSet;
  1335. i,j,
  1336. readed : longint;
  1337. buf : array[0..255] of char;
  1338. s : string[16];
  1339. begin
  1340. x:=0;
  1341. y:=0;
  1342. s:=#27'[6n';
  1343. fpWrite(0,s[1],length(s));
  1344. fpFD_ZERO(fds);
  1345. fpFD_SET(1,fds);
  1346. if (fpSelect(2,@fds,nil,nil,1000)>0) then
  1347. begin
  1348. readed:=fpRead(1,buf,sizeof(buf));
  1349. i:=0;
  1350. while (i+5<readed) and (buf[i]<>#27) and (buf[i+1]<>'[') do
  1351. inc(i);
  1352. if i+5<readed then
  1353. begin
  1354. s:=space(16);
  1355. move(buf[i+2],s[1],16);
  1356. i:=Pos(';',s);
  1357. if i>0 then
  1358. begin
  1359. Val(Copy(s,1,i-1),y);
  1360. j:=Pos('R',s);
  1361. if j=0 then
  1362. j:=length(s);
  1363. Val(Copy(s,i+1,j-(i+1)),x);
  1364. end;
  1365. end;
  1366. end;
  1367. end;
  1368. Procedure GetConsoleBuf;
  1369. var
  1370. WinInfo : TWinSize;
  1371. begin
  1372. if Assigned(ConsoleBuf) then
  1373. FreeMem(ConsoleBuf,ScreenHeight*ScreenWidth*2);
  1374. ScreenWidth:=0;
  1375. ScreenHeight:=0;
  1376. if (not OutputRedir) and (fpIOCtl(TextRec(Output).Handle,TIOCGWINSZ,@Wininfo)>=0) then
  1377. begin
  1378. ScreenWidth:=Wininfo.ws_col;
  1379. ScreenHeight:=Wininfo.ws_row;
  1380. end;
  1381. // Set some arbitrary defaults which make some sense...
  1382. If (ScreenWidth=0) then
  1383. ScreenWidth:=80;
  1384. If (ScreenHeight=0) then
  1385. ScreenHeight:=25;
  1386. GetMem(ConsoleBuf,ScreenHeight*ScreenWidth*2);
  1387. FillChar(ConsoleBuf^,ScreenHeight*ScreenWidth*2,0);
  1388. end;
  1389. Initialization
  1390. { Redirect the standard output }
  1391. assigncrt(Output);
  1392. Rewrite(Output);
  1393. TextRec(Output).Handle:=StdOutputHandle;
  1394. assigncrt(Input);
  1395. Reset(Input);
  1396. TextRec(Input).Handle:=StdInputHandle;
  1397. { Are we redirected to a file ? }
  1398. OutputRedir:= IsAtty(TextRec(Output).Handle)=-1;
  1399. { does the input come from another console or from a file? }
  1400. InputRedir :=
  1401. (IsAtty(TextRec(Input).Handle)=-1) or
  1402. (not OutputRedir and
  1403. (TTYName(TextRec(Input).Handle) <> TTYName(TextRec(Output).Handle)));
  1404. { Get Size of terminal and set WindMax to the window }
  1405. GetConsoleBuf;
  1406. WinMinX:=1;
  1407. WinMinY:=1;
  1408. WinMaxX:=ScreenWidth;
  1409. WinMaxY:=ScreenHeight;
  1410. WindMax:=((ScreenHeight-1) Shl 8)+(ScreenWidth-1);
  1411. {Get Current X&Y or Reset to Home}
  1412. if OutputRedir then
  1413. begin
  1414. CurrX:=1;
  1415. CurrY:=1;
  1416. end
  1417. else
  1418. begin
  1419. { Set default Terminal Settings }
  1420. SetRawMode(True);
  1421. { Get current X,Y if not set already }
  1422. GetXY(CurrX,CurrY);
  1423. if (CurrX=0) then
  1424. begin
  1425. CurrX:=1;
  1426. CurrY:=1;
  1427. ttySendStr(#27'[H');
  1428. end;
  1429. {Reset Attribute (TextAttr=7 at startup)}
  1430. ttySendStr(#27'[m');
  1431. end;
  1432. Finalization
  1433. ttyFlushOutput;
  1434. if not OutputRedir then
  1435. SetRawMode(False);
  1436. { remove console buf }
  1437. if Assigned(ConsoleBuf) then
  1438. FreeMem(ConsoleBuf,ScreenHeight*ScreenWidth*2);
  1439. End.
  1440. {
  1441. $Log$
  1442. Revision 1.25 2005-05-14 15:01:49 hajny
  1443. * TextMode parameter type changed to word for TP/BP compatibility
  1444. Revision 1.24 2005/03/16 18:17:23 jonas
  1445. * fix from mischi to fix extra spaces under some terminals
  1446. Revision 1.23 2005/03/15 09:20:11 jonas
  1447. * endianess fixes from mischi
  1448. Revision 1.22 2005/02/14 17:13:31 peter
  1449. * truncate log
  1450. }