当前位置: 首页 > news >正文

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

演示平台: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();
}

相关文章:

  • Crow介绍及使用
  • 一文了解亿级数据检索:RedisSearch
  • OpenBMC:BmcWeb 处理http请求5 检查权限
  • C#核心学习(十二)面向对象--多态(1)virtual override和base三剑客
  • CExercise_07_1指针和数组_5检查一个整数数组是否是回文,即正序与倒序相同
  • 【C#知识点详解】LinkedList<T>储存结构详解
  • Spring Boot接口返回Long类型的数据时丢失精度的全局处理
  • LCR 131. 砍竹子 I
  • 什么是混合搜索Hybrid Search?
  • Python 小练习系列 | Vol.14:掌握偏函数 partial,用函数更丝滑!
  • 和DeepSeek聊高速公路定向广播
  • NO.79十六届蓝桥杯备战|数据结构-扩展域并查集-带权并查集|团伙|食物链|银河英雄传说(C++)
  • CesiumEarth v1.12 更新,支持安卓平板离线浏览3DTiles格式的三维倾斜模型
  • 【计网】作业4
  • 树和图论(详细整理,简单易懂!)
  • AutoGLM沉思使用方式
  • 【已完结STM32】--自学江协科技笔记汇总
  • WHAT - React 元素接收的 ref 详解
  • 最新Spring Security实战教程(九)前后端分离认证实战 - JWT+SpringSecurity无缝整合
  • 进程间通信-共享内存
  • 西安短视频拍摄制作公司/网站整站优化公司
  • 公司网站建设小江/alexa
  • 做网站建设价格/今天的头条新闻
  • 新手建站广告联盟赚钱/亚马逊seo推广
  • 百度电脑版/安卓手机游戏优化器
  • 需要网站建设/网络软文