mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-05 10:37:58 +02:00
1240 lines
46 KiB
ObjectPascal
1240 lines
46 KiB
ObjectPascal
{-------------------------------------------------------------------------------
|
|
The contents of this file are subject to the Mozilla Public License
|
|
Version 1.1 (the "License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
http://www.mozilla.org/MPL/
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
|
|
the specific language governing rights and limitations under the License.
|
|
|
|
The Original Code is: SynEditKeyCmds.pas, released 2000-04-07.
|
|
The Original Code is based on the mwKeyCmds.pas file from the
|
|
mwEdit component suite by Martin Waldenburg and other developers, the Initial
|
|
Author of this file is Brad Stowers.
|
|
All Rights Reserved.
|
|
|
|
Contributors to the SynEdit and mwEdit projects are listed in the
|
|
Contributors.txt file.
|
|
|
|
Alternatively, the contents of this file may be used under the terms of the
|
|
GNU General Public License Version 2 or later (the "GPL"), in which case
|
|
the provisions of the GPL are applicable instead of those above.
|
|
If you wish to allow use of your version of this file only under the terms
|
|
of the GPL and not to allow others to use your version of this file
|
|
under the MPL, indicate your decision by deleting the provisions above and
|
|
replace them with the notice and other provisions required by the GPL.
|
|
If you do not delete the provisions above, a recipient may use your version
|
|
of this file under either the MPL or the GPL.
|
|
|
|
$Id$
|
|
|
|
You may retrieve the latest version of this file at the SynEdit home page,
|
|
located at http://SynEdit.SourceForge.net
|
|
|
|
Known Issues:
|
|
-------------------------------------------------------------------------------}
|
|
|
|
unit SynEditKeyCmds;
|
|
|
|
{$I synedit.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, Menus, SysUtils, LCLIntf, LCLType, LCLProc, SynEditStrConst;
|
|
|
|
const
|
|
//****************************************************************************
|
|
// NOTE! If you add an editor command, you must also update the
|
|
// EditorCommandStrs constant array in implementation section below, or the
|
|
// command will not show up in the IDE.
|
|
//****************************************************************************
|
|
|
|
// "Editor Commands". Key strokes are translated from a table into these
|
|
// I used constants instead of a set so that additional commands could be
|
|
// added in descendants (you can't extend a set)
|
|
|
|
// There are two ranges of editor commands: the ecViewXXX commands are always
|
|
// valid, while the ecEditXXX commands are ignored when the editor is in
|
|
// read-only mode
|
|
|
|
ecNone = 0; // Nothing. Useful for user event to handle command
|
|
ecViewCommandFirst = 0;
|
|
ecViewCommandLast = 500;
|
|
ecEditCommandFirst = 501;
|
|
ecEditCommandLast = 1000;
|
|
|
|
ecLeft = 1; // Move cursor left one char
|
|
ecRight = 2; // Move cursor right one char
|
|
ecUp = 3; // Move cursor up one line
|
|
ecDown = 4; // Move cursor down one line
|
|
ecWordLeft = 5; // Move cursor left one word
|
|
ecWordRight = 6; // Move cursor right one word
|
|
ecLineStart = 7; // Move cursor to beginning of line (smart home)
|
|
ecLineEnd = 8; // Move cursor to end of line
|
|
ecPageUp = 9; // Move cursor up one page
|
|
ecPageDown = 10; // Move cursor down one page
|
|
ecPageLeft = 11; // Move cursor right one page
|
|
ecPageRight = 12; // Move cursor left one page
|
|
ecPageTop = 13; // Move cursor to top of page
|
|
ecPageBottom = 14; // Move cursor to bottom of page
|
|
ecEditorTop = 15; // Move cursor to absolute beginning
|
|
ecEditorBottom = 16; // Move cursor to absolute end
|
|
ecGotoXY = 17; // Move cursor to specific coordinates, Data = PPoint
|
|
ecLineTextStart = 18; // Move cursor to the first none whitespace in the line
|
|
ecWordEndLeft = 19; // Move cursor left one word (to end of word)
|
|
ecWordEndRight = 20; // Move cursor right one word (to end of word)
|
|
ecHalfWordLeft = 21; // Move cursor left to word-begin/end or case change lower to uppper
|
|
ecHalfWordRight = 22; // Move cursor right to word-begin/end or case change lower to uppper
|
|
ecSmartWordLeft = 23; // Move cursor left one word with smart boundaries (either start of current word or end of previous word)
|
|
ecSmartWordRight = 24; // Move cursor right one word with smart boundaries (either end of current word or start of next word)
|
|
|
|
// Allow selecting with any movement
|
|
ecStickySelection = 95;
|
|
ecStickySelectionCol = 96;
|
|
ecStickySelectionLine = 97;
|
|
ecStickySelectionStop = 99;
|
|
|
|
ecSelection = 100; // Add this to ecXXX command to get equivalent
|
|
// command, but with selection enabled. This is not
|
|
// a command itself.
|
|
|
|
ecSelectionStart = 100; // The lowest Selection Command
|
|
ecSelectionEnd = 199; // The highest Selection Command
|
|
|
|
// Same as commands above, except they affect selection, too
|
|
ecSelLeft = ecLeft + ecSelection;
|
|
ecSelRight = ecRight + ecSelection;
|
|
ecSelUp = ecUp + ecSelection;
|
|
ecSelDown = ecDown + ecSelection;
|
|
ecSelWordLeft = ecWordLeft + ecSelection;
|
|
ecSelWordRight = ecWordRight + ecSelection;
|
|
ecSelLineStart = ecLineStart + ecSelection;
|
|
ecSelLineEnd = ecLineEnd + ecSelection;
|
|
ecSelPageUp = ecPageUp + ecSelection;
|
|
ecSelPageDown = ecPageDown + ecSelection;
|
|
ecSelPageLeft = ecPageLeft + ecSelection;
|
|
ecSelPageRight = ecPageRight + ecSelection;
|
|
ecSelPageTop = ecPageTop + ecSelection;
|
|
ecSelPageBottom = ecPageBottom + ecSelection;
|
|
ecSelEditorTop = ecEditorTop + ecSelection;
|
|
ecSelEditorBottom = ecEditorBottom + ecSelection;
|
|
ecSelGotoXY = ecGotoXY + ecSelection; // Data = PPoint
|
|
ecSelLineTextStart= ecLineTextStart + ecSelection; // Move cursor to the first none whitespace in the line
|
|
ecSelWordEndLeft = ecWordEndLeft + ecSelection;
|
|
ecSelWordEndRight = ecWordEndRight + ecSelection;
|
|
ecSelHalfWordLeft = ecHalfWordLeft + ecSelection;
|
|
ecSelHalfWordRight= ecHalfWordRight + ecSelection;
|
|
ecSelSmartWordLeft= ecSmartWordLeft + ecSelection;
|
|
ecSelSmartWordRight=ecSmartWordRight + ecSelection;
|
|
|
|
ecSelCmdRangeStart = ecLeft + ecSelection;
|
|
ecSelCmdRangeEnd = ecLeft + ecSelection + 49;
|
|
|
|
// Allow access to column mode selection
|
|
ecColumnSelection = ecSelection+50;
|
|
|
|
ecColSelLeft = ecLeft + ecColumnSelection;
|
|
ecColSelRight = ecRight + ecColumnSelection;
|
|
ecColSelUp = ecUp + ecColumnSelection;
|
|
ecColSelDown = ecDown + ecColumnSelection;
|
|
ecColSelWordLeft = ecWordLeft + ecColumnSelection;
|
|
ecColSelWordRight = ecWordRight + ecColumnSelection;
|
|
ecColSelLineStart = ecLineStart + ecColumnSelection;
|
|
ecColSelLineEnd = ecLineEnd + ecColumnSelection;
|
|
ecColSelPageUp = ecPageUp + ecColumnSelection;
|
|
ecColSelPageDown = ecPageDown + ecColumnSelection;
|
|
ecColSelPageLeft = ecPageLeft + ecColumnSelection;
|
|
ecColSelPageRight = ecPageRight + ecColumnSelection;
|
|
ecColSelPageTop = ecPageTop + ecColumnSelection;
|
|
ecColSelPageBottom = ecPageBottom + ecColumnSelection;
|
|
ecColSelEditorTop = ecEditorTop + ecColumnSelection;
|
|
ecColSelEditorBottom = ecEditorBottom + ecColumnSelection;
|
|
ecColSelLineTextStart= ecLineTextStart + ecColumnSelection;
|
|
|
|
ecSelColCmdRangeStart = ecColumnSelection;
|
|
ecSelColCmdRangeEnd = ecColumnSelection + 48; // 1 less for ecSelectAll
|
|
|
|
|
|
ecSelectAll = 199; // Select entire contents of editor, cursor to end
|
|
|
|
ecCopy = 201; // Copy selection to clipboard
|
|
|
|
ecScrollUp = 211; // Scroll up one line leaving cursor position unchanged.
|
|
ecScrollDown = 212; // Scroll down one line leaving cursor position unchanged.
|
|
ecScrollLeft = 213; // Scroll left one char leaving cursor position unchanged.
|
|
ecScrollRight = 214; // Scroll right one char leaving cursor position unchanged.
|
|
|
|
ecInsertMode = 221; // Set insert mode
|
|
ecOverwriteMode = 222; // Set overwrite mode
|
|
ecToggleMode = 223; // Toggle ins/ovr mode
|
|
|
|
ecNormalSelect = 231; // Normal selection mode
|
|
ecColumnSelect = 232; // Column selection mode
|
|
ecLineSelect = 233; // Line selection mode
|
|
|
|
// Persistent Block
|
|
ecBlockSetBegin = 235;
|
|
ecBlockSetEnd = 236;
|
|
ecBlockToggleHide = 237;
|
|
ecBlockHide = 238;
|
|
ecBlockShow = 239;
|
|
ecBlockMove = 240;
|
|
ecBlockCopy = 241;
|
|
ecBlockDelete = 242;
|
|
ecBlockGotoBegin = 243;
|
|
ecBlockGotoEnd = 244;
|
|
|
|
ecMatchBracket = 250; // Go to matching bracket
|
|
|
|
ecGotoMarker0 = 301; // Goto marker
|
|
ecGotoMarker1 = 302; // Goto marker
|
|
ecGotoMarker2 = 303; // Goto marker
|
|
ecGotoMarker3 = 304; // Goto marker
|
|
ecGotoMarker4 = 305; // Goto marker
|
|
ecGotoMarker5 = 306; // Goto marker
|
|
ecGotoMarker6 = 307; // Goto marker
|
|
ecGotoMarker7 = 308; // Goto marker
|
|
ecGotoMarker8 = 309; // Goto marker
|
|
ecGotoMarker9 = 310; // Goto marker
|
|
ecSetMarker0 = 351; // Set marker, Data = PPoint - X, Y Pos
|
|
ecSetMarker1 = 352; // Set marker, Data = PPoint - X, Y Pos
|
|
ecSetMarker2 = 353; // Set marker, Data = PPoint - X, Y Pos
|
|
ecSetMarker3 = 354; // Set marker, Data = PPoint - X, Y Pos
|
|
ecSetMarker4 = 355; // Set marker, Data = PPoint - X, Y Pos
|
|
ecSetMarker5 = 356; // Set marker, Data = PPoint - X, Y Pos
|
|
ecSetMarker6 = 357; // Set marker, Data = PPoint - X, Y Pos
|
|
ecSetMarker7 = 358; // Set marker, Data = PPoint - X, Y Pos
|
|
ecSetMarker8 = 359; // Set marker, Data = PPoint - X, Y Pos
|
|
ecSetMarker9 = 360; // Set marker, Data = PPoint - X, Y Pos
|
|
ecToggleMarker0 = 361; // If marker is in the lie, remove marker, lese set marker, Data = PPoint - X, Y Pos
|
|
ecToggleMarker1 = 362;
|
|
ecToggleMarker2 = 363;
|
|
ecToggleMarker3 = 364;
|
|
ecToggleMarker4 = 365;
|
|
ecToggleMarker5 = 366;
|
|
ecToggleMarker6 = 367;
|
|
ecToggleMarker7 = 368;
|
|
ecToggleMarker8 = 369;
|
|
ecToggleMarker9 = 370;
|
|
|
|
EcFoldLevel1 = 371; // fold all folds, greater/equal than nesting level 1
|
|
EcFoldLevel2 = EcFoldLevel1 + 1;
|
|
EcFoldLevel3 = EcFoldLevel2 + 1;
|
|
EcFoldLevel4 = EcFoldLevel3 + 1;
|
|
EcFoldLevel5 = EcFoldLevel4 + 1;
|
|
EcFoldLevel6 = EcFoldLevel5 + 1;
|
|
EcFoldLevel7 = EcFoldLevel6 + 1;
|
|
EcFoldLevel8 = EcFoldLevel7 + 1;
|
|
EcFoldLevel9 = EcFoldLevel8 + 1;
|
|
EcFoldLevel0 = EcFoldLevel9 + 1;
|
|
EcFoldCurrent = 381;
|
|
EcUnFoldCurrent = 382;
|
|
EcToggleMarkupWord = 383;
|
|
EcFoldToggle = 384;
|
|
|
|
ecZoomOut = 400;
|
|
ecZoomIn = 401;
|
|
ecZoomNorm = 402;
|
|
|
|
ecDeleteLastChar = 501; // Delete last char (i.e. backspace key)
|
|
ecDeleteChar = 502; // Delete char at cursor (i.e. delete key)
|
|
ecDeleteWord = 503; // Delete from cursor to end of word
|
|
ecDeleteLastWord = 504; // Delete from cursor to start of word
|
|
ecDeleteBOL = 505; // Delete from cursor to beginning of line
|
|
ecDeleteEOL = 506; // Delete from cursor to end of line
|
|
ecDeleteLine = 507; // Delete current line
|
|
ecClearAll = 508; // Delete everything
|
|
ecLineBreak = 509; // Break line at current position, move caret to new line
|
|
ecInsertLine = 510; // Break line at current position, leave caret
|
|
ecChar = 511; // Insert a character at current position
|
|
ecSmartUnindent = 512; // NOT regocniced as command, used for group-undo, set by beautifier
|
|
ecDeleteCharNoCrLf= 513; // Delete char at cursor (i.e. delete key), but do not join lines
|
|
ecDeleteLineKeepX = 514; // Delete current line
|
|
|
|
ecImeStr = 550; // Insert character(s) from IME
|
|
|
|
ecUndo = 601; // Perform undo if available
|
|
ecRedo = 602; // Perform redo if available
|
|
ecCut = 603; // Cut selection to clipboard
|
|
ecPaste = 604; // Paste clipboard to current position
|
|
|
|
ecCopyAdd = 605; // add selection to existing clipboard (space separated, unless whitespace exists)
|
|
ecCutAdd = 606; //
|
|
ecCopyCurrentLine = 607; // copy current line (or all covered at least partly by selection) to clipboard
|
|
ecCopyAddCurrentLine = 608; // add to existing clipboard
|
|
ecCutCurrentLine = 609; //
|
|
ecCutAddCurrentLine = 610; //
|
|
|
|
ecPasteAsColumns = 611; // Paste clipboard to current position as if it was column mode
|
|
|
|
ecBlockIndent = 615; // Indent selection
|
|
ecBlockUnindent = 616; // Unindent selection
|
|
ecTab = 617; // Tab key
|
|
ecShiftTab = 618; // Shift+Tab key
|
|
|
|
// TODO: The following block is not implemented => once it is the ec... must be added to the EditorCommandStrs array
|
|
ecUpperCase = 620 unimplemented; // apply to the current or previous word
|
|
ecLowerCase = 621 unimplemented;
|
|
ecToggleCase = 622 unimplemented;
|
|
ecTitleCase = 623 unimplemented;
|
|
ecUpperCaseBlock = 625 unimplemented; // apply to current selection, or current char if no selection
|
|
ecLowerCaseBlock = 626 unimplemented;
|
|
ecToggleCaseBlock = 627 unimplemented;
|
|
|
|
ecMoveLineUp = 630; // Moves current line (or selection) one line up
|
|
ecMoveLineDown = 631; // Moves current line (or selection) one line down
|
|
ecDuplicateLine = 632; // Line or selection (full lines)
|
|
|
|
ecMoveSelectUp = 633; // Moves selection one line up
|
|
ecMoveSelectDown = 634; // Moves selection one line down
|
|
ecMoveSelectLeft = 635; // Moves selection one line up
|
|
ecMoveSelectRight = 636; // Moves selection one line down
|
|
ecDuplicateSelection= 637;
|
|
|
|
|
|
ecString = 640; //Insert a whole string
|
|
|
|
ecAutoCompletion = 650;
|
|
ecBlockIndentMove = 651; // Indent selection (indent before column-sel, therefore moving the column-sel)
|
|
ecBlockUnindentMove = 652; // Unindent selection (indent before column-sel, therefore moving the column-sel)
|
|
|
|
ecColumnBlockShiftRight = 653; // Right Shift (Indent) column selection and delete right side inside selectio
|
|
ecColumnBlockMoveRight = 654; // Right Shift (Indent) column selection and overwrite text behind it
|
|
ecColumnBlockShiftLeft = 655; // Left Shift (Unindent) column selection and delete left side inside selectio
|
|
ecColumnBlockMoveLeft = 656; // Left Shift (Unindent) column selection and overwrite text at start of it
|
|
|
|
ecGotFocus = 700 deprecated 'Not used / To be removed in Lazarus 5.99';
|
|
ecLostFocus = 701 deprecated 'Not used / To be removed in Lazarus 5.99';
|
|
|
|
ecUserDefinedFirst = 900;
|
|
ecUserDefinedLast = 999;
|
|
|
|
ecUserFirst = 1001; // Start of user-defined commands
|
|
|
|
ecPluginFirstCompletion = 19000;
|
|
ecPluginFirstSyncro = 19010;
|
|
ecPluginFirstTemplEdit = 19030;
|
|
ecPluginFirstMultiCaret = 19050;
|
|
ecPluginFirstLineWrap = 19070;
|
|
|
|
ecPluginFirst = 20000;
|
|
|
|
// Plugins don't know of other plugins, so they need to map the codes
|
|
// In order to save Keymaps, Plugins all start at ecPluginFirst (overlapping)
|
|
// If ask by SynEdit they add an offset
|
|
|
|
// Return the next offset
|
|
function AllocatePluginKeyRange(Count: Integer; OffsetOnly: Boolean = False): integer;
|
|
|
|
type
|
|
ESynKeyError = class(Exception);
|
|
|
|
TSynEditorCommand = type word;
|
|
|
|
{ TSynEditKeyStroke }
|
|
|
|
TSynEditKeyStroke = class(TCollectionItem)
|
|
private
|
|
FKey: word; // Virtual keycode, i.e. VK_xxx
|
|
FShift: TShiftState;
|
|
FKey2: word;
|
|
FShift2: TShiftState;
|
|
FCommand: TSynEditorCommand;
|
|
FShiftMask: TShiftState;
|
|
FShiftMask2: TShiftState;
|
|
function GetCommand: TSynEditorCommand;
|
|
function GetShortCut: TShortCut;
|
|
function GetShortCut2: TShortCut;
|
|
procedure SetCommand(Value: TSynEditorCommand);
|
|
procedure SetKey(const Value: word);
|
|
procedure SetKey2(const Value: word);
|
|
procedure SetShift(const Value: TShiftState);
|
|
procedure SetShift2(const Value: TShiftState);
|
|
procedure SetShortCut(const Value: TShortCut);
|
|
procedure SetShortCut2(const Value: TShortCut);
|
|
protected
|
|
function GetDisplayName: string; override;
|
|
public
|
|
procedure Assign(Source: TPersistent); override;
|
|
// TODO: add ShiftMask optional
|
|
procedure LoadFromStream(AStream: TStream);
|
|
procedure SaveToStream(AStream: TStream);
|
|
// No duplicate checking is done if assignment made via these properties!
|
|
property Key: word read FKey write SetKey;
|
|
property Key2: word read FKey2 write SetKey2;
|
|
property Shift: TShiftState read FShift write SetShift;
|
|
property Shift2: TShiftState read FShift2 write SetShift2;
|
|
// Modifier keys, that should be ignored
|
|
(* ShiftMask:
|
|
ShiftStates that are SET in the mask will be ignored, and NOT compared with "Shift"
|
|
*)
|
|
property ShiftMask: TShiftState read FShiftMask write FShiftMask;
|
|
property ShiftMask2: TShiftState read FShiftMask2 write FShiftMask2;
|
|
published
|
|
property Command: TSynEditorCommand read GetCommand write SetCommand;
|
|
property ShortCut: TShortCut read GetShortCut write SetShortCut default 0;
|
|
property ShortCut2: TShortCut read GetShortCut2 write SetShortCut2 default 0;
|
|
end;
|
|
|
|
{ TSynEditKeyStrokes }
|
|
|
|
TSynEditKeyStrokes = class(TCollection)
|
|
private
|
|
FOwner: TPersistent;
|
|
fLastKey: word;
|
|
fLastShiftState: TShiftState;
|
|
FPluginOffset: Integer;
|
|
FUsePluginOffset: Boolean;
|
|
function GetItem(Index: Integer): TSynEditKeyStroke;
|
|
procedure SetItem(Index: Integer; Value: TSynEditKeyStroke);
|
|
protected
|
|
function GetOwner: TPersistent; override;
|
|
function FindKeycode2(Code1: word; SS1: TShiftState;
|
|
Code2: word; SS2: TShiftState): integer;
|
|
function FindKeycode2Start(Code: word; SS: TShiftState): integer;
|
|
public
|
|
constructor Create(AOwner: TPersistent);
|
|
function Add: TSynEditKeyStroke;
|
|
procedure Assign(Source: TPersistent); override;
|
|
function FindCommand(Cmd: TSynEditorCommand): integer;
|
|
function FindKeycode(Code: word; SS: TShiftState): integer;
|
|
function FindKeycodeEx(Code: word; SS: TShiftState; var Data: pointer;
|
|
out IsStartOfCombo: boolean;
|
|
FinishComboOnly: Boolean = False;
|
|
ComboStart: TSynEditKeyStrokes = nil): TSynEditorCommand;
|
|
procedure ResetKeyCombo;
|
|
function FindShortcut(SC: TShortcut): integer;
|
|
function FindShortcut2(SC, SC2: TShortcut): integer;
|
|
procedure LoadFromStream(AStream: TStream);
|
|
procedure ResetDefaults; virtual;
|
|
procedure SaveToStream(AStream: TStream);
|
|
public
|
|
property Items[Index: Integer]: TSynEditKeyStroke read GetItem
|
|
write SetItem; default;
|
|
property PluginOffset: Integer read FPluginOffset write FPluginOffset;
|
|
// only switch on while needed.
|
|
// So streaming will always see the constant, unmodified values
|
|
property UsePluginOffset: Boolean read FUsePluginOffset write FUsePluginOffset;
|
|
end;
|
|
|
|
TGetEditorCommandValuesProc = procedure(Proc: TGetStrProc);
|
|
|
|
// These are mainly for the TSynEditorCommand property editor, but could be
|
|
// useful elsewhere.
|
|
function EditorCommandToDescrString(Cmd: TSynEditorCommand): string;
|
|
function EditorCommandToCodeString(Cmd: TSynEditorCommand): string;
|
|
procedure GetEditorCommandValues(Proc: TGetStrProc);
|
|
function IdentToEditorCommand(const Ident: string; var Cmd: longint): boolean;
|
|
function EditorCommandToIdent(Cmd: longint; var Ident: string): boolean;
|
|
|
|
procedure RegisterKeyCmdIdentProcs(IdentToIntFn: TIdentToInt; IntToIdentFn: TIntToIdent);
|
|
procedure RegisterExtraGetEditorCommandValues(AProc: TGetEditorCommandValuesProc);
|
|
|
|
implementation
|
|
|
|
{ Command mapping routines }
|
|
|
|
const
|
|
EditorCommandStrs: array[0..184] of TIdentMapEntry = (
|
|
(Value: ecNone; Name: 'ecNone'),
|
|
(Value: ecLeft; Name: 'ecLeft'),
|
|
(Value: ecRight; Name: 'ecRight'),
|
|
(Value: ecUp; Name: 'ecUp'),
|
|
(Value: ecDown; Name: 'ecDown'),
|
|
(Value: ecWordLeft; Name: 'ecWordLeft'),
|
|
(Value: ecWordRight; Name: 'ecWordRight'),
|
|
(Value: ecWordEndLeft; Name: 'ecWordEndLeft'),
|
|
(Value: ecWordEndRight; Name: 'ecWordEndRight'),
|
|
(Value: ecHalfWordLeft; Name: 'ecHalfWordLeft'),
|
|
(Value: ecHalfWordRight; Name: 'ecHalfWordRight'),
|
|
(Value: ecSmartWordLeft; Name: 'ecSmartWordLeft'),
|
|
(Value: ecSmartWordRight; Name: 'ecSmartWordRight'),
|
|
(Value: ecLineStart; Name: 'ecLineStart'),
|
|
(Value: ecLineEnd; Name: 'ecLineEnd'),
|
|
(Value: ecPageUp; Name: 'ecPageUp'),
|
|
(Value: ecPageDown; Name: 'ecPageDown'),
|
|
(Value: ecPageLeft; Name: 'ecPageLeft'),
|
|
(Value: ecPageRight; Name: 'ecPageRight'),
|
|
(Value: ecPageTop; Name: 'ecPageTop'),
|
|
(Value: ecPageBottom; Name: 'ecPageBottom'),
|
|
(Value: ecEditorTop; Name: 'ecEditorTop'),
|
|
(Value: ecEditorBottom; Name: 'ecEditorBottom'),
|
|
(Value: ecGotoXY; Name: 'ecGotoXY'),
|
|
(Value: ecLineTextStart; Name: 'ecLineTextStart'),
|
|
(Value: ecStickySelection; Name: 'ecStickySelection'),
|
|
(Value: ecStickySelectionCol; Name: 'ecStickySelectionCol'),
|
|
(Value: ecStickySelectionLine; Name: 'ecStickySelectionLine'),
|
|
(Value: ecStickySelectionStop; Name: 'ecStickySelectionStop'),
|
|
(Value: ecSelLeft; Name: 'ecSelLeft'),
|
|
(Value: ecSelRight; Name: 'ecSelRight'),
|
|
(Value: ecSelUp; Name: 'ecSelUp'),
|
|
(Value: ecSelDown; Name: 'ecSelDown'),
|
|
(Value: ecSelWordLeft; Name: 'ecSelWordLeft'),
|
|
(Value: ecSelWordRight; Name: 'ecSelWordRight'),
|
|
(Value: ecSelWordEndLeft; Name: 'ecSelWordEndLeft'),
|
|
(Value: ecSelWordEndRight; Name: 'ecSelWordEndRight'),
|
|
(Value: ecSelHalfWordLeft; Name: 'ecSelHalfWordLeft'),
|
|
(Value: ecSelHalfWordRight; Name: 'ecSelHalfWordRight'),
|
|
(Value: ecSelSmartWordLeft; Name: 'ecSelSmartWordLeft'),
|
|
(Value: ecSelSmartWordRight; Name: 'ecSelSmartWordRight'),
|
|
(Value: ecSelLineStart; Name: 'ecSelLineStart'),
|
|
(Value: ecSelLineEnd; Name: 'ecSelLineEnd'),
|
|
(Value: ecSelPageUp; Name: 'ecSelPageUp'),
|
|
(Value: ecSelPageDown; Name: 'ecSelPageDown'),
|
|
(Value: ecSelPageLeft; Name: 'ecSelPageLeft'),
|
|
(Value: ecSelPageRight; Name: 'ecSelPageRight'),
|
|
(Value: ecSelPageTop; Name: 'ecSelPageTop'),
|
|
(Value: ecSelPageBottom; Name: 'ecSelPageBottom'),
|
|
(Value: ecSelEditorTop; Name: 'ecSelEditorTop'),
|
|
(Value: ecSelEditorBottom; Name: 'ecSelEditorBottom'),
|
|
(Value: ecSelGotoXY; Name: 'ecSelGotoXY'),
|
|
(Value: ecSelLineTextStart; Name: 'ecSelLineTextStart'),
|
|
(Value: ecColSelLeft; Name: 'ecColSelLeft'),
|
|
(Value: ecColSelRight; Name: 'ecColSelRight'),
|
|
(Value: ecColSelUp; Name: 'ecColSelUp'),
|
|
(Value: ecColSelDown; Name: 'ecColSelDown'),
|
|
(Value: ecColSelWordLeft; Name: 'ecColSelWordLeft'),
|
|
(Value: ecColSelWordRight; Name: 'ecColSelWordRight'),
|
|
(Value: ecColSelLineStart; Name: 'ecColSelLineStart'),
|
|
(Value: ecColSelLineEnd; Name: 'ecColSelLineEnd'),
|
|
(Value: ecColSelPageUp; Name: 'ecColSelPageUp'),
|
|
(Value: ecColSelPageDown; Name: 'ecColSelPageDown'),
|
|
(Value: ecColSelPageLeft; Name: 'ecColSelPageLeft'),
|
|
(Value: ecColSelPageRight; Name: 'ecColSelPageRight'),
|
|
(Value: ecColSelPageTop; Name: 'ecColSelPageTop'),
|
|
(Value: ecColSelPageBottom; Name: 'ecColSelPageBottom'),
|
|
(Value: ecColSelEditorTop; Name: 'ecColSelEditorTop'),
|
|
(Value: ecColSelEditorBottom; Name: 'ecColSelEditorBottom'),
|
|
(Value: ecColSelLineTextStart; Name: 'ecColSelLineTextStart'),
|
|
(Value: ecSelectAll; Name: 'ecSelectAll'),
|
|
(Value: ecDeleteLastChar; Name: 'ecDeleteLastChar'),
|
|
(Value: ecDeleteChar; Name: 'ecDeleteChar'),
|
|
(Value: ecDeleteCharNoCrLf; Name: 'ecDeleteCharNoCrLf'),
|
|
(Value: ecDeleteWord; Name: 'ecDeleteWord'),
|
|
(Value: ecDeleteLastWord; Name: 'ecDeleteLastWord'),
|
|
(Value: ecDeleteBOL; Name: 'ecDeleteBOL'),
|
|
(Value: ecDeleteEOL; Name: 'ecDeleteEOL'),
|
|
(Value: ecDeleteLine; Name: 'ecDeleteLine'),
|
|
(Value: ecDeleteLineKeepX; Name: 'ecDeleteLineKeepX'),
|
|
(Value: ecClearAll; Name: 'ecClearAll'),
|
|
(Value: ecLineBreak; Name: 'ecLineBreak'),
|
|
(Value: ecInsertLine; Name: 'ecInsertLine'),
|
|
(Value: ecChar; Name: 'ecChar'),
|
|
(Value: ecImeStr; Name: 'ecImeStr'),
|
|
(Value: ecUndo; Name: 'ecUndo'),
|
|
(Value: ecRedo; Name: 'ecRedo'),
|
|
(Value: ecCut; Name: 'ecCut'),
|
|
(Value: ecCopy; Name: 'ecCopy'),
|
|
(Value: ecPaste; Name: 'ecPaste'),
|
|
(Value: ecCopyAdd; Name: 'ecCopyAdd'),
|
|
(Value: ecCutAdd; Name: 'ecCutAdd'),
|
|
(Value: ecCopyCurrentLine; Name: 'ecCopyCurrentLine'),
|
|
(Value: ecCopyAddCurrentLine; Name: 'ecCopyAddCurrentLine'),
|
|
(Value: ecCutCurrentLine; Name: 'ecCutCurrentLine'),
|
|
(Value: ecCutAddCurrentLine; Name: 'ecCutAddCurrentLine'),
|
|
(Value: ecPasteAsColumns; Name: 'ecPasteAsColumns'),
|
|
(Value: ecMoveLineUp; Name: 'ecMoveLineUp'),
|
|
(Value: ecMoveLineDown; Name: 'ecMoveLineDown'),
|
|
(Value: ecMoveSelectUp; Name: 'ecMoveSelectUp'),
|
|
(Value: ecMoveSelectDown; Name: 'ecMoveSelectDown'),
|
|
(Value: ecMoveSelectLeft; Name: 'ecMoveSelectLeft'),
|
|
(Value: ecMoveSelectRight; Name: 'ecMoveSelectRight'),
|
|
(Value: ecDuplicateLine; Name: 'ecDuplicateLine'),
|
|
(Value: ecDuplicateSelection; Name: 'ecDuplicateSelection'),
|
|
(Value: ecScrollUp; Name: 'ecScrollUp'),
|
|
(Value: ecScrollDown; Name: 'ecScrollDown'),
|
|
(Value: ecScrollLeft; Name: 'ecScrollLeft'),
|
|
(Value: ecScrollRight; Name: 'ecScrollRight'),
|
|
(Value: ecInsertMode; Name: 'ecInsertMode'),
|
|
(Value: ecOverwriteMode; Name: 'ecOverwriteMode'),
|
|
(Value: ecToggleMode; Name: 'ecToggleMode'),
|
|
(Value: ecBlockIndent; Name: 'ecBlockIndent'),
|
|
(Value: ecBlockUnindent; Name: 'ecBlockUnindent'),
|
|
(Value: ecBlockIndentMove; Name: 'ecBlockIndentMove'),
|
|
(Value: ecBlockUnindentMove; Name: 'ecBlockUnindentMove'),
|
|
(Value: ecColumnBlockShiftRight; Name: 'ecColumnBlockShiftRight'),
|
|
(Value: ecColumnBlockMoveRight; Name: 'ecColumnBlockMoveRight'),
|
|
(Value: ecColumnBlockShiftLeft; Name: 'ecColumnBlockShiftLeft'),
|
|
(Value: ecColumnBlockMoveLeft; Name: 'ecColumnBlockMoveLeft'),
|
|
(Value: ecTab; Name: 'ecTab'),
|
|
(Value: ecShiftTab; Name: 'ecShiftTab'),
|
|
(Value: ecMatchBracket; Name: 'ecMatchBracket'),
|
|
(Value: ecNormalSelect; Name: 'ecNormalSelect'),
|
|
(Value: ecColumnSelect; Name: 'ecColumnSelect'),
|
|
(Value: ecLineSelect; Name: 'ecLineSelect'),
|
|
(Value: ecBlockSetBegin; Name: 'ecBlockSetBegin'),
|
|
(Value: ecBlockSetEnd; Name: 'ecBlockSetEnd'),
|
|
(Value: ecBlockToggleHide; Name: 'ecBlockToggleHide'),
|
|
(Value: ecBlockHide; Name: 'ecBlockHide'),
|
|
(Value: ecBlockShow; Name: 'ecBlockShow'),
|
|
(Value: ecBlockMove; Name: 'ecBlockMove'),
|
|
(Value: ecBlockCopy; Name: 'ecBlockCopy'),
|
|
(Value: ecBlockDelete; Name: 'ecBlockDelete'),
|
|
(Value: ecBlockGotoBegin; Name: 'ecBlockGotoBegin'),
|
|
(Value: ecBlockGotoEnd; Name: 'ecBlockGotoEnd'),
|
|
(Value: ecAutoCompletion; Name: 'ecAutoCompletion'),
|
|
(Value: ecUserFirst; Name: 'ecUserFirst'),
|
|
(Value: ecGotoMarker0; Name: 'ecGotoMarker0'),
|
|
(Value: ecGotoMarker1; Name: 'ecGotoMarker1'),
|
|
(Value: ecGotoMarker2; Name: 'ecGotoMarker2'),
|
|
(Value: ecGotoMarker3; Name: 'ecGotoMarker3'),
|
|
(Value: ecGotoMarker4; Name: 'ecGotoMarker4'),
|
|
(Value: ecGotoMarker5; Name: 'ecGotoMarker5'),
|
|
(Value: ecGotoMarker6; Name: 'ecGotoMarker6'),
|
|
(Value: ecGotoMarker7; Name: 'ecGotoMarker7'),
|
|
(Value: ecGotoMarker8; Name: 'ecGotoMarker8'),
|
|
(Value: ecGotoMarker9; Name: 'ecGotoMarker9'),
|
|
(Value: ecSetMarker0; Name: 'ecSetMarker0'),
|
|
(Value: ecSetMarker1; Name: 'ecSetMarker1'),
|
|
(Value: ecSetMarker2; Name: 'ecSetMarker2'),
|
|
(Value: ecSetMarker3; Name: 'ecSetMarker3'),
|
|
(Value: ecSetMarker4; Name: 'ecSetMarker4'),
|
|
(Value: ecSetMarker5; Name: 'ecSetMarker5'),
|
|
(Value: ecSetMarker6; Name: 'ecSetMarker6'),
|
|
(Value: ecSetMarker7; Name: 'ecSetMarker7'),
|
|
(Value: ecSetMarker8; Name: 'ecSetMarker8'),
|
|
(Value: ecSetMarker9; Name: 'ecSetMarker9'),
|
|
(Value: ecToggleMarker0; Name: 'ecToggleMarker0'),
|
|
(Value: ecToggleMarker1; Name: 'ecToggleMarker1'),
|
|
(Value: ecToggleMarker2; Name: 'ecToggleMarker2'),
|
|
(Value: ecToggleMarker3; Name: 'ecToggleMarker3'),
|
|
(Value: ecToggleMarker4; Name: 'ecToggleMarker4'),
|
|
(Value: ecToggleMarker5; Name: 'ecToggleMarker5'),
|
|
(Value: ecToggleMarker6; Name: 'ecToggleMarker6'),
|
|
(Value: ecToggleMarker7; Name: 'ecToggleMarker7'),
|
|
(Value: ecToggleMarker8; Name: 'ecToggleMarker8'),
|
|
(Value: ecToggleMarker9; Name: 'ecToggleMarker9'),
|
|
(Value: EcFoldLevel1; Name: 'EcFoldLevel1'),
|
|
(Value: EcFoldLevel2; Name: 'EcFoldLevel2'),
|
|
(Value: EcFoldLevel3; Name: 'EcFoldLevel3'),
|
|
(Value: EcFoldLevel4; Name: 'EcFoldLevel4'),
|
|
(Value: EcFoldLevel5; Name: 'EcFoldLevel5'),
|
|
(Value: EcFoldLevel6; Name: 'EcFoldLevel6'),
|
|
(Value: EcFoldLevel7; Name: 'EcFoldLevel7'),
|
|
(Value: EcFoldLevel8; Name: 'EcFoldLevel8'),
|
|
(Value: EcFoldLevel9; Name: 'EcFoldLevel9'),
|
|
(Value: EcFoldLevel0; Name: 'EcFoldLevel0'),
|
|
(Value: EcFoldCurrent; Name: 'EcFoldCurrent'),
|
|
(Value: EcUnFoldCurrent; Name: 'EcUnFoldCurrent'),
|
|
(Value: EcFoldToggle; Name: 'EcFoldToggle'),
|
|
(Value: EcToggleMarkupWord; Name: 'EcToggleMarkupWord'),
|
|
(Value: ecZoomOut; Name: 'ecZoomOut'),
|
|
(Value: ecZoomIn; Name: 'ecZoomIn'),
|
|
(Value: ecZoomNorm; Name: 'ecZoomNorm')
|
|
);
|
|
|
|
var
|
|
ExtraIdentToIntFn: Array of TIdentToInt = nil;
|
|
ExtraIntToIdentFn: Array of TIntToIdent = nil;
|
|
ExtraGetEditorCommandValues: Array of TGetEditorCommandValuesProc = nil;
|
|
|
|
procedure GetEditorCommandValues(Proc: TGetStrProc);
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i := 0 to 19 do
|
|
Proc('ecUserDefined' + IntToStr(i));
|
|
for i := Low(EditorCommandStrs) to High(EditorCommandStrs) do
|
|
Proc(EditorCommandStrs[I].Name);
|
|
i := 0;
|
|
while (i < length(ExtraGetEditorCommandValues)) do begin
|
|
ExtraGetEditorCommandValues[i](Proc);
|
|
inc(i);
|
|
end;
|
|
end;
|
|
|
|
function IdentToEditorCommand(const Ident: string; var Cmd: longint): boolean;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if (copy(Ident, 1 , 13) = 'ecUserDefined') then begin
|
|
Cmd := StrToIntDef(copy(Ident, 14, length(Ident)), -1) + ecUserDefinedFirst;
|
|
Result := (Cmd >= ecUserDefinedFirst) and (Cmd <= ecUserDefinedLast);
|
|
if Result then
|
|
exit;
|
|
end;
|
|
Result := IdentToInt(Ident, Cmd, EditorCommandStrs);
|
|
i := 0;
|
|
while (i < length(ExtraIdentToIntFn)) and (not Result) do begin
|
|
Result := ExtraIdentToIntFn[i](Ident, Cmd);
|
|
inc(i);
|
|
end;
|
|
end;
|
|
|
|
function EditorCommandToIdent(Cmd: longint; var Ident: string): boolean;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if (Cmd >= ecUserDefinedFirst) and (Cmd <= ecUserDefinedLast) then begin
|
|
Ident := 'ecUserDefined' + IntToStr(Cmd - ecUserDefinedFirst);
|
|
Result := True;
|
|
exit;
|
|
end;
|
|
Result := IntToIdent(Cmd, Ident, EditorCommandStrs);
|
|
i := 0;
|
|
while (i < length(ExtraIntToIdentFn)) and (not Result) do begin
|
|
Result := ExtraIntToIdentFn[i](Cmd, Ident);
|
|
inc(i);
|
|
end;
|
|
end;
|
|
|
|
procedure RegisterKeyCmdIdentProcs(IdentToIntFn: TIdentToInt;
|
|
IntToIdentFn: TIntToIdent);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
i := length(ExtraIdentToIntFn);
|
|
SetLength(ExtraIdentToIntFn, i + 1);
|
|
ExtraIdentToIntFn[i] := IdentToIntFn;
|
|
i := length(ExtraIntToIdentFn);
|
|
SetLength(ExtraIntToIdentFn, i + 1);
|
|
ExtraIntToIdentFn[i] := IntToIdentFn;
|
|
end;
|
|
|
|
procedure RegisterExtraGetEditorCommandValues(AProc: TGetEditorCommandValuesProc);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
i := length(ExtraGetEditorCommandValues);
|
|
SetLength(ExtraGetEditorCommandValues, i + 1);
|
|
ExtraGetEditorCommandValues[i] := AProc;
|
|
end;
|
|
|
|
|
|
function AllocatePluginKeyRange(Count: Integer; OffsetOnly: Boolean): integer;
|
|
const
|
|
CurOffset : integer = 0;
|
|
begin
|
|
Result := CurOffset;
|
|
inc(CurOffset, Count);
|
|
if not OffsetOnly then
|
|
inc(Result, ecPluginFirst);
|
|
end;
|
|
|
|
function EditorCommandToDescrString(Cmd: TSynEditorCommand): string;
|
|
begin
|
|
// Doesn't do anything yet.
|
|
Result := '';
|
|
end;
|
|
|
|
function EditorCommandToCodeString(Cmd: TSynEditorCommand): string;
|
|
begin
|
|
Result := '';
|
|
if not EditorCommandToIdent(Cmd, Result) then
|
|
Result := IntToStr(Cmd);
|
|
end;
|
|
|
|
{ TSynEditKeyStroke }
|
|
|
|
procedure TSynEditKeyStroke.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is TSynEditKeyStroke then
|
|
begin
|
|
Command := TSynEditKeyStroke(Source).Command;
|
|
Key := TSynEditKeyStroke(Source).Key;
|
|
Key2 := TSynEditKeyStroke(Source).Key2;
|
|
Shift := TSynEditKeyStroke(Source).Shift;
|
|
Shift2 := TSynEditKeyStroke(Source).Shift2;
|
|
ShiftMask := TSynEditKeyStroke(Source).ShiftMask;
|
|
ShiftMask2 := TSynEditKeyStroke(Source).ShiftMask2;
|
|
end else
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
function TSynEditKeyStroke.GetDisplayName: string;
|
|
begin
|
|
Result := EditorCommandToCodeString(Command) + ' - ' + ShortCutToText(ShortCut);
|
|
if ShortCut2 <> 0 then
|
|
Result := Result + ' ' + ShortCutToText(ShortCut2);
|
|
if Result = '' then
|
|
Result := inherited GetDisplayName;
|
|
end;
|
|
|
|
function TSynEditKeyStroke.GetShortCut: TShortCut;
|
|
begin
|
|
Result := Menus.ShortCut(Key, Shift);
|
|
end;
|
|
|
|
function TSynEditKeyStroke.GetCommand: TSynEditorCommand;
|
|
begin
|
|
Result:= FCommand;
|
|
if TSynEditKeyStrokes(Collection).UsePluginOffset and (Result >= ecPluginFirst) then
|
|
Inc(Result, TSynEditKeyStrokes(Collection).PluginOffset);
|
|
end;
|
|
|
|
procedure TSynEditKeyStroke.SetCommand(Value: TSynEditorCommand);
|
|
begin
|
|
if TSynEditKeyStrokes(Collection).UsePluginOffset and (Value >= ecPluginFirst) then
|
|
begin
|
|
Dec(Value, TSynEditKeyStrokes(Collection).PluginOffset);
|
|
if (Value < ecPluginFirst) then
|
|
Value := ecNone;
|
|
end;
|
|
if Value <> FCommand then
|
|
FCommand := Value;
|
|
end;
|
|
|
|
procedure TSynEditKeyStroke.SetKey(const Value: word);
|
|
begin
|
|
if Value <> FKey then
|
|
FKey := Value;
|
|
end;
|
|
|
|
procedure TSynEditKeyStroke.SetShift(const Value: TShiftState);
|
|
begin
|
|
if Value <> FShift then
|
|
FShift := Value;
|
|
end;
|
|
|
|
procedure TSynEditKeyStroke.SetShortCut(const Value: TShortCut);
|
|
var
|
|
NewKey: Word;
|
|
NewShift: TShiftState;
|
|
Dup: integer;
|
|
begin
|
|
// Duplicate values of no shortcut are OK.
|
|
if Value <> 0 then
|
|
begin
|
|
// Check for duplicate shortcut in the collection and disallow if there is.
|
|
Dup := TSynEditKeyStrokes(Collection).FindShortcut2(Value, Key2);
|
|
if (Dup <> -1) and (Dup <> Self.Index) then
|
|
raise ESynKeyError.Create(SYNS_EDuplicateShortCut);
|
|
end;
|
|
|
|
Menus.ShortCutToKey(Value, NewKey, NewShift);
|
|
ShiftMask := [];
|
|
if (NewKey <> Key) or (NewShift <> Shift) then
|
|
begin
|
|
Key := NewKey;
|
|
Shift := NewShift;
|
|
end;
|
|
end;
|
|
|
|
procedure TSynEditKeyStroke.SetKey2(const Value: word);
|
|
begin
|
|
if Value <> FKey2 then
|
|
FKey2 := Value;
|
|
end;
|
|
|
|
procedure TSynEditKeyStroke.SetShift2(const Value: TShiftState);
|
|
begin
|
|
if Value <> FShift2 then
|
|
FShift2 := Value;
|
|
end;
|
|
|
|
procedure TSynEditKeyStroke.SetShortCut2(const Value: TShortCut);
|
|
var
|
|
NewKey: Word;
|
|
NewShift: TShiftState;
|
|
Dup: integer;
|
|
begin
|
|
// Duplicate values of no shortcut are OK.
|
|
if Value <> 0 then
|
|
begin
|
|
// Check for duplicate shortcut in the collection and disallow if there is.
|
|
Dup := TSynEditKeyStrokes(Collection).FindShortcut2(Key, Value);
|
|
if (Dup <> -1) and (Dup <> Self.Index) then
|
|
raise ESynKeyError.Create(SYNS_EDuplicateShortCut);
|
|
end;
|
|
|
|
Menus.ShortCutToKey(Value, NewKey, NewShift);
|
|
ShiftMask2 := [];
|
|
if (NewKey <> Key2) or (NewShift <> Shift2) then
|
|
begin
|
|
Key2 := NewKey;
|
|
Shift2 := NewShift;
|
|
end;
|
|
end;
|
|
|
|
function TSynEditKeyStroke.GetShortCut2: TShortCut;
|
|
begin
|
|
Result := Menus.ShortCut(Key2, Shift2);
|
|
end;
|
|
|
|
{begin} //ac 2000-07-05
|
|
procedure TSynEditKeyStroke.LoadFromStream(AStream: TStream);
|
|
begin
|
|
with AStream do begin
|
|
Read(fKey, SizeOf(fKey));
|
|
Read(fShift, SizeOf(fShift));
|
|
Read(fKey2, SizeOf(fKey2));
|
|
Read(fShift2, SizeOf(fShift2));
|
|
Read(fCommand, SizeOf(fCommand));
|
|
end;
|
|
end;
|
|
|
|
procedure TSynEditKeyStroke.SaveToStream(AStream: TStream);
|
|
begin
|
|
with AStream do begin
|
|
Write(fKey, SizeOf(fKey));
|
|
Write(fShift, SizeOf(fShift));
|
|
Write(fKey2, SizeOf(fKey2));
|
|
Write(fShift2, SizeOf(fShift2));
|
|
Write(fCommand, SizeOf(fCommand));
|
|
end;
|
|
end;
|
|
{end} //ac 2000-07-05
|
|
|
|
{ TSynEditKeyStrokes }
|
|
|
|
function TSynEditKeyStrokes.Add: TSynEditKeyStroke;
|
|
begin
|
|
Result := TSynEditKeyStroke(inherited Add);
|
|
end;
|
|
|
|
procedure TSynEditKeyStrokes.Assign(Source: TPersistent);
|
|
var
|
|
x: integer;
|
|
begin
|
|
if Source is TSynEditKeyStrokes then
|
|
begin
|
|
Clear;
|
|
for x := 0 to TSynEditKeyStrokes(Source).Count-1 do
|
|
Add.Assign(TSynEditKeyStrokes(Source)[x]);
|
|
end else
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
constructor TSynEditKeyStrokes.Create(AOwner: TPersistent);
|
|
begin
|
|
inherited Create(TSynEditKeyStroke);
|
|
FOwner := AOwner;
|
|
fLastKey := 0;
|
|
fLastShiftState := [];
|
|
FPluginOffset := 0;
|
|
FUsePluginOffset := False;
|
|
end;
|
|
|
|
function TSynEditKeyStrokes.FindCommand(Cmd: TSynEditorCommand): integer;
|
|
var
|
|
x: integer;
|
|
begin
|
|
Result := -1;
|
|
for x := 0 to Count-1 do
|
|
if Items[x].Command = Cmd then
|
|
begin
|
|
Result := x;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
function TSynEditKeyStrokes.FindKeycode(Code: word; SS: TShiftState): integer;
|
|
var
|
|
x: integer;
|
|
begin
|
|
Result := -1;
|
|
for x := 0 to Count-1 do
|
|
if (Items[x].Key = Code) and (Items[x].Shift = SS-Items[x].ShiftMask)
|
|
and (Items[x].Key2 = 0) then
|
|
begin
|
|
Result := x;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
function TSynEditKeyStrokes.FindKeycodeEx(Code: word; SS: TShiftState; var Data: pointer;
|
|
out IsStartOfCombo: boolean;
|
|
FinishComboOnly: Boolean; ComboStart: TSynEditKeyStrokes): TSynEditorCommand;
|
|
var
|
|
i: integer;
|
|
CurComboStart: TSynEditKeyStrokes;
|
|
begin
|
|
(* if FinishComboOnly=True then ComboStart are the KeyStrokes, which have the
|
|
already received keys.
|
|
If several TSynEditKeyStrokes have combos, starting with the same key(s)
|
|
only one needs to keep the info. The others chek, if they have a matching combo
|
|
*)
|
|
|
|
Result := ecNone;
|
|
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
|
|
fLastKey := Code;
|
|
fLastShiftState := SS;
|
|
IsStartOfCombo := True;
|
|
// Now this is the start of combo
|
|
if (ComboStart <> nil) and (ComboStart <> self) then
|
|
ComboStart.ResetKeyCombo;
|
|
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;
|
|
|
|
procedure TSynEditKeyStrokes.ResetKeyCombo;
|
|
begin
|
|
fLastKey := 0;
|
|
fLastShiftState := [];
|
|
end;
|
|
|
|
function TSynEditKeyStrokes.FindKeycode2(Code1: word; SS1: TShiftState;
|
|
Code2: word; SS2: TShiftState): integer;
|
|
var
|
|
x: integer;
|
|
begin
|
|
Result := -1;
|
|
for x := 0 to Count-1 do
|
|
// If ShiftMask2 = [ssCtrl] and shortcut is "Ctrl-X, Y", then both
|
|
// "Ctrl-X, Y" and "Ctrl-X, Ctrl-Y" are accepted. The second CTRL is ignored.
|
|
with Items[x] do
|
|
if (Key = Code1) and (Shift = SS1 - ShiftMask)
|
|
and (Key2 = Code2) and (Shift2 = SS2 - ShiftMask2) then
|
|
begin
|
|
Result := x;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
function TSynEditKeyStrokes.FindKeycode2Start(Code: word; SS: TShiftState): integer;
|
|
var
|
|
x: integer;
|
|
begin
|
|
Result := -1;
|
|
for x := 0 to Count-1 do
|
|
if (Items[x].Key = Code) and (Items[x].Shift = SS - Items[x].ShiftMask) and
|
|
(Items[x].Key2 <> VK_UNKNOWN) then
|
|
begin
|
|
Result := x;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
function TSynEditKeyStrokes.FindShortcut(SC: TShortcut): integer;
|
|
var
|
|
x: integer;
|
|
begin
|
|
Result := -1;
|
|
for x := 0 to Count-1 do
|
|
if Items[x].Shortcut = SC then
|
|
begin
|
|
Result := x;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
function TSynEditKeyStrokes.FindShortcut2(SC, SC2: TShortcut): integer;
|
|
var
|
|
x: integer;
|
|
begin
|
|
Result := -1;
|
|
for x := 0 to Count-1 do
|
|
if (Items[x].Shortcut = SC) and (Items[x].Shortcut2 = SC2) then
|
|
begin
|
|
Result := x;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
function TSynEditKeyStrokes.GetItem(Index: Integer): TSynEditKeyStroke;
|
|
begin
|
|
Result := TSynEditKeyStroke(inherited GetItem(Index));
|
|
end;
|
|
|
|
function TSynEditKeyStrokes.GetOwner: TPersistent;
|
|
begin
|
|
Result := FOwner;
|
|
end;
|
|
|
|
{begin} //ac 2000-07-05
|
|
procedure TSynEditKeyStrokes.LoadFromStream(AStream: TStream);
|
|
var
|
|
Num: integer;
|
|
begin
|
|
Num := 0;
|
|
AStream.Read(Num, SizeOf(Num));
|
|
while Num > 0 do begin
|
|
with Add do
|
|
LoadFromStream(AStream);
|
|
Dec(Num);
|
|
end;
|
|
end;
|
|
{end} //ac 2000-07-05
|
|
|
|
procedure TSynEditKeyStrokes.ResetDefaults;
|
|
|
|
procedure AddKey(const ACmd: TSynEditorCommand; const AKey: word;
|
|
const AShift: TShiftState; const AShiftMask: TShiftState = []);
|
|
begin
|
|
with Add do
|
|
begin
|
|
Key := AKey;
|
|
Shift := AShift;
|
|
ShiftMask := AShiftMask;
|
|
Command := ACmd;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
Clear;
|
|
|
|
AddKey(ecUp, VK_UP, []);
|
|
AddKey(ecSelUp, VK_UP, [ssShift]);
|
|
AddKey(ecScrollUp, VK_UP, [ssCtrl]);
|
|
AddKey(ecDown, VK_DOWN, []);
|
|
AddKey(ecSelDown, VK_DOWN, [ssShift]);
|
|
AddKey(ecScrollDown, VK_DOWN, [ssCtrl]);
|
|
AddKey(ecLeft, VK_LEFT, []);
|
|
AddKey(ecSelLeft, VK_LEFT, [ssShift]);
|
|
AddKey(ecWordLeft, VK_LEFT, [ssCtrl]);
|
|
AddKey(ecSelWordLeft, VK_LEFT, [ssShift,ssCtrl]);
|
|
AddKey(ecRight, VK_RIGHT, []);
|
|
AddKey(ecSelRight, VK_RIGHT, [ssShift]);
|
|
AddKey(ecWordRight, VK_RIGHT, [ssCtrl]);
|
|
AddKey(ecSelWordRight, VK_RIGHT, [ssShift,ssCtrl]);
|
|
AddKey(ecPageDown, VK_NEXT, []);
|
|
AddKey(ecSelPageDown, VK_NEXT, [ssShift]);
|
|
AddKey(ecPageBottom, VK_NEXT, [ssCtrl]);
|
|
AddKey(ecSelPageBottom, VK_NEXT, [ssShift,ssCtrl]);
|
|
AddKey(ecPageUp, VK_PRIOR, []);
|
|
AddKey(ecSelPageUp, VK_PRIOR, [ssShift]);
|
|
AddKey(ecPageTop, VK_PRIOR, [ssCtrl]);
|
|
AddKey(ecSelPageTop, VK_PRIOR, [ssShift,ssCtrl]);
|
|
AddKey(ecLineStart, VK_HOME, []);
|
|
AddKey(ecSelLineStart, VK_HOME, [ssShift]);
|
|
AddKey(ecEditorTop, VK_HOME, [ssCtrl]);
|
|
AddKey(ecSelEditorTop, VK_HOME, [ssShift,ssCtrl]);
|
|
AddKey(ecLineEnd, VK_END, []);
|
|
AddKey(ecSelLineEnd, VK_END, [ssShift]);
|
|
AddKey(ecEditorBottom, VK_END, [ssCtrl]);
|
|
AddKey(ecSelEditorBottom, VK_END, [ssShift,ssCtrl]);
|
|
AddKey(ecToggleMode, VK_INSERT, []);
|
|
AddKey(ecCopy, VK_INSERT, [ssCtrl]);
|
|
AddKey(ecPaste, VK_INSERT, [ssShift]);
|
|
AddKey(ecDeleteChar, VK_DELETE, []);
|
|
AddKey(ecCut, VK_DELETE, [ssShift]);
|
|
AddKey(ecDeleteLastChar, VK_BACK, []);
|
|
AddKey(ecDeleteLastChar, VK_BACK, [ssShift]); //jr 2000-09-23
|
|
AddKey(ecDeleteLastWord, VK_BACK, [ssCtrl]);
|
|
AddKey(ecUndo, VK_BACK, [ssAlt]);
|
|
AddKey(ecRedo, VK_BACK, [ssAlt,ssShift]);
|
|
AddKey(ecLineBreak, VK_RETURN, []);
|
|
AddKey(ecSelectAll, ord('A'), [ssCtrl]);
|
|
AddKey(ecCopy, ord('C'), [ssCtrl]);
|
|
AddKey(ecBlockIndent, ord('I'), [ssCtrl]);
|
|
AddKey(ecLineBreak, ord('M'), [ssCtrl]);
|
|
AddKey(ecInsertLine, ord('N'), [ssCtrl]);
|
|
AddKey(ecDeleteWord, ord('T'), [ssCtrl]);
|
|
AddKey(ecBlockUnindent, ord('U'), [ssCtrl]);
|
|
AddKey(ecPaste, ord('V'), [ssCtrl]);
|
|
AddKey(ecCut, ord('X'), [ssCtrl]);
|
|
AddKey(ecDeleteLine, ord('Y'), [ssCtrl]);
|
|
AddKey(ecDeleteEOL, ord('Y'), [ssCtrl,ssShift]);
|
|
AddKey(ecUndo, ord('Z'), [ssCtrl]);
|
|
AddKey(ecRedo, ord('Z'), [ssCtrl,ssShift]);
|
|
AddKey(ecGotoMarker0, ord('0'), [ssCtrl]);
|
|
AddKey(ecGotoMarker1, ord('1'), [ssCtrl]);
|
|
AddKey(ecGotoMarker2, ord('2'), [ssCtrl]);
|
|
AddKey(ecGotoMarker3, ord('3'), [ssCtrl]);
|
|
AddKey(ecGotoMarker4, ord('4'), [ssCtrl]);
|
|
AddKey(ecGotoMarker5, ord('5'), [ssCtrl]);
|
|
AddKey(ecGotoMarker6, ord('6'), [ssCtrl]);
|
|
AddKey(ecGotoMarker7, ord('7'), [ssCtrl]);
|
|
AddKey(ecGotoMarker8, ord('8'), [ssCtrl]);
|
|
AddKey(ecGotoMarker9, ord('9'), [ssCtrl]);
|
|
AddKey(ecSetMarker0, ord('0'), [ssCtrl,ssShift]);
|
|
AddKey(ecSetMarker1, ord('1'), [ssCtrl,ssShift]);
|
|
AddKey(ecSetMarker2, ord('2'), [ssCtrl,ssShift]);
|
|
AddKey(ecSetMarker3, ord('3'), [ssCtrl,ssShift]);
|
|
AddKey(ecSetMarker4, ord('4'), [ssCtrl,ssShift]);
|
|
AddKey(ecSetMarker5, ord('5'), [ssCtrl,ssShift]);
|
|
AddKey(ecSetMarker6, ord('6'), [ssCtrl,ssShift]);
|
|
AddKey(ecSetMarker7, ord('7'), [ssCtrl,ssShift]);
|
|
AddKey(ecSetMarker8, ord('8'), [ssCtrl,ssShift]);
|
|
AddKey(ecSetMarker9, ord('9'), [ssCtrl,ssShift]);
|
|
AddKey(ecFoldLevel1, ord('1'), [ssAlt,ssShift]);
|
|
AddKey(ecFoldLevel2, ord('2'), [ssAlt,ssShift]);
|
|
AddKey(ecFoldLevel3, ord('3'), [ssAlt,ssShift]);
|
|
AddKey(ecFoldLevel4, ord('4'), [ssAlt,ssShift]);
|
|
AddKey(ecFoldLevel5, ord('5'), [ssAlt,ssShift]);
|
|
AddKey(ecFoldLevel6, ord('6'), [ssAlt,ssShift]);
|
|
AddKey(ecFoldLevel7, ord('7'), [ssAlt,ssShift]);
|
|
AddKey(ecFoldLevel8, ord('8'), [ssAlt,ssShift]);
|
|
AddKey(ecFoldLevel9, ord('9'), [ssAlt,ssShift]);
|
|
AddKey(ecFoldLevel0, ord('0'), [ssAlt,ssShift]);
|
|
AddKey(ecFoldCurrent, ord('-'), [ssAlt,ssShift]);
|
|
AddKey(ecUnFoldCurrent, ord('+'), [ssAlt,ssShift]);
|
|
AddKey(EcToggleMarkupWord, ord('M'), [ssAlt]);
|
|
AddKey(ecNormalSelect, ord('N'), [ssCtrl,ssShift]);
|
|
AddKey(ecColumnSelect, ord('C'), [ssCtrl,ssShift]);
|
|
AddKey(ecLineSelect, ord('L'), [ssCtrl,ssShift]);
|
|
AddKey(ecTab, VK_TAB, []);
|
|
AddKey(ecShiftTab, VK_TAB, [ssShift]);
|
|
AddKey(ecMatchBracket, ord('B'), [ssCtrl,ssShift]);
|
|
|
|
AddKey(ecColSelUp, VK_UP, [ssAlt, ssShift]);
|
|
AddKey(ecColSelDown, VK_DOWN, [ssAlt, ssShift]);
|
|
AddKey(ecColSelLeft, VK_LEFT, [ssAlt, ssShift]);
|
|
AddKey(ecColSelRight, VK_RIGHT, [ssAlt, ssShift]);
|
|
AddKey(ecColSelPageDown, VK_NEXT, [ssAlt, ssShift]);
|
|
AddKey(ecColSelPageBottom, VK_NEXT, [ssAlt, ssShift,ssCtrl]);
|
|
AddKey(ecColSelPageUp, VK_PRIOR, [ssAlt, ssShift]);
|
|
AddKey(ecColSelPageTop, VK_PRIOR, [ssAlt, ssShift,ssCtrl]);
|
|
AddKey(ecColSelLineStart, VK_HOME, [ssAlt, ssShift]);
|
|
AddKey(ecColSelLineEnd, VK_END, [ssAlt, ssShift]);
|
|
AddKey(ecColSelEditorTop, VK_HOME, [ssAlt, ssShift,ssCtrl]);
|
|
AddKey(ecColSelEditorBottom, VK_END, [ssAlt, ssShift,ssCtrl]);
|
|
end;
|
|
|
|
procedure TSynEditKeyStrokes.SetItem(Index: Integer; Value: TSynEditKeyStroke);
|
|
begin
|
|
inherited SetItem(Index, Value);
|
|
end;
|
|
|
|
{begin} //ac 2000-07-05
|
|
procedure TSynEditKeyStrokes.SaveToStream(AStream: TStream);
|
|
var
|
|
i, Num: integer;
|
|
begin
|
|
Num := Count;
|
|
AStream.Write(Num, SizeOf(Num));
|
|
for i := 0 to Num - 1 do
|
|
Items[i].SaveToStream(AStream);
|
|
end;
|
|
{end} //ac 2000-07-05
|
|
|
|
initialization
|
|
RegisterIntegerConsts(TypeInfo(TSynEditorCommand),
|
|
@IdentToEditorCommand,
|
|
@EditorCommandToIdent);
|
|
|
|
finalization
|
|
ExtraIdentToIntFn := nil;
|
|
ExtraIntToIdentFn := nil;
|
|
ExtraGetEditorCommandValues := nil;
|
|
|
|
end.
|
|
|