VC中键盘事件处理主要是通过对相应的消息的响应,这些事件有如:WM_CHAR、
WM_KEYDOWN、WM_KEYUP等他们分别对应OnChar、OnKeyDown、OnKeyUp消息处
理函数;当然在有些时候我们也可能需要用到对PreTranslateMessage函数的重载。
从这些事件的名称我们可以看出WM_CHAR表示字符事件,WM_KEYDOWN表示键
盘的键被按下时事件,而WM_KEYUP则表示键盘的键被放开时的事件;我们在键盘上按
下某个键时系统先调用OnKeyDown函数接着调用OnChar函数最后调用OnKeyUp函数;
这些消息函数的原形如下:
afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
nChar代表虚拟键,nRepCnt代表重复次数;而对于nFlags则有点麻烦但大多数时候我们不
管这个参数,nFlags的具体意义请参考MSDN相关文档。
在大多数时候我们只要用到OnChar、OnKeyDown、OnKeyUp这些消息处理函数就够
了,但有时候我们会发理这些函数并不会被调用(特别是对话框程序)这时我们就必需去重
载PreTranslateMessage函数;些函数的使用也比较简单但在处理组合按键时我们必需用到相
键盘消息被拦截而得不到正常响应,其中的关键就是Run函数对消息的预处理。在Run
函数中,调用了函数CWinThread::PumpMessage,就是利用这一函数,MFC实现了对消息
的分流,使得消息沿着MFC对各种消息规定的路线流动,直到被正确响应。函数PumpMessage调用了函数CWinThread::PreTranslateMessage对消息进行处理,如
果该函数不对消息进行处理,则调用API函数TranslateMessage函数将虚拟键消息转换为字
符消息并调用DispatchMessage分发消息给窗口处理程序。在对话框中,程序用
CWinThread::PreTranslateMessage函数处理了键盘消息,所以对话框程序是否要响应键盘消
息,将完全由CWinThread::PreTranslateMessage函数来决定了。
在CWnd及其派生类的成员函数PreTranslateMessage函数是一个虚函数,可以通过重
载来改变其处理过程。在默认情况下,没有重载这一函数。
例子1:
在VC6中创建基于对话框的工程,在Class view中找到相应的对话框类单击右键,在右键
菜单中选择Add Virtual Fuction...项,然后找到PreTranslateMessage虚函数进行加载。相应的
代码中如下:
BOOL CTestDlg::PreTranslateMessage(MSG* pMsg)
{
// TODO: Add your specialized code here and/or call the base class
//判断是否是按键消息
if( pMsg->message == WM_KEYDOWN )
{
MessageBox("有键被按下");
//判断具体键
switch( pMsg->wParam )
{
case VK_LEFT://按下左键
MessageBox(_T("左"));
return TRUE;
break;
case VK_RIGHT://按下右键
MessageBox(_T("右"));
return TRUE;
break;
case VK_UP://按下上键
MessageBox(_T("上"));
return TRUE;
break;
case VK_DOWN://按下下键
MessageBox(_T("下"));
return TRUE;
break;
default:
return TRUE;
break;
}
return CDialog::PreTranslateMessage(pMsg);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
将return CDialog::PreTranslateMessage(pMsg);放在if里将导致程序无法正常关闭!
最起码应该放到if的外面去。
下面是一个用WASD这几个按键控制滑块的代码:(用→这样的按钮控制时老是出问题)
其中m_X,和m_Y为滑块的控制变量
BOOL CTestDlg::PreTranslateMessage(MSG *pMsg)
{
if (pMsg->wParam == 'W')
{
Y = m_Y.GetPos();
Y++;
m_Y.SetPos(Y);
}
else if (pMsg->wParam == 'S')
{
Y = m_Y.GetPos();
Y--;
m_Y.SetPos(Y);
}
else if (pMsg->wParam == 'A')
{
X = m_X.GetPos();
X--;
m_X.SetPos(X);
}
else if (pMsg->wParam == 'D')
{
X = m_X.GetPos();
X++;
m_X.SetPos(X);
}
return CDialog::PreTranslateMessage(pMsg);
}
当然也可以分开写:
1.先添加PreTranslateMessage(pMsg);里面只加入:
return CDialog::PreTranslateMessage(pMsg);
即:
BOOL CKEYDlg::PreTranslateMessage(MSG *pMsg)
{
// TODO: Add your specialized code here and/or call the base class
return CDialog::PreTranslateMessage(pMsg);
}
2.然后添加单独添加WM_KEYDOWN等消息:
void CKEYDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
if (nChar == VK_SPACE)
{
MessageBox("空格键被按下","提示!");
}
CDialog::OnKeyDown(nChar, nRepCnt, nFlags);
}
另附上 虚拟码:
后面括号的是对应的ASCII码
ESC键 VK_ESCAPE (27)
回车键: VK_RETURN (13)
TAB键: VK_TAB (9)
Caps Lock键: VK_CAPITAL (20)
Shift键: VK_SHIFT ($10)
Ctrl键: VK_CONTROL (17)
Alt键: VK_MENU (18)
空格键: VK_SPACE ($20/32)
退格键: VK_BACK (8)
左徽标键: VK_LWIN (91)
右徽标键: VK_LWIN (92)
鼠标右键快捷键:VK_APPS (93)
Insert键: VK_INSERT (45)
Home键: VK_HOME (36)
Page Up: VK_PRIOR (33)
PageDown: VK_NEXT (34)
End键: VK_END (35)
Delete键: VK_DELETE (46)
方向键(←): VK_LEFT (37)
方向键(↑): VK_UP (38)
方向键(→): VK_RIGHT (39)
方向键(↓): VK_DOWN (40)
F1键: VK_F1 (112)
F2键: VK_F2 (113)
F3键: VK_F3 (114)
F4键: VK_F4 (115)
F5键: VK_F5 (116)
F6键: VK_F6 (117)
F7键: VK_F7 (118)
F8键: VK_F8 (119)
F9键: VK_F9 (120)
F10键: VK_F10 (121)
F11键: VK_F11 (122)
F12键: VK_F12 (123)
Num Lock键: VK_NUMLOCK (144)
小键盘0: VK_NUMPAD0 (96)
小键盘1: VK_NUMPAD0 (97)
小键盘2: VK_NUMPAD0 (98)
小键盘3: VK_NUMPAD0 (99)
小键盘4: VK_NUMPAD0 (100)
小键盘5: VK_NUMPAD0 (101)
小键盘6: VK_NUMPAD0 (102)
小键盘7: VK_NUMPAD0 (103)
小键盘8: VK_NUMPAD0 (104)
小键盘9: VK_NUMPAD0 (105)
小键盘.: VK_DECIMAL (110)
小键盘*: VK_MULTIPLY (106)
小键盘+: VK_MULTIPLY (107)
小键盘-: VK_SUBTRACT (109)
小键盘/: VK_DIVIDE (111)
Pause Break键: VK_PAUSE (19)
Scroll Lock键: VK_SCROLL (145)
字母的虚拟码直接使用ASCII码即可
另外需要注意:
VK_?? 定义在 winuser.h 中,而对于字母123...,ABC..却没有VK_A,VK_B...
MFC中恰恰没有VK_0 -- VK_9,VK_A --VK_Z ,倒是有VK_NUMPAD0 --VK_NUMPAD9
在delphi,BCB,JAVA中都有。
当然,你可以直接定义,但是打开winuser.h会找到:
所以直接用'A'就行了!