keyboard.pp 63 KB

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