keyboard.pp 124 KB

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