Qt上hook钩子的使用,监测键盘和鼠标。

发布于:2025-04-13 ⋅ 阅读:(39) ⋅ 点赞:(0)

演示平台:windows。
编译环境:Qt5.12.2 MinGW 64-bit
Windows API

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

///SetWindowsHookExW的回调函数
 /**
 * @brief Hookproc
 * @param code 这是一个整数值,用于指定发送到钩子过程的消息类型。它可以是几个值中的一个,例如HC_ACTION、HC_NOREMOVE或HC_CREATE
 * @param wParam 一个指向宽字符值的指针,其中包含有关发送到钩子过程的消息的附加信息,其值取决于code的值
 * @param lParam 一个指向长字符值的指针,其中包含有关发送到钩子过程的消息的附加信息,其值取决于code的值
 * @return 如果返回0,则消息未被处理,将继续由其他钩子或目标窗口处理。如果返回非零值,则消息已被钩子过程处理,不会被其他钩子或目标窗口处理
 */
LRESULT Hookproc2(int code, WPARAM wParam, LPARAM lParam)

// 卸载钩子
WINUSERAPI WINBOOL WINAPI UnhookWindowsHookEx (HHOOK hhk);

WH_KEYBOARD_LL:键盘监测
WH_MOUSE_LL:鼠标检测
示例
请添加图片描述
代码
chook.h

#ifndef CHOOK_H
#define CHOOK_H

class Widget;
class CHook
{
public:
    CHook(Widget* w);
    ~CHook();
};

#endif // CHOOK_H

chook.cpp

#include "chook.h"
#include <windows.h>
#include "widget.h"
#include <QDebug>

Widget* g_w;
HHOOK g_hook1;  // 钩子对象
HHOOK g_hook2; // 钩子对象

/**
 * @brief Hookproc
 * @param code 这是一个整数值,用于指定发送到钩子过程的消息类型。它可以是几个值中的一个,例如HC_ACTION、HC_NOREMOVE或HC_CREATE
 * @param wParam 一个指向宽字符值的指针,其中包含有关发送到钩子过程的消息的附加信息,其值取决于code的值
 * @param lParam 一个指向长字符值的指针,其中包含有关发送到钩子过程的消息的附加信息,其值取决于code的值
 * @return 如果返回0,则消息未被处理,将继续由其他钩子或目标窗口处理。如果返回非零值,则消息已被钩子过程处理,不会被其他钩子或目标窗口处理
 */
LRESULT Hookproc1(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_w->setText("组合按钮按下:Ctrl+Alt+x");
    }
    else if(GetAsyncKeyState(VK_LCONTROL) && 0x5a == data->vkCode)
    {
        g_w->setText("组合按钮按下:Ctrl+z");
    }
    else{
        QString txt;
        if (data->flags == 128 || data->flags == 129)
        {
            // 监控按键状态
            if (code >= 0)
            {
                switch (wParam)
                {
                case WM_KEYDOWN:
                    txt = "普通按键抬起" + QString::number(data->vkCode);
                    break;
                case WM_KEYUP:
                    txt = "普通按鍵按下" + QString::number(data->vkCode);
                    break;
                case WM_SYSKEYDOWN:
                    txt = "系统按键抬起" + QString::number(data->vkCode);
                    break;
                case WM_SYSKEYUP:
                    txt = "系统按键按下" + QString::number(data->vkCode);
                    break;
                }
            }

            // 监控键盘,并判断键
            switch (data->vkCode)
            {
            case VK_F1:
                txt = "检测到按键:F1";
                break;
            case VK_LCONTROL:
                txt = "检测到按键:Ctrl";
                break;
            case VK_LMENU:
                txt = "检测到按键:Alt";
                break;
            case VK_RETURN:
                txt = "检测到按键:Enter";
                break;
            case VK_RSHIFT:
            case VK_LSHIFT:
                txt = "检测到按键:Shift";
                break;
            case VK_BACK:
                txt =  "检测到按键:Backspace";
                break;
            case VK_SPACE:
                txt =  "检测到按键:Space";
                break;
            }
            g_w->setText(txt);
        }
    }

    return CallNextHookEx(g_hook1, code, wParam, lParam);
}

LRESULT Hookproc2(int code, WPARAM wParam, LPARAM lParam)
{
    MSLLHOOKSTRUCT* data = (MSLLHOOKSTRUCT* )lParam;
    POINT   pt = data->pt;
    DWORD   mouseData = data->time;

    const char* info = NULL;
    char text[60], pData[50], mData[50];

    if (code >= 0)
    {
        if (wParam == WM_MOUSEMOVE)
        {
            info = "鼠标 [移动]";
        }
        else if (wParam == WM_LBUTTONDOWN)
        {
            info = "鼠标 [左键] 按下";
        }
        else if (wParam == WM_LBUTTONUP)
        {
            info = "鼠标 [左键] 抬起";
        }
        else if (wParam == WM_LBUTTONDBLCLK)
        {
            info = "鼠标 [左键] 双击";
        }
        else if (wParam == WM_RBUTTONDOWN)
        {
            info = "鼠标 [右键] 按下";
        }
        else if (wParam == WM_RBUTTONUP)
        {
            info = "鼠标 [右键] 抬起";
        }
        else if (wParam == WM_RBUTTONDBLCLK)
        {
            info = "鼠标 [右键] 双击";
        }
        else if (wParam == WM_MBUTTONDOWN)
        {
            info = "鼠标 [滚轮] 按下";
        }
        else if (wParam == WM_MBUTTONUP)
        {
            info = "鼠标 [滚轮] 抬起";
        }
        else if (wParam == WM_MBUTTONDBLCLK)
        {
            info = "鼠标 [滚轮] 双击";
        }
        else if (wParam == WM_MOUSEWHEEL)
        {
            info = "鼠标 [滚轮] 滚动";
        }

        ZeroMemory(text, sizeof(text));
        ZeroMemory(pData, sizeof(pData));
        ZeroMemory(mData, sizeof(mData));

        QString txt = QString("鼠标状态:%1,X:%2,Y:%3,附加数据:%4").arg(info).arg(pt.x).arg(pt.y).arg(mouseData);
        g_w->setText(txt);
    }
    return CallNextHookEx(g_hook2, code, wParam, lParam);
}

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

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


widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "chook.h"
namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

    void setText(QString txt);
private:
    Ui::Widget *ui;
};

#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QScrollBar>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->textEdit->setReadOnly(true);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::setText(QString txt)
{
    ui->textEdit->append(txt);
    ui->textEdit->verticalScrollBar()->setValue(ui->textEdit->verticalScrollBar()->maximum());
}

main.cpp

#include "widget.h"
#include <QApplication>
#include "chook.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    CHook hook(&w);
    w.show();

    return a.exec();
}


网站公告

今日签到

点亮在社区的每一天
去签到