VC++ WM_CHAR和WM_KEYDOWN

一般程序初始化的时候焦点就会落到某个控件上或者说窗口,当KEYDOWN的时候是由当前活动的窗口处理的(每个控件也都是一个窗口),所以视图或者对话框就会没反应,最好在PreTranslateMessage里处理。WM_CHAR只能处理字符,而且像一些特殊鍵如ESC……不是WM_CHAR,需要反应 WM_KEYDOWN && 跟ASCII比较才能响应。对话框要重写PreTranslateMessage函数,来截获键盘消息。

MSDN文档原文内容:
WM_CHAR
The WM_CHAR message is posted to the window with the keyboard focus when a WM_KEYDOWN message is translated by the TranslateMessage function. The WM_CHAR message contains the character code of the key that was pressed.
原文意思主要是说
WM_CHAR是键盘所按下的那个字符的响应 可以用来判断是哪个字符的响应(如按下A实现什么功能 按下B 实现什么功能)而
WM_KEYDOWN是键盘按下后的消息响应(只要按下键盘都响应)

 二、不能响应回车键的原因分析
  之所以在以CEditView作为基类的程序中可以响应回车键,是由于该程序的视类本身就是一个Edit控件,这就是问题的关键所在。CEditView作为CView的派生类能响应从键盘输入的各种消息,其中有和键盘输入相关的WM_CHAR、WM_KEYDOWN、WM_KEYUP等消息。我们就可以在这些消息的响应函数中灵活地设计程序去捕捉到回车键的输入,并执行响应的操作。
  当我们将编辑框作为一个普通的控件放到对话框上时情况就发生了变化。在此我们以CFormView为例,它也是CView的一个派生类,视是一个Form窗体(即对话框),当放有编辑框的窗体有回车键输入时,由于只有编辑框可以接受从键盘输入的字符,所以当键盘按下时统统把消息都发给了编辑框(在Windows下每个窗口、按钮、编辑框都看作一个窗口,都可以接受消息),可以通过ClassWizard在"Object IDs"选中编辑框所对应的ID号,在右边的消息框中可以看出该编辑框并不能响应WM_CHAR等消息,只能用EN_CHANGE事件来做类似的响应。可当我们加入了对该事件的处理函数时,却又将回车键当作控制字符,当输入回车键并不会激发EN_CHANGE事件,也就是说用这种方法仍旧无法捕获回车键的输入。
  三、拦截回车键的思路与方法
  Windows操作系统下各个窗口、控件归根结底都是通过系统的各种各样的消息来相互协调、相互联系的,而我们所遇到的这个问题换到消息的角度说就是"如何使程序能响应在编辑框上输入的回车键所发出的消息",只要能响应到这个消息,剩下的工作都可以在消息处理函数中完成。所以有必要对Windows系统的消息机制做些了解。
  每个Windows应用程序开始执行后,Windows都为该程序创建一个"消息队列(message queue)",用来存放邮寄给该程序可能创建的各种不同窗口的消息。消息队列中消息的结构(MSG)为:

typedef struct tagMSG{
 /*msg*/
 HWND hwnd;//窗口句柄,标识接收消息的窗口。
 UINT message;//消息标识号,如WM_TIMER等。
 WPARAM wParam;//消息参数,当为键盘消息时,表示虚拟键码如VK_RETURN等。
 LPARAM lParam;//消息参数。
 DWORD time;//邮寄消息的时间。
 POINT pt;//邮寄消息时的光标位置,用屏幕坐标表示。
}MSG;


  在系统下最常用的消息循环是调用GetMessage()函数从消息队列中取出消息,然后调用DespatchMessage() 函数让系统把消息发送给窗口函数,一般情况下其结果是把窗口的所有消息都传送给窗口函数。但特殊情况下可以在GetMessage()函数获得消息而又没发送出去之前,通过TranslateMessage()函数可以中途对消息进行解析,可以对指定的消息进行拦截,拦截后即可以照样发送出去,也可以不继续发送,完成对该消息的拦截,下面代码是该过程的示例:

