keyboard.pp 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492
  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 : byte;
  606. begin
  607. FindSequence:=false;
  608. AChar:=0;
  609. AScan:=0;
  610. if St='' then
  611. exit;
  612. NPT:=RootTree[St[1]];
  613. if npt<>nil then
  614. begin
  615. for i:=2 to Length(St) do
  616. begin
  617. NPT:=FindChild(ord(St[i]),NPT);
  618. if NPT=nil then
  619. exit;
  620. end;
  621. if NPT^.CanBeTerminal then
  622. begin
  623. FindSequence:=true;
  624. AScan:=NPT^.ScanValue;
  625. AChar:=NPT^.CharValue;
  626. end;
  627. end;
  628. end;
  629. type key_sequence=packed record
  630. char,scan:byte;
  631. st:string[7];
  632. end;
  633. const key_sequences:array[0..211] of key_sequence=(
  634. (char:0;scan:kbAltA;st:#27'A'),
  635. (char:0;scan:kbAltA;st:#27'a'),
  636. (char:0;scan:kbAltB;st:#27'B'),
  637. (char:0;scan:kbAltB;st:#27'b'),
  638. (char:0;scan:kbAltC;st:#27'C'),
  639. (char:0;scan:kbAltC;st:#27'c'),
  640. (char:0;scan:kbAltD;st:#27'D'),
  641. (char:0;scan:kbAltD;st:#27'd'),
  642. (char:0;scan:kbAltE;st:#27'E'),
  643. (char:0;scan:kbAltE;st:#27'e'),
  644. (char:0;scan:kbAltF;st:#27'F'),
  645. (char:0;scan:kbAltF;st:#27'f'),
  646. (char:0;scan:kbAltG;st:#27'G'),
  647. (char:0;scan:kbAltG;st:#27'g'),
  648. (char:0;scan:kbAltH;st:#27'H'),
  649. (char:0;scan:kbAltH;st:#27'h'),
  650. (char:0;scan:kbAltI;st:#27'I'),
  651. (char:0;scan:kbAltI;st:#27'i'),
  652. (char:0;scan:kbAltJ;st:#27'J'),
  653. (char:0;scan:kbAltJ;st:#27'j'),
  654. (char:0;scan:kbAltK;st:#27'K'),
  655. (char:0;scan:kbAltK;st:#27'k'),
  656. (char:0;scan:kbAltL;st:#27'L'),
  657. (char:0;scan:kbAltL;st:#27'l'),
  658. (char:0;scan:kbAltM;st:#27'M'),
  659. (char:0;scan:kbAltM;st:#27'm'),
  660. (char:0;scan:kbAltN;st:#27'N'),
  661. (char:0;scan:kbAltN;st:#27'n'),
  662. (char:0;scan:kbAltO;st:#27'O'),
  663. (char:0;scan:kbAltO;st:#27'o'),
  664. (char:0;scan:kbAltP;st:#27'P'),
  665. (char:0;scan:kbAltP;st:#27'p'),
  666. (char:0;scan:kbAltQ;st:#27'Q'),
  667. (char:0;scan:kbAltQ;st:#27'q'),
  668. (char:0;scan:kbAltR;st:#27'R'),
  669. (char:0;scan:kbAltR;st:#27'r'),
  670. (char:0;scan:kbAltS;st:#27'S'),
  671. (char:0;scan:kbAltS;st:#27's'),
  672. (char:0;scan:kbAltT;st:#27'T'),
  673. (char:0;scan:kbAltT;st:#27't'),
  674. (char:0;scan:kbAltU;st:#27'U'),
  675. (char:0;scan:kbAltU;st:#27'u'),
  676. (char:0;scan:kbAltV;st:#27'V'),
  677. (char:0;scan:kbAltV;st:#27'v'),
  678. (char:0;scan:kbAltW;st:#27'W'),
  679. (char:0;scan:kbAltW;st:#27'w'),
  680. (char:0;scan:kbAltX;st:#27'X'),
  681. (char:0;scan:kbAltX;st:#27'x'),
  682. (char:0;scan:kbAltY;st:#27'Y'),
  683. (char:0;scan:kbAltY;st:#27'y'),
  684. (char:0;scan:kbAltZ;st:#27'Z'),
  685. (char:0;scan:kbAltZ;st:#27'z'),
  686. (char:0;scan:kbAltMinus;st:#27'-'),
  687. (char:0;scan:kbAltEqual;st:#27'='),
  688. (char:0;scan:kbAlt0;st:#27'0'),
  689. (char:0;scan:kbAlt1;st:#27'1'),
  690. (char:0;scan:kbAlt2;st:#27'2'),
  691. (char:0;scan:kbAlt3;st:#27'3'),
  692. (char:0;scan:kbAlt4;st:#27'4'),
  693. (char:0;scan:kbAlt5;st:#27'5'),
  694. (char:0;scan:kbAlt6;st:#27'6'),
  695. (char:0;scan:kbAlt7;st:#27'7'),
  696. (char:0;scan:kbAlt8;st:#27'8'),
  697. (char:0;scan:kbAlt9;st:#27'9'),
  698. (char:0;scan:kbF1;st:#27'[[A'), {linux,konsole,xterm}
  699. (char:0;scan:kbF2;st:#27'[[B'), {linux,konsole,xterm}
  700. (char:0;scan:kbF3;st:#27'[[C'), {linux,konsole,xterm}
  701. (char:0;scan:kbF4;st:#27'[[D'), {linux,konsole,xterm}
  702. (char:0;scan:kbF5;st:#27'[[E'), {linux,konsole}
  703. (char:0;scan:kbEsc;st:#27'[0~'), {if linux keyboard patched, escape
  704. returns this}
  705. (char:0;scan:kbHome;st:#27'[1~'), {linux}
  706. (char:0;scan:kbIns;st:#27'[2~'), {linux,Eterm}
  707. (char:0;scan:kbDel;st:#27'[3~'), {linux,Eterm}
  708. (char:0;scan:kbEnd;st:#27'[4~'), {linux,Eterm}
  709. (char:0;scan:kbPgUp;st:#27'[5~'), {linux,Eterm}
  710. (char:0;scan:kbPgDn;st:#27'[6~'), {linux,Eterm}
  711. (char:0;scan:kbHome;st:#27'[7~'), {Eterm}
  712. (char:0;scan:kbF1;st:#27'[11~'), {Eterm}
  713. (char:0;scan:kbF2;st:#27'[12~'), {Eterm}
  714. (char:0;scan:kbF3;st:#27'[13~'), {Eterm}
  715. (char:0;scan:kbF4;st:#27'[14~'), {Eterm}
  716. (char:0;scan:kbF5;st:#27'[15~'), {xterm,Eterm,gnome}
  717. (char:0;scan:kbF6;st:#27'[17~'), {linux,xterm,Eterm,konsole,gnome}
  718. (char:0;scan:kbF7;st:#27'[18~'), {linux,xterm,Eterm,konsole,gnome}
  719. (char:0;scan:kbF8;st:#27'[19~'), {linux,xterm,Eterm,konsole,gnome}
  720. (char:0;scan:kbF9;st:#27'[20~'), {linux,xterm,Eterm,konsole,gnome}
  721. (char:0;scan:kbF10;st:#27'[21~'), {linux,xterm,Eterm,konsole,gnome}
  722. (char:0;scan:kbF11;st:#27'[23~'), {linux,xterm,Eterm,konsole,gnome}
  723. (char:0;scan:kbF12;st:#27'[24~'), {linux,xterm,Eterm,konsole,gnome}
  724. (char:0;scan:kbShiftF3;st:#27'[25~'), {linux}
  725. (char:0;scan:kbShiftF4;st:#27'[26~'), {linux}
  726. (char:0;scan:kbShiftF5;st:#27'[28~'), {linux}
  727. (char:0;scan:kbShiftF6;st:#27'[29~'), {linux}
  728. (char:0;scan:kbShiftF7;st:#27'[31~'), {linux}
  729. (char:0;scan:kbShiftF8;st:#27'[32~'), {linux}
  730. (char:0;scan:kbShiftF9;st:#27'[33~'), {linux}
  731. (char:0;scan:kbShiftF10;st:#27'[34~'), {linux}
  732. (char:0;scan:kbShiftIns;st:#27'[2;2~'), {should be the code, but shift+ins
  733. is paste X clipboard in many
  734. terminal emulators :(}
  735. (char:0;scan:kbShiftDel;st:#27'[3;2~'), {xterm,konsole}
  736. (char:0;scan:kbShiftF1;st:#27'[11;2~'), {konsole in vt420pc mode}
  737. (char:0;scan:kbShiftF2;st:#27'[12;2~'), {konsole in vt420pc mode}
  738. (char:0;scan:kbShiftF3;st:#27'[13;2~'), {konsole in vt420pc mode}
  739. (char:0;scan:kbShiftF4;st:#27'[14;2~'), {konsole in vt420pc mode}
  740. (char:0;scan:kbShiftF5;st:#27'[15;2~'), {xterm}
  741. (char:0;scan:kbShiftF6;st:#27'[17;2~'), {xterm}
  742. (char:0;scan:kbShiftF7;st:#27'[18;2~'), {xterm}
  743. (char:0;scan:kbShiftF8;st:#27'[19;2~'), {xterm}
  744. (char:0;scan:kbShiftF9;st:#27'[20;2~'), {xterm}
  745. (char:0;scan:kbShiftF10;st:#27'[21;2~'), {xterm}
  746. (char:0;scan:kbShiftF11;st:#27'[23;2~'), {xterm}
  747. (char:0;scan:kbShiftF12;st:#27'[24;2~'), {xterm}
  748. (char:0;scan:kbCtrlIns;st:#27'[2;5~'), {xterm}
  749. (char:0;scan:kbCtrlDel;st:#27'[3;5~'), {xterm}
  750. (char:0;scan:kbAltF1;st:#27#27'[[A'),
  751. (char:0;scan:kbAltF2;st:#27#27'[[B'),
  752. (char:0;scan:kbAltF3;st:#27#27'[[C'),
  753. (char:0;scan:kbAltF4;st:#27#27'[[D'),
  754. (char:0;scan:kbAltF5;st:#27#27'[[E'),
  755. (char:0;scan:kbAltF6;st:#27#27'[17~'),
  756. (char:0;scan:kbAltF7;st:#27#27'[18~'),
  757. (char:0;scan:kbAltF8;st:#27#27'[19~'),
  758. (char:0;scan:kbAltF9;st:#27#27'[20~'),
  759. (char:0;scan:kbAltF10;st:#27#27'[21~'),
  760. (char:0;scan:kbAltF11;st:#27#27'[23~'),
  761. (char:0;scan:kbAltF12;st:#27#27'[24~'),
  762. (char:0;scan:kbUp;st:#27'[A'), {linux,FreeBSD}
  763. (char:0;scan:kbDown;st:#27'[B'), {linux,FreeBSD}
  764. (char:0;scan:kbRight;st:#27'[C'), {linux,FreeBSD}
  765. (char:0;scan:kbLeft;st:#27'[D'), {linux,FreeBSD}
  766. (char:0;scan:kbEnd;st:#27'[F'), {FreeBSD}
  767. (char:0;scan:kbPgdn;st:#27'[G'), {FreeBSD}
  768. (char:0;scan:kbHome;st:#27'[H'), {FreeBSD}
  769. (char:0;scan:kbPgup;st:#27'[I'), {FreeBSD}
  770. (char:0;scan:kbF1;st:#27'[M'), {FreeBSD}
  771. (char:0;scan:kbF2;st:#27'[N'), {FreeBSD}
  772. (char:0;scan:kbF3;st:#27'[O'), {FreeBSD}
  773. (char:0;scan:kbF4;st:#27'[P'), {FreeBSD}
  774. (char:0;scan:kbF5;st:#27'[Q'), {FreeBSD}
  775. (char:0;scan:kbF6;st:#27'[R'), {FreeBSD}
  776. (char:0;scan:kbF7;st:#27'[S'), {FreeBSD}
  777. (char:0;scan:kbF8;st:#27'[T'), {FreeBSD}
  778. (char:0;scan:kbF9;st:#27'[U'), {FreeBSD}
  779. (char:0;scan:kbF10;st:#27'[V'), {FreeBSD}
  780. (char:0;scan:kbF11;st:#27'[W'), {FreeBSD}
  781. (char:0;scan:kbF12;st:#27'[X'), {FreeBSD}
  782. (char:0;scan:kbShiftTab;st:#27'[Z'),
  783. (char:0;scan:kbShiftUp;st:#27'[1;2A'), {xterm}
  784. (char:0;scan:kbShiftDown;st:#27'[1;2B'), {xterm}
  785. (char:0;scan:kbShiftRight;st:#27'[1;2C'), {xterm}
  786. (char:0;scan:kbShiftLeft;st:#27'[1;2D'), {xterm}
  787. (char:0;scan:kbShiftEnd;st:#27'[1;2F'), {xterm}
  788. (char:0;scan:kbShiftHome;st:#27'[1;2H'), {xterm}
  789. (char:0;scan:kbCtrlUp;st:#27'[1;5A'), {xterm}
  790. (char:0;scan:kbCtrlDown;st:#27'[1;5B'), {xterm}
  791. (char:0;scan:kbCtrlRight;st:#27'[1;5C'), {xterm}
  792. (char:0;scan:kbCtrlLeft;st:#27'[1;5D'), {xterm}
  793. (char:0;scan:kbCtrlEnd;st:#27'[1;5F'), {xterm}
  794. (char:0;scan:kbCtrlHome;st:#27'[1;5H'), {xterm}
  795. (char:0;scan:kbAltUp;st:#27#27'[A'),
  796. (char:0;scan:kbAltDown;st:#27#27'[B'),
  797. (char:0;scan:kbAltLeft;st:#27#27'[D'),
  798. (char:0;scan:kbAltRight;st:#27#27'[C'),
  799. (char:0;scan:kbAltPgUp;st:#27#27'[5~'),
  800. (char:0;scan:kbAltPgDn;st:#27#27'[6~'),
  801. (char:0;scan:kbAltEnd;st:#27#27'[4~'),
  802. (char:0;scan:kbAltHome;st:#27#27'[1~'),
  803. (char:0;scan:kbAltIns;st:#27#27'[2~'),
  804. (char:0;scan:kbAltDel;st:#27#27'[3~'),
  805. (char:0;scan:kbUp;st:#27'OA'), {xterm}
  806. (char:0;scan:kbDown;st:#27'OB'), {xterm}
  807. (char:0;scan:kbRight;st:#27'OC'), {xterm}
  808. (char:0;scan:kbLeft;st:#27'OD'), {xterm}
  809. (char:0;scan:kbHome;st:#27'OF'), {some xterm configurations}
  810. (char:0;scan:kbEnd;st:#27'OH'), {some xterm configurations}
  811. (char:0;scan:kbF1;st:#27'OP'), {vt100,gnome,konsole}
  812. (char:0;scan:kbF2;st:#27'OQ'), {vt100,gnome,konsole}
  813. (char:0;scan:kbF3;st:#27'OR'), {vt100,gnome,konsole}
  814. (char:0;scan:kbF4;st:#27'OS'), {vt100,gnome,konsole}
  815. (char:0;scan:kbF5;st:#27'Ot'), {vt100}
  816. (char:0;scan:kbF6;st:#27'Ou'), {vt100}
  817. (char:0;scan:kbF7;st:#27'Ov'), {vt100}
  818. (char:0;scan:kbF8;st:#27'Ol'), {vt100}
  819. (char:0;scan:kbF9;st:#27'Ow'), {vt100}
  820. (char:0;scan:kbF10;st:#27'Ox'), {vt100}
  821. (char:0;scan:kbF11;st:#27'Oy'), {vt100}
  822. (char:0;scan:kbF12;st:#27'Oz'), {vt100}
  823. (char:0;scan:kbShiftF1;st:#27'O2P'), {konsole,xterm}
  824. (char:0;scan:kbShiftF2;st:#27'O2Q'), {konsole,xterm}
  825. (char:0;scan:kbShiftF3;st:#27'O2R'), {konsole,xterm}
  826. (char:0;scan:kbShiftF4;st:#27'O2S'), {konsole,xterm}
  827. (char:0;scan:kbAltF1;st:#27#27'OP'),
  828. (char:0;scan:kbAltF2;st:#27#27'OQ'),
  829. (char:0;scan:kbAltF3;st:#27#27'OR'),
  830. (char:0;scan:kbAltF4;st:#27#27'OS'),
  831. (char:0;scan:kbAltF5;st:#27#27'Ot'),
  832. (char:0;scan:kbAltF6;st:#27#27'Ou'),
  833. (char:0;scan:kbAltF7;st:#27#27'Ov'),
  834. (char:0;scan:kbAltF8;st:#27#27'Ol'),
  835. (char:0;scan:kbAltF9;st:#27#27'Ow'),
  836. (char:0;scan:kbAltF10;st:#27#27'Ox'),
  837. (char:0;scan:kbAltF11;st:#27#27'Oy'),
  838. (char:0;scan:kbAltF12;st:#27#27'Oz'),
  839. (char:0;scan:kbAltUp;st:#27#27'OA'),
  840. (char:0;scan:kbAltDown;st:#27#27'OB'),
  841. (char:0;scan:kbAltRight;st:#27#27'OC'),
  842. (char:0;scan:kbAltLeft;st:#27#27'OD'),
  843. { xterm default values }
  844. { xterm alternate default values }
  845. { ignored sequences }
  846. (char:0;scan:0;st:#27'[?1;0c'),
  847. (char:0;scan:0;st:#27'[?1l'),
  848. (char:0;scan:0;st:#27'[?1h'),
  849. (char:0;scan:0;st:#27'[?1;2c'),
  850. (char:0;scan:0;st:#27'[?7l'),
  851. (char:0;scan:0;st:#27'[?7h')
  852. );
  853. procedure LoadDefaultSequences;
  854. var i:cardinal;
  855. begin
  856. AddSpecialSequence(#27'[M',@GenMouseEvent);
  857. {Unix backspace/delete hell... Is #127 a backspace or delete?}
  858. if copy(fpgetenv('TERM'),1,4)='cons' then
  859. begin
  860. {FreeBSD is until now only terminal that uses it for delete.}
  861. DoAddSequence(#127,0,kbDel); {Delete}
  862. DoAddSequence(#27#127,0,kbAltDel); {Alt+delete}
  863. end
  864. else
  865. begin
  866. DoAddSequence(#127,8,0); {Backspace}
  867. DoAddSequence(#27#127,0,kbAltBack); {Alt+backspace}
  868. end;
  869. { all Esc letter }
  870. for i:=low(key_sequences) to high(key_sequences) do
  871. with key_sequences[i] do
  872. DoAddSequence(st,char,scan);
  873. end;
  874. function RawReadKey:char;
  875. var
  876. fdsin : tfdSet;
  877. begin
  878. {Check Buffer first}
  879. if KeySend<>KeyPut then
  880. begin
  881. RawReadKey:=PopKey;
  882. exit;
  883. end;
  884. {Wait for Key}
  885. if not sysKeyPressed then
  886. begin
  887. fpFD_ZERO (fdsin);
  888. fpFD_SET (StdInputHandle,fdsin);
  889. fpSelect (StdInputHandle+1,@fdsin,nil,nil,nil);
  890. end;
  891. RawReadKey:=ttyRecvChar;
  892. end;
  893. function RawReadString : String;
  894. var
  895. ch : char;
  896. fdsin : tfdSet;
  897. St : String;
  898. begin
  899. St:=RawReadKey;
  900. fpFD_ZERO (fdsin);
  901. fpFD_SET (StdInputHandle,fdsin);
  902. Repeat
  903. if inhead=intail then
  904. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  905. if SysKeyPressed then
  906. ch:=ttyRecvChar
  907. else
  908. ch:=#0;
  909. if ch<>#0 then
  910. St:=St+ch;
  911. Until ch=#0;
  912. RawReadString:=St;
  913. end;
  914. function ReadKey(var IsAlt : boolean):char;
  915. var
  916. ch : char;
  917. is_delay : boolean;
  918. fdsin : tfdSet;
  919. store : array [0..8] of char;
  920. arrayind : byte;
  921. NPT,NNPT : PTreeElement;
  922. procedure GenMouseEvent;
  923. var MouseEvent: TMouseEvent;
  924. begin
  925. Fillchar(MouseEvent,SizeOf(TMouseEvent),#0);
  926. case ch of
  927. #32 : {left button pressed }
  928. MouseEvent.buttons:=1;
  929. #33 : {middle button pressed }
  930. MouseEvent.buttons:=2;
  931. #34 : { right button pressed }
  932. MouseEvent.buttons:=4;
  933. #35 : { no button pressed };
  934. end;
  935. if inhead=intail then
  936. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  937. ch:=ttyRecvChar;
  938. MouseEvent.x:=Ord(ch)-ord(' ')-1;
  939. if inhead=intail then
  940. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  941. ch:=ttyRecvChar;
  942. MouseEvent.y:=Ord(ch)-ord(' ')-1;
  943. if (MouseEvent.buttons<>0) then
  944. MouseEvent.action:=MouseActionDown
  945. else
  946. begin
  947. if (LastMouseEvent.Buttons<>0) and
  948. ((LastMouseEvent.X<>MouseEvent.X) or (LastMouseEvent.Y<>MouseEvent.Y)) then
  949. begin
  950. MouseEvent.Action:=MouseActionMove;
  951. MouseEvent.Buttons:=LastMouseEvent.Buttons;
  952. PutMouseEvent(MouseEvent);
  953. MouseEvent.Buttons:=0;
  954. end;
  955. MouseEvent.Action:=MouseActionUp;
  956. end;
  957. PutMouseEvent(MouseEvent);
  958. LastMouseEvent:=MouseEvent;
  959. end;
  960. procedure RestoreArray;
  961. var
  962. i : byte;
  963. begin
  964. for i:=0 to arrayind-1 do
  965. PushKey(store[i]);
  966. end;
  967. begin
  968. IsAlt:=false;
  969. {Check Buffer first}
  970. if KeySend<>KeyPut then
  971. begin
  972. ReadKey:=PopKey;
  973. exit;
  974. end;
  975. {Wait for Key}
  976. if not sysKeyPressed then
  977. begin
  978. fpFD_ZERO (fdsin);
  979. fpFD_SET (StdInputHandle,fdsin);
  980. fpSelect (StdInputHandle+1,@fdsin,nil,nil,nil);
  981. end;
  982. ch:=ttyRecvChar;
  983. NPT:=RootTree[ch];
  984. if not assigned(NPT) then
  985. PushKey(ch)
  986. else
  987. begin
  988. fpFD_ZERO(fdsin);
  989. fpFD_SET(StdInputHandle,fdsin);
  990. store[0]:=ch;
  991. arrayind:=1;
  992. while assigned(NPT) and syskeypressed do
  993. begin
  994. if inhead=intail then
  995. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  996. ch:=ttyRecvChar;
  997. NNPT:=FindChild(ord(ch),NPT);
  998. if assigned(NNPT) then
  999. begin
  1000. NPT:=NNPT;
  1001. if NPT^.CanBeTerminal and
  1002. assigned(NPT^.SpecialHandler) then
  1003. break;
  1004. End;
  1005. if ch<>#0 then
  1006. begin
  1007. store[arrayind]:=ch;
  1008. inc(arrayind);
  1009. end;
  1010. if not assigned(NNPT) then
  1011. begin
  1012. if ch<>#0 then
  1013. begin
  1014. { Put that unused char back into InBuf }
  1015. If InTail=0 then
  1016. InTail:=InSize-1
  1017. else
  1018. Dec(InTail);
  1019. InBuf[InTail]:=ch;
  1020. end;
  1021. break;
  1022. end;
  1023. end;
  1024. if assigned(NPT) and NPT^.CanBeTerminal then
  1025. begin
  1026. if assigned(NPT^.SpecialHandler) then
  1027. begin
  1028. NPT^.SpecialHandler;
  1029. PushExt(0);
  1030. end
  1031. else if NPT^.CharValue<>0 then
  1032. PushKey(chr(NPT^.CharValue))
  1033. else if NPT^.ScanValue<>0 then
  1034. PushExt(NPT^.ScanValue);
  1035. end
  1036. else
  1037. RestoreArray;
  1038. end
  1039. {$ifdef logging}
  1040. writeln(f);
  1041. {$endif logging}
  1042. ;
  1043. ReadKey:=PopKey;
  1044. End;
  1045. {$ifdef linux}
  1046. function ShiftState:byte;
  1047. var arg:longint;
  1048. begin
  1049. shiftstate:=0;
  1050. arg:=6;
  1051. if fpioctl(StdInputHandle,TIOCLINUX,@arg)=0 then
  1052. begin
  1053. if (arg and 8)<>0 then
  1054. shiftstate:=kbAlt;
  1055. if (arg and 4)<>0 then
  1056. inc(shiftstate,kbCtrl);
  1057. { 2 corresponds to AltGr so set both kbAlt and kbCtrl PM }
  1058. if (arg and 2)<>0 then
  1059. shiftstate:=shiftstate or (kbAlt or kbCtrl);
  1060. if (arg and 1)<>0 then
  1061. inc(shiftstate,kbShift);
  1062. end;
  1063. end;
  1064. procedure force_linuxtty;
  1065. var s:string[15];
  1066. handle:sizeint;
  1067. thistty:string;
  1068. begin
  1069. is_console:=false;
  1070. if vcs_device<>-1 then
  1071. begin
  1072. { running on a tty, find out whether locally or remotely }
  1073. thistty:=ttyname(stdinputhandle);
  1074. if (copy(thistty,1,8)<>'/dev/tty') or not (thistty[9] in ['0'..'9']) then
  1075. begin
  1076. {Running from Midnight Commander or something... Bypass it.}
  1077. str(vcs_device,s);
  1078. handle:=fpopen('/dev/tty'+s,O_RDWR);
  1079. fpioctl(stdinputhandle,TIOCNOTTY,nil);
  1080. {This will currently only work when the user is root :(}
  1081. fpioctl(handle,TIOCSCTTY,nil);
  1082. if errno<>0 then
  1083. exit;
  1084. fpclose(stdinputhandle);
  1085. fpclose(stdoutputhandle);
  1086. fpclose(stderrorhandle);
  1087. fpdup2(handle,stdinputhandle);
  1088. fpdup2(handle,stdoutputhandle);
  1089. fpdup2(handle,stderrorhandle);
  1090. fpclose(handle);
  1091. end;
  1092. is_console:=true;
  1093. end;
  1094. end;
  1095. {$endif linux}
  1096. { Exported functions }
  1097. procedure SysInitKeyboard;
  1098. begin
  1099. SetRawMode(true);
  1100. {$ifdef logging}
  1101. assign(f,'keyboard.log');
  1102. rewrite(f);
  1103. {$endif logging}
  1104. {$ifdef linux}
  1105. force_linuxtty;
  1106. prepare_patching;
  1107. patchkeyboard;
  1108. if is_console then
  1109. install_vt_handler
  1110. else
  1111. begin
  1112. {$endif}
  1113. { default for Shift prefix is ^ A}
  1114. if ShiftPrefix = 0 then
  1115. ShiftPrefix:=1;
  1116. {default for Alt prefix is ^Z }
  1117. if AltPrefix=0 then
  1118. AltPrefix:=26;
  1119. { default for Ctrl Prefix is ^W }
  1120. if CtrlPrefix=0 then
  1121. CtrlPrefix:=23;
  1122. {$ifdef linux}
  1123. end;
  1124. {$endif}
  1125. LoadDefaultSequences;
  1126. { LoadTerminfoSequences;}
  1127. end;
  1128. procedure SysDoneKeyboard;
  1129. begin
  1130. {$ifdef linux}
  1131. unpatchkeyboard;
  1132. {$endif linux}
  1133. SetRawMode(false);
  1134. FreeTree;
  1135. {$ifdef logging}
  1136. close(f);
  1137. {$endif logging}
  1138. end;
  1139. function SysGetKeyEvent: TKeyEvent;
  1140. function EvalScan(b:byte):byte;
  1141. const
  1142. DScan:array[0..31] of byte = (
  1143. $39, $02, $28, $04, $05, $06, $08, $28,
  1144. $0A, $0B, $09, $0D, $33, $0C, $34, $35,
  1145. $0B, $02, $03, $04, $05, $06, $07, $08,
  1146. $09, $0A, $27, $27, $33, $0D, $34, $35);
  1147. LScan:array[0..31] of byte = (
  1148. $29, $1E, $30, $2E, $20, $12, $21, $22,
  1149. $23, $17, $24, $25, $26, $32, $31, $18,
  1150. $19, $10, $13, $1F, $14, $16, $2F, $11,
  1151. $2D, $15, $2C, $1A, $2B, $1B, $29, $0C);
  1152. begin
  1153. if (b and $E0)=$20 { digits / leters } then
  1154. EvalScan:=DScan[b and $1F]
  1155. else
  1156. case b of
  1157. $08:EvalScan:=$0E; { backspace }
  1158. $09:EvalScan:=$0F; { TAB }
  1159. $0D:EvalScan:=$1C; { CR }
  1160. $1B:EvalScan:=$01; { esc }
  1161. $40:EvalScan:=$03; { @ }
  1162. $5E:EvalScan:=$07; { ^ }
  1163. $60:EvalScan:=$29; { ` }
  1164. else
  1165. EvalScan:=LScan[b and $1F];
  1166. end;
  1167. end;
  1168. function EvalScanZ(b:byte):byte;
  1169. begin
  1170. EvalScanZ:=b;
  1171. if b in [$3B..$44] { F1..F10 -> Alt-F1..Alt-F10} then
  1172. EvalScanZ:=b+$2D;
  1173. end;
  1174. const
  1175. {kbHome, kbUp, kbPgUp,Missing, kbLeft,
  1176. kbCenter, kbRight, kbAltGrayPlus, kbend,
  1177. kbDown, kbPgDn, kbIns, kbDel }
  1178. CtrlArrow : array [kbHome..kbDel] of byte =
  1179. {($77,$8d,$84,$8e,$73,$8f,$74,$90,$75,$91,$76);}
  1180. (kbCtrlHome,kbCtrlUp,kbCtrlPgUp,kbNoKey,kbCtrlLeft,
  1181. kbCtrlCenter,kbCtrlRight,kbAltGrayPlus,kbCtrlEnd,
  1182. kbCtrlDown,kbCtrlPgDn,kbCtrlIns,kbCtrlDel);
  1183. AltArrow : array [kbHome..kbDel] of byte =
  1184. (kbAltHome,kbAltUp,kbAltPgUp,kbNoKey,kbAltLeft,
  1185. kbCenter,kbAltRight,kbAltGrayPlus,kbAltEnd,
  1186. kbAltDown,kbAltPgDn,kbAltIns,kbAltDel);
  1187. ShiftArrow : array [kbShiftUp..kbShiftEnd] of byte =
  1188. (kbUp,kbLeft,kbRight,kbDown,kbHome,kbEnd);
  1189. var
  1190. MyScan:byte;
  1191. MyChar : char;
  1192. EscUsed,AltPrefixUsed,CtrlPrefixUsed,ShiftPrefixUsed,IsAlt,Again : boolean;
  1193. SState:byte;
  1194. begin {main}
  1195. MyChar:=Readkey(IsAlt);
  1196. MyScan:=ord(MyChar);
  1197. {$ifdef linux}
  1198. if is_console then
  1199. SState:=ShiftState
  1200. else
  1201. {$endif}
  1202. Sstate:=0;
  1203. CtrlPrefixUsed:=false;
  1204. AltPrefixUsed:=false;
  1205. ShiftPrefixUsed:=false;
  1206. EscUsed:=false;
  1207. if IsAlt then
  1208. SState:=SState or kbAlt;
  1209. repeat
  1210. again:=false;
  1211. if Mychar=#0 then
  1212. begin
  1213. MyScan:=ord(ReadKey(IsAlt));
  1214. if myscan=$01 then
  1215. mychar:=#27;
  1216. { Handle Ctrl-<x>, but not AltGr-<x> }
  1217. if ((SState and kbCtrl)<>0) and ((SState and kbAlt) = 0) then
  1218. case MyScan of
  1219. kbHome..kbDel : { cArrow }
  1220. MyScan:=CtrlArrow[MyScan];
  1221. kbF1..KbF10 : { cF1-cF10 }
  1222. MyScan:=MyScan+kbCtrlF1-kbF1;
  1223. kbF11..KbF12 : { cF11-cF12 }
  1224. MyScan:=MyScan+kbCtrlF11-kbF11;
  1225. end
  1226. { Handle Alt-<x>, but not AltGr }
  1227. else if ((SState and kbAlt)<>0) and ((SState and kbCtrl) = 0) then
  1228. case MyScan of
  1229. kbHome..kbDel : { AltArrow }
  1230. MyScan:=AltArrow[MyScan];
  1231. kbF1..KbF10 : { aF1-aF10 }
  1232. MyScan:=MyScan+kbAltF1-kbF1;
  1233. kbF11..KbF12 : { aF11-aF12 }
  1234. MyScan:=MyScan+kbAltF11-kbF11;
  1235. end
  1236. else if (SState and kbShift)<>0 then
  1237. case MyScan of
  1238. kbIns: MyScan:=kbShiftIns;
  1239. kbDel: MyScan:=kbShiftDel;
  1240. kbF1..KbF10 : { sF1-sF10 }
  1241. MyScan:=MyScan+kbShiftF1-kbF1;
  1242. kbF11..KbF12 : { sF11-sF12 }
  1243. MyScan:=MyScan+kbShiftF11-kbF11;
  1244. end;
  1245. if myscan in [kbShiftUp..kbShiftEnd] then
  1246. begin
  1247. myscan:=ShiftArrow[myscan];
  1248. sstate:=sstate or kbshift;
  1249. end;
  1250. if myscan=kbAltBack then
  1251. sstate:=sstate or kbalt;
  1252. if (MyChar<>#0) or (MyScan<>0) or (SState<>0) then
  1253. SysGetKeyEvent:=$3000000 or ord(MyChar) or (MyScan shl 8) or (SState shl 16)
  1254. else
  1255. SysGetKeyEvent:=0;
  1256. exit;
  1257. end
  1258. else if MyChar=#27 then
  1259. begin
  1260. if EscUsed then
  1261. SState:=SState and not kbAlt
  1262. else
  1263. begin
  1264. SState:=SState or kbAlt;
  1265. Again:=true;
  1266. EscUsed:=true;
  1267. end;
  1268. end
  1269. else if (AltPrefix<>0) and (MyChar=chr(AltPrefix)) then
  1270. begin { ^Z - replace Alt for Linux OS }
  1271. if AltPrefixUsed then
  1272. begin
  1273. SState:=SState and not kbAlt;
  1274. end
  1275. else
  1276. begin
  1277. AltPrefixUsed:=true;
  1278. SState:=SState or kbAlt;
  1279. Again:=true;
  1280. end;
  1281. end
  1282. else if (CtrlPrefix<>0) and (MyChar=chr(CtrlPrefix)) then
  1283. begin
  1284. if CtrlPrefixUsed then
  1285. SState:=SState and not kbCtrl
  1286. else
  1287. begin
  1288. CtrlPrefixUsed:=true;
  1289. SState:=SState or kbCtrl;
  1290. Again:=true;
  1291. end;
  1292. end
  1293. else if (ShiftPrefix<>0) and (MyChar=chr(ShiftPrefix)) then
  1294. begin
  1295. if ShiftPrefixUsed then
  1296. SState:=SState and not kbShift
  1297. else
  1298. begin
  1299. ShiftPrefixUsed:=true;
  1300. SState:=SState or kbShift;
  1301. Again:=true;
  1302. end;
  1303. end;
  1304. if not again then
  1305. begin
  1306. MyScan:=EvalScan(ord(MyChar));
  1307. if ((SState and kbAlt)<>0) and ((SState and kbCtrl) = 0) then
  1308. begin
  1309. if MyScan in [$02..$0D] then
  1310. inc(MyScan,$76);
  1311. MyChar:=chr(0);
  1312. end
  1313. else if (SState and kbShift)<>0 then
  1314. if MyChar=#9 then
  1315. begin
  1316. MyChar:=#0;
  1317. MyScan:=kbShiftTab;
  1318. end;
  1319. end
  1320. else
  1321. begin
  1322. MyChar:=Readkey(IsAlt);
  1323. MyScan:=ord(MyChar);
  1324. if IsAlt then
  1325. SState:=SState or kbAlt;
  1326. end;
  1327. until not Again;
  1328. if (MyChar<>#0) or (MyScan<>0) or (SState<>0) then
  1329. SysGetKeyEvent:=$3000000 or ord(MyChar) or (MyScan shl 8) or (SState shl 16)
  1330. else
  1331. SysGetKeyEvent:=0;
  1332. end;
  1333. function SysPollKeyEvent: TKeyEvent;
  1334. var
  1335. KeyEvent : TKeyEvent;
  1336. begin
  1337. if keypressed then
  1338. begin
  1339. KeyEvent:=SysGetKeyEvent;
  1340. PutKeyEvent(KeyEvent);
  1341. SysPollKeyEvent:=KeyEvent
  1342. end
  1343. else
  1344. SysPollKeyEvent:=0;
  1345. end;
  1346. function SysGetShiftState : Byte;
  1347. begin
  1348. {$ifdef linux}
  1349. if is_console then
  1350. SysGetShiftState:=ShiftState
  1351. else
  1352. {$else}
  1353. SysGetShiftState:=0;
  1354. {$endif}
  1355. end;
  1356. procedure RestoreStartMode;
  1357. begin
  1358. TCSetAttr(1,TCSANOW,StartTio);
  1359. end;
  1360. const
  1361. SysKeyboardDriver : TKeyboardDriver = (
  1362. InitDriver : @SysInitKeyBoard;
  1363. DoneDriver : @SysDoneKeyBoard;
  1364. GetKeyevent : @SysGetKeyEvent;
  1365. PollKeyEvent : @SysPollKeyEvent;
  1366. GetShiftState : @SysGetShiftState;
  1367. TranslateKeyEvent : Nil;
  1368. TranslateKeyEventUnicode : Nil;
  1369. );
  1370. begin
  1371. SetKeyBoardDriver(SysKeyBoardDriver);
  1372. TCGetAttr(1,StartTio);
  1373. end.