keyboard.pp 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494
  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. Keyboard unit for linux
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit keyboard;
  13. {$inline on}
  14. {*****************************************************************************}
  15. interface
  16. {*****************************************************************************}
  17. {$i keybrdh.inc}
  18. const
  19. AltPrefix : byte = 0;
  20. ShiftPrefix : byte = 0;
  21. CtrlPrefix : byte = 0;
  22. function RawReadKey:char;
  23. function RawReadString : String;
  24. function KeyPressed : Boolean;
  25. procedure AddSequence(const St : String; AChar,AScan :byte);inline;
  26. function FindSequence(const St : String;var AChar, Ascan : byte) : boolean;
  27. procedure RestoreStartMode;
  28. {*****************************************************************************}
  29. implementation
  30. {*****************************************************************************}
  31. uses
  32. Mouse, Strings,
  33. termio,baseUnix
  34. {$ifdef linux},linuxvcs{$endif};
  35. {$i keyboard.inc}
  36. var OldIO,StartTio : TermIos;
  37. {$ifdef linux}
  38. is_console:boolean;
  39. vt_switched_away:boolean;
  40. {$endif}
  41. {$ifdef logging}
  42. f : text;
  43. {$endif logging}
  44. const
  45. KeyBufferSize = 20;
  46. var
  47. KeyBuffer : Array[0..KeyBufferSize-1] of Char;
  48. KeyPut,
  49. KeySend : longint;
  50. { Buffered Input routines }
  51. const
  52. InSize=256;
  53. var
  54. InBuf : array [0..InSize-1] of char;
  55. { InCnt,}
  56. InHead,
  57. InTail : longint;
  58. {$i keyscan.inc}
  59. {Some internal only scancodes}
  60. const KbShiftUp = $f0;
  61. KbShiftLeft = $f1;
  62. KbShiftRight = $f2;
  63. KbShiftDown = $f3;
  64. KbShiftHome = $f4;
  65. KbShiftEnd = $f5;
  66. {$ifdef Unused}
  67. type
  68. TKeyState = Record
  69. Normal, Shift, Ctrl, Alt : word;
  70. end;
  71. const
  72. KeyStates : Array[0..255] of TKeyState
  73. (
  74. );
  75. {$endif Unused}
  76. procedure SetRawMode(b:boolean);
  77. var
  78. Tio : Termios;
  79. Begin
  80. TCGetAttr(1,Tio);
  81. if b then
  82. begin
  83. OldIO:=Tio;
  84. CFMakeRaw(Tio);
  85. end
  86. else
  87. Tio := OldIO;
  88. TCSetAttr(1,TCSANOW,Tio);
  89. End;
  90. {$ifdef linux}
  91. {The Linux console can do nice things: we can get the state of the shift keys,
  92. and reprogram the keys. That's nice since it allows excellent circumvention
  93. of VT100 limitations, we can make the keyboard work 100%...
  94. A 100% working keyboard seems to be a pretty basic requirement, but we're
  95. one of the few guys providing such an outrageous luxury (DM).}
  96. type
  97. chgentry=packed record
  98. tab,
  99. idx,
  100. oldtab,
  101. oldidx : byte;
  102. oldval,
  103. newval : word;
  104. end;
  105. kbentry=packed record
  106. kb_table,
  107. kb_index : byte;
  108. kb_value : word;
  109. end;
  110. kbsentry=packed record
  111. kb_func:byte;
  112. kb_string:array[0..511] of char;
  113. end;
  114. vt_mode=packed record
  115. mode, {vt mode}
  116. waitv:byte; {if set, hang on writes if not active}
  117. relsig, {signal to raise on release req}
  118. acqsig, {signal to raise on acquisition}
  119. frsig:word; {unused (set to 0)}
  120. end;
  121. const
  122. kbdchange:array[0..23] of chgentry=(
  123. {This prevents the alt+function keys from switching consoles.
  124. We code the F1..F12 sequences into ALT+F1..ALT+12, we check
  125. the shiftstates separetely anyway.}
  126. (tab:8; idx:$3b; oldtab:0; oldidx:$3b; oldval:0; newval:0),
  127. (tab:8; idx:$3c; oldtab:0; oldidx:$3c; oldval:0; newval:0),
  128. (tab:8; idx:$3d; oldtab:0; oldidx:$3d; oldval:0; newval:0),
  129. (tab:8; idx:$3e; oldtab:0; oldidx:$3e; oldval:0; newval:0),
  130. (tab:8; idx:$3f; oldtab:0; oldidx:$3f; oldval:0; newval:0),
  131. (tab:8; idx:$40; oldtab:0; oldidx:$40; oldval:0; newval:0),
  132. (tab:8; idx:$41; oldtab:0; oldidx:$41; oldval:0; newval:0),
  133. (tab:8; idx:$42; oldtab:0; oldidx:$42; oldval:0; newval:0),
  134. (tab:8; idx:$43; oldtab:0; oldidx:$43; oldval:0; newval:0),
  135. (tab:8; idx:$44; oldtab:0; oldidx:$44; oldval:0; newval:0),
  136. (tab:8; idx:$45; oldtab:0; oldidx:$45; oldval:0; newval:0),
  137. (tab:8; idx:$46; oldtab:0; oldidx:$46; oldval:0; newval:0),
  138. {This prevents the shift+function keys outputting strings, so
  139. the kernel will the codes for the non-shifted function
  140. keys. This is desired because normally shift+f1/f2 will output the
  141. same string as f11/12. We will get the shift state separately.}
  142. (tab:1; idx:$3b; oldtab:0; oldidx:$3b; oldval:0; newval:0),
  143. (tab:1; idx:$3c; oldtab:0; oldidx:$3c; oldval:0; newval:0),
  144. (tab:1; idx:$3d; oldtab:0; oldidx:$3d; oldval:0; newval:0),
  145. (tab:1; idx:$3e; oldtab:0; oldidx:$3e; oldval:0; newval:0),
  146. (tab:1; idx:$3f; oldtab:0; oldidx:$3f; oldval:0; newval:0),
  147. (tab:1; idx:$40; oldtab:0; oldidx:$40; oldval:0; newval:0),
  148. (tab:1; idx:$41; oldtab:0; oldidx:$41; oldval:0; newval:0),
  149. (tab:1; idx:$42; oldtab:0; oldidx:$42; oldval:0; newval:0),
  150. (tab:1; idx:$43; oldtab:0; oldidx:$43; oldval:0; newval:0),
  151. (tab:1; idx:$44; oldtab:0; oldidx:$44; oldval:0; newval:0),
  152. (tab:1; idx:$45; oldtab:0; oldidx:$45; oldval:0; newval:0),
  153. (tab:1; idx:$46; oldtab:0; oldidx:$46; oldval:0; newval:0)
  154. );
  155. KDGKBENT=$4B46;
  156. KDSKBENT=$4B47;
  157. KDGKBSENT=$4B48;
  158. KDSKBSENT=$4B49;
  159. KDGKBMETA=$4B62;
  160. KDSKBMETA=$4B63;
  161. K_ESCPREFIX=$4;
  162. K_METABIT=$3;
  163. VT_GETMODE=$5601;
  164. VT_SETMODE=$5602;
  165. VT_RELDISP=$5605;
  166. VT_PROCESS=1;
  167. const
  168. oldmeta : longint = 0;
  169. meta : longint = 0;
  170. var oldesc0,oldesc1,oldesc2,oldesc4,oldesc8:word;
  171. procedure prepare_patching;
  172. var e:^chgentry;
  173. entry : kbentry;
  174. i:longint;
  175. begin
  176. for i:=low(kbdchange) to high(kbdchange) do
  177. begin
  178. e:=@kbdchange[i];
  179. entry.kb_table:=e^.tab;
  180. entry.kb_index:=e^.idx;
  181. fpIoctl(stdinputhandle,KDGKBENT,@entry);
  182. e^.oldval:=entry.kb_value;
  183. entry.kb_table:=e^.oldtab;
  184. entry.kb_index:=e^.oldidx;
  185. fpioctl(stdinputhandle,KDGKBENT,@entry);
  186. e^.newval:=entry.kb_value;
  187. end;
  188. {Save old escape code.}
  189. entry.kb_index:=1;
  190. entry.kb_table:=0;
  191. fpioctl(stdinputhandle,KDGKBENT,@entry);
  192. oldesc0:=entry.kb_value;
  193. entry.kb_table:=1;
  194. fpioctl(stdinputhandle,KDGKBENT,@entry);
  195. oldesc1:=entry.kb_value;
  196. entry.kb_table:=2;
  197. fpioctl(stdinputhandle,KDGKBENT,@entry);
  198. oldesc2:=entry.kb_value;
  199. entry.kb_table:=4;
  200. fpioctl(stdinputhandle,KDGKBENT,@entry);
  201. oldesc4:=entry.kb_value;
  202. entry.kb_table:=8;
  203. fpioctl(stdinputhandle,KDGKBENT,@entry);
  204. oldesc8:=entry.kb_value;
  205. end;
  206. procedure PatchKeyboard;
  207. var
  208. e : ^chgentry;
  209. entry : kbentry;
  210. sentry : kbsentry;
  211. i:longint;
  212. begin
  213. fpIoctl(stdinputhandle,KDGKBMETA,@oldmeta);
  214. meta:=K_ESCPREFIX;
  215. fpIoctl(stdinputhandle,KDSKBMETA,@meta);
  216. for i:=low(kbdchange) to high(kbdchange) do
  217. begin
  218. e:=@kbdchange[i];
  219. entry.kb_table:=e^.tab;
  220. entry.kb_index:=e^.idx;
  221. entry.kb_value:=e^.newval;
  222. fpioctl(stdinputhandle,KDSKBENT,@entry);
  223. end;
  224. {Map kernel escape key code to symbol F32.}
  225. entry.kb_index:=1;
  226. entry.kb_value:=$011f;
  227. entry.kb_table:=0;
  228. fpioctl(stdinputhandle,KDSKBENT,@entry);
  229. entry.kb_table:=1;
  230. fpioctl(stdinputhandle,KDSKBENT,@entry);
  231. entry.kb_table:=2;
  232. fpioctl(stdinputhandle,KDSKBENT,@entry);
  233. entry.kb_table:=4;
  234. fpioctl(stdinputhandle,KDSKBENT,@entry);
  235. entry.kb_table:=8;
  236. fpioctl(stdinputhandle,KDSKBENT,@entry);
  237. {F32 (the escape key) will generate ^[[0~ .}
  238. sentry.kb_func:=31;
  239. sentry.kb_string:=#27'[0~';
  240. fpioctl(stdinputhandle,KDSKBSENT,@sentry);
  241. end;
  242. procedure UnpatchKeyboard;
  243. var
  244. e : ^chgentry;
  245. entry : kbentry;
  246. i : longint;
  247. begin
  248. if oldmeta in [K_ESCPREFIX,K_METABIT] then
  249. fpioctl(stdinputhandle,KDSKBMETA,@oldmeta);
  250. for i:=low(kbdchange) to high(kbdchange) do
  251. begin
  252. e:=@kbdchange[i];
  253. entry.kb_table:=e^.tab;
  254. entry.kb_index:=e^.idx;
  255. entry.kb_value:=e^.oldval;
  256. fpioctl(stdinputhandle,KDSKBENT,@entry);
  257. end;
  258. entry.kb_index:=1;
  259. entry.kb_table:=0;
  260. entry.kb_value:=oldesc0;
  261. fpioctl(stdinputhandle,KDSKBENT,@entry);
  262. entry.kb_table:=1;
  263. entry.kb_value:=oldesc1;
  264. fpioctl(stdinputhandle,KDSKBENT,@entry);
  265. entry.kb_table:=2;
  266. entry.kb_value:=oldesc2;
  267. fpioctl(stdinputhandle,KDSKBENT,@entry);
  268. entry.kb_table:=4;
  269. entry.kb_value:=oldesc4;
  270. fpioctl(stdinputhandle,KDSKBENT,@entry);
  271. entry.kb_table:=8;
  272. entry.kb_value:=oldesc8;
  273. fpioctl(stdinputhandle,KDSKBENT,@entry);
  274. end;
  275. {A problem of patching the keyboard is that it no longer works as expected
  276. when working on another console. So we unpatch it when the user switches
  277. away.}
  278. const switches:longint=0;
  279. procedure vt_handler(sig:longint);cdecl;
  280. begin
  281. if vt_switched_away then
  282. begin
  283. {Confirm the switch.}
  284. fpioctl(stdoutputhandle,VT_RELDISP,pointer(2));
  285. {Switching to program, patch keyboard.}
  286. patchkeyboard;
  287. end
  288. else
  289. begin
  290. {Switching away from program, unpatch the keyboard.}
  291. unpatchkeyboard;
  292. fpioctl(stdoutputhandle,VT_RELDISP,pointer(1));
  293. end;
  294. vt_switched_away:=not vt_switched_away;
  295. {Clear buffer.}
  296. intail:=inhead;
  297. end;
  298. procedure install_vt_handler;
  299. var mode:vt_mode;
  300. begin
  301. { ioctl(vt_fd,KDSETMODE,KD_GRAPHICS);}
  302. fpioctl(stdoutputhandle,VT_GETMODE,@mode);
  303. mode.mode:=VT_PROCESS;
  304. mode.relsig:=SIGUSR1;
  305. mode.acqsig:=SIGUSR1;
  306. vt_switched_away:=false;
  307. fpsignal(SIGUSR1,@vt_handler);
  308. fpioctl(stdoutputhandle,VT_SETMODE,@mode);
  309. end;
  310. {$endif}
  311. function ttyRecvChar:char;
  312. var Readed,i : longint;
  313. begin
  314. {Buffer empty? Yes, input from stdin}
  315. if (InHead=InTail) then
  316. begin
  317. {Calc Amount of Chars to Read}
  318. i:=InSize-InHead;
  319. if InTail>InHead then
  320. i:=InTail-InHead;
  321. {Read}
  322. repeat
  323. Readed:=fpRead(StdInputHandle,InBuf[InHead],i);
  324. until readed<>-1;
  325. {Increase Counters}
  326. inc(InHead,Readed);
  327. {Wrap if End has Reached}
  328. if InHead>=InSize then
  329. InHead:=0;
  330. end;
  331. {Check Buffer}
  332. ttyRecvChar:=InBuf[InTail];
  333. inc(InTail);
  334. if InTail>=InSize then
  335. InTail:=0;
  336. end;
  337. procedure PushKey(Ch:char);
  338. var
  339. Tmp : Longint;
  340. begin
  341. Tmp:=KeyPut;
  342. Inc(KeyPut);
  343. If KeyPut>=KeyBufferSize Then
  344. KeyPut:=0;
  345. If KeyPut<>KeySend Then
  346. KeyBuffer[Tmp]:=Ch
  347. Else
  348. KeyPut:=Tmp;
  349. End;
  350. function PopKey:char;
  351. begin
  352. If KeyPut<>KeySend Then
  353. begin
  354. PopKey:=KeyBuffer[KeySend];
  355. Inc(KeySend);
  356. If KeySend>=KeyBufferSize Then
  357. KeySend:=0;
  358. End
  359. Else
  360. PopKey:=#0;
  361. End;
  362. procedure PushExt(b:byte);
  363. begin
  364. PushKey(#0);
  365. PushKey(chr(b));
  366. end;
  367. const
  368. AltKeyStr : string[38]='qwertyuiopasdfghjklzxcvbnm1234567890-=';
  369. AltCodeStr : string[38]=#016#017#018#019#020#021#022#023#024#025#030#031#032#033#034#035#036#037#038+
  370. #044#045#046#047#048#049#050#120#121#122#123#124#125#126#127#128#129#130#131;
  371. function FAltKey(ch:char):byte;
  372. var
  373. Idx : longint;
  374. begin
  375. Idx:=Pos(ch,AltKeyStr);
  376. if Idx>0 then
  377. FAltKey:=byte(AltCodeStr[Idx])
  378. else
  379. FAltKey:=0;
  380. End;
  381. { This one doesn't care about keypresses already processed by readkey }
  382. { and waiting in the KeyBuffer, only about waiting keypresses at the }
  383. { TTYLevel (including ones that are waiting in the TTYRecvChar buffer) }
  384. function sysKeyPressed: boolean;
  385. var
  386. fdsin : tfdSet;
  387. begin
  388. if (inhead<>intail) then
  389. sysKeyPressed:=true
  390. else
  391. begin
  392. fpFD_ZERO(fdsin);
  393. fpFD_SET(StdInputHandle,fdsin);
  394. sysKeypressed:=(fpSelect(StdInputHandle+1,@fdsin,nil,nil,0)>0);
  395. end;
  396. end;
  397. function KeyPressed:Boolean;
  398. begin
  399. Keypressed := (KeySend<>KeyPut) or sysKeyPressed;
  400. End;
  401. const
  402. LastMouseEvent : TMouseEvent =
  403. (
  404. Buttons : 0;
  405. X : 0;
  406. Y : 0;
  407. Action : 0;
  408. );
  409. procedure GenMouseEvent;
  410. var MouseEvent: TMouseEvent;
  411. ch : char;
  412. fdsin : tfdSet;
  413. begin
  414. fpFD_ZERO(fdsin);
  415. fpFD_SET(StdInputHandle,fdsin);
  416. { Fillchar(MouseEvent,SizeOf(TMouseEvent),#0);}
  417. MouseEvent.action:=0;
  418. if inhead=intail then
  419. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  420. ch:=ttyRecvChar;
  421. { Other bits are used for Shift, Meta and Ctrl modifiers PM }
  422. case (ord(ch)-ord(' ')) and 3 of
  423. 0 : {left button press}
  424. MouseEvent.buttons:=1;
  425. 1 : {middle button pressed }
  426. MouseEvent.buttons:=2;
  427. 2 : { right button pressed }
  428. MouseEvent.buttons:=4;
  429. 3 : { no button pressed };
  430. end;
  431. if inhead=intail then
  432. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  433. ch:=ttyRecvChar;
  434. MouseEvent.x:=Ord(ch)-ord(' ')-1;
  435. if inhead=intail then
  436. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  437. ch:=ttyRecvChar;
  438. MouseEvent.y:=Ord(ch)-ord(' ')-1;
  439. if (MouseEvent.buttons<>0) then
  440. MouseEvent.action:=MouseActionDown
  441. else
  442. begin
  443. if (LastMouseEvent.Buttons<>0) and
  444. ((LastMouseEvent.X<>MouseEvent.X) or (LastMouseEvent.Y<>MouseEvent.Y)) then
  445. begin
  446. MouseEvent.Action:=MouseActionMove;
  447. MouseEvent.Buttons:=LastMouseEvent.Buttons;
  448. {$ifdef DebugMouse}
  449. Writeln(system.stderr,' Mouse Move (',MouseEvent.X,',',MouseEvent.Y,')');
  450. {$endif DebugMouse}
  451. PutMouseEvent(MouseEvent);
  452. MouseEvent.Buttons:=0;
  453. end;
  454. MouseEvent.Action:=MouseActionUp;
  455. end;
  456. PutMouseEvent(MouseEvent);
  457. {$ifdef DebugMouse}
  458. if MouseEvent.Action=MouseActionDown then
  459. Write(system.stderr,'Button down : ')
  460. else
  461. Write(system.stderr,'Button up : ');
  462. Writeln(system.stderr,'buttons = ',MouseEvent.Buttons,' (',MouseEvent.X,',',MouseEvent.Y,')');
  463. {$endif DebugMouse}
  464. LastMouseEvent:=MouseEvent;
  465. end;
  466. type
  467. Tprocedure = procedure;
  468. PTreeElement = ^TTreeElement;
  469. TTreeElement = record
  470. Next,Parent,Child : PTreeElement;
  471. CanBeTerminal : boolean;
  472. char : byte;
  473. ScanValue : byte;
  474. CharValue : byte;
  475. SpecialHandler : Tprocedure;
  476. end;
  477. var roottree:array[char] of PTreeElement;
  478. procedure FreeElement (PT:PTreeElement);
  479. var next : PTreeElement;
  480. begin
  481. while PT <> nil do
  482. begin
  483. FreeElement(PT^.Child);
  484. next := PT^.Next;
  485. dispose(PT);
  486. PT := next;
  487. end;
  488. end;
  489. procedure FreeTree;
  490. var i:char;
  491. begin
  492. for i:=low(roottree) to high(roottree) do
  493. begin
  494. FreeElement(RootTree[i]);
  495. roottree[i]:=nil;
  496. end;
  497. end;
  498. function NewPTree(ch : byte;Pa : PTreeElement) : PTreeElement;
  499. begin
  500. newPtree:=allocmem(sizeof(Ttreeelement));
  501. newPtree^.char:=ch;
  502. newPtree^.Parent:=Pa;
  503. if Assigned(Pa) and (Pa^.Child=nil) then
  504. Pa^.Child:=newPtree;
  505. end;
  506. function DoAddSequence(const St : String; AChar,AScan :byte) : PTreeElement;
  507. var
  508. CurPTree,NPT : PTreeElement;
  509. c : byte;
  510. i : longint;
  511. begin
  512. if St='' then
  513. begin
  514. DoAddSequence:=nil;
  515. exit;
  516. end;
  517. CurPTree:=RootTree[st[1]];
  518. if CurPTree=nil then
  519. begin
  520. CurPTree:=NewPTree(ord(st[1]),nil);
  521. RootTree[st[1]]:=CurPTree;
  522. end;
  523. for i:=2 to Length(St) do
  524. begin
  525. NPT:=CurPTree^.Child;
  526. c:=ord(St[i]);
  527. if NPT=nil then
  528. NPT:=NewPTree(c,CurPTree);
  529. CurPTree:=nil;
  530. while assigned(NPT) and (NPT^.char<c) do
  531. begin
  532. CurPTree:=NPT;
  533. NPT:=NPT^.Next;
  534. end;
  535. if assigned(NPT) and (NPT^.char=c) then
  536. CurPTree:=NPT
  537. else
  538. begin
  539. if CurPTree=nil then
  540. begin
  541. NPT^.Parent^.child:=NewPTree(c,NPT^.Parent);
  542. CurPTree:=NPT^.Parent^.Child;
  543. CurPTree^.Next:=NPT;
  544. end
  545. else
  546. begin
  547. CurPTree^.Next:=NewPTree(c,CurPTree^.Parent);
  548. CurPTree:=CurPTree^.Next;
  549. CurPTree^.Next:=NPT;
  550. end;
  551. end;
  552. end;
  553. if CurPTree^.CanBeTerminal then
  554. begin
  555. { here we have a conflict !! }
  556. { maybe we should claim }
  557. with CurPTree^ do
  558. begin
  559. {$ifdef DEBUG}
  560. if (ScanValue<>AScan) or (CharValue<>AChar) then
  561. Writeln(system.stderr,'key "',st,'" changed value');
  562. if (ScanValue<>AScan) then
  563. Writeln(system.stderr,'Scan was ',ScanValue,' now ',AScan);
  564. if (CharValue<>AChar) then
  565. Writeln(system.stderr,'Char was ',chr(CharValue),' now ',chr(AChar));
  566. {$endif DEBUG}
  567. ScanValue:=AScan;
  568. CharValue:=AChar;
  569. end;
  570. end
  571. else with CurPTree^ do
  572. begin
  573. CanBeTerminal:=True;
  574. ScanValue:=AScan;
  575. CharValue:=AChar;
  576. end;
  577. DoAddSequence:=CurPTree;
  578. end;
  579. procedure AddSequence(const St : String; AChar,AScan :byte);inline;
  580. begin
  581. DoAddSequence(St,AChar,AScan);
  582. end;
  583. { Returns the Child that as c as char if it exists }
  584. function FindChild(c : byte;Root : PTreeElement) : PTreeElement;
  585. var
  586. NPT : PTreeElement;
  587. begin
  588. NPT:=Root^.Child;
  589. while assigned(NPT) and (NPT^.char<c) do
  590. NPT:=NPT^.Next;
  591. if assigned(NPT) and (NPT^.char=c) then
  592. FindChild:=NPT
  593. else
  594. FindChild:=nil;
  595. end;
  596. function AddSpecialSequence(const St : string;Proc : Tprocedure) : PTreeElement;
  597. var
  598. NPT : PTreeElement;
  599. begin
  600. NPT:=DoAddSequence(St,0,0);
  601. NPT^.SpecialHandler:=Proc;
  602. AddSpecialSequence:=NPT;
  603. end;
  604. function FindSequence(const St : String;var AChar,AScan :byte) : boolean;
  605. var
  606. NPT : PTreeElement;
  607. i : byte;
  608. begin
  609. FindSequence:=false;
  610. AChar:=0;
  611. AScan:=0;
  612. if St='' then
  613. exit;
  614. NPT:=RootTree[St[1]];
  615. if npt<>nil then
  616. begin
  617. for i:=2 to Length(St) do
  618. begin
  619. NPT:=FindChild(ord(St[i]),NPT);
  620. if NPT=nil then
  621. exit;
  622. end;
  623. if NPT^.CanBeTerminal then
  624. begin
  625. FindSequence:=true;
  626. AScan:=NPT^.ScanValue;
  627. AChar:=NPT^.CharValue;
  628. end;
  629. end;
  630. end;
  631. type key_sequence=packed record
  632. char,scan:byte;
  633. st:string[7];
  634. end;
  635. const key_sequences:array[0..211] of key_sequence=(
  636. (char:0;scan:kbAltA;st:#27'A'),
  637. (char:0;scan:kbAltA;st:#27'a'),
  638. (char:0;scan:kbAltB;st:#27'B'),
  639. (char:0;scan:kbAltB;st:#27'b'),
  640. (char:0;scan:kbAltC;st:#27'C'),
  641. (char:0;scan:kbAltC;st:#27'c'),
  642. (char:0;scan:kbAltD;st:#27'D'),
  643. (char:0;scan:kbAltD;st:#27'd'),
  644. (char:0;scan:kbAltE;st:#27'E'),
  645. (char:0;scan:kbAltE;st:#27'e'),
  646. (char:0;scan:kbAltF;st:#27'F'),
  647. (char:0;scan:kbAltF;st:#27'f'),
  648. (char:0;scan:kbAltG;st:#27'G'),
  649. (char:0;scan:kbAltG;st:#27'g'),
  650. (char:0;scan:kbAltH;st:#27'H'),
  651. (char:0;scan:kbAltH;st:#27'h'),
  652. (char:0;scan:kbAltI;st:#27'I'),
  653. (char:0;scan:kbAltI;st:#27'i'),
  654. (char:0;scan:kbAltJ;st:#27'J'),
  655. (char:0;scan:kbAltJ;st:#27'j'),
  656. (char:0;scan:kbAltK;st:#27'K'),
  657. (char:0;scan:kbAltK;st:#27'k'),
  658. (char:0;scan:kbAltL;st:#27'L'),
  659. (char:0;scan:kbAltL;st:#27'l'),
  660. (char:0;scan:kbAltM;st:#27'M'),
  661. (char:0;scan:kbAltM;st:#27'm'),
  662. (char:0;scan:kbAltN;st:#27'N'),
  663. (char:0;scan:kbAltN;st:#27'n'),
  664. (char:0;scan:kbAltO;st:#27'O'),
  665. (char:0;scan:kbAltO;st:#27'o'),
  666. (char:0;scan:kbAltP;st:#27'P'),
  667. (char:0;scan:kbAltP;st:#27'p'),
  668. (char:0;scan:kbAltQ;st:#27'Q'),
  669. (char:0;scan:kbAltQ;st:#27'q'),
  670. (char:0;scan:kbAltR;st:#27'R'),
  671. (char:0;scan:kbAltR;st:#27'r'),
  672. (char:0;scan:kbAltS;st:#27'S'),
  673. (char:0;scan:kbAltS;st:#27's'),
  674. (char:0;scan:kbAltT;st:#27'T'),
  675. (char:0;scan:kbAltT;st:#27't'),
  676. (char:0;scan:kbAltU;st:#27'U'),
  677. (char:0;scan:kbAltU;st:#27'u'),
  678. (char:0;scan:kbAltV;st:#27'V'),
  679. (char:0;scan:kbAltV;st:#27'v'),
  680. (char:0;scan:kbAltW;st:#27'W'),
  681. (char:0;scan:kbAltW;st:#27'w'),
  682. (char:0;scan:kbAltX;st:#27'X'),
  683. (char:0;scan:kbAltX;st:#27'x'),
  684. (char:0;scan:kbAltY;st:#27'Y'),
  685. (char:0;scan:kbAltY;st:#27'y'),
  686. (char:0;scan:kbAltZ;st:#27'Z'),
  687. (char:0;scan:kbAltZ;st:#27'z'),
  688. (char:0;scan:kbAltMinus;st:#27'-'),
  689. (char:0;scan:kbAltEqual;st:#27'='),
  690. (char:0;scan:kbAlt0;st:#27'0'),
  691. (char:0;scan:kbAlt1;st:#27'1'),
  692. (char:0;scan:kbAlt2;st:#27'2'),
  693. (char:0;scan:kbAlt3;st:#27'3'),
  694. (char:0;scan:kbAlt4;st:#27'4'),
  695. (char:0;scan:kbAlt5;st:#27'5'),
  696. (char:0;scan:kbAlt6;st:#27'6'),
  697. (char:0;scan:kbAlt7;st:#27'7'),
  698. (char:0;scan:kbAlt8;st:#27'8'),
  699. (char:0;scan:kbAlt9;st:#27'9'),
  700. (char:0;scan:kbF1;st:#27'[[A'), {linux,konsole,xterm}
  701. (char:0;scan:kbF2;st:#27'[[B'), {linux,konsole,xterm}
  702. (char:0;scan:kbF3;st:#27'[[C'), {linux,konsole,xterm}
  703. (char:0;scan:kbF4;st:#27'[[D'), {linux,konsole,xterm}
  704. (char:0;scan:kbF5;st:#27'[[E'), {linux,konsole}
  705. (char:0;scan:kbEsc;st:#27'[0~'), {if linux keyboard patched, escape
  706. returns this}
  707. (char:0;scan:kbHome;st:#27'[1~'), {linux}
  708. (char:0;scan:kbIns;st:#27'[2~'), {linux,Eterm}
  709. (char:0;scan:kbDel;st:#27'[3~'), {linux,Eterm}
  710. (char:0;scan:kbEnd;st:#27'[4~'), {linux,Eterm}
  711. (char:0;scan:kbPgUp;st:#27'[5~'), {linux,Eterm}
  712. (char:0;scan:kbPgDn;st:#27'[6~'), {linux,Eterm}
  713. (char:0;scan:kbHome;st:#27'[7~'), {Eterm}
  714. (char:0;scan:kbF1;st:#27'[11~'), {Eterm}
  715. (char:0;scan:kbF2;st:#27'[12~'), {Eterm}
  716. (char:0;scan:kbF3;st:#27'[13~'), {Eterm}
  717. (char:0;scan:kbF4;st:#27'[14~'), {Eterm}
  718. (char:0;scan:kbF5;st:#27'[15~'), {xterm,Eterm,gnome}
  719. (char:0;scan:kbF6;st:#27'[17~'), {linux,xterm,Eterm,konsole,gnome}
  720. (char:0;scan:kbF7;st:#27'[18~'), {linux,xterm,Eterm,konsole,gnome}
  721. (char:0;scan:kbF8;st:#27'[19~'), {linux,xterm,Eterm,konsole,gnome}
  722. (char:0;scan:kbF9;st:#27'[20~'), {linux,xterm,Eterm,konsole,gnome}
  723. (char:0;scan:kbF10;st:#27'[21~'), {linux,xterm,Eterm,konsole,gnome}
  724. (char:0;scan:kbF11;st:#27'[23~'), {linux,xterm,Eterm,konsole,gnome}
  725. (char:0;scan:kbF12;st:#27'[24~'), {linux,xterm,Eterm,konsole,gnome}
  726. (char:0;scan:kbShiftF3;st:#27'[25~'), {linux}
  727. (char:0;scan:kbShiftF4;st:#27'[26~'), {linux}
  728. (char:0;scan:kbShiftF5;st:#27'[28~'), {linux}
  729. (char:0;scan:kbShiftF6;st:#27'[29~'), {linux}
  730. (char:0;scan:kbShiftF7;st:#27'[31~'), {linux}
  731. (char:0;scan:kbShiftF8;st:#27'[32~'), {linux}
  732. (char:0;scan:kbShiftF9;st:#27'[33~'), {linux}
  733. (char:0;scan:kbShiftF10;st:#27'[34~'), {linux}
  734. (char:0;scan:kbShiftIns;st:#27'[2;2~'), {should be the code, but shift+ins
  735. is paste X clipboard in many
  736. terminal emulators :(}
  737. (char:0;scan:kbShiftDel;st:#27'[3;2~'), {xterm,konsole}
  738. (char:0;scan:kbShiftF1;st:#27'[11;2~'), {konsole in vt420pc mode}
  739. (char:0;scan:kbShiftF2;st:#27'[12;2~'), {konsole in vt420pc mode}
  740. (char:0;scan:kbShiftF3;st:#27'[13;2~'), {konsole in vt420pc mode}
  741. (char:0;scan:kbShiftF4;st:#27'[14;2~'), {konsole in vt420pc mode}
  742. (char:0;scan:kbShiftF5;st:#27'[15;2~'), {xterm}
  743. (char:0;scan:kbShiftF6;st:#27'[17;2~'), {xterm}
  744. (char:0;scan:kbShiftF7;st:#27'[18;2~'), {xterm}
  745. (char:0;scan:kbShiftF8;st:#27'[19;2~'), {xterm}
  746. (char:0;scan:kbShiftF9;st:#27'[20;2~'), {xterm}
  747. (char:0;scan:kbShiftF10;st:#27'[21;2~'), {xterm}
  748. (char:0;scan:kbShiftF11;st:#27'[23;2~'), {xterm}
  749. (char:0;scan:kbShiftF12;st:#27'[24;2~'), {xterm}
  750. (char:0;scan:kbCtrlIns;st:#27'[2;5~'), {xterm}
  751. (char:0;scan:kbCtrlDel;st:#27'[3;5~'), {xterm}
  752. (char:0;scan:kbAltF1;st:#27#27'[[A'),
  753. (char:0;scan:kbAltF2;st:#27#27'[[B'),
  754. (char:0;scan:kbAltF3;st:#27#27'[[C'),
  755. (char:0;scan:kbAltF4;st:#27#27'[[D'),
  756. (char:0;scan:kbAltF5;st:#27#27'[[E'),
  757. (char:0;scan:kbAltF6;st:#27#27'[17~'),
  758. (char:0;scan:kbAltF7;st:#27#27'[18~'),
  759. (char:0;scan:kbAltF8;st:#27#27'[19~'),
  760. (char:0;scan:kbAltF9;st:#27#27'[20~'),
  761. (char:0;scan:kbAltF10;st:#27#27'[21~'),
  762. (char:0;scan:kbAltF11;st:#27#27'[23~'),
  763. (char:0;scan:kbAltF12;st:#27#27'[24~'),
  764. (char:0;scan:kbUp;st:#27'[A'), {linux,FreeBSD}
  765. (char:0;scan:kbDown;st:#27'[B'), {linux,FreeBSD}
  766. (char:0;scan:kbRight;st:#27'[C'), {linux,FreeBSD}
  767. (char:0;scan:kbLeft;st:#27'[D'), {linux,FreeBSD}
  768. (char:0;scan:kbEnd;st:#27'[F'), {FreeBSD}
  769. (char:0;scan:kbPgdn;st:#27'[G'), {FreeBSD}
  770. (char:0;scan:kbHome;st:#27'[H'), {FreeBSD}
  771. (char:0;scan:kbPgup;st:#27'[I'), {FreeBSD}
  772. (char:0;scan:kbF1;st:#27'[M'), {FreeBSD}
  773. (char:0;scan:kbF2;st:#27'[N'), {FreeBSD}
  774. (char:0;scan:kbF3;st:#27'[O'), {FreeBSD}
  775. (char:0;scan:kbF4;st:#27'[P'), {FreeBSD}
  776. (char:0;scan:kbF5;st:#27'[Q'), {FreeBSD}
  777. (char:0;scan:kbF6;st:#27'[R'), {FreeBSD}
  778. (char:0;scan:kbF7;st:#27'[S'), {FreeBSD}
  779. (char:0;scan:kbF8;st:#27'[T'), {FreeBSD}
  780. (char:0;scan:kbF9;st:#27'[U'), {FreeBSD}
  781. (char:0;scan:kbF10;st:#27'[V'), {FreeBSD}
  782. (char:0;scan:kbF11;st:#27'[W'), {FreeBSD}
  783. (char:0;scan:kbF12;st:#27'[X'), {FreeBSD}
  784. (char:0;scan:kbShiftTab;st:#27'[Z'),
  785. (char:0;scan:kbShiftUp;st:#27'[1;2A'), {xterm}
  786. (char:0;scan:kbShiftDown;st:#27'[1;2B'), {xterm}
  787. (char:0;scan:kbShiftRight;st:#27'[1;2C'), {xterm}
  788. (char:0;scan:kbShiftLeft;st:#27'[1;2D'), {xterm}
  789. (char:0;scan:kbShiftEnd;st:#27'[1;2F'), {xterm}
  790. (char:0;scan:kbShiftHome;st:#27'[1;2H'), {xterm}
  791. (char:0;scan:kbCtrlUp;st:#27'[1;5A'), {xterm}
  792. (char:0;scan:kbCtrlDown;st:#27'[1;5B'), {xterm}
  793. (char:0;scan:kbCtrlRight;st:#27'[1;5C'), {xterm}
  794. (char:0;scan:kbCtrlLeft;st:#27'[1;5D'), {xterm}
  795. (char:0;scan:kbCtrlEnd;st:#27'[1;5F'), {xterm}
  796. (char:0;scan:kbCtrlHome;st:#27'[1;5H'), {xterm}
  797. (char:0;scan:kbAltUp;st:#27#27'[A'),
  798. (char:0;scan:kbAltDown;st:#27#27'[B'),
  799. (char:0;scan:kbAltLeft;st:#27#27'[D'),
  800. (char:0;scan:kbAltRight;st:#27#27'[C'),
  801. (char:0;scan:kbAltPgUp;st:#27#27'[5~'),
  802. (char:0;scan:kbAltPgDn;st:#27#27'[6~'),
  803. (char:0;scan:kbAltEnd;st:#27#27'[4~'),
  804. (char:0;scan:kbAltHome;st:#27#27'[1~'),
  805. (char:0;scan:kbAltIns;st:#27#27'[2~'),
  806. (char:0;scan:kbAltDel;st:#27#27'[3~'),
  807. (char:0;scan:kbUp;st:#27'OA'), {xterm}
  808. (char:0;scan:kbDown;st:#27'OB'), {xterm}
  809. (char:0;scan:kbRight;st:#27'OC'), {xterm}
  810. (char:0;scan:kbLeft;st:#27'OD'), {xterm}
  811. (char:0;scan:kbHome;st:#27'OF'), {some xterm configurations}
  812. (char:0;scan:kbEnd;st:#27'OH'), {some xterm configurations}
  813. (char:0;scan:kbF1;st:#27'OP'), {vt100,gnome,konsole}
  814. (char:0;scan:kbF2;st:#27'OQ'), {vt100,gnome,konsole}
  815. (char:0;scan:kbF3;st:#27'OR'), {vt100,gnome,konsole}
  816. (char:0;scan:kbF4;st:#27'OS'), {vt100,gnome,konsole}
  817. (char:0;scan:kbF5;st:#27'Ot'), {vt100}
  818. (char:0;scan:kbF6;st:#27'Ou'), {vt100}
  819. (char:0;scan:kbF7;st:#27'Ov'), {vt100}
  820. (char:0;scan:kbF8;st:#27'Ol'), {vt100}
  821. (char:0;scan:kbF9;st:#27'Ow'), {vt100}
  822. (char:0;scan:kbF10;st:#27'Ox'), {vt100}
  823. (char:0;scan:kbF11;st:#27'Oy'), {vt100}
  824. (char:0;scan:kbF12;st:#27'Oz'), {vt100}
  825. (char:0;scan:kbShiftF1;st:#27'O2P'), {konsole,xterm}
  826. (char:0;scan:kbShiftF2;st:#27'O2Q'), {konsole,xterm}
  827. (char:0;scan:kbShiftF3;st:#27'O2R'), {konsole,xterm}
  828. (char:0;scan:kbShiftF4;st:#27'O2S'), {konsole,xterm}
  829. (char:0;scan:kbAltF1;st:#27#27'OP'),
  830. (char:0;scan:kbAltF2;st:#27#27'OQ'),
  831. (char:0;scan:kbAltF3;st:#27#27'OR'),
  832. (char:0;scan:kbAltF4;st:#27#27'OS'),
  833. (char:0;scan:kbAltF5;st:#27#27'Ot'),
  834. (char:0;scan:kbAltF6;st:#27#27'Ou'),
  835. (char:0;scan:kbAltF7;st:#27#27'Ov'),
  836. (char:0;scan:kbAltF8;st:#27#27'Ol'),
  837. (char:0;scan:kbAltF9;st:#27#27'Ow'),
  838. (char:0;scan:kbAltF10;st:#27#27'Ox'),
  839. (char:0;scan:kbAltF11;st:#27#27'Oy'),
  840. (char:0;scan:kbAltF12;st:#27#27'Oz'),
  841. (char:0;scan:kbAltUp;st:#27#27'OA'),
  842. (char:0;scan:kbAltDown;st:#27#27'OB'),
  843. (char:0;scan:kbAltRight;st:#27#27'OC'),
  844. (char:0;scan:kbAltLeft;st:#27#27'OD'),
  845. { xterm default values }
  846. { xterm alternate default values }
  847. { ignored sequences }
  848. (char:0;scan:0;st:#27'[?1;0c'),
  849. (char:0;scan:0;st:#27'[?1l'),
  850. (char:0;scan:0;st:#27'[?1h'),
  851. (char:0;scan:0;st:#27'[?1;2c'),
  852. (char:0;scan:0;st:#27'[?7l'),
  853. (char:0;scan:0;st:#27'[?7h')
  854. );
  855. procedure LoadDefaultSequences;
  856. var i:cardinal;
  857. begin
  858. AddSpecialSequence(#27'[M',@GenMouseEvent);
  859. {Unix backspace/delete hell... Is #127 a backspace or delete?}
  860. if copy(fpgetenv('TERM'),1,4)='cons' then
  861. begin
  862. {FreeBSD is until now only terminal that uses it for delete.}
  863. DoAddSequence(#127,0,kbDel); {Delete}
  864. DoAddSequence(#27#127,0,kbAltDel); {Alt+delete}
  865. end
  866. else
  867. begin
  868. DoAddSequence(#127,8,0); {Backspace}
  869. DoAddSequence(#27#127,0,kbAltBack); {Alt+backspace}
  870. end;
  871. { all Esc letter }
  872. for i:=low(key_sequences) to high(key_sequences) do
  873. with key_sequences[i] do
  874. DoAddSequence(st,char,scan);
  875. end;
  876. function RawReadKey:char;
  877. var
  878. fdsin : tfdSet;
  879. begin
  880. {Check Buffer first}
  881. if KeySend<>KeyPut then
  882. begin
  883. RawReadKey:=PopKey;
  884. exit;
  885. end;
  886. {Wait for Key}
  887. if not sysKeyPressed then
  888. begin
  889. fpFD_ZERO (fdsin);
  890. fpFD_SET (StdInputHandle,fdsin);
  891. fpSelect (StdInputHandle+1,@fdsin,nil,nil,nil);
  892. end;
  893. RawReadKey:=ttyRecvChar;
  894. end;
  895. function RawReadString : String;
  896. var
  897. ch : char;
  898. fdsin : tfdSet;
  899. St : String;
  900. begin
  901. St:=RawReadKey;
  902. fpFD_ZERO (fdsin);
  903. fpFD_SET (StdInputHandle,fdsin);
  904. Repeat
  905. if inhead=intail then
  906. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  907. if SysKeyPressed then
  908. ch:=ttyRecvChar
  909. else
  910. ch:=#0;
  911. if ch<>#0 then
  912. St:=St+ch;
  913. Until ch=#0;
  914. RawReadString:=St;
  915. end;
  916. function ReadKey(var IsAlt : boolean):char;
  917. var
  918. ch : char;
  919. is_delay : boolean;
  920. fdsin : tfdSet;
  921. store : array [0..8] of char;
  922. arrayind : byte;
  923. NPT,NNPT : PTreeElement;
  924. procedure GenMouseEvent;
  925. var MouseEvent: TMouseEvent;
  926. begin
  927. Fillchar(MouseEvent,SizeOf(TMouseEvent),#0);
  928. case ch of
  929. #32 : {left button pressed }
  930. MouseEvent.buttons:=1;
  931. #33 : {middle button pressed }
  932. MouseEvent.buttons:=2;
  933. #34 : { right button pressed }
  934. MouseEvent.buttons:=4;
  935. #35 : { no button pressed };
  936. end;
  937. if inhead=intail then
  938. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  939. ch:=ttyRecvChar;
  940. MouseEvent.x:=Ord(ch)-ord(' ')-1;
  941. if inhead=intail then
  942. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  943. ch:=ttyRecvChar;
  944. MouseEvent.y:=Ord(ch)-ord(' ')-1;
  945. if (MouseEvent.buttons<>0) then
  946. MouseEvent.action:=MouseActionDown
  947. else
  948. begin
  949. if (LastMouseEvent.Buttons<>0) and
  950. ((LastMouseEvent.X<>MouseEvent.X) or (LastMouseEvent.Y<>MouseEvent.Y)) then
  951. begin
  952. MouseEvent.Action:=MouseActionMove;
  953. MouseEvent.Buttons:=LastMouseEvent.Buttons;
  954. PutMouseEvent(MouseEvent);
  955. MouseEvent.Buttons:=0;
  956. end;
  957. MouseEvent.Action:=MouseActionUp;
  958. end;
  959. PutMouseEvent(MouseEvent);
  960. LastMouseEvent:=MouseEvent;
  961. end;
  962. procedure RestoreArray;
  963. var
  964. i : byte;
  965. begin
  966. for i:=0 to arrayind-1 do
  967. PushKey(store[i]);
  968. end;
  969. begin
  970. IsAlt:=false;
  971. {Check Buffer first}
  972. if KeySend<>KeyPut then
  973. begin
  974. ReadKey:=PopKey;
  975. exit;
  976. end;
  977. {Wait for Key}
  978. if not sysKeyPressed then
  979. begin
  980. fpFD_ZERO (fdsin);
  981. fpFD_SET (StdInputHandle,fdsin);
  982. fpSelect (StdInputHandle+1,@fdsin,nil,nil,nil);
  983. end;
  984. ch:=ttyRecvChar;
  985. NPT:=RootTree[ch];
  986. if not assigned(NPT) then
  987. PushKey(ch)
  988. else
  989. begin
  990. fpFD_ZERO(fdsin);
  991. fpFD_SET(StdInputHandle,fdsin);
  992. store[0]:=ch;
  993. arrayind:=1;
  994. while assigned(NPT) and syskeypressed do
  995. begin
  996. if inhead=intail then
  997. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  998. ch:=ttyRecvChar;
  999. NNPT:=FindChild(ord(ch),NPT);
  1000. if assigned(NNPT) then
  1001. begin
  1002. NPT:=NNPT;
  1003. if NPT^.CanBeTerminal and
  1004. assigned(NPT^.SpecialHandler) then
  1005. break;
  1006. End;
  1007. if ch<>#0 then
  1008. begin
  1009. store[arrayind]:=ch;
  1010. inc(arrayind);
  1011. end;
  1012. if not assigned(NNPT) then
  1013. begin
  1014. if ch<>#0 then
  1015. begin
  1016. { Put that unused char back into InBuf }
  1017. If InTail=0 then
  1018. InTail:=InSize-1
  1019. else
  1020. Dec(InTail);
  1021. InBuf[InTail]:=ch;
  1022. end;
  1023. break;
  1024. end;
  1025. end;
  1026. if assigned(NPT) and NPT^.CanBeTerminal then
  1027. begin
  1028. if assigned(NPT^.SpecialHandler) then
  1029. begin
  1030. NPT^.SpecialHandler;
  1031. PushExt(0);
  1032. end
  1033. else if NPT^.CharValue<>0 then
  1034. PushKey(chr(NPT^.CharValue))
  1035. else if NPT^.ScanValue<>0 then
  1036. PushExt(NPT^.ScanValue);
  1037. end
  1038. else
  1039. RestoreArray;
  1040. end
  1041. {$ifdef logging}
  1042. writeln(f);
  1043. {$endif logging}
  1044. ;
  1045. ReadKey:=PopKey;
  1046. End;
  1047. {$ifdef linux}
  1048. function ShiftState:byte;
  1049. var arg:longint;
  1050. begin
  1051. shiftstate:=0;
  1052. arg:=6;
  1053. if fpioctl(StdInputHandle,TIOCLINUX,@arg)=0 then
  1054. begin
  1055. if (arg and 8)<>0 then
  1056. shiftstate:=kbAlt;
  1057. if (arg and 4)<>0 then
  1058. inc(shiftstate,kbCtrl);
  1059. { 2 corresponds to AltGr so set both kbAlt and kbCtrl PM }
  1060. if (arg and 2)<>0 then
  1061. shiftstate:=shiftstate or (kbAlt or kbCtrl);
  1062. if (arg and 1)<>0 then
  1063. inc(shiftstate,kbShift);
  1064. end;
  1065. end;
  1066. procedure force_linuxtty;
  1067. var s:string[15];
  1068. handle:sizeint;
  1069. thistty:string;
  1070. begin
  1071. is_console:=false;
  1072. if vcs_device<>-1 then
  1073. begin
  1074. { running on a tty, find out whether locally or remotely }
  1075. thistty:=ttyname(stdinputhandle);
  1076. if (copy(thistty,1,8)<>'/dev/tty') or not (thistty[9] in ['0'..'9']) then
  1077. begin
  1078. {Running from Midnight Commander or something... Bypass it.}
  1079. str(vcs_device,s);
  1080. handle:=fpopen('/dev/tty'+s,O_RDWR);
  1081. fpioctl(stdinputhandle,TIOCNOTTY,nil);
  1082. {This will currently only work when the user is root :(}
  1083. fpioctl(handle,TIOCSCTTY,nil);
  1084. if errno<>0 then
  1085. exit;
  1086. fpclose(stdinputhandle);
  1087. fpclose(stdoutputhandle);
  1088. fpclose(stderrorhandle);
  1089. fpdup2(handle,stdinputhandle);
  1090. fpdup2(handle,stdoutputhandle);
  1091. fpdup2(handle,stderrorhandle);
  1092. fpclose(handle);
  1093. end;
  1094. is_console:=true;
  1095. end;
  1096. end;
  1097. {$endif linux}
  1098. { Exported functions }
  1099. procedure SysInitKeyboard;
  1100. begin
  1101. SetRawMode(true);
  1102. {$ifdef logging}
  1103. assign(f,'keyboard.log');
  1104. rewrite(f);
  1105. {$endif logging}
  1106. {$ifdef linux}
  1107. force_linuxtty;
  1108. prepare_patching;
  1109. patchkeyboard;
  1110. if is_console then
  1111. install_vt_handler
  1112. else
  1113. begin
  1114. {$endif}
  1115. { default for Shift prefix is ^ A}
  1116. if ShiftPrefix = 0 then
  1117. ShiftPrefix:=1;
  1118. {default for Alt prefix is ^Z }
  1119. if AltPrefix=0 then
  1120. AltPrefix:=26;
  1121. { default for Ctrl Prefix is ^W }
  1122. if CtrlPrefix=0 then
  1123. CtrlPrefix:=23;
  1124. {$ifdef linux}
  1125. end;
  1126. {$endif}
  1127. LoadDefaultSequences;
  1128. { LoadTerminfoSequences;}
  1129. end;
  1130. procedure SysDoneKeyboard;
  1131. begin
  1132. {$ifdef linux}
  1133. unpatchkeyboard;
  1134. {$endif linux}
  1135. SetRawMode(false);
  1136. FreeTree;
  1137. {$ifdef logging}
  1138. close(f);
  1139. {$endif logging}
  1140. end;
  1141. function SysGetKeyEvent: TKeyEvent;
  1142. function EvalScan(b:byte):byte;
  1143. const
  1144. DScan:array[0..31] of byte = (
  1145. $39, $02, $28, $04, $05, $06, $08, $28,
  1146. $0A, $0B, $09, $0D, $33, $0C, $34, $35,
  1147. $0B, $02, $03, $04, $05, $06, $07, $08,
  1148. $09, $0A, $27, $27, $33, $0D, $34, $35);
  1149. LScan:array[0..31] of byte = (
  1150. $29, $1E, $30, $2E, $20, $12, $21, $22,
  1151. $23, $17, $24, $25, $26, $32, $31, $18,
  1152. $19, $10, $13, $1F, $14, $16, $2F, $11,
  1153. $2D, $15, $2C, $1A, $2B, $1B, $29, $0C);
  1154. begin
  1155. if (b and $E0)=$20 { digits / leters } then
  1156. EvalScan:=DScan[b and $1F]
  1157. else
  1158. case b of
  1159. $08:EvalScan:=$0E; { backspace }
  1160. $09:EvalScan:=$0F; { TAB }
  1161. $0D:EvalScan:=$1C; { CR }
  1162. $1B:EvalScan:=$01; { esc }
  1163. $40:EvalScan:=$03; { @ }
  1164. $5E:EvalScan:=$07; { ^ }
  1165. $60:EvalScan:=$29; { ` }
  1166. else
  1167. EvalScan:=LScan[b and $1F];
  1168. end;
  1169. end;
  1170. function EvalScanZ(b:byte):byte;
  1171. begin
  1172. EvalScanZ:=b;
  1173. if b in [$3B..$44] { F1..F10 -> Alt-F1..Alt-F10} then
  1174. EvalScanZ:=b+$2D;
  1175. end;
  1176. const
  1177. {kbHome, kbUp, kbPgUp,Missing, kbLeft,
  1178. kbCenter, kbRight, kbAltGrayPlus, kbend,
  1179. kbDown, kbPgDn, kbIns, kbDel }
  1180. CtrlArrow : array [kbHome..kbDel] of byte =
  1181. {($77,$8d,$84,$8e,$73,$8f,$74,$90,$75,$91,$76);}
  1182. (kbCtrlHome,kbCtrlUp,kbCtrlPgUp,kbNoKey,kbCtrlLeft,
  1183. kbCtrlCenter,kbCtrlRight,kbAltGrayPlus,kbCtrlEnd,
  1184. kbCtrlDown,kbCtrlPgDn,kbCtrlIns,kbCtrlDel);
  1185. AltArrow : array [kbHome..kbDel] of byte =
  1186. (kbAltHome,kbAltUp,kbAltPgUp,kbNoKey,kbAltLeft,
  1187. kbCenter,kbAltRight,kbAltGrayPlus,kbAltEnd,
  1188. kbAltDown,kbAltPgDn,kbAltIns,kbAltDel);
  1189. ShiftArrow : array [kbShiftUp..kbShiftEnd] of byte =
  1190. (kbUp,kbLeft,kbRight,kbDown,kbHome,kbEnd);
  1191. var
  1192. MyScan:byte;
  1193. MyChar : char;
  1194. EscUsed,AltPrefixUsed,CtrlPrefixUsed,ShiftPrefixUsed,IsAlt,Again : boolean;
  1195. SState:byte;
  1196. begin {main}
  1197. MyChar:=Readkey(IsAlt);
  1198. MyScan:=ord(MyChar);
  1199. {$ifdef linux}
  1200. if is_console then
  1201. SState:=ShiftState
  1202. else
  1203. {$endif}
  1204. Sstate:=0;
  1205. CtrlPrefixUsed:=false;
  1206. AltPrefixUsed:=false;
  1207. ShiftPrefixUsed:=false;
  1208. EscUsed:=false;
  1209. if IsAlt then
  1210. SState:=SState or kbAlt;
  1211. repeat
  1212. again:=false;
  1213. if Mychar=#0 then
  1214. begin
  1215. MyScan:=ord(ReadKey(IsAlt));
  1216. if myscan=$01 then
  1217. mychar:=#27;
  1218. { Handle Ctrl-<x>, but not AltGr-<x> }
  1219. if ((SState and kbCtrl)<>0) and ((SState and kbAlt) = 0) then
  1220. case MyScan of
  1221. kbHome..kbDel : { cArrow }
  1222. MyScan:=CtrlArrow[MyScan];
  1223. kbF1..KbF10 : { cF1-cF10 }
  1224. MyScan:=MyScan+kbCtrlF1-kbF1;
  1225. kbF11..KbF12 : { cF11-cF12 }
  1226. MyScan:=MyScan+kbCtrlF11-kbF11;
  1227. end
  1228. { Handle Alt-<x>, but not AltGr }
  1229. else if ((SState and kbAlt)<>0) and ((SState and kbCtrl) = 0) then
  1230. case MyScan of
  1231. kbHome..kbDel : { AltArrow }
  1232. MyScan:=AltArrow[MyScan];
  1233. kbF1..KbF10 : { aF1-aF10 }
  1234. MyScan:=MyScan+kbAltF1-kbF1;
  1235. kbF11..KbF12 : { aF11-aF12 }
  1236. MyScan:=MyScan+kbAltF11-kbF11;
  1237. end
  1238. else if (SState and kbShift)<>0 then
  1239. case MyScan of
  1240. kbIns: MyScan:=kbShiftIns;
  1241. kbDel: MyScan:=kbShiftDel;
  1242. kbF1..KbF10 : { sF1-sF10 }
  1243. MyScan:=MyScan+kbShiftF1-kbF1;
  1244. kbF11..KbF12 : { sF11-sF12 }
  1245. MyScan:=MyScan+kbShiftF11-kbF11;
  1246. end;
  1247. if myscan in [kbShiftUp..kbShiftEnd] then
  1248. begin
  1249. myscan:=ShiftArrow[myscan];
  1250. sstate:=sstate or kbshift;
  1251. end;
  1252. if myscan=kbAltBack then
  1253. sstate:=sstate or kbalt;
  1254. if (MyChar<>#0) or (MyScan<>0) or (SState<>0) then
  1255. SysGetKeyEvent:=$3000000 or ord(MyChar) or (MyScan shl 8) or (SState shl 16)
  1256. else
  1257. SysGetKeyEvent:=0;
  1258. exit;
  1259. end
  1260. else if MyChar=#27 then
  1261. begin
  1262. if EscUsed then
  1263. SState:=SState and not kbAlt
  1264. else
  1265. begin
  1266. SState:=SState or kbAlt;
  1267. Again:=true;
  1268. EscUsed:=true;
  1269. end;
  1270. end
  1271. else if (AltPrefix<>0) and (MyChar=chr(AltPrefix)) then
  1272. begin { ^Z - replace Alt for Linux OS }
  1273. if AltPrefixUsed then
  1274. begin
  1275. SState:=SState and not kbAlt;
  1276. end
  1277. else
  1278. begin
  1279. AltPrefixUsed:=true;
  1280. SState:=SState or kbAlt;
  1281. Again:=true;
  1282. end;
  1283. end
  1284. else if (CtrlPrefix<>0) and (MyChar=chr(CtrlPrefix)) then
  1285. begin
  1286. if CtrlPrefixUsed then
  1287. SState:=SState and not kbCtrl
  1288. else
  1289. begin
  1290. CtrlPrefixUsed:=true;
  1291. SState:=SState or kbCtrl;
  1292. Again:=true;
  1293. end;
  1294. end
  1295. else if (ShiftPrefix<>0) and (MyChar=chr(ShiftPrefix)) then
  1296. begin
  1297. if ShiftPrefixUsed then
  1298. SState:=SState and not kbShift
  1299. else
  1300. begin
  1301. ShiftPrefixUsed:=true;
  1302. SState:=SState or kbShift;
  1303. Again:=true;
  1304. end;
  1305. end;
  1306. if not again then
  1307. begin
  1308. MyScan:=EvalScan(ord(MyChar));
  1309. if ((SState and kbAlt)<>0) and ((SState and kbCtrl) = 0) then
  1310. begin
  1311. if MyScan in [$02..$0D] then
  1312. inc(MyScan,$76);
  1313. MyChar:=chr(0);
  1314. end
  1315. else if (SState and kbShift)<>0 then
  1316. if MyChar=#9 then
  1317. begin
  1318. MyChar:=#0;
  1319. MyScan:=kbShiftTab;
  1320. end;
  1321. end
  1322. else
  1323. begin
  1324. MyChar:=Readkey(IsAlt);
  1325. MyScan:=ord(MyChar);
  1326. if IsAlt then
  1327. SState:=SState or kbAlt;
  1328. end;
  1329. until not Again;
  1330. if (MyChar<>#0) or (MyScan<>0) or (SState<>0) then
  1331. SysGetKeyEvent:=$3000000 or ord(MyChar) or (MyScan shl 8) or (SState shl 16)
  1332. else
  1333. SysGetKeyEvent:=0;
  1334. end;
  1335. function SysPollKeyEvent: TKeyEvent;
  1336. var
  1337. KeyEvent : TKeyEvent;
  1338. begin
  1339. if keypressed then
  1340. begin
  1341. KeyEvent:=SysGetKeyEvent;
  1342. PutKeyEvent(KeyEvent);
  1343. SysPollKeyEvent:=KeyEvent
  1344. end
  1345. else
  1346. SysPollKeyEvent:=0;
  1347. end;
  1348. function SysGetShiftState : Byte;
  1349. begin
  1350. {$ifdef linux}
  1351. if is_console then
  1352. SysGetShiftState:=ShiftState
  1353. else
  1354. {$else}
  1355. SysGetShiftState:=0;
  1356. {$endif}
  1357. end;
  1358. procedure RestoreStartMode;
  1359. begin
  1360. TCSetAttr(1,TCSANOW,StartTio);
  1361. end;
  1362. const
  1363. SysKeyboardDriver : TKeyboardDriver = (
  1364. InitDriver : @SysInitKeyBoard;
  1365. DoneDriver : @SysDoneKeyBoard;
  1366. GetKeyevent : @SysGetKeyEvent;
  1367. PollKeyEvent : @SysPollKeyEvent;
  1368. GetShiftState : @SysGetShiftState;
  1369. TranslateKeyEvent : Nil;
  1370. TranslateKeyEventUnicode : Nil;
  1371. );
  1372. begin
  1373. SetKeyBoardDriver(SysKeyBoardDriver);
  1374. TCGetAttr(1,StartTio);
  1375. end.