video.pp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Florian Klaempfl
  4. member of the Free Pascal development team
  5. Video unit for linux
  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 Video;
  13. interface
  14. {$i videoh.inc}
  15. implementation
  16. uses
  17. BaseUnix, Strings, TermInfo, termio;
  18. {$i video.inc}
  19. Type TConsoleType = (ttyNetwork
  20. {$ifdef linux},ttyLinux{$endif}
  21. ,ttyFreeBSD
  22. ,ttyNetBSD);
  23. var
  24. LastCursorType : byte;
  25. TtyFd: Longint;
  26. Console: TConsoleType;
  27. {$ifdef logging}
  28. f: file;
  29. const
  30. logstart: string = '';
  31. nl: char = #10;
  32. logend: string = #10#10;
  33. {$endif logging}
  34. {$ifdef cpui386}
  35. {$ASMMODE ATT}
  36. {$endif cpui386}
  37. const
  38. can_delete_term : boolean = false;
  39. ACSIn : string = '';
  40. ACSOut : string = '';
  41. InACS : boolean =false;
  42. function IsACS(var ch,ACSchar : char): boolean;
  43. begin
  44. IsACS:=false;
  45. case ch of
  46. #24, #30: {}
  47. ch:='^';
  48. #25, #31: {}
  49. ch:='v';
  50. #26, #16: {Never introduce a ctrl-Z ... }
  51. ch:='>';
  52. {#27,needed in Escape sequences} #17: {}
  53. ch:='<';
  54. #176, #177, #178: {°±²}
  55. begin
  56. IsACS:=true;
  57. ACSChar:='a';
  58. end;
  59. #180, #181, #182, #185: {´µ¶¹}
  60. begin
  61. IsACS:=true;
  62. ACSChar:='u';
  63. end;
  64. #183, #184, #187, #191: {·¸»¿}
  65. begin
  66. IsACS:=true;
  67. ACSChar:='k';
  68. end;
  69. #188, #189, #190, #217: {¼½¾Ù}
  70. begin
  71. IsACS:=true;
  72. ACSChar:='j';
  73. end;
  74. #192, #200, #211, #212: {ÀÈÓÔ}
  75. begin
  76. IsACS:=true;
  77. ACSChar:='m';
  78. end;
  79. #193, #202, #207, #208: {ÁÊÏÐ}
  80. begin
  81. IsACS:=true;
  82. ACSChar:='v';
  83. end;
  84. #194, #203, #209, #210: {ÂËÑÒ}
  85. begin
  86. IsACS:=true;
  87. ACSChar:='w';
  88. end;
  89. #195, #198, #199, #204: {ÃÆÇÌ}
  90. begin
  91. IsACS:=true;
  92. ACSChar:='t';
  93. end;
  94. #196, #205: {ÄÍ}
  95. begin
  96. IsACS:=true;
  97. ACSChar:='q';
  98. end;
  99. #179, #186: {³º}
  100. begin
  101. IsACS:=true;
  102. ACSChar:='x';
  103. end;
  104. #197, #206, #215, #216: {ÅÎר}
  105. begin
  106. IsACS:=true;
  107. ACSChar:='n';
  108. end;
  109. #201, #213, #214, #218: {ÉÕÖÚ}
  110. begin
  111. IsACS:=true;
  112. ACSChar:='l';
  113. end;
  114. #254: { þ }
  115. begin
  116. ch:='*';
  117. end;
  118. { Shadows for Buttons }
  119. #220: { Ü }
  120. begin
  121. IsACS:=true;
  122. ACSChar:='a';
  123. end;
  124. #223: { ß }
  125. begin
  126. IsACS:=true;
  127. ACSChar:='a';
  128. end;
  129. end;
  130. end;
  131. function SendEscapeSeqNdx(Ndx: Word) : boolean;
  132. var
  133. P,pdelay: PChar;
  134. begin
  135. SendEscapeSeqNdx:=false;
  136. if not assigned(cur_term_Strings) then
  137. exit{RunError(219)};
  138. P:=cur_term_Strings^[Ndx];
  139. if assigned(p) then
  140. begin { Do not transmit the delays }
  141. pdelay:=strpos(p,'$<');
  142. if assigned(pdelay) then
  143. pdelay^:=#0;
  144. fpWrite(stdoutputhandle, P^, StrLen(P));
  145. SendEscapeSeqNdx:=true;
  146. if assigned(pdelay) then
  147. pdelay^:='$';
  148. end;
  149. end;
  150. procedure SendEscapeSeq(const S: String);
  151. begin
  152. fpWrite(stdoutputhandle, S[1], Length(S));
  153. end;
  154. Function IntStr(l:longint):string;
  155. var
  156. s : string;
  157. begin
  158. Str(l,s);
  159. IntStr:=s;
  160. end;
  161. Function XY2Ansi(x,y,ox,oy:longint):String;
  162. {
  163. Returns a string with the escape sequences to go to X,Y on the screen.
  164. Note that x, y, ox, oy are 1-based (i.e. top-left corner of the screen
  165. is (1, 1)), while SetCursorPos parameters and CursorX and CursorY
  166. are 0-based (top-left corner of the screen is (0, 0)).
  167. }
  168. Begin
  169. if y=oy then
  170. begin
  171. if x=ox then
  172. begin
  173. XY2Ansi:='';
  174. exit;
  175. end;
  176. if x=1 then
  177. begin
  178. XY2Ansi:=#13;
  179. exit;
  180. end;
  181. if x>ox then
  182. begin
  183. XY2Ansi:=#27'['+IntStr(x-ox)+'C';
  184. exit;
  185. end
  186. else
  187. begin
  188. XY2Ansi:=#27'['+IntStr(ox-x)+'D';
  189. exit;
  190. end;
  191. end;
  192. if x=ox then
  193. begin
  194. if y>oy then
  195. begin
  196. XY2Ansi:=#27'['+IntStr(y-oy)+'B';
  197. exit;
  198. end
  199. else
  200. begin
  201. XY2Ansi:=#27'['+IntStr(oy-y)+'A';
  202. exit;
  203. end;
  204. end;
  205. if ((x=1) and (oy+1=y)) and (console<>ttyfreebsd) then
  206. XY2Ansi:=#13#10
  207. else
  208. XY2Ansi:=#27'['+IntStr(y)+';'+IntStr(x)+'H';
  209. End;
  210. const
  211. AnsiTbl : string[8]='04261537';
  212. Function Attr2Ansi(Attr,OAttr:longint):string;
  213. {
  214. Convert Attr to an Ansi String, the Optimal code is calculate
  215. with use of the old OAttr
  216. }
  217. var
  218. hstr : string[16];
  219. OFg,OBg,Fg,Bg : longint;
  220. procedure AddSep(ch:char);
  221. begin
  222. if length(hstr)>0 then
  223. hstr:=hstr+';';
  224. hstr:=hstr+ch;
  225. end;
  226. begin
  227. if Attr=OAttr then
  228. begin
  229. Attr2Ansi:='';
  230. exit;
  231. end;
  232. Hstr:='';
  233. Fg:=Attr and $f;
  234. Bg:=Attr shr 4;
  235. OFg:=OAttr and $f;
  236. OBg:=OAttr shr 4;
  237. if (OFg<>7) or (Fg=7) or ((OFg>7) and (Fg<8)) or ((OBg>7) and (Bg<8)) then
  238. begin
  239. hstr:='0';
  240. OFg:=7;
  241. OBg:=0;
  242. end;
  243. if (Fg>7) and (OFg<8) then
  244. begin
  245. AddSep('1');
  246. OFg:=OFg or 8;
  247. end;
  248. if (Bg and 8)<>(OBg and 8) then
  249. begin
  250. AddSep('5');
  251. OBg:=OBg or 8;
  252. end;
  253. if (Fg<>OFg) then
  254. begin
  255. AddSep('3');
  256. hstr:=hstr+AnsiTbl[(Fg and 7)+1];
  257. end;
  258. if (Bg<>OBg) then
  259. begin
  260. AddSep('4');
  261. hstr:=hstr+AnsiTbl[(Bg and 7)+1];
  262. end;
  263. if hstr='0' then
  264. hstr:='';
  265. Attr2Ansi:=#27'['+hstr+'m';
  266. end;
  267. procedure UpdateTTY(Force:boolean);
  268. type
  269. tchattr=packed record
  270. {$ifdef ENDIAN_LITTLE}
  271. ch : char;
  272. attr : byte;
  273. {$else}
  274. attr : byte;
  275. ch : char;
  276. {$endif}
  277. end;
  278. var
  279. outbuf : array[0..1023+255] of char;
  280. chattr : tchattr;
  281. skipped : boolean;
  282. outptr,
  283. spaces,
  284. eol,
  285. x,y,
  286. LastX,LastY,
  287. SpaceAttr,
  288. LastAttr : longint;
  289. p,pold : pvideocell;
  290. LastLineWidth : Longint;
  291. procedure TransformUsingACS(var st : string);
  292. var
  293. res : string;
  294. i : longint;
  295. ch,ACSch : char;
  296. begin
  297. res:='';
  298. for i:=1 to length(st) do
  299. begin
  300. ch:=st[i];
  301. if IsACS(ch,ACSch) then
  302. begin
  303. if not InACS then
  304. begin
  305. res:=res+ACSIn;
  306. InACS:=true;
  307. end;
  308. res:=res+ACSch;
  309. end
  310. else
  311. begin
  312. if InACS then
  313. begin
  314. res:=res+ACSOut+Attr2Ansi(LastAttr,0);
  315. InACS:=false;
  316. end;
  317. res:=res+ch;
  318. end;
  319. end;
  320. st:=res;
  321. end;
  322. procedure outdata(hstr:string);
  323. begin
  324. If Length(HStr)>0 Then
  325. Begin
  326. while (eol>0) do
  327. begin
  328. hstr:=#13#10+hstr;
  329. dec(eol);
  330. end;
  331. if NoExtendedFrame and (ACSIn<>'') and (ACSOut<>'') then
  332. TransformUsingACS(Hstr);
  333. move(hstr[1],outbuf[outptr],length(hstr));
  334. inc(outptr,length(hstr));
  335. if outptr>=1024 then
  336. begin
  337. {$ifdef logging}
  338. blockwrite(f,logstart[1],length(logstart));
  339. blockwrite(f,nl,1);
  340. blockwrite(f,outptr,sizeof(outptr));
  341. blockwrite(f,nl,1);
  342. blockwrite(f,outbuf,outptr);
  343. blockwrite(f,nl,1);
  344. {$endif logging}
  345. fpWrite(stdoutputhandle,outbuf,outptr);
  346. outptr:=0;
  347. end;
  348. end;
  349. end;
  350. procedure OutClr(c:byte);
  351. begin
  352. if c=LastAttr then
  353. exit;
  354. OutData(Attr2Ansi(c,LastAttr));
  355. LastAttr:=c;
  356. end;
  357. procedure OutSpaces;
  358. begin
  359. if (Spaces=0) then
  360. exit;
  361. OutClr(SpaceAttr);
  362. OutData(Space(Spaces));
  363. LastX:=x;
  364. LastY:=y;
  365. Spaces:=0;
  366. end;
  367. function GetTermString(ndx:word):String;
  368. var
  369. P,pdelay: PChar;
  370. begin
  371. GetTermString:='';
  372. if not assigned(cur_term_Strings) then
  373. exit{RunError(219)};
  374. P:=cur_term_Strings^[Ndx];
  375. if assigned(p) then
  376. begin { Do not transmit the delays }
  377. pdelay:=strpos(p,'$<');
  378. if assigned(pdelay) then
  379. pdelay^:=#0;
  380. GetTermString:=StrPas(p);
  381. if assigned(pdelay) then
  382. pdelay^:='$';
  383. end;
  384. end;
  385. begin
  386. OutPtr:=0;
  387. Eol:=0;
  388. skipped:=true;
  389. p:=PVideoCell(VideoBuf);
  390. pold:=PVideoCell(OldVideoBuf);
  391. { init Attr, X,Y and set autowrap off }
  392. SendEscapeSeq(#27'[m'#27'[?7l'{#27'[H'} );
  393. // 1.0.x: SendEscapeSeq(#27'[m'{#27'[H'});
  394. LastAttr:=7;
  395. LastX:=-1;
  396. LastY:=-1;
  397. for y:=1 to ScreenHeight do
  398. begin
  399. SpaceAttr:=0;
  400. Spaces:=0;
  401. LastLineWidth:=ScreenWidth;
  402. If (y=ScreenHeight) And (Console=ttyFreeBSD) {And :am: is on} Then
  403. LastLineWidth:=ScreenWidth-2;
  404. for x:=1 to LastLineWidth do
  405. begin
  406. if (not force) and (p^=pold^) then
  407. begin
  408. if (Spaces>0) then
  409. OutSpaces;
  410. skipped:=true;
  411. end
  412. else
  413. begin
  414. if skipped then
  415. begin
  416. OutData(XY2Ansi(x,y,LastX,LastY));
  417. LastX:=x;
  418. LastY:=y;
  419. skipped:=false;
  420. end;
  421. chattr:=tchattr(p^);
  422. if chattr.ch in [#0,#255] then
  423. chattr.ch:=' ';
  424. if chattr.ch=' ' then
  425. begin
  426. if Spaces=0 then
  427. SpaceAttr:=chattr.Attr;
  428. if (chattr.attr and $f0)=(spaceattr and $f0) then
  429. chattr.Attr:=SpaceAttr
  430. else
  431. begin
  432. OutSpaces;
  433. SpaceAttr:=chattr.Attr;
  434. end;
  435. inc(Spaces);
  436. end
  437. else
  438. begin
  439. if (Spaces>0) then
  440. OutSpaces;
  441. if ord(chattr.ch)<32 then
  442. begin
  443. Chattr.Attr:= $ff xor Chattr.Attr;
  444. ChAttr.ch:= chr(ord(chattr.ch)+ord('A')-1);
  445. end;
  446. if LastAttr<>chattr.Attr then
  447. OutClr(chattr.Attr);
  448. OutData(chattr.ch);
  449. LastX:=x+1;
  450. LastY:=y;
  451. end;
  452. p^:=tvideocell(chattr);
  453. end;
  454. inc(p);
  455. inc(pold);
  456. end;
  457. if (Spaces>0) then
  458. OutSpaces;
  459. if force then
  460. inc(eol)
  461. else
  462. skipped:=true;
  463. end;
  464. eol:=0;
  465. {if am in capabilities? Then}
  466. If (Console=ttyFreeBSD) and (Plongint(p)^<>plongint(pold)^) Then
  467. Begin
  468. OutData(XY2Ansi(ScreenWidth,ScreenHeight,LastX,LastY));
  469. OutData(#8);
  470. {Output last char}
  471. chattr:=tchattr(p[1]);
  472. if LastAttr<>chattr.Attr then
  473. OutClr(chattr.Attr);
  474. OutData(chattr.ch);
  475. inc(LastX);
  476. // OutData(XY2Ansi(ScreenWidth-1,ScreenHeight,LastX,LastY));
  477. // OutData(GetTermString(Insert_character));
  478. OutData(#8+#27+'[1@');
  479. chattr:=tchattr(p^);
  480. if LastAttr<>chattr.Attr then
  481. OutClr(chattr.Attr);
  482. OutData(chattr.ch);
  483. inc(LastX);
  484. end;
  485. OutData(XY2Ansi(CursorX+1,CursorY+1,LastX,LastY));
  486. {$ifdef logging}
  487. blockwrite(f,logstart[1],length(logstart));
  488. blockwrite(f,nl,1);
  489. blockwrite(f,outptr,sizeof(outptr));
  490. blockwrite(f,nl,1);
  491. blockwrite(f,outbuf,outptr);
  492. blockwrite(f,nl,1);
  493. {$endif logging}
  494. fpWrite(stdoutputhandle,outbuf,outptr);
  495. if InACS then
  496. SendEscapeSeqNdx(exit_alt_charset_mode);
  497. {turn autowrap on}
  498. // SendEscapeSeq(#27'[?7h');
  499. end;
  500. var
  501. preInitVideoTio, postInitVideoTio: termio.termios;
  502. inputRaw, outputRaw: boolean;
  503. procedure saveRawSettings(const tio: termio.termios);
  504. Begin
  505. with tio do
  506. begin
  507. inputRaw :=
  508. ((c_iflag and (IGNBRK or BRKINT or PARMRK or ISTRIP or
  509. INLCR or IGNCR or ICRNL or IXON)) = 0) and
  510. ((c_lflag and (ECHO or ECHONL or ICANON or ISIG or IEXTEN)) = 0);
  511. outPutRaw :=
  512. ((c_oflag and OPOST) = 0) and
  513. ((c_cflag and (CSIZE or PARENB)) = 0) and
  514. ((c_cflag and CS8) <> 0);
  515. end;
  516. end;
  517. procedure restoreRawSettings(tio: termio.termios);
  518. begin
  519. with tio do
  520. begin
  521. if inputRaw then
  522. begin
  523. c_iflag := c_iflag and (not (IGNBRK or BRKINT or PARMRK or ISTRIP or
  524. INLCR or IGNCR or ICRNL or IXON));
  525. c_lflag := c_lflag and
  526. (not (ECHO or ECHONL or ICANON or ISIG or IEXTEN));
  527. c_cc[VMIN]:=1;
  528. c_cc[VTIME]:=0;
  529. end;
  530. if outPutRaw then
  531. begin
  532. c_oflag := c_oflag and not(OPOST);
  533. c_cflag := c_cflag and not(CSIZE or PARENB) or CS8;
  534. end;
  535. end;
  536. TCSetAttr(1,TCSANOW,tio);
  537. end;
  538. procedure prepareInitVideo;
  539. begin
  540. TCGetAttr(1,preInitVideoTio);
  541. saveRawSettings(preInitVideoTio);
  542. end;
  543. procedure videoInitDone;
  544. begin
  545. TCGetAttr(1,postInitVideoTio);
  546. restoreRawSettings(postInitVideoTio);
  547. end;
  548. procedure prepareDoneVideo;
  549. var
  550. tio: termio.termios;
  551. begin
  552. TCGetAttr(1,tio);
  553. saveRawSettings(tio);
  554. TCSetAttr(1,TCSANOW,postInitVideoTio);
  555. end;
  556. procedure doneVideoDone;
  557. begin
  558. restoreRawSettings(preInitVideoTio);
  559. end;
  560. {$ifdef linux}
  561. function try_grab_vcsa_in_path(path:Pchar;len:cardinal):boolean;
  562. const grab_vcsa='/grab_vcsa';
  563. grab_vcsa_s:array[1..length(grab_vcsa)] of char=grab_vcsa;
  564. var p:Pchar;
  565. child:Tpid;
  566. status:cint;
  567. pstat:stat;
  568. begin
  569. getmem(p,len+length(grab_vcsa)+1);
  570. move(path^,p^,len);
  571. move(grab_vcsa_s,(p+len)^,length(grab_vcsa));
  572. (p+len+length(grab_vcsa))^:=#0;
  573. {Check if file exists.}
  574. if fpstat(p,pstat)<>0 then
  575. begin
  576. try_grab_vcsa_in_path:=false;
  577. exit;
  578. end;
  579. child:=fpfork;
  580. if child=0 then
  581. begin
  582. fpexecve(p,nil,nil);
  583. halt(255); {fpexec must have failed...}
  584. end;
  585. fpwaitpid(child,status,0);
  586. try_grab_vcsa_in_path:=status=0; {Return true if success.}
  587. freemem(p);
  588. end;
  589. function try_grab_vcsa:boolean;
  590. {If we cannot open /dev/vcsa0-31 it usually because we do not have
  591. permission. At login the owner of the tty you login is set to yourself.
  592. This is not done for vcsa, which is kinda strange as vcsa is revoke from
  593. you when you log out. We try to call a setuid root helper which chowns
  594. the vcsa device so we can get access to the screen buffer...}
  595. var path,p:Pchar;
  596. begin
  597. try_grab_vcsa:=false;
  598. path:=fpgetenv('PATH');
  599. if path=nil then
  600. exit;
  601. p:=strscan(path,':');
  602. while p<>nil do
  603. begin
  604. if try_grab_vcsa_in_path(path,p-path) then
  605. begin
  606. try_grab_vcsa:=true;
  607. exit;
  608. end;
  609. path:=p+1;
  610. p:=strscan(path,':');
  611. end;
  612. if try_grab_vcsa_in_path(path,strlen(path)) then
  613. exit;
  614. end;
  615. {$endif}
  616. procedure SysInitVideo;
  617. const
  618. fontstr : string[3]=#27'(K';
  619. var
  620. ThisTTY: String[30];
  621. FName: String;
  622. WS: packed record
  623. ws_row, ws_col, ws_xpixel, ws_ypixel: Word;
  624. end;
  625. Err: Longint;
  626. prev_term : TerminalCommon_ptr1;
  627. begin
  628. {$ifndef CPUI386}
  629. LowAscii:=false;
  630. {$endif CPUI386}
  631. { check for tty }
  632. ThisTTY:=TTYName(stdinputhandle);
  633. if (IsATTY(stdinputhandle)=1) then
  634. begin
  635. { save current terminal characteristics and remove rawness }
  636. prepareInitVideo;
  637. { write code to set a correct font }
  638. fpWrite(stdoutputhandle,fontstr[1],length(fontstr));
  639. { running on a tty, find out whether locally or remotely }
  640. TTyfd:=-1;
  641. Console:=TTyNetwork; {Default: Network or other vtxxx tty}
  642. if (Copy(ThisTTY, 1, 8) = '/dev/tty') and
  643. not (ThisTTY[9] IN ['p'..'u','P']) then // FreeBSD has these
  644. begin
  645. { running on the console }
  646. Case ThisTTY[9] of
  647. {$ifdef linux}
  648. '0'..'9' : begin { running Linux on native console or native-emulation }
  649. FName:='/dev/vcsa' + ThisTTY[9];
  650. { open console, $1b6=rw-rw-rw- }
  651. TTYFd:=fpOpen(FName, $1b6, O_RdWr);
  652. if TTYFd<>-1 Then
  653. console:=ttyLinux
  654. else
  655. if try_grab_vcsa then
  656. begin
  657. TTYFd:=fpOpen(FName, $1b6, O_RdWr);
  658. if TTYFd<>-1 Then
  659. console:=Ttylinux;
  660. end;
  661. end;
  662. {$endif}
  663. 'v' : { check for (Free?)BSD native}
  664. If (ThisTTY[10]>='0') and (ThisTTY[10]<='9') Then
  665. Console:=ttyFreeBSD; {TTYFd ?}
  666. end;
  667. end;
  668. If (Copy(fpGetEnv('TERM'),1,4)='cons') Then // cons<lines>
  669. Console:=ttyFreeBSD;
  670. {$ifdef linux}
  671. If Console<>ttylinux Then
  672. begin
  673. { running on a remote terminal, no error with /dev/vcsa }
  674. LowAscii:=false;
  675. //TTYFd:=stdoutputhandle;
  676. end;
  677. {$else}
  678. lowascii:=false;
  679. {$endif}
  680. fpioctl(stdinputhandle, TIOCGWINSZ, @WS);
  681. if WS.ws_Col=0 then
  682. WS.ws_Col:=80;
  683. if WS.ws_Row=0 then
  684. WS.ws_Row:=25;
  685. ScreenWidth:=WS.ws_Col;
  686. { TDrawBuffer only has FVMaxWidth elements
  687. larger values lead to crashes }
  688. if ScreenWidth> FVMaxWidth then
  689. ScreenWidth:=FVMaxWidth;
  690. ScreenHeight:=WS.ws_Row;
  691. CursorX:=0;
  692. CursorY:=0;
  693. LastCursorType:=$ff;
  694. ScreenColor:=True;
  695. { Start with a clear screen }
  696. {$ifdef linux}
  697. if Console<>ttylinux then
  698. begin
  699. {$endif}
  700. prev_term:=cur_term;
  701. setupterm(nil, stdoutputhandle, err);
  702. can_delete_term:=assigned(prev_term) and (prev_term<>cur_term);
  703. SendEscapeSeqNdx(cursor_home);
  704. SendEscapeSeqNdx(cursor_normal);
  705. SendEscapeSeqNdx(cursor_visible);
  706. SendEscapeSeqNdx(enter_ca_mode);
  707. SetCursorType(crUnderLine);
  708. If Console=ttyFreeBSD Then
  709. SendEscapeSeqNdx(exit_am_mode);
  710. {$ifdef linux}
  711. end
  712. else if not assigned(cur_term) then
  713. begin
  714. setupterm(nil, stdoutputhandle, err);
  715. can_delete_term:=false;
  716. end;
  717. {$endif}
  718. if assigned(cur_term_Strings) then
  719. begin
  720. ACSIn:=StrPas(cur_term_Strings^[enter_alt_charset_mode]);
  721. ACSOut:=StrPas(cur_term_Strings^[exit_alt_charset_mode]);
  722. if (ACSIn<>'') and (ACSOut<>'') then
  723. SendEscapeSeqNdx(ena_acs);
  724. if pos('$<',ACSIn)>0 then
  725. ACSIn:=Copy(ACSIn,1,Pos('$<',ACSIn)-1);
  726. if pos('$<',ACSOut)>0 then
  727. ACSOut:=Copy(ACSOut,1,Pos('$<',ACSOut)-1);
  728. If fpGetEnv('TERM')='xterm' then
  729. NoExtendedFrame := true; {use of acs for xterm is ok}
  730. end
  731. else
  732. begin
  733. ACSIn:='';
  734. ACSOut:='';
  735. end;
  736. {$ifdef logging}
  737. assign(f,'video.log');
  738. rewrite(f,1);
  739. {$endif logging}
  740. { save new terminal characteristics and possible restore rawness }
  741. videoInitDone;
  742. end
  743. else
  744. ErrorCode:=errVioInit; { not a TTY }
  745. end;
  746. procedure SysDoneVideo;
  747. begin
  748. prepareDoneVideo;
  749. {$ifdef linux}
  750. if Console=ttylinux then
  751. SetCursorPos(0,0)
  752. else
  753. begin
  754. {$endif}
  755. SendEscapeSeqNdx(exit_ca_mode);
  756. SendEscapeSeqNdx(cursor_home);
  757. SendEscapeSeqNdx(cursor_normal);
  758. SendEscapeSeqNdx(cursor_visible);
  759. SetCursorType(crUnderLine);
  760. SendEscapeSeq(#27'[H');
  761. {$ifdef linux}
  762. end;
  763. {$endif}
  764. ACSIn:='';
  765. ACSOut:='';
  766. doneVideoDone;
  767. { FreeBSD gives an error here.
  768. According to Pierre this could be more a NCurses version thing that
  769. a FreeBSD one. FreeBSD 4.4 has ncurses 5.
  770. MvdV102003: Since I ran 1.1 with newer FreeBSD without problem, I let it be for now}
  771. if can_delete_term then
  772. begin
  773. del_curterm(cur_term);
  774. can_delete_term:=false;
  775. end;
  776. {$ifdef logging}
  777. close(f);
  778. {$endif logging}
  779. end;
  780. procedure SysClearScreen;
  781. begin
  782. {$ifdef linux}
  783. if Console=ttylinux then
  784. UpdateScreen(true)
  785. else
  786. begin
  787. {$endif}
  788. SendEscapeSeq(#27'[0m');
  789. SendEscapeSeqNdx(clear_screen);
  790. {$ifdef linux}
  791. end;
  792. {$endif}
  793. end;
  794. procedure SysUpdateScreen(Force: Boolean);
  795. var
  796. DoUpdate : boolean;
  797. i : longint;
  798. p1,p2 : plongint;
  799. begin
  800. if not force then
  801. begin
  802. {$ifdef cpui386}
  803. asm
  804. pushl %esi
  805. pushl %edi
  806. movl VideoBuf,%esi
  807. movl OldVideoBuf,%edi
  808. movl VideoBufSize,%ecx
  809. shrl $2,%ecx
  810. repe
  811. cmpsl
  812. setne DoUpdate
  813. popl %edi
  814. popl %esi
  815. end;
  816. {$else not cpui386}
  817. p1:=plongint(VideoBuf);
  818. p2:=plongint(OldVideoBuf);
  819. for i:=0 to VideoBufSize div 2 do
  820. if (p1^<>p2^) then
  821. begin
  822. DoUpdate:=true;
  823. break;
  824. end
  825. else
  826. begin
  827. { Inc does add sizeof(longint) to both pointer values }
  828. inc(p1);
  829. inc(p2);
  830. end;
  831. {$endif not cpui386}
  832. end
  833. else
  834. DoUpdate:=true;
  835. if not DoUpdate then
  836. exit;
  837. {$ifdef linux}
  838. if Console=ttylinux then
  839. begin
  840. fplSeek(TTYFd, 4, Seek_Set);
  841. fpWrite(TTYFd, VideoBuf^,VideoBufSize);
  842. end
  843. else
  844. begin
  845. {$endif}
  846. UpdateTTY(force);
  847. {$ifdef linux}
  848. end;
  849. {$endif}
  850. Move(VideoBuf^, OldVideoBuf^, VideoBufSize);
  851. end;
  852. function SysGetCapabilities: Word;
  853. begin
  854. { about cpColor... we should check the terminfo database... }
  855. SysGetCapabilities:=cpUnderLine + cpBlink + cpColor;
  856. end;
  857. procedure SysSetCursorPos(NewCursorX, NewCursorY: Word);
  858. var
  859. Pos : array [1..2] of Byte;
  860. begin
  861. if (CursorX=NewCursorX) and (CursorY=NewCursorY) then
  862. exit;
  863. {$ifdef linux}
  864. if Console=ttylinux then
  865. begin
  866. fplSeek(TTYFd, 2, Seek_Set);
  867. Pos[1]:=NewCursorX;
  868. Pos[2]:=NewCursorY;
  869. fpWrite(TTYFd, Pos, 2);
  870. end
  871. else
  872. begin
  873. {$endif}
  874. { newcursorx,y and CursorX,Y are 0 based ! }
  875. SendEscapeSeq(XY2Ansi(NewCursorX+1,NewCursorY+1,CursorX+1,CursorY+1));
  876. {$ifdef linux}
  877. end;
  878. {$endif}
  879. CursorX:=NewCursorX;
  880. CursorY:=NewCursorY;
  881. end;
  882. function SysGetCursorType: Word;
  883. begin
  884. SysGetCursorType:=LastCursorType;
  885. end;
  886. procedure SysSetCursorType(NewType: Word);
  887. begin
  888. If LastCursorType=NewType then
  889. exit;
  890. LastCursorType:=NewType;
  891. case NewType of
  892. crBlock :
  893. Begin
  894. If not SendEscapeSeqNdx(cursor_visible) then
  895. If Console<>ttyFreeBSD Then // should be done only for linux?
  896. SendEscapeSeq(#27'[?17;0;64c');
  897. End;
  898. crHidden :
  899. Begin
  900. If not SendEscapeSeqNdx(cursor_invisible) then
  901. If Console<>ttyFreeBSD Then
  902. SendEscapeSeq(#27'[?1c');
  903. End;
  904. else
  905. begin
  906. If not SendEscapeSeqNdx(cursor_normal) then
  907. If Console<>ttyFreeBSD Then
  908. SendEscapeSeq(#27'[?2c');
  909. end;
  910. end;
  911. end;
  912. Const
  913. SysVideoDriver : TVideoDriver = (
  914. InitDriver : @SysInitVideo;
  915. DoneDriver : @SysDoneVideo;
  916. UpdateScreen : @SysUpdateScreen;
  917. ClearScreen : @SysClearScreen;
  918. SetVideoMode : Nil;
  919. GetVideoModeCount : Nil;
  920. GetVideoModeData : Nil;
  921. SetCursorPos : @SysSetCursorPos;
  922. GetCursorType : @SysGetCursorType;
  923. SetCursorType : @SysSetCursorType;
  924. GetCapabilities : @SysGetCapabilities;
  925. );
  926. initialization
  927. SetVideoDriver(SysVideoDriver);
  928. end.