VC6捕获鼠标事件(移动、单击等)的一些总结(MFC消息、DriectInput、钩子)
来源:互联网 发布:考研英语单词书 知乎 编辑:程序博客网 时间:2024/05/14 05:04
鼠标事件,无非是WM_LBUTTONDOWN、WM_LBUTTONUP、WM_MOUSEMOVE(就说这基本的三个命令吧),开始以为很容易获取这些事件,但在实现过程中,并不是想象中的那么简单:
为什么会有这种应用呢?比如在应用程序中点击某个按钮,打开了一个CMD命令行控制台窗口(验证与对方能否Ping通),弹出的CMD窗口上就无法捕获这些鼠标数据;
上面说的为什么在“在【CWinApp】中的PreTranslateMessage更好一些”?是说如果要编写的应用程序假若有多个Dialog,岂不是要给每一个窗口写一个PreTranslateMessage!
② 怎么在“整个系统”中获取鼠标?想到了DriectX中的DriectInput,和鼠标钩子。先说DriectInput,下面是在定时器或者线程中获取鼠标数据的一段:(初始化部分就不粘贴了)
用DirectInput有几个局限,一是如上程序看到,鼠标移动中给出的是“相对位置”,而不是“绝对位置”(两者如何在DirectInput中转换,我没有试出来),不得不还是使用Win32中的::GetCursorPos;二是只能判断鼠标“点击按下”,无法识别鼠标按键“抬起”,如上程序,自己模拟了在点击后延时2ms后发生“抬起”事件,但这样并不是用户在操作中的真正行为;
③ 继续说鼠标低级钩子:用的是WH_MOUSE_LL,对应的挂接函数为LowLevelMouseProc,好处是不用单独写一个DLL库,直接在应用程序中使用即可;
鼠标低级钩子是一个全局的,只要安装钩子成功,在整个系统中都是有效的,基本解决了这个问题。
综上,决定使用鼠标低级钩子。
① 在基于MFC中的对话框应用程序中,可以在 PreTranslateMessage 中获取(【主对话框】的或者是【CWinApp】的,应该说放在【CWinApp】中的PreTranslateMessage更好一些),如同下面:
BOOL CTestApp::PreTranslateMessage(MSG* pMsg) {if (pMsg->message == WM_LBUTTONDOWN)//左键按下{if(m_bSend){CPoint pt;GetCursorPos(&pt);memset(szMsg,'\0',sizeof(szMsg));sprintf(szMsg,"WM_LBD;%d;%d;%d;0;\0",pt.x, pt.y, keyFlags);LanSend(szMsg, strlen(szMsg));}}else if (pMsg->message == WM_LBUTTONUP)//左键抬起{if(m_bSend){CPoint pt;GetCursorPos(&pt);memset(szMsg,'\0',sizeof(szMsg));sprintf(szMsg,"WM_LBU;%d;%d;%d;0;\0",pt.x, pt.y, keyFlags);LanSend(szMsg, strlen(szMsg));}}else if (pMsg->message == WM_MOUSEMOVE)//光标移动{if(m_bSend){POINT pt;::GetCursorPos(&pt);memset(szMsg,'\0',sizeof(szMsg));//sprintf(szMsg,"WM_MM;%d;%d;%d;0;\0", GET_X_LPARAM(pMsg->lParam), GET_Y_LPARAM(pMsg->lParam), 0);sprintf(szMsg,"WM_MM;%d;%d;%d;0;\0", pt.x, pt.y, 0);LanSend(szMsg, strlen(szMsg));}}else if (pMsg->message == WM_KEYDOWN)//键盘按下{if(m_bSend){memset(szMsg,'\0',sizeof(szMsg));sprintf(szMsg,"WM_KD;%d;%d;%d;%d;\0",pMsg->wParam, 0, 0, 0);LanSend(szMsg, strlen(szMsg));}}else if (pMsg->message == WM_KEYUP)//键盘抬起{if(m_bSend){memset(szMsg,'\0',sizeof(szMsg));sprintf(szMsg,"WM_KU;%d;%d;%d;%d;\0",pMsg->wParam, 0, 0, 0);LanSend(szMsg, strlen(szMsg));}}return CDialog::PreTranslateMessage(pMsg);}
为什么会有这种应用呢?比如在应用程序中点击某个按钮,打开了一个CMD命令行控制台窗口(验证与对方能否Ping通),弹出的CMD窗口上就无法捕获这些鼠标数据;
上面说的为什么在“在【CWinApp】中的PreTranslateMessage更好一些”?是说如果要编写的应用程序假若有多个Dialog,岂不是要给每一个窗口写一个PreTranslateMessage!
② 怎么在“整个系统”中获取鼠标?想到了DriectX中的DriectInput,和鼠标钩子。先说DriectInput,下面是在定时器或者线程中获取鼠标数据的一段:(初始化部分就不粘贴了)
HRESULT ReadImmediateData( HWND hDlg ){ HRESULT hr; TCHAR strNewText[128] = TEXT(""); // Output string DIMOUSESTATE2 dims2; // DirectInput mouse state structure if( NULL == g_pMouse ) return S_OK; // Get the input's device state, and put the state in dims ZeroMemory( &dims2, sizeof(dims2) ); hr = g_pMouse->GetDeviceState( sizeof(DIMOUSESTATE2), &dims2 ); if( FAILED(hr) ) { // DirectInput may be telling us that the input stream has been // interrupted. We aren't tracking any state between polls, so // we don't have any special reset that needs to be done. // We just re-acquire and try again. // If input is lost then acquire and keep trying hr = g_pMouse->Acquire(); while( hr == DIERR_INPUTLOST ) hr = g_pMouse->Acquire(); // Update the dialog text if( hr == DIERR_OTHERAPPHASPRIO || hr == DIERR_NOTACQUIRED ) SetDlgItemText( hDlg, IDC_DATA, TEXT("Unacquired") ); // hr may be DIERR_OTHERAPPHASPRIO or other errors. This // may occur when the app is minimized or in the process of // switching, so just try again later return S_OK; } // The dims structure now has the state of the mouse, so // display mouse coordinates (x, y, z) and buttons. StringCchPrintf( strNewText, 128, TEXT("(X=% 3.3d, Y=% 3.3d, Z=% 3.3d) B0=%c B1=%c B2=%c B3=%c B4=%c B5=%c B6=%c B7=%c"),dims2.lX, dims2.lY, dims2.lZ, (dims2.rgbButtons[0] & 0x80) ? '1' : '0', (dims2.rgbButtons[1] & 0x80) ? '1' : '0', (dims2.rgbButtons[2] & 0x80) ? '1' : '0', (dims2.rgbButtons[3] & 0x80) ? '1' : '0', (dims2.rgbButtons[4] & 0x80) ? '1' : '0', (dims2.rgbButtons[5] & 0x80) ? '1' : '0', (dims2.rgbButtons[6] & 0x80) ? '1' : '0', (dims2.rgbButtons[7] & 0x80) ? '1' : '0'); // Get the old text in the text box TCHAR strOldText[128]; GetDlgItemText( hDlg, IDC_DATA, strOldText, 127 ); // If nothing changed then don't repaint - avoid flicker if( 0 != lstrcmp( strOldText, strNewText ) ) SetDlgItemText( hDlg, IDC_DATA, strNewText );//// 仍然使用::GetCursorPos 发送鼠标的绝对位置//char szMsg[100] = {0};POINT pt;::GetCursorPos(&pt);sprintf(szMsg,"WM_MM;%d;%d;%d;0;\0", pt.x, pt.y, 0);LanSend(szMsg, strlen(szMsg));//// 发送鼠标的【按下】和【抬起】事件//因为driectInput里无法识别鼠标抬起事件,这里只能模拟抬起//if (dims2.rgbButtons[0] & 0x80){GetCursorPos(&pt);sprintf(szMsg,"WM_LBD;%d;%d;%d;0;\0",pt.x, pt.y, 0);LanSend(szMsg, strlen(szMsg));Sleep(2);sprintf(szMsg,"WM_LBU;%d;%d;%d;0;\0",pt.x, pt.y, 0);LanSend(szMsg, strlen(szMsg));} return S_OK;}
用DirectInput有几个局限,一是如上程序看到,鼠标移动中给出的是“相对位置”,而不是“绝对位置”(两者如何在DirectInput中转换,我没有试出来),不得不还是使用Win32中的::GetCursorPos;二是只能判断鼠标“点击按下”,无法识别鼠标按键“抬起”,如上程序,自己模拟了在点击后延时2ms后发生“抬起”事件,但这样并不是用户在操作中的真正行为;
③ 继续说鼠标低级钩子:用的是WH_MOUSE_LL,对应的挂接函数为LowLevelMouseProc,好处是不用单独写一个DLL库,直接在应用程序中使用即可;
//// 全局变量和全局函数定义//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);}
鼠标低级钩子是一个全局的,只要安装钩子成功,在整个系统中都是有效的,基本解决了这个问题。
综上,决定使用鼠标低级钩子。
0 0
- VC6捕获鼠标事件(移动、单击等)的一些总结(MFC消息、DriectInput、钩子)
- VC6捕获鼠标事件(移动、单击等)的一些总结(MFC消息、DriectInput、钩子)
- MFC 通过发送消息完成按钮操作模拟鼠标单击事件的发生的问题
- python代码实现键盘鼠标事件的捕获(可能盗取QQ号,身份证信息等)
- 鼠标的单击事件
- 全局钩子(hook鼠标键盘消息)
- 后台添加gridview事件(鼠标事件,单击双击事件)个人总结
- 【框架-MFC】MFC 在捕获控件外(窗口外)鼠标事件
- MFC:为STATIC控件添加鼠标移动事件(VS2010)
- mfc 如何捕获应用程序窗口以外的鼠标事件
- (11)HTML5-鼠标单击事件监听
- opengl中鼠标移动、单击、滚轮事件
- 关于symbian按键事件的一些总结(1)----------按键事件的捕获
- MFC 鼠标双击响应单击事件
- 没有躲过的坑--捕获窗口之外的鼠标消息(钩子还是??)
- listview单击等事件没有反应(自己的失误)
- MFC中的消息响应(左键按下鼠标)和(移动鼠标)
- MFC消息处理时,双击鼠标左键响应单击左键消息的处理
- apple watch 关于不同设备的尺寸调整
- hadoop读取 Sequence格式的文件的代码
- 关于Eclipse的Indigo和MyEclipse 2013版中文注释时字体太小的问题
- 分布式发布订阅消息系统 Kafka 架构设计
- Android4.0 开放Root权限
- VC6捕获鼠标事件(移动、单击等)的一些总结(MFC消息、DriectInput、钩子)
- apple 证书 账号 内购 详解
- 如何挂载 云磁盘
- identity(1,1)
- [小技巧] gdb 里数值轮换
- JavaScript模拟confirm弹出框
- 脚本ANT自动打包Android应用(方便多渠道发布)
- DM8127 降噪调节————整体思路
- 反射获取对象实例的字段信息和字段值