keyboard.pp 121 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252
  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. {$IFNDEF FPC_DOTTEDUNITS}
  13. unit keyboard;
  14. {$ENDIF FPC_DOTTEDUNITS}
  15. {$inline on}
  16. {*****************************************************************************}
  17. interface
  18. {*****************************************************************************}
  19. {$i keybrdh.inc}
  20. const
  21. AltPrefix : byte = 0;
  22. ShiftPrefix : byte = 0;
  23. CtrlPrefix : byte = 0;
  24. // Constants for win32-input-mode
  25. const
  26. RIGHT_ALT_PRESSED = $0001;
  27. LEFT_ALT_PRESSED = $0002;
  28. RIGHT_CTRL_PRESSED = $0004;
  29. LEFT_CTRL_PRESSED = $0008;
  30. SHIFT_PRESSED = $0010;
  31. NUMLOCK_ON = $0020;
  32. SCROLLLOCK_ON = $0040;
  33. CAPSLOCK_ON = $0080;
  34. ENHANCED_KEY = $0100;
  35. kbBack = $0E08;
  36. kbTab = $0F09;
  37. kbEnter = $1C0D;
  38. kbSpaceBar = $3920;
  39. type
  40. Tprocedure = procedure;
  41. PTreeElement = ^TTreeElement;
  42. TTreeElement = record
  43. Next,Parent,Child : PTreeElement;
  44. CanBeTerminal : boolean;
  45. AnsiChar : byte;
  46. ScanValue : byte;
  47. CharValue : byte;
  48. ShiftValue : TEnhancedShiftState;
  49. SpecialHandler : Tprocedure;
  50. end;
  51. function RawReadKey:AnsiChar;
  52. function RawReadString : ShortString;
  53. function KeyPressed : Boolean;
  54. procedure AddSequence(const St : ShortString; AChar,AScan :byte);inline;
  55. function FindSequence(const St : ShortString;var AChar, Ascan : byte) : boolean;
  56. procedure RestoreStartMode;
  57. function AddSpecialSequence(const St : Shortstring;Proc : Tprocedure) : PTreeElement; platform;
  58. {*****************************************************************************}
  59. implementation
  60. {*****************************************************************************}
  61. {$IFDEF FPC_DOTTEDUNITS}
  62. uses
  63. System.Console.Mouse, System.Strings,System.Console.Unixkvmbase,
  64. UnixApi.TermIO,UnixApi.Base
  65. {$ifdef Linux},LinuxApi.Vcs{$endif};
  66. {$ELSE FPC_DOTTEDUNITS}
  67. uses
  68. Mouse, Strings,unixkvmbase,
  69. termio,baseUnix
  70. {$ifdef linux},linuxvcs{$endif};
  71. {$ENDIF FPC_DOTTEDUNITS}
  72. {$i keyboard.inc}
  73. var OldIO,StartTio : TermIos;
  74. Utf8KeyboardInputEnabled: Boolean;
  75. {$ifdef linux}
  76. is_console:boolean;
  77. vt_switched_away:boolean;
  78. {$endif}
  79. {$ifdef logging}
  80. f : text;
  81. {$endif logging}
  82. const
  83. KeyBufferSize = 20;
  84. var
  85. KeyBuffer : Array[0..KeyBufferSize-1] of TEnhancedKeyEvent;
  86. KeyPut,
  87. KeySend : longint;
  88. PendingEnhancedKeyEvent: TEnhancedKeyEvent;
  89. { Buffered Input routines }
  90. const
  91. InSize=256;
  92. var
  93. InBuf : array [0..InSize-1] of AnsiChar;
  94. { InCnt,}
  95. InHead,
  96. InTail : longint;
  97. {$i keyscan.inc}
  98. var kitty_keys_yes : boolean; {one of two have to be true}
  99. kitty_keys_no : boolean;
  100. isKittyKeys : boolean;
  101. const
  102. kbAltCenter = kbCtrlCenter; {there is no true DOS scancode for Alt+Center (Numpad "5") reusing Ctrl+Center}
  103. double_esc_hack_enabled : boolean = false;
  104. {$ifdef Unused}
  105. type
  106. TKeyState = Record
  107. Normal, Shift, Ctrl, Alt : word;
  108. end;
  109. const
  110. KeyStates : Array[0..255] of TKeyState
  111. (
  112. );
  113. {$endif Unused}
  114. procedure SetRawMode(b:boolean);
  115. var Tio:Termios;
  116. begin
  117. TCGetAttr(0,Tio);
  118. if b then
  119. begin
  120. {Standard output now needs #13#10.}
  121. settextlineending(output,#13#10);
  122. OldIO:=Tio;
  123. CFMakeRaw(Tio);
  124. end
  125. else
  126. begin
  127. Tio := OldIO;
  128. {Standard output normally needs just a linefeed.}
  129. settextlineending(output,#10);
  130. end;
  131. TCsetattr(0,TCSANOW,Tio);
  132. end;
  133. {$ifdef linux}
  134. {The Linux console can do nice things: we can get the state of the shift keys,
  135. and reprogram the keys. That's nice since it allows excellent circumvention
  136. of VT100 limitations, we can make the keyboard work 100%...
  137. A 100% working keyboard seems to be a pretty basic requirement, but we're
  138. one of the few guys providing such an outrageous luxury (DM).}
  139. type
  140. chgentry=packed record
  141. tab,
  142. idx,
  143. oldtab,
  144. oldidx : byte;
  145. oldval,
  146. newval : word;
  147. end;
  148. kbentry=packed record
  149. kb_table,
  150. kb_index : byte;
  151. kb_value : word;
  152. end;
  153. kbsentry=packed record
  154. kb_func:byte;
  155. kb_string:array[0..511] of AnsiChar;
  156. end;
  157. vt_mode=packed record
  158. mode, {vt mode}
  159. waitv:byte; {if set, hang on writes if not active}
  160. relsig, {signal to raise on release req}
  161. acqsig, {signal to raise on acquisition}
  162. frsig:word; {unused (set to 0)}
  163. end;
  164. const
  165. kbdchange:array[0..35] of chgentry=(
  166. {This prevents the alt+function keys from switching consoles.
  167. We code the F1..F12 sequences into ALT+F1..ALT+F12, we check
  168. the shiftstates separetely anyway.}
  169. (tab:8; idx:$3b; oldtab:0; oldidx:$3b; oldval:0; newval:0),
  170. (tab:8; idx:$3c; oldtab:0; oldidx:$3c; oldval:0; newval:0),
  171. (tab:8; idx:$3d; oldtab:0; oldidx:$3d; oldval:0; newval:0),
  172. (tab:8; idx:$3e; oldtab:0; oldidx:$3e; oldval:0; newval:0),
  173. (tab:8; idx:$3f; oldtab:0; oldidx:$3f; oldval:0; newval:0),
  174. (tab:8; idx:$40; oldtab:0; oldidx:$40; oldval:0; newval:0),
  175. (tab:8; idx:$41; oldtab:0; oldidx:$41; oldval:0; newval:0),
  176. (tab:8; idx:$42; oldtab:0; oldidx:$42; oldval:0; newval:0),
  177. (tab:8; idx:$43; oldtab:0; oldidx:$43; oldval:0; newval:0),
  178. (tab:8; idx:$44; oldtab:0; oldidx:$44; oldval:0; newval:0),
  179. (tab:8; idx:$57; oldtab:0; oldidx:$57; oldval:0; newval:0),
  180. (tab:8; idx:$58; oldtab:0; oldidx:$58; oldval:0; newval:0),
  181. {This prevents the shift+function keys outputting strings, so
  182. the kernel will send the codes for the non-shifted function
  183. keys. This is desired because normally shift+f1/f2 will output the
  184. same string as f11/12. We will get the shift state separately.}
  185. (tab:1; idx:$3b; oldtab:0; oldidx:$3b; oldval:0; newval:0),
  186. (tab:1; idx:$3c; oldtab:0; oldidx:$3c; oldval:0; newval:0),
  187. (tab:1; idx:$3d; oldtab:0; oldidx:$3d; oldval:0; newval:0),
  188. (tab:1; idx:$3e; oldtab:0; oldidx:$3e; oldval:0; newval:0),
  189. (tab:1; idx:$3f; oldtab:0; oldidx:$3f; oldval:0; newval:0),
  190. (tab:1; idx:$40; oldtab:0; oldidx:$40; oldval:0; newval:0),
  191. (tab:1; idx:$41; oldtab:0; oldidx:$41; oldval:0; newval:0),
  192. (tab:1; idx:$42; oldtab:0; oldidx:$42; oldval:0; newval:0),
  193. (tab:1; idx:$43; oldtab:0; oldidx:$43; oldval:0; newval:0),
  194. (tab:1; idx:$44; oldtab:0; oldidx:$44; oldval:0; newval:0),
  195. (tab:1; idx:$57; oldtab:0; oldidx:$57; oldval:0; newval:0),
  196. (tab:1; idx:$58; oldtab:0; oldidx:$58; oldval:0; newval:0),
  197. {This maps ctrl+function keys outputting strings to the regular
  198. F1..F12 keys also, because they no longer produce an ASCII
  199. output at all in most modern linux keymaps. We obtain the
  200. shift state separately.}
  201. (tab:4; idx:$3b; oldtab:0; oldidx:$3b; oldval:0; newval:0),
  202. (tab:4; idx:$3c; oldtab:0; oldidx:$3c; oldval:0; newval:0),
  203. (tab:4; idx:$3d; oldtab:0; oldidx:$3d; oldval:0; newval:0),
  204. (tab:4; idx:$3e; oldtab:0; oldidx:$3e; oldval:0; newval:0),
  205. (tab:4; idx:$3f; oldtab:0; oldidx:$3f; oldval:0; newval:0),
  206. (tab:4; idx:$40; oldtab:0; oldidx:$40; oldval:0; newval:0),
  207. (tab:4; idx:$41; oldtab:0; oldidx:$41; oldval:0; newval:0),
  208. (tab:4; idx:$42; oldtab:0; oldidx:$42; oldval:0; newval:0),
  209. (tab:4; idx:$43; oldtab:0; oldidx:$43; oldval:0; newval:0),
  210. (tab:4; idx:$44; oldtab:0; oldidx:$44; oldval:0; newval:0),
  211. (tab:4; idx:$57; oldtab:0; oldidx:$57; oldval:0; newval:0),
  212. (tab:4; idx:$58; oldtab:0; oldidx:$58; oldval:0; newval:0)
  213. );
  214. KDGKBENT=$4B46;
  215. KDSKBENT=$4B47;
  216. KDGKBSENT=$4B48;
  217. KDSKBSENT=$4B49;
  218. KDGKBMETA=$4B62;
  219. KDSKBMETA=$4B63;
  220. K_ESCPREFIX=$4;
  221. K_METABIT=$3;
  222. VT_GETMODE=$5601;
  223. VT_SETMODE=$5602;
  224. VT_RELDISP=$5605;
  225. VT_PROCESS=1;
  226. const
  227. oldmeta : longint = 0;
  228. meta : longint = 0;
  229. var oldesc0,oldesc1,oldesc2,oldesc4,oldesc8:word;
  230. procedure prepare_patching;
  231. var entry : kbentry;
  232. i:longint;
  233. begin
  234. for i:=low(kbdchange) to high(kbdchange) do
  235. with kbdchange[i] do
  236. begin
  237. entry.kb_table:=tab;
  238. entry.kb_index:=idx;
  239. fpIoctl(stdinputhandle,KDGKBENT,@entry);
  240. oldval:=entry.kb_value;
  241. entry.kb_table:=oldtab;
  242. entry.kb_index:=oldidx;
  243. fpioctl(stdinputhandle,KDGKBENT,@entry);
  244. newval:=entry.kb_value;
  245. end;
  246. {Save old escape code.}
  247. entry.kb_index:=1;
  248. entry.kb_table:=0;
  249. fpioctl(stdinputhandle,KDGKBENT,@entry);
  250. oldesc0:=entry.kb_value;
  251. entry.kb_table:=1;
  252. fpioctl(stdinputhandle,KDGKBENT,@entry);
  253. oldesc1:=entry.kb_value;
  254. entry.kb_table:=2;
  255. fpioctl(stdinputhandle,KDGKBENT,@entry);
  256. oldesc2:=entry.kb_value;
  257. entry.kb_table:=4;
  258. fpioctl(stdinputhandle,KDGKBENT,@entry);
  259. oldesc4:=entry.kb_value;
  260. entry.kb_table:=8;
  261. fpioctl(stdinputhandle,KDGKBENT,@entry);
  262. oldesc8:=entry.kb_value;
  263. end;
  264. procedure PatchKeyboard;
  265. var
  266. entry : kbentry;
  267. sentry : kbsentry;
  268. i:longint;
  269. begin
  270. fpIoctl(stdinputhandle,KDGKBMETA,@oldmeta);
  271. meta:=K_ESCPREFIX;
  272. fpIoctl(stdinputhandle,KDSKBMETA,@meta);
  273. for i:=low(kbdchange) to high(kbdchange) do
  274. with kbdchange[i] do
  275. begin
  276. entry.kb_table:=tab;
  277. entry.kb_index:=idx;
  278. entry.kb_value:=newval;
  279. fpioctl(stdinputhandle,KDSKBENT,@entry);
  280. end;
  281. {Map kernel escape key code to symbol F32.}
  282. entry.kb_index:=1;
  283. entry.kb_value:=$011f;
  284. entry.kb_table:=0;
  285. fpioctl(stdinputhandle,KDSKBENT,@entry);
  286. entry.kb_table:=1;
  287. fpioctl(stdinputhandle,KDSKBENT,@entry);
  288. entry.kb_table:=2;
  289. fpioctl(stdinputhandle,KDSKBENT,@entry);
  290. entry.kb_table:=4;
  291. fpioctl(stdinputhandle,KDSKBENT,@entry);
  292. entry.kb_table:=8;
  293. fpioctl(stdinputhandle,KDSKBENT,@entry);
  294. {F32 (the escape key) will generate ^[[0~ .}
  295. sentry.kb_func:=31;
  296. sentry.kb_string:=#27'[0~';
  297. fpioctl(stdinputhandle,KDSKBSENT,@sentry);
  298. end;
  299. procedure UnpatchKeyboard;
  300. var
  301. entry : kbentry;
  302. i : longint;
  303. begin
  304. if oldmeta in [K_ESCPREFIX,K_METABIT] then
  305. fpioctl(stdinputhandle,KDSKBMETA,@oldmeta);
  306. for i:=low(kbdchange) to high(kbdchange) do
  307. with kbdchange[i] do
  308. begin
  309. entry.kb_table:=tab;
  310. entry.kb_index:=idx;
  311. entry.kb_value:=oldval;
  312. fpioctl(stdinputhandle,KDSKBENT,@entry);
  313. end;
  314. entry.kb_index:=1;
  315. entry.kb_table:=0;
  316. entry.kb_value:=oldesc0;
  317. fpioctl(stdinputhandle,KDSKBENT,@entry);
  318. entry.kb_table:=1;
  319. entry.kb_value:=oldesc1;
  320. fpioctl(stdinputhandle,KDSKBENT,@entry);
  321. entry.kb_table:=2;
  322. entry.kb_value:=oldesc2;
  323. fpioctl(stdinputhandle,KDSKBENT,@entry);
  324. entry.kb_table:=4;
  325. entry.kb_value:=oldesc4;
  326. fpioctl(stdinputhandle,KDSKBENT,@entry);
  327. entry.kb_table:=8;
  328. entry.kb_value:=oldesc8;
  329. fpioctl(stdinputhandle,KDSKBENT,@entry);
  330. end;
  331. {A problem of patching the keyboard is that it no longer works as expected
  332. when working on another console. So we unpatch it when the user switches
  333. away.}
  334. procedure vt_handler(sig:longint);cdecl;
  335. begin
  336. if vt_switched_away then
  337. begin
  338. {Confirm the switch.}
  339. fpioctl(stdoutputhandle,VT_RELDISP,pointer(2));
  340. {Switching to program, patch keyboard.}
  341. patchkeyboard;
  342. end
  343. else
  344. begin
  345. {Switching away from program, unpatch the keyboard.}
  346. unpatchkeyboard;
  347. fpioctl(stdoutputhandle,VT_RELDISP,pointer(1));
  348. end;
  349. vt_switched_away:=not vt_switched_away;
  350. {Clear buffer.}
  351. intail:=inhead;
  352. end;
  353. procedure install_vt_handler;
  354. var mode:vt_mode;
  355. begin
  356. { ioctl(vt_fd,KDSETMODE,KD_GRAPHICS);}
  357. fpioctl(stdoutputhandle,VT_GETMODE,@mode);
  358. mode.mode:=VT_PROCESS;
  359. mode.relsig:=SIGUSR1;
  360. mode.acqsig:=SIGUSR1;
  361. vt_switched_away:=false;
  362. fpsignal(SIGUSR1,@vt_handler);
  363. fpioctl(stdoutputhandle,VT_SETMODE,@mode);
  364. end;
  365. {$endif}
  366. function ttyRecvChar:AnsiChar;
  367. var Readed,i : longint;
  368. begin
  369. {Buffer empty? Yes, input from stdin}
  370. if (InHead=InTail) then
  371. begin
  372. {Calc Amount of Chars to Read}
  373. i:=InSize-InHead;
  374. if InTail>InHead then
  375. i:=InTail-InHead;
  376. {Read}
  377. repeat
  378. Readed:=fpRead(StdInputHandle,InBuf[InHead],i);
  379. until readed<>-1;
  380. {Increase Counters}
  381. inc(InHead,Readed);
  382. {Wrap if End has Reached}
  383. if InHead>=InSize then
  384. InHead:=0;
  385. end;
  386. {Check Buffer}
  387. ttyRecvChar:=InBuf[InTail];
  388. inc(InTail);
  389. if InTail>=InSize then
  390. InTail:=0;
  391. end;
  392. { returns an already read character back into InBuf }
  393. procedure PutBackIntoInBuf(ch: AnsiChar);
  394. begin
  395. If InTail=0 then
  396. InTail:=InSize-1
  397. else
  398. Dec(InTail);
  399. InBuf[InTail]:=ch;
  400. end;
  401. procedure PushKey(const Ch:TEnhancedKeyEvent);
  402. var
  403. Tmp : Longint;
  404. begin
  405. Tmp:=KeyPut;
  406. Inc(KeyPut);
  407. If KeyPut>=KeyBufferSize Then
  408. KeyPut:=0;
  409. If KeyPut<>KeySend Then
  410. KeyBuffer[Tmp]:=Ch
  411. Else
  412. KeyPut:=Tmp;
  413. End;
  414. function PopKey:TEnhancedKeyEvent;
  415. begin
  416. If KeyPut<>KeySend Then
  417. begin
  418. PopKey:=KeyBuffer[KeySend];
  419. Inc(KeySend);
  420. If KeySend>=KeyBufferSize Then
  421. KeySend:=0;
  422. End
  423. Else
  424. PopKey:=NilEnhancedKeyEvent;
  425. End;
  426. { This one doesn't care about keypresses already processed by readkey }
  427. { and waiting in the KeyBuffer, only about waiting keypresses at the }
  428. { TTYLevel (including ones that are waiting in the TTYRecvChar buffer) }
  429. function sysKeyPressed: boolean;
  430. var
  431. fdsin : tfdSet;
  432. begin
  433. if (inhead<>intail) then
  434. sysKeyPressed:=true
  435. else
  436. begin
  437. fpFD_ZERO(fdsin);
  438. fpFD_SET(StdInputHandle,fdsin);
  439. sysKeypressed:=(fpSelect(StdInputHandle+1,@fdsin,nil,nil,0)>0);
  440. end;
  441. end;
  442. function KeyPressed:Boolean;
  443. begin
  444. Keypressed := (KeySend<>KeyPut) or sysKeyPressed;
  445. End;
  446. const
  447. LastMouseEvent : TMouseEvent =
  448. (
  449. Buttons : 0;
  450. X : 0;
  451. Y : 0;
  452. Action : 0;
  453. );
  454. procedure GenFakeReleaseEvent(var MouseEvent : TMouseEvent);
  455. begin
  456. MouseEvent.action := MouseActionUp;
  457. MouseEvent.buttons := 0;
  458. { fake event is to decive LastMouseEvent
  459. PutMouseEvent(MouseEvent); do not make real event }
  460. end;
  461. procedure GenMouseEvent;
  462. { format: CSI M char1 charX charY
  463. char1 - button nr and state
  464. charX - mouse X (if multi byte format then 1 or 2 chars)
  465. charY - mouse Y (if multi byte format then 1 or 2 chars)
  466. }
  467. var MouseEvent: TMouseEvent;
  468. ch : AnsiChar;
  469. fdsin : tfdSet;
  470. buttonval:byte;
  471. x,y,x1 : word;
  472. notMultiByte : boolean;
  473. NeedMouseRelease:boolean;
  474. addButtMove : byte;
  475. begin
  476. fpFD_ZERO(fdsin);
  477. fpFD_SET(StdInputHandle,fdsin);
  478. { Fillchar(MouseEvent,SizeOf(TMouseEvent),#0);}
  479. MouseEvent.buttons:=0;
  480. if inhead=intail then
  481. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  482. ch:=ttyRecvChar;
  483. buttonval:=byte(ch);
  484. if ch in [#$c2,#$c3] then
  485. begin
  486. {xterm multibyte}
  487. addButtMove:=(byte(ch) and 1) shl 6;
  488. if inhead=intail then
  489. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  490. ch:=ttyRecvChar;
  491. buttonval:=byte(ch) or addButtMove;
  492. end;
  493. NeedMouseRelease:=false;
  494. { Other bits are used for Shift, Meta and Ctrl modifiers PM }
  495. buttonval:=buttonval and %11100111;
  496. {bits 0..1: button status
  497. bit 5 : mouse movement while button down.
  498. bit 6 : interpret button 1 as button 4
  499. interpret button 2 as button 5}
  500. case buttonval of
  501. %00100000,%01000000 : {left button pressed,moved}
  502. MouseEvent.buttons:=MouseLeftButton;
  503. %00100001,%01000001 : {middle button pressed,moved }
  504. MouseEvent.buttons:=MouseMiddleButton;
  505. %00100010,%01000010 : { right button pressed,moved }
  506. MouseEvent.buttons:=MouseRightButton;
  507. %00100011,%01000011 : { no button pressed,moved }
  508. MouseEvent.buttons:=0;
  509. %01100000: { button 4 pressed }
  510. MouseEvent.buttons:=MouseButton4;
  511. %10000000: { rxvt - button 4 move }
  512. MouseEvent.buttons:=0; {rxvt does not release button keeps moving it, fake as no button press move}
  513. %01100001: { button 5 pressed }
  514. MouseEvent.buttons:=MouseButton5;
  515. %10000001: { rxvt - button 5 move }
  516. MouseEvent.buttons:=0;
  517. %10100000,%11000000 : { xterm - button 6 pressed,moved }
  518. MouseEvent.buttons:=MouseXButton1;
  519. %01100100 : { rxvt - button 6 pressed, have to add fake release }
  520. begin MouseEvent.buttons:=MouseXButton1; NeedMouseRelease:=true; end;
  521. %10000100 : { rxvt - button 6 move }
  522. MouseEvent.buttons:=0;
  523. %10100001,%11000001 : { xterm - button 7 pressed,moved }
  524. MouseEvent.buttons:=MouseXButton2;
  525. %01100101 : { rxvt - button 7 pressed, have to add fake release }
  526. begin MouseEvent.buttons:=MouseXButton2; NeedMouseRelease:=true; end;
  527. %10000101: { rxvt - button 7 move }
  528. MouseEvent.buttons:=0;
  529. end;
  530. notMultiByte:=false;
  531. {mouse X}
  532. if inhead=intail then
  533. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  534. ch:=ttyRecvChar;
  535. x:=byte(ch);
  536. x1:=x;
  537. {mouse Y}
  538. if inhead=intail then
  539. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  540. ch:=ttyRecvChar;
  541. y:=byte(ch);
  542. {decide if this is a single byte or a multi byte mouse report format}
  543. if (x in [127..193]) or (x=0) then
  544. notMultiByte:=true
  545. else
  546. if x >= 194 then
  547. begin
  548. if ch in [#$80..#$bf] then {probably multibyte}
  549. x1:=128+(byte(ch)-128)+(x-194)*($bf-$80+1)
  550. else notMultiByte:=true;
  551. end;
  552. if y < 128 then
  553. notMultiByte:=true;
  554. {probability is high for multi byte format and we have extra character in line to read}
  555. if not notMultiByte and sysKeyPressed then
  556. begin
  557. if inhead=intail then
  558. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  559. ch:=ttyRecvChar;
  560. if ch > ' ' then
  561. begin
  562. {we are sure, it is a multi byte mouse report format}
  563. x:=x1; {new mouse X}
  564. y:=byte(ch); {new mouse Y}
  565. if (y <> 0 ) and sysKeyPressed and (y >= 194) then
  566. begin
  567. if inhead=intail then
  568. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  569. ch:=ttyRecvChar;
  570. y:=128+(byte(ch)-128)+(y-194)*($bf-$80+1); {multibyte mouse Y}
  571. end;
  572. end else PutBackIntoInBuf(ch);
  573. end;
  574. if (x=0) or (y=0) then exit; {single byte format hit its limts, no mouse event}
  575. MouseEvent.x:=x-32-1;
  576. MouseEvent.y:=y-32-1;
  577. mouseevent.action:=MouseActionMove;
  578. if (lastmouseevent.buttons=0) and (mouseevent.buttons<>0) then
  579. MouseEvent.action:=MouseActionDown;
  580. if (lastmouseevent.buttons<>0) and (mouseevent.buttons=0) then
  581. MouseEvent.action:=MouseActionUp;
  582. (*
  583. else
  584. begin
  585. if (LastMouseEvent.Buttons<>0) and
  586. ((LastMouseEvent.X<>MouseEvent.X) or (LastMouseEvent.Y<>MouseEvent.Y)) then
  587. begin
  588. MouseEvent.Action:=MouseActionMove;
  589. MouseEvent.Buttons:=LastMouseEvent.Buttons;
  590. {$ifdef DebugMouse}
  591. Writeln(system.stderr,' Mouse Move (',MouseEvent.X,',',MouseEvent.Y,')');
  592. {$endif DebugMouse}
  593. PutMouseEvent(MouseEvent);
  594. MouseEvent.Buttons:=0;
  595. end;
  596. MouseEvent.Action:=MouseActionUp;
  597. end;
  598. *)
  599. PutMouseEvent(MouseEvent);
  600. if (MouseEvent.buttons and (MouseButton4 or MouseButton5)) <> 0 then
  601. GenFakeReleaseEvent(MouseEvent);
  602. if NeedMouseRelease then
  603. begin
  604. GenFakeReleaseEvent(MouseEvent);
  605. PutMouseEvent(MouseEvent); {rxvt bug, need real event here as workaround }
  606. end;
  607. {$ifdef DebugMouse}
  608. if MouseEvent.Action=MouseActionDown then
  609. Write(system.stderr,'Button down : ')
  610. else
  611. Write(system.stderr,'Button up : ');
  612. Writeln(system.stderr,'buttons = ',MouseEvent.Buttons,' (',MouseEvent.X,',',MouseEvent.Y,')');
  613. {$endif DebugMouse}
  614. LastMouseEvent:=MouseEvent;
  615. end;
  616. { The Extended/SGR 1006 mouse protocol, supported by xterm 277 and newer.
  617. Message format: Esc [<0;123;456M - mouse button press
  618. or: Esc [<0;123;456m - mouse button release
  619. Advantages:
  620. - can report X and Y coordinates larger than 223
  621. - mouse release event informs us of *which* mouse button was released, so
  622. we can track buttons more accurately
  623. - messages use a different prefix (Esc [< instead of Esc [M) than the
  624. regular mouse event messages, so there's no need to detect if the
  625. terminal supports it - we can always try to enable it and then be
  626. prepared to handle both types of messages }
  627. procedure GenMouseEvent_ExtendedSGR1006;
  628. var MouseEvent: TMouseEvent;
  629. ch : AnsiChar;
  630. fdsin : tfdSet;
  631. buttonval: LongInt;
  632. tempstr: shortstring;
  633. code: LongInt;
  634. X, Y: LongInt;
  635. ButtonMask: Word;
  636. begin
  637. fpFD_ZERO(fdsin);
  638. fpFD_SET(StdInputHandle,fdsin);
  639. { read buttonval }
  640. tempstr:='';
  641. repeat
  642. if inhead=intail then
  643. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  644. ch:=ttyRecvChar;
  645. if (ch>='0') and (ch<='9') then
  646. tempstr:=tempstr+ch
  647. else if ch<>';' then
  648. exit;
  649. until ch=';';
  650. Val(tempstr,buttonval,code);
  651. { read X }
  652. tempstr:='';
  653. repeat
  654. if inhead=intail then
  655. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  656. ch:=ttyRecvChar;
  657. if (ch>='0') and (ch<='9') then
  658. tempstr:=tempstr+ch
  659. else if ch<>';' then
  660. exit;
  661. until ch=';';
  662. Val(tempstr,X,code);
  663. { read Y }
  664. tempstr:='';
  665. repeat
  666. if inhead=intail then
  667. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  668. ch:=ttyRecvChar;
  669. if (ch>='0') and (ch<='9') then
  670. tempstr:=tempstr+ch
  671. else if (ch<>'M') and (ch<>'m') then
  672. exit;
  673. until (ch='M') or (ch='m');
  674. Val(tempstr,Y,code);
  675. {$ifdef DebugMouse}
  676. Writeln(System.StdErr, 'SGR1006:', buttonval:3, X:5, Y:5, ' ', ch);
  677. {$endif DebugMouse}
  678. { let's range check X and Y just in case }
  679. if (X<(Low(MouseEvent.X)+1)) or (X>(High(MouseEvent.X)+1)) then
  680. exit;
  681. if (Y<(Low(MouseEvent.Y)+1)) or (Y>(High(MouseEvent.Y)+1)) then
  682. exit;
  683. case buttonval and (67 or 128) of
  684. 0 : {left button press}
  685. ButtonMask:=MouseLeftButton;
  686. 1 : {middle button pressed }
  687. ButtonMask:=MouseMiddleButton;
  688. 2 : { right button pressed }
  689. ButtonMask:=MouseRightButton;
  690. 3 : { no button pressed }
  691. ButtonMask:=0;
  692. 64: { button 4 pressed }
  693. ButtonMask:=MouseButton4;
  694. 65: { button 5 pressed }
  695. ButtonMask:=MouseButton5;
  696. 128: { button browse back }
  697. ButtonMask:=MouseXButton1;
  698. 129: { button browse forward }
  699. ButtonMask:=MouseXButton2;
  700. end;
  701. MouseEvent.X:=X-1;
  702. MouseEvent.Y:=Y-1;
  703. if (buttonval and 32)<>0 then
  704. begin
  705. MouseEvent.Action:=MouseActionMove;
  706. MouseEvent.Buttons:=LastMouseEvent.Buttons;
  707. end
  708. else
  709. begin
  710. if ch='M' then
  711. begin
  712. MouseEvent.Action:=MouseActionDown;
  713. MouseEvent.Buttons:=LastMouseEvent.Buttons or ButtonMask;
  714. end
  715. else
  716. begin
  717. MouseEvent.Action:=MouseActionUp;
  718. MouseEvent.Buttons:=LastMouseEvent.Buttons and not ButtonMask;
  719. end;
  720. end;
  721. PutMouseEvent(MouseEvent);
  722. if (ButtonMask and (MouseButton4 or MouseButton5)) <> 0 then
  723. begin
  724. MouseEvent.Action:=MouseActionUp; {to trick LastMouseEvent that we have MouseActionUp event }
  725. MouseEvent.Buttons:=LastMouseEvent.Buttons and not (MouseButton4 or MouseButton5);
  726. {PutMouseEvent(MouseEvent); do not put actual event }
  727. end;
  728. LastMouseEvent:=MouseEvent;
  729. end;
  730. var roottree:array[AnsiChar] of PTreeElement;
  731. procedure FreeElement (PT:PTreeElement);
  732. var next : PTreeElement;
  733. begin
  734. while PT <> nil do
  735. begin
  736. FreeElement(PT^.Child);
  737. next := PT^.Next;
  738. dispose(PT);
  739. PT := next;
  740. end;
  741. end;
  742. procedure FreeTree;
  743. var i:AnsiChar;
  744. begin
  745. for i:=low(roottree) to high(roottree) do
  746. begin
  747. FreeElement(RootTree[i]);
  748. roottree[i]:=nil;
  749. end;
  750. end;
  751. function NewPTree(ch : byte;Pa : PTreeElement) : PTreeElement;
  752. begin
  753. newPtree:=allocmem(sizeof(Ttreeelement));
  754. newPtree^.AnsiChar:=ch;
  755. newPtree^.Parent:=Pa;
  756. if Assigned(Pa) and (Pa^.Child=nil) then
  757. Pa^.Child:=newPtree;
  758. end;
  759. function DoAddSequence(const St : shortstring; AChar,AScan :byte; const AShift: TEnhancedShiftState) : PTreeElement;
  760. var
  761. CurPTree,NPT : PTreeElement;
  762. c : byte;
  763. i : longint;
  764. begin
  765. if St='' then
  766. begin
  767. DoAddSequence:=nil;
  768. exit;
  769. end;
  770. CurPTree:=RootTree[st[1]];
  771. if CurPTree=nil then
  772. begin
  773. CurPTree:=NewPTree(ord(st[1]),nil);
  774. RootTree[st[1]]:=CurPTree;
  775. end;
  776. for i:=2 to Length(St) do
  777. begin
  778. NPT:=CurPTree^.Child;
  779. c:=ord(St[i]);
  780. if NPT=nil then
  781. NPT:=NewPTree(c,CurPTree);
  782. CurPTree:=nil;
  783. while assigned(NPT) and (NPT^.AnsiChar<c) do
  784. begin
  785. CurPTree:=NPT;
  786. NPT:=NPT^.Next;
  787. end;
  788. if assigned(NPT) and (NPT^.AnsiChar=c) then
  789. CurPTree:=NPT
  790. else
  791. begin
  792. if CurPTree=nil then
  793. begin
  794. NPT^.Parent^.child:=NewPTree(c,NPT^.Parent);
  795. CurPTree:=NPT^.Parent^.Child;
  796. CurPTree^.Next:=NPT;
  797. end
  798. else
  799. begin
  800. CurPTree^.Next:=NewPTree(c,CurPTree^.Parent);
  801. CurPTree:=CurPTree^.Next;
  802. CurPTree^.Next:=NPT;
  803. end;
  804. end;
  805. end;
  806. if CurPTree^.CanBeTerminal then
  807. begin
  808. { here we have a conflict !! }
  809. { maybe we should claim }
  810. with CurPTree^ do
  811. begin
  812. {$ifdef DEBUG1}
  813. if (ScanValue<>AScan) or (CharValue<>AChar) then
  814. Writeln(system.stderr,'key "',st,'" changed value');
  815. if (ScanValue<>AScan) then
  816. Writeln(system.stderr,'Scan was ',ScanValue,' now ',AScan);
  817. if (CharValue<>AChar) then
  818. Writeln(system.stderr,'AnsiChar was ',chr(CharValue),' now ',chr(AChar));
  819. {$endif DEBUG1}
  820. ScanValue:=AScan;
  821. CharValue:=AChar;
  822. ShiftValue:=AShift;
  823. end;
  824. end
  825. else with CurPTree^ do
  826. begin
  827. CanBeTerminal:=True;
  828. ScanValue:=AScan;
  829. CharValue:=AChar;
  830. ShiftValue:=AShift;
  831. end;
  832. DoAddSequence:=CurPTree;
  833. end;
  834. procedure AddSequence(const St : shortstring; AChar,AScan :byte);inline;
  835. begin
  836. DoAddSequence(St,AChar,AScan,[]);
  837. end;
  838. { Returns the Child that as c as AnsiChar if it exists }
  839. function FindChild(c : byte;Root : PTreeElement) : PTreeElement;
  840. var
  841. NPT : PTreeElement;
  842. begin
  843. NPT:=Root^.Child;
  844. while assigned(NPT) and (NPT^.AnsiChar<c) do
  845. NPT:=NPT^.Next;
  846. if assigned(NPT) and (NPT^.AnsiChar=c) then
  847. FindChild:=NPT
  848. else
  849. FindChild:=nil;
  850. end;
  851. function AddSpecialSequence(const St : shortstring;Proc : Tprocedure) : PTreeElement;
  852. var
  853. NPT : PTreeElement;
  854. begin
  855. NPT:=DoAddSequence(St,0,0,[]);
  856. NPT^.SpecialHandler:=Proc;
  857. AddSpecialSequence:=NPT;
  858. end;
  859. function FindSequence(const St : shortstring;var AChar,AScan :byte) : boolean;
  860. var
  861. NPT : PTreeElement;
  862. i,p : byte;
  863. begin
  864. FindSequence:=false;
  865. AChar:=0;
  866. AScan:=0;
  867. if St='' then
  868. exit;
  869. p:=1;
  870. {This is a distusting hack for certain even more disgusting xterms: Some of
  871. them send two escapes for an alt-key. If we wouldn't do this, we would need
  872. to put a lot of entries twice in the table.}
  873. if double_esc_hack_enabled and (st[1]=#27) and (st[2]='#27') and
  874. (st[3] in ['a'..'z','A'..'Z','0'..'9','-','+','_','=']) then
  875. inc(p);
  876. NPT:=RootTree[St[p]];
  877. if npt<>nil then
  878. begin
  879. for i:=p+1 to Length(St) do
  880. begin
  881. NPT:=FindChild(ord(St[i]),NPT);
  882. if NPT=nil then
  883. exit;
  884. end;
  885. if NPT^.CanBeTerminal then
  886. begin
  887. FindSequence:=true;
  888. AScan:=NPT^.ScanValue;
  889. AChar:=NPT^.CharValue;
  890. end;
  891. end;
  892. end;
  893. type key_sequence=packed record
  894. AnsiChar:0..127;
  895. scan:byte;
  896. shift:TEnhancedShiftState;
  897. st:string[10];
  898. end;
  899. const key_sequences:array[0..425] of key_sequence=(
  900. (AnsiChar:0;scan:$39;shift:[essCtrl];st:#0), { xterm, Ctrl+Space }
  901. (AnsiChar:0;scan:kbAltA;shift:[essAlt];st:#27'A'),
  902. (AnsiChar:0;scan:kbAltA;shift:[essAlt];st:#27'a'),
  903. (AnsiChar:0;scan:kbAltB;shift:[essAlt];st:#27'B'),
  904. (AnsiChar:0;scan:kbAltB;shift:[essAlt];st:#27'b'),
  905. (AnsiChar:0;scan:kbAltC;shift:[essAlt];st:#27'C'),
  906. (AnsiChar:0;scan:kbAltC;shift:[essAlt];st:#27'c'),
  907. (AnsiChar:0;scan:kbAltD;shift:[essAlt];st:#27'D'),
  908. (AnsiChar:0;scan:kbAltD;shift:[essAlt];st:#27'd'),
  909. (AnsiChar:0;scan:kbAltE;shift:[essAlt];st:#27'E'),
  910. (AnsiChar:0;scan:kbAltE;shift:[essAlt];st:#27'e'),
  911. (AnsiChar:0;scan:kbAltF;shift:[essAlt];st:#27'F'),
  912. (AnsiChar:0;scan:kbAltF;shift:[essAlt];st:#27'f'),
  913. (AnsiChar:0;scan:kbAltG;shift:[essAlt];st:#27'G'),
  914. (AnsiChar:0;scan:kbAltG;shift:[essAlt];st:#27'g'),
  915. (AnsiChar:0;scan:kbAltH;shift:[essAlt];st:#27'H'),
  916. (AnsiChar:0;scan:kbAltH;shift:[essAlt];st:#27'h'),
  917. (AnsiChar:0;scan:kbAltI;shift:[essAlt];st:#27'I'),
  918. (AnsiChar:0;scan:kbAltI;shift:[essAlt];st:#27'i'),
  919. (AnsiChar:0;scan:kbAltJ;shift:[essAlt];st:#27'J'),
  920. (AnsiChar:0;scan:kbAltJ;shift:[essAlt];st:#27'j'),
  921. (AnsiChar:0;scan:kbAltK;shift:[essAlt];st:#27'K'),
  922. (AnsiChar:0;scan:kbAltK;shift:[essAlt];st:#27'k'),
  923. (AnsiChar:0;scan:kbAltL;shift:[essAlt];st:#27'L'),
  924. (AnsiChar:0;scan:kbAltL;shift:[essAlt];st:#27'l'),
  925. (AnsiChar:0;scan:kbAltM;shift:[essAlt];st:#27'M'),
  926. (AnsiChar:0;scan:kbAltM;shift:[essAlt];st:#27'm'),
  927. (AnsiChar:0;scan:kbAltN;shift:[essAlt];st:#27'N'),
  928. (AnsiChar:0;scan:kbAltN;shift:[essAlt];st:#27'n'),
  929. (AnsiChar:0;scan:kbAltO;shift:[essAlt];st:#27'O'),
  930. (AnsiChar:0;scan:kbAltO;shift:[essAlt];st:#27'o'),
  931. (AnsiChar:0;scan:kbAltP;shift:[essAlt];st:#27'P'),
  932. (AnsiChar:0;scan:kbAltP;shift:[essAlt];st:#27'p'),
  933. (AnsiChar:0;scan:kbAltQ;shift:[essAlt];st:#27'Q'),
  934. (AnsiChar:0;scan:kbAltQ;shift:[essAlt];st:#27'q'),
  935. (AnsiChar:0;scan:kbAltR;shift:[essAlt];st:#27'R'),
  936. (AnsiChar:0;scan:kbAltR;shift:[essAlt];st:#27'r'),
  937. (AnsiChar:0;scan:kbAltS;shift:[essAlt];st:#27'S'),
  938. (AnsiChar:0;scan:kbAltS;shift:[essAlt];st:#27's'),
  939. (AnsiChar:0;scan:kbAltT;shift:[essAlt];st:#27'T'),
  940. (AnsiChar:0;scan:kbAltT;shift:[essAlt];st:#27't'),
  941. (AnsiChar:0;scan:kbAltU;shift:[essAlt];st:#27'U'),
  942. (AnsiChar:0;scan:kbAltU;shift:[essAlt];st:#27'u'),
  943. (AnsiChar:0;scan:kbAltV;shift:[essAlt];st:#27'V'),
  944. (AnsiChar:0;scan:kbAltV;shift:[essAlt];st:#27'v'),
  945. (AnsiChar:0;scan:kbAltW;shift:[essAlt];st:#27'W'),
  946. (AnsiChar:0;scan:kbAltW;shift:[essAlt];st:#27'w'),
  947. (AnsiChar:0;scan:kbAltX;shift:[essAlt];st:#27'X'),
  948. (AnsiChar:0;scan:kbAltX;shift:[essAlt];st:#27'x'),
  949. (AnsiChar:0;scan:kbAltY;shift:[essAlt];st:#27'Y'),
  950. (AnsiChar:0;scan:kbAltY;shift:[essAlt];st:#27'y'),
  951. (AnsiChar:0;scan:kbAltZ;shift:[essAlt];st:#27'Z'),
  952. (AnsiChar:0;scan:kbAltZ;shift:[essAlt];st:#27'z'),
  953. (AnsiChar:0;scan:kbAltMinus;shift:[essAlt];st:#27'-'),
  954. (AnsiChar:0;scan:kbAltEqual;shift:[essAlt];st:#27'='),
  955. (AnsiChar:0;scan:kbAlt0;shift:[essAlt];st:#27'0'),
  956. (AnsiChar:0;scan:kbAlt1;shift:[essAlt];st:#27'1'),
  957. (AnsiChar:0;scan:kbAlt2;shift:[essAlt];st:#27'2'),
  958. (AnsiChar:0;scan:kbAlt3;shift:[essAlt];st:#27'3'),
  959. (AnsiChar:0;scan:kbAlt4;shift:[essAlt];st:#27'4'),
  960. (AnsiChar:0;scan:kbAlt5;shift:[essAlt];st:#27'5'),
  961. (AnsiChar:0;scan:kbAlt6;shift:[essAlt];st:#27'6'),
  962. (AnsiChar:0;scan:kbAlt7;shift:[essAlt];st:#27'7'),
  963. (AnsiChar:0;scan:kbAlt8;shift:[essAlt];st:#27'8'),
  964. (AnsiChar:0;scan:kbAlt9;shift:[essAlt];st:#27'9'),
  965. (AnsiChar:0;scan:kbF1;shift:[];st:#27'[[A'), {linux,konsole,xterm}
  966. (AnsiChar:0;scan:kbF2;shift:[];st:#27'[[B'), {linux,konsole,xterm}
  967. (AnsiChar:0;scan:kbF3;shift:[];st:#27'[[C'), {linux,konsole,xterm}
  968. (AnsiChar:0;scan:kbF4;shift:[];st:#27'[[D'), {linux,konsole,xterm}
  969. (AnsiChar:0;scan:kbF5;shift:[];st:#27'[[E'), {linux,konsole}
  970. (AnsiChar:0;scan:kbF1;shift:[];st:#27'[11~'), {Eterm,rxvt}
  971. (AnsiChar:0;scan:kbF2;shift:[];st:#27'[12~'), {Eterm,rxvt}
  972. (AnsiChar:0;scan:kbF3;shift:[];st:#27'[13~'), {Eterm,rxvt}
  973. (AnsiChar:0;scan:kbF4;shift:[];st:#27'[14~'), {Eterm,rxvt}
  974. (AnsiChar:0;scan:kbF5;shift:[];st:#27'[15~'), {xterm,Eterm,gnome,rxvt}
  975. (AnsiChar:0;scan:kbF6;shift:[];st:#27'[17~'), {linux,xterm,Eterm,konsole,gnome,rxvt}
  976. (AnsiChar:0;scan:kbF7;shift:[];st:#27'[18~'), {linux,xterm,Eterm,konsole,gnome,rxvt}
  977. (AnsiChar:0;scan:kbF8;shift:[];st:#27'[19~'), {linux,xterm,Eterm,konsole,gnome,rxvt}
  978. (AnsiChar:0;scan:kbF9;shift:[];st:#27'[20~'), {linux,xterm,Eterm,konsole,gnome,rxvt}
  979. (AnsiChar:0;scan:kbF10;shift:[];st:#27'[21~'), {linux,xterm,Eterm,konsole,gnome,rxvt}
  980. (AnsiChar:0;scan:kbF11;shift:[];st:#27'[23~'), {linux,xterm,Eterm,konsole,gnome,rxvt}
  981. (AnsiChar:0;scan:kbF12;shift:[];st:#27'[24~'), {linux,xterm,Eterm,konsole,gnome,rxvt}
  982. (AnsiChar:0;scan:kbF1;shift:[];st:#27'[M'), {FreeBSD}
  983. (AnsiChar:0;scan:kbF2;shift:[];st:#27'[N'), {FreeBSD}
  984. (AnsiChar:0;scan:kbF3;shift:[];st:#27'[O'), {FreeBSD}
  985. (AnsiChar:0;scan:kbF4;shift:[];st:#27'[P'), {FreeBSD}
  986. (AnsiChar:0;scan:kbF5;shift:[];st:#27'[Q'), {FreeBSD}
  987. (AnsiChar:0;scan:kbF6;shift:[];st:#27'[R'), {FreeBSD}
  988. (AnsiChar:0;scan:kbF7;shift:[];st:#27'[S'), {FreeBSD}
  989. (AnsiChar:0;scan:kbF8;shift:[];st:#27'[T'), {FreeBSD}
  990. (AnsiChar:0;scan:kbF9;shift:[];st:#27'[U'), {FreeBSD}
  991. (AnsiChar:0;scan:kbF10;shift:[];st:#27'[V'), {FreeBSD}
  992. (AnsiChar:0;scan:kbF11;shift:[];st:#27'[W'), {FreeBSD}
  993. (AnsiChar:0;scan:kbF12;shift:[];st:#27'[X'), {FreeBSD}
  994. (AnsiChar:0;scan:kbF1;shift:[];st:#27'OP'), {vt100,gnome,konsole}
  995. (AnsiChar:0;scan:kbF2;shift:[];st:#27'OQ'), {vt100,gnome,konsole}
  996. (AnsiChar:0;scan:kbF3;shift:[];st:#27'OR'), {vt100,gnome,konsole}
  997. (AnsiChar:0;scan:kbF4;shift:[];st:#27'OS'), {vt100,gnome,konsole}
  998. (AnsiChar:0;scan:kbF5;shift:[];st:#27'Ot'), {vt100}
  999. (AnsiChar:0;scan:kbF6;shift:[];st:#27'Ou'), {vt100}
  1000. (AnsiChar:0;scan:kbF7;shift:[];st:#27'Ov'), {vt100}
  1001. (AnsiChar:0;scan:kbF8;shift:[];st:#27'Ol'), {vt100}
  1002. (AnsiChar:0;scan:kbF9;shift:[];st:#27'Ow'), {vt100}
  1003. (AnsiChar:0;scan:kbF10;shift:[];st:#27'Ox'), {vt100}
  1004. (AnsiChar:0;scan:kbF11;shift:[];st:#27'Oy'), {vt100}
  1005. (AnsiChar:0;scan:kbF12;shift:[];st:#27'Oz'), {vt100}
  1006. (AnsiChar:27;scan:kbEsc;shift:[];st:#27'[0~'), {if linux keyboard patched, escape
  1007. returns this}
  1008. (AnsiChar:0;scan:kbAltF5;shift:[essAlt];st:#27#27'OT'), {pterm}
  1009. (AnsiChar:0;scan:kbF5;shift:[];st:#27'OT'), {pterm}
  1010. (AnsiChar:0;scan:kbF6;shift:[];st:#27'OU'), {pterm}
  1011. (AnsiChar:0;scan:kbF7;shift:[];st:#27'OV'), {pterm}
  1012. (AnsiChar:0;scan:kbF8;shift:[];st:#27'OW'), {pterm}
  1013. (AnsiChar:0;scan:kbF9;shift:[];st:#27'OX'), {pterm}
  1014. (AnsiChar:0;scan:kbF10;shift:[];st:#27'OY'), {pterm}
  1015. (AnsiChar:0;scan:kbF11;shift:[];st:#27'OZ'), {pterm}
  1016. (AnsiChar:0;scan:kbF12;shift:[];st:#27'O['), {pterm}
  1017. (AnsiChar:0;scan:kbIns;shift:[];st:#27'[2~'), {linux,Eterm,rxvt}
  1018. (AnsiChar:0;scan:kbDel;shift:[];st:#27'[3~'), {linux,Eterm,rxvt}
  1019. (AnsiChar:0;scan:kbHome;shift:[];st:#27'[1~'), {linux}
  1020. (AnsiChar:0;scan:kbHome;shift:[];st:#27'[7~'), {Eterm,rxvt}
  1021. (AnsiChar:0;scan:kbHome;shift:[];st:#27'[H'), {FreeBSD}
  1022. (AnsiChar:0;scan:kbHome;shift:[];st:#27'OH'), {some xterm configurations}
  1023. (AnsiChar:0;scan:kbEnd;shift:[];st:#27'[4~'), {linux,Eterm}
  1024. (AnsiChar:0;scan:kbEnd;shift:[];st:#27'[8~'), {rxvt}
  1025. (AnsiChar:0;scan:kbEnd;shift:[];st:#27'[F'), {FreeBSD}
  1026. (AnsiChar:0;scan:kbEnd;shift:[];st:#27'OF'), {some xterm configurations}
  1027. (AnsiChar:0;scan:kbPgUp;shift:[];st:#27'[5~'), {linux,Eterm,rxvt}
  1028. (AnsiChar:0;scan:kbPgUp;shift:[];st:#27'[I'), {FreeBSD}
  1029. (AnsiChar:0;scan:kbPgDn;shift:[];st:#27'[6~'), {linux,Eterm,rxvt}
  1030. {$ifdef FREEBSD}
  1031. (AnsiChar:0;scan:kbPgDn;shift:[];st:#27'[G'), {FreeBSD, conflicts with linux.
  1032. Note: new FreeBSD versions seem
  1033. to use xterm-like sequences, so
  1034. this one is not needed for them.
  1035. Todo: resolve conflicting sequences
  1036. according to the TERM variable,
  1037. instead of using IFDEFs, this way
  1038. it'll work over SSH across platforms
  1039. too.}
  1040. {$else FREEBSD}
  1041. (AnsiChar:0;scan:kbCenter;shift:[];st:#27'[G'), {linux}
  1042. {$endif FREEBSD}
  1043. (AnsiChar:0;scan:kbCenter;shift:[];st:#27'[E'), {xterm,gnome3}
  1044. (AnsiChar:0;scan:kbUp;shift:[];st:#27'[A'), {linux,FreeBSD,rxvt}
  1045. (AnsiChar:0;scan:kbDown;shift:[];st:#27'[B'), {linux,FreeBSD,rxvt}
  1046. (AnsiChar:0;scan:kbRight;shift:[];st:#27'[C'), {linux,FreeBSD,rxvt}
  1047. (AnsiChar:0;scan:kbLeft;shift:[];st:#27'[D'), {linux,FreeBSD,rxvt}
  1048. (AnsiChar:0;scan:kbUp;shift:[];st:#27'OA'), {xterm}
  1049. (AnsiChar:0;scan:kbDown;shift:[];st:#27'OB'), {xterm}
  1050. (AnsiChar:0;scan:kbRight;shift:[];st:#27'OC'), {xterm}
  1051. (AnsiChar:0;scan:kbLeft;shift:[];st:#27'OD'), {xterm}
  1052. (* Already recognized above as F11!
  1053. (AnsiChar:0;scan:kbShiftF1;shift:[essShift];st:#27'[23~'), {rxvt}
  1054. (AnsiChar:0;scan:kbShiftF2;shift:[essShift];st:#27'[24~'), {rxvt}
  1055. *)
  1056. (* These seem to be shifted. Probably something changed with linux's default keymaps.
  1057. (AnsiChar:0;scan:kbShiftF3;shift:[essShift];st:#27'[25~'), {linux,rxvt}
  1058. (AnsiChar:0;scan:kbShiftF4;shift:[essShift];st:#27'[26~'), {linux,rxvt}
  1059. (AnsiChar:0;scan:kbShiftF5;shift:[essShift];st:#27'[28~'), {linux,rxvt}
  1060. (AnsiChar:0;scan:kbShiftF6;shift:[essShift];st:#27'[29~'), {linux,rxvt}
  1061. (AnsiChar:0;scan:kbShiftF7;shift:[essShift];st:#27'[31~'), {linux,rxvt}
  1062. (AnsiChar:0;scan:kbShiftF8;shift:[essShift];st:#27'[32~'), {linux,rxvt}
  1063. (AnsiChar:0;scan:kbShiftF9;shift:[essShift];st:#27'[33~'), {linux,rxvt}
  1064. (AnsiChar:0;scan:kbShiftF10;shift:[essShift];st:#27'[34~'), {linux,rxvt}*)
  1065. (AnsiChar:0;scan:kbShiftF1;shift:[essShift];st:#27'[25~'), {linux}
  1066. (AnsiChar:0;scan:kbShiftF2;shift:[essShift];st:#27'[26~'), {linux}
  1067. (AnsiChar:0;scan:kbShiftF3;shift:[essShift];st:#27'[28~'), {linux}
  1068. (AnsiChar:0;scan:kbShiftF4;shift:[essShift];st:#27'[29~'), {linux}
  1069. (AnsiChar:0;scan:kbShiftF5;shift:[essShift];st:#27'[31~'), {linux}
  1070. (AnsiChar:0;scan:kbShiftF6;shift:[essShift];st:#27'[32~'), {linux}
  1071. (AnsiChar:0;scan:kbShiftF7;shift:[essShift];st:#27'[33~'), {linux}
  1072. (AnsiChar:0;scan:kbShiftF8;shift:[essShift];st:#27'[34~'), {linux}
  1073. (AnsiChar:0;scan:kbShiftF11;shift:[essShift];st:#27'[23$'), {rxvt}
  1074. (AnsiChar:0;scan:kbShiftF12;shift:[essShift];st:#27'[24$'), {rxvt}
  1075. (AnsiChar:0;scan:kbShiftF1;shift:[essShift];st:#27'[11;2~'), {konsole in vt420pc mode}
  1076. (AnsiChar:0;scan:kbShiftF2;shift:[essShift];st:#27'[12;2~'), {konsole in vt420pc mode}
  1077. (AnsiChar:0;scan:kbShiftF3;shift:[essShift];st:#27'[13;2~'), {konsole in vt420pc mode,kitty}
  1078. (AnsiChar:0;scan:kbShiftF4;shift:[essShift];st:#27'[14;2~'), {konsole in vt420pc mode}
  1079. (AnsiChar:0;scan:kbShiftF5;shift:[essShift];st:#27'[15;2~'), {xterm}
  1080. (AnsiChar:0;scan:kbShiftF6;shift:[essShift];st:#27'[17;2~'), {xterm}
  1081. (AnsiChar:0;scan:kbShiftF7;shift:[essShift];st:#27'[18;2~'), {xterm}
  1082. (AnsiChar:0;scan:kbShiftF8;shift:[essShift];st:#27'[19;2~'), {xterm}
  1083. (AnsiChar:0;scan:kbShiftF9;shift:[essShift];st:#27'[20;2~'), {xterm}
  1084. (AnsiChar:0;scan:kbShiftF10;shift:[essShift];st:#27'[21;2~'), {xterm}
  1085. (AnsiChar:0;scan:kbShiftF11;shift:[essShift];st:#27'[23;2~'), {xterm}
  1086. (AnsiChar:0;scan:kbShiftF12;shift:[essShift];st:#27'[24;2~'), {xterm}
  1087. (AnsiChar:0;scan:kbShiftF1;shift:[essShift];st:#27'O2P'), {konsole,xterm}
  1088. (AnsiChar:0;scan:kbShiftF2;shift:[essShift];st:#27'O2Q'), {konsole,xterm}
  1089. (AnsiChar:0;scan:kbShiftF3;shift:[essShift];st:#27'O2R'), {konsole,xterm}
  1090. (AnsiChar:0;scan:kbShiftF4;shift:[essShift];st:#27'O2S'), {konsole,xterm}
  1091. (AnsiChar:0;scan:kbShiftF1;shift:[essShift];st:#27'[1;2P'), {xterm,gnome3}
  1092. (AnsiChar:0;scan:kbShiftF2;shift:[essShift];st:#27'[1;2Q'), {xterm,gnome3}
  1093. (AnsiChar:0;scan:kbShiftF3;shift:[essShift];st:#27'[1;2R'), {xterm,gnome3}
  1094. (AnsiChar:0;scan:kbShiftF4;shift:[essShift];st:#27'[1;2S'), {xterm,gnome3}
  1095. (AnsiChar:0;scan:kbCtrlF1;shift:[essCtrl];st:#27'O5P'), {konsole,xterm}
  1096. (AnsiChar:0;scan:kbCtrlF2;shift:[essCtrl];st:#27'O5Q'), {konsole,xterm}
  1097. (AnsiChar:0;scan:kbCtrlF3;shift:[essCtrl];st:#27'O5R'), {konsole,xterm}
  1098. (AnsiChar:0;scan:kbCtrlF4;shift:[essCtrl];st:#27'O5S'), {konsole,xterm}
  1099. (AnsiChar:0;scan:kbCtrlF1;shift:[essCtrl];st:#27'[1;5P'), {xterm,gnome3}
  1100. (AnsiChar:0;scan:kbCtrlF2;shift:[essCtrl];st:#27'[1;5Q'), {xterm,gnome3}
  1101. (AnsiChar:0;scan:kbCtrlF3;shift:[essCtrl];st:#27'[1;5R'), {xterm,gnome3}
  1102. (AnsiChar:0;scan:kbCtrlF4;shift:[essCtrl];st:#27'[1;5S'), {xterm,gnome3}
  1103. (AnsiChar:0;scan:kbCtrlF1;shift:[essCtrl];st:#27'[11;5~'), {none, but expected}
  1104. (AnsiChar:0;scan:kbCtrlF2;shift:[essCtrl];st:#27'[12;5~'), {none, but expected}
  1105. (AnsiChar:0;scan:kbCtrlF3;shift:[essCtrl];st:#27'[13;5~'), {kitty}
  1106. (AnsiChar:0;scan:kbCtrlF4;shift:[essCtrl];st:#27'[14;5~'), {none, but expected}
  1107. (AnsiChar:0;scan:kbCtrlF5;shift:[essCtrl];st:#27'[15;5~'), {xterm}
  1108. (AnsiChar:0;scan:kbCtrlF6;shift:[essCtrl];st:#27'[17;5~'), {xterm}
  1109. (AnsiChar:0;scan:kbCtrlF7;shift:[essCtrl];st:#27'[18;5~'), {xterm}
  1110. (AnsiChar:0;scan:kbCtrlF8;shift:[essCtrl];st:#27'[19;5~'), {xterm}
  1111. (AnsiChar:0;scan:kbCtrlF9;shift:[essCtrl];st:#27'[20;5~'), {xterm}
  1112. (AnsiChar:0;scan:kbCtrlF10;shift:[essCtrl];st:#27'[21;5~'), {xterm}
  1113. (AnsiChar:0;scan:kbCtrlF11;shift:[essCtrl];st:#27'[23;5~'), {xterm}
  1114. (AnsiChar:0;scan:kbCtrlF12;shift:[essCtrl];st:#27'[24;5~'), {xterm}
  1115. (AnsiChar:0;scan:kbCtrlF1;shift:[essCtrl];st:#27'[11^'), {rxvt}
  1116. (AnsiChar:0;scan:kbCtrlF2;shift:[essCtrl];st:#27'[12^'), {rxvt}
  1117. (AnsiChar:0;scan:kbCtrlF3;shift:[essCtrl];st:#27'[13^'), {rxvt}
  1118. (AnsiChar:0;scan:kbCtrlF4;shift:[essCtrl];st:#27'[14^'), {rxvt}
  1119. (AnsiChar:0;scan:kbCtrlF5;shift:[essCtrl];st:#27'[15^'), {rxvt}
  1120. (AnsiChar:0;scan:kbCtrlF6;shift:[essCtrl];st:#27'[17^'), {rxvt}
  1121. (AnsiChar:0;scan:kbCtrlF7;shift:[essCtrl];st:#27'[18^'), {rxvt}
  1122. (AnsiChar:0;scan:kbCtrlF8;shift:[essCtrl];st:#27'[19^'), {rxvt}
  1123. (AnsiChar:0;scan:kbCtrlF9;shift:[essCtrl];st:#27'[20^'), {rxvt}
  1124. (AnsiChar:0;scan:kbCtrlF10;shift:[essCtrl];st:#27'[21^'), {rxvt}
  1125. (AnsiChar:0;scan:kbCtrlF11;shift:[essCtrl];st:#27'[23^'), {rxvt}
  1126. (AnsiChar:0;scan:kbCtrlF12;shift:[essCtrl];st:#27'[24^'), {rxvt}
  1127. (AnsiChar:0;scan:kbShiftIns;shift:[essShift];st:#27'[2;2~'), {should be the code, but shift+ins
  1128. is paste X clipboard in many
  1129. terminal emulators :(}
  1130. (AnsiChar:0;scan:kbShiftDel;shift:[essShift];st:#27'[3;2~'), {xterm,konsole}
  1131. (AnsiChar:0;scan:kbCtrlIns;shift:[essCtrl];st:#27'[2;5~'), {xterm}
  1132. (AnsiChar:0;scan:kbCtrlDel;shift:[essCtrl];st:#27'[3;5~'), {xterm}
  1133. (AnsiChar:0;scan:kbShiftIns;shift:[essShift];st:#27'[2$'), {rxvt}
  1134. (AnsiChar:0;scan:kbShiftDel;shift:[essShift];st:#27'[3$'), {rxvt}
  1135. (AnsiChar:0;scan:kbCtrlIns;shift:[essCtrl];st:#27'[2^'), {rxvt}
  1136. (AnsiChar:0;scan:kbCtrlDel;shift:[essCtrl];st:#27'[3^'), {rxvt}
  1137. (AnsiChar:0;scan:kbAltF1;shift:[essAlt];st:#27#27'[[A'),
  1138. (AnsiChar:0;scan:kbAltF2;shift:[essAlt];st:#27#27'[[B'),
  1139. (AnsiChar:0;scan:kbAltF3;shift:[essAlt];st:#27#27'[[C'),
  1140. (AnsiChar:0;scan:kbAltF4;shift:[essAlt];st:#27#27'[[D'),
  1141. (AnsiChar:0;scan:kbAltF5;shift:[essAlt];st:#27#27'[[E'),
  1142. (AnsiChar:0;scan:kbAltF1;shift:[essAlt];st:#27#27'[11~'), {rxvt}
  1143. (AnsiChar:0;scan:kbAltF2;shift:[essAlt];st:#27#27'[12~'), {rxvt}
  1144. (AnsiChar:0;scan:kbAltF3;shift:[essAlt];st:#27#27'[13~'), {rxvt}
  1145. (AnsiChar:0;scan:kbAltF4;shift:[essAlt];st:#27#27'[14~'), {rxvt}
  1146. (AnsiChar:0;scan:kbAltF5;shift:[essAlt];st:#27#27'[15~'), {rxvt}
  1147. (AnsiChar:0;scan:kbAltF6;shift:[essAlt];st:#27#27'[17~'), {rxvt}
  1148. (AnsiChar:0;scan:kbAltF7;shift:[essAlt];st:#27#27'[18~'), {rxvt}
  1149. (AnsiChar:0;scan:kbAltF8;shift:[essAlt];st:#27#27'[19~'), {rxvt}
  1150. (AnsiChar:0;scan:kbAltF9;shift:[essAlt];st:#27#27'[20~'), {rxvt}
  1151. (AnsiChar:0;scan:kbAltF10;shift:[essAlt];st:#27#27'[21~'), {rxvt}
  1152. (AnsiChar:0;scan:kbAltF11;shift:[essAlt];st:#27#27'[23~'), {rxvt}
  1153. (AnsiChar:0;scan:kbAltF12;shift:[essAlt];st:#27#27'[24~'), {rxvt}
  1154. (AnsiChar:0;scan:kbAltF1;shift:[essAlt];st:#27#27'OP'), {xterm}
  1155. (AnsiChar:0;scan:kbAltF2;shift:[essAlt];st:#27#27'OQ'), {xterm}
  1156. (AnsiChar:0;scan:kbAltF3;shift:[essAlt];st:#27#27'OR'), {xterm}
  1157. (AnsiChar:0;scan:kbAltF4;shift:[essAlt];st:#27#27'OS'), {xterm}
  1158. (AnsiChar:0;scan:kbAltF5;shift:[essAlt];st:#27#27'Ot'), {xterm}
  1159. (AnsiChar:0;scan:kbAltF6;shift:[essAlt];st:#27#27'Ou'), {xterm}
  1160. (AnsiChar:0;scan:kbAltF7;shift:[essAlt];st:#27#27'Ov'), {xterm}
  1161. (AnsiChar:0;scan:kbAltF8;shift:[essAlt];st:#27#27'Ol'), {xterm}
  1162. (AnsiChar:0;scan:kbAltF9;shift:[essAlt];st:#27#27'Ow'), {xterm}
  1163. (AnsiChar:0;scan:kbAltF10;shift:[essAlt];st:#27#27'Ox'), {xterm}
  1164. (AnsiChar:0;scan:kbAltF11;shift:[essAlt];st:#27#27'Oy'), {xterm}
  1165. (AnsiChar:0;scan:kbAltF12;shift:[essAlt];st:#27#27'Oz'), {xterm}
  1166. (AnsiChar:0;scan:kbAltF1;shift:[essAlt];st:#27'[1;3P'), {xterm,gnome3}
  1167. (AnsiChar:0;scan:kbAltF2;shift:[essAlt];st:#27'[1;3Q'), {xterm,gnome3}
  1168. (AnsiChar:0;scan:kbAltF3;shift:[essAlt];st:#27'[1;3R'), {xterm,gnome3}
  1169. (AnsiChar:0;scan:kbAltF4;shift:[essAlt];st:#27'[1;3S'), {xterm,gnome3}
  1170. (AnsiChar:0;scan:kbAltF1;shift:[essAlt];st:#27'O3P'), {xterm on FreeBSD}
  1171. (AnsiChar:0;scan:kbAltF2;shift:[essAlt];st:#27'O3Q'), {xterm on FreeBSD}
  1172. (AnsiChar:0;scan:kbAltF3;shift:[essAlt];st:#27'O3R'), {xterm on FreeBSD}
  1173. (AnsiChar:0;scan:kbAltF3;shift:[essAlt];st:#27'[13;3~'), {kitty}
  1174. (AnsiChar:0;scan:kbAltF4;shift:[essAlt];st:#27'O3S'), {xterm on FreeBSD}
  1175. (AnsiChar:0;scan:kbAltF5;shift:[essAlt];st:#27'[15;3~'), {xterm on FreeBSD}
  1176. (AnsiChar:0;scan:kbAltF6;shift:[essAlt];st:#27'[17;3~'), {xterm on FreeBSD}
  1177. (AnsiChar:0;scan:kbAltF7;shift:[essAlt];st:#27'[18;3~'), {xterm on FreeBSD}
  1178. (AnsiChar:0;scan:kbAltF8;shift:[essAlt];st:#27'[19;3~'), {xterm on FreeBSD}
  1179. (AnsiChar:0;scan:kbAltF9;shift:[essAlt];st:#27'[20;3~'), {xterm on FreeBSD}
  1180. (AnsiChar:0;scan:kbAltF10;shift:[essAlt];st:#27'[21;3~'), {xterm on FreeBSD}
  1181. (AnsiChar:0;scan:kbAltF11;shift:[essAlt];st:#27'[23;3~'), {xterm on FreeBSD}
  1182. (AnsiChar:0;scan:kbAltF12;shift:[essAlt];st:#27'[24;3~'), {xterm on FreeBSD}
  1183. (AnsiChar:0;scan:kbCtrlF1;shift:[essCtrl,essShift];st:#27'[1;6P'), {xterm,gnome3}
  1184. (AnsiChar:0;scan:kbCtrlF2;shift:[essCtrl,essShift];st:#27'[1;6Q'), {xterm,gnome3}
  1185. (AnsiChar:0;scan:kbCtrlF3;shift:[essCtrl,essShift];st:#27'[1;6R'), {xterm,gnome3}
  1186. (AnsiChar:0;scan:kbCtrlF3;shift:[essCtrl,essShift];st:#27'[13;6~'), {kitty}
  1187. (AnsiChar:0;scan:kbCtrlF4;shift:[essCtrl,essShift];st:#27'[1;6S'), {xterm,gnome3}
  1188. (AnsiChar:0;scan:kbCtrlF5;shift:[essCtrl,essShift];st:#27'[15;6~'), {xterm}
  1189. (AnsiChar:0;scan:kbCtrlF6;shift:[essCtrl,essShift];st:#27'[17;6~'), {xterm}
  1190. (AnsiChar:0;scan:kbCtrlF7;shift:[essCtrl,essShift];st:#27'[18;6~'), {xterm}
  1191. (AnsiChar:0;scan:kbCtrlF8;shift:[essCtrl,essShift];st:#27'[19;6~'), {xterm}
  1192. (AnsiChar:0;scan:kbCtrlF9;shift:[essCtrl,essShift];st:#27'[20;6~'), {xterm}
  1193. (AnsiChar:0;scan:kbCtrlF10;shift:[essCtrl,essShift];st:#27'[21;6~'), {xterm}
  1194. (AnsiChar:0;scan:kbCtrlF11;shift:[essCtrl,essShift];st:#27'[23;6~'), {xterm}
  1195. (AnsiChar:0;scan:kbCtrlF12;shift:[essCtrl,essShift];st:#27'[24;6~'), {xterm}
  1196. (AnsiChar:0;scan:kbAltF1;shift:[essShift,essAlt];st:#27'[1;4P'), {xterm}
  1197. (AnsiChar:0;scan:kbAltF2;shift:[essShift,essAlt];st:#27'[1;4Q'), {xterm}
  1198. (AnsiChar:0;scan:kbAltF3;shift:[essShift,essAlt];st:#27'[1;4R'), {xterm}
  1199. (AnsiChar:0;scan:kbAltF3;shift:[essShift,essAlt];st:#27'[13;4~'), {kitty}
  1200. (AnsiChar:0;scan:kbAltF4;shift:[essShift,essAlt];st:#27'[1;4S'), {xterm}
  1201. (AnsiChar:0;scan:kbAltF5;shift:[essShift,essAlt];st:#27'[15;4~'), {xterm}
  1202. (AnsiChar:0;scan:kbAltF6;shift:[essShift,essAlt];st:#27'[17;4~'), {xterm}
  1203. (AnsiChar:0;scan:kbAltF7;shift:[essShift,essAlt];st:#27'[18;4~'), {xterm}
  1204. (AnsiChar:0;scan:kbAltF8;shift:[essShift,essAlt];st:#27'[19;4~'), {xterm}
  1205. (AnsiChar:0;scan:kbAltF9;shift:[essShift,essAlt];st:#27'[20;4~'), {xterm}
  1206. (AnsiChar:0;scan:kbAltF10;shift:[essShift,essAlt];st:#27'[21;4~'), {xterm}
  1207. (AnsiChar:0;scan:kbAltF11;shift:[essShift,essAlt];st:#27'[23;4~'), {xterm}
  1208. (AnsiChar:0;scan:kbAltF12;shift:[essShift,essAlt];st:#27'[24;4~'), {xterm}
  1209. (AnsiChar:0;scan:KbAltF1;shift:[essCtrl,essShift,essAlt];st:#27'[1;8P'), {xterm}
  1210. (AnsiChar:0;scan:KbAltF2;shift:[essCtrl,essShift,essAlt];st:#27'[1;8Q'), {xterm}
  1211. (AnsiChar:0;scan:KbAltF3;shift:[essCtrl,essShift,essAlt];st:#27'[1;8R'), {xterm}
  1212. (AnsiChar:0;scan:KbAltF3;shift:[essCtrl,essShift,essAlt];st:#27'[13;8~'), {kitty}
  1213. (AnsiChar:0;scan:KbAltF4;shift:[essCtrl,essShift,essAlt];st:#27'[1;8S'), {xterm}
  1214. (AnsiChar:0;scan:KbAltF5;shift:[essCtrl,essShift,essAlt];st:#27'[15;8~'), {xterm}
  1215. (AnsiChar:0;scan:KbAltF6;shift:[essCtrl,essShift,essAlt];st:#27'[17;8~'), {xterm}
  1216. (AnsiChar:0;scan:KbAltF7;shift:[essCtrl,essShift,essAlt];st:#27'[18;8~'), {xterm}
  1217. (AnsiChar:0;scan:KbAltF8;shift:[essCtrl,essShift,essAlt];st:#27'[19;8~'), {xterm}
  1218. (AnsiChar:0;scan:KbAltF9;shift:[essCtrl,essShift,essAlt];st:#27'[20;8~'), {xterm}
  1219. (AnsiChar:0;scan:KbAltF10;shift:[essCtrl,essShift,essAlt];st:#27'[21;8~'), {xterm}
  1220. (AnsiChar:0;scan:KbAltF11;shift:[essCtrl,essShift,essAlt];st:#27'[23;8~'), {xterm}
  1221. (AnsiChar:0;scan:KbAltF12;shift:[essCtrl,essShift,essAlt];st:#27'[24;8~'), {xterm}
  1222. (AnsiChar:0;scan:kbShiftTab;shift:[essShift];st:#27#9), {linux - 'Meta_Tab'}
  1223. (AnsiChar:0;scan:kbShiftTab;shift:[essShift];st:#27'[Z'),
  1224. (AnsiChar:0;scan:kbUp;shift:[essShift];st:#27'[1;2A'), {xterm}
  1225. (AnsiChar:0;scan:kbDown;shift:[essShift];st:#27'[1;2B'), {xterm}
  1226. (AnsiChar:0;scan:kbRight;shift:[essShift];st:#27'[1;2C'), {xterm}
  1227. (AnsiChar:0;scan:kbLeft;shift:[essShift];st:#27'[1;2D'), {xterm}
  1228. (AnsiChar:0;scan:kbCenter;shift:[essShift];st:#27'[1;2E'),{xterm}
  1229. (AnsiChar:0;scan:kbPgUp;shift:[essShift];st:#27'[5;2~'), {fpterm, xterm-compatible sequence (but xterm uses shift+pgup/pgdn for scrollback)}
  1230. (AnsiChar:0;scan:kbPgDn;shift:[essShift];st:#27'[6;2~'), {fpterm, xterm-compatible sequence (but xterm uses shift+pgup/pgdn for scrollback)}
  1231. (AnsiChar:0;scan:kbUp;shift:[essShift];st:#27'[a'), {rxvt}
  1232. (AnsiChar:0;scan:kbDown;shift:[essShift];st:#27'[b'), {rxvt}
  1233. (AnsiChar:0;scan:kbRight;shift:[essShift];st:#27'[c'), {rxvt}
  1234. (AnsiChar:0;scan:kbLeft;shift:[essShift];st:#27'[d'), {rxvt}
  1235. (AnsiChar:0;scan:kbEnd;shift:[essShift];st:#27'[1;2F'), {xterm}
  1236. (AnsiChar:0;scan:kbEnd;shift:[essShift];st:#27'[8$'), {rxvt}
  1237. (AnsiChar:0;scan:kbHome;shift:[essShift];st:#27'[1;2H'), {xterm}
  1238. (AnsiChar:0;scan:kbHome;shift:[essShift];st:#27'[7$'), {rxvt}
  1239. (AnsiChar:0;scan:kbShiftIns;shift:[essShift];st:#27'Op'), {rxvt - on numpad}
  1240. (AnsiChar:0;scan:kbShiftDel;shift:[essShift];st:#27'On'), {rxvt - on numpad}
  1241. (AnsiChar:0;scan:KbCtrlUp;shift:[essCtrl,essShift];st:#27'[1;6A'), {xterm}
  1242. (AnsiChar:0;scan:KbCtrlDown;shift:[essCtrl,essShift];st:#27'[1;6B'), {xterm}
  1243. (AnsiChar:0;scan:KbCtrlRight;shift:[essCtrl,essShift];st:#27'[1;6C'), {xterm, xfce4}
  1244. (AnsiChar:0;scan:KbCtrlLeft;shift:[essCtrl,essShift];st:#27'[1;6D'), {xterm, xfce4}
  1245. (AnsiChar:0;scan:KbCtrlCenter;shift:[essCtrl,essShift];st:#27'[1;6E'),{xterm}
  1246. (AnsiChar:0;scan:KbCtrlHome;shift:[essCtrl,essShift];st:#27'[1;6H'), {xterm}
  1247. (AnsiChar:0;scan:KbCtrlEnd;shift:[essCtrl,essShift];st:#27'[1;6F'), {xterm}
  1248. (AnsiChar:0;scan:KbCtrlIns;shift:[essCtrl,essShift];st:#27'[2;6~'), {xterm}
  1249. (AnsiChar:0;scan:KbCtrlDel;shift:[essCtrl,essShift];st:#27'[3;6~'), {xterm}
  1250. (AnsiChar:0;scan:kbCtrlPgUp;shift:[essCtrl,essShift];st:#27'[5;6~'), {fpterm, xterm-compatible sequence (but xterm uses shift+pgup/pgdn for scrollback)}
  1251. (AnsiChar:0;scan:kbCtrlPgDn;shift:[essCtrl,essShift];st:#27'[6;6~'), {fpterm, xterm-compatible sequence (but xterm uses shift+pgup/pgdn for scrollback)}
  1252. (AnsiChar:0;scan:kbCtrlPgDn;shift:[essCtrl];st:#27'[6;5~'), {xterm}
  1253. (AnsiChar:0;scan:kbCtrlPgUp;shift:[essCtrl];st:#27'[5;5~'), {xterm}
  1254. (AnsiChar:0;scan:kbCtrlUp;shift:[essCtrl];st:#27'[1;5A'), {xterm}
  1255. (AnsiChar:0;scan:kbCtrlDown;shift:[essCtrl];st:#27'[1;5B'), {xterm}
  1256. (AnsiChar:0;scan:kbCtrlRight;shift:[essCtrl];st:#27'[1;5C'), {xterm}
  1257. (AnsiChar:0;scan:kbCtrlLeft;shift:[essCtrl];st:#27'[1;5D'), {xterm}
  1258. (AnsiChar:0;scan:kbCtrlCenter;shift:[essCtrl];st:#27'[1;5E'), {xterm}
  1259. (AnsiChar:0;scan:kbCtrlUp;shift:[essCtrl];st:#27'[Oa'), {rxvt}
  1260. (AnsiChar:0;scan:kbCtrlDown;shift:[essCtrl];st:#27'[Ob'), {rxvt}
  1261. (AnsiChar:0;scan:kbCtrlRight;shift:[essCtrl];st:#27'[Oc'), {rxvt}
  1262. (AnsiChar:0;scan:kbCtrlLeft;shift:[essCtrl];st:#27'[Od'), {rxvt}
  1263. (AnsiChar:0;scan:kbCtrlEnd;shift:[essCtrl];st:#27'[1;5F'), {xterm}
  1264. (AnsiChar:0;scan:kbCtrlEnd;shift:[essCtrl];st:#27'[8^'), {rxvt}
  1265. (AnsiChar:0;scan:kbCtrlHome;shift:[essCtrl];st:#27'[1;5H'), {xterm}
  1266. (AnsiChar:0;scan:kbCtrlHome;shift:[essCtrl];st:#27'[7^'), {rxvt}
  1267. (AnsiChar:0;scan:kbCtrlPgUp;shift:[essCtrl];st:#27'[5^'), {rxvt}
  1268. (AnsiChar:0;scan:kbCtrlPgDn;shift:[essCtrl];st:#27'[6^'), {rxvt}
  1269. (AnsiChar:0;scan:kbCtrlUp;shift:[essCtrl];st:#27'Oa'), {rxvt}
  1270. (AnsiChar:0;scan:kbCtrlDown;shift:[essCtrl];st:#27'Ob'), {rxvt}
  1271. (AnsiChar:0;scan:kbCtrlLeft;shift:[essCtrl];st:#27'Od'), {rxvt}
  1272. (AnsiChar:0;scan:kbCtrlRight;shift:[essCtrl];st:#27'Oc'), {rxvt}
  1273. (AnsiChar:0;scan:kbCtrlPgUp;shift:[essCtrl,essShift];st:#27'[5@'), {rxvt}
  1274. (AnsiChar:0;scan:kbCtrlPgDn;shift:[essCtrl,essShift];st:#27'[6@'), {rxvt}
  1275. (AnsiChar:0;scan:kbCtrlEnd;shift:[essCtrl,essShift];st:#27'[8@'), {rxvt}
  1276. (AnsiChar:0;scan:kbCtrlHome;shift:[essCtrl,essShift];st:#27'[7@'), {rxvt}
  1277. (AnsiChar:0;scan:kbCtrlIns;shift:[essCtrl,essShift];st:#27'[2@'), {rxvt}
  1278. (AnsiChar:0;scan:kbCtrlDel;shift:[essCtrl,essShift];st:#27'[3@'), {rxvt}
  1279. (AnsiChar:0;scan:kbAltUp;shift:[essAlt];st:#27#27'[A'), {rxvt}
  1280. (AnsiChar:0;scan:kbAltDown;shift:[essAlt];st:#27#27'[B'), {rxvt}
  1281. (AnsiChar:0;scan:kbAltLeft;shift:[essAlt];st:#27#27'[D'), {rxvt}
  1282. (AnsiChar:0;scan:kbAltRight;shift:[essAlt];st:#27#27'[C'), {rxvt}
  1283. (AnsiChar:0;scan:kbAltUp;shift:[essShift,essAlt];st:#27#27'[a'), {rxvt}
  1284. (AnsiChar:0;scan:kbAltDown;shift:[essShift,essAlt];st:#27#27'[b'), {rxvt}
  1285. (AnsiChar:0;scan:kbAltLeft;shift:[essShift,essAlt];st:#27#27'[d'), {rxvt}
  1286. (AnsiChar:0;scan:kbAltRight;shift:[essShift,essAlt];st:#27#27'[c'), {rxvt}
  1287. {$ifdef HAIKU}
  1288. (AnsiChar:0;scan:kbAltUp;shift:[essAlt];st:#27#27'OA'),
  1289. (AnsiChar:0;scan:kbAltDown;shift:[essAlt];st:#27#27'OB'),
  1290. (AnsiChar:0;scan:kbAltRight;shift:[essAlt];st:#27#27'OC'),
  1291. {$else}
  1292. (AnsiChar:0;scan:kbAltUp;shift:[essAlt];st:#27'OA'),
  1293. (AnsiChar:0;scan:kbAltDown;shift:[essAlt];st:#27'OB'),
  1294. (AnsiChar:0;scan:kbAltRight;shift:[essAlt];st:#27'OC'),
  1295. {$endif}
  1296. (AnsiChar:0;scan:kbAltLeft;shift:[essAlt];st:#27#27'OD'),
  1297. (AnsiChar:0;scan:kbAltPgUp;shift:[essAlt];st:#27#27'[5~'), {rxvt}
  1298. (AnsiChar:0;scan:kbAltPgDn;shift:[essAlt];st:#27#27'[6~'), {rxvt}
  1299. (AnsiChar:0;scan:kbAltEnd;shift:[essAlt];st:#27#27'[4~'),
  1300. (AnsiChar:0;scan:kbAltEnd;shift:[essAlt];st:#27#27'[8~'), {rxvt}
  1301. (AnsiChar:0;scan:kbAltHome;shift:[essAlt];st:#27#27'[1~'),
  1302. (AnsiChar:0;scan:kbAltHome;shift:[essAlt];st:#27#27'[7~'), {rxvt}
  1303. (AnsiChar:0;scan:kbAltIns;shift:[essAlt];st:#27#27'[2~'), {rxvt}
  1304. (AnsiChar:0;scan:kbAltDel;shift:[essAlt];st:#27#27'[3~'), {rxvt}
  1305. (AnsiChar:0;scan:kbAltPgUp;shift:[essShift,essAlt];st:#27#27'[5$'), {rxvt}
  1306. (AnsiChar:0;scan:kbAltPgDn;shift:[essShift,essAlt];st:#27#27'[6$'), {rxvt}
  1307. (AnsiChar:0;scan:kbAltEnd;shift:[essShift,essAlt];st:#27#27'[8$'), {rxvt}
  1308. (AnsiChar:0;scan:kbAltHome;shift:[essShift,essAlt];st:#27#27'[7$'), {rxvt}
  1309. (AnsiChar:0;scan:kbAltIns;shift:[essShift,essAlt];st:#27#27'[2$'), {rxvt}
  1310. (AnsiChar:0;scan:kbAltDel;shift:[essShift,essAlt];st:#27#27'[3$'), {rxvt}
  1311. (AnsiChar:0;scan:kbAltPgUp;shift:[essCtrl,essShift,essAlt];st:#27#27'[5@'), {rxvt}
  1312. (AnsiChar:0;scan:kbAltPgDn;shift:[essCtrl,essShift,essAlt];st:#27#27'[6@'), {rxvt}
  1313. (AnsiChar:0;scan:kbAltEnd;shift:[essCtrl,essShift,essAlt];st:#27#27'[8@'), {rxvt}
  1314. (AnsiChar:0;scan:kbAltHome;shift:[essCtrl,essShift,essAlt];st:#27#27'[7@'), {rxvt}
  1315. (AnsiChar:0;scan:kbAltIns;shift:[essCtrl,essShift,essAlt];st:#27#27'[2@'), {rxvt}
  1316. (AnsiChar:0;scan:kbAltDel;shift:[essCtrl,essShift,essAlt];st:#27#27'[3@'), {rxvt}
  1317. (AnsiChar:0;scan:KbAltUp;shift:[essAlt];st:#27'[1;3A'), {xterm}
  1318. (AnsiChar:0;scan:KbAltDown;shift:[essAlt];st:#27'[1;3B'), {xterm}
  1319. (AnsiChar:0;scan:KbAltRight;shift:[essAlt];st:#27'[1;3C'), {xterm}
  1320. (AnsiChar:0;scan:KbAltLeft;shift:[essAlt];st:#27'[1;3D'), {xterm}
  1321. (AnsiChar:0;scan:KbAltCenter;shift:[essAlt];st:#27'[1;3E'), {xterm}
  1322. (AnsiChar:0;scan:KbAltHome;shift:[essAlt];st:#27'[1;3H'), {xterm}
  1323. (AnsiChar:0;scan:KbAltEnd;shift:[essAlt];st:#27'[1;3F'), {xterm}
  1324. (AnsiChar:0;scan:KbAltIns;shift:[essAlt];st:#27'[2;3~'), {xterm}
  1325. (AnsiChar:0;scan:KbAltDel;shift:[essAlt];st:#27'[3;3~'), {xterm}
  1326. (AnsiChar:0;scan:kbAltPgUp;shift:[essAlt];st:#27'[5;3~'), {xterm}
  1327. (AnsiChar:0;scan:kbAltPgDn;shift:[essAlt];st:#27'[6;3~'), {xterm}
  1328. (AnsiChar:0;scan:kbAltUp;shift:[essShift,essAlt];st:#27'[1;4A'), {xterm}
  1329. (AnsiChar:0;scan:kbAltDown;shift:[essShift,essAlt];st:#27'[1;4B'), {xterm}
  1330. (AnsiChar:0;scan:kbAltRight;shift:[essShift,essAlt];st:#27'[1;4C'), {xterm}
  1331. (AnsiChar:0;scan:kbAltLeft;shift:[essShift,essAlt];st:#27'[1;4D'), {xterm}
  1332. (AnsiChar:0;scan:kbAltCenter;shift:[essShift,essAlt];st:#27'[1;4E'), {xterm}
  1333. (AnsiChar:0;scan:kbAltHome;shift:[essShift,essAlt];st:#27'[1;4H'), {xterm}
  1334. (AnsiChar:0;scan:kbAltEnd;shift:[essShift,essAlt];st:#27'[1;4F'), {xterm}
  1335. (AnsiChar:0;scan:kbAltIns;shift:[essShift,essAlt];st:#27'[2;4~'), {xterm}
  1336. (AnsiChar:0;scan:kbAltDel;shift:[essShift,essAlt];st:#27'[3;4~'), {xterm}
  1337. (AnsiChar:0;scan:kbAltPgUp;shift:[essShift,essAlt];st:#27'[5;4~'), {xterm}
  1338. (AnsiChar:0;scan:kbAltPgDn;shift:[essShift,essAlt];st:#27'[6;4~'), {xterm}
  1339. (AnsiChar:0;scan:KbAltIns;shift:[essCtrl,essAlt];st:#27'[2;7~'), {xterm}
  1340. (AnsiChar:0;scan:KbAltDel;shift:[essCtrl,essAlt];st:#27'[3;7~'), {xterm (Del on numpad)}
  1341. (AnsiChar:0;scan:KbAltPgUp;shift:[essCtrl,essAlt];st:#27'[5;7~'), {xterm}
  1342. (AnsiChar:0;scan:KbAltPgDn;shift:[essCtrl,essAlt];st:#27'[6;7~'), {xterm}
  1343. (AnsiChar:0;scan:KbAltUp;shift:[essCtrl,essShift,essAlt];st:#27'[1;8A'), {xterm}
  1344. (AnsiChar:0;scan:KbAltDown;shift:[essCtrl,essShift,essAlt];st:#27'[1;8B'), {xterm}
  1345. (AnsiChar:0;scan:KbAltRight;shift:[essCtrl,essShift,essAlt];st:#27'[1;8C'), {xterm}
  1346. (AnsiChar:0;scan:KbAltLeft;shift:[essCtrl,essShift,essAlt];st:#27'[1;8D'), {xterm}
  1347. (AnsiChar:0;scan:KbAltCenter;shift:[essCtrl,essShift,essAlt];st:#27'[1;8E'), {xterm}
  1348. (AnsiChar:0;scan:KbAltHome;shift:[essCtrl,essShift,essAlt];st:#27'[1;8H'), {xterm}
  1349. (AnsiChar:0;scan:KbAltEnd;shift:[essCtrl,essShift,essAlt];st:#27'[1;8F'), {xterm}
  1350. (AnsiChar:0;scan:KbAltIns;shift:[essCtrl,essShift,essAlt];st:#27'[2;8~'), {xterm}
  1351. (AnsiChar:0;scan:KbAltDel;shift:[essCtrl,essShift,essAlt];st:#27'[3;8~'), {xterm}
  1352. (AnsiChar:0;scan:KbAltPgUp;shift:[essCtrl,essShift,essAlt];st:#27'[5;8~'), {xterm}
  1353. (AnsiChar:0;scan:KbAltPgDn;shift:[essCtrl,essShift,essAlt];st:#27'[6;8~'), {xterm}
  1354. { xterm default values }
  1355. { xterm alternate default values }
  1356. { ignored sequences }
  1357. (AnsiChar:0;scan:0;shift:[];st:#27'[?1;0c'),
  1358. (AnsiChar:0;scan:0;shift:[];st:#27'[?1l'),
  1359. (AnsiChar:0;scan:0;shift:[];st:#27'[?1h'),
  1360. (AnsiChar:0;scan:0;shift:[];st:#27'[?1;2c'),
  1361. (AnsiChar:0;scan:0;shift:[];st:#27'[?7l'),
  1362. (AnsiChar:0;scan:0;shift:[];st:#27'[?7h')
  1363. );
  1364. {those are rxvt specific, due to conflict can not put in main array }
  1365. const rxvt_key_sequences:array[0..7] of key_sequence=(
  1366. (AnsiChar:0;scan:kbShiftF3;shift:[essShift];st:#27'[25~'), {rxvt,pterm}
  1367. (AnsiChar:0;scan:kbShiftF4;shift:[essShift];st:#27'[26~'), {rxvt,pterm}
  1368. (AnsiChar:0;scan:kbShiftF5;shift:[essShift];st:#27'[28~'), {rxvt,pterm}
  1369. (AnsiChar:0;scan:kbShiftF6;shift:[essShift];st:#27'[29~'), {rxvt,pterm}
  1370. (AnsiChar:0;scan:kbShiftF7;shift:[essShift];st:#27'[31~'), {rxvt,pterm}
  1371. (AnsiChar:0;scan:kbShiftF8;shift:[essShift];st:#27'[32~'), {rxvt,pterm}
  1372. (AnsiChar:0;scan:kbShiftF9;shift:[essShift];st:#27'[33~'), {rxvt,pterm}
  1373. (AnsiChar:0;scan:kbShiftF10;shift:[essShift];st:#27'[34~') {rxvt,pterm}
  1374. );
  1375. type TTerm = (trNone,trCons,trEterm,trGnome,trKonsole,trRxvt,trScreen,trXterm,trLinux);
  1376. function detect_terminal:TTerm;
  1377. const terminals:array[TTerm] of string[7]=('None'#0,'cons','eterm','gnome',
  1378. 'konsole','rxvt','screen',
  1379. 'xterm','linux');
  1380. var term:string;
  1381. i,t:TTerm;
  1382. begin
  1383. detect_terminal:=trNone;
  1384. t:=trNone;
  1385. term:=fpgetenv('TERM');
  1386. for i:=low(terminals) to high(terminals) do
  1387. if copy(term,1,length(terminals[i]))=terminals[i] then
  1388. begin
  1389. t:=i;
  1390. break;
  1391. end;
  1392. if t=trXterm then
  1393. begin
  1394. {Rxvt sets TERM=xterm and COLORTERM=rxvt. Gnome does something similar.}
  1395. term:=fpgetenv('COLORTERM');
  1396. for i:=low(terminals) to high(terminals) do
  1397. if copy(term,1,length(terminals[i]))=terminals[i] then
  1398. begin
  1399. t:=i;
  1400. break;
  1401. end;
  1402. end;
  1403. detect_terminal:=t;
  1404. end;
  1405. type TKeyByte = array [0..23] of byte;
  1406. PKeyByte = ^TKeyByte;
  1407. const cSunKey : TKeyByte =(224,225,226,227,228,229,230,231,232,233,192,193,
  1408. 2,3,214,220,216,222,218,197,0,0,0,0);
  1409. const cKb : TKeyByte = (kbF1,kbF2,kbF3,kbF4,kbF5,kbF6,kbF7,kbF8,kbF9,kbF10,kbF11,kbF12,
  1410. kbIns,kbDel,KbHome,KbEnd,KbPgUp,KbPgDn,KbCenter,{kbMenu}0,KbUp,KbLeft,KbRight,KbDown);
  1411. const cKbCtrl : TKeyByte = (kbCtrlF1,kbCtrlF2,kbCtrlF3,kbCtrlF4,kbCtrlF5,kbCtrlF6,kbCtrlF7,kbCtrlF8,kbCtrlF9,kbCtrlF10,kbCtrlF11,kbCtrlF12,
  1412. kbCtrlIns,kbCtrlDel,KbCtrlHome,KbCtrlEnd,KbCtrlPgUp,KbCtrlPgDn,KbCtrlCenter,{kbCtrlMenu}0,KbCtrlUp,KbCtrlLeft,KbCtrlRight,KbCtrlDown);
  1413. const cKbAlt : TKeyByte = (kbAltF1,kbAltF2,kbAltF3,kbAltF4,kbAltF5,kbAltF6,kbAltF7,kbAltF8,kbAltF9,kbAltF10,kbAltF11,kbAltF12,
  1414. kbAltIns,kbAltDel,KbAltHome,KbAltEnd,KbAltPgUp,KbAltPgDn,KbAltCenter,{kbAltMenu}0,KbAltUp,KbAltLeft,KbAltRight,KbAltDown);
  1415. const cSunKeyEnd : array [0..7] of string [3] = ('z',';2z',';3z',';4z',';5z',';6z',';7z',';8z');
  1416. cKeyScanCode : array [0..7] of PKeyByte = (@cKb,@cKb,@cKbAlt,@cKbAlt,@cKbCtrl,@cKbCtrl,@cKbAlt,@cKbAlt);
  1417. cKeyShift : array [0..7] of TEnhancedShiftState=(
  1418. {} [],
  1419. {2} [essShift],
  1420. {3} [essAlt],
  1421. {4} [essShift,essAlt],
  1422. {5} [essCtrl],
  1423. {6} [essCtrl,essShift],
  1424. {7} [essCtrl,essAlt],
  1425. {8} [essCtrl,essShift,essAlt]
  1426. );
  1427. procedure sunKeySquences;
  1428. { generate Sun function-key escape squences
  1429. format: CSI number z
  1430. CSI number ; modifier z
  1431. }
  1432. var st, zt : string[15];
  1433. AnsiChar : byte;
  1434. scan : byte;
  1435. shift:TEnhancedShiftState;
  1436. i,n : dword;
  1437. kb : PKeyByte;
  1438. begin
  1439. AnsiChar:=0;
  1440. for n:=0 to 7 do
  1441. begin
  1442. kb:=cKeyScanCode[n];
  1443. shift:=cKeyShift[n];
  1444. zt:=cSunKeyEnd[n];
  1445. for i:=0 to 23-5 do
  1446. begin
  1447. str(cSunKey[i],st);
  1448. st:=#27'['+st+zt;
  1449. scan:=kb^[i];
  1450. DoAddSequence(st,AnsiChar,scan,shift);
  1451. end;
  1452. end;
  1453. end;
  1454. procedure PushUnicodeKey (k: TEnhancedKeyEvent; UnicodeCodePoint : longint; ReplacementAsciiChar:AnsiChar);
  1455. begin
  1456. if UnicodeCodePoint<=$FFFF then
  1457. begin
  1458. { Code point is in the Basic Multilingual Plane (BMP)
  1459. -> encode as single WideChar }
  1460. k.UnicodeChar:=WideChar(UnicodeCodePoint);
  1461. if UnicodeCodePoint<=127 then
  1462. k.AsciiChar:=Chr(UnicodeCodePoint)
  1463. else
  1464. k.AsciiChar:=ReplacementAsciiChar;
  1465. PushKey(k);
  1466. end
  1467. else if UnicodeCodePoint<=$10FFFF then
  1468. begin
  1469. { Code point from the Supplementary Planes (U+010000..U+10FFFF)
  1470. -> encode as a surrogate pair of WideChars (as in UTF-16) }
  1471. k.UnicodeChar:=WideChar(((UnicodeCodePoint-$10000) shr 10)+$D800);
  1472. k.AsciiChar:=ReplacementAsciiChar;
  1473. PushKey(k);
  1474. k.UnicodeChar:=WideChar(((UnicodeCodePoint-$10000) and %1111111111)+$DC00);
  1475. PushKey(k);
  1476. end;
  1477. end;
  1478. const {lookup tables: nKey, modifier -> ScanCode, KeyChar }
  1479. cAltAscii : array [0..127] of AnsiChar = (
  1480. #$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,
  1481. #$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,
  1482. #$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,
  1483. #$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,
  1484. #$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,
  1485. #$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,
  1486. #$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,
  1487. #$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00);
  1488. cCtrlAscii : array [0..127] of AnsiChar = (
  1489. #$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$08,#$00,#$00,#$00,#$00,#$0a,#$00,#$00,
  1490. #$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$1b,#$00,#$00,#$00,#$00,
  1491. #$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,
  1492. #$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,
  1493. #$00,#$01,#$02,#$03,#$04,#$05,#$06,#$00,#$00,#$09,#$0a,#$0b,#$0c,#$0d,#$0e,#$0f,
  1494. #$10,#$11,#$12,#$13,#$14,#$15,#$16,#$17,#$18,#$19,#$1a,#$1b,#$1c,#$1d,#$1e,#$1f,
  1495. #$00,#$01,#$02,#$03,#$04,#$05,#$06,#$07,#$08,#$09,#$0a,#$0b,#$0c,#$0d,#$0e,#$0f,
  1496. #$10,#$11,#$12,#$13,#$14,#$15,#$16,#$17,#$18,#$19,#$1a,#$1b,#$1c,#$1d,#$1e,#$7f);
  1497. cShiftAscii : array [0..127] of AnsiChar = (
  1498. #$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$08,#$00,#$00,#$00,#$00,#$0d,#$00,#$00,
  1499. #$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$00,#$1b,#$00,#$00,#$00,#$00,
  1500. #$20,#$21,#$22,#$23,#$24,#$25,#$26,#$00,#$28,#$29,#$2a,#$2b,#$00,#$2d,#$2e,#$2f,
  1501. #$30,#$31,#$32,#$33,#$34,#$35,#$36,#$37,#$38,#$39,#$3a,#$00,#$3c,#$00,#$3e,#$3f,
  1502. #$40,#$41,#$42,#$43,#$44,#$45,#$46,#$47,#$48,#$49,#$4a,#$4b,#$4c,#$4d,#$4e,#$4f,
  1503. #$50,#$51,#$52,#$53,#$54,#$55,#$56,#$57,#$58,#$59,#$5a,#$00,#$00,#$00,#$5e,#$5f,
  1504. #$00,#$61,#$62,#$63,#$64,#$65,#$66,#$67,#$68,#$69,#$6a,#$6b,#$6c,#$6d,#$6e,#$6f,
  1505. #$70,#$71,#$72,#$73,#$74,#$75,#$76,#$77,#$78,#$79,#$7a,#$7b,#$7c,#$7d,#$7e,#$08);
  1506. cAscii : array [0..127] of AnsiChar = (
  1507. #$00,#$00,#$00,#$00,#$04,#$00,#$00,#$00,#$08,#$09,#$00,#$00,#$00,#$0d,#$00,#$00,
  1508. #$00,#$00,#$00,#$00,#$00,#$15,#$00,#$00,#$00,#$00,#$00,#$1b,#$00,#$00,#$00,#$00,
  1509. #$20,#$00,#$00,#$00,#$00,#$00,#$00,#$27,#$00,#$00,#$2a,#$2b,#$2c,#$2d,#$2e,#$2f,
  1510. #$30,#$31,#$32,#$33,#$34,#$35,#$36,#$37,#$38,#$39,#$00,#$3b,#$3c,#$3d,#$00,#$00,
  1511. #$00,#$41,#$42,#$43,#$44,#$45,#$46,#$47,#$48,#$49,#$4a,#$4b,#$4c,#$4d,#$4e,#$4f,
  1512. #$50,#$51,#$52,#$53,#$54,#$55,#$56,#$57,#$58,#$59,#$5a,#$5b,#$5c,#$5d,#$00,#$00,
  1513. #$60,#$61,#$62,#$63,#$64,#$65,#$66,#$67,#$68,#$69,#$6a,#$6b,#$6c,#$6d,#$6e,#$6f,
  1514. #$70,#$71,#$72,#$73,#$74,#$75,#$76,#$77,#$78,#$79,#$7a,#$00,#$00,#$00,#$00,#$08);
  1515. cScanValue : array [0..127] of byte = (
  1516. $fe, $00, $00, $00, $20, $00, $00, $00, $0e, $0f, $00, $00, $00, $1c, $00, $00,
  1517. $00, $00, $00, $00, $00, $16, $00, $00, $00, $00, $00, $01, $00, $00, $00, $00,
  1518. $39, $00, $00, $00, $00, $00, $00, $28, $00, $00, $37, $0d, $33, $0c, $34, $35,
  1519. $0b, $02, $03, $04, $05, $06, $07, $08, $09, $0a, $00, $27, $33, $0d, $00, $00,
  1520. $00, $1e, $30, $2e, $20, $12, $21, $22, $23, $17, $24, $25, $26, $32, $31, $18,
  1521. $19, $10, $13, $1f, $14, $16, $2f, $11, $2d, $15, $2c, $1a, $2b, $1b, $00, $00,
  1522. $2b, $1e, $30, $2e, $20, $12, $21, $22, $23, $17, $24, $25, $26, $32, $31, $18,
  1523. $19, $10, $13, $1f, $14, $16, $2f, $11, $2d, $15, $2c, $00, $00, $00, $00, $0e);
  1524. cShiftScanValue : array [0..127] of byte = (
  1525. $fe, $00, $00, $00, $00, $00, $00, $00, $0e, $0f, $00, $00, $00, $1c, $00, $00,
  1526. $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $01, $00, $00, $00, $00,
  1527. $39, $02, $28, $04, $05, $06, $08, $00, $0a, $0b, $09, $0d, $00, $0c, $53, $35,
  1528. $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $27, $00, $33, $00, $34, $35,
  1529. $03, $1e, $30, $2e, $20, $12, $21, $22, $23, $17, $24, $25, $26, $32, $31, $18,
  1530. $19, $10, $13, $1f, $14, $16, $2f, $11, $2d, $15, $2c, $00, $00, $00, $07, $0c,
  1531. $00, $1e, $30, $2e, $20, $12, $21, $22, $23, $17, $24, $25, $26, $32, $31, $18,
  1532. $19, $10, $13, $1f, $14, $16, $2f, $11, $2d, $15, $2c, $1a, $2b, $1b, $29, $0e);
  1533. cAltScanValue : array [0..127] of byte = (
  1534. $fe, $00, $00, $00, $00, $00, $00, $00, $0e, $00, $00, $00, $00, $1c, $00, $00,
  1535. $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $01, $00, $00, $00, $00,
  1536. $39, $78, $28, $7a, $7b, $7c, $7e, $28, $80, $81, $7f, $83, $33, $82, $34, $35,
  1537. $81, $78, $79, $7a, $7b, $7c, $7d, $7e, $7f, $80, $27, $27, $33, $83, $34, $35,
  1538. $79, $1e, $30, $2e, $20, $12, $21, $00, $00, $17, $24, $25, $26, $32, $31, $18,
  1539. $19, $10, $13, $1f, $14, $16, $2f, $11, $2d, $15, $2c, $1a, $2b, $1b, $7d, $82,
  1540. $2b, $1e, $30, $2e, $20, $12, $21, $22, $23, $17, $24, $25, $26, $32, $31, $18,
  1541. $19, $10, $13, $1f, $14, $16, $2f, $11, $2d, $15, $2c, $1a, $2b, $1b, $29, $0e);
  1542. cCtrlScanValue : array [0..127] of byte = (
  1543. $fe, $00, $00, $00, $00, $00, $00, $00, $0e, $94, $00, $00, $00, $1c, $00, $00,
  1544. $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $01, $00, $00, $00, $00,
  1545. $39, $02, $28, $04, $05, $06, $08, $28, $0a, $0b, $96, $0d, $33, $0c, $34, $35,
  1546. $0b, $02, $03, $04, $05, $06, $07, $08, $09, $0a, $27, $27, $33, $0d, $34, $35,
  1547. $03, $1e, $30, $2e, $20, $12, $21, $00, $00, $17, $24, $25, $26, $32, $31, $18,
  1548. $19, $10, $13, $1f, $14, $16, $2f, $11, $2d, $15, $2c, $1a, $2b, $1b, $07, $0c,
  1549. $29, $1e, $30, $2e, $20, $12, $21, $22, $23, $17, $24, $25, $26, $32, $31, $18,
  1550. $19, $10, $13, $1f, $14, $16, $2f, $11, $2d, $15, $2c, $1a, $2b, $1b, $29, $0e);
  1551. procedure BuildKeyEvent(modifier:dword; nKey, nShortCutKey :dword);
  1552. var k : TEnhancedKeyEvent;
  1553. SState: TEnhancedShiftState;
  1554. ScanValue : byte;
  1555. Key : dword;
  1556. begin
  1557. k:=NilEnhancedKeyEvent;
  1558. AltPrefix := 0;
  1559. ShiftPrefix := 0;
  1560. CtrlPrefix := 0;
  1561. { Shift states}
  1562. if modifier = 0 then modifier:=1;
  1563. modifier:=modifier-1;
  1564. SState:=[];
  1565. if (modifier and 1)>0 then SState:=SState+[essShift];
  1566. if (modifier and 2)>0 then SState:=SState+[essAlt];
  1567. if (modifier and 4)>0 then SState:=SState+[essCtrl];
  1568. k.ShiftState:=SState;
  1569. Key:=nShortCutKey;
  1570. if Key < 128 then
  1571. begin
  1572. if essAlt in SState then
  1573. k.AsciiChar:=cAltAscii[Key]
  1574. else if essCtrl in SState then
  1575. k.AsciiChar:=cCtrlAscii[Key]
  1576. else if essShift in SState then
  1577. k.AsciiChar:=cShiftAscii[Key]
  1578. else
  1579. k.AsciiChar:=cAscii[Key];
  1580. if essAlt in SState then
  1581. ScanValue :=cAltScanValue[Key]
  1582. else if essCtrl in SState then
  1583. ScanValue :=cCtrlScanValue[Key]
  1584. else if essShift in SState then
  1585. ScanValue :=cShiftScanValue[Key]
  1586. else
  1587. ScanValue :=cScanValue[Key];
  1588. if essCtrl in SState then
  1589. nKey:=Ord(k.AsciiChar); { if Ctrl+key then no normal UnicodeChar. Mimic Windows keyboard driver. }
  1590. k.VirtualScanCode := (ScanValue shl 8) or Ord(k.AsciiChar);
  1591. if nKey <= $FFFF then
  1592. begin
  1593. k.UnicodeChar := WideChar(nKey);
  1594. PushKey(k);
  1595. end
  1596. else
  1597. PushUnicodeKey (k,nKey,char(k.AsciiChar));
  1598. if byte(k.AsciiChar) = 27 then PushKey(k);
  1599. end else
  1600. PushUnicodeKey (k,nKey,'?');
  1601. end;
  1602. procedure xterm_ModifyOtherKeys;
  1603. { format: CSI 27 ; modifier ; number ~ }
  1604. var ch : AnsiChar;
  1605. fdsin : tfdSet;
  1606. st: string[31];
  1607. modifier : dword;
  1608. nKey : dword;
  1609. nr : byte;
  1610. i : dword;
  1611. begin
  1612. fpFD_ZERO(fdsin);
  1613. fpFD_SET(StdInputHandle,fdsin);
  1614. nr:=0;
  1615. modifier:=1;
  1616. nKey:=0;
  1617. st:='0';
  1618. repeat
  1619. if inhead=intail then
  1620. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  1621. ch:=ttyRecvChar;
  1622. if ch in [';','~'] then
  1623. begin
  1624. if nr = 0 then val(st,modifier,i);
  1625. if nr = 1 then val(st,nKey,i);
  1626. inc(nr);
  1627. st:='0';
  1628. end else
  1629. begin
  1630. if not (ch in ['0'..'9']) then break;
  1631. st:=st+ch;
  1632. end;
  1633. until ch='~';
  1634. {test for validity}
  1635. if ch<>'~' then exit;
  1636. if nr<> 2 then exit;
  1637. BuildKeyEvent(modifier,nKey,nKey);
  1638. end;
  1639. procedure LoadDefaultSequences;
  1640. var i:cardinal;
  1641. begin
  1642. AddSpecialSequence(#27'[M',@GenMouseEvent);
  1643. AddSpecialSequence(#27'[<',@GenMouseEvent_ExtendedSGR1006);
  1644. AddSpecialSequence(#27#27'[M',@GenMouseEvent);
  1645. AddSpecialSequence(#27#27'[<',@GenMouseEvent_ExtendedSGR1006);
  1646. if not isKittyKeys then
  1647. AddSpecialSequence(#27'[27;',@xterm_ModifyOtherKeys);
  1648. {Unix backspace/delete hell... Is #127 a backspace or delete?}
  1649. if copy(fpgetenv('TERM'),1,4)='cons' then
  1650. begin
  1651. {FreeBSD is until now only terminal that uses it for delete.}
  1652. DoAddSequence(#127,0,kbDel,[]); {Delete}
  1653. DoAddSequence(#27#127,0,kbAltDel,[essAlt]); {Alt+delete}
  1654. end
  1655. else
  1656. begin
  1657. DoAddSequence(#127,8,0,[]); {Backspace}
  1658. DoAddSequence(#27#127,0,kbAltBack,[essAlt]); {Alt+backspace}
  1659. end;
  1660. { all Esc letter }
  1661. for i:=low(key_sequences) to high(key_sequences) do
  1662. with key_sequences[i] do
  1663. DoAddSequence(st,AnsiChar,scan,shift);
  1664. if detect_terminal in [trRxvt] then
  1665. begin {rxvt specific escape sequences}
  1666. for i:=low(rxvt_key_sequences) to high(rxvt_key_sequences) do
  1667. with rxvt_key_sequences[i] do
  1668. DoAddSequence(st,AnsiChar,scan,shift);
  1669. end;
  1670. sunKeySquences;
  1671. end;
  1672. function RawReadKey:AnsiChar;
  1673. var
  1674. fdsin : tfdSet;
  1675. begin
  1676. {Check Buffer first}
  1677. { if KeySend<>KeyPut then
  1678. begin
  1679. RawReadKey:=PopKey;
  1680. exit;
  1681. end;}
  1682. {Wait for Key}
  1683. if not sysKeyPressed then
  1684. begin
  1685. fpFD_ZERO (fdsin);
  1686. fpFD_SET (StdInputHandle,fdsin);
  1687. fpSelect (StdInputHandle+1,@fdsin,nil,nil,nil);
  1688. end;
  1689. RawReadKey:=ttyRecvChar;
  1690. end;
  1691. function RawReadString : shortstring;
  1692. var
  1693. ch : AnsiChar;
  1694. fdsin : tfdSet;
  1695. St : shortstring;
  1696. begin
  1697. St:=RawReadKey;
  1698. fpFD_ZERO (fdsin);
  1699. fpFD_SET (StdInputHandle,fdsin);
  1700. Repeat
  1701. if inhead=intail then
  1702. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  1703. if SysKeyPressed then
  1704. ch:=ttyRecvChar
  1705. else
  1706. ch:=#0;
  1707. if ch<>#0 then
  1708. St:=St+ch;
  1709. if length(st)=255 then break;
  1710. Until ch=#0;
  1711. RawReadString:=St;
  1712. end;
  1713. {$ifdef linux}
  1714. function ShiftState:byte;
  1715. var arg:longint;
  1716. begin
  1717. shiftstate:=0;
  1718. arg:=6;
  1719. if fpioctl(StdInputHandle,TIOCLINUX,@arg)=0 then
  1720. begin
  1721. if (arg and 8)<>0 then
  1722. shiftstate:=kbAlt;
  1723. if (arg and 4)<>0 then
  1724. inc(shiftstate,kbCtrl);
  1725. { 2 corresponds to AltGr so set both kbAlt and kbCtrl PM }
  1726. if (arg and 2)<>0 then
  1727. shiftstate:=shiftstate or (kbAlt or kbCtrl);
  1728. if (arg and 1)<>0 then
  1729. inc(shiftstate,kbShift);
  1730. end;
  1731. end;
  1732. function EnhShiftState:TEnhancedShiftState;
  1733. const
  1734. KG_SHIFT = 0;
  1735. KG_CTRL = 2;
  1736. KG_ALT = 3;
  1737. KG_ALTGR = 1;
  1738. KG_SHIFTL = 4;
  1739. KG_KANASHIFT = 4;
  1740. KG_SHIFTR = 5;
  1741. KG_CTRLL = 6;
  1742. KG_CTRLR = 7;
  1743. KG_CAPSSHIFT = 8;
  1744. var
  1745. arg: longint;
  1746. begin
  1747. EnhShiftState:=[];
  1748. arg:=6;
  1749. if fpioctl(StdInputHandle,TIOCLINUX,@arg)=0 then
  1750. begin
  1751. if (arg and (1 shl KG_ALT))<>0 then
  1752. Include(EnhShiftState,essAlt);
  1753. if (arg and (1 shl KG_CTRL))<>0 then
  1754. Include(EnhShiftState,essCtrl);
  1755. if (arg and (1 shl KG_CTRLL))<>0 then
  1756. Include(EnhShiftState,essLeftCtrl);
  1757. if (arg and (1 shl KG_CTRLR))<>0 then
  1758. Include(EnhShiftState,essRightCtrl);
  1759. if (arg and (1 shl KG_ALTGR))<>0 then
  1760. Include(EnhShiftState,essAltGr);
  1761. if (arg and (1 shl KG_SHIFT))<>0 then
  1762. Include(EnhShiftState,essShift);
  1763. if (arg and (1 shl KG_SHIFTL))<>0 then
  1764. Include(EnhShiftState,essLeftShift);
  1765. if (arg and (1 shl KG_SHIFTR))<>0 then
  1766. Include(EnhShiftState,essRightShift);
  1767. end;
  1768. end;
  1769. procedure force_linuxtty;
  1770. var s:string[15];
  1771. handle:sizeint;
  1772. thistty:shortstring;
  1773. begin
  1774. is_console:=false;
  1775. if vcs_device<>-1 then
  1776. begin
  1777. { running on a tty, find out whether locally or remotely }
  1778. thistty:=ttyname(stdinputhandle);
  1779. if (copy(thistty,1,8)<>'/dev/tty') or not (thistty[9] in ['0'..'9']) then
  1780. begin
  1781. {Running from Midnight Commander or something... Bypass it.}
  1782. str(vcs_device,s);
  1783. handle:=fpopen('/dev/tty'+s,O_RDWR);
  1784. fpioctl(stdinputhandle,TIOCNOTTY,nil);
  1785. {This will currently only work when the user is root :(}
  1786. fpioctl(handle,TIOCSCTTY,nil);
  1787. if errno<>0 then
  1788. exit;
  1789. fpclose(stdinputhandle);
  1790. fpclose(stdoutputhandle);
  1791. fpclose(stderrorhandle);
  1792. fpdup2(handle,stdinputhandle);
  1793. fpdup2(handle,stdoutputhandle);
  1794. fpdup2(handle,stderrorhandle);
  1795. fpclose(handle);
  1796. end;
  1797. is_console:=true;
  1798. end;
  1799. end;
  1800. {$endif linux}
  1801. function DetectUtf8ByteSequenceStart(ch: AnsiChar): LongInt;
  1802. begin
  1803. if Ord(ch)<128 then
  1804. DetectUtf8ByteSequenceStart:=1
  1805. else if (Ord(ch) and %11100000)=%11000000 then
  1806. DetectUtf8ByteSequenceStart:=2
  1807. else if (Ord(ch) and %11110000)=%11100000 then
  1808. DetectUtf8ByteSequenceStart:=3
  1809. else if (Ord(ch) and %11111000)=%11110000 then
  1810. DetectUtf8ByteSequenceStart:=4
  1811. else
  1812. DetectUtf8ByteSequenceStart:=0;
  1813. end;
  1814. function IsValidUtf8ContinuationByte(ch: AnsiChar): Boolean;
  1815. begin
  1816. IsValidUtf8ContinuationByte:=(Ord(ch) and %11000000)=%10000000;
  1817. end;
  1818. const cKeysUnicodePrivateBase = 57344; { unicode private area starts here}
  1819. kCapsLock = 14;
  1820. kScrollLock = 15;
  1821. kNumLock = 16;
  1822. kPrintScreen = 17;
  1823. kPauseBreak = 18;
  1824. kMenu = 19;
  1825. {Numpad keys}
  1826. kDecimal = 65;
  1827. kDivide = 66;
  1828. kMultiple = 67;
  1829. kMinuss = 68;
  1830. kPluss = 69;
  1831. kEnter = 70;
  1832. kEqual = 71;
  1833. kSeperator = 72;
  1834. kLeft = 73;
  1835. kRight = 74;
  1836. kUp = 75;
  1837. kDown = 76;
  1838. kPgUp = 77;
  1839. kPgDown = 78;
  1840. kHome = 79;
  1841. kEnd = 80;
  1842. kIns = 81;
  1843. kDel = 82;
  1844. kMiddle = 83;
  1845. {modifyers}
  1846. kShiftLeft = 97;
  1847. kCtrlLeft = 98;
  1848. kAltLeft = 99;
  1849. kSuperLeft = 100;
  1850. kShiftRight = 103;
  1851. kCtrlRight = 104;
  1852. kAltRight = 105;
  1853. kSuperRight = 106;
  1854. kAltGr = 109;
  1855. const { lookup tables for ScanCodes of numpad keys}
  1856. cKP_ScanVal : array [kDecimal..kMiddle] of byte = (
  1857. { kDecimal = 65; } $53,
  1858. { kDivide = 66; } $e0,
  1859. { kMultiple = 67; } $37,
  1860. { kMinuss = 68; } $4a,
  1861. { kPluss = 69; } $4e,
  1862. { kEnter = 70; } $e0,
  1863. { kEqual = 71; } $f0, {none}
  1864. { kSeperator = 72; } $f1, {none}
  1865. { kLeft = 73; } $4b,
  1866. { kRight = 74; } $4d,
  1867. { kUp = 75; } $48,
  1868. { kDown = 76; } $50,
  1869. { kPgUp = 77; } $49,
  1870. { kPgDown = 78; } $51,
  1871. { kHome = 79; } $47,
  1872. { kEnd = 80; } $4f,
  1873. { kIns = 81; } $52,
  1874. { kDel = 82; } $53,
  1875. { kMiddle = 83; } $4c);
  1876. const cKP_CtrlScanVal : array [kDecimal..kMiddle] of byte = (
  1877. { kDecimal = 65; } $93,
  1878. { kDivide = 66; } $95,
  1879. { kMultiple = 67; } $96,
  1880. { kMinuss = 68; } $8e,
  1881. { kPluss = 69; } $90,
  1882. { kEnter = 70; } $e0,
  1883. { kEqual = 71; } $f0, {none}
  1884. { kSeperator = 72; } $f1, {none}
  1885. { kLeft = 73; } $73,
  1886. { kRight = 74; } $74,
  1887. { kUp = 75; } $8d,
  1888. { kDown = 76; } $91,
  1889. { kPgUp = 77; } $84,
  1890. { kPgDown = 78; } $76,
  1891. { kHome = 79; } $77,
  1892. { kEnd = 80; } $75,
  1893. { kIns = 81; } $92,
  1894. { kDel = 82; } $93,
  1895. { kMiddle = 83; } $8f);
  1896. const cKP_AltScanVal : array [kDecimal..kMiddle] of byte = (
  1897. { kDecimal = 65; } $93,
  1898. { kDivide = 66; } $a4,
  1899. { kMultiple = 67; } $37,
  1900. { kMinuss = 68; } $4a,
  1901. { kPluss = 69; } $4e,
  1902. { kEnter = 70; } $a6,
  1903. { kEqual = 71; } $f0, {none}
  1904. { kSeperator = 72; } $f1, {none}
  1905. { kLeft = 73; } $9b,
  1906. { kRight = 74; } $9d,
  1907. { kUp = 75; } $98,
  1908. { kDown = 76; } $a0,
  1909. { kPgUp = 77; } $99,
  1910. { kPgDown = 78; } $a1,
  1911. { kHome = 79; } $97,
  1912. { kEnd = 80; } $9f,
  1913. { kIns = 81; } $92,
  1914. { kDel = 82; } $93,
  1915. { kMiddle = 83; } $8f);
  1916. procedure BuildKeyPadEvent(modifier:dword; nKey:dword; ch : AnsiChar);
  1917. var k : TEnhancedKeyEvent;
  1918. SState: TEnhancedShiftState;
  1919. ScanValue : byte;
  1920. begin
  1921. k:=NilEnhancedKeyEvent;
  1922. AltPrefix := 0;
  1923. ShiftPrefix := 0;
  1924. CtrlPrefix := 0;
  1925. { Shift states}
  1926. if modifier = 0 then modifier:=1;
  1927. modifier:=modifier-1;
  1928. SState:=[];
  1929. if (modifier and 1)>0 then SState:=SState+[essShift];
  1930. if (modifier and 2)>0 then SState:=SState+[essAlt];
  1931. if (modifier and 4)>0 then SState:=SState+[essCtrl];
  1932. k.ShiftState:=SState;
  1933. if nKey < 128 then
  1934. begin
  1935. if nKey = kEnter then
  1936. begin
  1937. if essAlt in SState then
  1938. ch:=#0
  1939. else if essCtrl in SState then
  1940. ch:=#$0a
  1941. else if essShift in SState then
  1942. ch:=#$0d
  1943. else
  1944. ch:=#$0d;
  1945. end;
  1946. if essAlt in SState then
  1947. k.AsciiChar:=#0
  1948. else if essCtrl in SState then
  1949. k.AsciiChar:=ch
  1950. else if essShift in SState then
  1951. k.AsciiChar:=ch
  1952. else
  1953. k.AsciiChar:=ch;
  1954. if essAlt in SState then
  1955. ScanValue :=cKP_AltScanVal[nKey]
  1956. else if essCtrl in SState then
  1957. ScanValue :=cKP_CtrlScanVal[nKey]
  1958. else if essShift in SState then
  1959. ScanValue :=cKP_ScanVal[nKey]
  1960. else
  1961. ScanValue :=cKP_ScanVal[nKey];
  1962. k.UnicodeChar := WideChar(k.AsciiChar);
  1963. k.VirtualScanCode := (ScanValue shl 8) or Ord(k.AsciiChar);
  1964. PushKey(k);
  1965. end;
  1966. end;
  1967. function RemoveShiftState(AShiftState:TEnhancedShiftState; toRemoveState,aState,toTestState:TEnhancedShiftStateElement):TEnhancedShiftState;
  1968. { remove state toRemoveState and }
  1969. { remove state aState if AShiftState does not contain toTestState }
  1970. begin
  1971. AShiftState:=AShiftState-[toRemoveState];
  1972. if not (toTestState in AShiftState) then
  1973. AShiftState:=AShiftState-[aState];
  1974. RemoveShiftState:=AShiftState;
  1975. end;
  1976. var LastShiftState, CurrentShiftState : TEnhancedShiftState;
  1977. function GetLastShiftState : byte;
  1978. { get fake shift state or current shift state for kitty keys }
  1979. var State : byte;
  1980. begin
  1981. State:=0;
  1982. if isKittyKeys then
  1983. begin
  1984. LastShiftState:=CurrentShiftState;
  1985. if essLeftShift in LastShiftState then
  1986. inc(state,kbLeftShift);
  1987. if essRightShift in LastShiftState then
  1988. inc(state,kbRightShift);
  1989. if (essShift in LastShiftState) and (not ((essRightShift in LastShiftState) or (essLeftShift in LastShiftState))) then
  1990. inc(state,kbShift); {this for super rare case when shift state key press was not recived (maybe that is impossible)}
  1991. end else
  1992. if essShift in LastShiftState then
  1993. inc(state,kbShift);
  1994. if essCtrl in LastShiftState then
  1995. inc(state,kbCtrl);
  1996. if essAlt in LastShiftState then
  1997. inc(state,kbAlt);
  1998. GetLastShiftState:=State;
  1999. end;
  2000. procedure UpdateCurrentShiftState(nKey:longint; kbDown:byte);
  2001. begin
  2002. {current shift state changes}
  2003. if kbDown <3 then
  2004. begin {state key down}
  2005. case nKey of
  2006. kShiftLeft : CurrentShiftState:=CurrentShiftState +[essShift,essLeftShift];
  2007. kShiftRight : CurrentShiftState:=CurrentShiftState +[essShift,essRightShift];
  2008. kCtrlLeft : CurrentShiftState:=CurrentShiftState +[essCtrl,essLeftCtrl];
  2009. kCtrlRight : CurrentShiftState:=CurrentShiftState +[essCtrl,essRightCtrl];
  2010. kAltRight : CurrentShiftState:=CurrentShiftState +[essAlt,essRightAlt];
  2011. kAltLeft : CurrentShiftState:=CurrentShiftState +[essAlt,essLeftAlt];
  2012. kAltGr : CurrentShiftState:=CurrentShiftState +[essAltGr];
  2013. end;
  2014. end else
  2015. begin {state key up}
  2016. case nKey of
  2017. kShiftLeft : CurrentShiftState:=RemoveShiftState(CurrentShiftState,essLeftShift,essShift,essRightShift);
  2018. kShiftRight : CurrentShiftState:=RemoveShiftState(CurrentShiftState,essRightShift,essShift,essLeftShift);
  2019. kCtrlLeft : CurrentShiftState:=RemoveShiftState(CurrentShiftState,essLeftCtrl,essCtrl,essRightCtrl);
  2020. kCtrlRight : CurrentShiftState:=RemoveShiftState(CurrentShiftState,essRightCtrl,essCtrl,essLeftCtrl);
  2021. kAltRight : CurrentShiftState:=RemoveShiftState(CurrentShiftState,essRightAlt,essAlt,essLeftAlt);
  2022. kAltLeft : CurrentShiftState:=RemoveShiftState(CurrentShiftState,essLeftAlt,essAlt,essRightAlt);
  2023. kAltGr : CurrentShiftState:=CurrentShiftState -[essAltGr];
  2024. end;
  2025. end;
  2026. end;
  2027. procedure UpdateShiftStateWithModifier(modifier:longint);
  2028. { Sanity double check. In case if there is no generated shift state key release (shortcut key intercepted by OS or terminal). }
  2029. { Make sure on key press there is correct current shift state }
  2030. begin
  2031. { Shift states}
  2032. if modifier = 0 then modifier:=1;
  2033. modifier:=modifier-1;
  2034. if (modifier and 1)>0 then
  2035. begin if not (essShift in CurrentShiftState) then CurrentShiftState:=CurrentShiftState+[essShift];
  2036. end else if (essShift in CurrentShiftState) then CurrentShiftState:=CurrentShiftState-[essLeftShift,essShift,essRightShift];
  2037. if (modifier and 2)>0 then
  2038. begin if not (essAlt in CurrentShiftState) then CurrentShiftState:=CurrentShiftState+[essAlt];
  2039. end else if (essAlt in CurrentShiftState) then CurrentShiftState:=CurrentShiftState-[essLeftAlt,essAlt,essRightAlt];
  2040. if (modifier and 4)>0 then
  2041. begin if not (essCtrl in CurrentShiftState) then CurrentShiftState:=CurrentShiftState+[essCtrl];
  2042. end else if (essCtrl in CurrentShiftState) then CurrentShiftState:=CurrentShiftState-[essRightCtrl,essCtrl,essLeftCtrl];
  2043. end;
  2044. function ReadKey:TEnhancedKeyEvent;
  2045. const
  2046. ReplacementAsciiChar='?';
  2047. var
  2048. store : array [0..31] of AnsiChar;
  2049. arrayind : byte;
  2050. SState: TEnhancedShiftState;
  2051. procedure DecodeAndPushWin32Key(const store: array of AnsiChar; arrayind: byte);
  2052. function VKToScanCode(vk: Word): Byte;
  2053. begin
  2054. case vk of
  2055. // Standard keys
  2056. $41..$5A : VKToScanCode := cScanValue[vk]; // 'A'..'Z'
  2057. $30..$39 : VKToScanCode := cScanValue[vk]; // '0'..'9'
  2058. $08: VKToScanCode := kbBack;
  2059. $09: VKToScanCode := kbTab;
  2060. $0D: VKToScanCode := kbEnter;
  2061. $1B: VKToScanCode := kbEsc;
  2062. $20: VKToScanCode := kbSpaceBar;
  2063. // Function keys
  2064. $70..$79: VKToScanCode := vk - $70 + kbF1; // F1-F10
  2065. $7A..$7B: VKToScanCode := vk - $7A + kbF11; // F11-F12
  2066. // Navigation keys
  2067. $2D: VKToScanCode := kbIns;
  2068. $2E: VKToScanCode := kbDel;
  2069. $24: VKToScanCode := kbHome;
  2070. $23: VKToScanCode := kbEnd;
  2071. $21: VKToScanCode := kbPgUp;
  2072. $22: VKToScanCode := kbPgDn;
  2073. $26: VKToScanCode := kbUp;
  2074. $28: VKToScanCode := kbDown;
  2075. $25: VKToScanCode := kbLeft;
  2076. $27: VKToScanCode := kbRight;
  2077. // Modifier keys (scancodes for L/R versions)
  2078. $10: VKToScanCode := $2A; // VK_SHIFT -> Left shift
  2079. $11: VKToScanCode := $1D; // VK_CONTROL -> Left control
  2080. $12: VKToScanCode := $38; // VK_MENU -> Left alt
  2081. // Lock keys
  2082. $14: VKToScanCode := $3A; // VK_CAPITAL
  2083. $90: VKToScanCode := $45; // VK_NUMLOCK
  2084. $91: VKToScanCode := $46; // VK_SCROLL
  2085. // OEM Keys
  2086. $BA: VKToScanCode := $27; // VK_OEM_1 (;)
  2087. $BB: VKToScanCode := $0D; // VK_OEM_PLUS (=)
  2088. $BC: VKToScanCode := $33; // VK_OEM_COMMA (,)
  2089. $BD: VKToScanCode := $0C; // VK_OEM_MINUS (-)
  2090. $BE: VKToScanCode := $34; // VK_OEM_PERIOD (.)
  2091. $BF: VKToScanCode := $35; // VK_OEM_2 (/)
  2092. $C0: VKToScanCode := $29; // VK_OEM_3 (`)
  2093. $DB: VKToScanCode := $1A; // VK_OEM_4 ([)
  2094. $DC: VKToScanCode := $2B; // VK_OEM_5 (\)
  2095. $DD: VKToScanCode := $1B; // VK_OEM_6 (])
  2096. $DE: VKToScanCode := $28; // VK_OEM_7 (')
  2097. else
  2098. VKToScanCode := 0;
  2099. end;
  2100. end;
  2101. var
  2102. params: array[0..5] of LongInt; // Vk, Sc, Uc, Kd, Cs, Rc
  2103. i, p_idx, code: Integer;
  2104. st: string;
  2105. ch: AnsiChar;
  2106. ScanCode: Byte;
  2107. k: TEnhancedKeyEvent;
  2108. begin
  2109. // 1. Parse the parameters: Vk;Sc;Uc;Kd;Cs;Rc
  2110. for i := 0 to 5 do params[i] := 0; // Clear params
  2111. params[5] := 1; // Default repeat count is 1
  2112. p_idx := 0;
  2113. st := '';
  2114. // Start from after the CSI: ^[[
  2115. for i := 2 to arrayind - 2 do
  2116. begin
  2117. ch := store[i];
  2118. if ch = ';' then
  2119. begin
  2120. if st <> '' then Val(st, params[p_idx], code);
  2121. st := '';
  2122. Inc(p_idx);
  2123. if p_idx > 5 then Break;
  2124. end
  2125. else if ch in ['0'..'9'] then
  2126. st := st + ch;
  2127. end;
  2128. // Last parameter
  2129. if (p_idx <= 5) and (st <> '') then
  2130. Val(st, params[p_idx], code);
  2131. // For non-printable command keys, we must ignore any character code provided
  2132. // by the terminal (like #127 for Del) and force it to 0. This ensures the
  2133. // application interprets the key event as a command (via its scancode)
  2134. // rather than as a character to be printed.
  2135. case params[0] of // Check Virtual Key Code (wVirtualKeyCode)
  2136. // Function keys F1-F12
  2137. $70..$7B,
  2138. // Arrow keys (Left, Up, Right, Down)
  2139. $25..$28,
  2140. // Navigation keys (PgUp, PgDn, End, Home, Ins, Del)
  2141. $21..$24, $2D, $2E:
  2142. params[2] := 0; // Force UnicodeChar to be 0
  2143. end;
  2144. // 2. Process only key down and repeat events (param[3] must be non-zero)
  2145. if params[3] = 0 then exit; // Ignore key up events completely for now.
  2146. // The sequence is considered "handled".
  2147. // 3. Create a new key event
  2148. k := NilEnhancedKeyEvent;
  2149. // 4. Map ControlKeyState (Cs) to ShiftState
  2150. if (params[4] and SHIFT_PRESSED) <> 0 then Include(k.ShiftState, essShift);
  2151. if (params[4] and LEFT_CTRL_PRESSED) <> 0 then Include(k.ShiftState, essLeftCtrl);
  2152. if (params[4] and RIGHT_CTRL_PRESSED) <> 0 then Include(k.ShiftState, essRightCtrl);
  2153. if (params[4] and (LEFT_CTRL_PRESSED or RIGHT_CTRL_PRESSED)) <> 0 then Include(k.ShiftState, essCtrl);
  2154. if (params[4] and LEFT_ALT_PRESSED) <> 0 then Include(k.ShiftState, essLeftAlt);
  2155. if (params[4] and RIGHT_ALT_PRESSED) <> 0 then Include(k.ShiftState, essRightAlt);
  2156. if (params[4] and (LEFT_ALT_PRESSED or RIGHT_ALT_PRESSED)) <> 0 then Include(k.ShiftState, essAlt);
  2157. // 5. Map Uc, Sc, and Vk
  2158. k.UnicodeChar := WideChar(params[2]);
  2159. if params[2] <= 127 then
  2160. k.AsciiChar := AnsiChar(params[2])
  2161. else
  2162. k.AsciiChar := '?';
  2163. ScanCode := params[1]; // wVirtualScanCode
  2164. if ScanCode = 0 then
  2165. ScanCode := VKToScanCode(params[0]); // wVirtualKeyCode
  2166. // If we have a char but no special scancode, use the char's scancode
  2167. if (ScanCode = 0) and (Ord(k.AsciiChar) > 0) and (Ord(k.AsciiChar) < 128) then
  2168. ScanCode := cScanValue[Ord(k.AsciiChar)];
  2169. k.VirtualScanCode := (ScanCode shl 8) or Ord(k.AsciiChar);
  2170. PushKey(k);
  2171. end;
  2172. procedure DecodeKittyKey(var k :TEnhancedKeyEvent; var NPT : PTreeElement);
  2173. var i : dword;
  2174. wc: wideChar;
  2175. ch: AnsiChar;
  2176. st:string[15];
  2177. escStr:string[15];
  2178. asIs:string[15];
  2179. unicodeCodePoint : longint;
  2180. z : longint;
  2181. NNPT : PTreeElement;
  2182. enh: array[0..11] of longint;
  2183. iE : dword;
  2184. kbDown : byte;
  2185. nKey : longint;
  2186. modifier: longint;
  2187. shortCutKey: LongInt;
  2188. begin {
  2189. if arrayind>0 then
  2190. for i:= 0 to arrayind-1 do
  2191. begin
  2192. write(hexstr(byte(store[i]),2),' ');
  2193. end;}
  2194. iE:=0;
  2195. fillchar(enh,sizeof(enh),$ff);
  2196. enh[3]:=1;
  2197. enh[4]:=1;
  2198. st:='';
  2199. asIs:='';
  2200. if arrayind > 2 then
  2201. for i:= 2 to arrayind-1 do
  2202. begin
  2203. ch:=store[i];
  2204. asIs:=asIs+ch;
  2205. if ch in ['0'..'9'] then st:=st+ch else
  2206. begin
  2207. if length(st)>0 then
  2208. begin
  2209. val(st,unicodeCodePoint,z);
  2210. enh[iE]:=unicodeCodePoint;
  2211. end;
  2212. st:='';
  2213. if ch =';' then begin iE:=((iE div 3)+1)*3; end else
  2214. if ch =':' then inc(iE);
  2215. if not (ch in [';',':']) then break;
  2216. end;
  2217. end;
  2218. nKey:=enh[0];
  2219. modifier:=((enh[3]-1)and 7)+1;
  2220. kbDown:=enh[4];
  2221. unicodeCodePoint:=enh[6];
  2222. if unicodeCodePoint < 0 then
  2223. unicodeCodePoint:=enh[0];
  2224. enh[5]:=modifier;
  2225. escStr:='';
  2226. ch:=store[arrayind-1];
  2227. if (ch='E') and (enh[6]>0) then ch:='u'; {this is one exception (numlock off, Shift+Center (numpad 5))}
  2228. case ch of
  2229. '~': begin
  2230. if kbDown<3 then
  2231. begin
  2232. str(nKey,st);
  2233. escStr:='_['+st;
  2234. if modifier>1 then
  2235. begin
  2236. str(modifier,st);
  2237. escStr:=escStr+';'+st;
  2238. end;
  2239. escStr:=escStr+ch;
  2240. for i:=2 to length(escStr) do
  2241. begin
  2242. ch:=escStr[i];
  2243. NPT:=FindChild(ord(ch),NPT);
  2244. if not assigned(NPT) then
  2245. begin
  2246. break;
  2247. end;
  2248. end;
  2249. end else NPT:=nil;
  2250. end;
  2251. 'A','B','C','D','E','F','H','P','Q','S':
  2252. begin
  2253. if kbDown<3 then
  2254. begin
  2255. escStr:='_[';
  2256. if modifier>1 then
  2257. begin
  2258. str(modifier,st);
  2259. escStr:=escStr+'1;'+st;
  2260. end else
  2261. begin
  2262. if ch in ['P','Q','S'] then { F1, F2, F4 }
  2263. escStr:='_O';
  2264. end;
  2265. escStr:=escStr+ch;
  2266. for i:=2 to length(escStr) do
  2267. begin
  2268. ch:=escStr[i];
  2269. NPT:=FindChild(ord(ch),NPT);
  2270. if not assigned(NPT) then
  2271. begin
  2272. break;
  2273. end;
  2274. end;
  2275. end else NPT:=nil;
  2276. end;
  2277. otherwise
  2278. NPT:=nil;
  2279. end;
  2280. UpdateShiftStateWithModifier(modifier);
  2281. if kbDown =3 then arrayind:=0; {release keys are ignored}
  2282. if not assigned(NPT) and (ch='u') then
  2283. begin
  2284. if (unicodeCodePoint >=57344) and (unicodeCodePoint<=63743) then
  2285. begin
  2286. {function keys have been pressed}
  2287. arrayind:=0;
  2288. nKey:=unicodeCodePoint-cKeysUnicodePrivateBase;
  2289. if (nKey >=kShiftLeft) and (nKey<=kAltGr) then
  2290. UpdateCurrentShiftState(nKey,kbDown);
  2291. if (nKey < 128) and (kbDown <3) then
  2292. begin
  2293. if nKey = 60 then nKey:= kMiddle; {KP_5 -> KP_BEGIN}
  2294. if nKey in [kDecimal..kMiddle] then
  2295. begin
  2296. BuildKeyPadEvent(modifier,nKey,#0);
  2297. exit;
  2298. end else exit;
  2299. end else
  2300. {ignore...}
  2301. exit;
  2302. end;
  2303. if kbDown =3 then exit; {key up... ignored}
  2304. if (modifier > 2) and (enh[2]>=0) and (unicodeCodePoint>=0) then
  2305. begin
  2306. { ctrl, alt, shift + key combinations generate shortcut keys not tide to localized keyboard layout }
  2307. if (enh[1]>=0) then
  2308. nKey:=enh[1];
  2309. BuildKeyEvent(modifier,nKey,enh[2]);
  2310. end else
  2311. if unicodeCodePoint>-1 then
  2312. begin
  2313. nKey:=unicodeCodePoint;
  2314. if (enh[1]>=0) then
  2315. nKey:=enh[1];
  2316. shortCutKey := enh[2];
  2317. if shortCutKey < 0 then
  2318. shortCutKey := nKey;
  2319. BuildKeyEvent(modifier, nKey, shortCutKey);
  2320. end;
  2321. arrayind:=0;
  2322. end;
  2323. end;
  2324. procedure RestoreArray;
  2325. var
  2326. i : byte;
  2327. k : TEnhancedKeyEvent;
  2328. begin
  2329. if arrayind>0 then
  2330. for i:=0 to arrayind-1 do
  2331. begin
  2332. k := NilEnhancedKeyEvent;
  2333. k.AsciiChar := store[i];
  2334. k.VirtualScanCode := Ord(k.AsciiChar);
  2335. k.ShiftState := SState;
  2336. { todo: how to set the other fields? }
  2337. PushKey(k);
  2338. end;
  2339. end;
  2340. function ReadUtf8(ch: AnsiChar): LongInt;
  2341. const
  2342. ErrorCharacter = $FFFD; { U+FFFD = REPLACEMENT CHARACTER }
  2343. var
  2344. CodePoint: LongInt;
  2345. begin
  2346. ReadUtf8:=ErrorCharacter;
  2347. case DetectUtf8ByteSequenceStart(ch) of
  2348. 1: ReadUtf8:=Ord(ch);
  2349. 2:begin
  2350. CodePoint:=(Ord(ch) and %00011111) shl 6;
  2351. ch:=ttyRecvChar;
  2352. if not IsValidUtf8ContinuationByte(ch) then
  2353. exit;
  2354. CodePoint:=(Ord(ch) and %00111111) or CodePoint;
  2355. if (CodePoint>=$80) and (CodePoint<=$7FF) then
  2356. ReadUtf8:=CodePoint;
  2357. end;
  2358. 3:begin
  2359. CodePoint:=(Ord(ch) and %00001111) shl 12;
  2360. ch:=ttyRecvChar;
  2361. if not IsValidUtf8ContinuationByte(ch) then
  2362. exit;
  2363. CodePoint:=((Ord(ch) and %00111111) shl 6) or CodePoint;
  2364. ch:=ttyRecvChar;
  2365. if not IsValidUtf8ContinuationByte(ch) then
  2366. exit;
  2367. CodePoint:=(Ord(ch) and %00111111) or CodePoint;
  2368. if ((CodePoint>=$800) and (CodePoint<=$D7FF)) or
  2369. ((CodePoint>=$E000) and (CodePoint<=$FFFF)) then
  2370. ReadUtf8:=CodePoint;
  2371. end;
  2372. 4:begin
  2373. CodePoint:=(Ord(ch) and %00000111) shl 18;
  2374. ch:=ttyRecvChar;
  2375. if not IsValidUtf8ContinuationByte(ch) then
  2376. exit;
  2377. CodePoint:=((Ord(ch) and %00111111) shl 12) or CodePoint;
  2378. ch:=ttyRecvChar;
  2379. if not IsValidUtf8ContinuationByte(ch) then
  2380. exit;
  2381. CodePoint:=((Ord(ch) and %00111111) shl 6) or CodePoint;
  2382. ch:=ttyRecvChar;
  2383. if not IsValidUtf8ContinuationByte(ch) then
  2384. exit;
  2385. CodePoint:=(Ord(ch) and %00111111) or CodePoint;
  2386. if (CodePoint>=$10000) and (CodePoint<=$10FFFF) then
  2387. ReadUtf8:=CodePoint;
  2388. end;
  2389. end;
  2390. end;
  2391. var
  2392. ch : AnsiChar;
  2393. fdsin : tfdSet;
  2394. NPT,NNPT : PTreeElement;
  2395. RootNPT : PTreeElement;
  2396. FoundNPT : PTreeElement;
  2397. k: TEnhancedKeyEvent;
  2398. UnicodeCodePoint: LongInt;
  2399. i : dword;
  2400. // Variables for Alt+UTF8 sequence handling
  2401. ch1: AnsiChar;
  2402. utf8_bytes_to_read, loop_idx: Integer;
  2403. full_sequence_ok: boolean;
  2404. begin
  2405. {Check Buffer first}
  2406. if KeySend<>KeyPut then
  2407. begin
  2408. ReadKey:=PopKey;
  2409. exit;
  2410. end;
  2411. {Wait for Key}
  2412. if not sysKeyPressed then
  2413. begin
  2414. fpFD_ZERO (fdsin);
  2415. fpFD_SET (StdInputHandle,fdsin);
  2416. fpSelect (StdInputHandle+1,@fdsin,nil,nil,nil);
  2417. end;
  2418. k:=NilEnhancedKeyEvent;
  2419. {$ifdef linux}
  2420. if is_console then
  2421. SState:=EnhShiftState
  2422. else
  2423. {$endif}
  2424. SState:=[];
  2425. k.ShiftState:=SState;
  2426. ch:=ttyRecvChar;
  2427. k.AsciiChar:=ch;
  2428. NPT:=RootTree[ch];
  2429. if not assigned(NPT) then
  2430. begin
  2431. if Utf8KeyboardInputEnabled then
  2432. begin
  2433. UnicodeCodePoint:=ReadUtf8(ch);
  2434. PushUnicodeKey(k,UnicodeCodePoint,ReplacementAsciiChar);
  2435. end
  2436. else
  2437. PushKey(k);
  2438. end
  2439. else
  2440. begin
  2441. fpFD_ZERO(fdsin);
  2442. fpFD_SET(StdInputHandle,fdsin);
  2443. store[0]:=ch;
  2444. arrayind:=1;
  2445. RootNPT:=NPT;
  2446. FoundNPT:=nil;
  2447. if NPT^.CanBeTerminal then FoundNPT:=NPT;
  2448. while {assigned(NPT) and} syskeypressed do
  2449. begin
  2450. if inhead=intail then
  2451. fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
  2452. ch:=ttyRecvChar;
  2453. if (ch=#27) and double_esc_hack_enabled then
  2454. begin
  2455. {This is the same hack as in findsequence; see findsequence for
  2456. explanation.}
  2457. ch:=ttyrecvchar;
  2458. {Alt+O cannot be used in this situation, it can be a function key.}
  2459. if not(ch in ['a'..'z','A'..'N','P'..'Z','0'..'9','-','+','_','=']) then
  2460. begin
  2461. PutBackIntoInBuf(ch);
  2462. ch:=#27;
  2463. end
  2464. else
  2465. begin
  2466. write(#27'[?1036l');
  2467. double_esc_hack_enabled:=false;
  2468. end;
  2469. end;
  2470. {save char later use }
  2471. store[arrayind]:=ch;
  2472. inc(arrayind);
  2473. // If we detect a pattern for a complex parameterized sequence (ESC [ <digit>),
  2474. // which is common for win32-input-mode and Kitty, we switch from a non-blocking
  2475. // to a blocking read. This ensures we read the entire sequence even if it
  2476. // arrives in chunks with micro-delays.
  2477. if
  2478. (arrayind = 4) and
  2479. (store[0]=#27) and
  2480. (store[1]='[') and
  2481. (store[2] in ['0'..'9']) and
  2482. ((store[3] in ['0'..'9']) or (store[3] = ';')) and
  2483. (not ((store[2] = '1') and (store[3] = ';'))) // skip for legacy seqs like ESC[1;something
  2484. then
  2485. begin
  2486. // Enter blocking read loop with a safety break
  2487. while (arrayind < 31) do
  2488. begin
  2489. // This is a blocking read, it will wait for the next character
  2490. ch := ttyRecvChar;
  2491. store[arrayind] := ch;
  2492. inc(arrayind);
  2493. // Check for known terminators for win32, kitty, xterm, and other CSI sequences.
  2494. if (ch = '_') or (ch = 'u') or (ch = '~') or (ch in ['A'..'Z']) or (ch in ['a'..'z']) then
  2495. break; // Exit this inner blocking loop
  2496. end;
  2497. break; // We have the full sequence, so exit the outer `while syskeypressed` loop
  2498. end;
  2499. if arrayind >= 31 then break;
  2500. {check tree for maching sequence}
  2501. if assigned(NPT) then
  2502. NNPT:=FindChild(ord(ch),NPT);
  2503. if assigned(NNPT) then
  2504. begin
  2505. NPT:=NNPT;
  2506. if NPT^.CanBeTerminal then
  2507. begin
  2508. FoundNPT:=NPT;
  2509. if assigned(NPT^.SpecialHandler) then
  2510. break;
  2511. end;
  2512. End
  2513. else
  2514. NPT:=nil; {not found and not looking for anymore, but don't let hope fade... read sequence till the end}
  2515. {check sequnce end conditions}
  2516. if (arrayind>2) and (ch < #32) then
  2517. begin
  2518. {if two short escape sequences are back to back}
  2519. PutBackIntoInBuf(ch); { rolling back }
  2520. dec(arrayind);
  2521. break;
  2522. end;
  2523. if (arrayind>3) and not (ch in [';',':','0'..'9']) and (ch <> '_') then break; {end of escape sequence}
  2524. end;
  2525. ch := store[arrayind-1];
  2526. if (ch = '_') and (arrayind > 2) and (store[0]=#27) and (store[1]='[') then
  2527. begin
  2528. DecodeAndPushWin32Key(store, arrayind);
  2529. exit;
  2530. end else
  2531. if (arrayind>3) then
  2532. if (ch = 'u' ) { for sure kitty keys or }
  2533. or ( isKittyKeys and not assigned(FoundNPT) ) {probally kitty keys}
  2534. then
  2535. begin
  2536. if not (assigned(FoundNPT) and assigned(FoundNPT^.SpecialHandler)) then
  2537. begin
  2538. FoundNPT:=RootNPT;
  2539. DecodeKittyKey(k,FoundNPT);
  2540. end;
  2541. end;
  2542. if not assigned(FoundNPT) then
  2543. begin
  2544. // This handles the case for non-kitty terminals sending ESC + UTF-8 bytes for Alt+key
  2545. if (arrayind > 1) and (store[0] = #27) and not isKittyKeys then
  2546. begin
  2547. ch1 := store[1];
  2548. utf8_bytes_to_read := DetectUtf8ByteSequenceStart(ch1) - 1;
  2549. full_sequence_ok := (arrayind - 1) = (utf8_bytes_to_read + 1);
  2550. if full_sequence_ok then
  2551. begin
  2552. // Push continuation bytes back to be re-read by ReadUtf8
  2553. for loop_idx := arrayind - 1 downto 2 do
  2554. PutBackIntoInBuf(store[loop_idx]);
  2555. UnicodeCodePoint := ReadUtf8(ch1);
  2556. if UnicodeCodePoint > 0 then
  2557. begin
  2558. k.ShiftState := [essAlt];
  2559. k.VirtualScanCode := 0;
  2560. PushUnicodeKey(k, UnicodeCodePoint, ReplacementAsciiChar);
  2561. ReadKey := PopKey;
  2562. exit;
  2563. end
  2564. else
  2565. begin
  2566. // Failed to parse, push everything back as-is
  2567. PutBackIntoInBuf(ch1);
  2568. for loop_idx := 2 to arrayind - 1 do
  2569. PutBackIntoInBuf(store[loop_idx]);
  2570. end;
  2571. end;
  2572. end;
  2573. RestoreArray;
  2574. end
  2575. else
  2576. NPT:=FoundNPT;
  2577. if assigned(NPT) and NPT^.CanBeTerminal then
  2578. begin
  2579. if assigned(NPT^.SpecialHandler) then
  2580. begin
  2581. NPT^.SpecialHandler;
  2582. k.AsciiChar := #0;
  2583. k.UnicodeChar := WideChar(#0);
  2584. k.VirtualScanCode := 0;
  2585. PushKey(k);
  2586. end
  2587. else if (NPT^.CharValue<>0) or (NPT^.ScanValue<>0) then
  2588. begin
  2589. k.AsciiChar := chr(NPT^.CharValue);
  2590. k.UnicodeChar := WideChar(NPT^.CharValue);
  2591. k.VirtualScanCode := (NPT^.ScanValue shl 8) or Ord(k.AsciiChar);
  2592. k.ShiftState:=k.ShiftState+NPT^.ShiftValue;
  2593. PushKey(k);
  2594. end;
  2595. end
  2596. else
  2597. RestoreArray;
  2598. end;
  2599. {$ifdef logging}
  2600. writeln(f);
  2601. {$endif logging}
  2602. ReadKey:=PopKey;
  2603. End;
  2604. procedure KittyKeyAvailability;
  2605. var st,zt : shortstring;
  2606. i: integer;
  2607. ch : AnsiChar;
  2608. begin
  2609. if (kitty_keys_yes=kitty_keys_no) then {make this test just once}
  2610. begin
  2611. write(#27'[?u'); { request response! }
  2612. write(#27'[c'); { request device status (DA1) to get at least some answer. }
  2613. st:=RawReadString; { read the answer }
  2614. isKittyKeys:=false;
  2615. if length(st)>0 then
  2616. begin
  2617. zt:='';
  2618. for i:=1 to length(st) do
  2619. begin
  2620. ch:=st[i];
  2621. if ch = #27 then
  2622. begin
  2623. if zt = #27'[?31u' then
  2624. begin
  2625. isKittyKeys:=true; {kitty keys supported and enabled}
  2626. end;
  2627. zt:='';
  2628. end;
  2629. zt:=zt+ch;
  2630. end;
  2631. if zt =#27'[?31u' then
  2632. begin
  2633. isKittyKeys:=true; {kitty keys supported and enabled}
  2634. end;
  2635. kitty_keys_yes:= isKittyKeys;
  2636. kitty_keys_no := not isKittyKeys;
  2637. end;
  2638. end;
  2639. end;
  2640. procedure waitAndReadAfterArtifacts;
  2641. var st : shortstring;
  2642. timewait,finalparsec : TimeSpec;
  2643. ree : longint;
  2644. begin
  2645. if not kitty_keys_yes then exit;
  2646. timewait.tv_sec := 0;
  2647. timewait.tv_nsec := 100000000; {few nano seconds to wait}
  2648. ree:=fpNanoSleep(@timewait,@finalparsec);
  2649. st:='';
  2650. if syskeypressed then st:=RawReadString; {empty key buffer (key realeas might be pending)}
  2651. end;
  2652. { Exported functions }
  2653. procedure SysInitKeyboard;
  2654. var
  2655. envInput: string;
  2656. begin
  2657. isKittyKeys:=false;
  2658. CurrentShiftState:=[];
  2659. PendingEnhancedKeyEvent:=NilEnhancedKeyEvent;
  2660. Utf8KeyboardInputEnabled:={$IFDEF FPC_DOTTEDUNITS}System.Console.{$ENDIF}UnixKVMBase.UTF8Enabled;
  2661. SetRawMode(true);
  2662. {$ifdef logging}
  2663. assign(f,'keyboard.log');
  2664. rewrite(f);
  2665. {$endif logging}
  2666. {$ifdef linux}
  2667. force_linuxtty;
  2668. prepare_patching;
  2669. patchkeyboard;
  2670. if is_console then
  2671. install_vt_handler
  2672. else
  2673. begin
  2674. {$endif}
  2675. { default for Shift prefix is ^ A}
  2676. if ShiftPrefix = 0 then
  2677. ShiftPrefix:=1;
  2678. {default for Alt prefix is ^Z }
  2679. if AltPrefix=0 then
  2680. AltPrefix:=26;
  2681. { default for Ctrl Prefix is ^W }
  2682. if CtrlPrefix=0 then
  2683. CtrlPrefix:=23;
  2684. if copy(fpgetenv('TERM'),1,5)='xterm' then
  2685. {The alt key should generate an escape prefix. Save the old setting
  2686. make make it send that escape prefix.}
  2687. begin
  2688. write(#27'[?1036s'#27'[?1036h');
  2689. double_esc_hack_enabled:=true;
  2690. end;
  2691. {kitty_keys_no:=true;}
  2692. isKittyKeys:=kitty_keys_yes;
  2693. envInput := fpgetenv('TV_INPUT');
  2694. if length(envInput) > 0 then
  2695. envInput[1] := UpCase(envInput[1]);
  2696. if envInput = 'Win32' then
  2697. begin
  2698. write(#27'[?9001h');
  2699. end
  2700. else if envInput = 'Kitty' then
  2701. begin
  2702. write(#27'[>31u');
  2703. KittyKeyAvailability;
  2704. end
  2705. else if envInput = 'Legacy' then
  2706. begin
  2707. // Do nothing
  2708. end
  2709. else // TV_INPUT not set or incorrect, use default logic
  2710. begin
  2711. if kitty_keys_yes or (kitty_keys_yes=kitty_keys_no) then
  2712. write(#27'[>31u'); { try to set up kitty keys }
  2713. KittyKeyAvailability;
  2714. if not isKittyKeys then
  2715. write(#27'[>4;2m'); { xterm -> modifyOtherKeys }
  2716. write(#27'[?9001h'); // Try to enable win32-input-mode
  2717. end;
  2718. {$ifdef linux}
  2719. end;
  2720. {$endif}
  2721. LoadDefaultSequences;
  2722. { LoadTerminfoSequences;}
  2723. end;
  2724. procedure SysDoneKeyboard;
  2725. begin
  2726. {$ifdef linux}
  2727. if is_console then
  2728. unpatchkeyboard;
  2729. {$endif linux}
  2730. write(#27'[?9001l'); // Disable win32-input-mode
  2731. if not isKittyKeys then
  2732. write(#27'[>4m'); { xterm -> reset to default modifyOtherKeys }
  2733. if kitty_keys_yes then
  2734. begin
  2735. write(#27'[<u'); {if we have kitty keys, disable them}
  2736. waitAndReadAfterArtifacts;
  2737. isKittyKeys:=false;
  2738. end;
  2739. if copy(fpgetenv('TERM'),1,5)='xterm' then
  2740. {Restore the old alt key behaviour.}
  2741. write(#27'[?1036r');
  2742. SetRawMode(false);
  2743. FreeTree;
  2744. {$ifdef logging}
  2745. close(f);
  2746. {$endif logging}
  2747. end;
  2748. function SysGetEnhancedKeyEvent: TEnhancedKeyEvent;
  2749. function EvalScan(b:byte):byte;
  2750. const
  2751. DScan:array[0..31] of byte = (
  2752. $39, $02, $28, $04, $05, $06, $08, $28,
  2753. $0A, $0B, $09, $0D, $33, $0C, $34, $35,
  2754. $0B, $02, $03, $04, $05, $06, $07, $08,
  2755. $09, $0A, $27, $27, $33, $0D, $34, $35);
  2756. LScan:array[0..31] of byte = (
  2757. $29, $1E, $30, $2E, $20, $12, $21, $22,
  2758. $23, $17, $24, $25, $26, $32, $31, $18,
  2759. $19, $10, $13, $1F, $14, $16, $2F, $11,
  2760. $2D, $15, $2C, $1A, $2B, $1B, $29, $0C);
  2761. begin
  2762. if (b and $E0)=$20 { digits / leters } then
  2763. EvalScan:=DScan[b and $1F]
  2764. else
  2765. case b of
  2766. $08:EvalScan:=$0E; { backspace }
  2767. $09:EvalScan:=$0F; { TAB }
  2768. $0D:EvalScan:=$1C; { CR }
  2769. $1B:EvalScan:=$01; { esc }
  2770. $40:EvalScan:=$03; { @ }
  2771. $5E:EvalScan:=$07; { ^ }
  2772. $60:EvalScan:=$29; { ` }
  2773. else
  2774. EvalScan:=LScan[b and $1F];
  2775. end;
  2776. end;
  2777. function EvalScanZ(b:byte):byte;
  2778. begin
  2779. EvalScanZ:=b;
  2780. if b in [$3B..$44] { F1..F10 -> Alt-F1..Alt-F10} then
  2781. EvalScanZ:=b+$2D;
  2782. end;
  2783. const
  2784. {kbHome, kbUp, kbPgUp,Missing, kbLeft,
  2785. kbCenter, kbRight, kbAltGrayPlus, kbend,
  2786. kbDown, kbPgDn, kbIns, kbDel }
  2787. CtrlArrow : array [kbHome..kbDel] of byte =
  2788. {($77,$8d,$84,$8e,$73,$8f,$74,$90,$75,$91,$76);}
  2789. (kbCtrlHome,kbCtrlUp,kbCtrlPgUp,kbNoKey,kbCtrlLeft,
  2790. kbCtrlCenter,kbCtrlRight,kbAltGrayPlus,kbCtrlEnd,
  2791. kbCtrlDown,kbCtrlPgDn,kbCtrlIns,kbCtrlDel);
  2792. AltArrow : array [kbHome..kbDel] of byte =
  2793. (kbAltHome,kbAltUp,kbAltPgUp,{kbNoKey}$4a,kbAltLeft,
  2794. kbAltCenter,kbAltRight,kbAltGrayPlus,kbAltEnd,
  2795. kbAltDown,kbAltPgDn,kbAltIns,kbAltDel);
  2796. var
  2797. MyScan:byte;
  2798. MyChar : AnsiChar;
  2799. MyUniChar: WideChar;
  2800. MyKey: TEnhancedKeyEvent;
  2801. EscUsed,AltPrefixUsed,CtrlPrefixUsed,ShiftPrefixUsed,Again : boolean;
  2802. SState: TEnhancedShiftState;
  2803. begin {main}
  2804. if PendingEnhancedKeyEvent<>NilEnhancedKeyEvent then
  2805. begin
  2806. SysGetEnhancedKeyEvent:=PendingEnhancedKeyEvent;
  2807. LastShiftState:=SysGetEnhancedKeyEvent.ShiftState; {to fake shift state later}
  2808. PendingEnhancedKeyEvent:=NilEnhancedKeyEvent;
  2809. exit;
  2810. end;
  2811. SysGetEnhancedKeyEvent:=NilEnhancedKeyEvent;
  2812. MyKey:=ReadKey;
  2813. // FAST PATH for pre-constructed events from ReadKey's Alt+UTF8 logic
  2814. if (MyKey.ShiftState <> []) and (Ord(MyKey.UnicodeChar) > 0) and (Ord(MyKey.UnicodeChar) <> Ord(MyKey.AsciiChar)) then
  2815. begin
  2816. SysGetEnhancedKeyEvent := MyKey;
  2817. LastShiftState := MyKey.ShiftState;
  2818. exit;
  2819. end;
  2820. MyChar:=MyKey.AsciiChar;
  2821. MyUniChar:=MyKey.UnicodeChar;
  2822. MyScan:=MyKey.VirtualScanCode shr 8;
  2823. Sstate:=MyKey.ShiftState;
  2824. CtrlPrefixUsed:=false;
  2825. AltPrefixUsed:=false;
  2826. ShiftPrefixUsed:=false;
  2827. EscUsed:=false;
  2828. repeat
  2829. again:=false;
  2830. if Mychar=#0 then
  2831. begin
  2832. { Handle Ctrl-<x>, but not AltGr-<x> }
  2833. if (essCtrl in SState) and (not (essAlt in SState)) then
  2834. case MyScan of
  2835. kbShiftTab: MyScan := kbCtrlTab;
  2836. kbHome..kbDel : { cArrow }
  2837. MyScan:=CtrlArrow[MyScan];
  2838. kbF1..KbF10 : { cF1-cF10 }
  2839. MyScan:=MyScan+kbCtrlF1-kbF1;
  2840. kbF11..KbF12 : { cF11-cF12 }
  2841. MyScan:=MyScan+kbCtrlF11-kbF11;
  2842. end
  2843. { Handle Alt-<x>, but not AltGr }
  2844. else if (essAlt in SState) and (not (essCtrl in SState)) then
  2845. case MyScan of
  2846. kbShiftTab: MyScan := kbAltTab;
  2847. kbHome..kbDel : { AltArrow }
  2848. MyScan:=AltArrow[MyScan];
  2849. kbF1..KbF10 : { aF1-aF10 }
  2850. MyScan:=MyScan+kbAltF1-kbF1;
  2851. kbF11..KbF12 : { aF11-aF12 }
  2852. MyScan:=MyScan+kbAltF11-kbF11;
  2853. end
  2854. else if essShift in SState then
  2855. case MyScan of
  2856. kbIns: MyScan:=kbShiftIns;
  2857. kbDel: MyScan:=kbShiftDel;
  2858. kbF1..KbF10 : { sF1-sF10 }
  2859. MyScan:=MyScan+kbShiftF1-kbF1;
  2860. kbF11..KbF12 : { sF11-sF12 }
  2861. MyScan:=MyScan+kbShiftF11-kbF11;
  2862. end;
  2863. if myscan=kbAltBack then
  2864. Include(sstate, essAlt);
  2865. if (MyChar<>#0) or (MyUniChar<>WideChar(0)) or (MyScan<>0) or (SState<>[]) then
  2866. begin
  2867. SysGetEnhancedKeyEvent.AsciiChar:=MyChar;
  2868. SysGetEnhancedKeyEvent.UnicodeChar:=MyUniChar;
  2869. SysGetEnhancedKeyEvent.ShiftState:=SState;
  2870. SysGetEnhancedKeyEvent.VirtualScanCode:=(MyScan shl 8) or Ord(MyChar);
  2871. end;
  2872. LastShiftState:=SysGetEnhancedKeyEvent.ShiftState; {to fake shift state later}
  2873. exit;
  2874. end
  2875. else if (AltPrefix<>0) and (MyChar=chr(AltPrefix)) then
  2876. begin { ^Z - replace Alt for Linux OS }
  2877. if AltPrefixUsed then
  2878. SState:=SState-[essAlt,essLeftAlt,essRightAlt]
  2879. else
  2880. begin
  2881. AltPrefixUsed:=true;
  2882. Include(SState,essAlt);
  2883. Again:=true;
  2884. end;
  2885. end
  2886. else if (CtrlPrefix<>0) and (MyChar=chr(CtrlPrefix)) then
  2887. begin
  2888. if CtrlPrefixUsed then
  2889. SState:=SState-[essCtrl,essLeftCtrl,essRightCtrl]
  2890. else
  2891. begin
  2892. CtrlPrefixUsed:=true;
  2893. Include(SState,essCtrl);
  2894. Again:=true;
  2895. end;
  2896. end
  2897. else if (ShiftPrefix<>0) and (MyChar=chr(ShiftPrefix)) then
  2898. begin
  2899. if ShiftPrefixUsed then
  2900. SState:=SState-[essShift,essLeftShift,essRightShift]
  2901. else
  2902. begin
  2903. ShiftPrefixUsed:=true;
  2904. Include(SState,essShift);
  2905. Again:=true;
  2906. end;
  2907. end;
  2908. if again then
  2909. begin
  2910. MyKey:=ReadKey;
  2911. MyChar:=MyKey.AsciiChar;
  2912. MyUniChar:=MyKey.UnicodeChar;
  2913. MyScan:=MyKey.VirtualScanCode shr 8;
  2914. end;
  2915. until not Again;
  2916. if MyScan = 0 then
  2917. MyScan:=EvalScan(ord(MyChar));
  2918. if (essCtrl in SState) and (not (essAlt in SState)) then
  2919. begin
  2920. if (MyChar=#9) and (MyScan <> $17) then
  2921. begin
  2922. MyChar:=#0;
  2923. MyUniChar:=WideChar(0);
  2924. MyScan:=kbCtrlTab;
  2925. end;
  2926. end
  2927. else if (essAlt in SState) and (not (essCtrl in SState)) then
  2928. begin
  2929. if (MyChar=#9) and (MyScan <> $17) then
  2930. begin
  2931. MyChar:=#0;
  2932. MyUniChar:=WideChar(0);
  2933. MyScan:=kbAltTab;
  2934. end
  2935. else if (MyScan <> $17) then
  2936. begin
  2937. if MyScan in [$02..$0D] then
  2938. inc(MyScan,$76);
  2939. MyChar:=chr(0);
  2940. MyUniChar:=WideChar(0);
  2941. end;
  2942. end
  2943. else if essShift in SState then
  2944. if (MyChar=#9) and (MyScan <> $17) then
  2945. begin
  2946. MyChar:=#0;
  2947. MyUniChar:=WideChar(0);
  2948. MyScan:=kbShiftTab;
  2949. end;
  2950. if (MyChar<>#0) or (MyUniChar<>WideChar(0)) or (MyScan<>0) or (SState<>[]) then
  2951. begin
  2952. SysGetEnhancedKeyEvent.AsciiChar:=MyChar;
  2953. SysGetEnhancedKeyEvent.UnicodeChar:=MyUniChar;
  2954. SysGetEnhancedKeyEvent.ShiftState:=SState;
  2955. SysGetEnhancedKeyEvent.VirtualScanCode:=(MyScan shl 8) or Ord(MyChar);
  2956. end;
  2957. LastShiftState:=SysGetEnhancedKeyEvent.ShiftState; {to fake shift state later}
  2958. end;
  2959. function SysPollEnhancedKeyEvent: TEnhancedKeyEvent;
  2960. var
  2961. KeyEvent : TEnhancedKeyEvent;
  2962. begin
  2963. if PendingEnhancedKeyEvent<>NilEnhancedKeyEvent then
  2964. SysPollEnhancedKeyEvent:=PendingEnhancedKeyEvent
  2965. else if keypressed then
  2966. begin
  2967. KeyEvent:=SysGetEnhancedKeyEvent;
  2968. PendingEnhancedKeyEvent:=KeyEvent;
  2969. SysPollEnhancedKeyEvent:=KeyEvent;
  2970. end
  2971. else
  2972. SysPollEnhancedKeyEvent:=NilEnhancedKeyEvent;
  2973. LastShiftState:=SysPollEnhancedKeyEvent.ShiftState; {to fake shift state later}
  2974. end;
  2975. function SysGetShiftState : Byte;
  2976. begin
  2977. {$ifdef linux}
  2978. if is_console then
  2979. SysGetShiftState:=ShiftState
  2980. else
  2981. {$endif}
  2982. SysGetShiftState:=GetLastShiftState;
  2983. end;
  2984. procedure RestoreStartMode;
  2985. begin
  2986. TCSetAttr(1,TCSANOW,StartTio);
  2987. end;
  2988. const
  2989. SysKeyboardDriver : TKeyboardDriver = (
  2990. InitDriver : @SysInitKeyBoard;
  2991. DoneDriver : @SysDoneKeyBoard;
  2992. GetKeyevent : Nil;
  2993. PollKeyEvent : Nil;
  2994. GetShiftState : @SysGetShiftState;
  2995. TranslateKeyEvent : Nil;
  2996. TranslateKeyEventUnicode : Nil;
  2997. GetEnhancedKeyEvent : @SysGetEnhancedKeyEvent;
  2998. PollEnhancedKeyEvent : @SysPollEnhancedKeyEvent;
  2999. );
  3000. begin
  3001. SetKeyBoardDriver(SysKeyBoardDriver);
  3002. TCGetAttr(1,StartTio);
  3003. end.