MSG msg;
while(GetMessage(&msg,NULL,NULL,NULL,NULL){
 TranslateMessage(&msg);
 …… //对拦截的消息进行处理
 DispathchMessage(&msg);
}

  由于按下回车键时把产生的消息加入到消息队列中了,也传给了编辑框,但仅仅是由于编辑框没有能力处理该消息而造成了无法对回车键的响应,所以可以在消息循环里在把消息发送到编辑框之前就对消息进行拦截,并对其进行处理。其效果同编辑框响应回车键是一样的,仅在时序上有所提前而已。上述代码是在SDK(Software Develope Kits)下使用的,在MFC(Microsoft Foundation Class)下早已对其进行了封装,可以通过重载虚函数PreTranslateMessage()对所关心的消息进行解析:

BOOL CTestView::PreTranslateMessage(MSG* pMsg)
{
 if (WM_KEYFIRST <= pMsg->message && pMsg->message <= WM_KEYLAST)
 {
  if(pMsg->wParam==VK_RETURN )
  {
   UpdateData(TRUE);
   AfxMessageBox(m_Text);
  }
 }
 return CFormView::PreTranslateMessage(pMsg);
}

  在上面的代码中,首先将pMsg->message所表示的消息同WM_KEYFIRST 和WM_KEYLAST比较,确定是键盘消息,然后通过消息参数pMsg->wParam的值来判断是否是回车键(VK_RETURN,虚拟键码可以从SDK相关资料查到)。如是,则可以将已输入到编辑框中的字符读取到m_Text中,并将其显示出来

void C**Dlg::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    // TODO: Add your message handler code here and/or call default
    switch(nChar)
    {
        case 'c':OnBnClickedButtonJump();break;
        case 'b':......
    }
char buf[256];
sprintf(buf,"%c",nChar); //格式化到字符
//itoa(nChar,buf,10);
AfxMessageBox(CString(buf));
CDialog::OnChar(nChar, nRepCnt, nFlags);
}
BOOL C**Dlg::PreTranslateMessage(MSG* pMsg) 
{
    if(pMsg->message==WM_KEYDOWN )
    {
        UINT iKey=(UINT)pMsg->wParam;
        if(iKey==VK_RETURN )//按了回车
        {                           
            pMsg->message=WM_CHAR;  //send WM_CHAR消息
            SendMessage(pMsg->message,pMsg->wParam,pMsg->lParam); 

        }
    }
    return CDialog::PreTranslateMessage(pMsg);
}

用VC++实现特定编辑框上对回车键响应

 前面已经可以对回车键响应了,可一个表单窗体有若干个编辑框,其各自的处理方式不尽相同,这就有必要对编辑框进行识别、对不同的编辑框做不同的处理。而且当按下回车键时必须保证只有当前有焦点的编辑框能完成对回车键的响应动作,否则也就失去了实际意义。
  在Windows下的程序中,所有的资源都是有唯一标号的,使每个资源对象能唯一的区别于其他资源,所以我们可以通过资源ID来对编辑框做出区别,使之完成各自的响应处理。在Microsoft vc++下可以通过"View"菜单的"ID= Resource Symboles…"查到指定ID的资源标识号的实际数值,如在本例中的两个编辑框IDC_EDIT1和IDC_EDIT2所对应的数值分别为1000和1001, 在此通过API函数::GetFocus()(注意前面的"::",标识是全局API函数,而非某个类中的成员函数)取得当前光标所处的(即有焦点的)编辑框的句柄,然后通过API函数::GetDlgCtrlID()根据这个句柄返回此窗口资源的ID 号,该ID号是动态获取的,使之同预先查看好的编辑框的ID作下比较即可区分出是需要哪个编辑框对回车键作出响应。

对前面的解析消息的代码做些改动,主要如下所示:

BOOL CAlv_Lidar_SystemDlg::PreTranslateMessage(MSG* pMsg) 
{
    if(pMsg->message==WM_KEYDOWN )
    {
        UINT iKey=(UINT)pMsg->wParam;
        if(iKey==VK_RETURN )//按了回车
        {  
            HWND hwnd = ::GetFocus();//获取焦点控件
            int iID = ::GetDlgCtrlID(hwnd);
            if(iID == IDC_EDIT2)  //查看是否那个控件ID
            {
                OnBnClickedButtonJump(); //点击回车,处理
            }
            return TRUE; //不能让回车退出
        }
    }
    return CDialog::PreTranslateMessage(pMsg);
}
原文地址:https://www.cnblogs.com/cheng07045406/p/3145973.html