第5讲Windows应用程序中的键盘与鼠标扫描码是依赖于具体设备的,为达到设备无关性的要求,往往使用与具体设备无关的虚拟码,虚拟码是由Windows系统定义的与设备无关的键的标识由于键盘的输入产生一条消息扫描码、虚拟码以及其他与击键有关的消息设备驱动程序截取键的扫描码翻译虚拟码它含键盘上的键对应一个唯一的标识值(扫描码)按下或释放某键时产生取出键盘消息进行处理消息设备驱动程序把消息放到系统的消息队列中Windows从系统消息队列中取出消息发送到相应的线程消息队列中窗口过程6.1键盘在应用程序中的应用虚拟码是一种与设备无关的键盘编码,它的值存放在键盘消息的wParam参数中,用以标识哪一个键被按下或释放,最常用的虚拟码已经在Windows.h中定义,常用的虚拟码符号常量名称等价的键盘键或鼠标按钮符号常量名称等价的键盘键或鼠标按钮VK_LBUTTON鼠标左按钮VK_BACK退格键VK_RBUTTON鼠标右按钮VK_TAB制表键VK_MBUTTON鼠标中按钮VK_RETURN回车键VK_SHIFTShift键VK_CONTROLCtrl键VK_MENUAlt键VK_PAUSEPause键VK_CAPITALCapsLock键VK_ESCAPEEsc键VK_PRIORPageUp键VK_NEXTPageDown键VK_ENDEnd键VK_HOMEHome键VK_LEFT左键头键VK_RIGHT右箭头键VK_UP上箭头键VK_DOWN下箭头键VK_0~VK_90~9键VK_A~VK_ZA~Z键操作系统在接收到键盘输入后把消息发送给具有“输入焦点(inputfocus)的窗口应用程序一般有几个窗口,但当按下某一个键时,只有一个窗口能接收到该键盘消息,接收这个键盘消息的窗口称为有“输入焦点”的窗口有“输入焦点”的窗口应是活动窗口或者活动窗口的子窗口窗口正在接收输入焦点窗口函数通过捕获WM_SETFOCUS和WM_KILLFOCUS消息确定当前窗口是否具有输入焦点。窗口失去输入焦点键盘消息按键消息字符消息按下或松开一个键时就产生了一按键消息一个按键的组合产生了一个可以显示的字符时,就产生了一个字符消息系统按键消息非系统按键消息Alt键与相关输入键的组合产生的消息,这些键一般由Windows系统内部直接处理,应用程序不处理若应用程序处理了这些系统键消息,还要调用DefWindowsProc()函数,以便不影响系统对它们的处理不使用Alt键组合的的按键消息消息类型含义WM_KEYDOWN非系统按下了非系统键消息WM_KEYUP非系统松开了非系统键消息WM_SYSKEYDOWN系统按下了系统键消息WM_SYSKEYUP系统松开了系统键消息按键消息的两个变量wParamlParam32位的变量重复计数位(0~15位)OEM扫描码(16~23位)扩展键标志(24位)保留位(25~28位)关联码(29位)键的先前状态(位30)转换状态(31位)包含了识别按下的键的虚键码在WinMain函数的消息循环中包含了TranslateMessage函数,其功能是把按键消息转化为字符消息,但只有当键盘驱动程序把键盘字符映射成ASCII码后才能产生WM_CHAR消息消息类型含义WM_CHAR非系统非系统字符WM_DEADCHAR非系统非系统死字符WM_SYSCHAR系统系统字符WM_SYSDEADCHAR系统系统死字符字符消息系统非系统WM_KEYDOWN和WM_KEYUP的按键消息只能产生非系统消息WM_SYSKEYDOWN和WM_SYSKEYUP按键消息只能产生系统消息【6-1】设计一个窗口,在该窗口中练习键盘的响应,要求如下:(1)单击键盘上的向上箭头时,窗口中显示“Youhadhittedtheupkey”(2)单击Shift键时,窗口中显示“YouhadhittedtheSHIFTkey”(3)单击Ctrl键时,窗口中显示“YouhadhittedtheCTRLkey”(4)单击Ctrl+A键时,窗口中显示“YouhadhittedtheCTRLAkey”(5)单击Shift+B键时,窗口中显示“YouhadhittedtheSHIFTBkey”longWINAPIWndProc(HWNDhWnd,UINTiMessage,UINTwParam,LONGlParam){HDChDC;//定义设备环境句柄.PAINTSTRUCTps;//定义包含绘图信息的结构体变量HPENhPen;//定义画笔句柄。HBRUSHhBrush;//定义画刷句柄//以下定义输出的字符串。staticcharcUp[]=YouhadhittedtheUPkey;staticcharcCtrl[]=YouhadhittedtheCtrlkey;staticcharcShift[]=YouhadhittedtheSHIFTkey;staticcharcCtrl_A[]=YouhadhittedtheCTRLAkey;staticcharcShift_B[]=YouhadhittedtheSHIFTBkey;//下面定义并初始化按键标志变量。staticBOOLnUpKeyDown=FALSE,nShiftKeyDown=FALSE,nCtrlKeyDown=FALSE,nCtrlAKeyDown=FALSE,nShiftBKeyDown=FALSE;switch(iMessage){caseWM_KEYDOWN:{switch(wParam){caseVK_UP://当按上箭头键时,变量置为真。nUpKeyDown=TRUE;break;caseVK_SHIFT://当按shift键时,变量置为真。nShiftKeyDown=TRUE;break;caseVK_CONTROL://当按control键时,变量置为真nCtrlKeyDown=TRUE;break;default:break;}}break;caseWM_KEYUP:InvalidateRect(hWnd,NULL,FALSE);break;caseWM_CHAR:if(wParam==(65&VK_CONTROL))//65为主键盘字符A的ASCII码值{if(nCtrlKeyDown==TRUE)//VK_CONTROL的值为11{nCtrlAKeyDown=TRUE;nCtrlKeyDown=FALSE;}}elseif(wParam==98||wParam==66)//当按下b键时。66是B{if(nShiftKeyDown==TRUE)//检查shift键是否处于按下状态。{nShiftBKeyDown=TRUE;//当SHIFT键按下时,变量置为真nShiftKeyDown=FALSE;}}break;caseWM_PAINT://处理绘图消息.hDC=BeginPaint(hWnd,&ps);hBrush=(HBRUSH)GetStockObject(WHITE_BRUSH);//创建白画刷。hPen=(HPEN)GetStockObject(WHITE_PEN);//创建白画笔。SelectObject(hDC,hPen);//选入白画刷SelectObject(hDC,hBrush);//选入白画笔SetTextColor(hDC,RGB(255,0,0));//设置字体颜色为红色。//输出信息。if(nUpKeyDown==TRUE){Rectangle(hDC,0,0,300,200);//绘制一个矩形TextOut(hDC,0,0,cUp,strlen(cUp));//在矩形内输出字符串cUPnUpKeyDown=FALSE;//重新刷新}elseif(nCtrlAKeyDown==TRUE){Rectangle(hDC,0,0,300,200);TextOut(hDC,0,100,cCtrl_A,strlen(cCtrl_A));nCtrlAKeyDown=FALSE;nCtrlKeyDown=FALSE;}elseif(nCtrlAKeyDown==TRUE)elseif(nCtrlKeyDown==TRUE&&nCtrlAKeyDown==FALSE){Rectangle(hDC,0,0,300,200);TextOut(hDC,0,60,cCtrl,strlen(cCtrl));nCtrlKeyDown=FALSE;}elseif(nShiftBKeyDown==TRUE){Rectangle(hDC,0,0,300,200);TextOut(hDC,0,0,cShift_B,strlen(cShift_B));nShiftBKeyDown=FALSE;nShiftKeyDown=FALSE;}elseif(nShiftBKeyDown==FALSE&&nShiftKeyDown==TRUE){Rectangle(hDC,0,0,300,200);TextOut(hDC,0,0,cShift,strlen(cShift));nShiftKeyDown=FALSE;}else;//删除画笔和画刷DeleteObject(hPen);DeleteObject(hBrush);EndPaint(hWnd,&ps);break;caseWM_DESTROY:PostQuitMessage(0);return0;default:return(DefWindowProc(hWnd,iMessage,wParam,lParam));}return0;}用户窗口区输入“这是一个有关键盘操作的示例程序”的字符串程序中缓冲区大小只设30个字符,当缓冲区满时若再输入任何字符,就出现(1)号错误提示用户按下左箭头键直至光标到达本行起始位置时,就无法再往左移动,则出现(2)号错误信息若此时您按下Esc键,就出现(3)号错误提示信息若当前光标位置处于本行的起始位置,此时按下回退键(BackSpace),则出现编号为(4)的错误提示信息若字符缓冲区中已没有任何字符,此时按下了Delete键,则出现(5)号错误提示信息6.2键盘操作应用举例【例6-2本例演示键盘输入时所产生的消息序列并在窗口的客户区显示对应的字符longWINAPIWndProc(HWNDhWnd,UINTiMessage,UINTwParam,LONGlParam){#defineBufSize15//设置存放字符的缓冲区大小staticcharcCharBuf[BufSize];//设置静态字符数组,存放输入的字符,字符个数不能超出缓冲区大小staticintnNumChar=0;//现有字符个数staticintnArrayPos=0;//字符的位置staticintnLnHeight;staticintnCharWidth;intx;HDChDC;TEXTMETRICtm;PAINTSTRUCTPtStr;//定义指向包含绘图信息的结构体变量switch(iMessage)//处理消息{caseWM_CHAR://遇到非系统字符所作的处理{if(wParam==VK_BACK)//处理“遇到回退键的消息”{if(nArrayPos==0)//若已在一行文字的开始处,则提示用户不能回退MessageBox(hWnd,当前位置是文本的起始位置,不能回退,NULL,MB_OK);else{nArrayPos=nArrayPos-1;//每按一次回退键就回退一个字符的位置nNumChar=nNumChar-1;//对现有字符总数进行计数InvalidateRect(hWnd,NULL,TRUE);//刷新用户区,并序发送WM_PAINT消息}break;}if(wParam==VK_ESCAPE)//处理按下Escape键消息{MessageBox(hWnd,您现在不能按ESC键,请继续其它操作,NULL,MB_OK);break;}if(nNumChar=BufSize)//如果写入的字符数超过缓冲区大小,则报警{Me