keyboard.pp 45 KB

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