crt.pp 35 KB

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