ADD: Support for shortcuts sequences, i.e., commands can be executed after two or more consecutive shortcuts.

This commit is contained in:
cobines 2012-04-05 05:23:22 +00:00
commit bb006cbb99
10 changed files with 765 additions and 413 deletions

View file

@ -207,7 +207,7 @@ begin
begin
hotkey := HMForm.Hotkeys[i];
if hotkey.Command = cHotKeyCommand then
FHotKeyList.AddObject(hotkey.Shortcut, hotkey);
FHotKeyList.AddObject(hotkey.Shortcuts[0], hotkey);// TODO fix for multiple hotkeys
end;
end;
end;
@ -522,13 +522,20 @@ end;
procedure TfrmConfigToolBar.btnClearHotKeyClick(Sender: TObject);
var
HMForm: THMForm;
Hotkey: THotkey;
Shortcuts: array of String = nil;
begin
edtHotKeys.Text:= EmptyStr;
btnClearHotKey.Enabled:= False;
ktbBar.SetButtonX(LastToolButton, MiskX, EmptyStr);
HMForm := HotMan.Forms.Find('Main');
if Assigned(HMForm) then
HMForm.Hotkeys.Delete(GetHotKey(LastToolButton));
begin
// TODO find by multiple shortcuts
AddString(Shortcuts, GetHotKey(LastToolButton));
Hotkey := HMForm.Hotkeys.Find(Shortcuts);
HMForm.Hotkeys.Remove(Hotkey);
end;
end;
procedure TfrmConfigToolBar.edtHotKeysKeyDown(Sender: TObject; var Key: Word;
@ -536,6 +543,7 @@ procedure TfrmConfigToolBar.edtHotKeysKeyDown(Sender: TObject; var Key: Word;
var
sShortCut: String;
Shortcut: TShortCut;
Shortcuts: array of String = nil;
HMForm: THMForm;
hotkey: THotkey;
begin
@ -550,10 +558,11 @@ begin
HMForm := HotMan.Forms.Find('Main');
if Assigned(HMForm) then
begin
hotkey := HMForm.Hotkeys.Find(sShortCut);
AddString(Shortcuts, sShortCut);
hotkey := HMForm.Hotkeys.FindByBeginning(Shortcuts, True);
if Assigned(hotkey) then
begin
ShowHint(edtHotKeys, Format(rsOptHotkeysShortCutUsedText1, [sShortCut, hotkey.Command]));
ShowHint(edtHotKeys, Format(rsOptHotkeysShortCutUsedText1, [ShortcutsToText(Shortcuts), hotkey.Command]));
end;
end;
end;
@ -569,13 +578,14 @@ end;
procedure TfrmConfigToolBar.SetButtonHotKey;
var
sShortCut: String;
Shortcuts: array of String = nil;
HMForm: THMForm;
hotkey: THotkey;
//< local function for add hot key,
procedure AddHotKeyButton(Hotkeys: THotkeys);
begin
Hotkeys.Add(sShortCut, cHotKeyCommand, [sShortCut]);
Hotkeys.Add(Shortcuts, [sShortCut], cHotKeyCommand);
ktbBar.SetButtonX(LastToolButton, MiskX, edtHotKeys.Text);
end;
@ -585,9 +595,10 @@ begin
else
begin
sShortCut := edtHotKeys.Text;
AddString(Shortcuts, sShortCut);
HMForm := HotMan.Forms.FindOrCreate('Main');
hotkey := HMForm.Hotkeys.Find(sShortCut);
hotkey := HMForm.Hotkeys.FindByBeginning(Shortcuts, True);
if not Assigned(hotkey) then
begin
AddHotKeyButton(HMForm.Hotkeys);
@ -598,12 +609,12 @@ begin
if (hotkey.Command = cHotKeyCommand) or
(MessageDlg(rsOptHotkeysShortCutUsed,
Format(rsOptHotkeysShortCutUsedText1,
[sShortCut, hotkey.Command]) + LineEnding +
[ShortcutsToText(Shortcuts), hotkey.Command]) + LineEnding +
Format(rsOptHotkeysShortCutUsedText2,
[cHotKeyCommand]),
mtConfirmation, mbYesNo, 0) = mrYes) then
begin
HMForm.Hotkeys.Delete(sShortCut);
HMForm.Hotkeys.Remove(hotkey);
AddHotKeyButton(HMForm.Hotkeys);
end;
end;

View file

@ -93,7 +93,7 @@ implementation
{$R *.lfm}
uses
fMain, LCLType, LCLVersion, uGlobs, uLng, uHotkeyManager;
fMain, LCLType, LCLVersion, uGlobs, uLng, uHotkeyManager, uDCUtils;
const
HotkeysCategory = 'Copy/Move Dialog';
@ -362,7 +362,7 @@ begin
Hotkey := HMForm.Hotkeys.FindByCommand('cm_AddToQueue');
if Assigned(Hotkey) then
btnAddToQueue.Caption := btnAddToQueue.Caption + ' (' + Hotkey.Shortcut + ')';
btnAddToQueue.Caption := btnAddToQueue.Caption + ' (' + ShortcutsToText(Hotkey.Shortcuts) + ')';
end;
procedure TfrmCopyDlg.FormDestroy(Sender: TObject);
@ -405,4 +405,4 @@ end;
initialization
TFormCommands.RegisterCommandsForm(TfrmCopyDlg, HotkeysCategory, @rsHotkeyCategoryCopyMoveDialog);
end.
end.

View file

@ -1,54 +1,57 @@
object frmEditHotkey: TfrmEditHotkey
Left = 337
Height = 450
Height = 465
Top = 120
Width = 464
ActiveControl = edtHotKey
Width = 458
BorderIcons = [biSystemMenu]
ClientHeight = 450
ClientWidth = 464
ClientHeight = 465
ClientWidth = 458
Constraints.MinHeight = 200
Constraints.MinWidth = 200
OnCreate = FormCreate
OnShow = FormShow
Position = poScreenCenter
LCLVersion = '1.1'
object lblHotKey: TLabel
LCLVersion = '0.9.31'
object lblShortcuts: TLabel
AnchorSideLeft.Control = edtParameters
AnchorSideTop.Control = Owner
Left = 8
Height = 22
Top = 6
Width = 55
Width = 69
BorderSpacing.Top = 6
Caption = 'Hot key:'
Caption = 'Shortcuts:'
ParentColor = False
end
object edtHotKey: TEdit
object pnlShortcuts: TPanel
AnchorSideLeft.Control = edtParameters
AnchorSideTop.Control = lblHotKey
AnchorSideTop.Control = btnAddShortcut
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = edtParameters
AnchorSideRight.Side = asrBottom
Left = 8
Height = 29
Height = 0
Top = 28
Width = 448
Width = 442
Anchors = [akTop, akLeft, akRight]
OnKeyDown = edtHotKeyKeyDown
OnKeyPress = edtHotKeyKeyPress
AutoSize = True
BevelOuter = bvNone
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
ChildSizing.EnlargeVertical = crsHomogenousChildResize
ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 1
TabOrder = 0
end
object lblHotKeyConflict: TLabel
AnchorSideLeft.Control = edtParameters
AnchorSideTop.Control = edtHotKey
AnchorSideTop.Control = pnlShortcuts
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = edtParameters
AnchorSideRight.Side = asrBottom
Left = 8
Height = 1
Top = 61
Width = 448
Top = 32
Width = 442
Anchors = [akTop, akLeft, akRight]
BorderSpacing.Top = 4
BorderSpacing.Bottom = 4
@ -64,7 +67,7 @@ object frmEditHotkey: TfrmEditHotkey
AnchorSideTop.Side = asrBottom
Left = 8
Height = 22
Top = 68
Top = 39
Width = 247
BorderSpacing.Top = 6
Caption = 'Parameters (each in a separate line):'
@ -78,9 +81,9 @@ object frmEditHotkey: TfrmEditHotkey
AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = btnShowCommandHelp
Left = 8
Height = 228
Top = 90
Width = 448
Height = 272
Top = 61
Width = 442
HelpType = htKeyword
Anchors = [akTop, akLeft, akRight, akBottom]
BorderSpacing.Left = 8
@ -97,8 +100,8 @@ object frmEditHotkey: TfrmEditHotkey
AnchorSideBottom.Control = cgHKControls
Left = 8
Height = 10
Top = 322
Width = 448
Top = 337
Width = 442
Anchors = [akLeft, akRight, akBottom]
AutoSize = True
BorderSpacing.Top = 4
@ -112,8 +115,8 @@ object frmEditHotkey: TfrmEditHotkey
AnchorSideBottom.Control = btnOK
Left = 8
Height = 68
Top = 332
Width = 448
Top = 347
Width = 442
Anchors = [akLeft, akRight, akBottom]
AutoFill = True
AutoSize = True
@ -136,7 +139,7 @@ object frmEditHotkey: TfrmEditHotkey
AnchorSideBottom.Side = asrBottom
Left = 8
Height = 40
Top = 404
Top = 419
Width = 120
Anchors = [akLeft, akBottom]
AutoSize = True
@ -155,9 +158,9 @@ object frmEditHotkey: TfrmEditHotkey
AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 336
Left = 330
Height = 40
Top = 404
Top = 419
Width = 120
Anchors = [akRight, akBottom]
AutoSize = True
@ -170,4 +173,33 @@ object frmEditHotkey: TfrmEditHotkey
ModalResult = 2
TabOrder = 5
end
object btnAddShortcut: TSpeedButton
AnchorSideTop.Control = btnRemoveShortcut
AnchorSideRight.Control = btnRemoveShortcut
Left = 406
Height = 22
Hint = 'Add new shortcut to sequence'
Top = 6
Width = 22
Anchors = [akTop, akRight]
NumGlyphs = 0
OnClick = btnAddShortcutClick
ShowHint = True
ParentShowHint = False
end
object btnRemoveShortcut: TSpeedButton
AnchorSideTop.Control = lblShortcuts
AnchorSideRight.Control = edtParameters
AnchorSideRight.Side = asrBottom
Left = 428
Height = 22
Hint = 'Remove last shortcut from sequence'
Top = 6
Width = 22
Anchors = [akTop, akRight]
NumGlyphs = 0
OnClick = btnRemoveShortcutClick
ShowHint = True
ParentShowHint = False
end
end

View file

@ -1,3 +1,5 @@
TFRMEDITHOTKEY.LBLHOTKEY.CAPTION=Hot key:
TFRMEDITHOTKEY.LBLSHORTCUTS.CAPTION=Shortcuts:
TFRMEDITHOTKEY.LBLPARAMETERS.CAPTION=Parameters (each in a separate line):
TFRMEDITHOTKEY.CGHKCONTROLS.CAPTION=Only for these controls
TFRMEDITHOTKEY.BTNADDSHORTCUT.HINT=Add new shortcut to sequence
TFRMEDITHOTKEY.BTNREMOVESHORTCUT.HINT=Remove last shortcut from sequence

View file

@ -40,38 +40,47 @@ type
btnCancel: TBitBtn;
btnShowCommandHelp: TButton;
cgHKControls: TCheckGroup;
edtHotKey: TEdit;
lblHotKey: TLabel;
lblShortcuts: TLabel;
lblHotKeyConflict: TLabel;
lblParameters: TLabel;
edtParameters: TMemo;
pnlShortcuts: TPanel;
btnAddShortcut: TSpeedButton;
btnRemoveShortcut: TSpeedButton;
procedure btnAddShortcutClick(Sender: TObject);
procedure btnRemoveShortcutClick(Sender: TObject);
procedure btnShowCommandHelpClick(Sender: TObject);
procedure cgHKControlsItemClick(Sender: TObject; Index: integer);
procedure edtHotKeyKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure edtHotKeyKeyPress(Sender: TObject; var Key: char);
procedure edtShortcutKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure edtShortcutKeyPress(Sender: TObject; var Key: char);
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
private
FCommand: String;
FControls: TDynamicStringArray;
FShortcutsEditors: Integer;
FForm: String;
FForms, FFormsTranslated: TStringList;
function ApplyHotkey: Boolean;
procedure AddShortcutEditor;
{en
Check if combination of pressed hotkey and checked controls are already in use.
Conflicting hotkeys are deleted if DeleteConflicts parameter is true.
}
procedure CheckHotKeyConflicts(DeleteConflicts: Boolean = false);
procedure FillHKControlList;
function GetShortcutsEditorsCount: Integer;
function GetParameters: TDynamicStringArray;
function GetShortcut: String;
function GetShortcuts: TDynamicStringArray;
function GetTranslatedControlName(const AName: String): String;
function GetTranslatedFormName(const AName: String): String;
procedure RemoveLastShortcutEditor;
procedure SetBitmapOrCaption(Button: TSpeedButton; const AIconName, ACaption: String);
procedure SetCommand(NewCommand: String);
procedure SetControls(NewControls: TDynamicStringArray);
procedure SetControls(const NewControls: TDynamicStringArray);
procedure SetHotkey(Hotkey: THotkey);
procedure SetParameters(NewParameters: TDynamicStringArray);
procedure SetShortcut(NewShortcut: String);
procedure SetParameters(const NewParameters: TDynamicStringArray);
procedure SetShortcuts(const NewShortcuts: TDynamicStringArray);
public
destructor Destroy; override;
function Execute(EditMode: Boolean;
@ -79,7 +88,7 @@ type
Command: String;
Hotkey: THotkey;
AControls: TDynamicStringArray): Boolean;
property NewShortcut: String read GetShortcut;
function CloneNewHotkey: THotkey;
end;
implementation
@ -87,15 +96,31 @@ implementation
{$R *.lfm}
uses
HelpIntfs, LCLType, uKeyboard, uLng, uGlobs, uFormCommands;
HelpIntfs, LCLType, uKeyboard, uLng, uGlobs, uFormCommands, uDCUtils,
uPixMapManager;
const
MaxShortcutSequenceLength = 5;
{ TfrmEditHotkey }
procedure TfrmEditHotkey.AddShortcutEditor;
var
EditControl: TEdit;
begin
if GetShortcutsEditorsCount < MaxShortcutSequenceLength then
begin
EditControl := TEdit.Create(Self);
EditControl.Parent := pnlShortcuts;
EditControl.OnKeyDown := @edtShortcutKeyDown;
EditControl.OnKeyPress := @edtShortcutKeyPress;
end;
end;
function TfrmEditHotkey.ApplyHotkey: Boolean;
var
i: Integer;
sShortCut: String;
Params: array of String;
Shortcuts, Params: array of String;
HMForm: THMForm;
HMControl: THMControl;
hotkey: THotkey;
@ -103,10 +128,9 @@ var
begin
Result := False;
sShortCut := edtHotKey.Text;
Shortcuts := GetShortcuts;
// check for invalid hotkey
if sShortCut = EmptyStr then
if Length(Shortcuts) = 0 then
Exit;
Params := GetParameters;
@ -115,7 +139,7 @@ begin
begin
if (MessageDlg(rsOptHotkeysShortCutUsed, // delete command on assigned shortcut
Format(rsOptHotkeysShortCutUsedText1, // if another was applied
[sShortCut]) + LineEnding +
[ShortcutsToText(Shortcuts)]) + LineEnding +
Format(rsOptHotkeysShortCutUsedText2,
[FCommand]),
mtConfirmation, mbYesNo, 0) = mrYes) then
@ -133,7 +157,7 @@ begin
continue;
// delete previous hotkey if exists
hotkey := HMControl.Hotkeys.Find(sShortCut);
hotkey := HMControl.Hotkeys.Find(Shortcuts);
if Assigned(hotkey) and (hotkey.Command = FCommand) then
HMControl.Hotkeys.Remove(hotkey);
@ -141,21 +165,31 @@ begin
if cgHKControls.Checked[i] then
begin
isFormHotkey := false;
HMControl.Hotkeys.Add(sShortCut, FCommand, Params);
HMControl.Hotkeys.Add(Shortcuts, Params, FCommand);
end;
end;
// delete previous hotkey if exists
hotkey := HMForm.Hotkeys.Find(sShortCut);
hotkey := HMForm.Hotkeys.Find(Shortcuts);
if Assigned(hotkey) and (hotkey.Command = FCommand) then
HMForm.Hotkeys.Remove(hotkey);
if isFormHotkey then
HMForm.Hotkeys.Add(sShortCut, FCommand, Params);
HMForm.Hotkeys.Add(Shortcuts, Params, FCommand);
Result := True;
end;
procedure TfrmEditHotkey.btnAddShortcutClick(Sender: TObject);
begin
AddShortcutEditor;
end;
procedure TfrmEditHotkey.btnRemoveShortcutClick(Sender: TObject);
begin
RemoveLastShortcutEditor;
end;
procedure TfrmEditHotkey.btnShowCommandHelpClick(Sender: TObject);
begin
ShowHelpOrErrorForKeyword('', edtParameters.HelpKeyword);
@ -179,7 +213,7 @@ procedure TfrmEditHotkey.CheckHotKeyConflicts(DeleteConflicts: Boolean);
var
HMForm: THMForm;
HMControl: THMControl;
sShortCut: String;
Shortcuts: TDynamicStringArray;
hotkey: THotkey;
i, count: Integer;
isFormHotKey: Boolean;
@ -191,7 +225,7 @@ begin
if not Assigned(HMForm) then
Exit;
sShortCut := edtHotKey.Text;
Shortcuts := GetShortcuts;
count := 0;
isFormHotKey := true;
@ -207,7 +241,7 @@ begin
if not Assigned(HMControl) then
continue;
hotkey := HMControl.Hotkeys.Find(sShortCut);
hotkey := HMControl.Hotkeys.Find(Shortcuts);
if Assigned(hotkey) and (hotkey.command <> FCommand) then
begin
Inc(count);
@ -221,7 +255,7 @@ begin
if isFormHotKey then
begin
hotkey := HMForm.Hotkeys.Find(sShortCut);
hotkey := HMForm.Hotkeys.Find(Shortcuts);
if Assigned(hotkey) and (hotkey.command <> FCommand) then
begin
Inc(count);
@ -242,6 +276,14 @@ begin
lblHotKeyConflict.Visible := count > 0;
end;
function TfrmEditHotkey.CloneNewHotkey: THotkey;
begin
Result := THotkey.Create;
Result.Shortcuts := GetShortcuts;
Result.Params := GetParameters;
Result.Command := FCommand;
end;
destructor TfrmEditHotkey.Destroy;
begin
inherited Destroy;
@ -249,31 +291,36 @@ begin
FFormsTranslated.Free;
end;
procedure TfrmEditHotkey.edtHotKeyKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure TfrmEditHotkey.edtShortcutKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
var
ShortCut: TShortCut;
sShortCut: String;
EditControl: TEdit;
begin
ShortCut := KeyToShortCutEx(Key,GetKeyShiftStateEx);
ShortCut := KeyToShortCutEx(Key, GetKeyShiftStateEx);
sShortCut := ShortCutToTextEx(ShortCut);
EditControl := Sender as TEdit;
// Allow closing the dialog if Escape pressed twice.
if (ShortCut <> VK_ESCAPE) or (edtHotKey.Text <> sShortCut) then
if (ShortCut <> VK_ESCAPE) or (EditControl.Text <> sShortCut) then
begin
edtHotKey.Text := sShortCut;
EditControl.Text := sShortCut;
Key := 0;
btnOK.Enabled := edtHotKey.Text <> '';
btnOK.Enabled := sShortCut <> '';
lblHotKeyConflict.Caption := '';
CheckHotKeyConflicts;
end;
end;
procedure TfrmEditHotkey.edtHotKeyKeyPress(Sender: TObject; var Key: char);
procedure TfrmEditHotkey.edtShortcutKeyPress(Sender: TObject; var Key: char);
var
EditControl: TEdit;
begin
Key := #0;
edtHotKey.Text := '';
EditControl := Sender as TEdit;
EditControl.Text := '';
btnOK.Enabled := False;
Key := #0;
end;
function TfrmEditHotkey.Execute(
@ -329,11 +376,24 @@ begin
FForms := TStringList.Create;
FFormsTranslated := TStringList.Create;
TFormCommands.GetCategoriesList(FForms, FFormsTranslated);
SetBitmapOrCaption(btnAddShortcut, 'list-add', '+');
SetBitmapOrCaption(btnRemoveShortcut, 'list-remove', '-');
AddShortcutEditor;
end;
procedure TfrmEditHotkey.FormShow(Sender: TObject);
var
EditControl: TEdit;
begin
edtHotKey.SetFocus;
if pnlShortcuts.ControlCount > 0 then
begin
EditControl := pnlShortcuts.Controls[0] as TEdit;
EditControl.SetFocus;
EditControl.SelStart := Length(EditControl.Text);
EditControl.SelLength := 0;
end;
end;
function TfrmEditHotkey.GetParameters: TDynamicStringArray;
@ -352,9 +412,23 @@ begin
end;
end;
function TfrmEditHotkey.GetShortcut: String;
function TfrmEditHotkey.GetShortcuts: TDynamicStringArray;
var
i: Integer;
EditControl: TEdit;
begin
Result := edtHotKey.Text;
Result := nil;
for i := 0 to pnlShortcuts.ControlCount - 1 do
begin
EditControl := pnlShortcuts.Controls[i] as TEdit;
if EditControl.Text <> '' then
AddString(Result, EditControl.Text);
end;
end;
function TfrmEditHotkey.GetShortcutsEditorsCount: Integer;
begin
Result := pnlShortcuts.ControlCount;
end;
function TfrmEditHotkey.GetTranslatedControlName(const AName: String): String;
@ -374,6 +448,34 @@ begin
Result := AName;
end;
procedure TfrmEditHotkey.RemoveLastShortcutEditor;
begin
if pnlShortcuts.ControlCount > 1 then
pnlShortcuts.Controls[pnlShortcuts.ControlCount - 1].Free;
end;
procedure TfrmEditHotkey.SetBitmapOrCaption(Button: TSpeedButton; const AIconName, ACaption: String);
var
Bmp: TBitmap = nil;
IconIndex: PtrInt;
begin
IconIndex := PixMapManager.GetIconByName(AIconName);
if IconIndex <> -1 then
Bmp := PixMapManager.GetBitmap(IconIndex);
if Assigned(Bmp) then
begin
Button.Glyph := Bmp;
Button.Height := gIconsSize;
Button.Width := gIconsSize;
Bmp.Free;
end
else
begin
Button.Caption := ACaption;
end;
end;
procedure TfrmEditHotkey.SetCommand(NewCommand: String);
begin
FCommand := NewCommand;
@ -381,7 +483,7 @@ begin
edtParameters.HelpKeyword := '/cmds.html#' + FCommand;
end;
procedure TfrmEditHotkey.SetControls(NewControls: TDynamicStringArray);
procedure TfrmEditHotkey.SetControls(const NewControls: TDynamicStringArray);
var
sControl: String;
i: Integer;
@ -408,17 +510,17 @@ procedure TfrmEditHotkey.SetHotkey(Hotkey: THotkey);
begin
if Assigned(Hotkey) then
begin
SetShortcut(Hotkey.Shortcut);
SetShortcuts(Hotkey.Shortcuts);
SetParameters(Hotkey.Params);
end
else
begin
SetShortcut(EmptyStr);
SetShortcuts(nil);
SetParameters(nil);
end;
end;
procedure TfrmEditHotkey.SetParameters(NewParameters: TDynamicStringArray);
procedure TfrmEditHotkey.SetParameters(const NewParameters: TDynamicStringArray);
var
Param: String;
begin
@ -427,9 +529,27 @@ begin
edtParameters.Lines.Add(Param);
end;
procedure TfrmEditHotkey.SetShortcut(NewShortcut: String);
procedure TfrmEditHotkey.SetShortcuts(const NewShortcuts: TDynamicStringArray);
var
Index: Integer;
EditControl: TEdit;
Shortcut: String;
begin
edtHotKey.Text := NewShortcut;
if Assigned(NewShortcuts) then
begin
while pnlShortcuts.ControlCount < Length(NewShortcuts) do
AddShortcutEditor;
while pnlShortcuts.ControlCount > Length(NewShortcuts) do
RemoveLastShortcutEditor;
Index := 0;
for Shortcut in NewShortcuts do
begin
EditControl := pnlShortcuts.Controls[Index] as TEdit;
EditControl.Text := Shortcut;
Inc(Index);
end;
end;
end;
end.

View file

@ -79,7 +79,7 @@ type
{en
Return hotkeys assigned for command for the form and its controls.
}
procedure GetHotKeyList(HMForm: THMForm; Command: String; HotkeysList: TStringList);
procedure GetHotKeyList(HMForm: THMForm; Command: String; HotkeysList: THotkeys);
{en
Fill hotkey grid with all hotkeys assigned to a command
}
@ -95,6 +95,7 @@ type
Retrieves untranslated form name.
}
function GetSelectedForm: String;
procedure SelectHotkey(Hotkey: THotkey);
procedure ShowEditHotkeyForm(EditMode: Boolean; aHotkeyRow: Integer);
procedure ShowEditHotkeyForm(EditMode: Boolean;
const AForm: String;
@ -142,30 +143,28 @@ begin
end;
end;
function StListToStr(separator:string; const lStList:TStringList; duplicates: boolean = true):string;
//< convert stringlist to string
// Converts hotkeys list to string.
function HotkeysToString(const Hotkeys: THotkeys): String;
var
sLast: String;
sCurrent: String;
i: Integer;
sList: TStringList;
begin
Result:='';
if lStList.Count>0 then
begin
if not duplicates then
lStList.Sort;
sLast := lStList[0];
Result:=lStList[0]+separator;
for i:=1 to lStList.Count-1 do
Result := '';
sList := TStringList.Create;
try
sList.CaseSensitive := True;
for i := 0 to Hotkeys.Count - 1 do
begin
if not duplicates and (lStList[i] = sLast) then
continue;
sLast := lStList[i];
Result:=Result+lStList[i]+separator;
sCurrent := ShortcutsToText(Hotkeys[i].Shortcuts);
if sList.IndexOf(sCurrent) < 0 then
begin
sList.Add(sCurrent);
AddStrWithSep(Result, sCurrent, ';');
end;
end;
finally
sList.Free;
end;
end;
@ -183,36 +182,38 @@ end;
procedure TfrmOptionsHotkeys.btnDeleteHotKeyClick(Sender: TObject);
var
i: Integer;
sShortCut: String;
sCommand: String;
HMForm: THMForm;
HMControl: THMControl;
hotkey: THotkey;
HotkeyItem: PHotkeyItem;
begin
if lbxCategories.ItemIndex=-1 then Exit;
sShortCut := stgHotkeys.Cells[0, stgHotkeys.Row];
sCommand := GetSelectedCommand;
HMForm := HotMan.Forms.Find(GetSelectedForm);
if Assigned(HMForm) then
if stgHotkeys.Row >= stgHotkeys.FixedRows then
begin
for i := 0 to HMForm.Controls.Count - 1 do
HotkeyItem := PHotkeyItem(stgHotkeys.Objects[0, stgHotkeys.Row]);
sCommand := GetSelectedCommand;
HMForm := HotMan.Forms.Find(GetSelectedForm);
if Assigned(HMForm) then
begin
HMControl := HMForm.Controls[i];
if Assigned(HMControl) then
for i := 0 to HMForm.Controls.Count - 1 do
begin
hotkey := HMControl.Hotkeys.Find(sShortCut);
if Assigned(hotkey) and (hotkey.Command = sCommand) then
HMControl.Hotkeys.Remove(hotkey);
HMControl := HMForm.Controls[i];
if Assigned(HMControl) then
begin
hotkey := HMControl.Hotkeys.FindByContents(HotkeyItem^.Hotkey);
if Assigned(hotkey) then
HMControl.Hotkeys.Remove(hotkey);
end;
end;
hotkey := HMForm.Hotkeys.FindByContents(HotkeyItem^.Hotkey);
if Assigned(hotkey) then
HMForm.Hotkeys.Remove(hotkey);
// refresh lists
Self.UpdateHotkeys(HMForm);
Self.FillHotkeyList(sCommand);
end;
hotkey := HMForm.Hotkeys.Find(sShortCut);
if Assigned(hotkey) and (hotkey.Command = sCommand) then
HMForm.Hotkeys.Remove(hotkey);
// refresh lists
Self.UpdateHotkeys(HMForm);
Self.FillHotkeyList(sCommand);
end;
end;
@ -343,12 +344,15 @@ end;
procedure TfrmOptionsHotkeys.UpdateHotkeysForCommand(HMForm: THMForm; RowNr: Integer);
var
lslHotKeys: TStringList;
Hotkeys: THotkeys;
begin
lslHotKeys:=TStringList.Create;
GetHotKeyList(HMForm, stgCommands.Cells[stgCmdCommandIndex,RowNr],lslHotKeys);
stgCommands.Cells[stgCmdHotkeysIndex,RowNr]:=StListToStr(';',lslHotKeys,false);
lslHotKeys.Free;
Hotkeys := THotkeys.Create(False);
try
GetHotKeyList(HMForm, stgCommands.Cells[stgCmdCommandIndex,RowNr], Hotkeys);
stgCommands.Cells[stgCmdHotkeysIndex, RowNr] := HotkeysToString(Hotkeys);
finally
Hotkeys.Free;
end;
end;
procedure TfrmOptionsHotkeys.FillSCFilesList;
@ -368,7 +372,7 @@ begin
FindCloseEx(SR);
end;
procedure TfrmOptionsHotkeys.GetHotKeyList(HMForm: THMForm; Command: String; HotkeysList: TStringList);
procedure TfrmOptionsHotkeys.GetHotKeyList(HMForm: THMForm; Command: String; HotkeysList: THotkeys);
procedure AddHotkeys(hotkeys: THotkeys);
var
i: Integer;
@ -376,7 +380,7 @@ procedure TfrmOptionsHotkeys.GetHotKeyList(HMForm: THMForm; Command: String; Hot
for i := 0 to hotkeys.Count - 1 do
begin
if hotkeys[i].Command = Command then
HotkeysList.AddObject(hotkeys[i].Shortcut, hotkeys[i]);
HotkeysList.Add(hotkeys[i]);
end;
end;
var
@ -397,14 +401,6 @@ begin
end;
procedure TfrmOptionsHotkeys.FillHotkeyList(sCommand: String);
function GatherParams(const Params: array of String): String;
var
i: Integer;
begin
Result := '';
for i := Low(Params) to High(Params) do
AddStrWithSep(Result, Params[i], ' ');
end;
function SetObject(RowNr: Integer; AHotkey: THotkey): PHotkeyItem;
var
HotkeyItem: PHotkeyItem;
@ -441,8 +437,8 @@ begin
continue;
stgHotkeys.RowCount := stgHotkeys.RowCount + 1;
stgHotkeys.Cells[0, stgHotkeys.RowCount - 1] := hotkey.ShortCut;
stgHotkeys.Cells[1, stgHotkeys.RowCount - 1] := GatherParams(hotkey.Params);
stgHotkeys.Cells[0, stgHotkeys.RowCount - 1] := ShortcutsToText(hotkey.Shortcuts);
stgHotkeys.Cells[1, stgHotkeys.RowCount - 1] := ArrayToString(hotkey.Params);
SetObject(stgHotkeys.RowCount - 1, hotkey);
end;
@ -460,7 +456,9 @@ begin
found := false;
for iGrid := stgHotkeys.FixedRows to stgHotkeys.RowCount - 1 do
begin
if stgHotkeys.Cells[0, iGrid] = hotkey.ShortCut then
HotkeyItem := PHotkeyItem(stgHotkeys.Objects[0, iGrid]);
if HotkeyItem^.Hotkey.SameShortcuts(hotkey.Shortcuts) and
HotkeyItem^.Hotkey.SameParams(hotkey.Params) then
begin
stgHotkeys.Cells[2, iGrid] := stgHotkeys.Cells[2, iGrid] + HMControl.Name + ';';
HotkeyItem := PHotkeyItem(stgHotkeys.Objects[0, iGrid]);
@ -474,8 +472,8 @@ begin
if not found then
begin
stgHotkeys.RowCount := stgHotkeys.RowCount + 1;
stgHotkeys.Cells[0, stgHotkeys.RowCount - 1] := hotkey.ShortCut;
stgHotkeys.Cells[1, stgHotkeys.RowCount - 1] := GatherParams(hotkey.Params);
stgHotkeys.Cells[0, stgHotkeys.RowCount - 1] := ShortcutsToText(hotkey.Shortcuts);
stgHotkeys.Cells[1, stgHotkeys.RowCount - 1] := ArrayToString(hotkey.Params);
stgHotkeys.Cells[2, stgHotkeys.RowCount - 1] := HMControl.Name + ';';
HotkeyItem := SetObject(stgHotkeys.RowCount - 1, hotkey);
AddString(HotkeyItem^.Controls, HMControl.Name);
@ -498,7 +496,8 @@ end;
procedure TfrmOptionsHotkeys.FillCommandList(Filter: String);
//< fill stgCommands with commands and descriptions
var
slTmp, slAllCommands, slDescriptions, slHotKey: TStringList;
slTmp: THotkeys;
slAllCommands, slDescriptions, slHotKey: TStringList;
slFiltered: TStringList = nil;
lstr: String;
i: Integer;
@ -538,7 +537,7 @@ begin
slAllCommands := TStringList.Create;
slDescriptions := TStringList.Create;
slHotKey := TStringList.Create;
slTmp := TStringList.Create;
slTmp := THotkeys.Create(False);
HMForm := HotMan.Forms.Find(sForm);
CommandsIntf.GetCommandsList(slAllCommands);
@ -573,7 +572,7 @@ begin
begin
slTmp.Clear;
GetHotKeyList(HMForm, slFiltered.Strings[i], slTmp);
slHotKey.Add(StListToStr(';', slTmp, false)); //add to hotkey list created string
slHotKey.Add(HotkeysToString(slTmp)); //add to hotkey list created string
end
else
slHotKey.Add('');
@ -706,6 +705,22 @@ begin
gNameSCFile := lbSCFilesList.Items[lbSCFilesList.ItemIndex];
end;
procedure TfrmOptionsHotkeys.SelectHotkey(Hotkey: THotkey);
var
HotkeyItem: PHotkeyItem;
i: Integer;
begin
for i := stgHotkeys.FixedRows to stgHotkeys.RowCount - 1 do
begin
HotkeyItem := PHotkeyItem(stgHotkeys.Objects[0, i]);
if Assigned(HotkeyItem) and HotkeyItem^.Hotkey.SameAs(Hotkey) then
begin
stgHotkeys.Row := i;
Break;
end;
end;
end;
procedure TfrmOptionsHotkeys.ShowEditHotkeyForm(EditMode: Boolean; aHotkeyRow: Integer);
var
HotkeyItem: PHotkeyItem;
@ -727,6 +742,7 @@ procedure TfrmOptionsHotkeys.ShowEditHotkeyForm(
const AControls: TDynamicStringArray);
var
HMForm: THMForm;
Hotkey: THotkey = nil;
begin
if AForm <> EmptyStr then
begin
@ -741,8 +757,13 @@ begin
Self.UpdateHotkeys(HMForm);
Self.FillHotkeyList(ACommand);
// Select the new shortcut in the hotkeys table.
stgHotkeys.Row := stgHotkeys.Cols[0].IndexOf(FEditForm.NewShortcut);
Hotkey := FEditForm.CloneNewHotkey;
try
// Select the new shortcut in the hotkeys table.
SelectHotkey(Hotkey);
finally
Hotkey.Free;
end;
end;
end;
end;
@ -764,7 +785,7 @@ procedure TfrmOptionsHotkeys.AddDeleteWithShiftHotkey(UseTrash: Boolean);
var
ShiftState: TShiftState;
begin
Shortcut := TextToShortCutEx(Hotkey.Shortcut);
Shortcut := TextToShortCutEx(Hotkey.Shortcuts[0]);
ShiftState := ShortcutToShiftEx(Shortcut);
if ssShift in ShiftState then
ShiftState := ShiftState - [ssShift]
@ -782,7 +803,7 @@ procedure TfrmOptionsHotkeys.AddDeleteWithShiftHotkey(UseTrash: Boolean);
begin
if Contains(Hotkey.Params, OldTrashParam) or NewTrashParam then
begin
Result := ConfirmFix(Hotkey, Format(rsOptHotkeysDeleteTrashCanOverrides, [Hotkey.Shortcut]));
Result := ConfirmFix(Hotkey, Format(rsOptHotkeysDeleteTrashCanOverrides, [Hotkey.Shortcuts[0]]));
if Result then
begin
DeleteString(Hotkey.Params, OldTrashParam);
@ -808,7 +829,7 @@ procedure TfrmOptionsHotkeys.AddDeleteWithShiftHotkey(UseTrash: Boolean);
begin
if ContainsOneOf(Hotkey.Params, ParamsToDelete) or
(HasTrashCan and (TrashStr <> NewTrashParam)) then
if not ConfirmFix(Hotkey, Format(rsOptHotkeysDeleteTrashCanParameterExists, [Hotkey.Shortcut, NonReversedHotkey.Shortcut])) then
if not ConfirmFix(Hotkey, Format(rsOptHotkeysDeleteTrashCanParameterExists, [Hotkey.Shortcuts[0], NonReversedHotkey.Shortcuts[0]])) then
Exit;
for sDelete in ParamsToDelete do
@ -834,93 +855,104 @@ procedure TfrmOptionsHotkeys.AddDeleteWithShiftHotkey(UseTrash: Boolean);
for i := 0 to CountBeforeAdded - 1 do
begin
if (Hotkeys[i].Command = 'cm_Delete') and
not Contains(CheckedShortcuts, Hotkeys[i].Shortcut) then
(Length(Hotkeys[i].Shortcuts) > 0) then
begin
ReversedHotkey := nil;
SetShortcut := True;
ReverseShift(Hotkeys[i], Shortcut, TextShortcut);
AddString(CheckedShortcuts, TextShortcut);
// Check if shortcut with reversed shift already exists.
for j := 0 to CountBeforeAdded - 1 do
if Length(Hotkeys[i].Shortcuts) > 1 then
begin
if Hotkeys[j].Shortcut = TextShortcut then
begin
if Hotkeys[j].Command <> Hotkeys[i].Command then
begin
if QuestionDlg(rsOptHotkeysCannotSetShortcut,
Format(rsOptHotkeysShortcutForDeleteAlreadyAssigned,
[Hotkeys[i].Shortcut, TextShortcut, Hotkeys[j].Command]),
mtConfirmation, [mrYes, rsOptHotkeysChangeShortcut, 'isdefault', mrCancel], 0) = mrYes then
begin
Hotkeys[j].Command := Hotkeys[i].Command;
end
else
SetShortcut := False;
end;
ReversedHotkey := Hotkeys[j];
Break;
end;
MessageDlg(rsOptHotkeysCannotSetShortcut,
Format(rsOptHotkeysShortcutForDeleteIsSequence, [ShortcutsToText(Hotkeys[i].Shortcuts)]),
mtWarning, [mbOK], 0);
Continue;
end;
if not SetShortcut then
Continue;
// Fix parameters of original hotkey if needed.
HasTrashCan := GetParamValue(Hotkeys[i].Params, 'trashcan', TrashStr);
HasTrashBool := HasTrashCan and GetBoolValue(TrashStr, TrashBoolValue);
if not FixOverrides(Hotkeys[i], 'recycle', HasTrashBool and TrashBoolValue, UseTrash) then
Continue;
if not FixOverrides(Hotkeys[i], 'norecycle', HasTrashBool and not TrashBoolValue, not UseTrash) then
Continue;
// Reverse trash setting for reversed hotkey.
NewParams := Copy(Hotkeys[i].Params);
HasTrashCan := GetParamValue(NewParams, 'trashcan', TrashStr); // Could have been added above so check again
if Contains(NewParams, 'recyclesettingrev') then
if not Contains(CheckedShortcuts, Hotkeys[i].Shortcuts[0]) then
begin
DeleteString(NewParams, 'recyclesettingrev');
NormalTrashSetting := True;
end
else if Contains(NewParams, 'recyclesetting') then
begin
DeleteString(NewParams, 'recyclesetting');
NormalTrashSetting := False;
end
else if HasTrashCan and (TrashStr = 'reversesetting') then
NormalTrashSetting := True
else
NormalTrashSetting := False;
ReversedHotkey := nil;
SetShortcut := True;
ReverseShift(Hotkeys[i], Shortcut, TextShortcut);
AddString(CheckedShortcuts, TextShortcut);
if Assigned(ReversedHotkey) then
begin
HasTrashCan := GetParamValue(ReversedHotkey.Params, 'trashcan', TrashStr);
if NormalTrashSetting then
// Check if shortcut with reversed shift already exists.
for j := 0 to CountBeforeAdded - 1 do
begin
FixReversedShortcut(ReversedHotkey, Hotkeys[i],
['recyclesettingrev', 'recycle', 'norecycle'],
'recyclesetting', 'setting', HasTrashCan, TrashStr);
end
else
begin
FixReversedShortcut(ReversedHotkey, Hotkeys[i],
['recyclesetting', 'recycle', 'norecycle'],
'recyclesettingrev', 'reversesetting', HasTrashCan, TrashStr);
if ArrBegins(Hotkeys[j].Shortcuts, [TextShortcut], False) then
begin
if Hotkeys[j].Command <> Hotkeys[i].Command then
begin
if QuestionDlg(rsOptHotkeysCannotSetShortcut,
Format(rsOptHotkeysShortcutForDeleteAlreadyAssigned,
[Hotkeys[i].Shortcuts[0], TextShortcut, Hotkeys[j].Command]),
mtConfirmation, [mrYes, rsOptHotkeysChangeShortcut, 'isdefault', mrCancel], 0) = mrYes then
begin
Hotkeys[j].Command := Hotkeys[i].Command;
end
else
SetShortcut := False;
end;
ReversedHotkey := Hotkeys[j];
Break;
end;
end;
end
else if QuestionDlg(rsOptHotkeysSetDeleteShortcut,
Format(rsOptHotkeysAddDeleteShortcutLong, [TextShortcut]),
mtConfirmation, [mrYes, rsOptHotkeysAddShortcutButton, 'isdefault', mrCancel], 0) = mrYes then
begin
if NormalTrashSetting then
TrashStr := 'setting'
else
TrashStr := 'reversesetting';
SetValue(NewParams, 'trashcan', TrashStr);
Hotkeys.Add(TextShortcut, Hotkeys[i].Command, NewParams);
if not SetShortcut then
Continue;
// Fix parameters of original hotkey if needed.
HasTrashCan := GetParamValue(Hotkeys[i].Params, 'trashcan', TrashStr);
HasTrashBool := HasTrashCan and GetBoolValue(TrashStr, TrashBoolValue);
if not FixOverrides(Hotkeys[i], 'recycle', HasTrashBool and TrashBoolValue, UseTrash) then
Continue;
if not FixOverrides(Hotkeys[i], 'norecycle', HasTrashBool and not TrashBoolValue, not UseTrash) then
Continue;
// Reverse trash setting for reversed hotkey.
NewParams := Copy(Hotkeys[i].Params);
HasTrashCan := GetParamValue(NewParams, 'trashcan', TrashStr); // Could have been added above so check again
if Contains(NewParams, 'recyclesettingrev') then
begin
DeleteString(NewParams, 'recyclesettingrev');
NormalTrashSetting := True;
end
else if Contains(NewParams, 'recyclesetting') then
begin
DeleteString(NewParams, 'recyclesetting');
NormalTrashSetting := False;
end
else if HasTrashCan and (TrashStr = 'reversesetting') then
NormalTrashSetting := True
else
NormalTrashSetting := False;
if Assigned(ReversedHotkey) then
begin
HasTrashCan := GetParamValue(ReversedHotkey.Params, 'trashcan', TrashStr);
if NormalTrashSetting then
begin
FixReversedShortcut(ReversedHotkey, Hotkeys[i],
['recyclesettingrev', 'recycle', 'norecycle'],
'recyclesetting', 'setting', HasTrashCan, TrashStr);
end
else
begin
FixReversedShortcut(ReversedHotkey, Hotkeys[i],
['recyclesetting', 'recycle', 'norecycle'],
'recyclesettingrev', 'reversesetting', HasTrashCan, TrashStr);
end;
end
else if QuestionDlg(rsOptHotkeysSetDeleteShortcut,
Format(rsOptHotkeysAddDeleteShortcutLong, [TextShortcut]),
mtConfirmation, [mrYes, rsOptHotkeysAddShortcutButton, 'isdefault', mrCancel], 0) = mrYes then
begin
if NormalTrashSetting then
TrashStr := 'setting'
else
TrashStr := 'reversesetting';
SetValue(NewParams, 'trashcan', TrashStr);
Hotkeys.Add([TextShortcut], NewParams, Hotkeys[i].Command);
end;
end;
end;
end;

View file

@ -422,6 +422,23 @@ procedure UpdateColor(Control: TControl; Checked: Boolean);
procedure EnableControl(Control: TControl; Enabled: Boolean);
procedure AddString(var anArray: TDynamicStringArray; const sToAdd: String);
{en
Checks if the second array is the beginning of first.
If BothWays is @true then also checks the other way around,
if the first array is the beginning of second.
For Array1=[1,2] Array2=[1,2] returns @true.
For Array1=[1,2,...] Array2=[1,2] returns @true.
For Array1=[1,3,...] Array2=[1,2] returns @false.
If BothWays = True then also
For Array1=[1] Array2=[1,2] returns @true.
For Array1=[1] Array2=[2] returns @false.
}
function ArrBegins(const Array1, Array2: array of String; BothWays: Boolean): Boolean;
function ArrayToString(const anArray: TDynamicStringArray; const Separator: Char = ' '): String;
{en
Compares length and contents of the arrays.
If lengths differ or individual elements differ returns @false, otherwise @true.
}
function Compare(const Array1, Array2: array of String): Boolean;
{en
Copies open array to dynamic array.
@ -436,6 +453,7 @@ procedure DeleteString(var anArray: TDynamicStringArray; const sToDelete: String
}
procedure SetValue(var anArray: TDynamicStringArray; Key, NewValue: String);
procedure SetValue(var anArray: TDynamicStringArray; Key: String; NewValue: Boolean);
function ShortcutsToText(const Shortcuts: TDynamicStringArray): String;
implementation
@ -1784,6 +1802,35 @@ begin
anArray[Len] := sToAdd;
end;
function ArrBegins(const Array1, Array2: array of String; BothWays: Boolean): Boolean;
var
Len1, Len2: Integer;
i: Integer;
begin
Len1 := Length(Array1);
Len2 := Length(Array2);
if not BothWays and (Len1 < Len2) then
Result := False
else
begin
if Len1 > Len2 then
Len1 := Len2;
for i := 0 to Len1 - 1 do
if Array1[i] <> Array2[i] then
Exit(False);
Result := True;
end;
end;
function ArrayToString(const anArray: TDynamicStringArray; const Separator: Char): String;
var
i: Integer;
begin
Result := '';
for i := Low(anArray) to High(anArray) do
AddStrWithSep(Result, anArray[i], Separator);
end;
function Compare(const Array1, Array2: array of String): Boolean;
var
Len1, Len2: Integer;
@ -1876,5 +1923,10 @@ begin
SetValue(anArray, Key, 'false');
end;
function ShortcutsToText(const Shortcuts: TDynamicStringArray): String;
begin
Result := ArrayToString(Shortcuts, ' ');
end;
end.

View file

@ -90,7 +90,7 @@ type
const
{ Default hotkey list version number }
hkVersion = 9;
hkVersion = 10;
// Previously existing names if reused must check for ConfigVersion >= X.
// History:
@ -389,95 +389,95 @@ begin
HMForm := HotMan.Forms.FindOrCreate('Main');
with HMForm.Hotkeys do
begin
AddIfNotExists('F1','cm_About',[]);
AddIfNotExists('F2','cm_RenameOnly',[]);
AddIfNotExists('F3','cm_View',[]);
AddIfNotExists('F4','cm_Edit',[]);
AddIfNotExists('F5','cm_Copy',[]);
AddIfNotExists('F6','cm_Rename',[]);
AddIfNotExists('F7','cm_MakeDir',[]);
AddIfNotExists(['F8','',
'Shift+F8','trashcan=reversesetting',''], 'cm_Delete');
AddIfNotExists('F9','cm_RunTerm',[]);
AddIfNotExists('Ctrl+7','cm_ShowCmdLineHistory',[]);
AddIfNotExists('Ctrl+D','cm_DirHotList',[]);
AddIfNotExists('Ctrl+F','cm_QuickFilter',[]);
AddIfNotExists('Ctrl+H','cm_DirHistory',[]);
AddIfNotExists('Ctrl+L','cm_CalculateSpace',[]);
AddIfNotExists('Ctrl+M','cm_MultiRename',[]);
AddIfNotExists('Ctrl+P','cm_AddPathToCmdLine',[]);
AddIfNotExists('Ctrl+Q','cm_QuickView',[]);
AddIfNotExists('Ctrl+S','cm_QuickSearch',[]);
AddIfNotExists('Ctrl+R','cm_Refresh',[]);
AddIfNotExists('Ctrl+T','cm_NewTab',[]);
AddIfNotExists('Ctrl+U','cm_Exchange',[]);
AddIfNotExists('Ctrl+W','cm_RemoveTab',[]);
AddIfNotExists('Ctrl+Z','cm_EditComment',[]);
AddIfNotExists('Ctrl+F3','cm_SortByName',[]);
AddIfNotExists('Ctrl+F4','cm_SortByExt',[]);
AddIfNotExists('Ctrl+F5','cm_SortByDate',[]);
AddIfNotExists('Ctrl+F6','cm_SortBySize',[]);
AddIfNotExists('Ctrl+Down','cm_ShowCmdLineHistory',[]);
AddIfNotExists('Ctrl+Enter','cm_AddFilenameToCmdLine',[]);
AddIfNotExists('Ctrl+PgDn','cm_OpenArchive',[]);
AddIfNotExists('Ctrl+PgUp','cm_ChangeDirToParent',[]);
AddIfNotExists('Ctrl+Shift+C','cm_CopyFullNamesToClip',[]);
AddIfNotExists('Ctrl+Shift+H','cm_HorizontalFilePanels',[]);
AddIfNotExists('Ctrl+Shift+X','cm_CopyNamesToClip',[]);
AddIfNotExists('Ctrl+Shift+Enter','cm_AddPathAndFilenameToCmdLine',[]);
AddIfNotExists('Ctrl+Shift+Tab','cm_PrevTab',[]);
AddIfNotExists('Ctrl+Tab','cm_NextTab',[]);
AddIfNotExists('Ctrl+Up','cm_OpenDirInNewTab',[]);
AddIfNotExists('Ctrl+\','cm_ChangeDirToRoot',[]);
AddIfNotExists('Ctrl+.','cm_ShowSysFiles',[]);
AddIfNotExists('Shift+F2','cm_FocusCmdLine',[]);
AddIfNotExists('Shift+F4','cm_EditNew',[]);
AddIfNotExists('Shift+F5','cm_CopySamePanel',[]);
AddIfNotExists('Shift+F6','cm_RenameOnly',[]);
AddIfNotExists('Shift+F10','cm_ContextMenu',[]);
AddIfNotExists('Alt+V','cm_OperationsViewer',[]);
AddIfNotExists('Alt+X','cm_Exit',[]);
AddIfNotExists('Alt+Z','cm_TargetEqualSource',[]);
AddIfNotExists('Alt+F1','cm_LeftOpenDrives',[]);
AddIfNotExists('Alt+F2','cm_RightOpenDrives',[]);
AddIfNotExists('Alt+F5','cm_PackFiles',[]);
AddIfNotExists('Alt+F7','cm_Search',[]);
AddIfNotExists('Alt+F9','cm_ExtractFiles',[]);
AddIfNotExists('Alt+Del','cm_Wipe',[]);
AddIfNotExists('Alt+Down','cm_DirHistory',[]);
AddIfNotExists('Alt+Enter','cm_FileProperties',[]);
AddIfNotExists('Alt+Left','cm_ViewHistoryPrev',[]);
AddIfNotExists('Alt+Right','cm_ViewHistoryNext',[]);
AddIfNotExists('Alt+Shift+Enter','cm_CountDirContent',[]);
AddIfNotExists('Alt+Shift+F9','cm_TestArchive',[]);
AddIfNotExists(['F1'],[],'cm_About');
AddIfNotExists(['F2'],[],'cm_RenameOnly');
AddIfNotExists(['F3'],[],'cm_View');
AddIfNotExists(['F4'],[],'cm_Edit');
AddIfNotExists(['F5'],[],'cm_Copy');
AddIfNotExists(['F6'],[],'cm_Rename');
AddIfNotExists(['F7'],[],'cm_MakeDir');
AddIfNotExists(['F8','','',
'Shift+F8','','trashcan=reversesetting',''], 'cm_Delete');
AddIfNotExists(['F9'],[],'cm_RunTerm');
AddIfNotExists(['Ctrl+7'],[],'cm_ShowCmdLineHistory');
AddIfNotExists(['Ctrl+D'],[],'cm_DirHotList');
AddIfNotExists(['Ctrl+F'],[],'cm_QuickFilter');
AddIfNotExists(['Ctrl+H'],[],'cm_DirHistory');
AddIfNotExists(['Ctrl+L'],[],'cm_CalculateSpace');
AddIfNotExists(['Ctrl+M'],[],'cm_MultiRename');
AddIfNotExists(['Ctrl+P'],[],'cm_AddPathToCmdLine');
AddIfNotExists(['Ctrl+Q'],[],'cm_QuickView');
AddIfNotExists(['Ctrl+S'],[],'cm_QuickSearch');
AddIfNotExists(['Ctrl+R'],[],'cm_Refresh');
AddIfNotExists(['Ctrl+T'],[],'cm_NewTab');
AddIfNotExists(['Ctrl+U'],[],'cm_Exchange');
AddIfNotExists(['Ctrl+W'],[],'cm_RemoveTab');
AddIfNotExists(['Ctrl+Z'],[],'cm_EditComment');
AddIfNotExists(['Ctrl+F3'],[],'cm_SortByName');
AddIfNotExists(['Ctrl+F4'],[],'cm_SortByExt');
AddIfNotExists(['Ctrl+F5'],[],'cm_SortByDate');
AddIfNotExists(['Ctrl+F6'],[],'cm_SortBySize');
AddIfNotExists(['Ctrl+Down'],[],'cm_ShowCmdLineHistory');
AddIfNotExists(['Ctrl+Enter'],[],'cm_AddFilenameToCmdLine');
AddIfNotExists(['Ctrl+PgDn'],[],'cm_OpenArchive');
AddIfNotExists(['Ctrl+PgUp'],[],'cm_ChangeDirToParent');
AddIfNotExists(['Ctrl+Shift+C'],[],'cm_CopyFullNamesToClip');
AddIfNotExists(['Ctrl+Shift+H'],[],'cm_HorizontalFilePanels');
AddIfNotExists(['Ctrl+Shift+X'],[],'cm_CopyNamesToClip');
AddIfNotExists(['Ctrl+Shift+Enter'],[],'cm_AddPathAndFilenameToCmdLine');
AddIfNotExists(['Ctrl+Shift+Tab'],[],'cm_PrevTab');
AddIfNotExists(['Ctrl+Tab'],[],'cm_NextTab');
AddIfNotExists(['Ctrl+Up'],[],'cm_OpenDirInNewTab');
AddIfNotExists(['Ctrl+\'],[],'cm_ChangeDirToRoot');
AddIfNotExists(['Ctrl+.'],[],'cm_ShowSysFiles');
AddIfNotExists(['Shift+F2'],[],'cm_FocusCmdLine');
AddIfNotExists(['Shift+F4'],[],'cm_EditNew');
AddIfNotExists(['Shift+F5'],[],'cm_CopySamePanel');
AddIfNotExists(['Shift+F6'],[],'cm_RenameOnly');
AddIfNotExists(['Shift+F10'],[],'cm_ContextMenu');
AddIfNotExists(['Alt+V'],[],'cm_OperationsViewer');
AddIfNotExists(['Alt+X'],[],'cm_Exit');
AddIfNotExists(['Alt+Z'],[],'cm_TargetEqualSource');
AddIfNotExists(['Alt+F1'],[],'cm_LeftOpenDrives');
AddIfNotExists(['Alt+F2'],[],'cm_RightOpenDrives');
AddIfNotExists(['Alt+F5'],[],'cm_PackFiles');
AddIfNotExists(['Alt+F7'],[],'cm_Search');
AddIfNotExists(['Alt+F9'],[],'cm_ExtractFiles');
AddIfNotExists(['Alt+Del'],[],'cm_Wipe');
AddIfNotExists(['Alt+Down'],[],'cm_DirHistory');
AddIfNotExists(['Alt+Enter'],[],'cm_FileProperties');
AddIfNotExists(['Alt+Left'],[],'cm_ViewHistoryPrev');
AddIfNotExists(['Alt+Right'],[],'cm_ViewHistoryNext');
AddIfNotExists(['Alt+Shift+Enter'],[],'cm_CountDirContent');
AddIfNotExists(['Alt+Shift+F9'],[],'cm_TestArchive');
end;
HMControl := HMForm.Controls.FindOrCreate('Files Panel');
with HMControl.Hotkeys do
begin
AddIfNotExists(['Del','',
'Shift+Del','trashcan=reversesetting',''], 'cm_Delete');
AddIfNotExists('Ctrl+A','cm_MarkMarkAll',[]);
AddIfNotExists('Ctrl+C','cm_CopyToClipboard',[]);
AddIfNotExists('Ctrl+V','cm_PasteFromClipboard',[]);
AddIfNotExists('Ctrl+X','cm_CutToClipboard',[]);
AddIfNotExists('Ctrl+Left','cm_TransferLeft',[]);
AddIfNotExists('Ctrl+Right','cm_TransferRight',[]);
AddIfNotExists(['Del','','',
'Shift+Del','','trashcan=reversesetting',''], 'cm_Delete');
AddIfNotExists(['Ctrl+A'],[],'cm_MarkMarkAll');
AddIfNotExists(['Ctrl+C'],[],'cm_CopyToClipboard');
AddIfNotExists(['Ctrl+V'],[],'cm_PasteFromClipboard');
AddIfNotExists(['Ctrl+X'],[],'cm_CutToClipboard');
AddIfNotExists(['Ctrl+Left'],[],'cm_TransferLeft');
AddIfNotExists(['Ctrl+Right'],[],'cm_TransferRight');
end;
HMForm := HotMan.Forms.FindOrCreate('Viewer');
with HMForm.Hotkeys do
begin
AddIfNotExists('F1','cm_About',[]);
AddIfNotExists('F2','cm_Reload',[]);
AddIfNotExists('N','cm_LoadNextFile',[]);
AddIfNotExists('P','cm_LoadPrevFile',[]);
AddIfNotExists(['F1'],[],'cm_About');
AddIfNotExists(['F2'],[],'cm_Reload');
AddIfNotExists(['N'],[],'cm_LoadNextFile');
AddIfNotExists(['P'],[],'cm_LoadPrevFile');
end;
HMForm := HotMan.Forms.FindOrCreate('Copy/Move Dialog');
with HMForm.Hotkeys do
begin
AddIfNotExists('F2','cm_AddToQueue',[]);
AddIfNotExists(['F2'],[],'cm_AddToQueue');
end;
if not mbFileExists(gpCfgDir + gNameSCFile) then

View file

@ -31,7 +31,7 @@ interface
uses
Classes, SysUtils, Controls, LCLProc, LCLType, LCLIntf, Forms, ActnList,
uClassesEx, fgl, contnrs, uXmlConfig;
uClassesEx, fgl, contnrs, uXmlConfig, uTypes;
type
generic THMObjectInstance<InstanceClass> = class
@ -45,13 +45,15 @@ type
{ THotkey }
THotkey = class
Shortcut: String;
Shortcuts: array of String;
Command: String;
Params: array of String;
function Clone: THotkey;
function HasParam(const aParam: String): Boolean; overload;
function HasParam(const aParams: array of String): Boolean; overload;
function SameAs(Hotkey: THotkey): Boolean;
function SameParams(const aParams: array of String): Boolean;
function SameShortcuts(const aShortcuts: array of String): Boolean;
end;
TBaseHotkeysList = specialize TFPGObjectList<THotkey>;
@ -79,22 +81,29 @@ type
procedure DoOnChange(hotkey: THotkey; operation: THotkeyOperation);
public
constructor Create(AFreeObjects: Boolean = True); reintroduce;
function Add(Shortcut: String; Command: String; const Params: array of String): THotkey; overload;
function AddIfNotExists(Shortcut: String; Command: String; const Params: array of String): THotkey; overload;
function Add(const Shortcuts, Params: array of String; Command: String): THotkey; overload;
function AddIfNotExists(const Shortcuts, Params: array of String; Command: String): THotkey; overload;
{en
Adds multiple shortcuts to the same command.
@param(ShortcutsWithParams
Array of shortcuts followed by any number of parameters.
Each shortcut+parameters needs to end with an empty string.
[Shortcut1, S1Param1, '', Shortcut2, S2Param1, S2Param2, '', ...])
Each shortcuts array must end with an empty string,
and similarly each parameters must end with an empty string.
[Shortcut1A, Shortcut1B, '', S1ParamA, '',
Shortcut2, '', S2ParamA, S2ParamB, '', ...])
@param(Command
Command to which the shortcuts should be added.)
}
procedure AddIfNotExists(const ShortcutsWithParams: array of String; Command: String);
procedure Clear;
procedure Delete(Shortcut: String); reintroduce;
procedure Clear; reintroduce;
procedure Remove(var hotkey: THotkey); reintroduce;
function Find(Shortcut: String): THotkey; overload;
function Find(const Shortcuts: TDynamicStringArray): THotkey;
{en
Find hotkey which shortcuts begin with Shortcuts parameter.
If BothWays=@true then also looks for shortcuts which are the beginning
of Shortcuts parameter.
}
function FindByBeginning(const Shortcuts: TDynamicStringArray; BothWays: Boolean): THotkey;
function FindByCommand(Command: String): THotkey;
function FindByContents(Hotkey: THotkey): THotkey;
property OnChange: THotkeyEvent read FOnChange write FOnChange;
@ -169,6 +178,9 @@ type
THotKeyManager = class
private
FForms: THMForms;
FLastShortcutTime: Double; // When last shortcut was received (used for sequences of shortcuts)
FSequenceStep: Integer; // Which hotkey we are waiting for (from 0)
FShortcutsSequence: TDynamicStringArray; // Sequence of shortcuts that has been processed since last key event
FVersion: Integer;
//---------------------
procedure ClearAllHotkeys;
@ -176,7 +188,7 @@ type
procedure KeyDownHandler(Sender: TObject; var Key: Word; Shift: TShiftState);
//---------------------
//This function is called from KeyDownHandler to find registered hotkey and execute assigned action
function HotKeyEvent(Form: TCustomForm; Shortcut: String; Hotkeys: THotkeys): Boolean;
function HotKeyEvent(Form: TCustomForm; Hotkeys: THotkeys): Boolean;
//---------------------
function RegisterForm(AFormName: String): THMForm;
function RegisterControl(AFormName: String; AControlName: String): THMControl;
@ -208,12 +220,15 @@ uses
XMLRead, uKeyboard, uGlobs, uDebug, uOSUtils, uDCUtils, uDCVersion,
uFormCommands;
const
MaxShortcutSequenceInterval = 1000; // in ms
{ THotkey }
function THotkey.Clone: THotkey;
begin
Result := THotkey.Create;
Result.Shortcut := Shortcut;
Result.Shortcuts := Copy(Shortcuts);
Result.Command := Command;
Result.Params := Copy(Params);
end;
@ -228,11 +243,23 @@ begin
Result := Contains(Params, aParam);
end;
function THotkey.SameAs(Hotkey: THotkey): Boolean;
begin
Result := (Command = Hotkey.Command) and
(SameShortcuts(Hotkey.Shortcuts)) and
(SameParams(Hotkey.Params));
end;
function THotkey.SameParams(const aParams: array of String): Boolean;
begin
Result := Compare(Params, aParams);
end;
function THotkey.SameShortcuts(const aShortcuts: array of String): Boolean;
begin
Result := Compare(Shortcuts, aShortcuts);
end;
{ TFreeNotifier }
procedure TFreeNotifier.Notification(AComponent: TComponent; Operation: TOperation);
@ -250,56 +277,77 @@ begin
inherited Create(AFreeObjects);
end;
function THotkeys.Add(Shortcut: String; Command: String; const Params: array of String): THotkey;
function THotkeys.Add(const Shortcuts, Params: array of String; Command: String): THotkey;
begin
Result := THotkey.Create;
Result.Shortcut := Shortcut;
Result.Command := Command;
Result.Params := CopyArray(Params);
Add(Result);
DoOnChange(Result, hopAdd);
if (Command <> EmptyStr) and (Length(Shortcuts) > 0) then
begin
Result := THotkey.Create;
Result.Shortcuts := CopyArray(Shortcuts);
Result.Params := CopyArray(Params);
Result.Command := Command;
Add(Result);
DoOnChange(Result, hopAdd);
end
else
Result := nil;
end;
function THotkeys.AddIfNotExists(Shortcut: String; Command: String; const Params: array of String): THotkey;
function THotkeys.AddIfNotExists(const Shortcuts, Params: array of String; Command: String): THotkey;
var
i: Integer;
begin
// Check if the shortcut isn't already assigned to a different command
// Check if the shortcuts aren't already assigned to a different command
// or if a different shortcut isn't already assigned to the command.
// Also check if the shortucts aren't a partial match to another shortcuts.
for i := 0 to Count - 1 do
begin
if (Items[i].Shortcut = Shortcut) or (Items[i].Command = Command) then
if ArrBegins(Items[i].Shortcuts, Shortcuts, True) or (Items[i].Command = Command) then
Exit(nil);
end;
Result := Add(Shortcut, Command, Params);
Result := Add(Shortcuts, Params, Command);
end;
procedure THotkeys.AddIfNotExists(const ShortcutsWithParams: array of String; Command: String);
var
s: String;
ShortCut: String = '';
Params: array of String = nil;
StartIndex: Integer;
function GetArray: TDynamicStringArray;
var
i: Integer;
begin
Result := nil;
for i := StartIndex to High(ShortcutsWithParams) do
begin
s := ShortcutsWithParams[i];
if s <> '' then
AddString(Result, s)
else
Break;
end;
Inc(StartIndex);
end;
var
Shortcuts, Params: array of String;
begin
// Check if a different shortcut isn't already assigned to the command.
if Assigned(FindByCommand(Command)) then
Exit;
for s in ShortcutsWithParams do
StartIndex := Low(ShortcutsWithParams);
while True do
begin
if s = '' then
Shortcuts := GetArray;
Params := GetArray;
if Length(Shortcuts) > 0 then
begin
// Check if the shortcut isn't already assigned to a different command.
if not Assigned(Find(ShortCut)) then
Add(ShortCut, Command, Params);
ShortCut := '';
SetLength(Params, 0);
// Check if the shortcuts aren't already assigned to a different command.
if not Assigned(FindByBeginning(Shortcuts, True)) then
Add(Shortcuts, Params, Command);
end
else if ShortCut = '' then
ShortCut := s
else
begin
AddString(Params, s);
end;
Break;
end;
end;
@ -314,19 +362,6 @@ begin
end;
end;
procedure THotkeys.Delete(Shortcut: String);
var
i: Integer;
begin
for i := 0 to Count - 1 do
if Items[i].ShortCut = Shortcut then
begin
DoOnChange(Items[i], hopRemove);
inherited Delete(i);
Exit;
end;
end;
procedure THotkeys.Remove(var hotkey: THotkey);
begin
if Assigned(hotkey) then
@ -338,12 +373,22 @@ begin
end;
end;
function THotkeys.Find(Shortcut: String): THotkey;
function THotkeys.Find(const Shortcuts: TDynamicStringArray): THotkey;
var
i: Integer;
begin
for i := 0 to Count - 1 do
if Items[i].ShortCut = Shortcut then
if Items[i].SameShortcuts(Shortcuts) then
Exit(Items[i]);
Result := nil;
end;
function THotkeys.FindByBeginning(const Shortcuts: TDynamicStringArray; BothWays: Boolean): THotkey;
var
i: Integer;
begin
for i := 0 to Count - 1 do
if ArrBegins(Items[i].Shortcuts, Shortcuts, BothWays) then
Exit(Items[i]);
Result := nil;
end;
@ -365,9 +410,7 @@ begin
for i := 0 to Count - 1 do
begin
Result := Items[i];
if (Result.ShortCut = Hotkey.Shortcut) and
(Result.Command = Hotkey.Command) and
(Result.SameParams(Hotkey.Params)) then
if Result.SameAs(Hotkey) then
Exit;
end;
Result := nil;
@ -461,7 +504,7 @@ var
i, j: Integer;
shortcut, newShortcut: TShortCut;
begin
shortcut := TextToShortCutEx(hotkey.Shortcut);
shortcut := TextToShortCutEx(hotkey.Shortcuts[0]);
for i := 0 to FActionLists.Count - 1 do
begin
action := GetActionByCommand(FActionLists[i], hotkey.Command);
@ -477,7 +520,7 @@ begin
for j := 0 to hotkeys.Count - 1 do
if (hotkeys[j].Command = hotkey.Command) and (hotkeys[j] <> hotkey) then
begin
newShortcut := TextToShortCutEx(hotkeys[j].Shortcut);
newShortcut := TextToShortCutEx(hotkeys[j].Shortcuts[0]);
Break;
end;
end;
@ -494,7 +537,7 @@ var
i: Integer;
shortcut: TShortCut;
begin
shortcut := TextToShortCutEx(hotkey.Shortcut);
shortcut := TextToShortCutEx(hotkey.Shortcuts[0]);
for i := 0 to FActionLists.Count - 1 do
begin
action := GetActionByCommand(FActionLists[i], hotkey.Command);
@ -651,6 +694,7 @@ end;
constructor THotKeyManager.Create;
begin
FForms := THMForms.Create(True);
FSequenceStep := 0;
end;
destructor THotKeyManager.Destroy;
@ -724,8 +768,9 @@ var
begin
HotkeyNode := Config.AddNode(Node, 'Hotkey');
Config.SetAttr(HotkeyNode, 'Key', Hotkeys[i].Shortcut);
Config.SetValue(HotkeyNode, 'Command', Hotkeys[i].Command);
for j := Low(Hotkeys[i].Shortcuts) to High(Hotkeys[i].Shortcuts) do
Config.AddValue(HotkeyNode, 'Shortcut', Hotkeys[i].Shortcuts[j]);
Config.AddValue(HotkeyNode, 'Command', Hotkeys[i].Command);
for j := Low(Hotkeys[i].Params) to High(Hotkeys[i].Params) do
Config.AddValue(HotkeyNode, 'Param', Hotkeys[i].Params[j]);
@ -775,55 +820,75 @@ procedure THotKeyManager.Load(Config: TXmlConfig; Root: TXmlNode);
var
Form: THMForm;
procedure AddIfNotEmpty(var Arr: TDynamicStringArray; const Value: String);
begin
if Value <> '' then
AddString(Arr, Value);
end;
procedure LoadHotkey(Hotkeys: THotkeys; Node: TXmlNode);
var
Shortcut, Command, Param: String;
Shortcuts: array of String = nil;
Params: array of String = nil;
Controls: array of String = nil;
HMControl: THMControl;
i: Integer;
begin
if (Config.TryGetAttr(Node, 'Key', Shortcut)) and
(((FVersion <= 1) and Config.TryGetAttr(Node, 'Command', Command)) or
Config.TryGetValue(Node, 'Command', Command)) and
(Shortcut <> EmptyStr) and
(Command <> EmptyStr) then
// These checks for version may be removed after 0.5.5 release because
// the XML format for hotkeys has only been added in development version 0.5.5.
// Only Command needs to be retrieved here.
if FVersion <= 1 then
Command := Config.GetAttr(Node, 'Command', '')
else
Command := Config.GetValue(Node, 'Command', ''); // Leave only this
if FVersion <= 1 then
Param := Config.GetAttr(Node, 'Params', '')
else if FVersion < 9 then
Param := Config.GetValue(Node, 'Params', '');
if FVersion < 10 then
begin
if FVersion <= 1 then
Param := Config.GetAttr(Node, 'Params', '')
else if FVersion < 9 then
Param := Config.GetValue(Node, 'Params', '');
if (FVersion < 9) and (Param <> '') then
AddString(Params, Param);
Shortcut := NormalizeModifiers(Shortcut);
Node := Node.FirstChild;
while Assigned(Node) do
Shortcut := Config.GetAttr(Node, 'Key', '');
if Shortcut <> '' then
begin
if Node.CompareName('Control') = 0 then
AddString(Controls, Config.GetContent(Node))
else if Node.CompareName('Param') = 0 then
AddString(Params, Config.GetContent(Node));
Node := Node.NextSibling;
Shortcut := NormalizeModifiers(Shortcut);
AddIfNotEmpty(Shortcuts, Shortcut);
end;
end;
if (FVersion < 9) then
AddIfNotEmpty(Params, Param);
// Up to here may be deleted after 0.5.5 release.
Node := Node.FirstChild;
while Assigned(Node) do
begin
if Node.CompareName('Shortcut') = 0 then
AddIfNotEmpty(Shortcuts, NormalizeModifiers(Config.GetContent(Node)))
else if Node.CompareName('Control') = 0 then
AddIfNotEmpty(Controls, Config.GetContent(Node))
else if Node.CompareName('Param') = 0 then
AddIfNotEmpty(Params, Config.GetContent(Node));
Node := Node.NextSibling;
end;
if Length(Shortcuts) > 0 then
begin
if Length(Controls) = 0 then
begin
if (FVersion <= 3) and IsShortcutConflictingWithOS(Shortcut) then
// This "if" block may also be deleted after 0.5.5 release.
if (FVersion <= 3) and IsShortcutConflictingWithOS(Shortcuts[0]) then
begin
HMControl := Form.Controls.FindOrCreate('Files Panel');
HMControl.Hotkeys.AddIfNotExists(Shortcut, Command, Params);
HMControl.Hotkeys.AddIfNotExists(Shortcuts, Params, Command);
end
else
Hotkeys.Add(Shortcut, Command, Params);
Hotkeys.Add(Shortcuts, Params, Command); // Leave only this
end
else
begin
for i := Low(Controls) to High(Controls) do
begin
HMControl := Form.Controls.FindOrCreate(Controls[i]);
HMControl.Hotkeys.Add(Shortcut, Command, Params);
HMControl.Hotkeys.Add(Shortcuts, Params, Command);
end;
end;
end;
@ -873,6 +938,7 @@ var
form: THMForm;
control: THMControl;
Command, Param, FormName, ControlName: String;
Params: array of String = nil;
procedure RemoveFrmPrexif(var s: String);
begin
@ -890,36 +956,47 @@ begin
begin
section := st[i];
shortCut := NormalizeModifiers(section);
j := 0;
while ini.ValueExists(section, 'Command' + IntToStr(j)) do
if shortCut <> '' then
begin
Command := ini.ReadString(section, 'Command' + IntToStr(j), '');
Param := ini.ReadString(section, 'Param' + IntToStr(j), '');
ControlName := ini.ReadString(section, 'Object' + IntToStr(j), '');
FormName := ini.ReadString(section, 'Form' + IntToStr(j), '');
RemoveFrmPrexif(FormName);
RemoveFrmPrexif(ControlName);
form := FForms.FindOrCreate(FormName);
if IsShortcutConflictingWithOS(shortCut) then
ControlName := 'Files Panel';
// Old config had FormName=ControlName for main form.
if SameText(FormName, ControlName) then
j := 0;
while ini.ValueExists(section, 'Command' + IntToStr(j)) do
begin
hotkeys := form.Hotkeys;
end
else
begin
control := form.Controls.FindOrCreate(ControlName);
hotkeys := control.Hotkeys;
Command := ini.ReadString(section, 'Command' + IntToStr(j), '');
Param := ini.ReadString(section, 'Param' + IntToStr(j), '');
ControlName := ini.ReadString(section, 'Object' + IntToStr(j), '');
FormName := ini.ReadString(section, 'Form' + IntToStr(j), '');
RemoveFrmPrexif(FormName);
RemoveFrmPrexif(ControlName);
form := FForms.FindOrCreate(FormName);
if IsShortcutConflictingWithOS(shortCut) then
ControlName := 'Files Panel';
// Old config had FormName=ControlName for main form.
if SameText(FormName, ControlName) then
begin
hotkeys := form.Hotkeys;
end
else
begin
control := form.Controls.FindOrCreate(ControlName);
hotkeys := control.Hotkeys;
end;
if Param <> '' then
begin
SetLength(Params, 1);
Params[0] := Param;
end
else
Params := nil;
hotkeys.Add([shortcut], Params, Command);
j := j + 1;
end;
hotkeys.Add(shortcut, Command, [Param]);
j := j + 1;
end;
end;
@ -1090,17 +1167,28 @@ begin
end;
end;
function THotKeyManager.HotKeyEvent(Form: TCustomForm; Shortcut: String; Hotkeys: THotkeys): Boolean;
function THotKeyManager.HotKeyEvent(Form: TCustomForm; Hotkeys: THotkeys): Boolean;
var
hotkey: THotkey;
FormCommands: IFormCommands;
begin
hotkey := Hotkeys.Find(Shortcut);
hotkey := Hotkeys.FindByBeginning(FShortcutsSequence, False);
if Assigned(hotkey) then
begin
FormCommands := Form as IFormCommands;
Result := Assigned(FormCommands) and
(FormCommands.ExecuteCommand(hotkey.Command, hotkey.Params) = cfrSuccess);
if High(hotkey.Shortcuts) > FSequenceStep then
begin
// There are more shortcuts to match.
FLastShortcutTime := SysUtils.Now;
Inc(FSequenceStep);
Result := True;
end
else
begin
FSequenceStep := 0;
FormCommands := Form as IFormCommands;
Result := Assigned(FormCommands) and
(FormCommands.ExecuteCommand(hotkey.Command, hotkey.Params) = cfrSuccess);
end;
end
else
Result := False;
@ -1157,7 +1245,9 @@ begin
Control := Form.ActiveControl;
// Don't execute hotkeys that coincide with key typing actions.
if not (((GetKeyTypingAction(ShiftEx) <> ktaNone)
if (TextShortcut <> '') and
((FSequenceStep > 0) or
(not (((GetKeyTypingAction(ShiftEx) <> ktaNone)
{$IFDEF MSWINDOWS}
// Don't execute hotkeys with Ctrl+Alt = AltGr on Windows.
or ((ShiftEx * KeyModifiersShortcutNoText = [ssCtrl, ssAlt]) and
@ -1165,8 +1255,17 @@ begin
// Don't execute hotkeys with AltGr on Windows.
or (ShiftEx = [ssAltGr])
{$ENDIF}
) and (Key in [VK_0..VK_9, VK_A..VK_Z])) then
) and (Key in [VK_0..VK_9, VK_A..VK_Z])))) then
begin
// If too much time has passed reset sequence.
if (FSequenceStep > 0) and (DateTimeToTimeStamp(SysUtils.Now - FLastShortcutTime).Time > MaxShortcutSequenceInterval) then
FSequenceStep := 0;
// Add shortcut to sequence.
if Length(FShortcutsSequence) <> FSequenceStep + 1 then
SetLength(FShortcutsSequence, FSequenceStep + 1);
FShortcutsSequence[FSequenceStep] := TextShortcut;
if Assigned(Control) then
begin
for i := 0 to HMForm.Controls.Count - 1 do
@ -1175,7 +1274,7 @@ begin
HMControlInstance := HMControl.Find(Control);
if Assigned(HMControlInstance) then
begin
if HotKeyEvent(Form, TextShortcut, HMControl.Hotkeys) then
if HotKeyEvent(Form, HMControl.Hotkeys) then
begin
Key := VK_UNKNOWN;
Exit;
@ -1188,11 +1287,13 @@ begin
end;
// Hotkey for the whole form
if HotKeyEvent(Form, TextShortcut, HMForm.Hotkeys) then
if HotKeyEvent(Form, HMForm.Hotkeys) then
begin
Key := VK_UNKNOWN;
Exit;
end;
FSequenceStep := 0; // Hotkey was not matched - reset sequence.
end;
if Key <> VK_UNKNOWN then

View file

@ -416,6 +416,8 @@ resourcestring
rsOptHotkeysSetDeleteShortcut = 'Set shortcut to delete file';
rsOptHotkeysShortcutForDeleteAlreadyAssigned =
'For this setting to work with shortcut %s, shortcut %s must be assigned to cm_Delete but it is already assigned to %s. Do you want to change it?';
rsOptHotkeysShortcutForDeleteIsSequence =
'Shortcut %s for cm_Delete is a sequence shortcut for which a hotkey with reversed Shift cannot be assigned. This setting might not work.';
rsOptHotkeysCommand = 'Command';
rsOptHotkeysDescription = 'Description';
rsOptHotkeysFixParameter = 'Fix parameter';