用户点击桌面上的任意点(不在目标窗口内),如何用键盘钩子捕获到该消息,或者有更好的办法?

2010-11-13 11:23:06

4 Answers

就像@黄文彬说的,我再被充一下,全局的鼠标抓获有两种方式

1.WH_MOUSE

2.WH_MOUSE_LL

这二种都可以实现全局鼠标消息的捕获,唯一不同的是WH_MOUSE是捕获GetMessage 或者 PeekMessage 函数所触发的鼠标消息,而WH_MOUSE_LL则是当有鼠标消息事件产生即触发。

相对来说WH_MOUSE_LL权限更高一些。

我附上一段代码

#include "stdafx.h" #include "msgh.h" #pragma data_seg("ShareData") HHOOK g_Hook = NULL; HWND g_Hwnd = NULL; DWORD g_dwMsg = 0; HINSTANCE g_hHINS = NULL; #pragma data_seg() // //SECTIONS // ShareData READ WRITE SHARED BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { g_hHINS = (HINSTANCE)hModule; switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } LRESULT CALLBACK MouseProc( int nCode, // hook code WPARAM wParam, // message identifier LPARAM lParam // mouse coordinates ) { // if (HC_ACTION == nCode) { //if (WM_MOUSEMOVE == wParam) { SendMessage(g_Hwnd, g_dwMsg, wParam, lParam); // return 1; } } return CallNextHookEx(g_Hook, nCode, wParam, lParam); } extern "C" MSGH_API void installHook(HWND hWnd, DWORD dwMsg) { g_Hwnd = hWnd; g_dwMsg = dwMsg; g_Hook = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, g_hHINS, 0); DWORD dwE = GetLastError(); DWORD k = dwE; }
2010-11-13 15:07:56

提供SetWindowsHookEx的一个例子:

//nType ,0-mouse,1-key! //fInstall,TRUE-install hook FALSE-uninstall hook //dwThreadId,0-hook all process! other-hook specified process! HHOOK hMouseHook=NULL,hKeyHook=NULL; BOOL CMouseKeyHookDlg::SetHook(INT nType, BOOL fInstall, DWORD dwThreadId) { BOOL fOk = TRUE; if(nType == 0) { if (fInstall) { //Install the windows'' hook HINSTANCE hInst=LoadLibrary((LPCTSTR) "MsgHook.dll"); //MsgHook.dll is in the same path hMouseHook = SetWindowsHookEx(WH_MOUSE,(HOOKPROC)GetProcAddress(hInst, "CallBackMouseMsgProc"),hInst,dwThreadId); fOk = (hMouseHook != NULL); } else { fOk = UnhookWindowsHookEx(hMouseHook); hMouseHook = NULL; } }else if (nType == 1) { if (fInstall) { //Install the windows'' hook HINSTANCE hInst = LoadLibrary((LPCTSTR) "MsgHook.dll"); //MsgHook.dll is in the same path hKeyHook = SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)GetProcAddress(hInst, "CallBackKeyMsgProc"),hInst,dwThreadId); fOk = (hKeyHook != NULL); } else { fOk = UnhookWindowsHookEx(hKeyHook); hKeyHook = NULL; } } return (fOk); }
2010-11-13 16:16:40

用setcapture只能捕获到鼠标单击的事件
SetCapture并非只能捕获单击事件。
你使用SetCapture不能获取MouseMove事件是因为你处理WM_MOUSEMOVE是依赖于当前窗口的。当鼠标在这个窗口之外时,系统不会把WM_MOUSEMOVE返回给SetCapture的窗口。
如果你实在想处理这个消息,可以使用SetTimer来获取鼠标位置试试:)
实在不行,只有Hook了。
用Hook可以轻松获得任意鼠标事件,只是所付出的代价是:系统的效率
void CMyTestView::OnLButtonDown(UINT nFlags, CPoint point)
{
SetCapture();
TRACE("OnLButtonDown\n");

CView::OnLButtonDown(nFlags, point);
}

int g_nValue = 0 ;

void CMyTestView::OnMouseMove(UINT nFlags, CPoint point)
{
TRACE("OnMouseMove%d\n" , g_nValue++);

CView::OnMouseMove(nFlags, point);
}

void CMyTestView::OnLButtonUp(UINT nFlags, CPoint point)
{
ReleaseCapture();
TRACE("OnLButtonUp\n");

CView::OnLButtonUp(nFlags, point);
}
可以啊,为什么不行?只要你不ReleaseCapture,鼠标消息是可以给本窗口的啊

步骤一:
SetCapture()
步骤二:
MouseMove()中GetCusorPos(). 获取当前光标相对于屏幕的坐标
步骤三:
ReleaseCapture().

