crt.pp 35 KB

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