unit ATSynEdit_Keymap; {$mode objfpc}{$H+} //{$define test_correct_keynames} interface uses Classes, SysUtils, Forms; const cMaxKeyCombo = 3; //3 must be enougth for everybody.. type TATKeyArray = array[0..Pred(cMaxKeyCombo)] of TShortcut; function KeyArrayToString(const K: TATKeyArray): string; function KeyArraysEqualNotEmpty(const a1, a2: TATKeyArray): boolean; function KeyArrayLength(const K: TATKeyArray): integer; type { TATKeymapItem } TATKeymapItem = class public Command: integer; Name: string; Keys1, Keys2: TATKeyArray; end; type { TATKeymap } TATKeymap = class private FList: TList; FHistory: TATKeyArray; function GetItem(N: integer): TATKeymapItem; procedure ClearHistory; procedure AddToHistory(sh: TShortcut); function IsMatchedKeys(const AKeys: TATKeyArray; AKey: TShortcut; AAllowOneKey: boolean): boolean; public constructor Create; destructor Destroy; override; procedure Clear; function Count: integer; function IsIndexValid(N: integer): boolean; property Items[N: integer]: TATKeymapItem read GetItem; default; procedure Add(ACmd: integer; const AName: string; const AKeys1, AKeys2: array of string); procedure Delete(N: integer); function IndexOf(ACmd: integer): integer; function GetShortcutFromCommand(ACode: integer): TShortcut; function GetCommandFromShortcut(AKey: TShortcut): integer; end; implementation uses Math, LCLProc, Dialogs; function KeyArrayLength(const K: TATKeyArray): integer; var i: integer; begin Result:= 0; for i:= Low(K) to High(K) do if K[i]<>0 then Inc(Result); end; { TATKeymap } constructor TATKeymap.Create; begin FList:= TList.Create; ClearHistory; end; destructor TATKeymap.Destroy; begin ClearHistory; Clear; FreeAndNil(FList); inherited; end; function TATKeymap.GetItem(N: integer): TATKeymapItem; begin if IsIndexValid(N) then Result:= TATKeymapItem(FList[N]) else Result:= nil; end; procedure TATKeymap.Clear; var i: integer; begin for i:= FList.Count-1 downto 0 do TObject(FList[i]).Free; FList.Clear; end; function TATKeymap.Count: integer; begin Result:= FList.Count; end; function TATKeymap.IsIndexValid(N: integer): boolean; begin Result:= (N>=0) and (N0 then AddToHistory(AKey); end; function TATKeymap.IsMatchedKeys(const AKeys: TATKeyArray; AKey: TShortcut; AAllowOneKey: boolean): boolean; //function called first for all items with Allow=false (for combos) //if not found, called for all items with Allow=true (for single keys) var LenThis, LenStack, IndexStack, i: integer; begin Result:= false; LenThis:= KeyArrayLength(AKeys); if LenThis=0 then Exit; if LenThis=1 then begin Result:= AAllowOneKey and (AKeys[0]=AKey); Exit end; //AKey is last in combo AKeys? if AKeys[LenThis-1]<>AKey then Exit; //stack filled? LenStack:= KeyArrayLength(FHistory); if LenStack=Low(FHistory)) and (IndexStack<=High(FHistory)) then if AKeys[i]<>FHistory[IndexStack] then begin //showmessage('no match: check items'); Exit; end; end; Result:= true; end; procedure TATKeymap.ClearHistory; begin FillChar(FHistory, Sizeof(FHistory), 0); end; procedure TATKeymap.AddToHistory(sh: TShortcut); var len: integer; begin len:= KeyArrayLength(FHistory); if len>=Length(FHistory) then begin ClearHistory; len:= KeyArrayLength(FHistory); end; FHistory[len]:= sh; end; function KeyArrayToString(const K: TATKeyArray): string; var i: integer; begin result:= ''; for i:= Low(K) to High(K) do if K[i]<>0 then begin if result<>'' then result:= result+' * '; result:= result+ShortcutToText(K[i]); end; end; function KeyArraysEqualNotEmpty(const a1, a2: TATKeyArray): boolean; var i: integer; begin Result:= true; if a1[0]=0 then Exit(false); if a2[0]=0 then Exit(false); for i:= Low(a1) to High(a1) do if a1[i]<>a2[i] then Exit(false); end; end.