主窗体打开一个子窗体,上面有一些按钮控件。我需要捕获键盘事件,因此我对其中一个控件进行了子类化。一切都很好,直到控制当然失去焦点。
理想情况下,只要这个子窗体是打开的,我想将焦点分配给这个控件,从而捕获所有的击键,无论用户点击哪里。
我怀疑超类可能是一个更好的方法,但我并不熟悉它。
也许我应该做的是在主窗体上使用加速器?
添加:我应该提到主窗体有一个大型列表视图控件,该控件被子类化以恢复向上/向下箭头和鼠标滚轮等。
主窗体打开一个子窗体,上面有一些按钮控件。我需要捕获键盘事件,因此我对其中一个控件进行了子类化。一切都很好,直到控制当然失去焦点。
理想情况下,只要这个子窗体是打开的,我想将焦点分配给这个控件,从而捕获所有的击键,无论用户点击哪里。
我怀疑超类可能是一个更好的方法,但我并不熟悉它。
也许我应该做的是在主窗体上使用加速器?
添加:我应该提到主窗体有一个大型列表视图控件,该控件被子类化以恢复向上/向下箭头和鼠标滚轮等。
传统的方法是安装一个键盘钩子(SetWindowsHookEx),但是您需要将它注入到每个应用程序中,并且它不能跨越 32/64 位边界。
但是,您可以很容易地在计时器上使用GetKeyboardState轮询键盘并检查您的 f1-f12 键是否已激活。计时器可以慢到 100 毫秒,它几乎可以在不使用任何资源的情况下捕获所有内容。
假设这是在 Windows 和 Win32 API 中,一种选择是在您的 main GetMessage
、TranslateMessage
、DispatchMessage
循环中查找消息。您可以在此循环中对任何消息进行特殊处理,而不管它针对的是哪个窗口。
您可能应该使用IsChild
检查该消息是否用于主窗口上的控件(而不是某些可能单独显示的对话框或消息框)。获得正确的逻辑也可能很繁琐。最好只在您知道您的控件失去焦点时才拦截消息,并且只拦截您需要的确切消息。
几年前,我写了一个库消息循环,其中包含很多内置的。我有一个简单的管理器类,它保存指向我自己的小窗口类实例的指针。循环知道对话框和普通窗口之间的区别,让每个窗口类有机会窥探其子级消息,等等。您将无法直接运行它,并且约定有点奇怪,但您可能会发现这很有用......
int c_Window_List::Message_Loop (void)
{
MSG msg;
bool l_Handled;
while (GetMessage (&msg, NULL, 0, 0))
{
l_Handled = false;
c_Windows::c_Cursor l_Cursor;
bool ok;
for (ok = l_Cursor.Find_First (g_Windows); ok; ok = l_Cursor.Step_Next ())
{
if (IsChild (l_Cursor.Key (), msg.hwnd))
{
if (l_Cursor.Data ().f_Accelerators != NULL)
{
l_Handled = TranslateAccelerator (l_Cursor.Key (), l_Cursor.Data ().f_Accelerators, &msg);
if (l_Handled) break;
}
if (l_Cursor.Data ().f_Manager != 0)
{
l_Handled = l_Cursor.Data ().f_Manager->Spy_Msg (l_Cursor.Key (), msg);
}
if (l_Handled) break;
if (l_Cursor.Data ().f_Is_Dialog)
{
l_Handled = IsDialogMessage (l_Cursor.Key (), &msg);
if (l_Handled) break;
}
}
}
if (!l_Handled)
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
if (g_Windows.Size () == 0)
{
// When all windows have closed, exit
PostQuitMessage (0);
}
}
return msg.wParam;
}
f_
前缀表示字段 - 我后来采用了约定m_
,但是很长时间没有重新访问此代码。f_Manager
特别指向我c_Window_Base
班级的一个实例。该类c_Cursor
是一种迭代器,用于遍历存储在g_Windows
变量中的所有窗口(实际上是静态类成员而不是全局成员)。