Home > database >  How to make Tpopupmenu to pre-select the 1st menu entry when a popup is opened with the keyboard
How to make Tpopupmenu to pre-select the 1st menu entry when a popup is opened with the keyboard

Time:04-01

The items in TPopupMenu can be highlighted/selected with keyboard or mouse. When selected with keyboard, you can move in the menu with the arrow keys.

How to mark the 1st menu item as selected (blue) without simulating the down arrow keypress with VK_DOWN (see code below)?

Popup := TPopupMenu.create(nil);
Popup.OnPopup := PopupClick;
class procedure TTrayMain.PopupClick(Sender: TObject) ;
begin    
  // Code below activates the first menu entry.. 
  // Now Looking for an alternative solution to replace this hack:
  keybd_event( VK_DOWN, MapVirtualKey( VK_DOWN,0), 0, 0);
  keybd_event( VK_DOWN, MapVirtualKey( VK_DOWN,0), KEYEVENTF_KEYUP, 0);

end;

CodePudding user response:

I believe you are stuck with faking input. I think you can PostMessage key down/up messages to GetFocus. That makes it at least a local hack instead of global. You might need a hook to catch the right message to trigger the hack.

Ideally this should be documented here but sadly it's not. The only way to know for sure how Microsoft does it would be to debug Explorer in 98/2000/XP. The menu implementation on these systems in Explorer and Internet Explorer is a context menu dropped down from toolbar buttons, faking a menu bar.

CodePudding user response:

You need to send the undocumented MN_SELECITEM message to the popupwindow.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    PopupMenu1: TPopupMenu;
    Item1: TMenuItem;
    Item2: TMenuItem;
    Item3: TMenuItem;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  //To override the default PopupList, based on Remy Lebeau's code
  TPopupListEx = class(TPopupList)
  protected
    procedure WndProc(var Message: TMessage); override;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

const MN_SELECTITEM = $01E5;

{ TPopupListEx }

procedure TPopupListEx.WndProc(var Message: TMessage);
var hm:HMENU;

begin
  inherited;
  if (Message.Msg = WM_ENTERMENULOOP) and (Message.WParam = 1) then
    begin
      //When the popupwindow is already created, we can ask it's handle
      hm:=FindWindow(PChar('#32768'),nil);
      //Send the MN_SELECTITEM message. The third parameter is the desired menuitem's index.
      SendMessage(hm,MN_SELECTITEM,0,0);
    end;
end;

initialization
  Popuplist.Free; //free the "default", "old" list
  PopupList := TPopupListEx.Create; //create the new one
  // The new PopupList will be freed by
  // finalization section of Menus unit.
end.

Note about other (including the mentioned delphipraxis sample) solutions:

Setting the MenuItem to a highlight state with SetMenuItemInfoW or with HiliteMenuItem won't work, since it's only affect the appearance, but when you hover the mouse over any other item, the first item remains highlighted.

  • Related