video.pp 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522
  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. var SpaceLen : longint;
  588. begin
  589. if (Spaces=0) then
  590. exit;
  591. OutClr(SpaceFg,SpaceBg,SpaceAttr);
  592. repeat
  593. SpaceLen:=Spaces;
  594. if SpaceLen > 200 then SpaceLen:=200; {have to fit in ShortString}
  595. OutData(Space(SpaceLen));
  596. Spaces:=Spaces-SpaceLen;
  597. until Spaces = 0;
  598. LastX:=x;
  599. LastY:=y;
  600. Spaces:=0;
  601. end;
  602. (*
  603. function GetTermString(ndx:Ttermcode):shortstring;
  604. var
  605. P{,pdelay}: PAnsiChar;
  606. begin
  607. GetTermString:='';
  608. if not assigned(cur_term_Strings) then
  609. exit{RunError(219)};
  610. P:=cur_term_Strings^[Ndx];
  611. if assigned(p) then
  612. begin { Do not transmit the delays }
  613. { pdelay:=strpos(p,'$<');
  614. if assigned(pdelay) then
  615. pdelay^:=#0;}
  616. GetTermString:=StrPas(p);
  617. { if assigned(pdelay) then
  618. pdelay^:='$';}
  619. end;
  620. end;
  621. *)
  622. begin
  623. OutPtr:=0;
  624. Eol:=0;
  625. skipped:=true;
  626. p:=PEnhancedVideoCell(@EnhancedVideoBuf[0]);
  627. pold:=PEnhancedVideoCell(@OldEnhancedVideoBuf[0]);
  628. { init Attr, X,Y and set autowrap off }
  629. SendEscapeSeq(#27'[0;40;37m'#27'[?7l'{#27'[H'} );
  630. // 1.0.x: SendEscapeSeq(#27'[m'{#27'[H'});
  631. LastFg:=7;
  632. LastBg:=0;
  633. LastAttr:=[];
  634. LastX:=-1;
  635. LastY:=-1;
  636. for y:=1 to ScreenHeight do
  637. begin
  638. SpaceFg:=0;
  639. SpaceBg:=0;
  640. SpaceAttr:=[];
  641. Spaces:=0;
  642. LastLineWidth:=ScreenWidth;
  643. If (y=ScreenHeight) And (Console=ttyFreeBSD) {And :am: is on} Then
  644. LastLineWidth:=ScreenWidth-2;
  645. LastCharWasDoubleWidth:=False;
  646. for x:=1 to LastLineWidth do
  647. begin
  648. if LastCharWasDoubleWidth then
  649. LastCharWasDoubleWidth:=false
  650. else
  651. begin
  652. CurCharWidth := ExtendedGraphemeClusterDisplayWidth(p^.ExtendedGraphemeCluster);
  653. if (not force) and (p^=pold^) and
  654. ((CurCharWidth <= 1) or (x=LastLineWidth) or (p[1]=pold[1])) then
  655. begin
  656. if (Spaces>0) then
  657. OutSpaces;
  658. skipped:=true;
  659. if CurCharWidth = 2 then
  660. LastCharWasDoubleWidth:=true;
  661. end
  662. else
  663. begin
  664. if skipped then
  665. begin
  666. OutData(XY2Ansi(x,y,LastX,LastY));
  667. LastX:=x;
  668. LastY:=y;
  669. skipped:=false;
  670. end;
  671. chattr:=p^;
  672. { if chattr.ch in [#0,#255] then
  673. chattr.ch:=' ';}
  674. if chattr.ExtendedGraphemeCluster=' ' then
  675. begin
  676. if Spaces=0 then
  677. begin
  678. SpaceFg:=chattr.ForegroundColor;
  679. SpaceBg:=chattr.BackgroundColor;
  680. SpaceAttr:=chattr.EnhancedVideoAttributes;
  681. end;
  682. if (chattr.BackgroundColor=SpaceBg) and (chattr.EnhancedVideoAttributes=SpaceAttr) then
  683. chattr.ForegroundColor:=SpaceFg
  684. else
  685. begin
  686. OutSpaces;
  687. SpaceFg:=chattr.ForegroundColor;
  688. SpaceBg:=chattr.BackgroundColor;
  689. SpaceAttr:=chattr.EnhancedVideoAttributes;
  690. end;
  691. inc(Spaces);
  692. end
  693. else
  694. begin
  695. if (Spaces>0) then
  696. OutSpaces;
  697. { if ord(chattr.ch)<32 then
  698. begin
  699. Chattr.Attr:= $ff xor Chattr.Attr;
  700. ChAttr.ch:=chr(ord(chattr.ch)+ord('A')-1);
  701. end;}
  702. if (LastFg<>chattr.ForegroundColor) or (LastBg<>chattr.BackgroundColor) or (LastAttr<>chattr.EnhancedVideoAttributes) then
  703. OutClr(chattr.ForegroundColor,chattr.BackgroundColor,chattr.EnhancedVideoAttributes);
  704. OutData(transform(chattr.ExtendedGraphemeCluster));
  705. if CurCharWidth=2 then
  706. begin
  707. LastX:=x+2;
  708. LastCharWasDoubleWidth:=True;
  709. end
  710. else
  711. begin
  712. LastX:=x+1;
  713. LastCharWasDoubleWidth:=False;
  714. end;
  715. LastY:=y;
  716. end;
  717. //p^:=chattr;
  718. end;
  719. end;
  720. inc(p);
  721. inc(pold);
  722. end;
  723. if (Spaces>0) then
  724. OutSpaces;
  725. if force then
  726. inc(eol)
  727. else
  728. skipped:=true;
  729. end;
  730. eol:=0;
  731. {if am in capabilities? Then}
  732. if (Console=ttyFreeBSD) and (p^<>pold^) Then
  733. begin
  734. OutData(XY2Ansi(ScreenWidth,ScreenHeight,LastX,LastY));
  735. OutData(#8);
  736. {Output last AnsiChar}
  737. chattr:=p[1];
  738. if (LastFg<>chattr.ForegroundColor) or (LastBg<>chattr.BackgroundColor) or (LastAttr<>chattr.EnhancedVideoAttributes) then
  739. OutClr(chattr.ForegroundColor,chattr.BackgroundColor,chattr.EnhancedVideoAttributes);
  740. OutData(transform(chattr.ExtendedGraphemeCluster));
  741. inc(LastX);
  742. // OutData(XY2Ansi(ScreenWidth-1,ScreenHeight,LastX,LastY));
  743. // OutData(GetTermString(Insert_character));
  744. OutData(#8+#27+'[1@');
  745. chattr:=p^;
  746. if (LastFg<>chattr.ForegroundColor) or (LastBg<>chattr.BackgroundColor) or (LastAttr<>chattr.EnhancedVideoAttributes) then
  747. OutClr(chattr.ForegroundColor,chattr.BackgroundColor,chattr.EnhancedVideoAttributes);
  748. OutData(transform(chattr.ExtendedGraphemeCluster));
  749. inc(LastX);
  750. end;
  751. OutData(XY2Ansi(CursorX+1,CursorY+1,LastX,LastY));
  752. if in_ACS then
  753. begin
  754. {If the program crashes and the ACS is still enabled, the user's
  755. keyboard will output strange characters. Therefore we disable the
  756. acs after each screen update, so the risk that it happens is greatly
  757. reduced.}
  758. { SendEscapeSeqNdx(exit_alt_charset_mode);}
  759. outdata(acsout);
  760. in_acs:=false;
  761. end;
  762. {$ifdef logging}
  763. blockwrite(f,logstart[1],length(logstart));
  764. blockwrite(f,nl,1);
  765. blockwrite(f,outptr,sizeof(outptr));
  766. blockwrite(f,nl,1);
  767. blockwrite(f,outbuf,outptr);
  768. blockwrite(f,nl,1);
  769. {$endif logging}
  770. fpWrite(stdoutputhandle,outbuf,outptr);
  771. {turn autowrap on}
  772. // SendEscapeSeq(#27'[?7h');
  773. end;
  774. {$ifdef linux}
  775. procedure update_vcsa(force:boolean);
  776. const max_updates=64;
  777. label update,update_all,equal_loop,unequal_loop;
  778. var position,update_count,i:word;
  779. update_positions:array[0..max_updates-1] of word;
  780. update_lengths:array[0..max_updates-1] of word;
  781. begin
  782. if force then
  783. goto update_all;
  784. update_count:=0;
  785. i:=0;
  786. equal_loop:
  787. repeat
  788. if videobuf^[i]<>oldvideobuf^[i] then
  789. goto unequal_loop;
  790. inc(i);
  791. until i>videobufsize div 2;
  792. goto update;
  793. unequal_loop:
  794. if update_count>=max_updates then
  795. goto update_all;
  796. update_positions[update_count]:=i;
  797. update_lengths[update_count]:=0;
  798. inc(update_count);
  799. repeat
  800. if videobuf^[i]=oldvideobuf^[i] then
  801. goto equal_loop;
  802. inc(i);
  803. inc(update_lengths[update_count-1]);
  804. until i>videobufsize div 2;
  805. update:
  806. for i:=1 to update_count do
  807. begin
  808. position:=update_positions[i-1];
  809. fppwrite(ttyfd,videobuf^[position],update_lengths[i-1]*2,4+position*2);
  810. end;
  811. exit;
  812. update_all:
  813. fppwrite(ttyfd,videobuf^,videobufsize,4);
  814. end;
  815. {$endif}
  816. var
  817. preInitVideoTio, postInitVideoTio: {$IFDEF FPC_DOTTEDUNITS}UnixApi.{$ENDIF}TermIo.termios;
  818. inputRaw, outputRaw: boolean;
  819. procedure saveRawSettings(const tio: {$IFDEF FPC_DOTTEDUNITS}UnixApi.{$ENDIF}TermIo.termios);
  820. begin
  821. with tio do
  822. begin
  823. inputRaw :=
  824. ((c_iflag and (IGNBRK or BRKINT or PARMRK or ISTRIP or
  825. INLCR or IGNCR or ICRNL or IXON)) = 0) and
  826. ((c_lflag and (ECHO or ECHONL or ICANON or ISIG or IEXTEN)) = 0);
  827. outPutRaw :=
  828. ((c_oflag and OPOST) = 0) and
  829. ((c_cflag and (CSIZE or PARENB)) = 0) and
  830. ((c_cflag and CS8) <> 0);
  831. end;
  832. end;
  833. procedure restoreRawSettings(tio: {$IFDEF FPC_DOTTEDUNITS}UnixApi.{$ENDIF}TermIo.termios);
  834. begin
  835. with tio do
  836. begin
  837. if inputRaw then
  838. begin
  839. c_iflag := c_iflag and (not (IGNBRK or BRKINT or PARMRK or ISTRIP or
  840. INLCR or IGNCR or ICRNL or IXON));
  841. c_lflag := c_lflag and
  842. (not (ECHO or ECHONL or ICANON or ISIG or IEXTEN));
  843. c_cc[VMIN]:=1;
  844. c_cc[VTIME]:=0;
  845. end;
  846. if outPutRaw then
  847. begin
  848. c_oflag := c_oflag and not(OPOST);
  849. c_cflag := c_cflag and not(CSIZE or PARENB) or CS8;
  850. end;
  851. end;
  852. TCSetAttr(1,TCSANOW,tio);
  853. end;
  854. function DeduceOemCodePageFromLocale: TSystemCodePage;
  855. var
  856. lc: PAnsiChar;
  857. lc_str: AnsiString;
  858. function IsLocaleMatches(const current, wanted: AnsiString): boolean;
  859. var
  860. wanted_len: integer;
  861. begin
  862. wanted_len := length(wanted);
  863. if length(current) < wanted_len then
  864. begin
  865. IsLocaleMatches:=false;
  866. exit;
  867. end;
  868. if StrLComp(PAnsiChar(current), PAnsiChar(wanted), wanted_len) <> 0 then
  869. begin
  870. IsLocaleMatches:=false;
  871. exit;
  872. end;
  873. if length(current) = wanted_len then
  874. IsLocaleMatches:=true
  875. else
  876. IsLocaleMatches:=(current[wanted_len + 1] = '.');
  877. end;
  878. begin
  879. DeduceOemCodePageFromLocale := 437;
  880. lc := fpgetenv('LANG');
  881. if lc = nil then
  882. exit;
  883. lc_str := lc;
  884. if IsLocaleMatches(lc_str, 'af_ZA') then DeduceOemCodePageFromLocale := 850
  885. else if IsLocaleMatches(lc_str, 'ar_SA') then DeduceOemCodePageFromLocale := 720
  886. else if IsLocaleMatches(lc_str, 'ar_LB') then DeduceOemCodePageFromLocale := 720
  887. else if IsLocaleMatches(lc_str, 'ar_EG') then DeduceOemCodePageFromLocale := 720
  888. else if IsLocaleMatches(lc_str, 'ar_DZ') then DeduceOemCodePageFromLocale := 720
  889. else if IsLocaleMatches(lc_str, 'ar_BH') then DeduceOemCodePageFromLocale := 720
  890. else if IsLocaleMatches(lc_str, 'ar_IQ') then DeduceOemCodePageFromLocale := 720
  891. else if IsLocaleMatches(lc_str, 'ar_JO') then DeduceOemCodePageFromLocale := 720
  892. else if IsLocaleMatches(lc_str, 'ar_KW') then DeduceOemCodePageFromLocale := 720
  893. else if IsLocaleMatches(lc_str, 'ar_LY') then DeduceOemCodePageFromLocale := 720
  894. else if IsLocaleMatches(lc_str, 'ar_MA') then DeduceOemCodePageFromLocale := 720
  895. else if IsLocaleMatches(lc_str, 'ar_OM') then DeduceOemCodePageFromLocale := 720
  896. else if IsLocaleMatches(lc_str, 'ar_QA') then DeduceOemCodePageFromLocale := 720
  897. else if IsLocaleMatches(lc_str, 'ar_SY') then DeduceOemCodePageFromLocale := 720
  898. else if IsLocaleMatches(lc_str, 'ar_TN') then DeduceOemCodePageFromLocale := 720
  899. else if IsLocaleMatches(lc_str, 'ar_AE') then DeduceOemCodePageFromLocale := 720
  900. else if IsLocaleMatches(lc_str, 'ar_YE') then DeduceOemCodePageFromLocale := 720
  901. else if IsLocaleMatches(lc_str, 'ast_ES') then DeduceOemCodePageFromLocale := 850
  902. else if IsLocaleMatches(lc_str, 'az_AZ') then DeduceOemCodePageFromLocale := 866
  903. else if IsLocaleMatches(lc_str, 'be_BY') then DeduceOemCodePageFromLocale := 866
  904. else if IsLocaleMatches(lc_str, 'bg_BG') then DeduceOemCodePageFromLocale := 866
  905. else if IsLocaleMatches(lc_str, 'br_FR') then DeduceOemCodePageFromLocale := 850
  906. else if IsLocaleMatches(lc_str, 'ca_ES') then DeduceOemCodePageFromLocale := 850
  907. else if IsLocaleMatches(lc_str, 'zh_CN') then DeduceOemCodePageFromLocale := 936
  908. else if IsLocaleMatches(lc_str, 'zh_TW') then DeduceOemCodePageFromLocale := 950
  909. else if IsLocaleMatches(lc_str, 'kw_GB') then DeduceOemCodePageFromLocale := 850
  910. else if IsLocaleMatches(lc_str, 'cs_CZ') then DeduceOemCodePageFromLocale := 852
  911. else if IsLocaleMatches(lc_str, 'cy_GB') then DeduceOemCodePageFromLocale := 850
  912. else if IsLocaleMatches(lc_str, 'da_DK') then DeduceOemCodePageFromLocale := 850
  913. else if IsLocaleMatches(lc_str, 'de_AT') then DeduceOemCodePageFromLocale := 850
  914. else if IsLocaleMatches(lc_str, 'de_LI') then DeduceOemCodePageFromLocale := 850
  915. else if IsLocaleMatches(lc_str, 'de_LU') then DeduceOemCodePageFromLocale := 850
  916. else if IsLocaleMatches(lc_str, 'de_CH') then DeduceOemCodePageFromLocale := 850
  917. else if IsLocaleMatches(lc_str, 'de_DE') then DeduceOemCodePageFromLocale := 850
  918. else if IsLocaleMatches(lc_str, 'el_GR') then DeduceOemCodePageFromLocale := 737
  919. else if IsLocaleMatches(lc_str, 'en_AU') then DeduceOemCodePageFromLocale := 850
  920. else if IsLocaleMatches(lc_str, 'en_CA') then DeduceOemCodePageFromLocale := 850
  921. else if IsLocaleMatches(lc_str, 'en_GB') then DeduceOemCodePageFromLocale := 850
  922. else if IsLocaleMatches(lc_str, 'en_IE') then DeduceOemCodePageFromLocale := 850
  923. else if IsLocaleMatches(lc_str, 'en_JM') then DeduceOemCodePageFromLocale := 850
  924. else if IsLocaleMatches(lc_str, 'en_BZ') then DeduceOemCodePageFromLocale := 850
  925. else if IsLocaleMatches(lc_str, 'en_PH') then DeduceOemCodePageFromLocale := 437
  926. else if IsLocaleMatches(lc_str, 'en_ZA') then DeduceOemCodePageFromLocale := 437
  927. else if IsLocaleMatches(lc_str, 'en_TT') then DeduceOemCodePageFromLocale := 850
  928. else if IsLocaleMatches(lc_str, 'en_US') then DeduceOemCodePageFromLocale := 437
  929. else if IsLocaleMatches(lc_str, 'en_ZW') then DeduceOemCodePageFromLocale := 437
  930. else if IsLocaleMatches(lc_str, 'en_NZ') then DeduceOemCodePageFromLocale := 850
  931. else if IsLocaleMatches(lc_str, 'es_PA') then DeduceOemCodePageFromLocale := 850
  932. else if IsLocaleMatches(lc_str, 'es_BO') then DeduceOemCodePageFromLocale := 850
  933. else if IsLocaleMatches(lc_str, 'es_CR') then DeduceOemCodePageFromLocale := 850
  934. else if IsLocaleMatches(lc_str, 'es_DO') then DeduceOemCodePageFromLocale := 850
  935. else if IsLocaleMatches(lc_str, 'es_SV') then DeduceOemCodePageFromLocale := 850
  936. else if IsLocaleMatches(lc_str, 'es_EC') then DeduceOemCodePageFromLocale := 850
  937. else if IsLocaleMatches(lc_str, 'es_GT') then DeduceOemCodePageFromLocale := 850
  938. else if IsLocaleMatches(lc_str, 'es_HN') then DeduceOemCodePageFromLocale := 850
  939. else if IsLocaleMatches(lc_str, 'es_NI') then DeduceOemCodePageFromLocale := 850
  940. else if IsLocaleMatches(lc_str, 'es_CL') then DeduceOemCodePageFromLocale := 850
  941. else if IsLocaleMatches(lc_str, 'es_MX') then DeduceOemCodePageFromLocale := 850
  942. else if IsLocaleMatches(lc_str, 'es_ES') then DeduceOemCodePageFromLocale := 850
  943. else if IsLocaleMatches(lc_str, 'es_CO') then DeduceOemCodePageFromLocale := 850
  944. else if IsLocaleMatches(lc_str, 'es_PE') then DeduceOemCodePageFromLocale := 850
  945. else if IsLocaleMatches(lc_str, 'es_AR') then DeduceOemCodePageFromLocale := 850
  946. else if IsLocaleMatches(lc_str, 'es_PR') then DeduceOemCodePageFromLocale := 850
  947. else if IsLocaleMatches(lc_str, 'es_VE') then DeduceOemCodePageFromLocale := 850
  948. else if IsLocaleMatches(lc_str, 'es_UY') then DeduceOemCodePageFromLocale := 850
  949. else if IsLocaleMatches(lc_str, 'es_PY') then DeduceOemCodePageFromLocale := 850
  950. else if IsLocaleMatches(lc_str, 'et_EE') then DeduceOemCodePageFromLocale := 775
  951. else if IsLocaleMatches(lc_str, 'eu_ES') then DeduceOemCodePageFromLocale := 850
  952. else if IsLocaleMatches(lc_str, 'fa_IR') then DeduceOemCodePageFromLocale := 720
  953. else if IsLocaleMatches(lc_str, 'fi_FI') then DeduceOemCodePageFromLocale := 850
  954. else if IsLocaleMatches(lc_str, 'fo_FO') then DeduceOemCodePageFromLocale := 850
  955. else if IsLocaleMatches(lc_str, 'fr_FR') then DeduceOemCodePageFromLocale := 850
  956. else if IsLocaleMatches(lc_str, 'fr_BE') then DeduceOemCodePageFromLocale := 850
  957. else if IsLocaleMatches(lc_str, 'fr_CA') then DeduceOemCodePageFromLocale := 850
  958. else if IsLocaleMatches(lc_str, 'fr_LU') then DeduceOemCodePageFromLocale := 850
  959. else if IsLocaleMatches(lc_str, 'fr_MC') then DeduceOemCodePageFromLocale := 850
  960. else if IsLocaleMatches(lc_str, 'fr_CH') then DeduceOemCodePageFromLocale := 850
  961. else if IsLocaleMatches(lc_str, 'ga_IE') then DeduceOemCodePageFromLocale := 437
  962. else if IsLocaleMatches(lc_str, 'gd_GB') then DeduceOemCodePageFromLocale := 850
  963. else if IsLocaleMatches(lc_str, 'gv_IM') then DeduceOemCodePageFromLocale := 850
  964. else if IsLocaleMatches(lc_str, 'gl_ES') then DeduceOemCodePageFromLocale := 850
  965. else if IsLocaleMatches(lc_str, 'he_IL') then DeduceOemCodePageFromLocale := 862
  966. else if IsLocaleMatches(lc_str, 'hr_HR') then DeduceOemCodePageFromLocale := 852
  967. else if IsLocaleMatches(lc_str, 'hu_HU') then DeduceOemCodePageFromLocale := 852
  968. else if IsLocaleMatches(lc_str, 'id_ID') then DeduceOemCodePageFromLocale := 850
  969. else if IsLocaleMatches(lc_str, 'is_IS') then DeduceOemCodePageFromLocale := 850
  970. else if IsLocaleMatches(lc_str, 'it_IT') then DeduceOemCodePageFromLocale := 850
  971. else if IsLocaleMatches(lc_str, 'it_CH') then DeduceOemCodePageFromLocale := 850
  972. else if IsLocaleMatches(lc_str, 'iv_IV') then DeduceOemCodePageFromLocale := 437
  973. else if IsLocaleMatches(lc_str, 'ja_JP') then DeduceOemCodePageFromLocale := 932
  974. else if IsLocaleMatches(lc_str, 'kk_KZ') then DeduceOemCodePageFromLocale := 866
  975. else if IsLocaleMatches(lc_str, 'ko_KR') then DeduceOemCodePageFromLocale := 949
  976. else if IsLocaleMatches(lc_str, 'ky_KG') then DeduceOemCodePageFromLocale := 866
  977. else if IsLocaleMatches(lc_str, 'lt_LT') then DeduceOemCodePageFromLocale := 775
  978. else if IsLocaleMatches(lc_str, 'lv_LV') then DeduceOemCodePageFromLocale := 775
  979. else if IsLocaleMatches(lc_str, 'mk_MK') then DeduceOemCodePageFromLocale := 866
  980. else if IsLocaleMatches(lc_str, 'mn_MN') then DeduceOemCodePageFromLocale := 866
  981. else if IsLocaleMatches(lc_str, 'ms_BN') then DeduceOemCodePageFromLocale := 850
  982. else if IsLocaleMatches(lc_str, 'ms_MY') then DeduceOemCodePageFromLocale := 850
  983. else if IsLocaleMatches(lc_str, 'nl_BE') then DeduceOemCodePageFromLocale := 850
  984. else if IsLocaleMatches(lc_str, 'nl_NL') then DeduceOemCodePageFromLocale := 850
  985. else if IsLocaleMatches(lc_str, 'nl_SR') then DeduceOemCodePageFromLocale := 850
  986. else if IsLocaleMatches(lc_str, 'nn_NO') then DeduceOemCodePageFromLocale := 850
  987. else if IsLocaleMatches(lc_str, 'nb_NO') then DeduceOemCodePageFromLocale := 850
  988. else if IsLocaleMatches(lc_str, 'pl_PL') then DeduceOemCodePageFromLocale := 852
  989. else if IsLocaleMatches(lc_str, 'pt_BR') then DeduceOemCodePageFromLocale := 850
  990. else if IsLocaleMatches(lc_str, 'pt_PT') then DeduceOemCodePageFromLocale := 850
  991. else if IsLocaleMatches(lc_str, 'rm_CH') then DeduceOemCodePageFromLocale := 850
  992. else if IsLocaleMatches(lc_str, 'ro_RO') then DeduceOemCodePageFromLocale := 852
  993. else if IsLocaleMatches(lc_str, 'ru_RU') then DeduceOemCodePageFromLocale := 866
  994. else if IsLocaleMatches(lc_str, 'sk_SK') then DeduceOemCodePageFromLocale := 852
  995. else if IsLocaleMatches(lc_str, 'sl_SI') then DeduceOemCodePageFromLocale := 852
  996. else if IsLocaleMatches(lc_str, 'sq_AL') then DeduceOemCodePageFromLocale := 852
  997. else if IsLocaleMatches(lc_str, 'sr_RS') then DeduceOemCodePageFromLocale := 855
  998. else if IsLocaleMatches(lc_str, 'sv_SE') then DeduceOemCodePageFromLocale := 850
  999. else if IsLocaleMatches(lc_str, 'sv_FI') then DeduceOemCodePageFromLocale := 850
  1000. else if IsLocaleMatches(lc_str, 'sw_KE') then DeduceOemCodePageFromLocale := 437
  1001. else if IsLocaleMatches(lc_str, 'th_TH') then DeduceOemCodePageFromLocale := 874
  1002. else if IsLocaleMatches(lc_str, 'tr_TR') then DeduceOemCodePageFromLocale := 857
  1003. else if IsLocaleMatches(lc_str, 'tt_RU') then DeduceOemCodePageFromLocale := 866
  1004. else if IsLocaleMatches(lc_str, 'uk_UA') then DeduceOemCodePageFromLocale := 866
  1005. else if IsLocaleMatches(lc_str, 'ur_PK') then DeduceOemCodePageFromLocale := 720
  1006. else if IsLocaleMatches(lc_str, 'uz_UZ') then DeduceOemCodePageFromLocale := 866
  1007. else if IsLocaleMatches(lc_str, 'vi_VN') then DeduceOemCodePageFromLocale := 1258
  1008. else if IsLocaleMatches(lc_str, 'wa_BE') then DeduceOemCodePageFromLocale := 850
  1009. else if IsLocaleMatches(lc_str, 'zh_HK') then DeduceOemCodePageFromLocale := 950
  1010. else if IsLocaleMatches(lc_str, 'zh_SG') then DeduceOemCodePageFromLocale := 936
  1011. else if IsLocaleMatches(lc_str, 'zh_MO') then DeduceOemCodePageFromLocale := 950;
  1012. end;
  1013. procedure decide_codepages;
  1014. var s:shortstring;
  1015. begin
  1016. if is_vga_code_page(external_codepage) then
  1017. begin
  1018. {Possible override...}
  1019. s:=upcase(fpgetenv('CONSOLEFONT_CP'));
  1020. if s='CP437' then
  1021. external_codepage:=437
  1022. else if s='CP850' then
  1023. external_codepage:=850;
  1024. end;
  1025. {A non-vcsa Linux console can display most control characters, but not all.}
  1026. case external_codepage of
  1027. CP_ISO01: {West Europe}
  1028. CurrentLegacy2EnhancedTranslationCodePage:=850;
  1029. CP_ISO02: {East Europe}
  1030. CurrentLegacy2EnhancedTranslationCodePage:=852;
  1031. CP_ISO05: {Cyrillic}
  1032. CurrentLegacy2EnhancedTranslationCodePage:=866;
  1033. CP_UTF8:
  1034. CurrentLegacy2EnhancedTranslationCodePage:=DeduceOemCodePageFromLocale;
  1035. else
  1036. if is_vga_code_page(external_codepage) then
  1037. CurrentLegacy2EnhancedTranslationCodePage:=external_codepage
  1038. else
  1039. {We don't know how to convert to the external codepage. Use codepage
  1040. 437 in the hope that the actual font has similarity to codepage 437.}
  1041. CurrentLegacy2EnhancedTranslationCodePage:=437;
  1042. end;
  1043. end;
  1044. procedure prepareInitVideo;
  1045. begin
  1046. TCGetAttr(1,preInitVideoTio);
  1047. saveRawSettings(preInitVideoTio);
  1048. end;
  1049. procedure videoInitDone;
  1050. begin
  1051. TCGetAttr(1,postInitVideoTio);
  1052. restoreRawSettings(postInitVideoTio);
  1053. end;
  1054. procedure prepareDoneVideo;
  1055. var
  1056. tio: {$IFDEF FPC_DOTTEDUNITS}UnixApi.{$ENDIF}TermIo.termios;
  1057. begin
  1058. TCGetAttr(1,tio);
  1059. saveRawSettings(tio);
  1060. TCSetAttr(1,TCSANOW,postInitVideoTio);
  1061. end;
  1062. procedure doneVideoDone;
  1063. begin
  1064. restoreRawSettings(preInitVideoTio);
  1065. end;
  1066. procedure SysInitVideo;
  1067. var
  1068. {$ifdef linux}
  1069. FName: shortstring;
  1070. {$endif linux}
  1071. WS: packed record
  1072. ws_row, ws_col, ws_xpixel, ws_ypixel: Word;
  1073. end;
  1074. { Err: Longint;}
  1075. { prev_term : TerminalCommon_ptr1;}
  1076. term:shortstring;
  1077. i:word;
  1078. {$ifdef Linux}
  1079. s:string[15];
  1080. {$endif}
  1081. {$ifdef freebsd}
  1082. ThisTTY: String[30];
  1083. {$endif}
  1084. envInput: string;
  1085. const font_vga:array[0..11] of AnsiChar=#15#27'%@'#27'(U'#27'[3h';
  1086. font_lat1:array[0..5] of AnsiChar=#27'%@'#27'(B';
  1087. begin
  1088. { check for tty }
  1089. if (IsATTY(stdinputhandle)=1) then
  1090. begin
  1091. { save current terminal characteristics and remove rawness }
  1092. prepareInitVideo;
  1093. {$ifdef linux}
  1094. { running on a tty, find out whether locally or remotely }
  1095. TTyfd:=-1;
  1096. {$endif linux}
  1097. Console:=TTyNetwork; {Default: Network or other vtxxx tty}
  1098. cur_term_strings:=@term_codes_vt100; {Default: vt100}
  1099. external_codepage:=CP_ISO01; {Default: ISO-8859-1}
  1100. if UTF8Enabled then
  1101. external_codepage:=CP_UTF8;
  1102. {$ifdef linux}
  1103. if (vcs_device>=0) and (external_codepage<>CP_UTF8) then
  1104. begin
  1105. str(vcs_device,s);
  1106. fname:='/dev/vcsa'+s;
  1107. { open console, $1b6=rw-rw-rw- }
  1108. ttyfd:=fpopen(fname,$1b6,O_RDWR);
  1109. if ttyfd<>-1 then
  1110. begin
  1111. console:=ttylinux;
  1112. external_codepage:=437; {VCSA defaults to codepage 437.}
  1113. end
  1114. else
  1115. if try_grab_vcsa then
  1116. begin
  1117. ttyfd:=fpopen(fname,$1b6,O_RDWR);
  1118. if ttyfd<>-1 then
  1119. begin
  1120. console:=ttylinux;
  1121. external_codepage:=437; {VCSA defaults to codepage 437.}
  1122. end;
  1123. end;
  1124. end;
  1125. {$endif}
  1126. {$ifdef freebsd}
  1127. ThisTTY:=TTYName(stdinputhandle);
  1128. if copy(ThisTTY, 1, 9) = '/dev/ttyv' then {FreeBSD has these}
  1129. begin
  1130. { check for (Free?)BSD native}
  1131. if (ThisTTY[10]>='0') and (ThisTTY[10]<='9') Then
  1132. Console:=ttyFreeBSD; {TTYFd ?}
  1133. end;
  1134. {$endif}
  1135. term:=fpgetenv('TERM');
  1136. for i:=low(terminal_names) to high(terminal_names) do
  1137. if copy(term,1,length(terminal_names[i]))=terminal_names[i] then
  1138. cur_term_strings:=terminal_data[i];
  1139. if cur_term_strings=@term_codes_xterm then
  1140. begin
  1141. {$ifdef haiku}
  1142. TerminalSupportsBold := true;
  1143. TerminalSupportsHighIntensityColors := false;
  1144. {$else}
  1145. TerminalSupportsBold := false;
  1146. TerminalSupportsHighIntensityColors := true;
  1147. {$endif}
  1148. end
  1149. else
  1150. begin
  1151. TerminalSupportsBold := true;
  1152. TerminalSupportsHighIntensityColors := false;
  1153. end;
  1154. if cur_term_strings=@term_codes_beos then
  1155. begin
  1156. TerminalSupportsBold := false;
  1157. TerminalSupportsHighIntensityColors := false;
  1158. end;
  1159. if cur_term_strings=@term_codes_freebsd then
  1160. console:=ttyFreeBSD;
  1161. {$ifdef linux}
  1162. if (console<>ttylinux) then
  1163. begin
  1164. {$endif}
  1165. if cur_term_strings=@term_codes_linux then
  1166. begin
  1167. if external_codepage<>CP_UTF8 then
  1168. begin
  1169. {Enable the VGA character set (codepage 437,850,....)}
  1170. fpwrite(stdoutputhandle,font_vga,sizeof(font_vga));
  1171. external_codepage:=437; {Now default to codepage 437.}
  1172. end;
  1173. end
  1174. else
  1175. begin
  1176. if external_codepage<>CP_UTF8 then
  1177. begin
  1178. {No VGA font :( }
  1179. fpwrite(stdoutputhandle,font_lat1,sizeof(font_lat1));
  1180. end;
  1181. { running on a remote terminal, no error with /dev/vcsa }
  1182. end;
  1183. {$ifdef linux}
  1184. end;
  1185. {$endif}
  1186. fpioctl(stdinputhandle, TIOCGWINSZ, @WS);
  1187. if WS.ws_Col=0 then
  1188. WS.ws_Col:=80;
  1189. if WS.ws_Row=0 then
  1190. WS.ws_Row:=25;
  1191. ScreenWidth:=WS.ws_Col;
  1192. { TDrawBuffer only has FVMaxWidth elements
  1193. larger values lead to crashes }
  1194. if ScreenWidth> FVMaxWidth then
  1195. ScreenWidth:=FVMaxWidth;
  1196. ScreenHeight:=WS.ws_Row;
  1197. CursorX:=0;
  1198. CursorY:=0;
  1199. LastCursorType:=$ff;
  1200. ScreenColor:=True;
  1201. { Start with a clear screen }
  1202. {$ifdef linux}
  1203. if Console<>ttylinux then
  1204. begin
  1205. {$endif}
  1206. SendEscapeSeqNdx(enter_ca_mode);
  1207. SendEscapeSeqNdx(cursor_home);
  1208. SendEscapeSeqNdx(cursor_normal);
  1209. SendEscapeSeqNdx(cursor_visible_underline);
  1210. SetCursorType(crUnderLine);
  1211. If Console=ttyFreeBSD Then
  1212. SendEscapeSeqNdx(exit_am_mode);
  1213. {$ifdef linux}
  1214. end;
  1215. {$endif}
  1216. { Always true because of vt100 default...
  1217. if assigned(cur_term_Strings) then
  1218. begin}
  1219. ACSIn:=StrPas(cur_term_strings^[enter_alt_charset_mode]);
  1220. ACSOut:=StrPas(cur_term_strings^[exit_alt_charset_mode]);
  1221. if (ACSIn<>'') and (ACSOut<>'') then
  1222. SendEscapeSeqNdx(ena_acs);
  1223. (* If fpGetEnv('TERM')='xterm' then
  1224. convert:=cv_vga_to_acs; {use of acs for xterm is ok}*)
  1225. { end
  1226. else
  1227. begin
  1228. ACSIn:='';
  1229. ACSOut:='';
  1230. end;}
  1231. {$ifdef logging}
  1232. assign(f,'video.log');
  1233. rewrite(f,1);
  1234. {$endif logging}
  1235. { save new terminal characteristics and possible restore rawness }
  1236. videoInitDone;
  1237. decide_codepages;
  1238. envInput := LowerCase(fpgetenv('TV_INPUT'));
  1239. if (envInput = '') or (envInput = 'kitty') then
  1240. SendEscapeSeq(#27'[>31u');{Entering alternativ screen we have to set up kitty keys}
  1241. end
  1242. else
  1243. ErrorCode:=errVioInit; { not a TTY }
  1244. end;
  1245. procedure SysDoneVideo;
  1246. var font_custom:array[0..2] of AnsiChar=#27'(K';
  1247. begin
  1248. SendEscapeSeq(#27'[<u'); { kitty keys disable }
  1249. prepareDoneVideo;
  1250. SetCursorType(crUnderLine);
  1251. {$ifdef linux}
  1252. if Console=ttylinux then
  1253. SetCursorPos(0,0)
  1254. else
  1255. begin
  1256. {$endif}
  1257. SendEscapeSeqNdx(cursor_home);
  1258. SendEscapeSeqNdx(cursor_normal);
  1259. SendEscapeSeqNdx(cursor_visible_underline);
  1260. SendEscapeSeq(#27'[H');
  1261. SendEscapeSeqNdx(exit_ca_mode);
  1262. if cur_term_strings=@term_codes_linux then
  1263. begin
  1264. {Executed in case ttylinux is false (i.e. no vcsa), but
  1265. TERM=linux.}
  1266. { if we're in utf8 mode, we didn't change the font, so
  1267. no need to restore anything }
  1268. if external_codepage<>CP_UTF8 then
  1269. begin
  1270. {Enable the character set set through setfont}
  1271. fpwrite(stdoutputhandle,font_custom,3);
  1272. end;
  1273. end;
  1274. {$ifdef linux}
  1275. end;
  1276. {$endif}
  1277. ACSIn:='';
  1278. ACSOut:='';
  1279. doneVideoDone;
  1280. {$ifdef logging}
  1281. close(f);
  1282. {$endif logging}
  1283. end;
  1284. procedure SysClearScreen;
  1285. begin
  1286. {$ifdef linux}
  1287. if Console=ttylinux then
  1288. UpdateScreen(true)
  1289. else
  1290. begin
  1291. {$endif}
  1292. SendEscapeSeq(#27'[0m');
  1293. SendEscapeSeqNdx(clear_screen);
  1294. {$ifdef linux}
  1295. end;
  1296. {$endif}
  1297. end;
  1298. procedure SysUpdateScreen(Force: Boolean);
  1299. var
  1300. I: Integer;
  1301. begin
  1302. {$ifdef linux}
  1303. if console=ttylinux then
  1304. update_vcsa(force)
  1305. else
  1306. {$endif}
  1307. updateTTY(force);
  1308. if VideoInitialized then
  1309. begin
  1310. move(VideoBuf^,OldVideoBuf^,VideoBufSize);
  1311. end else
  1312. begin
  1313. for I := Low(EnhancedVideoBuf) to High(EnhancedVideoBuf) do
  1314. OldEnhancedVideoBuf[I] := EnhancedVideoBuf[I];
  1315. end;
  1316. end;
  1317. function SysGetCapabilities: Word;
  1318. begin
  1319. { about cpColor... we should check the terminfo database... }
  1320. SysGetCapabilities:=cpUnderLine + cpBlink + cpColor;
  1321. end;
  1322. procedure SysSetCursorPos(NewCursorX, NewCursorY: Word);
  1323. {$ifdef linux}
  1324. var
  1325. Pos : array [1..2] of Byte;
  1326. {$endif linux}
  1327. begin
  1328. if (CursorX=NewCursorX) and (CursorY=NewCursorY) then
  1329. exit;
  1330. {$ifdef linux}
  1331. if Console=ttylinux then
  1332. begin
  1333. Pos[1]:=NewCursorX;
  1334. Pos[2]:=NewCursorY;
  1335. fppwrite(ttyfd,pos,2,2);
  1336. end
  1337. else
  1338. {$endif}
  1339. { newcursorx,y and CursorX,Y are 0 based ! }
  1340. SendEscapeSeq(XY2Ansi(NewCursorX+1,NewCursorY+1,CursorX+1,CursorY+1));
  1341. CursorX:=NewCursorX;
  1342. CursorY:=NewCursorY;
  1343. end;
  1344. function SysGetCursorType: Word;
  1345. begin
  1346. SysGetCursorType:=LastCursorType;
  1347. end;
  1348. procedure SysSetCursorType(NewType: Word);
  1349. begin
  1350. If LastCursorType=NewType then
  1351. exit;
  1352. LastCursorType:=NewType;
  1353. case NewType of
  1354. crBlock:
  1355. SendEscapeSeqNdx(cursor_visible_block);
  1356. crUnderLine:
  1357. SendEscapeSeqNdx(cursor_visible_underline);
  1358. crHidden:
  1359. SendEscapeSeqNdx(cursor_invisible);
  1360. else
  1361. SendEscapeSeqNdx(cursor_normal);
  1362. end;
  1363. end;
  1364. function SysSetVideoMode(const mode:Tvideomode):boolean;
  1365. var winsize:Twinsize;
  1366. begin
  1367. {Due to xterm resize this procedure might get called with the new xterm
  1368. size. Approve the video mode change if the new size equals that of
  1369. the terminal window size.}
  1370. SysSetVideoMode:=false;
  1371. fpioctl(stdinputhandle,TIOCGWINSZ,@winsize);
  1372. if (mode.row=winsize.ws_row) and
  1373. (mode.col=winsize.ws_col) then
  1374. begin
  1375. screenwidth:=mode.col;
  1376. screenheight:=mode.row;
  1377. screencolor:=true;
  1378. SysSetVideoMode:=true;
  1379. end;
  1380. end;
  1381. Const
  1382. SysVideoDriver : TVideoDriver = (
  1383. InitDriver : nil;
  1384. InitEnhancedDriver: @SysInitVideo;
  1385. DoneDriver : @SysDoneVideo;
  1386. UpdateScreen : @SysUpdateScreen;
  1387. UpdateScreenArea : Nil;
  1388. ClearScreen : @SysClearScreen;
  1389. SetVideoMode : @SysSetVideoMode;
  1390. GetVideoModeCount : Nil;
  1391. GetVideoModeData : Nil;
  1392. SetCursorPos : @SysSetCursorPos;
  1393. GetCursorType : @SysGetCursorType;
  1394. SetCursorType : @SysSetCursorType;
  1395. GetCapabilities : @SysGetCapabilities;
  1396. GetActiveCodePage : Nil;
  1397. ActivateCodePage : Nil;
  1398. GetSupportedCodePageCount : Nil;
  1399. GetSupportedCodePage : Nil;
  1400. );
  1401. initialization
  1402. SetVideoDriver(SysVideoDriver);
  1403. end.