video.pp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338
  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. {$IFNDEF FPC_DOTTEDUNITS}
  13. unit video;
  14. {$ENDIF FPC_DOTTEDUNITS}
  15. {$I-}
  16. {$GOTO on}
  17. {*****************************************************************************}
  18. interface
  19. {*****************************************************************************}
  20. {$i videoh.inc}
  21. {*****************************************************************************}
  22. implementation
  23. {*****************************************************************************}
  24. {$IFDEF FPC_DOTTEDUNITS}
  25. uses UnixApi.Base,UnixApi.TermIO,System.Strings,System.Console.Unixkvmbase,System.Unicode.Graphemebreakproperty,System.Unicode.Eastasianwidth
  26. ,System.CharSet
  27. {$ifdef Linux},LinuxApi.Vcs{$endif};
  28. {$ELSE FPC_DOTTEDUNITS}
  29. uses baseunix,termio,strings,unixkvmbase,graphemebreakproperty,eastasianwidth
  30. ,charset
  31. {$ifdef linux},linuxvcs{$endif};
  32. {$ENDIF FPC_DOTTEDUNITS}
  33. const
  34. CP_ISO01 = 28591; {ISO 8859-1}
  35. CP_ISO02 = 28592; {ISO 8859-2}
  36. CP_ISO05 = 28595; {ISO 8859-5}
  37. var external_codepage:TSystemCodePage;
  38. {$i video.inc}
  39. type Tconsole_type=(ttyNetwork
  40. {$ifdef linux},ttyLinux{$endif}
  41. ,ttyFreeBSD
  42. ,ttyNetBSD);
  43. Ttermcode=(
  44. enter_alt_charset_mode,
  45. exit_alt_charset_mode,
  46. clear_screen,
  47. cursor_home,
  48. cursor_normal,
  49. cursor_visible_underline,
  50. cursor_visible_block,
  51. cursor_invisible,
  52. enter_ca_mode,
  53. exit_ca_mode,
  54. exit_am_mode,
  55. ena_acs
  56. );
  57. Ttermcodes=array[Ttermcode] of PAnsiChar;
  58. Ptermcodes=^Ttermcodes;
  59. const term_codes_ansi:Ttermcodes=
  60. (#$1B#$5B#$31#$31#$6D, {enter_alt_charset_mode}
  61. #$1B#$5B#$31#$30#$6D, {exit_alt_charset_mode}
  62. #$1B#$5B#$48#$1B#$5B#$4A, {clear_screen}
  63. #$1B#$5B#$48, {cursor_home}
  64. nil, {cursor_normal}
  65. nil, {cursor visible, underline}
  66. nil, {cursor visible, block}
  67. nil, {cursor_invisible}
  68. nil, {enter_ca_mode}
  69. nil, {exit_ca_mode}
  70. nil, {exit_am_mode}
  71. nil); {ena_acs}
  72. term_codes_freebsd:Ttermcodes=
  73. (nil, {enter_alt_charset_mode}
  74. nil, {exit_alt_charset_mode}
  75. #$1B#$5B#$48#$1B#$5B#$4A, {clear_screen}
  76. #$1B#$5B#$48, {cursor_home}
  77. #$1B#$5B#$3D#$30#$43, {cursor_normal}
  78. #$1B#$5B#$3D#$31#$43, {cursor visible, underline}
  79. #$1B#$5B#$3D#$31#$43, {cursor visible, block}
  80. nil, {cursor_invisible}
  81. nil, {enter_ca_mode}
  82. nil, {exit_ca_mode}
  83. nil, {exit_am_mode}
  84. nil); {ena_acs}
  85. term_codes_linux:Ttermcodes=
  86. (#$1B#$5B#$31#$31#$6D, {enter_alt_charset_mode}
  87. #$1B#$5B#$31#$30#$6D, {exit_alt_charset_mode}
  88. #$1B#$5B#$48#$1B#$5B#$4A, {clear_screen}
  89. #$1B#$5B#$48, {cursor_home}
  90. #$1B'[?25h'#$1B'[?0c', {cursor_normal}
  91. #$1B'[?0c', {cursor visible, underline}
  92. #$1B'[?6c', {cursor visible, block}
  93. #$1B'[?1c', {cursor_invisible}
  94. nil, {enter_ca_mode}
  95. nil, {exit_ca_mode}
  96. nil, {exit_am_mode}
  97. nil); {ena_acs}
  98. term_codes_vt100:Ttermcodes=
  99. (#$0E, {enter_alt_charset_mode}
  100. #$0F, {exit_alt_charset_mode}
  101. #$1B#$5B#$48#$1B#$5B#$4A{#$24#$3C#$35#$30#$3E}, {clear_screen}
  102. #$1B#$5B#$48, {cursor_home}
  103. nil, {cursor_normal}
  104. nil, {cursor visible, underline}
  105. nil, {cursor visible, block}
  106. nil, {cursor_invisible}
  107. nil, {enter_ca_mode}
  108. nil, {exit_ca_mode}
  109. #$1B#$5B#$3F#$37#$6C, {exit_am_mode}
  110. #$1B#$28#$42#$1B#$29#$30); {ena_acs}
  111. term_codes_vt220:Ttermcodes=
  112. (#$1B#$28#$30{#$24#$3C#$32#$3E}, {enter_alt_charset_mode}
  113. #$1B#$28#$42{#$24#$3C#$34#$3E}, {exit_alt_charset_mode}
  114. #$1B#$5B#$48#$1B#$5B#$4A, {clear_screen}
  115. #$1B#$5B#$48, {cursor_home}
  116. nil, {cursor_normal}
  117. nil, {cursor visible, underline}
  118. nil, {cursor visible, block}
  119. nil, {cursor_invisible}
  120. nil, {enter_ca_mode}
  121. nil, {exit_ca_mode}
  122. #$1B#$5B#$3F#$37#$6C, {exit_am_mode}
  123. #$1B#$29#$30); {ena_acs}
  124. term_codes_xterm:Ttermcodes=
  125. (#$0E, {enter_alt_charset_mode}
  126. #$0F, {exit_alt_charset_mode}
  127. #$1B#$5B#$48#$1B#$5B#$32#$4A, {clear_screen}
  128. #$1B#$5B#$48, {cursor_home}
  129. #$1B#$5B#$3F#$31#$32#$6C#$1B#$5B#$3F#$32#$35#$68, {cursor_normal}
  130. #27'[?25h'#27'[4 q', {cursor visible, underline}
  131. #27'[?25h'#27'[2 q', {cursor visible, block}
  132. #$1B#$5B#$3F#$32#$35#$6C, {cursor_invisible}
  133. #$1B#$5B#$3F#$31#$30#$34#$39#$68, {enter_ca_mode}
  134. #$1B#$5B#$3F#$31#$30#$34#$39#$6C, {exit_ca_mode}
  135. #$1B#$5B#$3F#$37#$6C, {exit_am_mode}
  136. #$1B#$28#$42#$1B#$29#$30); {ena_acs}
  137. term_codes_beos:Ttermcodes=
  138. (nil,//#$0E, {enter_alt_charset_mode}
  139. nil,//#$0F, {exit_alt_charset_mode}
  140. #$1B#$5B#$48#$1B#$5B#$4A, {clear_screen}
  141. #$1B#$5B#$48, {cursor_home}
  142. #$1B'[?25h',// nil,//#$1B#$5B#$3F#$31#$32#$6C#$1B#$5B#$3F#$32#$35#$68, {cursor_normal}
  143. nil,//#$1B#$5B#$3F#$31#$32#$3B#$32#$35#$68, {cursor visible, underline}
  144. nil,//#$1B#$5B#$3F#$31#$32#$3B#$32#$35#$68, {cursor visible, block}
  145. #$1B'[?25l',//nil,//#$1B#$5B#$3F#$32#$35#$6C, {cursor_invisible}
  146. nil,//#$1B#$5B#$3F#$31#$30#$34#$39#$68, {enter_ca_mode}
  147. nil,//#$1B#$5B#$3F#$31#$30#$34#$39#$6C, {exit_ca_mode}
  148. nil,//#$1B#$5B#$3F#$37#$6C, {exit_am_mode}
  149. nil);//#$1B#$28#$42#$1B#$29#$30); {ena_acs}
  150. const terminal_names:array[0..11] of string[7]=(
  151. 'ansi',
  152. 'cons',
  153. 'eterm',
  154. 'gnome',
  155. 'konsole',
  156. 'linux',
  157. 'rxvt',
  158. 'screen',
  159. 'vt100',
  160. 'vt220',
  161. 'xterm',
  162. 'beterm');
  163. terminal_data:array[0..11] of Ptermcodes=(
  164. @term_codes_ansi,
  165. @term_codes_freebsd,
  166. @term_codes_xterm,
  167. @term_codes_xterm,
  168. @term_codes_xterm,
  169. @term_codes_linux,
  170. @term_codes_xterm,
  171. @term_codes_xterm,
  172. @term_codes_vt100,
  173. @term_codes_vt220,
  174. @term_codes_xterm,
  175. @term_codes_beos);
  176. var
  177. LastCursorType : byte;
  178. {$ifdef linux}
  179. TtyFd: Longint;
  180. {$endif linux}
  181. Console: Tconsole_type;
  182. cur_term_strings:Ptermcodes;
  183. {$ifdef logging}
  184. f: file;
  185. const
  186. logstart: shortstring = '';
  187. nl: AnsiChar = #10;
  188. logend: shortstring = #10#10;
  189. {$endif logging}
  190. {$ifdef cpui386}
  191. {$ASMMODE ATT}
  192. {$endif cpui386}
  193. const
  194. { can_delete_term : boolean = false;}
  195. ACSIn : shortstring = '';
  196. ACSOut : shortstring = '';
  197. in_ACS : boolean =false;
  198. TerminalSupportsHighIntensityColors: boolean = false;
  199. TerminalSupportsBold: boolean = true;
  200. {Contains all code pages that can be considered a normal vga font.
  201. Note: KOI8-R has line drawing characters in wrong place. Support
  202. can perhaps be added, for now we'll let it rest.}
  203. function is_vga_code_page(CP: TSystemCodePage): Boolean;
  204. begin
  205. case CP of
  206. 437,850,852,866:
  207. result:=true;
  208. else
  209. result:=false;
  210. end;
  211. end;
  212. function Unicode2DecSpecialGraphics(Ch: WideChar): AnsiChar;
  213. begin
  214. case Ch of
  215. #$25C6:
  216. Result := #$60;
  217. #$2592,#$2591,#$2593,#$2584,#$2580:
  218. Result := #$61;
  219. #$2409:
  220. Result := #$62;
  221. #$240C:
  222. Result := #$63;
  223. #$240D:
  224. Result := #$64;
  225. #$240A:
  226. Result := #$65;
  227. #$00B0:
  228. Result := #$66;
  229. #$00B1:
  230. Result := #$67;
  231. #$2424:
  232. Result := #$68;
  233. #$240B:
  234. Result := #$69;
  235. #$2518,#$255B,#$255C,#$255D:
  236. Result := #$6A;
  237. #$2510,#$2556,#$2555,#$2557:
  238. Result := #$6B;
  239. #$250C,#$2553,#$2552,#$2554:
  240. Result := #$6C;
  241. #$2514,#$2558,#$2559,#$255A:
  242. Result := #$6D;
  243. #$253C,#$256C,#$256B,#$256A:
  244. Result := #$6E;
  245. #$23BA:
  246. Result := #$6F;
  247. #$23BB:
  248. Result := #$70;
  249. #$2500,#$2550:
  250. Result := #$71;
  251. #$23BC:
  252. Result := #$72;
  253. #$23BD:
  254. Result := #$73;
  255. #$251C,#$255E,#$255F,#$2560:
  256. Result := #$74;
  257. #$2524,#$2561,#$2562,#$2563:
  258. Result := #$75;
  259. #$2534,#$2569,#$2567,#$2568:
  260. Result := #$76;
  261. #$252C,#$2566,#$2564,#$2565:
  262. Result := #$77;
  263. #$2502,#$2551:
  264. Result := #$78;
  265. #$2264:
  266. Result := #$79;
  267. #$2265:
  268. Result := #$7A;
  269. #$03A0:
  270. Result := #$7B;
  271. #$2260:
  272. Result := #$7C;
  273. #$00A3:
  274. Result := #$7D;
  275. #$00B7:
  276. Result := #$7E;
  277. else
  278. Result := #0;
  279. end;
  280. end;
  281. function convert_vga_to_acs(ch:AnsiChar):word;
  282. {Ch contains a character in the VGA character set (i.e. codepage 437).
  283. This routine tries to convert some VGA symbols as well as possible to the
  284. xterm alternate character set.
  285. Return type is word to allow expanding to UCS-2 characters in the
  286. future.}
  287. begin
  288. case ch of
  289. #18:
  290. convert_vga_to_acs:=word('|');
  291. #24, #30: {↑▲}
  292. convert_vga_to_acs:=word('^');
  293. #25, #31: {↓▼}
  294. convert_vga_to_acs:=word('v');
  295. #26, #16: {Never introduce a ctrl-Z ... →►}
  296. convert_vga_to_acs:=word('>');
  297. {#27,} #17: {←◄}
  298. convert_vga_to_acs:=word('<');
  299. #176, #177, #178: {░▒▓}
  300. convert_vga_to_acs:=$f800+word('a');
  301. #180, #181, #182, #185: {┤╡╢╣}
  302. convert_vga_to_acs:=$f800+word('u');
  303. #183, #184, #187, #191: {╖╕╗┐}
  304. convert_vga_to_acs:=$f800+word('k');
  305. #188, #189, #190, #217: {╝╜╛┘}
  306. convert_vga_to_acs:=$f800+word('j');
  307. #192, #200, #211, #212: {└╚╙╘}
  308. convert_vga_to_acs:=$f800+word('m');
  309. #193, #202, #207, #208: {┴╩╧╨}
  310. convert_vga_to_acs:=$f800+word('v');
  311. #194, #203, #209, #210: {┬╦╤╥}
  312. convert_vga_to_acs:=$f800+word('w');
  313. #195, #198, #199, #204: {├╞╟╠}
  314. convert_vga_to_acs:=$f800+word('t');
  315. #196, #205: {─═}
  316. convert_vga_to_acs:=$f800+word('q');
  317. #179, #186: {│║}
  318. convert_vga_to_acs:=$f800+word('x');
  319. #197, #206, #215, #216: {┼╬╫╪}
  320. convert_vga_to_acs:=$f800+word('n');
  321. #201, #213, #214, #218: {╔╒╓┌}
  322. convert_vga_to_acs:=$f800+word('l');
  323. #254: { ■ }
  324. convert_vga_to_acs:=word('*');
  325. { Shadows for Buttons }
  326. #220 { ▄ },
  327. #223: { ▀ }
  328. convert_vga_to_acs:=$f800+word('a');
  329. else
  330. convert_vga_to_acs:=word(ch);
  331. end;
  332. end;
  333. procedure SendEscapeSeqNdx(ndx:Ttermcode);
  334. var p:PAnsiChar;
  335. begin
  336. { Always true because of vt100 default.
  337. if not assigned(cur_term_Strings) then
  338. exit}{RunError(219)};
  339. p:=cur_term_strings^[ndx];
  340. if p<>nil then
  341. fpwrite(stdoutputhandle,p^,strlen(p));
  342. end;
  343. procedure SendEscapeSeq(const S: shortstring);
  344. begin
  345. fpWrite(stdoutputhandle, S[1], Length(S));
  346. end;
  347. function IntStr(l:longint):shortstring;
  348. begin
  349. Str(l,intstr);
  350. end;
  351. Function XY2Ansi(x,y,ox,oy:longint):shortstring;
  352. {
  353. Returns a string with the escape sequences to go to X,Y on the screen.
  354. Note that x, y, ox, oy are 1-based (i.e. top-left corner of the screen
  355. is (1, 1)), while SetCursorPos parameters and CursorX and CursorY
  356. are 0-based (top-left corner of the screen is (0, 0)).
  357. }
  358. var delta:longint;
  359. direction:AnsiChar;
  360. movement:string[32];
  361. begin
  362. if ((x=1) and (oy+1=y)) and (console<>ttyfreebsd) then
  363. begin
  364. XY2Ansi:=#13#10;
  365. exit;
  366. end;
  367. direction:='H';
  368. if y=oy then
  369. begin
  370. if x=ox then
  371. begin
  372. XY2Ansi:='';
  373. exit;
  374. end;
  375. if x=1 then
  376. begin
  377. XY2Ansi:=#13;
  378. exit;
  379. end;
  380. delta:=ox-x;
  381. direction:=AnsiChar(byte('C')+byte(x<=ox));
  382. end;
  383. if x=ox then
  384. begin
  385. delta:=oy-y;
  386. direction:=AnsiChar(byte('A')+byte(y>oy));
  387. end;
  388. if direction='H' then
  389. movement:=intstr(y)+';'+intstr(x)
  390. else
  391. movement:=intstr(abs(delta));
  392. xy2ansi:=#27'['+movement+direction;
  393. end;
  394. const ansitbl:array[0..7] of AnsiChar='04261537';
  395. function attr2ansi(Fg,Bg:byte;Attr:TEnhancedVideoAttributes;OFg,OBg:byte;OAttr:TEnhancedVideoAttributes):shortstring;
  396. const
  397. AttrOnOffStr: array [TEnhancedVideoAttribute, Boolean] of shortstring = (
  398. ('22;','1;'),
  399. ('22;','2;'),
  400. ('23;','3;'),
  401. ('24;','4;'),
  402. ('25;','5;'),
  403. ('25;','6;'),
  404. ('27;','7;'),
  405. ('28;','8;'),
  406. ('29;','9;'),
  407. ('24;','21;'));
  408. var
  409. tmpS: shortstring;
  410. A: TEnhancedVideoAttribute;
  411. begin
  412. attr2ansi:=#27'[';
  413. if Attr<>OAttr then
  414. begin
  415. { turn off old attributes first }
  416. for A := Low(TEnhancedVideoAttribute) to High(TEnhancedVideoAttribute) do
  417. if (not (A in Attr)) and (A in OAttr) then
  418. attr2ansi:=attr2ansi+AttrOnOffStr[A,False];
  419. { then, turn on new attributes }
  420. for A := Low(TEnhancedVideoAttribute) to High(TEnhancedVideoAttribute) do
  421. if (A in Attr) and (not (A in OAttr)) then
  422. attr2ansi:=attr2ansi+AttrOnOffStr[A,True];
  423. end;
  424. if (Fg > 15) or (Bg > 15) then
  425. begin
  426. if Fg<>OFg then
  427. begin
  428. if TerminalSupportsBold and (ofg and 8<>0) then
  429. attr2ansi:=attr2ansi+'22;';
  430. Str(Fg,tmpS);
  431. attr2ansi:=attr2ansi+'38;5;'+tmpS+';';
  432. end;
  433. if Bg<>OBg then
  434. begin
  435. Str(Bg,tmpS);
  436. attr2ansi:=attr2ansi+'48;5;'+tmpS+';';
  437. end;
  438. end
  439. else
  440. begin
  441. if TerminalSupportsBold then
  442. if fg and 8<>0 then
  443. begin
  444. {Enable bold if not yet on.}
  445. if ofg and 8=0 then
  446. attr2ansi:=attr2ansi+'1;';
  447. end
  448. else
  449. {Disable bold if on.}
  450. if ofg and 8<>0 then
  451. attr2ansi:=attr2ansi+'22;';
  452. if bg and 8<>0 then
  453. begin
  454. {Enable bold if not yet on.}
  455. if obg and 8=0 then
  456. attr2ansi:=attr2ansi+'5;';
  457. end
  458. else
  459. {Disable bold if on.}
  460. if obg and 8<>0 then
  461. attr2ansi:=attr2ansi+'25;';
  462. if TerminalSupportsHighIntensityColors then
  463. begin
  464. if fg and 15<>ofg and 15 then
  465. if fg and 8<>0 then
  466. attr2ansi:=attr2ansi+'9'+ansitbl[fg and 7]+';'
  467. else
  468. attr2ansi:=attr2ansi+'3'+ansitbl[fg and 7]+';';
  469. end
  470. else
  471. begin
  472. if fg and 7<>ofg and 7 then
  473. attr2ansi:=attr2ansi+'3'+ansitbl[fg and 7]+';';
  474. end;
  475. if bg and 7<>obg and 7 then
  476. attr2ansi:=attr2ansi+'4'+ansitbl[bg and 7]+';';
  477. end;
  478. if attr2ansi[length(attr2ansi)]=';' then
  479. attr2ansi[length(attr2ansi)]:='m'
  480. else
  481. attr2ansi:='';
  482. end;
  483. procedure UpdateTTY(Force:boolean);
  484. var
  485. outbuf : array[0..1023+255] of AnsiChar;
  486. chattr : tenhancedvideocell;
  487. skipped : boolean;
  488. outptr,
  489. spaces,
  490. eol,
  491. x,y,
  492. LastX,LastY : longint;
  493. SpaceFg, SpaceBg : byte;
  494. SpaceAttr: TEnhancedVideoAttributes;
  495. LastFg, LastBg : byte;
  496. LastAttr: TEnhancedVideoAttributes;
  497. LastLineWidth : Longint;
  498. p,pold : penhancedvideocell;
  499. LastCharWasDoubleWidth: Boolean;
  500. CurCharWidth: Integer;
  501. function transform(const hstr:UnicodeString):RawByteString;
  502. var
  503. DecSpecialGraphicsCharacter: AnsiChar;
  504. begin
  505. if external_codepage=CP_UTF8 then
  506. result:=Utf8Encode(hstr)
  507. else
  508. begin
  509. DecSpecialGraphicsCharacter:=#0;
  510. if (Length(hstr)=1) and (ACSIn<>'') and (ACSOut<>'') then
  511. DecSpecialGraphicsCharacter:=Unicode2DecSpecialGraphics(hstr[1]);
  512. if DecSpecialGraphicsCharacter<>#0 then
  513. begin
  514. result:=ACSIn+DecSpecialGraphicsCharacter+ACSOut;
  515. SetCodePage(result,external_codepage,False);
  516. end
  517. else
  518. begin
  519. result:=Utf8Encode(hstr);
  520. SetCodePage(result,external_codepage,True);
  521. if (result='?') and (hstr<>'?') then
  522. begin
  523. { Character is missing in the external codepage. }
  524. { Try some replacements. }
  525. if Length(hstr)=1 then
  526. begin
  527. case hstr[1] of
  528. #$2195:
  529. result:='|';
  530. #$2191,#$25B2:
  531. result:='^';
  532. #$2193,#$25BC:
  533. result:='v';
  534. #$2192,#$25BA:
  535. result:='>';
  536. #$2190,#$25C4:
  537. result:='<';
  538. #$25A0:
  539. result:='*';
  540. end;
  541. SetCodePage(result,external_codepage,False);
  542. end;
  543. end;
  544. end;
  545. end;
  546. end;
  547. procedure outdata(hstr:rawbytestring);
  548. begin
  549. If Length(HStr)>0 Then
  550. Begin
  551. while (eol>0) do
  552. begin
  553. outbuf[outptr]:=#13;
  554. outbuf[outptr+1]:=#10;
  555. inc(outptr,2);
  556. dec(eol);
  557. end;
  558. { if (convert=cv_vga_to_acs) and (ACSIn<>'') and (ACSOut<>'') then
  559. transform_using_acs(Hstr);}
  560. move(hstr[1],outbuf[outptr],length(hstr));
  561. inc(outptr,length(hstr));
  562. if outptr>=1024 then
  563. begin
  564. {$ifdef logging}
  565. blockwrite(f,logstart[1],length(logstart));
  566. blockwrite(f,nl,1);
  567. blockwrite(f,outptr,sizeof(outptr));
  568. blockwrite(f,nl,1);
  569. blockwrite(f,outbuf,outptr);
  570. blockwrite(f,nl,1);
  571. {$endif logging}
  572. fpWrite(stdoutputhandle,outbuf,outptr);
  573. outptr:=0;
  574. end;
  575. end;
  576. end;
  577. procedure OutClr(Fg,Bg:byte;Attr:TEnhancedVideoAttributes);
  578. begin
  579. if (Fg=LastFg) and (Bg=LastBg) and (Attr=LastAttr) then
  580. exit;
  581. OutData(Attr2Ansi(Fg,Bg,Attr,LastFg,LastBg,LastAttr));
  582. LastFg:=Fg;
  583. LastBg:=Bg;
  584. LastAttr:=Attr;
  585. end;
  586. procedure OutSpaces;
  587. begin
  588. if (Spaces=0) then
  589. exit;
  590. OutClr(SpaceFg,SpaceBg,SpaceAttr);
  591. OutData(Space(Spaces));
  592. LastX:=x;
  593. LastY:=y;
  594. Spaces:=0;
  595. end;
  596. (*
  597. function GetTermString(ndx:Ttermcode):shortstring;
  598. var
  599. P{,pdelay}: PAnsiChar;
  600. begin
  601. GetTermString:='';
  602. if not assigned(cur_term_Strings) then
  603. exit{RunError(219)};
  604. P:=cur_term_Strings^[Ndx];
  605. if assigned(p) then
  606. begin { Do not transmit the delays }
  607. { pdelay:=strpos(p,'$<');
  608. if assigned(pdelay) then
  609. pdelay^:=#0;}
  610. GetTermString:=StrPas(p);
  611. { if assigned(pdelay) then
  612. pdelay^:='$';}
  613. end;
  614. end;
  615. *)
  616. begin
  617. OutPtr:=0;
  618. Eol:=0;
  619. skipped:=true;
  620. p:=PEnhancedVideoCell(@EnhancedVideoBuf[0]);
  621. pold:=PEnhancedVideoCell(@OldEnhancedVideoBuf[0]);
  622. { init Attr, X,Y and set autowrap off }
  623. SendEscapeSeq(#27'[0;40;37m'#27'[?7l'{#27'[H'} );
  624. // 1.0.x: SendEscapeSeq(#27'[m'{#27'[H'});
  625. LastFg:=7;
  626. LastBg:=0;
  627. LastAttr:=[];
  628. LastX:=-1;
  629. LastY:=-1;
  630. for y:=1 to ScreenHeight do
  631. begin
  632. SpaceFg:=0;
  633. SpaceBg:=0;
  634. SpaceAttr:=[];
  635. Spaces:=0;
  636. LastLineWidth:=ScreenWidth;
  637. If (y=ScreenHeight) And (Console=ttyFreeBSD) {And :am: is on} Then
  638. LastLineWidth:=ScreenWidth-2;
  639. LastCharWasDoubleWidth:=False;
  640. for x:=1 to LastLineWidth do
  641. begin
  642. if LastCharWasDoubleWidth then
  643. LastCharWasDoubleWidth:=false
  644. else
  645. begin
  646. CurCharWidth := ExtendedGraphemeClusterDisplayWidth(p^.ExtendedGraphemeCluster);
  647. if (not force) and (p^=pold^) and
  648. ((CurCharWidth <= 1) or (x=LastLineWidth) or (p[1]=pold[1])) then
  649. begin
  650. if (Spaces>0) then
  651. OutSpaces;
  652. skipped:=true;
  653. if CurCharWidth = 2 then
  654. LastCharWasDoubleWidth:=true;
  655. end
  656. else
  657. begin
  658. if skipped then
  659. begin
  660. OutData(XY2Ansi(x,y,LastX,LastY));
  661. LastX:=x;
  662. LastY:=y;
  663. skipped:=false;
  664. end;
  665. chattr:=p^;
  666. { if chattr.ch in [#0,#255] then
  667. chattr.ch:=' ';}
  668. if chattr.ExtendedGraphemeCluster=' ' then
  669. begin
  670. if Spaces=0 then
  671. begin
  672. SpaceFg:=chattr.ForegroundColor;
  673. SpaceBg:=chattr.BackgroundColor;
  674. SpaceAttr:=chattr.EnhancedVideoAttributes;
  675. end;
  676. if (chattr.BackgroundColor=SpaceBg) and (chattr.EnhancedVideoAttributes=SpaceAttr) then
  677. chattr.ForegroundColor:=SpaceFg
  678. else
  679. begin
  680. OutSpaces;
  681. SpaceFg:=chattr.ForegroundColor;
  682. SpaceBg:=chattr.BackgroundColor;
  683. SpaceAttr:=chattr.EnhancedVideoAttributes;
  684. end;
  685. inc(Spaces);
  686. end
  687. else
  688. begin
  689. if (Spaces>0) then
  690. OutSpaces;
  691. { if ord(chattr.ch)<32 then
  692. begin
  693. Chattr.Attr:= $ff xor Chattr.Attr;
  694. ChAttr.ch:=chr(ord(chattr.ch)+ord('A')-1);
  695. end;}
  696. if (LastFg<>chattr.ForegroundColor) or (LastBg<>chattr.BackgroundColor) or (LastAttr<>chattr.EnhancedVideoAttributes) then
  697. OutClr(chattr.ForegroundColor,chattr.BackgroundColor,chattr.EnhancedVideoAttributes);
  698. OutData(transform(chattr.ExtendedGraphemeCluster));
  699. if CurCharWidth=2 then
  700. begin
  701. LastX:=x+2;
  702. LastCharWasDoubleWidth:=True;
  703. end
  704. else
  705. begin
  706. LastX:=x+1;
  707. LastCharWasDoubleWidth:=False;
  708. end;
  709. LastY:=y;
  710. end;
  711. //p^:=chattr;
  712. end;
  713. end;
  714. inc(p);
  715. inc(pold);
  716. end;
  717. if (Spaces>0) then
  718. OutSpaces;
  719. if force then
  720. inc(eol)
  721. else
  722. skipped:=true;
  723. end;
  724. eol:=0;
  725. {if am in capabilities? Then}
  726. if (Console=ttyFreeBSD) and (p^<>pold^) Then
  727. begin
  728. OutData(XY2Ansi(ScreenWidth,ScreenHeight,LastX,LastY));
  729. OutData(#8);
  730. {Output last AnsiChar}
  731. chattr:=p[1];
  732. if (LastFg<>chattr.ForegroundColor) or (LastBg<>chattr.BackgroundColor) or (LastAttr<>chattr.EnhancedVideoAttributes) then
  733. OutClr(chattr.ForegroundColor,chattr.BackgroundColor,chattr.EnhancedVideoAttributes);
  734. OutData(transform(chattr.ExtendedGraphemeCluster));
  735. inc(LastX);
  736. // OutData(XY2Ansi(ScreenWidth-1,ScreenHeight,LastX,LastY));
  737. // OutData(GetTermString(Insert_character));
  738. OutData(#8+#27+'[1@');
  739. chattr:=p^;
  740. if (LastFg<>chattr.ForegroundColor) or (LastBg<>chattr.BackgroundColor) or (LastAttr<>chattr.EnhancedVideoAttributes) then
  741. OutClr(chattr.ForegroundColor,chattr.BackgroundColor,chattr.EnhancedVideoAttributes);
  742. OutData(transform(chattr.ExtendedGraphemeCluster));
  743. inc(LastX);
  744. end;
  745. OutData(XY2Ansi(CursorX+1,CursorY+1,LastX,LastY));
  746. if in_ACS then
  747. begin
  748. {If the program crashes and the ACS is still enabled, the user's
  749. keyboard will output strange characters. Therefore we disable the
  750. acs after each screen update, so the risk that it happens is greatly
  751. reduced.}
  752. { SendEscapeSeqNdx(exit_alt_charset_mode);}
  753. outdata(acsout);
  754. in_acs:=false;
  755. end;
  756. {$ifdef logging}
  757. blockwrite(f,logstart[1],length(logstart));
  758. blockwrite(f,nl,1);
  759. blockwrite(f,outptr,sizeof(outptr));
  760. blockwrite(f,nl,1);
  761. blockwrite(f,outbuf,outptr);
  762. blockwrite(f,nl,1);
  763. {$endif logging}
  764. fpWrite(stdoutputhandle,outbuf,outptr);
  765. {turn autowrap on}
  766. // SendEscapeSeq(#27'[?7h');
  767. end;
  768. {$ifdef linux}
  769. procedure update_vcsa(force:boolean);
  770. const max_updates=64;
  771. label update,update_all,equal_loop,unequal_loop;
  772. var position,update_count,i:word;
  773. update_positions:array[0..max_updates-1] of word;
  774. update_lengths:array[0..max_updates-1] of word;
  775. begin
  776. if force then
  777. goto update_all;
  778. update_count:=0;
  779. i:=0;
  780. equal_loop:
  781. repeat
  782. if videobuf^[i]<>oldvideobuf^[i] then
  783. goto unequal_loop;
  784. inc(i);
  785. until i>videobufsize div 2;
  786. goto update;
  787. unequal_loop:
  788. if update_count>=max_updates then
  789. goto update_all;
  790. update_positions[update_count]:=i;
  791. update_lengths[update_count]:=0;
  792. inc(update_count);
  793. repeat
  794. if videobuf^[i]=oldvideobuf^[i] then
  795. goto equal_loop;
  796. inc(i);
  797. inc(update_lengths[update_count-1]);
  798. until i>videobufsize div 2;
  799. update:
  800. for i:=1 to update_count do
  801. begin
  802. position:=update_positions[i-1];
  803. fppwrite(ttyfd,videobuf^[position],update_lengths[i-1]*2,4+position*2);
  804. end;
  805. exit;
  806. update_all:
  807. fppwrite(ttyfd,videobuf^,videobufsize,4);
  808. end;
  809. {$endif}
  810. var
  811. preInitVideoTio, postInitVideoTio: {$IFDEF FPC_DOTTEDUNITS}UnixApi.{$ENDIF}TermIo.termios;
  812. inputRaw, outputRaw: boolean;
  813. procedure saveRawSettings(const tio: {$IFDEF FPC_DOTTEDUNITS}UnixApi.{$ENDIF}TermIo.termios);
  814. begin
  815. with tio do
  816. begin
  817. inputRaw :=
  818. ((c_iflag and (IGNBRK or BRKINT or PARMRK or ISTRIP or
  819. INLCR or IGNCR or ICRNL or IXON)) = 0) and
  820. ((c_lflag and (ECHO or ECHONL or ICANON or ISIG or IEXTEN)) = 0);
  821. outPutRaw :=
  822. ((c_oflag and OPOST) = 0) and
  823. ((c_cflag and (CSIZE or PARENB)) = 0) and
  824. ((c_cflag and CS8) <> 0);
  825. end;
  826. end;
  827. procedure restoreRawSettings(tio: {$IFDEF FPC_DOTTEDUNITS}UnixApi.{$ENDIF}TermIo.termios);
  828. begin
  829. with tio do
  830. begin
  831. if inputRaw then
  832. begin
  833. c_iflag := c_iflag and (not (IGNBRK or BRKINT or PARMRK or ISTRIP or
  834. INLCR or IGNCR or ICRNL or IXON));
  835. c_lflag := c_lflag and
  836. (not (ECHO or ECHONL or ICANON or ISIG or IEXTEN));
  837. c_cc[VMIN]:=1;
  838. c_cc[VTIME]:=0;
  839. end;
  840. if outPutRaw then
  841. begin
  842. c_oflag := c_oflag and not(OPOST);
  843. c_cflag := c_cflag and not(CSIZE or PARENB) or CS8;
  844. end;
  845. end;
  846. TCSetAttr(1,TCSANOW,tio);
  847. end;
  848. procedure decide_codepages;
  849. var s:shortstring;
  850. begin
  851. if is_vga_code_page(external_codepage) then
  852. begin
  853. {Possible override...}
  854. s:=upcase(fpgetenv('CONSOLEFONT_CP'));
  855. if s='CP437' then
  856. external_codepage:=437
  857. else if s='CP850' then
  858. external_codepage:=850;
  859. end;
  860. {A non-vcsa Linux console can display most control characters, but not all.}
  861. case external_codepage of
  862. CP_ISO01: {West Europe}
  863. CurrentLegacy2EnhancedTranslationCodePage:=850;
  864. CP_ISO02: {East Europe}
  865. CurrentLegacy2EnhancedTranslationCodePage:=852;
  866. CP_ISO05: {Cyrillic}
  867. CurrentLegacy2EnhancedTranslationCodePage:=866;
  868. CP_UTF8:
  869. CurrentLegacy2EnhancedTranslationCodePage:=437;
  870. else
  871. if is_vga_code_page(external_codepage) then
  872. CurrentLegacy2EnhancedTranslationCodePage:=external_codepage
  873. else
  874. {We don't know how to convert to the external codepage. Use codepage
  875. 437 in the hope that the actual font has similarity to codepage 437.}
  876. CurrentLegacy2EnhancedTranslationCodePage:=437;
  877. end;
  878. end;
  879. procedure prepareInitVideo;
  880. begin
  881. TCGetAttr(1,preInitVideoTio);
  882. saveRawSettings(preInitVideoTio);
  883. end;
  884. procedure videoInitDone;
  885. begin
  886. TCGetAttr(1,postInitVideoTio);
  887. restoreRawSettings(postInitVideoTio);
  888. end;
  889. procedure prepareDoneVideo;
  890. var
  891. tio: {$IFDEF FPC_DOTTEDUNITS}UnixApi.{$ENDIF}TermIo.termios;
  892. begin
  893. TCGetAttr(1,tio);
  894. saveRawSettings(tio);
  895. TCSetAttr(1,TCSANOW,postInitVideoTio);
  896. end;
  897. procedure doneVideoDone;
  898. begin
  899. restoreRawSettings(preInitVideoTio);
  900. end;
  901. procedure SysInitVideo;
  902. var
  903. {$ifdef linux}
  904. FName: shortstring;
  905. {$endif linux}
  906. WS: packed record
  907. ws_row, ws_col, ws_xpixel, ws_ypixel: Word;
  908. end;
  909. { Err: Longint;}
  910. { prev_term : TerminalCommon_ptr1;}
  911. term:shortstring;
  912. i:word;
  913. {$ifdef Linux}
  914. s:string[15];
  915. {$endif}
  916. {$ifdef freebsd}
  917. ThisTTY: String[30];
  918. {$endif}
  919. const font_vga:array[0..11] of AnsiChar=#15#27'%@'#27'(U'#27'[3h';
  920. font_lat1:array[0..5] of AnsiChar=#27'%@'#27'(B';
  921. begin
  922. { check for tty }
  923. if (IsATTY(stdinputhandle)=1) then
  924. begin
  925. { save current terminal characteristics and remove rawness }
  926. prepareInitVideo;
  927. {$ifdef linux}
  928. { running on a tty, find out whether locally or remotely }
  929. TTyfd:=-1;
  930. {$endif linux}
  931. Console:=TTyNetwork; {Default: Network or other vtxxx tty}
  932. cur_term_strings:=@term_codes_vt100; {Default: vt100}
  933. external_codepage:=CP_ISO01; {Default: ISO-8859-1}
  934. if UTF8Enabled then
  935. external_codepage:=CP_UTF8;
  936. {$ifdef linux}
  937. if (vcs_device>=0) and (external_codepage<>CP_UTF8) then
  938. begin
  939. str(vcs_device,s);
  940. fname:='/dev/vcsa'+s;
  941. { open console, $1b6=rw-rw-rw- }
  942. ttyfd:=fpopen(fname,$1b6,O_RDWR);
  943. if ttyfd<>-1 then
  944. begin
  945. console:=ttylinux;
  946. external_codepage:=437; {VCSA defaults to codepage 437.}
  947. end
  948. else
  949. if try_grab_vcsa then
  950. begin
  951. ttyfd:=fpopen(fname,$1b6,O_RDWR);
  952. if ttyfd<>-1 then
  953. begin
  954. console:=ttylinux;
  955. external_codepage:=437; {VCSA defaults to codepage 437.}
  956. end;
  957. end;
  958. end;
  959. {$endif}
  960. {$ifdef freebsd}
  961. ThisTTY:=TTYName(stdinputhandle);
  962. if copy(ThisTTY, 1, 9) = '/dev/ttyv' then {FreeBSD has these}
  963. begin
  964. { check for (Free?)BSD native}
  965. if (ThisTTY[10]>='0') and (ThisTTY[10]<='9') Then
  966. Console:=ttyFreeBSD; {TTYFd ?}
  967. end;
  968. {$endif}
  969. term:=fpgetenv('TERM');
  970. for i:=low(terminal_names) to high(terminal_names) do
  971. if copy(term,1,length(terminal_names[i]))=terminal_names[i] then
  972. cur_term_strings:=terminal_data[i];
  973. if cur_term_strings=@term_codes_xterm then
  974. begin
  975. {$ifdef haiku}
  976. TerminalSupportsBold := true;
  977. TerminalSupportsHighIntensityColors := false;
  978. {$else}
  979. TerminalSupportsBold := false;
  980. TerminalSupportsHighIntensityColors := true;
  981. {$endif}
  982. end
  983. else
  984. begin
  985. TerminalSupportsBold := true;
  986. TerminalSupportsHighIntensityColors := false;
  987. end;
  988. if cur_term_strings=@term_codes_beos then
  989. begin
  990. TerminalSupportsBold := false;
  991. TerminalSupportsHighIntensityColors := false;
  992. end;
  993. if cur_term_strings=@term_codes_freebsd then
  994. console:=ttyFreeBSD;
  995. {$ifdef linux}
  996. if (console<>ttylinux) then
  997. begin
  998. {$endif}
  999. if cur_term_strings=@term_codes_linux then
  1000. begin
  1001. if external_codepage<>CP_UTF8 then
  1002. begin
  1003. {Enable the VGA character set (codepage 437,850,....)}
  1004. fpwrite(stdoutputhandle,font_vga,sizeof(font_vga));
  1005. external_codepage:=437; {Now default to codepage 437.}
  1006. end;
  1007. end
  1008. else
  1009. begin
  1010. if external_codepage<>CP_UTF8 then
  1011. begin
  1012. {No VGA font :( }
  1013. fpwrite(stdoutputhandle,font_lat1,sizeof(font_lat1));
  1014. end;
  1015. { running on a remote terminal, no error with /dev/vcsa }
  1016. end;
  1017. {$ifdef linux}
  1018. end;
  1019. {$endif}
  1020. fpioctl(stdinputhandle, TIOCGWINSZ, @WS);
  1021. if WS.ws_Col=0 then
  1022. WS.ws_Col:=80;
  1023. if WS.ws_Row=0 then
  1024. WS.ws_Row:=25;
  1025. ScreenWidth:=WS.ws_Col;
  1026. { TDrawBuffer only has FVMaxWidth elements
  1027. larger values lead to crashes }
  1028. if ScreenWidth> FVMaxWidth then
  1029. ScreenWidth:=FVMaxWidth;
  1030. ScreenHeight:=WS.ws_Row;
  1031. CursorX:=0;
  1032. CursorY:=0;
  1033. LastCursorType:=$ff;
  1034. ScreenColor:=True;
  1035. { Start with a clear screen }
  1036. {$ifdef linux}
  1037. if Console<>ttylinux then
  1038. begin
  1039. {$endif}
  1040. SendEscapeSeqNdx(enter_ca_mode);
  1041. SendEscapeSeqNdx(cursor_home);
  1042. SendEscapeSeqNdx(cursor_normal);
  1043. SendEscapeSeqNdx(cursor_visible_underline);
  1044. SetCursorType(crUnderLine);
  1045. If Console=ttyFreeBSD Then
  1046. SendEscapeSeqNdx(exit_am_mode);
  1047. {$ifdef linux}
  1048. end;
  1049. {$endif}
  1050. { Always true because of vt100 default...
  1051. if assigned(cur_term_Strings) then
  1052. begin}
  1053. ACSIn:=StrPas(cur_term_strings^[enter_alt_charset_mode]);
  1054. ACSOut:=StrPas(cur_term_strings^[exit_alt_charset_mode]);
  1055. if (ACSIn<>'') and (ACSOut<>'') then
  1056. SendEscapeSeqNdx(ena_acs);
  1057. (* If fpGetEnv('TERM')='xterm' then
  1058. convert:=cv_vga_to_acs; {use of acs for xterm is ok}*)
  1059. { end
  1060. else
  1061. begin
  1062. ACSIn:='';
  1063. ACSOut:='';
  1064. end;}
  1065. {$ifdef logging}
  1066. assign(f,'video.log');
  1067. rewrite(f,1);
  1068. {$endif logging}
  1069. { save new terminal characteristics and possible restore rawness }
  1070. videoInitDone;
  1071. decide_codepages;
  1072. end
  1073. else
  1074. ErrorCode:=errVioInit; { not a TTY }
  1075. end;
  1076. procedure SysDoneVideo;
  1077. var font_custom:array[0..2] of AnsiChar=#27'(K';
  1078. begin
  1079. prepareDoneVideo;
  1080. SetCursorType(crUnderLine);
  1081. {$ifdef linux}
  1082. if Console=ttylinux then
  1083. SetCursorPos(0,0)
  1084. else
  1085. begin
  1086. {$endif}
  1087. SendEscapeSeqNdx(cursor_home);
  1088. SendEscapeSeqNdx(cursor_normal);
  1089. SendEscapeSeqNdx(cursor_visible_underline);
  1090. SendEscapeSeq(#27'[H');
  1091. SendEscapeSeqNdx(exit_ca_mode);
  1092. if cur_term_strings=@term_codes_linux then
  1093. begin
  1094. {Executed in case ttylinux is false (i.e. no vcsa), but
  1095. TERM=linux.}
  1096. { if we're in utf8 mode, we didn't change the font, so
  1097. no need to restore anything }
  1098. if external_codepage<>CP_UTF8 then
  1099. begin
  1100. {Enable the character set set through setfont}
  1101. fpwrite(stdoutputhandle,font_custom,3);
  1102. end;
  1103. end;
  1104. {$ifdef linux}
  1105. end;
  1106. {$endif}
  1107. ACSIn:='';
  1108. ACSOut:='';
  1109. doneVideoDone;
  1110. {$ifdef logging}
  1111. close(f);
  1112. {$endif logging}
  1113. end;
  1114. procedure SysClearScreen;
  1115. begin
  1116. {$ifdef linux}
  1117. if Console=ttylinux then
  1118. UpdateScreen(true)
  1119. else
  1120. begin
  1121. {$endif}
  1122. SendEscapeSeq(#27'[0m');
  1123. SendEscapeSeqNdx(clear_screen);
  1124. {$ifdef linux}
  1125. end;
  1126. {$endif}
  1127. end;
  1128. procedure SysUpdateScreen(Force: Boolean);
  1129. var
  1130. I: Integer;
  1131. begin
  1132. {$ifdef linux}
  1133. if console=ttylinux then
  1134. update_vcsa(force)
  1135. else
  1136. {$endif}
  1137. updateTTY(force);
  1138. for I := Low(EnhancedVideoBuf) to High(EnhancedVideoBuf) do
  1139. OldEnhancedVideoBuf[I] := EnhancedVideoBuf[I];
  1140. end;
  1141. function SysGetCapabilities: Word;
  1142. begin
  1143. { about cpColor... we should check the terminfo database... }
  1144. SysGetCapabilities:=cpUnderLine + cpBlink + cpColor;
  1145. end;
  1146. procedure SysSetCursorPos(NewCursorX, NewCursorY: Word);
  1147. {$ifdef linux}
  1148. var
  1149. Pos : array [1..2] of Byte;
  1150. {$endif linux}
  1151. begin
  1152. if (CursorX=NewCursorX) and (CursorY=NewCursorY) then
  1153. exit;
  1154. {$ifdef linux}
  1155. if Console=ttylinux then
  1156. begin
  1157. Pos[1]:=NewCursorX;
  1158. Pos[2]:=NewCursorY;
  1159. fppwrite(ttyfd,pos,2,2);
  1160. end
  1161. else
  1162. {$endif}
  1163. { newcursorx,y and CursorX,Y are 0 based ! }
  1164. SendEscapeSeq(XY2Ansi(NewCursorX+1,NewCursorY+1,CursorX+1,CursorY+1));
  1165. CursorX:=NewCursorX;
  1166. CursorY:=NewCursorY;
  1167. end;
  1168. function SysGetCursorType: Word;
  1169. begin
  1170. SysGetCursorType:=LastCursorType;
  1171. end;
  1172. procedure SysSetCursorType(NewType: Word);
  1173. begin
  1174. If LastCursorType=NewType then
  1175. exit;
  1176. LastCursorType:=NewType;
  1177. case NewType of
  1178. crBlock:
  1179. SendEscapeSeqNdx(cursor_visible_block);
  1180. crUnderLine:
  1181. SendEscapeSeqNdx(cursor_visible_underline);
  1182. crHidden:
  1183. SendEscapeSeqNdx(cursor_invisible);
  1184. else
  1185. SendEscapeSeqNdx(cursor_normal);
  1186. end;
  1187. end;
  1188. function SysSetVideoMode(const mode:Tvideomode):boolean;
  1189. var winsize:Twinsize;
  1190. begin
  1191. {Due to xterm resize this procedure might get called with the new xterm
  1192. size. Approve the video mode change if the new size equals that of
  1193. the terminal window size.}
  1194. SysSetVideoMode:=false;
  1195. fpioctl(stdinputhandle,TIOCGWINSZ,@winsize);
  1196. if (mode.row=winsize.ws_row) and
  1197. (mode.col=winsize.ws_col) then
  1198. begin
  1199. screenwidth:=mode.col;
  1200. screenheight:=mode.row;
  1201. screencolor:=true;
  1202. SysSetVideoMode:=true;
  1203. end;
  1204. end;
  1205. Const
  1206. SysVideoDriver : TVideoDriver = (
  1207. InitDriver : nil;
  1208. InitEnhancedDriver: @SysInitVideo;
  1209. DoneDriver : @SysDoneVideo;
  1210. UpdateScreen : @SysUpdateScreen;
  1211. UpdateScreenArea : Nil;
  1212. ClearScreen : @SysClearScreen;
  1213. SetVideoMode : @SysSetVideoMode;
  1214. GetVideoModeCount : Nil;
  1215. GetVideoModeData : Nil;
  1216. SetCursorPos : @SysSetCursorPos;
  1217. GetCursorType : @SysGetCursorType;
  1218. SetCursorType : @SysSetCursorType;
  1219. GetCapabilities : @SysGetCapabilities;
  1220. GetActiveCodePage : Nil;
  1221. ActivateCodePage : Nil;
  1222. GetSupportedCodePageCount : Nil;
  1223. GetSupportedCodePage : Nil;
  1224. );
  1225. initialization
  1226. SetVideoDriver(SysVideoDriver);
  1227. end.