123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 1999-2000 by Florian Klaempfl
- member of the Free Pascal development team
- Keyboard unit for linux
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- unit keyboard;
- {$inline on}
- {*****************************************************************************}
- interface
- {*****************************************************************************}
- {$i keybrdh.inc}
- const
- AltPrefix : byte = 0;
- ShiftPrefix : byte = 0;
- CtrlPrefix : byte = 0;
- type
- Tprocedure = procedure;
- PTreeElement = ^TTreeElement;
- TTreeElement = record
- Next,Parent,Child : PTreeElement;
- CanBeTerminal : boolean;
- char : byte;
- ScanValue : byte;
- CharValue : byte;
- SpecialHandler : Tprocedure;
- end;
- function RawReadKey:char;
- function RawReadString : String;
- function KeyPressed : Boolean;
- procedure AddSequence(const St : String; AChar,AScan :byte);inline;
- function FindSequence(const St : String;var AChar, Ascan : byte) : boolean;
- procedure RestoreStartMode;
- function AddSpecialSequence(const St : string;Proc : Tprocedure) : PTreeElement; platform;
- {*****************************************************************************}
- implementation
- {*****************************************************************************}
- uses
- Mouse, Strings,
- termio,baseUnix
- {$ifdef linux},linuxvcs{$endif};
- {$i keyboard.inc}
- var OldIO,StartTio : TermIos;
- {$ifdef linux}
- is_console:boolean;
- vt_switched_away:boolean;
- {$endif}
- {$ifdef logging}
- f : text;
- {$endif logging}
- const
- KeyBufferSize = 20;
- var
- KeyBuffer : Array[0..KeyBufferSize-1] of Char;
- KeyPut,
- KeySend : longint;
- { Buffered Input routines }
- const
- InSize=256;
- var
- InBuf : array [0..InSize-1] of char;
- { InCnt,}
- InHead,
- InTail : longint;
- {$i keyscan.inc}
- {Some internal only scancodes}
- const KbShiftUp = $f0;
- KbShiftLeft = $f1;
- KbShiftRight = $f2;
- KbShiftDown = $f3;
- KbShiftHome = $f4;
- KbShiftEnd = $f5;
- double_esc_hack_enabled : boolean = false;
- {$ifdef Unused}
- type
- TKeyState = Record
- Normal, Shift, Ctrl, Alt : word;
- end;
- const
- KeyStates : Array[0..255] of TKeyState
- (
- );
- {$endif Unused}
- procedure SetRawMode(b:boolean);
- var Tio:Termios;
- begin
- TCGetAttr(1,Tio);
- if b then
- begin
- {Standard output now needs #13#10.}
- settextlineending(output,#13#10);
- OldIO:=Tio;
- CFMakeRaw(Tio);
- end
- else
- begin
- Tio := OldIO;
- {Standard output normally needs just a linefeed.}
- settextlineending(output,#10);
- end;
- TCsetattr(1,TCSANOW,Tio);
- end;
- {$ifdef linux}
- {The Linux console can do nice things: we can get the state of the shift keys,
- and reprogram the keys. That's nice since it allows excellent circumvention
- of VT100 limitations, we can make the keyboard work 100%...
- A 100% working keyboard seems to be a pretty basic requirement, but we're
- one of the few guys providing such an outrageous luxury (DM).}
- type
- chgentry=packed record
- tab,
- idx,
- oldtab,
- oldidx : byte;
- oldval,
- newval : word;
- end;
- kbentry=packed record
- kb_table,
- kb_index : byte;
- kb_value : word;
- end;
- kbsentry=packed record
- kb_func:byte;
- kb_string:array[0..511] of char;
- end;
- vt_mode=packed record
- mode, {vt mode}
- waitv:byte; {if set, hang on writes if not active}
- relsig, {signal to raise on release req}
- acqsig, {signal to raise on acquisition}
- frsig:word; {unused (set to 0)}
- end;
- const
- kbdchange:array[0..23] of chgentry=(
- {This prevents the alt+function keys from switching consoles.
- We code the F1..F12 sequences into ALT+F1..ALT+12, we check
- the shiftstates separetely anyway.}
- (tab:8; idx:$3b; oldtab:0; oldidx:$3b; oldval:0; newval:0),
- (tab:8; idx:$3c; oldtab:0; oldidx:$3c; oldval:0; newval:0),
- (tab:8; idx:$3d; oldtab:0; oldidx:$3d; oldval:0; newval:0),
- (tab:8; idx:$3e; oldtab:0; oldidx:$3e; oldval:0; newval:0),
- (tab:8; idx:$3f; oldtab:0; oldidx:$3f; oldval:0; newval:0),
- (tab:8; idx:$40; oldtab:0; oldidx:$40; oldval:0; newval:0),
- (tab:8; idx:$41; oldtab:0; oldidx:$41; oldval:0; newval:0),
- (tab:8; idx:$42; oldtab:0; oldidx:$42; oldval:0; newval:0),
- (tab:8; idx:$43; oldtab:0; oldidx:$43; oldval:0; newval:0),
- (tab:8; idx:$44; oldtab:0; oldidx:$44; oldval:0; newval:0),
- (tab:8; idx:$45; oldtab:0; oldidx:$45; oldval:0; newval:0),
- (tab:8; idx:$46; oldtab:0; oldidx:$46; oldval:0; newval:0),
- {This prevents the shift+function keys outputting strings, so
- the kernel will the codes for the non-shifted function
- keys. This is desired because normally shift+f1/f2 will output the
- same string as f11/12. We will get the shift state separately.}
- (tab:1; idx:$3b; oldtab:0; oldidx:$3b; oldval:0; newval:0),
- (tab:1; idx:$3c; oldtab:0; oldidx:$3c; oldval:0; newval:0),
- (tab:1; idx:$3d; oldtab:0; oldidx:$3d; oldval:0; newval:0),
- (tab:1; idx:$3e; oldtab:0; oldidx:$3e; oldval:0; newval:0),
- (tab:1; idx:$3f; oldtab:0; oldidx:$3f; oldval:0; newval:0),
- (tab:1; idx:$40; oldtab:0; oldidx:$40; oldval:0; newval:0),
- (tab:1; idx:$41; oldtab:0; oldidx:$41; oldval:0; newval:0),
- (tab:1; idx:$42; oldtab:0; oldidx:$42; oldval:0; newval:0),
- (tab:1; idx:$43; oldtab:0; oldidx:$43; oldval:0; newval:0),
- (tab:1; idx:$44; oldtab:0; oldidx:$44; oldval:0; newval:0),
- (tab:1; idx:$45; oldtab:0; oldidx:$45; oldval:0; newval:0),
- (tab:1; idx:$46; oldtab:0; oldidx:$46; oldval:0; newval:0)
- );
- KDGKBENT=$4B46;
- KDSKBENT=$4B47;
- KDGKBSENT=$4B48;
- KDSKBSENT=$4B49;
- KDGKBMETA=$4B62;
- KDSKBMETA=$4B63;
- K_ESCPREFIX=$4;
- K_METABIT=$3;
- VT_GETMODE=$5601;
- VT_SETMODE=$5602;
- VT_RELDISP=$5605;
- VT_PROCESS=1;
- const
- oldmeta : longint = 0;
- meta : longint = 0;
- var oldesc0,oldesc1,oldesc2,oldesc4,oldesc8:word;
- procedure prepare_patching;
- var entry : kbentry;
- i:longint;
- begin
- for i:=low(kbdchange) to high(kbdchange) do
- with kbdchange[i] do
- begin
- entry.kb_table:=tab;
- entry.kb_index:=idx;
- fpIoctl(stdinputhandle,KDGKBENT,@entry);
- oldval:=entry.kb_value;
- entry.kb_table:=oldtab;
- entry.kb_index:=oldidx;
- fpioctl(stdinputhandle,KDGKBENT,@entry);
- newval:=entry.kb_value;
- end;
- {Save old escape code.}
- entry.kb_index:=1;
- entry.kb_table:=0;
- fpioctl(stdinputhandle,KDGKBENT,@entry);
- oldesc0:=entry.kb_value;
- entry.kb_table:=1;
- fpioctl(stdinputhandle,KDGKBENT,@entry);
- oldesc1:=entry.kb_value;
- entry.kb_table:=2;
- fpioctl(stdinputhandle,KDGKBENT,@entry);
- oldesc2:=entry.kb_value;
- entry.kb_table:=4;
- fpioctl(stdinputhandle,KDGKBENT,@entry);
- oldesc4:=entry.kb_value;
- entry.kb_table:=8;
- fpioctl(stdinputhandle,KDGKBENT,@entry);
- oldesc8:=entry.kb_value;
- end;
- procedure PatchKeyboard;
- var
- entry : kbentry;
- sentry : kbsentry;
- i:longint;
- begin
- fpIoctl(stdinputhandle,KDGKBMETA,@oldmeta);
- meta:=K_ESCPREFIX;
- fpIoctl(stdinputhandle,KDSKBMETA,@meta);
- for i:=low(kbdchange) to high(kbdchange) do
- with kbdchange[i] do
- begin
- entry.kb_table:=tab;
- entry.kb_index:=idx;
- entry.kb_value:=newval;
- fpioctl(stdinputhandle,KDSKBENT,@entry);
- end;
- {Map kernel escape key code to symbol F32.}
- entry.kb_index:=1;
- entry.kb_value:=$011f;
- entry.kb_table:=0;
- fpioctl(stdinputhandle,KDSKBENT,@entry);
- entry.kb_table:=1;
- fpioctl(stdinputhandle,KDSKBENT,@entry);
- entry.kb_table:=2;
- fpioctl(stdinputhandle,KDSKBENT,@entry);
- entry.kb_table:=4;
- fpioctl(stdinputhandle,KDSKBENT,@entry);
- entry.kb_table:=8;
- fpioctl(stdinputhandle,KDSKBENT,@entry);
- {F32 (the escape key) will generate ^[[0~ .}
- sentry.kb_func:=31;
- sentry.kb_string:=#27'[0~';
- fpioctl(stdinputhandle,KDSKBSENT,@sentry);
- end;
- procedure UnpatchKeyboard;
- var
- e : ^chgentry;
- entry : kbentry;
- i : longint;
- begin
- if oldmeta in [K_ESCPREFIX,K_METABIT] then
- fpioctl(stdinputhandle,KDSKBMETA,@oldmeta);
- for i:=low(kbdchange) to high(kbdchange) do
- with kbdchange[i] do
- begin
- entry.kb_table:=tab;
- entry.kb_index:=idx;
- entry.kb_value:=oldval;
- fpioctl(stdinputhandle,KDSKBENT,@entry);
- end;
- entry.kb_index:=1;
- entry.kb_table:=0;
- entry.kb_value:=oldesc0;
- fpioctl(stdinputhandle,KDSKBENT,@entry);
- entry.kb_table:=1;
- entry.kb_value:=oldesc1;
- fpioctl(stdinputhandle,KDSKBENT,@entry);
- entry.kb_table:=2;
- entry.kb_value:=oldesc2;
- fpioctl(stdinputhandle,KDSKBENT,@entry);
- entry.kb_table:=4;
- entry.kb_value:=oldesc4;
- fpioctl(stdinputhandle,KDSKBENT,@entry);
- entry.kb_table:=8;
- entry.kb_value:=oldesc8;
- fpioctl(stdinputhandle,KDSKBENT,@entry);
- end;
- {A problem of patching the keyboard is that it no longer works as expected
- when working on another console. So we unpatch it when the user switches
- away.}
- const switches:longint=0;
- procedure vt_handler(sig:longint);cdecl;
- begin
- if vt_switched_away then
- begin
- {Confirm the switch.}
- fpioctl(stdoutputhandle,VT_RELDISP,pointer(2));
- {Switching to program, patch keyboard.}
- patchkeyboard;
- end
- else
- begin
- {Switching away from program, unpatch the keyboard.}
- unpatchkeyboard;
- fpioctl(stdoutputhandle,VT_RELDISP,pointer(1));
- end;
- vt_switched_away:=not vt_switched_away;
- {Clear buffer.}
- intail:=inhead;
- end;
- procedure install_vt_handler;
- var mode:vt_mode;
- begin
- { ioctl(vt_fd,KDSETMODE,KD_GRAPHICS);}
- fpioctl(stdoutputhandle,VT_GETMODE,@mode);
- mode.mode:=VT_PROCESS;
- mode.relsig:=SIGUSR1;
- mode.acqsig:=SIGUSR1;
- vt_switched_away:=false;
- fpsignal(SIGUSR1,@vt_handler);
- fpioctl(stdoutputhandle,VT_SETMODE,@mode);
- end;
- {$endif}
- function ttyRecvChar:char;
- var Readed,i : longint;
- begin
- {Buffer empty? Yes, input from stdin}
- if (InHead=InTail) then
- begin
- {Calc Amount of Chars to Read}
- i:=InSize-InHead;
- if InTail>InHead then
- i:=InTail-InHead;
- {Read}
- repeat
- Readed:=fpRead(StdInputHandle,InBuf[InHead],i);
- until readed<>-1;
- {Increase Counters}
- inc(InHead,Readed);
- {Wrap if End has Reached}
- if InHead>=InSize then
- InHead:=0;
- end;
- {Check Buffer}
- ttyRecvChar:=InBuf[InTail];
- inc(InTail);
- if InTail>=InSize then
- InTail:=0;
- end;
- procedure PushKey(Ch:char);
- var
- Tmp : Longint;
- begin
- Tmp:=KeyPut;
- Inc(KeyPut);
- If KeyPut>=KeyBufferSize Then
- KeyPut:=0;
- If KeyPut<>KeySend Then
- KeyBuffer[Tmp]:=Ch
- Else
- KeyPut:=Tmp;
- End;
- function PopKey:char;
- begin
- If KeyPut<>KeySend Then
- begin
- PopKey:=KeyBuffer[KeySend];
- Inc(KeySend);
- If KeySend>=KeyBufferSize Then
- KeySend:=0;
- End
- Else
- PopKey:=#0;
- End;
- procedure PushExt(b:byte);
- begin
- PushKey(#0);
- PushKey(chr(b));
- end;
- const
- AltKeyStr : string[38]='qwertyuiopasdfghjklzxcvbnm1234567890-=';
- AltCodeStr : string[38]=#016#017#018#019#020#021#022#023#024#025#030#031#032#033#034#035#036#037#038+
- #044#045#046#047#048#049#050#120#121#122#123#124#125#126#127#128#129#130#131;
- function FAltKey(ch:char):byte;
- var
- Idx : longint;
- begin
- Idx:=Pos(ch,AltKeyStr);
- if Idx>0 then
- FAltKey:=byte(AltCodeStr[Idx])
- else
- FAltKey:=0;
- End;
- { This one doesn't care about keypresses already processed by readkey }
- { and waiting in the KeyBuffer, only about waiting keypresses at the }
- { TTYLevel (including ones that are waiting in the TTYRecvChar buffer) }
- function sysKeyPressed: boolean;
- var
- fdsin : tfdSet;
- begin
- if (inhead<>intail) then
- sysKeyPressed:=true
- else
- begin
- fpFD_ZERO(fdsin);
- fpFD_SET(StdInputHandle,fdsin);
- sysKeypressed:=(fpSelect(StdInputHandle+1,@fdsin,nil,nil,0)>0);
- end;
- end;
- function KeyPressed:Boolean;
- begin
- Keypressed := (KeySend<>KeyPut) or sysKeyPressed;
- End;
- const
- LastMouseEvent : TMouseEvent =
- (
- Buttons : 0;
- X : 0;
- Y : 0;
- Action : 0;
- );
- procedure GenMouseEvent;
- var MouseEvent: TMouseEvent;
- ch : char;
- fdsin : tfdSet;
- buttonval:byte;
- begin
- fpFD_ZERO(fdsin);
- fpFD_SET(StdInputHandle,fdsin);
- { Fillchar(MouseEvent,SizeOf(TMouseEvent),#0);}
- MouseEvent.action:=0;
- if inhead=intail then
- fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
- ch:=ttyRecvChar;
- { Other bits are used for Shift, Meta and Ctrl modifiers PM }
- buttonval:=byte(ch)-byte(' ');
- {bits 0..1: button status
- bit 5 : mouse movement while button down.
- bit 6 : interpret button 1 as button 4
- interpret button 2 as button 5}
- case buttonval and 3 of
- 0 : {left button press}
- MouseEvent.buttons:=1;
- 1 : {middle button pressed }
- MouseEvent.buttons:=2;
- 2 : { right button pressed }
- MouseEvent.buttons:=4;
- 3 : { no button pressed }
- MouseEvent.buttons:=0;
- end;
- if inhead=intail then
- fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
- ch:=ttyRecvChar;
- MouseEvent.x:=Ord(ch)-ord(' ')-1;
- if inhead=intail then
- fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
- ch:=ttyRecvChar;
- MouseEvent.y:=Ord(ch)-ord(' ')-1;
- mouseevent.action:=MouseActionMove;
- if (lastmouseevent.buttons=0) and (mouseevent.buttons<>0) then
- MouseEvent.action:=MouseActionDown;
- if (lastmouseevent.buttons<>0) and (mouseevent.buttons=0) then
- MouseEvent.action:=MouseActionUp;
- (*
- else
- begin
- if (LastMouseEvent.Buttons<>0) and
- ((LastMouseEvent.X<>MouseEvent.X) or (LastMouseEvent.Y<>MouseEvent.Y)) then
- begin
- MouseEvent.Action:=MouseActionMove;
- MouseEvent.Buttons:=LastMouseEvent.Buttons;
- {$ifdef DebugMouse}
- Writeln(system.stderr,' Mouse Move (',MouseEvent.X,',',MouseEvent.Y,')');
- {$endif DebugMouse}
- PutMouseEvent(MouseEvent);
- MouseEvent.Buttons:=0;
- end;
- MouseEvent.Action:=MouseActionUp;
- end;
- *)
- PutMouseEvent(MouseEvent);
- {$ifdef DebugMouse}
- if MouseEvent.Action=MouseActionDown then
- Write(system.stderr,'Button down : ')
- else
- Write(system.stderr,'Button up : ');
- Writeln(system.stderr,'buttons = ',MouseEvent.Buttons,' (',MouseEvent.X,',',MouseEvent.Y,')');
- {$endif DebugMouse}
- LastMouseEvent:=MouseEvent;
- end;
- var roottree:array[char] of PTreeElement;
- procedure FreeElement (PT:PTreeElement);
- var next : PTreeElement;
- begin
- while PT <> nil do
- begin
- FreeElement(PT^.Child);
- next := PT^.Next;
- dispose(PT);
- PT := next;
- end;
- end;
- procedure FreeTree;
- var i:char;
- begin
- for i:=low(roottree) to high(roottree) do
- begin
- FreeElement(RootTree[i]);
- roottree[i]:=nil;
- end;
- end;
- function NewPTree(ch : byte;Pa : PTreeElement) : PTreeElement;
- begin
- newPtree:=allocmem(sizeof(Ttreeelement));
- newPtree^.char:=ch;
- newPtree^.Parent:=Pa;
- if Assigned(Pa) and (Pa^.Child=nil) then
- Pa^.Child:=newPtree;
- end;
- function DoAddSequence(const St : String; AChar,AScan :byte) : PTreeElement;
- var
- CurPTree,NPT : PTreeElement;
- c : byte;
- i : longint;
- begin
- if St='' then
- begin
- DoAddSequence:=nil;
- exit;
- end;
- CurPTree:=RootTree[st[1]];
- if CurPTree=nil then
- begin
- CurPTree:=NewPTree(ord(st[1]),nil);
- RootTree[st[1]]:=CurPTree;
- end;
- for i:=2 to Length(St) do
- begin
- NPT:=CurPTree^.Child;
- c:=ord(St[i]);
- if NPT=nil then
- NPT:=NewPTree(c,CurPTree);
- CurPTree:=nil;
- while assigned(NPT) and (NPT^.char<c) do
- begin
- CurPTree:=NPT;
- NPT:=NPT^.Next;
- end;
- if assigned(NPT) and (NPT^.char=c) then
- CurPTree:=NPT
- else
- begin
- if CurPTree=nil then
- begin
- NPT^.Parent^.child:=NewPTree(c,NPT^.Parent);
- CurPTree:=NPT^.Parent^.Child;
- CurPTree^.Next:=NPT;
- end
- else
- begin
- CurPTree^.Next:=NewPTree(c,CurPTree^.Parent);
- CurPTree:=CurPTree^.Next;
- CurPTree^.Next:=NPT;
- end;
- end;
- end;
- if CurPTree^.CanBeTerminal then
- begin
- { here we have a conflict !! }
- { maybe we should claim }
- with CurPTree^ do
- begin
- {$ifdef DEBUG}
- if (ScanValue<>AScan) or (CharValue<>AChar) then
- Writeln(system.stderr,'key "',st,'" changed value');
- if (ScanValue<>AScan) then
- Writeln(system.stderr,'Scan was ',ScanValue,' now ',AScan);
- if (CharValue<>AChar) then
- Writeln(system.stderr,'Char was ',chr(CharValue),' now ',chr(AChar));
- {$endif DEBUG}
- ScanValue:=AScan;
- CharValue:=AChar;
- end;
- end
- else with CurPTree^ do
- begin
- CanBeTerminal:=True;
- ScanValue:=AScan;
- CharValue:=AChar;
- end;
- DoAddSequence:=CurPTree;
- end;
- procedure AddSequence(const St : String; AChar,AScan :byte);inline;
- begin
- DoAddSequence(St,AChar,AScan);
- end;
- { Returns the Child that as c as char if it exists }
- function FindChild(c : byte;Root : PTreeElement) : PTreeElement;
- var
- NPT : PTreeElement;
- begin
- NPT:=Root^.Child;
- while assigned(NPT) and (NPT^.char<c) do
- NPT:=NPT^.Next;
- if assigned(NPT) and (NPT^.char=c) then
- FindChild:=NPT
- else
- FindChild:=nil;
- end;
- function AddSpecialSequence(const St : string;Proc : Tprocedure) : PTreeElement;
- var
- NPT : PTreeElement;
- begin
- NPT:=DoAddSequence(St,0,0);
- NPT^.SpecialHandler:=Proc;
- AddSpecialSequence:=NPT;
- end;
- function FindSequence(const St : String;var AChar,AScan :byte) : boolean;
- var
- NPT : PTreeElement;
- i,p : byte;
- begin
- FindSequence:=false;
- AChar:=0;
- AScan:=0;
- if St='' then
- exit;
- p:=1;
- {This is a distusting hack for certain even more disgusting xterms: Some of
- them send two escapes for an alt-key. If we wouldn't do this, we would need
- to put a lot of entries twice in the table.}
- if double_esc_hack_enabled and (st[1]=#27) and (st[2]='#27') and
- (st[3] in ['a'..'z','A'..'Z','0'..'9','-','+','_','=']) then
- inc(p);
- NPT:=RootTree[St[p]];
- if npt<>nil then
- begin
- for i:=p+1 to Length(St) do
- begin
- NPT:=FindChild(ord(St[i]),NPT);
- if NPT=nil then
- exit;
- end;
- if NPT^.CanBeTerminal then
- begin
- FindSequence:=true;
- AScan:=NPT^.ScanValue;
- AChar:=NPT^.CharValue;
- end;
- end;
- end;
- type key_sequence=packed record
- char,scan:byte;
- st:string[7];
- end;
- const key_sequences:array[0..277] of key_sequence=(
- (char:0;scan:kbAltA;st:#27'A'),
- (char:0;scan:kbAltA;st:#27'a'),
- (char:0;scan:kbAltB;st:#27'B'),
- (char:0;scan:kbAltB;st:#27'b'),
- (char:0;scan:kbAltC;st:#27'C'),
- (char:0;scan:kbAltC;st:#27'c'),
- (char:0;scan:kbAltD;st:#27'D'),
- (char:0;scan:kbAltD;st:#27'd'),
- (char:0;scan:kbAltE;st:#27'E'),
- (char:0;scan:kbAltE;st:#27'e'),
- (char:0;scan:kbAltF;st:#27'F'),
- (char:0;scan:kbAltF;st:#27'f'),
- (char:0;scan:kbAltG;st:#27'G'),
- (char:0;scan:kbAltG;st:#27'g'),
- (char:0;scan:kbAltH;st:#27'H'),
- (char:0;scan:kbAltH;st:#27'h'),
- (char:0;scan:kbAltI;st:#27'I'),
- (char:0;scan:kbAltI;st:#27'i'),
- (char:0;scan:kbAltJ;st:#27'J'),
- (char:0;scan:kbAltJ;st:#27'j'),
- (char:0;scan:kbAltK;st:#27'K'),
- (char:0;scan:kbAltK;st:#27'k'),
- (char:0;scan:kbAltL;st:#27'L'),
- (char:0;scan:kbAltL;st:#27'l'),
- (char:0;scan:kbAltM;st:#27'M'),
- (char:0;scan:kbAltM;st:#27'm'),
- (char:0;scan:kbAltN;st:#27'N'),
- (char:0;scan:kbAltN;st:#27'n'),
- (char:0;scan:kbAltO;st:#27'O'),
- (char:0;scan:kbAltO;st:#27'o'),
- (char:0;scan:kbAltP;st:#27'P'),
- (char:0;scan:kbAltP;st:#27'p'),
- (char:0;scan:kbAltQ;st:#27'Q'),
- (char:0;scan:kbAltQ;st:#27'q'),
- (char:0;scan:kbAltR;st:#27'R'),
- (char:0;scan:kbAltR;st:#27'r'),
- (char:0;scan:kbAltS;st:#27'S'),
- (char:0;scan:kbAltS;st:#27's'),
- (char:0;scan:kbAltT;st:#27'T'),
- (char:0;scan:kbAltT;st:#27't'),
- (char:0;scan:kbAltU;st:#27'U'),
- (char:0;scan:kbAltU;st:#27'u'),
- (char:0;scan:kbAltV;st:#27'V'),
- (char:0;scan:kbAltV;st:#27'v'),
- (char:0;scan:kbAltW;st:#27'W'),
- (char:0;scan:kbAltW;st:#27'w'),
- (char:0;scan:kbAltX;st:#27'X'),
- (char:0;scan:kbAltX;st:#27'x'),
- (char:0;scan:kbAltY;st:#27'Y'),
- (char:0;scan:kbAltY;st:#27'y'),
- (char:0;scan:kbAltZ;st:#27'Z'),
- (char:0;scan:kbAltZ;st:#27'z'),
- (char:0;scan:kbAltMinus;st:#27'-'),
- (char:0;scan:kbAltEqual;st:#27'='),
- (char:0;scan:kbAlt0;st:#27'0'),
- (char:0;scan:kbAlt1;st:#27'1'),
- (char:0;scan:kbAlt2;st:#27'2'),
- (char:0;scan:kbAlt3;st:#27'3'),
- (char:0;scan:kbAlt4;st:#27'4'),
- (char:0;scan:kbAlt5;st:#27'5'),
- (char:0;scan:kbAlt6;st:#27'6'),
- (char:0;scan:kbAlt7;st:#27'7'),
- (char:0;scan:kbAlt8;st:#27'8'),
- (char:0;scan:kbAlt9;st:#27'9'),
- (char:0;scan:kbF1;st:#27'[[A'), {linux,konsole,xterm}
- (char:0;scan:kbF2;st:#27'[[B'), {linux,konsole,xterm}
- (char:0;scan:kbF3;st:#27'[[C'), {linux,konsole,xterm}
- (char:0;scan:kbF4;st:#27'[[D'), {linux,konsole,xterm}
- (char:0;scan:kbF5;st:#27'[[E'), {linux,konsole}
- (char:0;scan:kbF1;st:#27'[11~'), {Eterm,rxvt}
- (char:0;scan:kbF2;st:#27'[12~'), {Eterm,rxvt}
- (char:0;scan:kbF3;st:#27'[13~'), {Eterm,rxvt}
- (char:0;scan:kbF4;st:#27'[14~'), {Eterm,rxvt}
- (char:0;scan:kbF5;st:#27'[15~'), {xterm,Eterm,gnome,rxvt}
- (char:0;scan:kbF6;st:#27'[17~'), {linux,xterm,Eterm,konsole,gnome,rxvt}
- (char:0;scan:kbF7;st:#27'[18~'), {linux,xterm,Eterm,konsole,gnome,rxvt}
- (char:0;scan:kbF8;st:#27'[19~'), {linux,xterm,Eterm,konsole,gnome,rxvt}
- (char:0;scan:kbF9;st:#27'[20~'), {linux,xterm,Eterm,konsole,gnome,rxvt}
- (char:0;scan:kbF10;st:#27'[21~'), {linux,xterm,Eterm,konsole,gnome,rxvt}
- (char:0;scan:kbF11;st:#27'[23~'), {linux,xterm,Eterm,konsole,gnome,rxvt}
- (char:0;scan:kbF12;st:#27'[24~'), {linux,xterm,Eterm,konsole,gnome,rxvt}
- (char:0;scan:kbF1;st:#27'[M'), {FreeBSD}
- (char:0;scan:kbF2;st:#27'[N'), {FreeBSD}
- (char:0;scan:kbF3;st:#27'[O'), {FreeBSD}
- (char:0;scan:kbF4;st:#27'[P'), {FreeBSD}
- (char:0;scan:kbF5;st:#27'[Q'), {FreeBSD}
- (char:0;scan:kbF6;st:#27'[R'), {FreeBSD}
- (char:0;scan:kbF7;st:#27'[S'), {FreeBSD}
- (char:0;scan:kbF8;st:#27'[T'), {FreeBSD}
- (char:0;scan:kbF9;st:#27'[U'), {FreeBSD}
- (char:0;scan:kbF10;st:#27'[V'), {FreeBSD}
- (char:0;scan:kbF11;st:#27'[W'), {FreeBSD}
- (char:0;scan:kbF12;st:#27'[X'), {FreeBSD}
- (char:0;scan:kbF1;st:#27'OP'), {vt100,gnome,konsole}
- (char:0;scan:kbF2;st:#27'OQ'), {vt100,gnome,konsole}
- (char:0;scan:kbF3;st:#27'OR'), {vt100,gnome,konsole}
- (char:0;scan:kbF4;st:#27'OS'), {vt100,gnome,konsole}
- (char:0;scan:kbF5;st:#27'Ot'), {vt100}
- (char:0;scan:kbF6;st:#27'Ou'), {vt100}
- (char:0;scan:kbF7;st:#27'Ov'), {vt100}
- (char:0;scan:kbF8;st:#27'Ol'), {vt100}
- (char:0;scan:kbF9;st:#27'Ow'), {vt100}
- (char:0;scan:kbF10;st:#27'Ox'), {vt100}
- (char:0;scan:kbF11;st:#27'Oy'), {vt100}
- (char:0;scan:kbF12;st:#27'Oz'), {vt100}
- (char:0;scan:kbEsc;st:#27'[0~'), {if linux keyboard patched, escape
- returns this}
- (char:0;scan:kbIns;st:#27'[2~'), {linux,Eterm,rxvt}
- (char:0;scan:kbDel;st:#27'[3~'), {linux,Eterm,rxvt}
- (char:0;scan:kbHome;st:#27'[1~'), {linux}
- (char:0;scan:kbHome;st:#27'[7~'), {Eterm,rxvt}
- (char:0;scan:kbHome;st:#27'[H'), {FreeBSD}
- (char:0;scan:kbHome;st:#27'OH'), {some xterm configurations}
- (char:0;scan:kbEnd;st:#27'[4~'), {linux,Eterm}
- (char:0;scan:kbEnd;st:#27'[8~'), {rxvt}
- (char:0;scan:kbEnd;st:#27'[F'), {FreeBSD}
- (char:0;scan:kbEnd;st:#27'OF'), {some xterm configurations}
- (char:0;scan:kbPgUp;st:#27'[5~'), {linux,Eterm,rxvt}
- (char:0;scan:kbPgUp;st:#27'[I'), {FreeBSD}
- (char:0;scan:kbPgDn;st:#27'[6~'), {linux,Eterm,rxvt}
- (char:0;scan:kbPgDn;st:#27'[G'), {FreeBSD}
- (char:0;scan:kbUp;st:#27'[A'), {linux,FreeBSD,rxvt}
- (char:0;scan:kbDown;st:#27'[B'), {linux,FreeBSD,rxvt}
- (char:0;scan:kbRight;st:#27'[C'), {linux,FreeBSD,rxvt}
- (char:0;scan:kbLeft;st:#27'[D'), {linux,FreeBSD,rxvt}
- (char:0;scan:kbUp;st:#27'OA'), {xterm}
- (char:0;scan:kbDown;st:#27'OB'), {xterm}
- (char:0;scan:kbRight;st:#27'OC'), {xterm}
- (char:0;scan:kbLeft;st:#27'OD'), {xterm}
- (* Already recognized above as F11!
- (char:0;scan:kbShiftF1;st:#27'[23~'), {rxvt}
- (char:0;scan:kbShiftF2;st:#27'[24~'), {rxvt}
- *)
- (char:0;scan:kbShiftF3;st:#27'[25~'), {linux,rxvt}
- (char:0;scan:kbShiftF4;st:#27'[26~'), {linux,rxvt}
- (char:0;scan:kbShiftF5;st:#27'[28~'), {linux,rxvt}
- (char:0;scan:kbShiftF6;st:#27'[29~'), {linux,rxvt}
- (char:0;scan:kbShiftF7;st:#27'[31~'), {linux,rxvt}
- (char:0;scan:kbShiftF8;st:#27'[32~'), {linux,rxvt}
- (char:0;scan:kbShiftF9;st:#27'[33~'), {linux,rxvt}
- (char:0;scan:kbShiftF10;st:#27'[34~'), {linux,rxvt}
- (char:0;scan:kbShiftF11;st:#27'[23$'), {rxvt}
- (char:0;scan:kbShiftF12;st:#27'[24$'), {rxvt}
- (char:0;scan:kbShiftF1;st:#27'[11;2~'), {konsole in vt420pc mode}
- (char:0;scan:kbShiftF2;st:#27'[12;2~'), {konsole in vt420pc mode}
- (char:0;scan:kbShiftF3;st:#27'[13;2~'), {konsole in vt420pc mode}
- (char:0;scan:kbShiftF4;st:#27'[14;2~'), {konsole in vt420pc mode}
- (char:0;scan:kbShiftF5;st:#27'[15;2~'), {xterm}
- (char:0;scan:kbShiftF6;st:#27'[17;2~'), {xterm}
- (char:0;scan:kbShiftF7;st:#27'[18;2~'), {xterm}
- (char:0;scan:kbShiftF8;st:#27'[19;2~'), {xterm}
- (char:0;scan:kbShiftF9;st:#27'[20;2~'), {xterm}
- (char:0;scan:kbShiftF10;st:#27'[21;2~'), {xterm}
- (char:0;scan:kbShiftF11;st:#27'[23;2~'), {xterm}
- (char:0;scan:kbShiftF12;st:#27'[24;2~'), {xterm}
- (char:0;scan:kbShiftF1;st:#27'O5P'), {xterm}
- (char:0;scan:kbShiftF2;st:#27'O5Q'), {xterm}
- (char:0;scan:kbShiftF3;st:#27'O5R'), {xterm}
- (char:0;scan:kbShiftF4;st:#27'O5S'), {xterm}
- (char:0;scan:kbShiftF1;st:#27'O2P'), {konsole,xterm}
- (char:0;scan:kbShiftF2;st:#27'O2Q'), {konsole,xterm}
- (char:0;scan:kbShiftF3;st:#27'O2R'), {konsole,xterm}
- (char:0;scan:kbShiftF4;st:#27'O2S'), {konsole,xterm}
- (char:0;scan:kbCtrlF1;st:#27'[11;5~'), {none, but expected}
- (char:0;scan:kbCtrlF2;st:#27'[12;5~'), {none, but expected}
- (char:0;scan:kbCtrlF3;st:#27'[13;5~'), {none, but expected}
- (char:0;scan:kbCtrlF4;st:#27'[14;5~'), {none, but expected}
- (char:0;scan:kbCtrlF5;st:#27'[15;5~'), {xterm}
- (char:0;scan:kbCtrlF6;st:#27'[17;5~'), {xterm}
- (char:0;scan:kbCtrlF7;st:#27'[18;5~'), {xterm}
- (char:0;scan:kbCtrlF8;st:#27'[19;5~'), {xterm}
- (char:0;scan:kbCtrlF9;st:#27'[20;5~'), {xterm}
- (char:0;scan:kbCtrlF10;st:#27'[21;5~'), {xterm}
- (char:0;scan:kbCtrlF11;st:#27'[23;5~'), {xterm}
- (char:0;scan:kbCtrlF12;st:#27'[24;5~'), {xterm}
- (char:0;scan:kbCtrlF1;st:#27'[11^'), {rxvt}
- (char:0;scan:kbCtrlF2;st:#27'[12^'), {rxvt}
- (char:0;scan:kbCtrlF3;st:#27'[13^'), {rxvt}
- (char:0;scan:kbCtrlF4;st:#27'[14^'), {rxvt}
- (char:0;scan:kbCtrlF5;st:#27'[15^'), {rxvt}
- (char:0;scan:kbCtrlF6;st:#27'[17^'), {rxvt}
- (char:0;scan:kbCtrlF7;st:#27'[18^'), {rxvt}
- (char:0;scan:kbCtrlF8;st:#27'[19^'), {rxvt}
- (char:0;scan:kbCtrlF9;st:#27'[20^'), {rxvt}
- (char:0;scan:kbCtrlF10;st:#27'[21^'), {rxvt}
- (char:0;scan:kbCtrlF11;st:#27'[23^'), {rxvt}
- (char:0;scan:kbCtrlF12;st:#27'[24^'), {rxvt}
- (char:0;scan:kbShiftIns;st:#27'[2;2~'), {should be the code, but shift+ins
- is paste X clipboard in many
- terminal emulators :(}
- (char:0;scan:kbShiftDel;st:#27'[3;2~'), {xterm,konsole}
- (char:0;scan:kbCtrlIns;st:#27'[2;5~'), {xterm}
- (char:0;scan:kbCtrlDel;st:#27'[3;5~'), {xterm}
- (char:0;scan:kbShiftDel;st:#27'[3$'), {rxvt}
- (char:0;scan:kbCtrlIns;st:#27'[2^'), {rxvt}
- (char:0;scan:kbCtrlDel;st:#27'[3^'), {rxvt}
- (char:0;scan:kbAltF1;st:#27#27'[[A'),
- (char:0;scan:kbAltF2;st:#27#27'[[B'),
- (char:0;scan:kbAltF3;st:#27#27'[[C'),
- (char:0;scan:kbAltF4;st:#27#27'[[D'),
- (char:0;scan:kbAltF5;st:#27#27'[[E'),
- (char:0;scan:kbAltF1;st:#27#27'[11~'), {rxvt}
- (char:0;scan:kbAltF2;st:#27#27'[12~'), {rxvt}
- (char:0;scan:kbAltF3;st:#27#27'[13~'), {rxvt}
- (char:0;scan:kbAltF4;st:#27#27'[14~'), {rxvt}
- (char:0;scan:kbAltF5;st:#27#27'[15~'), {rxvt}
- (char:0;scan:kbAltF6;st:#27#27'[17~'), {rxvt}
- (char:0;scan:kbAltF7;st:#27#27'[18~'), {rxvt}
- (char:0;scan:kbAltF8;st:#27#27'[19~'), {rxvt}
- (char:0;scan:kbAltF9;st:#27#27'[20~'), {rxvt}
- (char:0;scan:kbAltF10;st:#27#27'[21~'), {rxvt}
- (char:0;scan:kbAltF11;st:#27#27'[23~'), {rxvt}
- (char:0;scan:kbAltF12;st:#27#27'[24~'), {rxvt}
- (char:0;scan:kbAltF1;st:#27#27'OP'), {xterm}
- (char:0;scan:kbAltF2;st:#27#27'OQ'), {xterm}
- (char:0;scan:kbAltF3;st:#27#27'OR'), {xterm}
- (char:0;scan:kbAltF4;st:#27#27'OS'), {xterm}
- (char:0;scan:kbAltF5;st:#27#27'Ot'), {xterm}
- (char:0;scan:kbAltF6;st:#27#27'Ou'), {xterm}
- (char:0;scan:kbAltF7;st:#27#27'Ov'), {xterm}
- (char:0;scan:kbAltF8;st:#27#27'Ol'), {xterm}
- (char:0;scan:kbAltF9;st:#27#27'Ow'), {xterm}
- (char:0;scan:kbAltF10;st:#27#27'Ox'), {xterm}
- (char:0;scan:kbAltF11;st:#27#27'Oy'), {xterm}
- (char:0;scan:kbAltF12;st:#27#27'Oz'), {xterm}
- (char:0;scan:kbAltF1;st:#27'O3P'), {xterm on FreeBSD}
- (char:0;scan:kbAltF2;st:#27'O3Q'), {xterm on FreeBSD}
- (char:0;scan:kbAltF3;st:#27'O3R'), {xterm on FreeBSD}
- (char:0;scan:kbAltF4;st:#27'O3S'), {xterm on FreeBSD}
- (char:0;scan:kbAltF5;st:#27'[15;3~'), {xterm on FreeBSD}
- (char:0;scan:kbAltF6;st:#27'[17;3~'), {xterm on FreeBSD}
- (char:0;scan:kbAltF7;st:#27'[18;3~'), {xterm on FreeBSD}
- (char:0;scan:kbAltF8;st:#27'[19;3~'), {xterm on FreeBSD}
- (char:0;scan:kbAltF9;st:#27'[20;3~'), {xterm on FreeBSD}
- (char:0;scan:kbAltF10;st:#27'[21;3~'), {xterm on FreeBSD}
- (char:0;scan:kbAltF11;st:#27'[23;3~'), {xterm on FreeBSD}
- (char:0;scan:kbAltF12;st:#27'[24;3~'), {xterm on FreeBSD}
- (char:0;scan:kbShiftTab;st:#27#9), {linux - 'Meta_Tab'}
- (char:0;scan:kbShiftTab;st:#27'[Z'),
- (char:0;scan:kbShiftUp;st:#27'[1;2A'), {xterm}
- (char:0;scan:kbShiftDown;st:#27'[1;2B'), {xterm}
- (char:0;scan:kbShiftRight;st:#27'[1;2C'), {xterm}
- (char:0;scan:kbShiftLeft;st:#27'[1;2D'), {xterm}
- (char:0;scan:kbShiftUp;st:#27'[a'), {rxvt}
- (char:0;scan:kbShiftDown;st:#27'[b'), {rxvt}
- (char:0;scan:kbShiftRight;st:#27'[c'), {rxvt}
- (char:0;scan:kbShiftLeft;st:#27'[d'), {rxvt}
- (char:0;scan:kbShiftEnd;st:#27'[1;2F'), {xterm}
- (char:0;scan:kbShiftEnd;st:#27'[8$'), {rxvt}
- (char:0;scan:kbShiftHome;st:#27'[1;2H'), {xterm}
- (char:0;scan:kbShiftHome;st:#27'[7$'), {rxvt}
- (char:0;scan:kbCtrlUp;st:#27'[1;5A'), {xterm}
- (char:0;scan:kbCtrlDown;st:#27'[1;5B'), {xterm}
- (char:0;scan:kbCtrlRight;st:#27'[1;5C'), {xterm}
- (char:0;scan:kbCtrlLeft;st:#27'[1;5D'), {xterm}
- (char:0;scan:kbCtrlUp;st:#27'[Oa'), {rxvt}
- (char:0;scan:kbCtrlDown;st:#27'[Ob'), {rxvt}
- (char:0;scan:kbCtrlRight;st:#27'[Oc'), {rxvt}
- (char:0;scan:kbCtrlLeft;st:#27'[Od'), {rxvt}
- (char:0;scan:kbCtrlEnd;st:#27'[1;5F'), {xterm}
- (char:0;scan:kbCtrlEnd;st:#27'[8^'), {rxvt}
- (char:0;scan:kbCtrlHome;st:#27'[1;5H'), {xterm}
- (char:0;scan:kbCtrlHome;st:#27'[7^'), {rxvt}
- (char:0;scan:kbAltUp;st:#27#27'[A'), {rxvt}
- (char:0;scan:kbAltDown;st:#27#27'[B'), {rxvt}
- (char:0;scan:kbAltLeft;st:#27#27'[D'), {rxvt}
- (char:0;scan:kbAltRight;st:#27#27'[C'), {rxvt}
- {$ifdef HAIKU}
- (char:0;scan:kbAltUp;st:#27#27'OA'),
- (char:0;scan:kbAltDown;st:#27#27'OB'),
- (char:0;scan:kbAltRight;st:#27#27'OC'),
- {$else}
- (char:0;scan:kbAltUp;st:#27'OA'),
- (char:0;scan:kbAltDown;st:#27'OB'),
- (char:0;scan:kbAltRight;st:#27'OC'),
- {$endif}
- (char:0;scan:kbAltLeft;st:#27#27'OD'),
- (char:0;scan:kbAltPgUp;st:#27#27'[5~'), {rxvt}
- (char:0;scan:kbAltPgDn;st:#27#27'[6~'), {rxvt}
- (char:0;scan:kbAltEnd;st:#27#27'[4~'),
- (char:0;scan:kbAltEnd;st:#27#27'[8~'), {rxvt}
- (char:0;scan:kbAltHome;st:#27#27'[1~'),
- (char:0;scan:kbAltHome;st:#27#27'[7~'), {rxvt}
- (char:0;scan:kbAltIns;st:#27#27'[2~'), {rxvt}
- (char:0;scan:kbAltDel;st:#27#27'[3~'), {rxvt}
- { xterm default values }
- { xterm alternate default values }
- { ignored sequences }
- (char:0;scan:0;st:#27'[?1;0c'),
- (char:0;scan:0;st:#27'[?1l'),
- (char:0;scan:0;st:#27'[?1h'),
- (char:0;scan:0;st:#27'[?1;2c'),
- (char:0;scan:0;st:#27'[?7l'),
- (char:0;scan:0;st:#27'[?7h')
- );
- procedure LoadDefaultSequences;
- var i:cardinal;
- begin
- AddSpecialSequence(#27'[M',@GenMouseEvent);
- {Unix backspace/delete hell... Is #127 a backspace or delete?}
- if copy(fpgetenv('TERM'),1,4)='cons' then
- begin
- {FreeBSD is until now only terminal that uses it for delete.}
- DoAddSequence(#127,0,kbDel); {Delete}
- DoAddSequence(#27#127,0,kbAltDel); {Alt+delete}
- end
- else
- begin
- DoAddSequence(#127,8,0); {Backspace}
- DoAddSequence(#27#127,0,kbAltBack); {Alt+backspace}
- end;
- { all Esc letter }
- for i:=low(key_sequences) to high(key_sequences) do
- with key_sequences[i] do
- DoAddSequence(st,char,scan);
- end;
- function RawReadKey:char;
- var
- fdsin : tfdSet;
- begin
- {Check Buffer first}
- if KeySend<>KeyPut then
- begin
- RawReadKey:=PopKey;
- exit;
- end;
- {Wait for Key}
- if not sysKeyPressed then
- begin
- fpFD_ZERO (fdsin);
- fpFD_SET (StdInputHandle,fdsin);
- fpSelect (StdInputHandle+1,@fdsin,nil,nil,nil);
- end;
- RawReadKey:=ttyRecvChar;
- end;
- function RawReadString : String;
- var
- ch : char;
- fdsin : tfdSet;
- St : String;
- begin
- St:=RawReadKey;
- fpFD_ZERO (fdsin);
- fpFD_SET (StdInputHandle,fdsin);
- Repeat
- if inhead=intail then
- fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
- if SysKeyPressed then
- ch:=ttyRecvChar
- else
- ch:=#0;
- if ch<>#0 then
- St:=St+ch;
- Until ch=#0;
- RawReadString:=St;
- end;
- function ReadKey(var IsAlt : boolean):char;
- var
- ch : char;
- fdsin : tfdSet;
- store : array [0..8] of char;
- arrayind : byte;
- NPT,NNPT : PTreeElement;
- procedure RestoreArray;
- var
- i : byte;
- begin
- for i:=0 to arrayind-1 do
- PushKey(store[i]);
- end;
- begin
- IsAlt:=false;
- {Check Buffer first}
- if KeySend<>KeyPut then
- begin
- ReadKey:=PopKey;
- exit;
- end;
- {Wait for Key}
- if not sysKeyPressed then
- begin
- fpFD_ZERO (fdsin);
- fpFD_SET (StdInputHandle,fdsin);
- fpSelect (StdInputHandle+1,@fdsin,nil,nil,nil);
- end;
- ch:=ttyRecvChar;
- NPT:=RootTree[ch];
- if not assigned(NPT) then
- PushKey(ch)
- else
- begin
- fpFD_ZERO(fdsin);
- fpFD_SET(StdInputHandle,fdsin);
- store[0]:=ch;
- arrayind:=1;
- while assigned(NPT) and syskeypressed do
- begin
- if inhead=intail then
- fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
- ch:=ttyRecvChar;
- if (ch=#27) and double_esc_hack_enabled then
- begin
- {This is the same hack as in findsequence; see findsequence for
- explanation.}
- ch:=ttyrecvchar;
- {Alt+O cannot be used in this situation, it can be a function key.}
- if not(ch in ['a'..'z','A'..'N','P'..'Z','0'..'9','-','+','_','=']) then
- begin
- if intail=0 then
- intail:=insize
- else
- dec(intail);
- inbuf[intail]:=ch;
- ch:=#27;
- end
- else
- begin
- write(#27'[?1036l');
- double_esc_hack_enabled:=false;
- end;
- end;
- NNPT:=FindChild(ord(ch),NPT);
- if assigned(NNPT) then
- begin
- NPT:=NNPT;
- if NPT^.CanBeTerminal and
- assigned(NPT^.SpecialHandler) then
- break;
- End;
- if ch<>#0 then
- begin
- store[arrayind]:=ch;
- inc(arrayind);
- end;
- if not assigned(NNPT) then
- begin
- if ch<>#0 then
- begin
- { Put that unused char back into InBuf }
- If InTail=0 then
- InTail:=InSize-1
- else
- Dec(InTail);
- InBuf[InTail]:=ch;
- end;
- break;
- end;
- end;
- if assigned(NPT) and NPT^.CanBeTerminal then
- begin
- if assigned(NPT^.SpecialHandler) then
- begin
- NPT^.SpecialHandler;
- PushExt(0);
- end
- else if NPT^.CharValue<>0 then
- PushKey(chr(NPT^.CharValue))
- else if NPT^.ScanValue<>0 then
- PushExt(NPT^.ScanValue);
- end
- else
- RestoreArray;
- end
- {$ifdef logging}
- writeln(f);
- {$endif logging}
- ;
- ReadKey:=PopKey;
- End;
- {$ifdef linux}
- function ShiftState:byte;
- var arg:longint;
- begin
- shiftstate:=0;
- arg:=6;
- if fpioctl(StdInputHandle,TIOCLINUX,@arg)=0 then
- begin
- if (arg and 8)<>0 then
- shiftstate:=kbAlt;
- if (arg and 4)<>0 then
- inc(shiftstate,kbCtrl);
- { 2 corresponds to AltGr so set both kbAlt and kbCtrl PM }
- if (arg and 2)<>0 then
- shiftstate:=shiftstate or (kbAlt or kbCtrl);
- if (arg and 1)<>0 then
- inc(shiftstate,kbShift);
- end;
- end;
- procedure force_linuxtty;
- var s:string[15];
- handle:sizeint;
- thistty:string;
- begin
- is_console:=false;
- if vcs_device<>-1 then
- begin
- { running on a tty, find out whether locally or remotely }
- thistty:=ttyname(stdinputhandle);
- if (copy(thistty,1,8)<>'/dev/tty') or not (thistty[9] in ['0'..'9']) then
- begin
- {Running from Midnight Commander or something... Bypass it.}
- str(vcs_device,s);
- handle:=fpopen('/dev/tty'+s,O_RDWR);
- fpioctl(stdinputhandle,TIOCNOTTY,nil);
- {This will currently only work when the user is root :(}
- fpioctl(handle,TIOCSCTTY,nil);
- if errno<>0 then
- exit;
- fpclose(stdinputhandle);
- fpclose(stdoutputhandle);
- fpclose(stderrorhandle);
- fpdup2(handle,stdinputhandle);
- fpdup2(handle,stdoutputhandle);
- fpdup2(handle,stderrorhandle);
- fpclose(handle);
- end;
- is_console:=true;
- end;
- end;
- {$endif linux}
- { Exported functions }
- procedure SysInitKeyboard;
- begin
- SetRawMode(true);
- {$ifdef logging}
- assign(f,'keyboard.log');
- rewrite(f);
- {$endif logging}
- {$ifdef linux}
- force_linuxtty;
- prepare_patching;
- patchkeyboard;
- if is_console then
- install_vt_handler
- else
- begin
- {$endif}
- { default for Shift prefix is ^ A}
- if ShiftPrefix = 0 then
- ShiftPrefix:=1;
- {default for Alt prefix is ^Z }
- if AltPrefix=0 then
- AltPrefix:=26;
- { default for Ctrl Prefix is ^W }
- if CtrlPrefix=0 then
- CtrlPrefix:=23;
- if copy(fpgetenv('TERM'),1,5)='xterm' then
- {The alt key should generate an escape prefix. Save the old setting
- make make it send that escape prefix.}
- begin
- write(#27'[?1036s'#27'[?1036h');
- double_esc_hack_enabled:=true;
- end;
- {$ifdef linux}
- end;
- {$endif}
- LoadDefaultSequences;
- { LoadTerminfoSequences;}
- end;
- procedure SysDoneKeyboard;
- begin
- {$ifdef linux}
- if is_console then
- unpatchkeyboard;
- {$endif linux}
- if copy(fpgetenv('TERM'),1,5)='xterm' then
- {Restore the old alt key behaviour.}
- write(#27'[?1036r');
- SetRawMode(false);
- FreeTree;
- {$ifdef logging}
- close(f);
- {$endif logging}
- end;
- function SysGetKeyEvent: TKeyEvent;
- function EvalScan(b:byte):byte;
- const
- DScan:array[0..31] of byte = (
- $39, $02, $28, $04, $05, $06, $08, $28,
- $0A, $0B, $09, $0D, $33, $0C, $34, $35,
- $0B, $02, $03, $04, $05, $06, $07, $08,
- $09, $0A, $27, $27, $33, $0D, $34, $35);
- LScan:array[0..31] of byte = (
- $29, $1E, $30, $2E, $20, $12, $21, $22,
- $23, $17, $24, $25, $26, $32, $31, $18,
- $19, $10, $13, $1F, $14, $16, $2F, $11,
- $2D, $15, $2C, $1A, $2B, $1B, $29, $0C);
- begin
- if (b and $E0)=$20 { digits / leters } then
- EvalScan:=DScan[b and $1F]
- else
- case b of
- $08:EvalScan:=$0E; { backspace }
- $09:EvalScan:=$0F; { TAB }
- $0D:EvalScan:=$1C; { CR }
- $1B:EvalScan:=$01; { esc }
- $40:EvalScan:=$03; { @ }
- $5E:EvalScan:=$07; { ^ }
- $60:EvalScan:=$29; { ` }
- else
- EvalScan:=LScan[b and $1F];
- end;
- end;
- function EvalScanZ(b:byte):byte;
- begin
- EvalScanZ:=b;
- if b in [$3B..$44] { F1..F10 -> Alt-F1..Alt-F10} then
- EvalScanZ:=b+$2D;
- end;
- const
- {kbHome, kbUp, kbPgUp,Missing, kbLeft,
- kbCenter, kbRight, kbAltGrayPlus, kbend,
- kbDown, kbPgDn, kbIns, kbDel }
- CtrlArrow : array [kbHome..kbDel] of byte =
- {($77,$8d,$84,$8e,$73,$8f,$74,$90,$75,$91,$76);}
- (kbCtrlHome,kbCtrlUp,kbCtrlPgUp,kbNoKey,kbCtrlLeft,
- kbCtrlCenter,kbCtrlRight,kbAltGrayPlus,kbCtrlEnd,
- kbCtrlDown,kbCtrlPgDn,kbCtrlIns,kbCtrlDel);
- AltArrow : array [kbHome..kbDel] of byte =
- (kbAltHome,kbAltUp,kbAltPgUp,kbNoKey,kbAltLeft,
- kbCenter,kbAltRight,kbAltGrayPlus,kbAltEnd,
- kbAltDown,kbAltPgDn,kbAltIns,kbAltDel);
- ShiftArrow : array [kbShiftUp..kbShiftEnd] of byte =
- (kbUp,kbLeft,kbRight,kbDown,kbHome,kbEnd);
- var
- MyScan:byte;
- MyChar : char;
- EscUsed,AltPrefixUsed,CtrlPrefixUsed,ShiftPrefixUsed,IsAlt,Again : boolean;
- SState:byte;
- begin {main}
- MyChar:=Readkey(IsAlt);
- MyScan:=ord(MyChar);
- {$ifdef linux}
- if is_console then
- SState:=ShiftState
- else
- {$endif}
- Sstate:=0;
- CtrlPrefixUsed:=false;
- AltPrefixUsed:=false;
- ShiftPrefixUsed:=false;
- EscUsed:=false;
- if IsAlt then
- SState:=SState or kbAlt;
- repeat
- again:=false;
- if Mychar=#0 then
- begin
- MyScan:=ord(ReadKey(IsAlt));
- if myscan=$01 then
- mychar:=#27;
- { Handle Ctrl-<x>, but not AltGr-<x> }
- if ((SState and kbCtrl)<>0) and ((SState and kbAlt) = 0) then
- case MyScan of
- kbShiftTab: MyScan := kbCtrlTab;
- kbHome..kbDel : { cArrow }
- MyScan:=CtrlArrow[MyScan];
- kbF1..KbF10 : { cF1-cF10 }
- MyScan:=MyScan+kbCtrlF1-kbF1;
- kbF11..KbF12 : { cF11-cF12 }
- MyScan:=MyScan+kbCtrlF11-kbF11;
- end
- { Handle Alt-<x>, but not AltGr }
- else if ((SState and kbAlt)<>0) and ((SState and kbCtrl) = 0) then
- case MyScan of
- kbShiftTab: MyScan := kbAltTab;
- kbHome..kbDel : { AltArrow }
- MyScan:=AltArrow[MyScan];
- kbF1..KbF10 : { aF1-aF10 }
- MyScan:=MyScan+kbAltF1-kbF1;
- kbF11..KbF12 : { aF11-aF12 }
- MyScan:=MyScan+kbAltF11-kbF11;
- end
- else if (SState and kbShift)<>0 then
- case MyScan of
- kbIns: MyScan:=kbShiftIns;
- kbDel: MyScan:=kbShiftDel;
- kbF1..KbF10 : { sF1-sF10 }
- MyScan:=MyScan+kbShiftF1-kbF1;
- kbF11..KbF12 : { sF11-sF12 }
- MyScan:=MyScan+kbShiftF11-kbF11;
- end;
- if myscan in [kbShiftUp..kbShiftEnd] then
- begin
- myscan:=ShiftArrow[myscan];
- sstate:=sstate or kbshift;
- end;
- if myscan=kbAltBack then
- sstate:=sstate or kbalt;
- if (MyChar<>#0) or (MyScan<>0) or (SState<>0) then
- SysGetKeyEvent:=$3000000 or ord(MyChar) or (MyScan shl 8) or (SState shl 16)
- else
- SysGetKeyEvent:=0;
- exit;
- end
- else if MyChar=#27 then
- begin
- if EscUsed then
- SState:=SState and not kbAlt
- else
- begin
- SState:=SState or kbAlt;
- Again:=true;
- EscUsed:=true;
- end;
- end
- else if (AltPrefix<>0) and (MyChar=chr(AltPrefix)) then
- begin { ^Z - replace Alt for Linux OS }
- if AltPrefixUsed then
- begin
- SState:=SState and not kbAlt;
- end
- else
- begin
- AltPrefixUsed:=true;
- SState:=SState or kbAlt;
- Again:=true;
- end;
- end
- else if (CtrlPrefix<>0) and (MyChar=chr(CtrlPrefix)) then
- begin
- if CtrlPrefixUsed then
- SState:=SState and not kbCtrl
- else
- begin
- CtrlPrefixUsed:=true;
- SState:=SState or kbCtrl;
- Again:=true;
- end;
- end
- else if (ShiftPrefix<>0) and (MyChar=chr(ShiftPrefix)) then
- begin
- if ShiftPrefixUsed then
- SState:=SState and not kbShift
- else
- begin
- ShiftPrefixUsed:=true;
- SState:=SState or kbShift;
- Again:=true;
- end;
- end;
- if not again then
- begin
- MyScan:=EvalScan(ord(MyChar));
- if ((SState and kbCtrl)<>0) and ((SState and kbAlt) = 0) then
- begin
- if MyChar=#9 then
- begin
- MyChar:=#0;
- MyScan:=kbCtrlTab;
- end;
- end
- else if ((SState and kbAlt)<>0) and ((SState and kbCtrl) = 0) then
- begin
- if MyChar=#9 then
- begin
- MyChar:=#0;
- MyScan:=kbAltTab;
- end
- else
- begin
- if MyScan in [$02..$0D] then
- inc(MyScan,$76);
- MyChar:=chr(0);
- end;
- end
- else if (SState and kbShift)<>0 then
- if MyChar=#9 then
- begin
- MyChar:=#0;
- MyScan:=kbShiftTab;
- end;
- end
- else
- begin
- MyChar:=Readkey(IsAlt);
- MyScan:=ord(MyChar);
- if IsAlt then
- SState:=SState or kbAlt;
- end;
- until not Again;
- if (MyChar<>#0) or (MyScan<>0) or (SState<>0) then
- SysGetKeyEvent:=$3000000 or ord(MyChar) or (MyScan shl 8) or (SState shl 16)
- else
- SysGetKeyEvent:=0;
- end;
- function SysPollKeyEvent: TKeyEvent;
- var
- KeyEvent : TKeyEvent;
- begin
- if keypressed then
- begin
- KeyEvent:=SysGetKeyEvent;
- PutKeyEvent(KeyEvent);
- SysPollKeyEvent:=KeyEvent
- end
- else
- SysPollKeyEvent:=0;
- end;
- function SysGetShiftState : Byte;
- begin
- {$ifdef linux}
- if is_console then
- SysGetShiftState:=ShiftState
- else
- {$else}
- SysGetShiftState:=0;
- {$endif}
- end;
- procedure RestoreStartMode;
- begin
- TCSetAttr(1,TCSANOW,StartTio);
- end;
- const
- SysKeyboardDriver : TKeyboardDriver = (
- InitDriver : @SysInitKeyBoard;
- DoneDriver : @SysDoneKeyBoard;
- GetKeyevent : @SysGetKeyEvent;
- PollKeyEvent : @SysPollKeyEvent;
- GetShiftState : @SysGetShiftState;
- TranslateKeyEvent : Nil;
- TranslateKeyEventUnicode : Nil;
- );
- begin
- SetKeyBoardDriver(SysKeyBoardDriver);
- TCGetAttr(1,StartTio);
- end.
|