EditorOpts: Fixed Keymaps, combo strokes in plugins

git-svn-id: trunk@35406 -
This commit is contained in:
martin 2012-02-17 01:58:06 +00:00
parent ce0c730b46
commit a1ff712f8b
4 changed files with 137 additions and 74 deletions

View File

@ -381,7 +381,10 @@ type
procedure CallHookedKeyTranslationHandlers(Sender: TObject; procedure CallHookedKeyTranslationHandlers(Sender: TObject;
Code: word; SState: TShiftState; var Data: pointer; Code: word; SState: TShiftState; var Data: pointer;
var IsStartOfCombo: boolean; var Handled: boolean; var IsStartOfCombo: boolean; var Handled: boolean;
var Command: TSynEditorCommand; var ComboKeyStrokes: TSynEditKeyStrokes); var Command: TSynEditorCommand;
// ComboKeyStrokes decides, either FinishComboOnly, or new stroke
var ComboKeyStrokes: TSynEditKeyStrokes
);
end; end;
TSynMouseLinkEvent = procedure ( TSynMouseLinkEvent = procedure (
@ -488,7 +491,8 @@ type
fHideSelection: boolean; fHideSelection: boolean;
fOverwriteCaret: TSynEditCaretType; fOverwriteCaret: TSynEditCaretType;
fInsertCaret: TSynEditCaretType; fInsertCaret: TSynEditCaretType;
FKeyStrokes, FLastKeyStrokes: TSynEditKeyStrokes; FKeyStrokes: TSynEditKeyStrokes;
FCurrentComboKeyStrokes: TSynEditKeyStrokes; // Holding info about the keystroke(s) already received for a mult-stroke-combo
FMouseActions, FMouseSelActions, FMouseTextActions: TSynEditMouseInternalActions; FMouseActions, FMouseSelActions, FMouseTextActions: TSynEditMouseInternalActions;
FMouseActionSearchHandlerList: TSynEditMouseActionSearchList; FMouseActionSearchHandlerList: TSynEditMouseActionSearchList;
FMouseActionExecHandlerList: TSynEditMouseActionExecList; FMouseActionExecHandlerList: TSynEditMouseActionExecList;
@ -1989,7 +1993,7 @@ begin
fInsertCaret := ctVerticalLine; fInsertCaret := ctVerticalLine;
fOverwriteCaret := ctBlock; fOverwriteCaret := ctBlock;
FKeystrokes := TSynEditKeyStrokes.Create(Self); FKeystrokes := TSynEditKeyStrokes.Create(Self);
FLastKeyStrokes := nil; FCurrentComboKeyStrokes := nil;
if assigned(Owner) and not (csLoading in Owner.ComponentState) then begin if assigned(Owner) and not (csLoading in Owner.ComponentState) then begin
SetDefaultKeystrokes; SetDefaultKeystrokes;
end; end;
@ -2597,28 +2601,65 @@ begin
inherited; inherited;
if assigned(fMarkupCtrlMouse) then if assigned(fMarkupCtrlMouse) then
fMarkupCtrlMouse.UpdateCtrlState(Shift); fMarkupCtrlMouse.UpdateCtrlState(Shift);
if Key in [VK_SHIFT, VK_CONTROL, VK_MENU,
VK_LSHIFT, VK_LCONTROL, VK_LMENU,
VK_RSHIFT, VK_RCONTROL, VK_RMENU,
VK_LWIN, VK_RWIN]
then
exit;
Data := nil; Data := nil;
C := #0; C := #0;
try try
IsStartOfCombo := False;
Handled := False;
// If the translations requires Data, memory will be allocated for it via a // If the translations requires Data, memory will be allocated for it via a
// GetMem call. The client must call FreeMem on Data if it is not NIL. // GetMem call. The client must call FreeMem on Data if it is not NIL.
if FLastKeyStrokes = FKeyStrokes then begin IsStartOfCombo := False;
Cmd := KeyStrokes.FindKeycodeEx(Key, Shift, Data, IsStartOfCombo, True); Handled := False;
Handled := Cmd <> ecNone;
end; // Check 2nd stroke in SynEdit.KeyStrokes
// Hooked if FCurrentComboKeyStrokes <> nil then begin
if not Handled then // Run hooked first, it might want to "steal" the key(s)
FHookedKeyTranslationList.CallHookedKeyTranslationHandlers(self, FHookedKeyTranslationList.CallHookedKeyTranslationHandlers(self,
Key, Shift, Data, IsStartOfCombo, Handled, Cmd, FLastKeyStrokes); Key, Shift, Data, IsStartOfCombo, Handled, Cmd, FCurrentComboKeyStrokes);
if not Handled then begin
Cmd := KeyStrokes.FindKeycodeEx(Key, Shift, Data, IsStartOfCombo, True, FCurrentComboKeyStrokes);
if IsStartOfCombo then
FCurrentComboKeyStrokes := FKeyStrokes;
Handled := (Cmd <> ecNone) or IsStartOfCombo;
end;
if not IsStartOfCombo then begin
FCurrentComboKeyStrokes.ResetKeyCombo;
FCurrentComboKeyStrokes := nil;
end;
end;
assert(Handled or (FCurrentComboKeyStrokes=nil), 'FCurrentComboKeyStrokes<>nil, should be handled');
// Check 1st/single stroke in Hooked KeyStrokes
if not Handled then begin if not Handled then begin
FCurrentComboKeyStrokes := nil;
FHookedKeyTranslationList.CallHookedKeyTranslationHandlers(self,
Key, Shift, Data, IsStartOfCombo, Handled, Cmd, FCurrentComboKeyStrokes);
if (not IsStartOfCombo) and (FCurrentComboKeyStrokes <> nil) then
FCurrentComboKeyStrokes.ResetKeyCombo; // should not happen
end;
// Check 1st/single stroke in SynEdit.KeyStrokes
if not Handled then begin
FKeyStrokes.ResetKeyCombo;
Cmd := KeyStrokes.FindKeycodeEx(Key, Shift, Data, IsStartOfCombo); Cmd := KeyStrokes.FindKeycodeEx(Key, Shift, Data, IsStartOfCombo);
if IsStartOfCombo then if IsStartOfCombo then
FLastKeyStrokes := FKeyStrokes; FCurrentComboKeyStrokes := FKeyStrokes;
end; end;
if Cmd <> ecNone then begin if Cmd <> ecNone then begin
// Reset FCurrentComboKeyStrokes => no open combo
assert(FCurrentComboKeyStrokes=nil, 'FCurrentComboKeyStrokes<>nil, should be ecNone');
if FCurrentComboKeyStrokes <> nil then
FCurrentComboKeyStrokes.ResetKeyCombo;
FCurrentComboKeyStrokes := nil;
Include(FStateFlags, sfHideCursor); Include(FStateFlags, sfHideCursor);
LastMouseCaret := Point(-1,-1); // includes update cursor LastMouseCaret := Point(-1,-1); // includes update cursor
//DebugLn(['[TCustomSynEdit.KeyDown] key translated ',cmd]); //DebugLn(['[TCustomSynEdit.KeyDown] key translated ',cmd]);
@ -8722,16 +8763,18 @@ procedure TSynHookedKeyTranslationList.CallHookedKeyTranslationHandlers(Sender:
var var
i: Integer; i: Integer;
begin begin
// Finish Combo ? if ComboKeyStrokes <> nil then begin
for i := 0 to Count - 1 do // Finish Combo
THookedKeyTranslationEvent(Items[i])(Sender, Code, SState, Data, for i := 0 to Count - 1 do
IsStartOfCombo, Handled, Command, True, ComboKeyStrokes); THookedKeyTranslationEvent(Items[i])(Sender, Code, SState, Data,
if Handled then IsStartOfCombo, Handled, Command, True, ComboKeyStrokes);
exit; end
// New Stroke ? else begin
for i := 0 to Count - 1 do // New Stroke
THookedKeyTranslationEvent(Items[i])(Sender, Code, SState, Data, for i := 0 to Count - 1 do
IsStartOfCombo, Handled, Command, False, ComboKeyStrokes); THookedKeyTranslationEvent(Items[i])(Sender, Code, SState, Data,
IsStartOfCombo, Handled, Command, False, ComboKeyStrokes);
end;
end; end;
{ TSynStatusChangedHandlerList } { TSynStatusChangedHandlerList }

View File

@ -357,7 +357,8 @@ type
function FindKeycode(Code: word; SS: TShiftState): integer; function FindKeycode(Code: word; SS: TShiftState): integer;
function FindKeycodeEx(Code: word; SS: TShiftState; var Data: pointer; function FindKeycodeEx(Code: word; SS: TShiftState; var Data: pointer;
out IsStartOfCombo: boolean; out IsStartOfCombo: boolean;
FinishComboOnly: Boolean = False): TSynEditorCommand; FinishComboOnly: Boolean = False;
ComboStart: TSynEditKeyStrokes = nil): TSynEditorCommand;
procedure ResetKeyCombo; procedure ResetKeyCombo;
function FindShortcut(SC: TShortcut): integer; function FindShortcut(SC: TShortcut): integer;
function FindShortcut2(SC, SC2: TShortcut): integer; function FindShortcut2(SC, SC2: TShortcut): integer;
@ -921,34 +922,70 @@ begin
end; end;
end; end;
function TSynEditKeyStrokes.FindKeycodeEx(Code: word; SS: TShiftState; var Data: pointer; out function TSynEditKeyStrokes.FindKeycodeEx(Code: word; SS: TShiftState; var Data: pointer;
IsStartOfCombo: boolean; FinishComboOnly: Boolean = False): TSynEditorCommand; out IsStartOfCombo: boolean;
FinishComboOnly: Boolean; ComboStart: TSynEditKeyStrokes): TSynEditorCommand;
var var
i: integer; i: integer;
LK: Word;
LS: TShiftState;
CurComboStart: TSynEditKeyStrokes;
{$IFNDEF SYN_COMPILER_3_UP} {$IFNDEF SYN_COMPILER_3_UP}
const const
VK_ACCEPT = $30; VK_ACCEPT = $30;
{$ENDIF} {$ENDIF}
begin begin
i := FindKeycode2(fLastKey, fLastShiftState, Code, SS); (* if FinishComboOnly=True then ComboStart are the KeyStrokes, which have the
if (i < 0) and not FinishComboOnly then already received keys.
i := FindKeycode(Code, SS); If several TSynEditKeyStrokes have combos, starting with the same key(s)
if i >= 0 then only one needs to keep the info. The others chek, if they have a matching combo
Result := Items[i].Command *)
else
Result := ecNone;
if (Result = ecNone) and (Code >= VK_ACCEPT) and (Code <= VK_SCROLL) and Result := ecNone;
(FindKeycode2Start(Code, SS) >= 0) and not FinishComboOnly then IsStartOfCombo := False;
if ComboStart = nil then
CurComboStart := self
else
CurComboStart := ComboStart;
if CurComboStart.fLastKey <> 0 then begin
// Try to finish the combo
i := FindKeycode2(CurComboStart.fLastKey, CurComboStart.fLastShiftState, Code, SS);
if (i >= 0) then begin
Result := Items[i].Command;
CurComboStart.ResetKeyCombo;
exit;
end;
end;
if FinishComboOnly then
exit;
// Check for single stroke
i := FindKeycode(Code, SS);
if i >= 0 then begin
Result := Items[i].Command;
ResetKeyCombo;
if (ComboStart <> nil) and (ComboStart <> self) then
ComboStart.ResetKeyCombo;
exit;
end;
if (FindKeycode2Start(Code, SS) >= 0) and not FinishComboOnly then
begin begin
fLastKey := Code; fLastKey := Code;
fLastShiftState := SS; fLastShiftState := SS;
IsStartOfCombo := True; IsStartOfCombo := True;
end else begin // Now this is the start of combo
fLastKey := 0; if (ComboStart <> nil) and (ComboStart <> self) then
fLastShiftState := []; ComboStart.ResetKeyCombo;
IsStartOfCombo := False; end
end; else begin
// Nothing was found.
// Keep CurComboStart.fLastKey. It may be ued by another TSynEditKeyStrokes
if (ComboStart <> self) then
ResetKeyCombo; // reset self, if not CurComboStart
end
end; end;
procedure TSynEditKeyStrokes.ResetKeyCombo; procedure TSynEditKeyStrokes.ResetKeyCombo;

View File

@ -1326,38 +1326,30 @@ begin
exit; exit;
keys := nil; keys := nil;
if Mode = spseSelecting then if Mode = spseSelecting then
keys := FKeystrokesSelecting; keys := FKeystrokesSelecting;
if Mode = spseEditing then begin if Mode = spseEditing then begin
if CurrentCell < 0 then begin if CurrentCell < 0 then
keys := FKeyStrokesOffCell; keys := FKeyStrokesOffCell
FKeyStrokes.ResetKeyCombo; else
end
else begin
keys := FKeyStrokes; keys := FKeyStrokes;
FKeyStrokesOffCell.ResetKeyCombo;
end;
end; end;
if keys = nil then exit; if keys = nil then exit;
if (FinishComboOnly and (ComboKeyStrokes <> keys)) then begin
keys.ResetKeyCombo;
exit;
end;
IsStartOfCombo := False;
try try
keys.UsePluginOffset := True; keys.UsePluginOffset := True;
Command := keys.FindKeycodeEx(Code, SState, Data, IsStartOfCombo, if not FinishComboOnly then
FinishComboOnly); keys.ResetKeyCombo;
Command := keys.FindKeycodeEx(Code, SState, Data, IsStartOfCombo, FinishComboOnly, ComboKeyStrokes);
finally finally
keys.UsePluginOffset := False; keys.UsePluginOffset := False;
end; end;
Handled := (Command <> ecNone) or IsStartOfCombo; Handled := (Command <> ecNone) or IsStartOfCombo;
if Handled then begin if IsStartOfCombo then
ComboKeyStrokes := keys; ComboKeyStrokes := keys;
end;
end; end;
procedure TSynPluginSyncroEdit.ProcessSynCommand(Sender: TObject; AfterProcessing: boolean; procedure TSynPluginSyncroEdit.ProcessSynCommand(Sender: TObject; AfterProcessing: boolean;

View File

@ -199,32 +199,23 @@ begin
if (not Active) or Handled then if (not Active) or Handled then
exit; exit;
if CurrentCell < 0 then begin if CurrentCell < 0 then
keys := FKeyStrokesOffCell; keys := FKeyStrokesOffCell
FKeyStrokes.ResetKeyCombo; else
end
else begin
keys := FKeyStrokes; keys := FKeyStrokes;
FKeyStrokesOffCell.ResetKeyCombo;
end;
if (FinishComboOnly and (ComboKeyStrokes <> keys)) then begin
keys.ResetKeyCombo;
exit;
end;
IsStartOfCombo := False;
try try
keys.UsePluginOffset := True; keys.UsePluginOffset := True;
Command := keys.FindKeycodeEx(Code, SState, Data, IsStartOfCombo, if not FinishComboOnly then
FinishComboOnly); keys.ResetKeyCombo;
Command := keys.FindKeycodeEx(Code, SState, Data, IsStartOfCombo, FinishComboOnly, ComboKeyStrokes);
finally finally
keys.UsePluginOffset := False; keys.UsePluginOffset := False;
end; end;
Handled := (Command <> ecNone) or IsStartOfCombo; Handled := (Command <> ecNone) or IsStartOfCombo;
if Handled then begin if IsStartOfCombo then
ComboKeyStrokes := keys; ComboKeyStrokes := keys;
end;
end; end;
procedure TSynPluginTemplateEdit.ProcessSynCommand(Sender: TObject; AfterProcessing: boolean; procedure TSynPluginTemplateEdit.ProcessSynCommand(Sender: TObject; AfterProcessing: boolean;