keyboard.pp 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Florian Klaempfl
  5. member of the Free Pascal development team
  6. Keyboard unit for linux
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. unit Keyboard;
  14. interface
  15. {$i keybrdh.inc}
  16. Const
  17. AltPrefix : byte = 0;
  18. ShiftPrefix : byte = 0;
  19. CtrlPrefix : byte = 0;
  20. Function RawReadKey:char;
  21. Function RawReadString : String;
  22. Function KeyPressed : Boolean;
  23. {$ifndef NotUseTree}
  24. Procedure AddSequence(Const St : String; AChar,AScan :byte);
  25. Function FindSequence(Const St : String;var AChar, Ascan : byte) : boolean;
  26. {$endif NotUseTree}
  27. procedure RestoreStartMode;
  28. implementation
  29. uses
  30. Mouse,
  31. {$ifndef NotUseTree}
  32. Strings,
  33. TermInfo,
  34. {$endif NotUseTree}
  35. Unix;
  36. {$i keyboard.inc}
  37. var
  38. OldIO,StartTio : TermIos;
  39. {$ifdef logging}
  40. f : text;
  41. {$endif logging}
  42. { list of all dos scancode for key giving 0 as char }
  43. Const
  44. kbNoKey = $00;
  45. kbAltEsc = $01;
  46. kbAltSpace = $02;
  47. kbCtrlIns = $04;
  48. kbShiftIns = $05;
  49. kbCtrlDel = $06;
  50. kbShiftDel = $07;
  51. kbAltBack = $08;
  52. kbAltShiftBack= $09;
  53. kbShiftTab = $0F;
  54. kbAltQ = $10;
  55. kbAltW = $11;
  56. kbAltE = $12;
  57. kbAltR = $13;
  58. kbAltT = $14;
  59. kbAltY = $15;
  60. kbAltU = $16;
  61. kbAltI = $17;
  62. kbAltO = $18;
  63. kbAltP = $19;
  64. kbAltLftBrack = $1A;
  65. kbAltRgtBrack = $1B;
  66. kbAltA = $1E;
  67. kbAltS = $1F;
  68. kbAltD = $20;
  69. kbAltF = $21;
  70. kbAltG = $22;
  71. kbAltH = $23;
  72. kbAltJ = $24;
  73. kbAltK = $25;
  74. kbAltL = $26;
  75. kbAltSemiCol = $27;
  76. kbAltQuote = $28;
  77. kbAltOpQuote = $29;
  78. kbAltBkSlash = $2B;
  79. kbAltZ = $2C;
  80. kbAltX = $2D;
  81. kbAltC = $2E;
  82. kbAltV = $2F;
  83. kbAltB = $30;
  84. kbAltN = $31;
  85. kbAltM = $32;
  86. kbAltComma = $33;
  87. kbAltPeriod = $34;
  88. kbAltSlash = $35;
  89. kbAltGreyAst = $37;
  90. kbF1 = $3B;
  91. kbF2 = $3C;
  92. kbF3 = $3D;
  93. kbF4 = $3E;
  94. kbF5 = $3F;
  95. kbF6 = $40;
  96. kbF7 = $41;
  97. kbF8 = $42;
  98. kbF9 = $43;
  99. kbF10 = $44;
  100. kbHome = $47;
  101. kbUp = $48;
  102. kbPgUp = $49;
  103. kbLeft = $4B;
  104. kbCenter = $4C;
  105. kbRight = $4D;
  106. kbAltGrayPlus = $4E;
  107. kbend = $4F;
  108. kbDown = $50;
  109. kbPgDn = $51;
  110. kbIns = $52;
  111. kbDel = $53;
  112. kbShiftF1 = $54;
  113. kbShiftF2 = $55;
  114. kbShiftF3 = $56;
  115. kbShiftF4 = $57;
  116. kbShiftF5 = $58;
  117. kbShiftF6 = $59;
  118. kbShiftF7 = $5A;
  119. kbShiftF8 = $5B;
  120. kbShiftF9 = $5C;
  121. kbShiftF10 = $5D;
  122. kbCtrlF1 = $5E;
  123. kbCtrlF2 = $5F;
  124. kbCtrlF3 = $60;
  125. kbCtrlF4 = $61;
  126. kbCtrlF5 = $62;
  127. kbCtrlF6 = $63;
  128. kbCtrlF7 = $64;
  129. kbCtrlF8 = $65;
  130. kbCtrlF9 = $66;
  131. kbCtrlF10 = $67;
  132. kbAltF1 = $68;
  133. kbAltF2 = $69;
  134. kbAltF3 = $6A;
  135. kbAltF4 = $6B;
  136. kbAltF5 = $6C;
  137. kbAltF6 = $6D;
  138. kbAltF7 = $6E;
  139. kbAltF8 = $6F;
  140. kbAltF9 = $70;
  141. kbAltF10 = $71;
  142. kbCtrlPrtSc = $72;
  143. kbCtrlLeft = $73;
  144. kbCtrlRight = $74;
  145. kbCtrlend = $75;
  146. kbCtrlPgDn = $76;
  147. kbCtrlHome = $77;
  148. kbAlt1 = $78;
  149. kbAlt2 = $79;
  150. kbAlt3 = $7A;
  151. kbAlt4 = $7B;
  152. kbAlt5 = $7C;
  153. kbAlt6 = $7D;
  154. kbAlt7 = $7E;
  155. kbAlt8 = $7F;
  156. kbAlt9 = $80;
  157. kbAlt0 = $81;
  158. kbAltMinus = $82;
  159. kbAltEqual = $83;
  160. kbCtrlPgUp = $84;
  161. kbF11 = $85;
  162. kbF12 = $86;
  163. kbShiftF11 = $87;
  164. kbShiftF12 = $88;
  165. kbCtrlF11 = $89;
  166. kbCtrlF12 = $8A;
  167. kbAltF11 = $8B;
  168. kbAltF12 = $8C;
  169. kbCtrlUp = $8D;
  170. kbCtrlMinus = $8E;
  171. kbCtrlCenter = $8F;
  172. kbCtrlGreyPlus= $90;
  173. kbCtrlDown = $91;
  174. kbCtrlTab = $94;
  175. kbAltHome = $97;
  176. kbAltUp = $98;
  177. kbAltPgUp = $99;
  178. kbAltLeft = $9B;
  179. kbAltRight = $9D;
  180. kbAltend = $9F;
  181. kbAltDown = $A0;
  182. kbAltPgDn = $A1;
  183. kbAltIns = $A2;
  184. kbAltDel = $A3;
  185. kbAltTab = $A5;
  186. {$ifdef Unused}
  187. type
  188. TKeyState = Record
  189. Normal, Shift, Ctrl, Alt : word;
  190. end;
  191. Const
  192. KeyStates : Array[0..255] of TKeyState
  193. (
  194. );
  195. {$endif Unused}
  196. Procedure SetRawMode(b:boolean);
  197. Var
  198. Tio : Termios;
  199. Begin
  200. TCGetAttr(1,Tio);
  201. if b then
  202. begin
  203. OldIO:=Tio;
  204. Tio.c_iflag:=Tio.c_iflag and (not (IGNBRK or BRKINT or PARMRK or ISTRIP or
  205. INLCR or IGNCR or ICRNL or IXON));
  206. Tio.c_lflag:=Tio.c_lflag and (not (ECHO or ECHONL or ICANON or ISIG or IEXTEN));
  207. end
  208. else
  209. Tio := OldIO;
  210. TCSetAttr(1,TCSANOW,Tio);
  211. End;
  212. type
  213. chgentry=packed record
  214. tab,
  215. idx,
  216. oldtab,
  217. oldidx : byte;
  218. oldval,
  219. newval : word;
  220. end;
  221. kbentry=packed record
  222. kb_table,
  223. kb_index : byte;
  224. kb_value : word;
  225. end;
  226. const
  227. kbdchanges=10;
  228. kbdchange:array[1..kbdchanges] of chgentry=(
  229. (tab:8; idx:$3b; oldtab:0; oldidx:$3b; oldval:0; newval:0),
  230. (tab:8; idx:$3c; oldtab:0; oldidx:$3c; oldval:0; newval:0),
  231. (tab:8; idx:$3d; oldtab:0; oldidx:$3d; oldval:0; newval:0),
  232. (tab:8; idx:$3e; oldtab:0; oldidx:$3e; oldval:0; newval:0),
  233. (tab:8; idx:$3f; oldtab:0; oldidx:$3f; oldval:0; newval:0),
  234. (tab:8; idx:$40; oldtab:0; oldidx:$40; oldval:0; newval:0),
  235. (tab:8; idx:$41; oldtab:0; oldidx:$41; oldval:0; newval:0),
  236. (tab:8; idx:$42; oldtab:0; oldidx:$42; oldval:0; newval:0),
  237. (tab:8; idx:$43; oldtab:0; oldidx:$43; oldval:0; newval:0),
  238. (tab:8; idx:$44; oldtab:0; oldidx:$44; oldval:0; newval:0)
  239. );
  240. KDGKBENT=$4B46;
  241. KDSKBENT=$4B47;
  242. KDGKBMETA=$4B62;
  243. KDSKBMETA=$4B63;
  244. K_ESCPREFIX=$4;
  245. K_METABIT=$3;
  246. const
  247. oldmeta : longint = 0;
  248. meta : longint = 0;
  249. procedure PatchKeyboard;
  250. var
  251. e : ^chgentry;
  252. entry : kbentry;
  253. i : longint;
  254. begin
  255. Ioctl(stdinputhandle,KDGKBMETA,@oldmeta);
  256. meta:=K_ESCPREFIX;
  257. Ioctl(stdinputhandle,KDSKBMETA,@meta);
  258. for i:=1 to kbdchanges do
  259. begin
  260. e:=@kbdchange[i];
  261. entry.kb_table:=e^.tab;
  262. entry.kb_index:=e^.idx;
  263. Ioctl(stdinputhandle,KDGKBENT,@entry);
  264. e^.oldval:=entry.kb_value;
  265. entry.kb_table:=e^.oldtab;
  266. entry.kb_index:=e^.oldidx;
  267. ioctl(stdinputhandle,KDGKBENT,@entry);
  268. e^.newval:=entry.kb_value;
  269. end;
  270. for i:=1 to kbdchanges do
  271. begin
  272. e:=@kbdchange[i];
  273. entry.kb_table:=e^.tab;
  274. entry.kb_index:=e^.idx;
  275. entry.kb_value:=e^.newval;
  276. Ioctl(stdinputhandle,KDSKBENT,@entry);
  277. end;
  278. end;
  279. procedure UnpatchKeyboard;
  280. var
  281. e : ^chgentry;
  282. entry : kbentry;
  283. i : longint;
  284. begin
  285. if oldmeta in [K_ESCPREFIX,K_METABIT] then
  286. Ioctl(stdinputhandle,KDSKBMETA,@oldmeta);
  287. for i:=1 to kbdchanges do
  288. begin
  289. e:=@kbdchange[i];
  290. entry.kb_table:=e^.tab;
  291. entry.kb_index:=e^.idx;
  292. entry.kb_value:=e^.oldval;
  293. Ioctl(stdinputhandle,KDSKBENT,@entry);
  294. end;
  295. end;
  296. { Buffered Input routines }
  297. const
  298. InSize=256;
  299. var
  300. InBuf : array [0..InSize-1] of char;
  301. InCnt,
  302. InHead,
  303. InTail : longint;
  304. function ttyRecvChar:char;
  305. var
  306. Readed,i : longint;
  307. begin
  308. {Buffer Empty? Yes, Input from StdIn}
  309. if (InHead=InTail) then
  310. begin
  311. {Calc Amount of Chars to Read}
  312. i:=InSize-InHead;
  313. if InTail>InHead then
  314. i:=InTail-InHead;
  315. {Read}
  316. Readed:=fdRead(StdInputHandle,InBuf[InHead],i);
  317. {Increase Counters}
  318. inc(InCnt,Readed);
  319. inc(InHead,Readed);
  320. {Wrap if End has Reached}
  321. if InHead>=InSize then
  322. InHead:=0;
  323. end;
  324. {Check Buffer}
  325. if (InCnt=0) then
  326. ttyRecvChar:=#0
  327. else
  328. begin
  329. ttyRecvChar:=InBuf[InTail];
  330. dec(InCnt);
  331. inc(InTail);
  332. if InTail>=InSize then
  333. InTail:=0;
  334. end;
  335. end;
  336. Const
  337. KeyBufferSize = 20;
  338. var
  339. KeyBuffer : Array[0..KeyBufferSize-1] of Char;
  340. KeyPut,
  341. KeySend : longint;
  342. Procedure PushKey(Ch:char);
  343. Var
  344. Tmp : Longint;
  345. Begin
  346. Tmp:=KeyPut;
  347. Inc(KeyPut);
  348. If KeyPut>=KeyBufferSize Then
  349. KeyPut:=0;
  350. If KeyPut<>KeySend Then
  351. KeyBuffer[Tmp]:=Ch
  352. Else
  353. KeyPut:=Tmp;
  354. End;
  355. Function PopKey:char;
  356. Begin
  357. If KeyPut<>KeySend Then
  358. Begin
  359. PopKey:=KeyBuffer[KeySend];
  360. Inc(KeySend);
  361. If KeySend>=KeyBufferSize Then
  362. KeySend:=0;
  363. End
  364. Else
  365. PopKey:=#0;
  366. End;
  367. Procedure PushExt(b:byte);
  368. begin
  369. PushKey(#0);
  370. PushKey(chr(b));
  371. end;
  372. const
  373. AltKeyStr : string[38]='qwertyuiopasdfghjklzxcvbnm1234567890-=';
  374. AltCodeStr : string[38]=#016#017#018#019#020#021#022#023#024#025#030#031#032#033#034#035#036#037#038+
  375. #044#045#046#047#048#049#050#120#121#122#123#124#125#126#127#128#129#130#131;
  376. Function FAltKey(ch:char):byte;
  377. var
  378. Idx : longint;
  379. Begin
  380. Idx:=Pos(ch,AltKeyStr);
  381. if Idx>0 then
  382. FAltKey:=byte(AltCodeStr[Idx])
  383. else
  384. FAltKey:=0;
  385. End;
  386. { This one doesn't care about keypresses already processed by readkey }
  387. { and waiting in the KeyBuffer, only about waiting keypresses at the }
  388. { TTYLevel (including ones that are waiting in the TTYRecvChar buffer) }
  389. function sysKeyPressed: boolean;
  390. var
  391. fdsin : fdSet;
  392. begin
  393. if (InCnt>0) then
  394. sysKeyPressed:=true
  395. else
  396. begin
  397. FD_Zero(fdsin);
  398. fd_Set(StdInputHandle,fdsin);
  399. sysKeypressed:=(Select(StdInputHandle+1,@fdsin,nil,nil,0)>0);
  400. end;
  401. end;
  402. Function KeyPressed:Boolean;
  403. Begin
  404. Keypressed := (KeySend<>KeyPut) or sysKeyPressed;
  405. End;
  406. Function IsConsole : Boolean;
  407. var
  408. ThisTTY: String[30];
  409. FName : String;
  410. TTYfd: longint;
  411. begin
  412. IsConsole:=false;
  413. { check for tty }
  414. ThisTTY:=TTYName(stdinputhandle);
  415. if IsATTY(stdinputhandle) then
  416. begin
  417. { running on a tty, find out whether locally or remotely }
  418. if (Copy(ThisTTY, 1, 8) = '/dev/tty') and
  419. (ThisTTY[9] >= '0') and (ThisTTY[9] <= '9') then
  420. begin
  421. { running on the console }
  422. FName:='/dev/vcsa' + ThisTTY[9];
  423. { check with read only as it might already be
  424. open in ReadWrite by video unit }
  425. TTYFd:=fdOpen(FName, 0, Open_RdOnly); { open console }
  426. end
  427. else
  428. TTYFd:=-1;
  429. if TTYFd<>-1 then
  430. begin
  431. IsConsole:=true;
  432. fdClose(TTYFd);
  433. end;
  434. end;
  435. end;
  436. Const
  437. LastMouseEvent : TMouseEvent =
  438. (
  439. Buttons : 0;
  440. X : 0;
  441. Y : 0;
  442. Action : 0;
  443. );
  444. {$ifndef NotUseTree}
  445. procedure GenMouseEvent;
  446. var MouseEvent: TMouseEvent;
  447. ch : char;
  448. fdsin : fdSet;
  449. begin
  450. FD_Zero(fdsin);
  451. fd_Set(StdInputHandle,fdsin);
  452. Fillchar(MouseEvent,SizeOf(TMouseEvent),#0);
  453. if InCnt=0 then
  454. Select(StdInputHandle+1,@fdsin,nil,nil,10);
  455. ch:=ttyRecvChar;
  456. { Other bits are used for Shift, Meta and Ctrl modifiers PM }
  457. case (ord(ch)-ord(' ')) and 3 of
  458. 0 : {left button press}
  459. MouseEvent.buttons:=1;
  460. 1 : {middle button pressed }
  461. MouseEvent.buttons:=2;
  462. 2 : { right button pressed }
  463. MouseEvent.buttons:=4;
  464. 3 : { no button pressed };
  465. end;
  466. if InCnt=0 then
  467. Select(StdInputHandle+1,@fdsin,nil,nil,10);
  468. ch:=ttyRecvChar;
  469. MouseEvent.x:=Ord(ch)-ord(' ')-1;
  470. if InCnt=0 then
  471. Select(StdInputHandle+1,@fdsin,nil,nil,10);
  472. ch:=ttyRecvChar;
  473. MouseEvent.y:=Ord(ch)-ord(' ')-1;
  474. if (MouseEvent.buttons<>0) then
  475. MouseEvent.action:=MouseActionDown
  476. else
  477. begin
  478. if (LastMouseEvent.Buttons<>0) and
  479. ((LastMouseEvent.X<>MouseEvent.X) or (LastMouseEvent.Y<>MouseEvent.Y)) then
  480. begin
  481. MouseEvent.Action:=MouseActionMove;
  482. MouseEvent.Buttons:=LastMouseEvent.Buttons;
  483. {$ifdef DebugMouse}
  484. Writeln(system.stderr,' Mouse Move (',MouseEvent.X,',',MouseEvent.Y,')');
  485. {$endif DebugMouse}
  486. PutMouseEvent(MouseEvent);
  487. MouseEvent.Buttons:=0;
  488. end;
  489. MouseEvent.Action:=MouseActionUp;
  490. end;
  491. PutMouseEvent(MouseEvent);
  492. {$ifdef DebugMouse}
  493. if MouseEvent.Action=MouseActionDown then
  494. Write(system.stderr,'Button down : ')
  495. else
  496. Write(system.stderr,'Button up : ');
  497. Writeln(system.stderr,'buttons = ',MouseEvent.Buttons,' (',MouseEvent.X,',',MouseEvent.Y,')');
  498. {$endif DebugMouse}
  499. LastMouseEvent:=MouseEvent;
  500. end;
  501. type
  502. TProcedure = procedure;
  503. PTreeElement = ^TTreeElement;
  504. TTreeElement = record
  505. Next,Parent,Child : PTreeElement;
  506. CanBeTerminal : boolean;
  507. char : byte;
  508. ScanValue : byte;
  509. CharValue : byte;
  510. SpecialHandler : TProcedure;
  511. end;
  512. var
  513. RootTree : Array[0..255] of PTreeElement;
  514. function NewPTree(ch : byte;Pa : PTreeElement) : PTreeElement;
  515. var PT : PTreeElement;
  516. begin
  517. New(PT);
  518. FillChar(PT^,SizeOf(TTreeElement),#0);
  519. PT^.char:=ch;
  520. PT^.Parent:=Pa;
  521. if Assigned(Pa) and (Pa^.Child=nil) then
  522. Pa^.Child:=PT;
  523. NewPTree:=PT;
  524. end;
  525. function DoAddSequence(Const St : String; AChar,AScan :byte) : PTreeElement;
  526. var
  527. CurPTree,NPT : PTreeElement;
  528. c : byte;
  529. i : longint;
  530. begin
  531. if St='' then
  532. begin
  533. DoAddSequence:=nil;
  534. exit;
  535. end;
  536. CurPTree:=RootTree[ord(st[1])];
  537. if CurPTree=nil then
  538. begin
  539. CurPTree:=NewPTree(ord(st[1]),nil);
  540. RootTree[ord(st[1])]:=CurPTree;
  541. end;
  542. for i:=2 to Length(St) do
  543. begin
  544. NPT:=CurPTree^.Child;
  545. c:=ord(St[i]);
  546. if NPT=nil then
  547. NPT:=NewPTree(c,CurPTree);
  548. CurPTree:=nil;
  549. while assigned(NPT) and (NPT^.char<c) do
  550. begin
  551. CurPTree:=NPT;
  552. NPT:=NPT^.Next;
  553. end;
  554. if assigned(NPT) and (NPT^.char=c) then
  555. CurPTree:=NPT
  556. else
  557. begin
  558. if CurPTree=nil then
  559. begin
  560. NPT^.Parent^.child:=NewPTree(c,NPT^.Parent);
  561. CurPTree:=NPT^.Parent^.Child;
  562. CurPTree^.Next:=NPT;
  563. end
  564. else
  565. begin
  566. CurPTree^.Next:=NewPTree(c,CurPTree^.Parent);
  567. CurPTree:=CurPTree^.Next;
  568. CurPTree^.Next:=NPT;
  569. end;
  570. end;
  571. end;
  572. if CurPTree^.CanBeTerminal then
  573. begin
  574. { here we have a conflict !! }
  575. { maybe we should claim }
  576. with CurPTree^ do
  577. begin
  578. {$ifdef DEBUG}
  579. if (ScanValue<>AScan) or (CharValue<>AChar) then
  580. Writeln(system.stderr,'key "',st,'" changed value');
  581. if (ScanValue<>AScan) then
  582. Writeln(system.stderr,'Scan was ',ScanValue,' now ',AScan);
  583. if (CharValue<>AChar) then
  584. Writeln(system.stderr,'Char was ',chr(CharValue),' now ',chr(AChar));
  585. {$endif DEBUG}
  586. ScanValue:=AScan;
  587. CharValue:=AChar;
  588. end;
  589. end
  590. else with CurPTree^ do
  591. begin
  592. CanBeTerminal:=True;
  593. ScanValue:=AScan;
  594. CharValue:=AChar;
  595. end;
  596. DoAddSequence:=CurPTree;
  597. end;
  598. procedure AddSequence(Const St : String; AChar,AScan :byte);
  599. begin
  600. DoAddSequence(St,AChar,AScan);
  601. end;
  602. { Returns the Child that as c as char if it exists }
  603. Function FindChild(c : byte;Root : PTreeElement) : PTreeElement;
  604. var
  605. NPT : PTreeElement;
  606. begin
  607. if not assigned(Root) then
  608. begin
  609. FindChild:=nil;
  610. exit;
  611. end;
  612. NPT:=Root^.Child;
  613. while assigned(NPT) and (NPT^.char<c) do
  614. NPT:=NPT^.Next;
  615. if assigned(NPT) and (NPT^.char=c) then
  616. FindChild:=NPT
  617. else
  618. FindChild:=nil;
  619. end;
  620. Function AddSpecialSequence(Const St : string;Proc : TProcedure) : PTreeElement;
  621. var
  622. NPT : PTreeElement;
  623. begin
  624. NPT:=DoAddSequence(St,0,0);
  625. NPT^.SpecialHandler:=Proc;
  626. AddSpecialSequence:=NPT;
  627. end;
  628. function FindSequence(Const St : String;var AChar,AScan :byte) : boolean;
  629. var
  630. NPT : PTreeElement;
  631. I : longint;
  632. begin
  633. FindSequence:=false;
  634. AChar:=0;
  635. AScan:=0;
  636. if St='' then
  637. exit;
  638. NPT:=RootTree[ord(St[1])];
  639. if not assigned(NPT) then
  640. exit;
  641. for i:=2 to Length(St) do
  642. begin
  643. NPT:=FindChild(ord(St[i]),NPT);
  644. if not assigned(NPT) then
  645. exit;
  646. end;
  647. if not NPT^.CanBeTerminal then
  648. exit
  649. else
  650. begin
  651. FindSequence:=true;
  652. AScan:=NPT^.ScanValue;
  653. AChar:=NPT^.CharValue;
  654. end;
  655. end;
  656. Procedure LoadDefaultSequences;
  657. begin
  658. AddSpecialSequence(#27'[M',@GenMouseEvent);
  659. { linux default values }
  660. if IsConsole then
  661. begin
  662. DoAddSequence(#127,8,0);
  663. end
  664. else
  665. begin
  666. DoAddSequence(#127,0,kbDel);
  667. end;
  668. { all Esc letter }
  669. DoAddSequence(#27'A',0,kbAltA);
  670. DoAddSequence(#27'a',0,kbAltA);
  671. DoAddSequence(#27'B',0,kbAltB);
  672. DoAddSequence(#27'b',0,kbAltB);
  673. DoAddSequence(#27'C',0,kbAltC);
  674. DoAddSequence(#27'c',0,kbAltC);
  675. DoAddSequence(#27'D',0,kbAltD);
  676. DoAddSequence(#27'd',0,kbAltD);
  677. DoAddSequence(#27'E',0,kbAltE);
  678. DoAddSequence(#27'e',0,kbAltE);
  679. DoAddSequence(#27'F',0,kbAltF);
  680. DoAddSequence(#27'f',0,kbAltF);
  681. DoAddSequence(#27'G',0,kbAltG);
  682. DoAddSequence(#27'g',0,kbAltG);
  683. DoAddSequence(#27'H',0,kbAltH);
  684. DoAddSequence(#27'h',0,kbAltH);
  685. DoAddSequence(#27'I',0,kbAltI);
  686. DoAddSequence(#27'i',0,kbAltI);
  687. DoAddSequence(#27'J',0,kbAltJ);
  688. DoAddSequence(#27'j',0,kbAltJ);
  689. DoAddSequence(#27'K',0,kbAltK);
  690. DoAddSequence(#27'k',0,kbAltK);
  691. DoAddSequence(#27'L',0,kbAltL);
  692. DoAddSequence(#27'l',0,kbAltL);
  693. DoAddSequence(#27'M',0,kbAltM);
  694. DoAddSequence(#27'm',0,kbAltM);
  695. DoAddSequence(#27'N',0,kbAltN);
  696. DoAddSequence(#27'n',0,kbAltN);
  697. DoAddSequence(#27'O',0,kbAltO);
  698. DoAddSequence(#27'o',0,kbAltO);
  699. DoAddSequence(#27'P',0,kbAltP);
  700. DoAddSequence(#27'p',0,kbAltP);
  701. DoAddSequence(#27'Q',0,kbAltQ);
  702. DoAddSequence(#27'q',0,kbAltQ);
  703. DoAddSequence(#27'R',0,kbAltR);
  704. DoAddSequence(#27'r',0,kbAltR);
  705. DoAddSequence(#27'S',0,kbAltS);
  706. DoAddSequence(#27's',0,kbAltS);
  707. DoAddSequence(#27'T',0,kbAltT);
  708. DoAddSequence(#27't',0,kbAltT);
  709. DoAddSequence(#27'U',0,kbAltU);
  710. DoAddSequence(#27'u',0,kbAltU);
  711. DoAddSequence(#27'V',0,kbAltV);
  712. DoAddSequence(#27'v',0,kbAltV);
  713. DoAddSequence(#27'W',0,kbAltW);
  714. DoAddSequence(#27'w',0,kbAltW);
  715. DoAddSequence(#27'X',0,kbAltX);
  716. DoAddSequence(#27'x',0,kbAltX);
  717. DoAddSequence(#27'Y',0,kbAltY);
  718. DoAddSequence(#27'y',0,kbAltY);
  719. DoAddSequence(#27'Z',0,kbAltZ);
  720. DoAddSequence(#27'z',0,kbAltZ);
  721. DoAddSequence(#27'-',0,kbAltMinus);
  722. DoAddSequence(#27'=',0,kbAltEqual);
  723. DoAddSequence(#27'0',0,kbAlt0);
  724. DoAddSequence(#27'1',0,kbAlt1);
  725. DoAddSequence(#27'2',0,kbAlt2);
  726. DoAddSequence(#27'3',0,kbAlt3);
  727. DoAddSequence(#27'4',0,kbAlt4);
  728. DoAddSequence(#27'5',0,kbAlt5);
  729. DoAddSequence(#27'6',0,kbAlt6);
  730. DoAddSequence(#27'7',0,kbAlt7);
  731. DoAddSequence(#27'8',0,kbAlt8);
  732. DoAddSequence(#27'9',0,kbAlt9);
  733. { vt100 default values }
  734. DoAddSequence(#27'[[A',0,kbF1);
  735. DoAddSequence(#27'[[B',0,kbF2);
  736. DoAddSequence(#27'[[C',0,kbF3);
  737. DoAddSequence(#27'[[D',0,kbF4);
  738. DoAddSequence(#27'[[E',0,kbF5);
  739. DoAddSequence(#27'[17~',0,kbF6);
  740. DoAddSequence(#27'[18~',0,kbF7);
  741. DoAddSequence(#27'[19~',0,kbF8);
  742. DoAddSequence(#27'[20~',0,kbF9);
  743. DoAddSequence(#27'[21~',0,kbF10);
  744. DoAddSequence(#27'[23~',0,kbF11);
  745. DoAddSequence(#27'[24~',0,kbF12);
  746. DoAddSequence(#27'[25~',0,kbShiftF3);
  747. DoAddSequence(#27'[26~',0,kbShiftF4);
  748. DoAddSequence(#27'[28~',0,kbShiftF5);
  749. DoAddSequence(#27'[29~',0,kbShiftF6);
  750. DoAddSequence(#27'[31~',0,kbShiftF7);
  751. DoAddSequence(#27'[32~',0,kbShiftF8);
  752. DoAddSequence(#27'[33~',0,kbShiftF9);
  753. DoAddSequence(#27'[34~',0,kbShiftF10);
  754. DoAddSequence(#27#27'[[A',0,kbAltF1);
  755. DoAddSequence(#27#27'[[B',0,kbAltF2);
  756. DoAddSequence(#27#27'[[C',0,kbAltF3);
  757. DoAddSequence(#27#27'[[D',0,kbAltF4);
  758. DoAddSequence(#27#27'[[E',0,kbAltF5);
  759. DoAddSequence(#27#27'[17~',0,kbAltF6);
  760. DoAddSequence(#27#27'[18~',0,kbAltF7);
  761. DoAddSequence(#27#27'[19~',0,kbAltF8);
  762. DoAddSequence(#27#27'[20~',0,kbAltF9);
  763. DoAddSequence(#27#27'[21~',0,kbAltF10);
  764. DoAddSequence(#27#27'[23~',0,kbAltF11);
  765. DoAddSequence(#27#27'[24~',0,kbAltF12);
  766. DoAddSequence(#27'[A',0,kbUp);
  767. DoAddSequence(#27'[B',0,kbDown);
  768. DoAddSequence(#27'[C',0,kbRight);
  769. DoAddSequence(#27'[D',0,kbLeft);
  770. DoAddSequence(#27'[F',0,kbEnd);
  771. DoAddSequence(#27'[H',0,kbHome);
  772. DoAddSequence(#27'[Z',0,kbShiftTab);
  773. DoAddSequence(#27'[5~',0,kbPgUp);
  774. DoAddSequence(#27'[6~',0,kbPgDn);
  775. DoAddSequence(#27'[4~',0,kbEnd);
  776. DoAddSequence(#27'[1~',0,kbHome);
  777. DoAddSequence(#27'[2~',0,kbIns);
  778. DoAddSequence(#27'[3~',0,kbDel);
  779. DoAddSequence(#27#27'[A',0,kbAltUp);
  780. DoAddSequence(#27#27'[B',0,kbAltDown);
  781. DoAddSequence(#27#27'[D',0,kbAltLeft);
  782. DoAddSequence(#27#27'[C',0,kbAltRight);
  783. DoAddSequence(#27#27'[5~',0,kbAltPgUp);
  784. DoAddSequence(#27#27'[6~',0,kbAltPgDn);
  785. DoAddSequence(#27#27'[4~',0,kbAltEnd);
  786. DoAddSequence(#27#27'[1~',0,kbAltHome);
  787. DoAddSequence(#27#27'[2~',0,kbAltIns);
  788. DoAddSequence(#27#27'[3~',0,kbAltDel);
  789. DoAddSequence(#27'OP',0,kbF1);
  790. DoAddSequence(#27'OQ',0,kbF2);
  791. DoAddSequence(#27'OR',0,kbF3);
  792. DoAddSequence(#27'OS',0,kbF4);
  793. DoAddSequence(#27'Ot',0,kbF5);
  794. DoAddSequence(#27'Ou',0,kbF6);
  795. DoAddSequence(#27'Ov',0,kbF7);
  796. DoAddSequence(#27'Ol',0,kbF8);
  797. DoAddSequence(#27'Ow',0,kbF9);
  798. DoAddSequence(#27'Ox',0,kbF10);
  799. DoAddSequence(#27'Oy',0,kbF11);
  800. DoAddSequence(#27'Oz',0,kbF12);
  801. DoAddSequence(#27#27'OP',0,kbAltF1);
  802. DoAddSequence(#27#27'OQ',0,kbAltF2);
  803. DoAddSequence(#27#27'OR',0,kbAltF3);
  804. DoAddSequence(#27#27'OS',0,kbAltF4);
  805. DoAddSequence(#27#27'Ot',0,kbAltF5);
  806. DoAddSequence(#27#27'Ou',0,kbAltF6);
  807. DoAddSequence(#27#27'Ov',0,kbAltF7);
  808. DoAddSequence(#27#27'Ol',0,kbAltF8);
  809. DoAddSequence(#27#27'Ow',0,kbAltF9);
  810. DoAddSequence(#27#27'Ox',0,kbAltF10);
  811. DoAddSequence(#27#27'Oy',0,kbAltF11);
  812. DoAddSequence(#27#27'Oz',0,kbAltF12);
  813. DoAddSequence(#27'OA',0,kbUp);
  814. DoAddSequence(#27'OB',0,kbDown);
  815. DoAddSequence(#27'OC',0,kbRight);
  816. DoAddSequence(#27'OD',0,kbLeft);
  817. DoAddSequence(#27#27'OA',0,kbAltUp);
  818. DoAddSequence(#27#27'OB',0,kbAltDown);
  819. DoAddSequence(#27#27'OC',0,kbAltRight);
  820. DoAddSequence(#27#27'OD',0,kbAltLeft);
  821. { xterm default values }
  822. { xterm alternate default values }
  823. { ignored sequences }
  824. DoAddSequence(#27'[?1;0c',0,0);
  825. DoAddSequence(#27'[?1l',0,0);
  826. DoAddSequence(#27'[?1h',0,0);
  827. DoAddSequence(#27'[?1;2c',0,0);
  828. DoAddSequence(#27'[?7l',0,0);
  829. DoAddSequence(#27'[?7h',0,0);
  830. end;
  831. function EnterEscapeSeqNdx(Ndx: Word;Char,Scan : byte) : PTreeElement;
  832. var
  833. P,pdelay: PChar;
  834. St : string;
  835. begin
  836. EnterEscapeSeqNdx:=nil;
  837. P:=cur_term_Strings^[Ndx];
  838. if assigned(p) then
  839. begin { Do not record the delays }
  840. pdelay:=strpos(p,'$<');
  841. if assigned(pdelay) then
  842. pdelay^:=#0;
  843. St:=StrPas(p);
  844. EnterEscapeSeqNdx:=DoAddSequence(St,Char,Scan);
  845. if assigned(pdelay) then
  846. pdelay^:='$';
  847. end;
  848. end;
  849. Procedure LoadTermInfoSequences;
  850. var
  851. err : longint;
  852. begin
  853. if not assigned(cur_term) then
  854. setupterm(nil, stdoutputhandle, err);
  855. if not assigned(cur_term_Strings) then
  856. exit;
  857. EnterEscapeSeqNdx(key_f1,0,kbF1);
  858. EnterEscapeSeqNdx(key_f2,0,kbF2);
  859. EnterEscapeSeqNdx(key_f3,0,kbF3);
  860. EnterEscapeSeqNdx(key_f4,0,kbF4);
  861. EnterEscapeSeqNdx(key_f5,0,kbF5);
  862. EnterEscapeSeqNdx(key_f6,0,kbF6);
  863. EnterEscapeSeqNdx(key_f7,0,kbF7);
  864. EnterEscapeSeqNdx(key_f8,0,kbF8);
  865. EnterEscapeSeqNdx(key_f9,0,kbF9);
  866. EnterEscapeSeqNdx(key_f10,0,kbF10);
  867. EnterEscapeSeqNdx(key_f11,0,kbF11);
  868. EnterEscapeSeqNdx(key_f12,0,kbF12);
  869. EnterEscapeSeqNdx(key_up,0,kbUp);
  870. EnterEscapeSeqNdx(key_down,0,kbDown);
  871. EnterEscapeSeqNdx(key_left,0,kbLeft);
  872. EnterEscapeSeqNdx(key_right,0,kbRight);
  873. EnterEscapeSeqNdx(key_ppage,0,kbPgUp);
  874. EnterEscapeSeqNdx(key_npage,0,kbPgDn);
  875. EnterEscapeSeqNdx(key_end,0,kbEnd);
  876. EnterEscapeSeqNdx(key_home,0,kbHome);
  877. EnterEscapeSeqNdx(key_ic,0,kbIns);
  878. EnterEscapeSeqNdx(key_dc,0,kbDel);
  879. EnterEscapeSeqNdx(key_stab,0,kbShiftTab);
  880. { EnterEscapeSeqNdx(key_,0,kb);
  881. EnterEscapeSeqNdx(key_,0,kb); }
  882. end;
  883. {$endif not NotUseTree}
  884. Function RawReadKey:char;
  885. Var
  886. fdsin : fdSet;
  887. Begin
  888. {Check Buffer first}
  889. if KeySend<>KeyPut then
  890. begin
  891. RawReadKey:=PopKey;
  892. exit;
  893. end;
  894. {Wait for Key}
  895. if not sysKeyPressed then
  896. begin
  897. FD_Zero (fdsin);
  898. FD_Set (StdInputHandle,fdsin);
  899. Select (StdInputHandle+1,@fdsin,nil,nil,nil);
  900. end;
  901. RawReadKey:=ttyRecvChar;
  902. end;
  903. Function RawReadString : String;
  904. Var
  905. ch : char;
  906. fdsin : fdSet;
  907. St : String;
  908. Begin
  909. St:=RawReadKey;
  910. FD_Zero (fdsin);
  911. FD_Set (StdInputHandle,fdsin);
  912. Repeat
  913. if InCnt=0 then
  914. Select(StdInputHandle+1,@fdsin,nil,nil,10);
  915. if SysKeyPressed then
  916. ch:=ttyRecvChar
  917. else
  918. ch:=#0;
  919. if ch<>#0 then
  920. St:=St+ch;
  921. Until ch=#0;
  922. RawReadString:=St;
  923. end;
  924. Function ReadKey(var IsAlt : boolean):char;
  925. Var
  926. ch : char;
  927. {$ifdef NotUseTree}
  928. OldState : longint;
  929. State : longint;
  930. {$endif NotUseTree}
  931. is_delay : boolean;
  932. fdsin : fdSet;
  933. store : array [0..8] of char;
  934. arrayind : byte;
  935. {$ifndef NotUseTree}
  936. NPT,NNPT : PTreeElement;
  937. {$else NotUseTree}
  938. procedure GenMouseEvent;
  939. var MouseEvent: TMouseEvent;
  940. begin
  941. Fillchar(MouseEvent,SizeOf(TMouseEvent),#0);
  942. case ch of
  943. #32 : {left button pressed }
  944. MouseEvent.buttons:=1;
  945. #33 : {middle button pressed }
  946. MouseEvent.buttons:=2;
  947. #34 : { right button pressed }
  948. MouseEvent.buttons:=4;
  949. #35 : { no button pressed };
  950. end;
  951. if InCnt=0 then
  952. Select(StdInputHandle+1,@fdsin,nil,nil,10);
  953. ch:=ttyRecvChar;
  954. MouseEvent.x:=Ord(ch)-ord(' ')-1;
  955. if InCnt=0 then
  956. Select(StdInputHandle+1,@fdsin,nil,nil,10);
  957. ch:=ttyRecvChar;
  958. MouseEvent.y:=Ord(ch)-ord(' ')-1;
  959. if (MouseEvent.buttons<>0) then
  960. MouseEvent.action:=MouseActionDown
  961. else
  962. begin
  963. if (LastMouseEvent.Buttons<>0) and
  964. ((LastMouseEvent.X<>MouseEvent.X) or (LastMouseEvent.Y<>MouseEvent.Y)) then
  965. begin
  966. MouseEvent.Action:=MouseActionMove;
  967. MouseEvent.Buttons:=LastMouseEvent.Buttons;
  968. PutMouseEvent(MouseEvent);
  969. MouseEvent.Buttons:=0;
  970. end;
  971. MouseEvent.Action:=MouseActionUp;
  972. end;
  973. PutMouseEvent(MouseEvent);
  974. LastMouseEvent:=MouseEvent;
  975. end;
  976. {$endif NotUseTree}
  977. procedure RestoreArray;
  978. var
  979. i : byte;
  980. begin
  981. for i:=0 to arrayind-1 do
  982. PushKey(store[i]);
  983. end;
  984. Begin
  985. IsAlt:=false;
  986. {Check Buffer first}
  987. if KeySend<>KeyPut then
  988. begin
  989. ReadKey:=PopKey;
  990. exit;
  991. end;
  992. {Wait for Key}
  993. if not sysKeyPressed then
  994. begin
  995. FD_Zero (fdsin);
  996. FD_Set (StdInputHandle,fdsin);
  997. Select (StdInputHandle+1,@fdsin,nil,nil,nil);
  998. end;
  999. ch:=ttyRecvChar;
  1000. {$ifndef NotUseTree}
  1001. NPT:=RootTree[ord(ch)];
  1002. if not assigned(NPT) then
  1003. PushKey(ch)
  1004. else
  1005. begin
  1006. FD_Zero(fdsin);
  1007. fd_Set(StdInputHandle,fdsin);
  1008. store[0]:=ch;
  1009. arrayind:=1;
  1010. while assigned(NPT) and syskeypressed do
  1011. begin
  1012. if (InCnt=0) then
  1013. Select(StdInputHandle+1,@fdsin,nil,nil,10);
  1014. ch:=ttyRecvChar;
  1015. NNPT:=FindChild(ord(ch),NPT);
  1016. if assigned(NNPT) then
  1017. Begin
  1018. NPT:=NNPT;
  1019. if NPT^.CanBeTerminal and
  1020. assigned(NPT^.SpecialHandler) then
  1021. break;
  1022. End;
  1023. if ch<>#0 then
  1024. begin
  1025. store[arrayind]:=ch;
  1026. inc(arrayind);
  1027. end;
  1028. end;
  1029. if assigned(NPT) and NPT^.CanBeTerminal then
  1030. begin
  1031. if assigned(NPT^.SpecialHandler) then
  1032. begin
  1033. NPT^.SpecialHandler;
  1034. PushExt(0);
  1035. end
  1036. else if NPT^.CharValue<>0 then
  1037. PushKey(chr(NPT^.CharValue))
  1038. else if NPT^.ScanValue<>0 then
  1039. PushExt(NPT^.ScanValue);
  1040. end
  1041. else
  1042. RestoreArray;
  1043. {$else NotUseTree}
  1044. {Esc Found ?}
  1045. If (ch=#27) then
  1046. begin
  1047. FD_Zero(fdsin);
  1048. fd_Set(StdInputHandle,fdsin);
  1049. State:=1;
  1050. store[0]:=#27;
  1051. arrayind:=1;
  1052. {$ifdef logging}
  1053. write(f,'Esc');
  1054. {$endif logging}
  1055. if InCnt=0 then
  1056. Select(StdInputHandle+1,@fdsin,nil,nil,10);
  1057. while (State<>0) and (sysKeyPressed) do
  1058. begin
  1059. ch:=ttyRecvChar;
  1060. store[arrayind]:=ch;
  1061. inc(arrayind);
  1062. {$ifdef logging}
  1063. if ord(ch)>31 then
  1064. write(f,ch)
  1065. else
  1066. write(f,'#',ord(ch):2);
  1067. {$endif logging}
  1068. OldState:=State;
  1069. State:=0;
  1070. case OldState of
  1071. 1 : begin {Esc}
  1072. case ch of
  1073. 'a'..'z',
  1074. '0'..'9',
  1075. '-','=' : PushExt(FAltKey(ch));
  1076. 'A'..'N',
  1077. 'P'..'Z' : PushExt(FAltKey(chr(ord(ch)+ord('a')-ord('A'))));
  1078. #10 : PushKey(#10);
  1079. #13 : PushKey(#10);
  1080. #27 : begin
  1081. IsAlt:=True;
  1082. State:=1;
  1083. end;
  1084. #127 : PushExt(kbAltDel);
  1085. '[' : State:=2;
  1086. 'O' : State:=6;
  1087. else
  1088. RestoreArray;
  1089. end;
  1090. end;
  1091. 2 : begin {Esc[}
  1092. case ch of
  1093. '[' : State:=3;
  1094. 'A' : PushExt(kbUp);
  1095. 'B' : PushExt(kbDown);
  1096. 'C' : PushExt(kbRight);
  1097. 'D' : PushExt(kbLeft);
  1098. 'F' : PushExt(kbEnd);
  1099. 'G' : PushKey('5');
  1100. 'H' : PushExt(kbHome);
  1101. 'K' : PushExt(kbEnd);
  1102. 'M' : State:=13;
  1103. '1' : State:=4;
  1104. '2' : State:=5;
  1105. '3' : State:=12;{PushExt(kbDel)}
  1106. '4' : PushExt(kbEnd);
  1107. '5' : PushExt(73);
  1108. '6' : PushExt(kbPgDn);
  1109. '?' : State:=7;
  1110. else
  1111. RestoreArray;
  1112. end;
  1113. if ch in ['4'..'6'] then
  1114. State:=255;
  1115. end;
  1116. 3 : begin {Esc[[}
  1117. case ch of
  1118. 'A' : PushExt(kbF1);
  1119. 'B' : PushExt(kbF2);
  1120. 'C' : PushExt(kbF3);
  1121. 'D' : PushExt(kbF4);
  1122. 'E' : PushExt(kbF5);
  1123. else
  1124. RestoreArray;
  1125. end;
  1126. end;
  1127. 4 : begin {Esc[1}
  1128. case ch of
  1129. '~' : PushExt(kbHome);
  1130. '7' : PushExt(kbF6);
  1131. '8' : PushExt(kbF7);
  1132. '9' : PushExt(kbF8);
  1133. else
  1134. RestoreArray;
  1135. end;
  1136. if (Ch<>'~') then
  1137. State:=255;
  1138. end;
  1139. 5 : begin {Esc[2}
  1140. case ch of
  1141. '~' : PushExt(kbIns);
  1142. '0' : pushExt(kbF9);
  1143. '1' : PushExt(kbF10);
  1144. '3' : PushExt($85){F11, but ShiftF1 also !!};
  1145. '4' : PushExt($86){F12, but Shift F2 also !!};
  1146. '5' : PushExt($56){ShiftF3};
  1147. '6' : PushExt($57){ShiftF4};
  1148. '8' : PushExt($58){ShiftF5};
  1149. '9' : PushExt($59){ShiftF6};
  1150. else
  1151. RestoreArray;
  1152. end;
  1153. if (Ch<>'~') then
  1154. State:=255;
  1155. end;
  1156. 12 : begin {Esc[3}
  1157. case ch of
  1158. '~' : PushExt(kbDel);
  1159. '1' : PushExt($5A){ShiftF7};
  1160. '2' : PushExt($5B){ShiftF8};
  1161. '3' : PushExt($5C){ShiftF9};
  1162. '4' : PushExt($5D){ShiftF10};
  1163. else
  1164. RestoreArray;
  1165. end;
  1166. if (Ch<>'~') then
  1167. State:=255;
  1168. end;
  1169. 6 : begin {EscO Function keys in vt100 mode PM }
  1170. case ch of
  1171. 'P' : {F1}PushExt(kbF1);
  1172. 'Q' : {F2}PushExt(kbF2);
  1173. 'R' : {F3}PushExt(kbF3);
  1174. 'S' : {F4}PushExt(kbF4);
  1175. 't' : {F5}PushExt(kbF5);
  1176. 'u' : {F6}PushExt(kbF6);
  1177. 'v' : {F7}PushExt(kbF7);
  1178. 'l' : {F8}PushExt(kbF8);
  1179. 'w' : {F9}PushExt(kbF9);
  1180. 'x' : {F10}PushExt(kbF10);
  1181. 'D' : {keyLeft}PushExt($4B);
  1182. 'C' : {keyRight}PushExt($4D);
  1183. 'A' : {keyUp}PushExt($48);
  1184. 'B' : {keyDown}PushExt($50);
  1185. else
  1186. RestoreArray;
  1187. end;
  1188. end;
  1189. 7 : begin {Esc[? keys in vt100 mode PM }
  1190. case ch of
  1191. '0' : State:=11;
  1192. '1' : State:=8;
  1193. '7' : State:=9;
  1194. else
  1195. RestoreArray;
  1196. end;
  1197. end;
  1198. 8 : begin {Esc[?1 keys in vt100 mode PM }
  1199. case ch of
  1200. 'l' : {local mode};
  1201. 'h' : {transmit mode};
  1202. ';' : { 'Esc[1;0c seems to be sent by M$ telnet app
  1203. for no hangup purposes }
  1204. state:=10;
  1205. else
  1206. RestoreArray;
  1207. end;
  1208. end;
  1209. 9 : begin {Esc[?7 keys in vt100 mode PM }
  1210. case ch of
  1211. 'l' : {exit_am_mode};
  1212. 'h' : {enter_am_mode};
  1213. else
  1214. RestoreArray;
  1215. end;
  1216. end;
  1217. 10 : begin {Esc[?1; keys in vt100 mode PM }
  1218. case ch of
  1219. '0' : state:=11;
  1220. else
  1221. RestoreArray;
  1222. end;
  1223. end;
  1224. 11 : begin {Esc[?1;0 keys in vt100 mode PM }
  1225. case ch of
  1226. 'c' : ;
  1227. else
  1228. RestoreArray;
  1229. end;
  1230. end;
  1231. 13 : begin {Esc[M mouse prefix for xterm }
  1232. GenMouseEvent;
  1233. end;
  1234. 255 : { just forget this trailing char };
  1235. end;
  1236. if (State<>0) and (InCnt=0) then
  1237. Select(StdInputHandle+1,@fdsin,nil,nil,10);
  1238. end;
  1239. if State=1 then
  1240. PushKey(ch);
  1241. {$endif NotUseTree}
  1242. if ch='$' then
  1243. begin { '$<XX>' means a delay of XX millisecs }
  1244. is_delay :=false;
  1245. Select(StdInputHandle+1,@fdsin,nil,nil,10);
  1246. if (sysKeyPressed) then
  1247. begin
  1248. ch:=ttyRecvChar;
  1249. is_delay:=(ch='<');
  1250. if not is_delay then
  1251. begin
  1252. PushKey('$');
  1253. PushKey(ch);
  1254. end
  1255. else
  1256. begin
  1257. {$ifdef logging}
  1258. write(f,'$<');
  1259. {$endif logging}
  1260. Select(StdInputHandle+1,@fdsin,nil,nil,10);
  1261. while (sysKeyPressed) and (ch<>'>') do
  1262. begin
  1263. { Should we really repect this delay ?? }
  1264. ch:=ttyRecvChar;
  1265. {$ifdef logging}
  1266. write(f,ch);
  1267. {$endif logging}
  1268. Select(StdInputHandle+1,@fdsin,nil,nil,10);
  1269. end;
  1270. end;
  1271. end
  1272. else
  1273. PushKey('$');
  1274. end;
  1275. end
  1276. {$ifdef logging}
  1277. writeln(f);
  1278. {$endif logging}
  1279. {$ifndef NotUseTree}
  1280. ;
  1281. ReadKey:=PopKey;
  1282. {$else NotUseTree}
  1283. else
  1284. Begin
  1285. case ch of
  1286. #127 : PushKey(#8);
  1287. else
  1288. PushKey(ch);
  1289. end;
  1290. End;
  1291. ReadKey:=PopKey;
  1292. {$endif NotUseTree}
  1293. End;
  1294. function ShiftState:byte;
  1295. var
  1296. arg,shift : longint;
  1297. begin
  1298. arg:=6;
  1299. shift:=0;
  1300. {$Ifndef BSD}
  1301. if IOCtl(StdInputHandle,TIOCLINUX,@arg) then
  1302. begin
  1303. if (arg and 8)<>0 then
  1304. shift:=kbAlt;
  1305. if (arg and 4)<>0 then
  1306. inc(shift,kbCtrl);
  1307. { 2 corresponds to AltGr so set both kbAlt and kbCtrl PM }
  1308. if (arg and 2)<>0 then
  1309. shift:=shift or (kbAlt or kbCtrl);
  1310. if (arg and 1)<>0 then
  1311. inc(shift,kbShift);
  1312. end;
  1313. {$endif}
  1314. ShiftState:=shift;
  1315. end;
  1316. { Exported functions }
  1317. procedure InitKeyboard;
  1318. begin
  1319. SetRawMode(true);
  1320. patchkeyboard;
  1321. {$ifdef logging}
  1322. assign(f,'keyboard.log');
  1323. rewrite(f);
  1324. {$endif logging}
  1325. if not IsConsole then
  1326. begin
  1327. { default for Shift prefix is ^ A}
  1328. if ShiftPrefix = 0 then
  1329. ShiftPrefix:=1;
  1330. {default for Alt prefix is ^Z }
  1331. if AltPrefix=0 then
  1332. AltPrefix:=26;
  1333. { default for Ctrl Prefix is ^W }
  1334. if CtrlPrefix=0 then
  1335. CtrlPrefix:=23;
  1336. end;
  1337. {$ifndef NotUseTree}
  1338. LoadDefaultSequences;
  1339. LoadTerminfoSequences;
  1340. {$endif not NotUseTree}
  1341. end;
  1342. procedure DoneKeyboard;
  1343. begin
  1344. unpatchkeyboard;
  1345. SetRawMode(false);
  1346. {$ifdef logging}
  1347. close(f);
  1348. {$endif logging}
  1349. end;
  1350. function GetKeyEvent: TKeyEvent;
  1351. function EvalScan(b:byte):byte;
  1352. const
  1353. DScan:array[0..31] of byte = (
  1354. $39, $02, $28, $04, $05, $06, $08, $28,
  1355. $0A, $0B, $09, $0D, $33, $0C, $34, $35,
  1356. $0B, $02, $03, $04, $05, $06, $07, $08,
  1357. $09, $0A, $27, $27, $33, $0D, $34, $35);
  1358. LScan:array[0..31] of byte = (
  1359. $29, $1E, $30, $2E, $20, $12, $21, $22,
  1360. $23, $17, $24, $25, $26, $32, $31, $18,
  1361. $19, $10, $13, $1F, $14, $16, $2F, $11,
  1362. $2D, $15, $2C, $1A, $2B, $1B, $29, $0C);
  1363. begin
  1364. if (b and $E0)=$20 { digits / leters } then
  1365. EvalScan:=DScan[b and $1F]
  1366. else
  1367. case b of
  1368. $08:EvalScan:=$0E; { backspace }
  1369. $09:EvalScan:=$0F; { TAB }
  1370. $0D:EvalScan:=$1C; { CR }
  1371. $1B:EvalScan:=$01; { esc }
  1372. $40:EvalScan:=$03; { @ }
  1373. $5E:EvalScan:=$07; { ^ }
  1374. $60:EvalScan:=$29; { ` }
  1375. else
  1376. EvalScan:=LScan[b and $1F];
  1377. end;
  1378. end;
  1379. function EvalScanZ(b:byte):byte;
  1380. begin
  1381. EvalScanZ:=b;
  1382. if b in [$3B..$44] { F1..F10 -> Alt-F1..Alt-F10} then
  1383. EvalScanZ:=b+$2D;
  1384. end;
  1385. const
  1386. {kbHome, kbUp, kbPgUp,Missing, kbLeft,
  1387. kbCenter, kbRight, kbAltGrayPlus, kbend,
  1388. kbDown, kbPgDn, kbIns, kbDel }
  1389. CtrlArrow : array [kbHome..kbDel] of byte =
  1390. {($77,$8d,$84,$8e,$73,$8f,$74,$90,$75,$91,$76);}
  1391. (kbCtrlHome,kbCtrlUp,kbCtrlPgUp,kbNoKey,kbCtrlLeft,
  1392. kbCtrlCenter,kbCtrlRight,kbAltGrayPlus,kbCtrlEnd,
  1393. kbCtrlDown,kbCtrlPgDn,kbCtrlIns,kbCtrlDel);
  1394. AltArrow : array [kbHome..kbDel] of byte =
  1395. (kbAltHome,kbAltUp,kbAltPgUp,kbNoKey,kbAltLeft,
  1396. kbCenter,kbAltRight,kbAltGrayPlus,kbAltEnd,
  1397. kbAltDown,kbAltPgDn,kbAltIns,kbAltDel);
  1398. var
  1399. MyScan,
  1400. SState : byte;
  1401. MyChar : char;
  1402. EscUsed,AltPrefixUsed,CtrlPrefixUsed,ShiftPrefixUsed,IsAlt,Again : boolean;
  1403. begin {main}
  1404. if PendingKeyEvent<>0 then
  1405. begin
  1406. GetKeyEvent:=PendingKeyEvent;
  1407. PendingKeyEvent:=0;
  1408. exit;
  1409. end;
  1410. MyChar:=Readkey(IsAlt);
  1411. MyScan:=ord(MyChar);
  1412. SState:=ShiftState;
  1413. CtrlPrefixUsed:=false;
  1414. AltPrefixUsed:=false;
  1415. ShiftPrefixUsed:=false;
  1416. EscUsed:=false;
  1417. if IsAlt then
  1418. SState:=SState or kbAlt;
  1419. repeat
  1420. again:=false;
  1421. if Mychar=#0 then
  1422. begin
  1423. MyScan:=ord(ReadKey(IsAlt));
  1424. { Handle Ctrl-<x>, but not AltGr-<x> }
  1425. if ((SState and kbCtrl)<>0) and ((SState and kbAlt) = 0) then
  1426. begin
  1427. case MyScan of
  1428. kbHome..kbDel : { cArrow }
  1429. MyScan:=CtrlArrow[MyScan];
  1430. kbF1..KbF10 : { cF1-cF10 }
  1431. MyScan:=MyScan+kbCtrlF1-kbF1;
  1432. kbF11..KbF12 : { cF11-cF12 }
  1433. MyScan:=MyScan+kbCtrlF11-kbF11;
  1434. end;
  1435. end
  1436. { Handle Alt-<x>, but not AltGr }
  1437. else if ((SState and kbAlt)<>0) and ((SState and kbCtrl) = 0) then
  1438. begin
  1439. case MyScan of
  1440. kbHome..kbDel : { AltArrow }
  1441. MyScan:=AltArrow[MyScan];
  1442. kbF1..KbF10 : { aF1-aF10 }
  1443. MyScan:=MyScan+kbAltF1-kbF1;
  1444. kbF11..KbF12 : { aF11-aF12 }
  1445. MyScan:=MyScan+kbAltF11-kbF11;
  1446. end;
  1447. end
  1448. else if (SState and kbShift)<>0 then
  1449. begin
  1450. case MyScan of
  1451. kbIns: MyScan:=kbShiftIns;
  1452. kbDel: MyScan:=kbShiftDel;
  1453. kbF1..KbF10 : { sF1-sF10 }
  1454. MyScan:=MyScan+kbShiftF1-kbF1;
  1455. kbF11..KbF12 : { sF11-sF12 }
  1456. MyScan:=MyScan+kbShiftF11-kbF11;
  1457. end;
  1458. end;
  1459. if (MyChar<>#0) or (MyScan<>0) or (SState<>0) then
  1460. GetKeyEvent:=$3000000 or ord(MyChar) or (MyScan shl 8) or (SState shl 16)
  1461. else
  1462. GetKeyEvent:=0;
  1463. exit;
  1464. end
  1465. else if MyChar=#27 then
  1466. begin
  1467. if EscUsed then
  1468. SState:=SState and not kbAlt
  1469. else
  1470. begin
  1471. SState:=SState or kbAlt;
  1472. Again:=true;
  1473. EscUsed:=true;
  1474. end;
  1475. end
  1476. else if (AltPrefix<>0) and (MyChar=chr(AltPrefix)) then
  1477. begin { ^Z - replace Alt for Linux OS }
  1478. if AltPrefixUsed then
  1479. begin
  1480. SState:=SState and not kbAlt;
  1481. end
  1482. else
  1483. begin
  1484. AltPrefixUsed:=true;
  1485. SState:=SState or kbAlt;
  1486. Again:=true;
  1487. end;
  1488. end
  1489. else if (CtrlPrefix<>0) and (MyChar=chr(CtrlPrefix)) then
  1490. begin
  1491. if CtrlPrefixUsed then
  1492. SState:=SState and not kbCtrl
  1493. else
  1494. begin
  1495. CtrlPrefixUsed:=true;
  1496. SState:=SState or kbCtrl;
  1497. Again:=true;
  1498. end;
  1499. end
  1500. else if (ShiftPrefix<>0) and (MyChar=chr(ShiftPrefix)) then
  1501. begin
  1502. if ShiftPrefixUsed then
  1503. SState:=SState and not kbShift
  1504. else
  1505. begin
  1506. ShiftPrefixUsed:=true;
  1507. SState:=SState or kbShift;
  1508. Again:=true;
  1509. end;
  1510. end;
  1511. if not again then
  1512. begin
  1513. MyScan:=EvalScan(ord(MyChar));
  1514. if ((SState and kbAlt)<>0) and ((SState and kbCtrl) = 0) then
  1515. begin
  1516. if MyScan in [$02..$0D] then
  1517. inc(MyScan,$76);
  1518. MyChar:=chr(0);
  1519. end
  1520. else if (SState and kbShift)<>0 then
  1521. if MyChar=#9 then
  1522. begin
  1523. MyChar:=#0;
  1524. MyScan:=kbShiftTab;
  1525. end;
  1526. end
  1527. else
  1528. begin
  1529. MyChar:=Readkey(IsAlt);
  1530. MyScan:=ord(MyChar);
  1531. if IsAlt then
  1532. SState:=SState or kbAlt;
  1533. end;
  1534. until not Again;
  1535. if (MyChar<>#0) or (MyScan<>0) or (SState<>0) then
  1536. GetKeyEvent:=$3000000 or ord(MyChar) or (MyScan shl 8) or (SState shl 16)
  1537. else
  1538. GetKeyEvent:=0;
  1539. end;
  1540. function PollKeyEvent: TKeyEvent;
  1541. begin
  1542. if PendingKeyEvent<>0 then
  1543. exit(PendingKeyEvent);
  1544. if keypressed then
  1545. begin
  1546. { just get the key and place it in the pendingkeyevent }
  1547. PendingKeyEvent:=GetKeyEvent;
  1548. PollKeyEvent:=PendingKeyEvent;
  1549. end
  1550. else
  1551. PollKeyEvent:=0;
  1552. end;
  1553. function PollShiftStateEvent: TKeyEvent;
  1554. begin
  1555. PollShiftStateEvent:=ShiftState shl 16;
  1556. end;
  1557. { Function key translation }
  1558. type
  1559. TTranslationEntry = packed record
  1560. Min, Max: Byte;
  1561. Offset: Word;
  1562. end;
  1563. const
  1564. TranslationTableEntries = 12;
  1565. TranslationTable: array [1..TranslationTableEntries] of TTranslationEntry =
  1566. ((Min: $3B; Max: $44; Offset: kbdF1), { function keys F1-F10 }
  1567. (Min: $54; Max: $5D; Offset: kbdF1), { Shift fn keys F1-F10 }
  1568. (Min: $5E; Max: $67; Offset: kbdF1), { Ctrl fn keys F1-F10 }
  1569. (Min: $68; Max: $71; Offset: kbdF1), { Alt fn keys F1-F10 }
  1570. (Min: $85; Max: $86; Offset: kbdF11), { function keys F11-F12 }
  1571. (Min: $87; Max: $88; Offset: kbdF11), { Shift+function keys F11-F12 }
  1572. (Min: $89; Max: $8A; Offset: kbdF11), { Ctrl+function keys F11-F12 }
  1573. (Min: $8B; Max: $8C; Offset: kbdF11), { Alt+function keys F11-F12 }
  1574. (Min: $47; Max: $49; Offset: kbdHome), { Keypad keys kbdHome-kbdPgUp }
  1575. (Min: $4B; Max: $4D; Offset: kbdLeft), { Keypad keys kbdLeft-kbdRight }
  1576. (Min: $4F; Max: $51; Offset: kbdEnd), { Keypad keys kbdEnd-kbdPgDn }
  1577. (Min: $52; Max: $53; Offset: kbdInsert));
  1578. function TranslateKeyEvent(KeyEvent: TKeyEvent): TKeyEvent;
  1579. var
  1580. I: Integer;
  1581. ScanCode: Byte;
  1582. begin
  1583. if KeyEvent and $03000000 = $03000000 then
  1584. begin
  1585. if KeyEvent and $000000FF <> 0 then
  1586. begin
  1587. TranslateKeyEvent := KeyEvent and $00FFFFFF;
  1588. exit;
  1589. end
  1590. else
  1591. begin
  1592. { This is a function key }
  1593. ScanCode := (KeyEvent and $0000FF00) shr 8;
  1594. for I := 1 to TranslationTableEntries do
  1595. begin
  1596. if (TranslationTable[I].Min <= ScanCode) and (ScanCode <= TranslationTable[I].Max) then
  1597. begin
  1598. TranslateKeyEvent := $02000000 + (KeyEvent and $00FF0000) +
  1599. (ScanCode - TranslationTable[I].Min) + TranslationTable[I].Offset;
  1600. exit;
  1601. end;
  1602. end;
  1603. end;
  1604. end;
  1605. TranslateKeyEvent := KeyEvent;
  1606. end;
  1607. function TranslateKeyEventUniCode(KeyEvent: TKeyEvent): TKeyEvent;
  1608. begin
  1609. TranslateKeyEventUniCode := KeyEvent;
  1610. ErrorCode:=errKbdNotImplemented;
  1611. end;
  1612. procedure RestoreStartMode;
  1613. begin
  1614. TCSetAttr(1,TCSANOW,StartTio);
  1615. end;
  1616. begin
  1617. TCGetAttr(1,StartTio);
  1618. end.
  1619. {
  1620. $Log$
  1621. Revision 1.4 2001-06-27 21:37:38 peter
  1622. * v10 merges
  1623. Revision 1.3 2001/04/10 23:35:02 peter
  1624. * fixed argument name
  1625. * merged fixes
  1626. Revision 1.2.2.5 2001/03/27 12:38:10 pierre
  1627. + RestoreStartMode function
  1628. Revision 1.2.2.4 2001/03/27 11:41:03 pierre
  1629. * fix the special handler case to avoid waiting for one more char
  1630. Revision 1.2.2.3 2001/03/24 22:38:46 pierre
  1631. * fix bug with AltGr keys
  1632. Revision 1.2.2.2 2001/01/30 22:23:44 peter
  1633. * unix back to linux
  1634. Revision 1.2.2.1 2001/01/30 21:52:02 peter
  1635. * moved api utils to rtl
  1636. Revision 1.2 2001/01/21 20:21:40 marco
  1637. * Rename fest II. Rtl OK
  1638. Revision 1.1 2001/01/13 11:03:58 peter
  1639. * API 2 RTL commit
  1640. }