SetCapture
函数功能:该函数在属于当前线程的指定窗口里设置鼠标捕获。一旦窗口捕获了鼠标,所有鼠标输入都针对该窗口,无论光标是否在窗口的边界内。同一时刻只能有一个窗口捕获鼠标。如果鼠标光标在另一个线程创建的窗口上,只有当鼠标键按下时系统才将鼠标输入指向指定的窗口。
函数原型:HWND SetCapture(HWND hwnd);
参数:
hWnd:当前线程里要捕获鼠标的窗口句柄。
返回值:返回值是上次捕获鼠标的窗口句柄。如果不存在那样的句柄,返回值是NULL。
备注:只有前台窗口才能捕获鼠标。如果一个后台窗口想捕获鼠标,则该窗口仅为其光标热点在该窗口可见部份的鼠标事件接收消息。另外,即使前台窗口已捕获了鼠标,用户也可点击该窗口,将其调入前台。当一个窗日不再需要所有的鼠标输入时,创建该窗口的线程应当调用函数ReleaseCapture来释放鼠标。此函数不能被用来捕获另一进程的鼠标输入。
Windows 95:调用SetCaptune会引起失去鼠标捕获的窗口接收一个WM_CAPTURECHANGED消息。
速查:头文件:Winuser.h:输入库:user32.lib。

ReleaseCapture
函数功能:该函数从当前线程中的窗口释放鼠标捕获,并恢复通常的鼠标输入处理。捕获鼠标的窗口接收所有的鼠标输入(无论光标的位置在哪里),除非点击鼠标键时,光标热点在另一个线程的窗口中。
函数原型:BOOL ReleaseCapture(VOlD)
参数:无。
返回值:如果函数调用成功,返回非零值;如果函数调用失败,返回值是零。若想获得更多的错误信息,请调用GetlastError函数。
备注:应用程序在调用函数SetCaPture之后调用此函数。
Windows 95:调用ReleaseCapture会引起失去鼠标捕获的窗日接收一个WM_CAPTURECHANGED消息。
速查:Windows NT:3.1及以上版本;Windows:95及以上版本:Windows CE:1.0及以上版本;头文件:winuser.h;输入库:User32.lib。

2010-11-13 17:42:54

有几种方法实现:
1.创建一个桌面大小的"透明窗体",并且边框设为0。这样窗口坐标就是桌面坐标,在自己程序的消息循环中捕获鼠标消息就行了。QQ、RTX的"屏幕截图"功能就是这样实现的。

2.使用SetWindowsHookEx捕获WH_MOUSE、WH_GETMESSAGE消息。并将SetWindowsHookEx的第四个参数设置为NULL,捕获全局的消息。然后在第二个参数的回调函数中调用CallNextHookEx,以及监听鼠标消息。程序关闭后,别忘记调用UnhookWindowsHookEx。还有就是程序要写在DLL中,因为系统会把它注入到其它进程中去捕获消息的。可以参考网上SetWindowsHookEx实现键盘记录的例子,实现鼠标记录。

3.驱动中Inline Hook Mouclass鼠标类驱动的MouseClassServiceCallback函数,获得鼠标输入。

建议使用1、2中的一种方法。没必要开发驱动,这里只是介绍有几种方法可以获得鼠标全局点击事件。

2010-11-13 13:22:55
您不能回答该问题或者回答已经关闭!

相关文章推荐

  • C#中using指令的几种用法

    using + 命名空间名字,这样可以在程序中直接用命令空间中的类型,而不必指定类型的详细命名空间,类似于Java的import,这个功能也是最常用的,几乎每个cs的程序都会用到

  • C#实例解析适配器设计模式

    将一个类的接口变成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够一起工作

  • 使用托管C++粘合C#和C++代码(二)

    本文实现一下C++代码调用C#代码的过程。我构造一个简单并且直观的例子:通过C++ UI 触发C# UI.

  • C#开发高性能Log Help类设计开发

    项目中要在操作数据库的异常处理中加入写Log日志,对于商业上有要求,写log时对其它操作尽可能影响小,不能因为加入log导致耗时太多

  • Async和Await使异步编程更简单

    C#5.0中async和await两个关键字,这两个关键字简化了异步编程,之所以简化了,还是因为编译器给我们做了更多的工作

  • C#开发中的反射机制

    反射的定义:审查元数据并收集关于它的类型信息的能力。元数据(编译以后的最基本数据单元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等

  • C#运行时相互关系

    C#运行时相互关系,包括运行时类型、对象、线程栈和托管堆之间的相互关系,静态方法、实例方法和虚方法的区别等等

  • C#协变和逆变

    “协变”是指能够使用与原始指定的派生类型相比,派生程度更大的类型,“逆变”则是指能够使用派生程度更小的类型

  • C#基础概念之延迟加载

    延迟加载(lazy load)是Hibernate3关联关系对象默认的加载方式,延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作

  • C#中的索引器的简单理解和用法

    C#中的类成员可以是任意类型,包括数组和集合。当一个类包含了数组和集合成员时,索引器将大大简化对数组或集合成员的存取操作

  • 使用托管C++粘合C#和C++代码(一)

    C#在xml读写,数据库操纵,界面构造等很多方面性能卓越;C++的效率高,是底层开发的必备武器

  • 深入C# 序列化(Serialize)、反序列化(Deserialize)

    C#中的序列化和反序列化,序列化是.NET运行时环境用来支持用户定义类型的流化的机制