Shortcut mappings are transferred to a plugin's activity
-
I did run into the problem, that in my plugin for a Listview - as well as a Treeview - the virtual key F2 could not be intercepted by the OnKeyDown, OnKeyPress event for to invoke these control’s item caption editors via pressing F2. Digged some time along the pascal units hierarchy where the “F2” might have gone lost, always suspecting that it could have been eaten up by NPP itself.
And yes: within the shortcut mapper, the shortcut “F2” is assigned to the functionality “next bookmark”.
I removed that mapping for test, and voilà, the caption editing via F2 is back again …Is this by design, that Notepad++ transfers mappings, that are surely useful for it’s own text editor processing, brute-force to plugins actually active, and why?
And: is it possible to block this transfer specifically for a plugin and specifically for a key via an internal NPP notification?
-
@klaus101 said in Shortcut mappings are transferred to a plugin's activity:
And: is it possible to block this transfer specifically for a plugin and specifically for a key via an internal NPP notification?
It is possible. The block is by window handle. Send the NPPM_MODELESSDIALOG message.
That will cause all messages to the window handle and any of its child windows to be dispatched through IsDialogMessage and not to be passed through TranslateAccelerator.
This works exactly as expected when your window is a standard Windows non-modal dialog using the C (Win32 API) interface. There have been reports of unexpected changes in behavior when the window is a C# form — there does not appear to be a totally satisfactory resolution in this case.
-
@klaus101 said in Shortcut mappings are transferred to a plugin's activity:
Digged some time along the pascal units hierarchy…
If your dialog inherits from
TNppForm
, calling theRegisterForm
method is equivalent to what @Coises suggested. -
@rdipardo
About “Digged some time along the pascal units hierarchy” -> sorry, misunderstandable wording from my side here;
i meant the Lazarus/FreePascal LCL base sources itself that i inspected first, until i assumed more and more that this keydown event already must have been filtered out by NPP. -
@rdipardo and @Coises
first, really many thanks both for your responses!
Meanwhile i had found this very similar thread:
https://github.com/funap/npp-explorer-plugin/issues/74
and, so, was indeed pointed to deactivate/comment such statement in the dialog’s creation:::SendMessage(msgDestParent ? _hParent : (::GetParent(_hParent)), NPPM_MODELESSDIALOG, MODELESSDIALOGADD, reinterpret_cast<WPARAM
By that at the end i landed (as you say @rdipardo) in NppForms.pas at the line
FRegistered := LRESULT(0) <> SafeSendMessage(self.Npp.NppData.NppHandle, NPPM_MODELESSDIALOG, MODELESSDIALOGADD, LPARAM(self.Handle));
and deactivated it accordingly for test.
But, after having restored my previous NPP’s shortcuts.xml, unexpectedly no effect so far regarding the “F2”.
(I’ll repeat the test with the helloworld demo project afterwards. If not successful, i’d stay at the removal of this key from the mappings).(Btw, it would be nice to allow plugins to overrule a shortcurt selectively,
- and not to deactivate it for NPP itself too by removing it from the shortcut mappings
- or not to hide all NPP-used shortcuts for NPP for a plugin by not doing the registration,
but i understand very well that would imply to build a more and more complicated and sophisticated rule system. Too much …)
Edit: for to be sure, i tried it also with using MODELESSDIALOGREMOVE as parameter instead of MODELESSDIALOGADD. No difference.
Edit-2: i tried it with my slightly modified version of the helloworld demo project and tested, if, after deactivation of the SafeSendMessage mentioned, event handler for keydown or keypress would be reached now when pressing F2. They didn’t (in difference to other keys, like space etc.)
-
Oh, in the demo project, “RegisterForm” is only called from TModelessForm.FormCreate.
No wonder, that a deactivation of this SafeSendMessage in speech had no effect at all for the docking form …Is it that @Coises what you meant when you referred to a non-modal dialog (modeless in difference to a docking form as modal)?
Or does the context more target the language (prooved when using the C(++) … vs. issues in C-Sharp)? -
And again: oh.
Tried to call “RegisterForm” now from “THelloWorldDockingForm.FormCreate” too and … pross F2 on a tree node -> “keydown reached” …That’s fully according @Coises what you had said “Send the NPPM_MODELESSDIALOG message” - and completely disaccording to my understanding of the link mentioned above (issue in funap’s npp-explorer, and solution), which i understood as the need to suppress such send (i’ll read the latter contribution again, tomorrow …)
-
@klaus101 said in Shortcut mappings are transferred to a plugin's activity:
Is it that @Coises what you meant when you referred to a non-modal dialog (modeless in difference to a docking form as modal)?
Non-modal and modeless are two words for the same thing. They refer to a top-level window (usually a dialog) that does not prevent the user from interacting with the rest of the application while the window is open. Docking forms/dialogs are always modeless (though they are not top-level when displayed, but they are created as top-level windows, and then Notepad++ does some tricky mucking about to re-parent them).
(An example of the opposite, a modal dialog, is the Open File dialog: you can’t leave that dialog visible and still interact with the rest of the program. You have to finish with Open File, Open or Cancel, before you can do anything else. Standard Windows message boxes work that way, too. Modal dialogs never send shortcuts back to the main program.)
If your program does not send NPPM_MODELESSDIALOG with MODELESSDIALOGADD for a regular Windows modeless dialog, standard navigation won’t work as expected (tabbing to the next field, using Alt+underlinedLetter to activate a control using the keyboard, etc.), and most shortcut keys will be intercepted by Notepad++.
I do not know Pascal, and I can’t say how it might affect this. I know that someone using C# had problems with the form not working right either way — without the message, he lost key combinations because they were interpreted as shortcuts, with it navigation behaved oddly — and after searching, no one succeeded in finding any clear documentation from Microsoft as to what C# or WinForms or whatever was the problem expected to see to support proper operation when embedded within a standard Win32 API application.
So, here’s the next bit of the puzzle. IsDialogMessage is the standard Windows way of separating messages that are directed to a non-modal dialog or any of its child controls from the normal flow through the message loop. (I recommend reading the write-up at that link.) If the routine determines that the message (such as a keypress) belongs to the dialog, it does some “magic” (which I cannot find described precisely anywhere) to dispatch the message correctly, then returns TRUE so the message loop knows processing is complete, and the message shouldn’t be processed as a normal application-level message. The message loop code has to call IsDialogMessage separately for each dialog that requires examination. NPPM_MODELESSDIALOG is how you tell Notepad++ to include a call to IsDialogMessage for your window.
A further complication is that IsDialogMessage makes decisions based on the control to which the message is actually directed. (Part, but not all, of that “magic” I mentioned.) This is where WM_GETDLGCODE can come into play. If keyboard focus is in a control, that control will decide which keys it wants and which keys should be processed as container navigation. I have not gone into this deeply, but I believe you rarely (if ever?) get WM_KEY* messages in your dialog procedure. If a control natively processes the key you want to use to do what you want it to do, adding NPPM_MODELESSDIALOG should work. If it doesn’t do it natively, you’ll probably need to subclass the control as well — you won’t (I think) be able to get the keydown in your dialog procedure.
-
@Coises
very detailed explanations indeed, thank you a lot!
For today (evening here) only a few responses:
a) Modeless vs. modal, yes difference is well-known, but at the beginning here it hadn’t been quite clear for me how it might apply here in this specific context.
b) In Lazarus/FreePascal, some components are purely pascal-written and valid for all OSses, whereas many others are OS-based, coded in specifc widgetsets, ie. for Windows: with heavily using the Windows API. Eg. processing of the window procedure, WM_ and CN_ messages, as well as SendMessages are oftenly used, and many applications (as mine too) are using subclassed window procedures for to process certain messages specifically, inheriting others from the anchestor.
c) “Focus”-topic: also well-known. Typical scenario for a npp explorer: select a file in a listview, trigger an ‘open’ via NPP and delegate the focus back to the NPP editor area.
Then, when the mouse is over the listview, each the question might arise: do i miss the message because the control does not have the focus?
In most cases it turned out that this had not been the problem.The solution looks very promising! I’ll check more deeply tomorrow.
-
@Coises : My thoughts about the topics:
- “IsDialogMessage” (“standard Windows way of separating messages that are directed to a non-modal dialog or any of its child controls from the normal flow through the message loop”)
- and “WM_GETDLGCODE” (“If keyboard focus is in a control, that control will decide which keys it wants and which keys should be processed as container navigation”):
Basically the Lazarus component library (LCL) acts as a fully qualified message loop system that is able to react on nearly each message and notification within a windows message loop, nearly all WM_, eg. WM_KEY(down,press;up;…) can be detected and processed (*).
Normally it’s hard to detect any lacks here imo. However i initially looked into that hierarchy, as here, like everywhere else in the programming world, some business rules might have been come into play for to negate a message (like eg. an app can do when it nulls out an Enter Key for to suppress a beep; Key := #0).(*) At least in the win32 “widgetset” as one within all those platforms: all-interfaces win32-interface
It depends a bit on whether someone compiles “cross-platform” or for an OS-specific build, ie. “win32”):But - right, maybe that is it what matches your pointing! - there is no explicit call of “IsDialogMessage” itself within the LCL hierarchy (i grepped here)!
But it is a function that is known and predefined in the free pascal compiler system (FPC) though. And, so, there really low-level based apps can be written (and do exist) without the LCL, using basic TranslateMessage, DispatchMessage etc. which are calling “IsDialogMessage” explicitely.
“Matches your point” in so far as it makes understandable why without NPPM_MODELESSDIALOG (which calls “IsDialogMessage”) “most shortcut keys will be intercepted by Notepad++” - with other words, let NPP act as a gate-keeper for messages here.In sum, with your explanations it’s much more understandable now for me what’s going on (hope so).
And why “RegisterForm” (-> the NPPM_MODELESSDIALOG-Send) in the docking formcreate now lets work again F2 (and Ctrl-c, Ctrl-v & co.) by the plugin. Otherwise the NPP gate-keeper would decide itself and won’t pass messages to the plugin that it claims for own usage, e.g as defined in the shortcut mapper.I hope I’m somehow on the right track here :-)
I’d use this solution, it does indeed remove the issue :-)
(i have to sort out a few subsequent flaws now, but those are assumingly outside the current thread)