将WM_CHANGEUISTATE发送到窗口应用程序后,当用鼠标访问菜单时,助记符不会显示在系统菜单上
After sending a WM_CHANGEUISTATE to the window app, the mnemonics are not shown on the system menu, when the menu is accessed with the mouse
下面的代码向窗口过程本身发送一个WM_CHANGEUISTATE,参数为:
LOWORD(wParam)=UIS_CLEAR
HIWORD(wParam)=UISF_HIDACCEL
lParam=0x0000000
当用鼠标左键单击窗口客户端区域时。
根据Raymond Chen的博客,当用鼠标访问菜单时,应该会显示系统菜单中的助记符。以下段落摘自本文:
清除标志将显示相应的指示符。例如,如果对于UISF_HIDEFOCUS有一个UIS_CLEAR,这意味着您要显示焦点指标。
在我的例子中,我有一个UIS_CLEAR用于UISF_HIDACCEL,这意味着我想显示菜单快捷键。
如果您运行下面的代码并用鼠标左键单击应用程序客户端区域,则应使加速器在"系统"菜单中可见,即使使用鼠标访问此菜单也是如此。但这种情况不会发生,即,如果您左键单击窗口图标或右键单击窗口标题栏激活系统菜单,则系统菜单中的助记符将不会显示。我错过了什么?
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pszCmdLine, int nCmdShow)
{
WNDCLASSEX wndclassx;
wchar_t szAppName[] = L"WM_CHANGEUISTATE";
wndclassx.cbSize = sizeof(WNDCLASSEX);
wndclassx.style = CS_HREDRAW | CS_VREDRAW;
wndclassx.lpfnWndProc = WndProc;
wndclassx.cbClsExtra = 0;
wndclassx.cbWndExtra = 0;
wndclassx.hInstance = hInstance;
wndclassx.hIcon = 0;
wndclassx.hCursor = LoadCursor(0, IDC_ARROW);
wndclassx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wndclassx.lpszClassName = szAppName;
wndclassx.lpszMenuName = nullptr;
wndclassx.hIconSm = 0;
if (!RegisterClassEx(&wndclassx)) return 0;
HWND hWnd = CreateWindow(szAppName, szAppName, WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance, 0);
ShowWindow(hWnd, SW_MAXIMIZE);
UpdateWindow(hWnd);
MSG msg;
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_LBUTTONUP:
{
BOOL b;
// Note that in my system (Windows 10) I have:
//
// Control Panel > Ease of Access > Ease of Access Center > Make the keyboard easier
//
// and the option "Underline keyboard shortcuts and access keys" unmarked (the default). Therefore, the value
// returned in b below will be 0x00000000 (FALSE).
SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &b, 0);
// If b = FALSE, the SendMessage() below should underline the accelerators in the System menu, when this menu is
// accessed with the mouse. But that doesn't work. Why?
if( !b ) SendMessage(hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_CLEAR, UISF_HIDEACCEL), NULL);
}
break;
// Setting a break in the return below, one can see that WM_CHANGEUISTATE message is being sent to the window and
// passed to DefWindowProc().
case WM_CHANGEUISTATE:
return DefWindowProc(hwnd, message, wParam, lParam);
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
这似乎是Windows中的一个错误/疏忽。DefWindowProc
在显示系统菜单之前不发送WM_QUERYUISTATE
。菜单实现直接检查最后一个输入事件,如果它来自键盘,则显示下划线。
我尝试发送和发布WM_CHANGEUISTATE
和WM_UPDATEUISTATE
以响应WM_ENTERMENULOOP
、WM_INITMENUPOPUP
、WM_NCRBUTTONDOWN
和WM_SYSCOMMAND
,但没有任何运气。
我能想出的唯一解决办法是通过将SC_MOUSEMENU
更改为SC_KEYMENU
:来破解HTSYSMENU
/图标菜单
case WM_SYSCOMMAND:
if ((wParam & 0xFFF0) == SC_MOUSEMENU)
{
return SendMessage(hwnd, WM_SYSCOMMAND, SC_KEYMENU, ' ');
}
return DefWindowProc(hwnd, message, wParam, lParam);
SC_KEYMENU
在DefWindowProc
中有特殊处理,如果适用,强制下划线。
这不处理右键单击图标、标题或任务栏。。。
- 表示"accepting anything for this template argument" C++概念的通配符
- 助记符和指向成员语法的指针
- 如何用转义符替换字符串中的所有特殊字符
- 概念TS检查忽略私有访问修饰符
- 无法获取菜单选择以运行函数.C++
- 将模板与类模板扣除占位符参数匹配
- 概念中的cv限定符需要表达式参数列表
- 如何防止clang格式在流运算符调用之间添加换行符<<
- 当使用通配符和null指针调用函数时,对输出的说明
- C++中数据类型修饰符的顺序
- 从字符串变量中逐字符读取单词
- 如何在C/C++中用FD_set Unix设置套接字文件描述符
- llvm构建器向基本块添加终止符
- 从 Boost ASIO 获取 epoll 描述符 io_service对象
- 标准库类型的赋值运算符的引用限定符
- 警告:在函数返回类型 [-Wignore 限定符] 时忽略类型限定符
- 是否有内置方法可以强制转换为不同的基础类型,但保留常量限定符?
- 将WM_CHANGEUISTATE发送到窗口应用程序后,当用鼠标访问菜单时,助记符不会显示在系统菜单上
- 如何在KDE上禁用Qt应用程序中的自动助记符
- 键盘助记符应该如何本地化