1、前言
想要在窗口失去焦点的情况下获取鼠标和键盘消息,需要用到钩子技术,API函数为:SetWindowsHookEx()。而且必须是全局钩子,全局钩子需要使用DLL注入。即首先生成一个带有全局钩子的DLL,DLL获取鼠标位置和键盘按键消息再发送给QT主程序。
2、全局钩子DLL
// myHookMouseAndKeybord.cpp : 定义 DLL 应用程序的导出函数。
//
#include <windows.h>
#include "stdafx.h"
//HINSTANCE g_hInstance;
HHOOK g_hMouseHook;
HHOOK g_hKeybordHook;
HWND g_hMainWND;
//安装鼠标钩子(要生成lib文件需要加上extern "C" __declspec(dllexport) )
extern "C" __declspec(dllexport) BOOL InstallMouseHook(HWND hWnd);
//卸载鼠标钩子
extern "C" __declspec(dllexport) BOOL UnInstallMouseHook();
//安装键盘钩子
extern "C" __declspec(dllexport) BOOL InstallKeybordHook();
//卸载键盘钩子
extern "C" __declspec(dllexport) BOOL UnInstallKeybordHook();
//鼠标钩子处理函数声明
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam);
//键盘钩子处理函数声明
LRESULT CALLBACK keyBordProc(int nCode, WPARAM wParam, LPARAM lParam);
//安装鼠标钩子
BOOL InstallMouseHook(HWND hWnd)
{
g_hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, GetModuleHandle(L"myHookMouseAndKeybord"), 0);
g_hMainWND = hWnd;
if (g_hMouseHook != NULL)
{
return TRUE;
}
else
{
return FALSE;
}
}
//卸载鼠标钩子
BOOL UnInstallMouseHook()
{
return UnhookWindowsHookEx(g_hMouseHook);
}
//安装键盘钩子
BOOL InstallKeybordHook()
{
g_hKeybordHook = SetWindowsHookEx(WH_KEYBOARD_LL, keyBordProc, GetModuleHandle(L"myHookMouseAndKeybord"), 0);
if (g_hKeybordHook != NULL)
{
return TRUE;
}
else
{
return FALSE;
}
}
//卸载键盘钩子
BOOL UnInstallKeybordHook()
{
return UnhookWindowsHookEx(g_hKeybordHook);
}
//鼠标钩子处理函数
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (wParam == WM_RBUTTONDOWN) //当鼠标点击右键时发送信息给QT主窗口
{
MOUSEHOOKSTRUCT *mhookstruct; //鼠标HOOK结构体
mhookstruct = (MOUSEHOOKSTRUCT*)lParam;
POINT pt = mhookstruct->pt; //将当前鼠标坐标点的x,y坐标作为参数向主程序窗口发送消息
PostMessage(g_hMainWND, WM_RBUTTONDOWN, MK_CONTROL, MAKELPARAM(pt.x, pt.y));
}
return CallNextHookEx(g_hMouseHook, nCode, wParam, lParam);
}
//键盘钩子处理函数
LRESULT CALLBACK keyBordProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (wParam == WM_KEYDOWN)
{
tagKBDLLHOOKSTRUCT *keyhookstruct; //键盘HOOK结构体
keyhookstruct = (tagKBDLLHOOKSTRUCT*)lParam;
PostMessage(g_hMainWND, WM_KEYDOWN, keyhookstruct->vkCode, keyhookstruct->scanCode);
}
return CallNextHookEx(g_hKeybordHook, nCode, wParam, lParam);
}
3、发送鼠标键盘消息
上面代码已经贴出来了,就在钩子处理函数中。鼠标发送的是位置信息,键盘发送的是键码
4、QT窗口接收信息
QT要接收消息,需要在QApplication中安装QAbstractNativeEventFilter,
#include "LOLdesk.h"
#include <QtWidgets/QApplication>
#include <QAbstractNativeEventFilter>
#include <QDebug>
class MyAppNativeEventFilter : public QAbstractNativeEventFilter
{
virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *longMsg) override
{
if (eventType == "windows_generic_MSG" || eventType == "windows_dispatcher_MSG")
{
MSG* pMsg = reinterpret_cast<MSG*>(message);
if (pMsg->message == WM_RBUTTONDOWN)
{
POINT pt = pMsg->pt;
qDebug() << "x="<<pt.x << "y=" << pt.y;
}
if (pMsg->message == WM_KEYDOWN)
{
qDebug() << pMsg->wParam;
}
}
return false; // 注意返回值
};
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
LOLdesk w;
MyAppNativeEventFilter filter;
a.installNativeEventFilter(&filter); //在APP上安装EventFilter
w.show();
return a.exec();
}
5、调用DLL钩子
//链接lib文件
#pragma comment(lib, "myHookMouseAndKeybord.lib")
//安装鼠标钩子声明
extern "C" __declspec(dllimport) BOOL InstallMouseHook(HWND hWnd);
//卸载鼠标钩子声明
extern "C" __declspec(dllimport) BOOL UnInstallMouseHook();
//安装键盘钩子
extern "C" __declspec(dllimport) BOOL InstallKeybordHook();
//卸载键盘钩子
extern "C" __declspec(dllimport) BOOL UnInstallKeybordHook();
//安装钩子
BOOL LOLdesk::installHook()
{
HMODULE hDll = NULL;
HWND m_hWnd = (HWND)this->winId();
BOOL hookMouseState = InstallMouseHook(m_hWnd);
BOOL hookKeybordState = InstallKeybordHook();
if (!hookMouseState && !hookKeybordState)
{
qDebug() << "hook failed!";
}
else
{
qDebug() << "hook success!";
}
return 0;
}
//卸载钩子
BOOL LOLdesk::uninstallHook()
{
BOOL hookMouseState = UnInstallMouseHook();
BOOL hookKeybordState = UnInstallKeybordHook();
if (!hookMouseState && !hookKeybordState)
{
qDebug() << "unhook failed!";
}
else
{
qDebug() << "unhook success!";
}
return 0;
}