Jump to content
santiago

Tools Api: how to detect a key has been pressed in the editor window?

Recommended Posts

Hi there,

 

I am using the Open Tools Api to develop a plugin for the Delphi IDE.


What I would like to be able to do, is detect that a user has pressed a key in the code editor window. If the active file (module) is read-only I would then like to take a specific action.

 

Unfortunately the Open Tools Api does not seem to offer the functionality I require (be notified of a key press in the editor window).

 

The only other option I can think of, would be to use a Windows Hook.

SetWindowsHookEx(WH_KEYBOARD, ...

 

Maybe someone knows if there is a better way to achieve this instead of having to resort to a Windows Hook.

 

Thanks!!

 

Share this post


Link to post

Or you could hook the editors onkeypress event. In both cases be careful, you have to clean up before your module gets unloaded/dumped.

  • Like 1

Share this post


Link to post
20 hours ago, santiago said:

If the active file (module) is read-only I would then like to take a specific action.

If you are not actually interested in the key itself, but only in the fact that the editor content has changed, you might get away with EditorViewModified.

Share this post


Link to post
29 minutes ago, Uwe Raabe said:

If you are not actually interested in the key itself, but only in the fact that the editor content has changed, you might get away with EditorViewModified.

Yes, I noticed, but that is not really detecting keyboard actions, is it, it is just very indirectly detecting some of them.

 

Hooking up the editor, if possible, would be the best way, IMO. I just don't know how. <g>

Share this post


Link to post

@Uwe Raabe The file is read-only. So unfortunately, the EditorViewModified event will never be triggered.

 

I got it to work. Here is a high level overview of how it works, in case it might be of help to someone else:

 

I react to the INTAEditServicesNotifier.EditorViewModified event. This is triggered whenever a new editor window is activated.

 

Here I can easily detect whether the source file is read only or not, using EditView.Buffer.IsReadOnly.

 

The trickiest part was then getting the handle of the editor control window (TEditControl). The Open Tools Api provides no functionality for that.
It does provide you with the IDE's TCustomForm though (INTAEditWindow.Form).

 

With the form you can find the editor control by searching for a child component with ClassName = 'TEditControl' and ComponentName = 'Editor'.

 

Instead of working with a Windows Hook, I just added a handler for Application.OnMessage.

 

procedure TEditorNotifier.ApplicationEventsMessage(var Msg: tagMSG; var Handled: Boolean);
begin
  if (Msg.message = WM_KEYDOWN) and (FEditControl.Handle = Msg.hwnd) then
  begin
     // magic happens...
  end;

  if not Handled and Assigned(FPreviousMessageEvent) then
    FPreviousMessageEvent(Msg, Handled);
end;

 

 

 

  • Like 3

Share this post


Link to post

TApplication.OnMessage seems to be assigned by default, so you are just overwriting it. I'd hook it or use a TApplicationevents component on a custom form. (Never tried)

 

Edit: Ah I see, you are already hooking it.

Edited by Attila Kovacs

Share this post


Link to post

@Attila Kovacs yes I am keeping a reference to the previous handler in case it was set.

I would prefer to use TApplicationEvents though. Thx for the tip.

Unfortunately I could not get it to work.
 

FApplicationEvents := TApplicationEvents.Create(EditWindow.Form);// nil);
FApplicationEvents.OnMessage := ApplicationEventsMessage;

The callback method (ApplicationEventsMessage) was never called. I also tried without setting an owner.

Edited by santiago
typo

Share this post


Link to post

Hooking events in the Delphi IDE is dangerous, as you never know whether there already is another plugin that uses the same event.

I tried to describe a way to make that process a little bit safer and blogged about it:

https://blog.dummzeuch.de/2016/03/28/safe-event-hooking-for-delphi-ide-plugins-revisited/

But it's not just other plugins you must be wary about. New versions of the IDE might also start using previously unused events. E.g. Delphi 10.3 is now using the previously unused Screen.OnFormChanged event, but only within the Options dialog. This broke some of the GExperts enhancements to this dialog and those dialogs opened from there, in particular those for the path edit dialog.

  • Like 1
  • Thanks 2

Share this post


Link to post

@dummzeuch this plugin is only for internal use. I am chaining the event. For my use case the TApplicationEvents class which was recommended by @Attila Kovacs seems to be a good choice.

Unfortunately, I could not get it to work. Have you used this class inside an ide plugin? If I understand correctly this would allow multiple event subcribers to coexist.
 

Share this post


Link to post

Works for me:

 

procedure TTestWizard.OnAppMessage(var Msg: TMsg; var Handled: Boolean);
begin
if (Msg.message = WM_KEYDOWN) then
  begin
    Beep;
  end;
end;

 

constructor TTestWizard.Create;
begin
  FAppEv := TApplicationEvents.Create(Application.FindComponent('EditWindow_0'));
  FAppEv.OnMessage := OnAppMessage;

 

 

 

 

  • Like 1
  • Thanks 1

Share this post


Link to post

@Attila Kovacs I gave it another go, and it does indeed work. Don't know what I did wrong the first time I tried...

I also tested if multiple TApplicationEvents can be used simultaneously. This also works well.

Thank you!

  • Like 1

Share this post


Link to post
4 hours ago, santiago said:

For my use case the TApplicationEvents class which was recommended by @Attila Kovacs seems to be a good choice.

Unfortunately, I could not get it to work.

TApplicationEvents works by assigning its own handlers to the TApplication events.   So if the IDE, or another plugin, assigns its own handlers to the TApplication events directly then TApplicationEvents will not work correctly.

I also tested if multiple TApplicationEvents can be used simultaneously. This also works well.

As it should, since TApplicationEvents is specifically designed to be used that way.  When everyone uses TApplicationEvents handlers instead of TApplication handlers, then everyone gets notified of events.

Edited by Remy Lebeau
  • Thanks 1

Share this post


Link to post
On 5/7/2019 at 12:00 AM, Dave Nottage said:

If you don't have it already, I recommend downloading the GExperts source:

https://sourceforge.net/p/gexperts/code/HEAD/tree/trunk/

Just to make that clear:

The url Dave posted is for browsing the source code in a web browser, not for downloading it with subversion.

The url for subversion is this:

https://svn.code.sf.net/p/gexperts/code/trunk

 

Edited by dummzeuch
  • Like 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×