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.