Search code examples
user-interfacedelphihotkeysaero

Delphi Application Main Form temporarly flicking to the front


We have a Delphi 2007 application and have recently enabled MainFormOnTaskBar for better support of Windows Aero. However because the main form would not come to the top of all child forms when clicked we added the following code.

procedure TBaseForm.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);

  Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
  Params.WndParent := 0; 
end;

One side effect of this is that when pressing an Alt + key hotkey on a child form that does not handle that particular hot key the main form flicks to the front and then back again. If the hot key is handled then this behavior does not occur, probably because the hotkey is swallowed.

Has anyone else experienced this behavior and can advise a workaround.

Thanks


Solution

  • The observed behavior is the result of VCL's accelerator support for a possible main menu on the main form, so that you can select menu items from the main form's menu even when another form is active.

    The activation of the main form takes place by a SetFocus call on the main form's handle while the "Application" is handling the CM_APPSYSCOMMAND message which is sent from the WM_SYSCOMMAND handler of a "WinControl" (secondary form) when command type is SC_KEYMENU (window menu activation - Alt key).

    Note that this behavior is not a side effect of using MainFormOnTaskBar and then overriding CreateParams to have forms that can be brought to front. The same behavior occurs regardless of the setting of MainFormOnTaskBar. The only difference is that the activated main form cannot come in front of secondary forms when it is set, but the main form is activated all the same.

    You can intercept to modify the behavior in a number of places, like a WM_SYSKEYDOWN handler on the secondary form, or in OnKeyDown of the secondary form. Semantically more correct override, IMO, should be done on the IsShortCut of the secondary form. As you have found out, when the secondary form handles a key combination, the processing of the system key terminates. You can, then, tell the VCL that your form requires the key:

    type
      TSecondaryForm = class(TForm)
        ..
      public
        function IsShortCut(var Message: TWMKey): Boolean; override;
    
    ...
    
    function TSecondaryForm.IsShortCut(var Message: TWMKey): Boolean;
    begin
      Result := True;
    end;
    

    Of course you can fine tune to conditionally return true depending on the parameter.