Author Topic: changing key while in multicaret mode (BeforeUtf8KeyPress not working)  (Read 5267 times)


  • Hero Member
  • *****
  • Posts: 931
I've implemented a kontext aware upper and lower case for my descendant of TCustomSynEdit by
using and registering a handler.
Code: Pascal  [Select][+][-]
  1. RegisterBeforeUtf8KeyPressHandler(@BeforeUTF8KeyPress);
This works okay so far.
But it does not when using multicaret!

Is there a similar handler which i can use to be able to make it also work in multicaret mode?
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)


  • Hero Member
  • *****
  • Posts: 931
Any Hint?
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)


  • Administrator
  • Hero Member
  • *
  • Posts: 7946
  • Debugger - SynEdit - and more
    • wiki
Well depends what you mean by "doesn't work".

The way this should work is, that the key is changed once, and the changed key is then applied to all carets.

Actually a bit more detailed.

Code: Pascal  [Select][+][-]
  1. KeyDown
  2. KeyPress
  3.   In KeyPress the key is translated into a "EditorCommand",
  4.   and that command will be applied
  5.   => CommandProcessor(ecChar, c, nil) // where c is the char
  6.      In CommandProcessor the loop will happen
  7. KeyUp

CommandProcessor has a few callbacks of its own.

you can register some hooks with
Code: Pascal  [Select][+][-]
  1. RegisterCommandHandler(
  2.   AHandlerProc: THookedCommandEvent;  // your event
  3.   AHandlerData: pointer; // nil, or whatever you want
  4.   AFlags: THookedCommandFlags);
  6.   THookedCommandFlag = (
  7.     hcfInit,     // run before On[User]CommandProcess (outside UndoBlock / should not do execution)
  8.     hcfPreExec,  // Run before CommandProcessor (unless handled by On[User]CommandProcess)
  9.     hcfPostExec, // Run after CommandProcessor (unless handled by On[User]CommandProcess)
  10.     hcfFinish    // Run at the very end
  11.   );

and there are
Code: Pascal  [Select][+][-]
  1.     property OnProcessCommand: TProcessCommandEvent read FOnProcessCommand write FOnProcessCommand;
  2.     property OnProcessUserCommand: TProcessCommandEvent  read FOnProcessUserCommand write FOnProcessUserCommand;
  3.     property OnCommandProcessed: TProcessCommandEvent read fOnCommandProcessed write fOnCommandProcessed;

The order of those events is:
* hcfInit
This you should NOT use.
This is used by multicaret, and by the macro-recorder

* OnProcessCommand / OnProcessUserCommand
Only one is called, for build in commands (Command < ecUserFirst ) this is OnProcessCommand.
This may receive extra calls with ecNone as command.
This is one place where you can change the char. (the char is passed as var param) You must check that the command is ecChar. This is probably the best place. But you can not hook it in an IDE plugin, as the IDE itself hooks it
You can also change the command itself.
This is run before the beautifier (indent on new line)

* hcfPreExec
Last chance to edit the char.
Well it may be too late: Many plugins (like Syncro edit) use this hook to execute. So if you hook this too, there is no guarantee that you will be before syncro edit.

** then the editor executes the command
  if it is build in / plugins run in one of the hooks

* hcfPostExec
for clean up

* OnCommandProcessed

* hcfFinish
also used by multicaret, and macro recorder.

Note: There are no hooks to interrupt syncro edit. It will always apply the same char to all locations.

Also note, if you record, and play a macro, and the you exec the macro, then the above is repeated for each command in the macro, including each ecChar in the macro.

IIRC: Both, multi caret, and macro, call the CommandProcessor recursive (depth = 1).
They hook hcfInit/hcfFinish
And in the first run of CommandProcessor, they interrupt it and call it again for each step (each caret, or each entry in the macro),
The outer run of CommandProcessor is changed to ecNone.


  • Hero Member
  • *****
  • Posts: 931
Many thanks for the detailed hints.

So OnProcessCommand would be the best place.
With command=ecChar i could check the context at CaretXY and decide if i have to convert AChar to upper case.

laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)


  • Hero Member
  • *****
  • Posts: 931
Thanks again, works like a charm  :D
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)


TinyPortal © 2005-2018