Short Answer: Actions short-cuts do not automatically fire across forms and data-modules.
If you follow the instructions in the question, you'll find that not even the primary short-cut fires. This is because a key step has been left out of the instructions. One that will serve to explain why OP experienced the primary short-cut firing and not the secondary one.
If you include the extra steps:
- Add a menu to the form.
- And link a menu-item to the action.
Then the primary short-cut will be able to fire the action. This is because the Action component pushes its settings to the menu item (including the ShortCut
property). However, TMenuItem
does not implement the concept of secondary short-cuts. Which is why one works and not the other.
Pause to consider an application with many forms and data-modules; and the implication if action short-cuts could fire across all of them. It should be fairly obvious that they should not be able automatically fire without explicit code to permit it. You wouldn't want a background form doing a bunch of things because its configured short-cut keys happen to be pressed in the context of other unrelated work.
The documentation points out the benefit of putting action lists on data-modules. But doesn't seem to offer any explanation how to use actions with short-cuts on a data-module correctly. Certainly nothing is mentioned in the expected places, namely: ShortCut and SecondaryShortcuts. (I'd be disappointed, but my expectations of decent documentation have been dragged quite low.)
So...
What should be done to get actions with short-cuts working across forms and data-modules?
I have done a bit of investigation and found a few options. As always, evaluate the trade-off's relative to what you are trying to achieve.
When you drop an action list on a (non-main) form, all the short-cuts work as expected. This is the most common scenario and applies when the actions are local and form specific.
When you drop an action list on the main form, all those short-cuts will be able to fire from any other form. This is great for application-wide short-cuts such as opening other forms.
NOTE: There is a prioritisation sequence as to where a short-cut is tested first. So if the active form has a short-cut matching one on the main form, the short-cut will be processed locally. And the main form understandably won't get it.
- When a form is tested to see if it handles a short-cut, all owned components are also checked. (This is in fact why the first two above work.) This means that simply setting the
Owner
of your data-module appropriately will allow its short-cuts to apply to your chosen form.
I.e. Instead of:
Application.CreateForm(TDataModule1, DataModule1);
You can use the following:
DataModule1 := TDataModule1.Create(LocalForm);
However, since each instance of a data-module can have only one owner: you would have to create multiple instances to let multiple forms share the short-cuts. Whether this is an option depends on your circumstances. However, you could also make the main form the owner of your data-module which would be somewhat equivalent to the second option above.
- The final option which provides the most control is OP's own answer. I.e. Any form that needs to support "external short-cuts" can handle the OnShortCut event with the following code:
As can be seen in the code sample you can delegate to multiple action lists in different locations according to the priority you choose.
procedure TMyForm.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
begin
Handled := DataModule1.ActionList3.IsShortCut(Msg);
Handled := Handled or DataModule2.ActionList1.IsShortCut(Msg);
Handled := Handled or DataModule1.ActionList1.IsShortCut(Msg);
end;