Reputation: 22255
Bear with me. I'll have to give you my setup.
I have a dialog window with a syslink-control on it (CLinkCtrl):
that can be clicked to display a context menu.
I'm now trying to set up an accessibility option for a user to press a spacebar or hit enter on the keyboard to display that context menu:
I'm using the NM_RETURN
notification for that:
LRESULT CTestMfcLinkCtrlDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// TODO: Add your specialized code here and/or call the base class
if(message == WM_NOTIFY)
{
NMHDR* pNmhdr = (NMHDR*)lParam;
if(pNmhdr->code == NM_RETURN)
{
showMenu();
}
}
return CDialogEx::WindowProc(message, wParam, lParam);
}
And the menu itself is shown as follows:
void CTestMfcLinkCtrlDlg::showMenu()
{
HMENU hMMenu = LoadMenu(GetModuleHandle(NULL),
MAKEINTRESOURCE(IDR_MENU1));
HMENU hMenu = GetSubMenu(hMMenu, 0);
if(hMenu)
{
HWND hParentWnd = this->GetSafeHwnd();
CWnd* pW = this->GetDlgItem(IDC_SYSLINK1);
CRect rcW;
pW->GetWindowRect(&rcW);
UINT iCmdRes = ::TrackPopupMenu(hMenu,
TPM_TOPALIGN | TPM_LEFTALIGN | TPM_LEFTBUTTON |
TPM_VERPOSANIMATION | TPM_HORPOSANIMATION | TPM_RETURNCMD,
rcW.left, rcW.bottom,
0, hParentWnd, NULL);
switch(iCmdRes)
{
//...
}
}
DestroyMenu(hMMenu);
}
IDR_MENU1
is taken from the resources:
So what happens is this: if the system-link
control has keyboard focus, press spacebar or the enter (return) key on the keyboard. My context menu will be displayed, but then at the same time you will hear a message beep, what looks like with the MB_ICONWARNING
parameter. I did some debugging and this message beep comes from the TrackPopupMenu
call.
Any idea why is it doing it and how to prevent that warning beep?
Here's the link to VS2017 MFC solution that I was testing it on.
Upvotes: 2
Views: 249
Reputation: 31599
The popup menu is opened in response to WM_CHAR
message. It seems the menu is opened before the WM_CHAR
is fully processed. So the popup menu receives the same WM_CHAR
message. The menu doesn't know what to do with that key and complains with annoying beep.
If you press the space bar while the menu is open, you will hear the same beep.
Solution, run the default function first:
LRESULT CMyDialog::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT lres = CDialogEx::WindowProc(message, wParam, lParam);
if(message == WM_NOTIFY)
{
NMHDR* pNmhdr = (NMHDR*)lParam;
if(pNmhdr->code == NM_RETURN)
{
showMenu();
}
}
return lres;
}
Or, do this in response to ON_NOTIFY
, but make sure to remove the message from the thread by using
PeekMessage(&msg, NULL, WM_CHAR, WM_CHAR, PM_REMOVE);
Example:
void CMyDialog::showMenu()
{
CMenu menu;
menu.LoadMenu(IDR_MENU1);
ASSERT(menu.GetSafeHmenu());
CMenu *popup = menu.GetSubMenu(0);
ASSERT(popup);
CRect rc;
CWnd *syslink = GetDlgItem(IDC_SYSLINK1);
ASSERT(syslink);
syslink->GetWindowRect(&rc);
MSG msg;
if (::PeekMessage(&msg, NULL, WM_CHAR, WM_CHAR, PM_NOREMOVE))
AfxGetThread()->PumpMessage();
UINT iCmdRes = popup->TrackPopupMenu(
TPM_TOPALIGN | TPM_LEFTALIGN | TPM_LEFTBUTTON |
TPM_VERPOSANIMATION | TPM_HORPOSANIMATION | TPM_RETURNCMD,
rc.left, rc.bottom, this);
switch(iCmdRes)
{
//...
}
}
Upvotes: 2