GUI开发-如何捕获窗口外面的鼠标点击事件?

GUI开发-如何捕获窗口外面的鼠标点击事件?

晚风撩人 发布于 2017-03-11 字数 92 浏览 1287 回复 4

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

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

偏爱自由 2017-06-02 4 楼

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

CView::OnLButtonDown(nFlags, point);
}

int g_nValue = 0 ;

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

CView::OnMouseMove(nFlags, point);
}

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

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。

浮生未歇 2017-04-26 3 楼

提供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);
}

夜无邪 2017-04-20 2 楼

全局的鼠标抓获有两种方式

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;
}
灵芸 2017-03-19 1 楼

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

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

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

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