Qt之Hook(键盘钩子)的简单使用(挂接截图程序,含源码+注释)

一、后台钩子截图调用示例

二、钩子的个人理解

  1. 挂接钩子的步骤:SetWindowsHookEx -> UnhookWindowsHookEx,直接用SetWindowsHookEx 函数挂接到对应的钩子类型和处理函数中;当钩子使用完后需要调用UnhookWindowsHookEx函数卸载(因为钩子消耗系统性能)。
    SetWindowsHookEx 函数原型如下:
    //! int idHook 所监控的挂钩类型
    //! HOOKPROC lpfn 监控信息的处理函数
    //! HINSTANCEhMod 监控信息的动态链接位置 nullptr则与本线程相关
    //! DWORD dwThreadId 挂钩线程id 0则代表当前 决定了此钩子是系统钩子还是线程钩子
    //! 返回值 函数执行成功,则返回值为对应的钩子句柄;若此函数执行失败,则返回值为NULL(0)
	HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId);

SetWindowsHookEx 函数原型如下:

	//! hHook 要卸载的钩子句柄
	BOOL UnhookWindowsHookEx(HHOOK hHook);
  1. 各个类型的钩子原型一致,如下:
	/**
	 * @brief Hookproc
	 * @param code 这是一个整数值,用于指定发送到钩子过程的消息类型。它可以是几个值中的一个,例如HC_ACTION、HC_NOREMOVE或HC_CREATE
	 * @param wParam 一个指向宽字符值的指针,其中包含有关发送到钩子过程的消息的附加信息,其值取决于code的值
	 * @param lParam 一个指向长字符值的指针,其中包含有关发送到钩子过程的消息的附加信息,其值取决于code的值
	 * @return 如果返回0,则消息未被处理,将继续由其他钩子或目标窗口处理。如果返回非零值,则消息已被钩子过程处理,不会被其他钩子或目标窗口处理
	 */
	LRESULT Hookproc(int code, WPARAM wParam, LPARAM lParam)
  1. 不同的钩子对应的数据结构体及参数含义不同,如当关联键盘钩子(WH_KEYBOARD_LL)时,其lParam参数代表的结构体为KBDLLHOOKSTRUCT;当关联鼠标钩子(WH_MOUSE_LL)时,其wParam代表鼠标操作的类型(如左键按下、放开等),lParam参数代表的结构体为MSLLHOOKSTRUCT。具体可按需求查看对应内容。
  2. 推荐的链接:官方链接、钩子(HOOK)函数教程

三、源码

CHook.h

#ifndef CHOOK_H
#define CHOOK_H

// 干净的钩子类
class CHook
{
public:
    explicit CHook();
    ~CHook();
};

#endif // CHOOK_H

CHook.cpp

#include "CHook.h"

#include "CMainWindow.h"

#include 
#include 

// 引用全局变量
extern CMainWindow *g_mainWdindow;

HHOOK g_hook; // 钩子对象
/**
 * @brief Hookproc
 * @param code 这是一个整数值,用于指定发送到钩子过程的消息类型。它可以是几个值中的一个,例如HC_ACTION、HC_NOREMOVE或HC_CREATE
 * @param wParam 一个指向宽字符值的指针,其中包含有关发送到钩子过程的消息的附加信息,其值取决于code的值
 * @param lParam 一个指向长字符值的指针,其中包含有关发送到钩子过程的消息的附加信息,其值取决于code的值
 * @return 如果返回0,则消息未被处理,将继续由其他钩子或目标窗口处理。如果返回非零值,则消息已被钩子过程处理,不会被其他钩子或目标窗口处理
 */
LRESULT Hookproc(int code, WPARAM wParam, LPARAM lParam)
{
    // lParam强转为键盘数据结构体
    KBDLLHOOKSTRUCT *data = (KBDLLHOOKSTRUCT *)lParam;
    //! GetAsyncKeyState
    //! 获取指定按钮状态:非0则为按下状态,为0则为未按下状态
    // 当Ctrl、Alt、X都按下时进入
    if(GetAsyncKeyState(VK_LCONTROL) && GetAsyncKeyState(VK_LMENU) && 0x58 == data->vkCode && g_mainWdindow->screenShotFlag())
    {
        // 调用截图
        g_mainWdindow->startScreenShot();
    }
    return CallNextHookEx(g_hook, code, wParam, lParam);
}

CHook::CHook()
{
    //! SetWindowsHookEx 函数解释
    //! int idHook 所监控的挂钩类型
    //! HOOKPROC lpfn 监控信息的处理函数
    //! HINSTANCEhMod 监控信息的动态链接位置 nullptr则与本线程相关
    //! DWORD dwThreadId 挂钩线程id 0则代表当前 决定了此钩子是系统钩子还是线程钩子
    //! 返回值 函数执行成功,则返回值就是该挂钩处理过程的句柄;若此函数执行失败,则返回值为NULL(0)
    g_hook = SetWindowsHookEx(WH_KEYBOARD_LL, Hookproc, nullptr, 0);
}

CHook::~CHook()
{
    // 卸载钩子
    UnhookWindowsHookEx(g_hook);
}

main.cpp

#include "CMainWindow.h"
#include 

#include "CHook.h"

CMainWindow *g_mainWdindow;

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    // 创建钩子对象
    CHook hook;
    // 创建程序对象
    g_mainWdindow = new CMainWindow;
    // 初始化程序
    g_mainWdindow->initialize();
    int ret = a.exec();
    // 反初始化
    g_mainWdindow->uninitialize();
    delete g_mainWdindow;
    return ret;
}

总结

使用钩子时注意数据的类型及参数的含义,不同的钩子其参数及含义不同需要好好记一下;包括钩子可以封装在库中或子线程中调用,该部分文中没有体现,值得研究一下。

相关文章

Qt之QGraphicsView实现截图(漏洞百出且BUG丛生版,部分源码+注释)

友情提示——哪里看不懂可私哦,让我们一起互相进步吧
(创作不易,请留下一个免费的赞叭 谢谢 o/)

注:文章为作者编程过程中所遇到的问题和总结,内容仅供参考,若有错误欢迎指出。
注:如有侵权,请联系作者删除

你可能感兴趣的:(qt,计算机外设,开发语言)