video.pp 28 KB

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