PreTranslateMessage详解
1. 函数原型:( MSDN )
Override this function to filter window messages before they are dispatched to the Windows functions
TranslateMessage and DispatchMessage The default implementation performs accelerator-key translation,
so you must call the CWinApp::PreTranslateMessage member function in your overridden version.
virtual BOOL PreTranslateMessage( MSG* pMsg );
Parameters
pMsg :A pointer to a MSG structure that contains the message to process.
Return Value
Nonzero if the message was fully processed in PreTranslateMessage and should not be processed further.
Zero if the message should be processed in the normal way.
重载该函数可以实现窗口消息在派发给窗口函数 TrnaslateMessage 和 DispatchMessae() 之前的过滤 .缺省的实现是完成加
速键的翻译 . 因为您必须在你的重载版本中调用 CWinApp:PreTranslateMessage()函数 .在 MFC 中, PreTranslateMessage
是虚函数,我们可以重载它来处理键盘和鼠标消息。在 sdk 中,这又有所不同,我们必须在回调函数中
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 处理消息:
它和 PreTranslateMessage 起的作用是类似的。只是 MFC 封装的更好而已
2. 说明:
该函数表示在消息处理( TranslateMessge() 和 DispatchMessage() 等)前所作的操作,如果函数返回值为 TRUE ,那么消息 处理即终止,
不会调用 TranslateMessge() 和 DispatchMessage() 来翻译和分发消息给相应的窗口;若返回值为 FALSE ,才会调用翻译和分发消息函数。
该函数是 MFC 消息控制流最具特色的地方,它是 CWnd 类的虚拟函数,通过重载这个函数,我们可以改变 MFC 的消息控制流程,甚至可
以作一个全新的控制流出来。
在 win32 程序中,关于消息有两种传递方式:
1. MFC 消息, MFC 会把所有的消息一条条放到一个 AFX_MSGMAP_ENTRY 结构中,形成一个数组,该数组存放了所有的消息和与
它们相关的参数。也可以说是放到消息队列里去。
2. 采用 SendMessage() 或其他类似的方式向窗口直接发送的而不经过消息队列的消息。
这两种方式中只有第一种(穿过消息队列的消息)才受 PreTranslateMessage() 影响,
第二种消息并不会理睬 PreTranslateMessage() 的存在。
1) 是否调用 TranslateMessage() 和 DispatchMessage() 是由一个名称为 PreTranslateMessage() 函数的返回值决定的,如果该函数返回
TRUE ,则不会把该消息分发给窗口函数处理。
2) 传给 PreTranslateMessage() 的消息是未经翻译过的消息,它没有经过 TranslateMessage() 处理。可以在该函数中使用
(pMsg->wParam==VK_RETURN) 来拦截回车键。
3) 在 WindowProc 里不能处理 WM_Char 消息。( WindowProc 函数见 MFC 消息响应机制一文)
4) SetWindowText 会发送 WM_Char 给窗口。
5) PeekMessage 和 GetMessage 的区别:
6) GetMessage 在没有消息的时候等待消息, cpu 当然低
7) PeekMessage 没有消息的时候立刻返回,所以 cpu 占用率高。因为游戏不能靠 windows 消息驱动,所以要用 PeekMessage();
另一篇文章中:
在一个 WIN32 程序中, WINDOWS 会将消息传递给相应的窗口。但是消息不是立即就被传递给相应的窗口,而是会从整个程序最顶层
的窗口传递到下一级窗 口,再传递到下一级窗口,直到传递给目标窗口。在整个过程中,有些消息,在某些特定的情况下,无法默认传递到目
标窗口的。比如用户在 EDIT 控件中按下回 车键, CANCEL 键等,如果 EDIT 窗口之前有对话框窗口,对话框会默认处理回车消息(即响应
ONOK 函数,然后关闭对话框),然后退出消息传递。所以 EDIT 会收不到。要解决这个问题,可以在 EDIT 窗口之前所有的对话框中重载
PreTranslateMessage 函数,然后在函数内加上:
if (pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_RETURN) // 如果消息类型为WM_KEYDOWN 并且用户按下的是回车
return FALSE; // 不翻译消息,直接将消息传递下去。具体可查 MSDN 。注意,这里返回值不能为TRUE , TRUE 的意思是翻译消息后退出消
息传递,如此一来虽然也能避开对话框默认处理,但是会退出消息传递,这样 EDIT 控件照样得不到消息。
如此,就可避开对话框默认处理,将消息传递下去。注意:只有对话框才会默认处理按下回车,CANCEL 消息,其他控件窗口则不会,所以在其
他窗口中不必重载 PreTranslateMessage 函数,当然如果重载了也不会错。
附:关于 PreTranslateMessage() 函数的小程序示例:
BOOL CSearchuserDlg::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message==WM_KEYDOWN) // 判断是否有按键按下
{
switch (pMsg->wParam)
{
case VK_DOWN: // 表示是方向键中的向下的键
//add handle code here
break ;
case VK_UP: // 表示是方向键中的向上的键
//add handle code here
break ;
default :
break ;
}
}
}
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg)
{
// TODO: Add your specialized code here and/or call the base class
// 按键相应
if (pMsg->message == WM_KEYDOWN)
{
if (pMsg->wParam == VK_DOWN)
{
// 向下键按下
}
else if (pMsg->wParam == VK_RIGHT)
{
// 向右键按下
}
else if (pMsg->wParam == VK_LEFT)
{
// 向左键按下
}
else if (pMsg->wParam == VK_UP)
{
// 向上键按下
}
else if (pMsg->wParam == VK_SHIFT)
{
//VK_LSHIFT 为左 Shift 键按下
//Shift 键按下
}
else if (pMsg->wParam == VK_CONTROL)
{
//Ctrl 键按下
}
else if (pMsg->wParam>=VK_NUMPAD0 && pMsg->wParam<=VK_NUMPAD9)
{
// 小键盘数字键按下
}
else if (pMsg->wParam>=0x30 && pMsg->wParam<=0x39)
{
// 数字键按下 ( 我记得不能使用 VK_0)
}
else if (pMsg->wParam>=0x41 && pMsg->wParam<=0x5A)
{
// 键盘字母键按下 ( 我记得不能使用 VK_A)
}
else if (pMsg->wParam == VK_BACK)
{
// 退格键按下
}
else if (pMsg->wParam == VK_DELETE)
{
// 删除键按下
}
else if (pMsg->wParam == VK_F1)
{
//F1 键按下
}
//return true; // 使消息不再进行处理
}
if (pMsg->message == WM_KEYUP)
{
if (pMsg->wParam == VK_SHIFT)
{
//Shift 键弹起
}
else if (pMsg->wParam == VK_CONTROL)
{
//Ctrl 键弹起
}
//return true; // 使消息不再进行处理
}
return CDialog::PreTranslateMessage(pMsg);
}
// 同时按下 ctrl 键
BOOL CDemo_DevStudioView::PreTranslateMessage(MSG* pMsg) // 根据键盘上的按键对图形进行相应的操作
{
if (pMsg->message==256) // 256 有键按下, 46 DEL 键
{
switch (pMsg->wParam)
{
/// 向左键被按下
case 37:
{
// 同时按下了 CTRL 键
if (::GetKeyState(VK_CONTROL) < 0)
{
}
}
}
}
}