MFC 对话框Dialog响应键盘事件

在对话框程序中有时需要响应键盘和鼠标事件,MFC的对话框继承于CWnd窗口类,总结了如下几种可能的处理方式:

1,最直观的想法是重写类中的虚拟响应函数,这些响应函数有:

键盘相关:ON_WM_CHAR、ON_WM_KWEYDOWN、ON_WM_KEYUP等,对应的消息处理函数为:OnChar、OnKeyDown、OnKeyUp等

鼠标相关:ON_WM_MOUSEHWHEEL()、ON_WM_MOUSEMOVE()、ON_WM_KEYDOWN()、ON_WM_LBUTTONDOWN,对应的消息处理函数为:OnMouseHWheel、OnMouseMove等

1).cpp文件中的代码为:

BEGIN_MESSAGE_MAP(CtestDlg, CDialogEx)
	ON_WM_LBUTTONDOWN()//mouse left key down
	ON_WM_RBUTTONDOWN()//right key down
	ON_WM_MOUSEHWHEEL()
	ON_WM_MOUSEMOVE()//mouse move
	ON_WM_KEYDOWN()//keyboard key down
END_MESSAGE_MAP()
void CtestDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
	TRACE("OnLButtonDown\r\n");
	//SetFocus();
	CDialogEx::OnLButtonDown(nFlags, point);
}

2).h文件中的修改:

afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);

 

在这种情况下,OnLButtonDown可以响应,但只响应对话框的空白区域,控件区域无法响应;OnKeyDown并不能响应,消息被拦截,于是切换到另一种更直接的方法,怎么处理这种拦截将在下面的方法中叙述。

2,对PreTranslateMessage函数的重载

PreTranslateMessage是消息送给TranslateMessage函数之前被调用的,绝大多数本窗口的消息都要通过这个函数,通过重载这个函数,我们可以改变MFC的消息控制流程,只有穿过消息队列的消息才受该函数的影响。处理按键的该函数重写为:

1).cpp中的代码

BOOL CtestDlg::PreTranslateMessage(MSG* pMsg)
{
    // TODO: Add your specialized code here and/or call the base class
    //判断是否是按键消息
    if( pMsg->message == WM_KEYDOWN )
    {
        //判断具体键		
        switch( pMsg->wParam )
        { 
          case VK_LEFT://按下左键
	      TRACE("left\r\n");
              break; 
          case VK_RIGHT://按下右键
              TRACE("right\r\n");
              break;   
          case VK_UP://按下上键
              TRACE("up\r\n");
              //return TRUE;
              break; 
         case VK_DOWN://按下下键
              TRACE("down\r\n");
              //return TRUE;
              break; 
        default: 
              //return TRUE;
              break; 
      }		
    }
    return CDialogEx::PreTranslateMessage(pMsg);
}


2).h文件

afx_msg BOOL PreTranslateMessage(MSG* pMsg);

需要响应的操作都可以在该函数中操作。

现在回过头,第一种方法中按键不会响应,是因为按键消息被拦截了,此时只需要在PreTranslateMessage中添加消息转发函数即可:

SendMessage(pMsg->message,pMsg->wParam,pMsg->lParam);
但是此时发现界面刷新不顺畅,似乎还是直接在PreTranslateMessage函数中直接处理函数较好,可以直接在该函数中消息分流后直接调用响应函数。

此处介绍下MFC跟该函数相关的消息处理流程:

MFC 中PreTranslateMessage是GetMessage(...)函数的下一级操作,即GetMessage(...)从消息队列中获取消息后,交由PreTranslateMessage()处理,若其返回FALSE则再交给TranslateMessage和 DispatchMessage处理(进入WindowProc);   
如果用SendMessage,   则消息直接交到WindowProc处理,所以GetMessage不会取得SendMessage的消息,当然PreTranslateMessage也就不会被调用。   [Page]
如果用PostMessage,则消息进入消息队列,由GetMessage取得,PreTranslateMessage就有机会进行处理。


3,使用低级钩子函数

以鼠标响应为例,鼠标使用WH_MOUSE_LL,对应的函数为LowLevelMouseProc:

//  
// 全局变量和全局函数定义  
//  
HHOOK hhookMs = NULL;  
LRESULT CALLBACK LowLevelMouseProc (INT nCode, WPARAM wParam, LPARAM lParam);  
BOOL UninstallKbHook();  
BOOL InstallKbHook();  
  
//  
// 安装鼠标Hook  
//  
void CTestMFCDlg::OnButton1()   
{  
    InstallKbHook();  
}  
  
//  
// 卸掉键盘Hook  
//  
void CTestMFCDlg::OnButton2()   
{  
    UninstallKbHook();  
      
}  
  
LRESULT CALLBACK LowLevelMouseProc (INT nCode, WPARAM wParam, LPARAM lParam)  
{  
    MSLLHOOKSTRUCT *pkbhs = (MSLLHOOKSTRUCT *)lParam;  
    char strMsg[100] = {0};  
      
    switch (nCode)  
    {  
        case HC_ACTION:  
        {  
            //鼠标移动  
            if (wParam == WM_MOUSEMOVE)   
            {  
                sprintf(strMsg, "WM_MOUSEMOVE: x= %d, y= %d\n", pkbhs->pt.x, pkbhs->pt.y);  
                OutputDebugString(strMsg);  
            }  
              
            //鼠标左击  
            if(wParam == WM_LBUTTONDOWN)  
            {  
                sprintf(strMsg, "WM_LBUTTONDOWN: x= %d, y= %d\n", pkbhs->pt.x, pkbhs->pt.y);  
                OutputDebugString(strMsg);  
            }  
  
//          //滚轮事件  
//          if (wParam == WM_MOUSEWHEEL)  
//          {  
//              sprintf(strMsg, "WM_MOUSEWHEEL: %d\n", HIWORD(pkbhs->mouseData));  
//              OutputDebugString(strMsg);  
//          }  
        }  
    default:  
        break;  
    }  
    return CallNextHookEx (NULL, nCode, wParam, lParam);  
}  
  
BOOL InstallKbHook( )  
{  
      
    if (hhookMs )  
        UninstallKbHook();  
      
    hhookMs = SetWindowsHookEx(WH_MOUSE_LL,   
        (HOOKPROC)LowLevelMouseProc, AfxGetApp()->m_hInstance, NULL);  
      
    return(hhookMs != NULL);  
      
}  
  
BOOL UninstallKbHook()  
{  
      
    BOOL fOk = FALSE;  
    if (hhookMs ) {  
        fOk = UnhookWindowsHookEx(hhookMs );  
        hhookMs = NULL;  
    }  
      
    return(fOk);  
}  


鼠标低级钩子是一个全局的,只要安装钩子成功,在整个系统中都是有效的。该方法参考了http://blog.csdn.net/dijkstar/article/details/9007167




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值