keyboard.pp 44 KB

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