keyboard.pp 54 KB

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