crt.pp 34 KB

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