This is a VCL design issue. (Below explanation maybe somewhat off in parts. I'm tracing with XE2 and the behavior is not exactly equivalent. You may need to leave off one of the message handlers at the solution part.)
Menu bar accelerators generate a WM_SYSCOMMAND
message. Your exact accelerator case is given as an example in API documentation:
If the wParam is SC_KEYMENU, lParam contains the character code of the
key that is used with the ALT key to display the popup menu. For
example, pressing ALT+F to display the File popup will cause a
WM_SYSCOMMAND with wParam equal to SC_KEYMENU and lParam equal to 'f'.
Action menu bars are proprietary VCL components. As such default window procedure of a form have no chance to handle an accelerator message for them. The component itself have the code to simulate the behavior (TCustomActionMainMenuBar.WMSysCommand
), but it has to be delivered the message to be able to do that. VCL's design issue is that, only an action menu bar on the main form is given that opportunity.
A TWinControl
receiving a WM_SYSCOMMAND
(secondary form itself or the memo in this case), makes its parent form (secondary form) perform a CM_APPSYSCOMMAND
. Upon receiving the message, the form (again the secondary form) sends the message to the Application window. CM_APPSYSCOMMAND
handler of the Application, transforms the message again to a WM_SYSCOMMAND
and sends it to the main form.
I can only guess, but the purpose behind this design can be, to be able to access the main menu from secondary forms that don't have menu bars.
In any case, short of switching to native menus, you have to intercept and forward the message to the action menu bar on the secondary form before the message is processed by the VCL. There can be other ways to accomplish this, but what I tried and seemed to work is this:
type
TSecondaryForm = class(TForm)
...
protected
procedure CMAppsyscommand(var Message: TMessage); message CM_APPSYSCOMMAND;
procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND;
...
procedure TSecondaryForm.CMAppsyscommand(var Message: TMessage);
begin
if ActionMainMenuBar1.Perform(PMessage(Message.LParam).Msg,,
PMessage(Message.LParam).WParam, PMessage(Message.LParam).LParam) = 0 then
inherited;
end;
// you may not need the below handler
procedure TSecondaryForm.WMSysCommand(var Message: TWMSysCommand);
begin
if ActionMainMenuBar1.Perform(Message.Msg,
TMessage(Message).WParam, TMessage(Message).LParam) = 0 then
inherited;
end;