Qt/C++全局键盘和鼠标事件监控工具

科技   2024-11-09 22:47   福建  

技术背景

在Qt/C++环境下开发全局键盘和鼠标事件监控工具,可以实现对系统范围内键盘和鼠标事件的捕获和处理。这种工具在多种应用场景下都非常有用,例如自动化测试、用户行为分析、游戏控制等。Qt C++ 是一个跨平台的应用程序开发框架,提供了丰富的类库和工具,使得开发者可以高效地创建图形用户界面(GUI)以及实现各种功能。

关键技术点

  1. 全局钩子

  • 在Windows环境下,可以使用Windows API(如SetWindowsHookEx)来实现全局键盘和鼠标钩子。这些钩子能够捕获系统中的键盘和鼠标事件。
  • 在Linux环境下,可以使用X11库来实现全局键盘和鼠标事件监控。
  • Qt信号槽机制

    • Qt的信号槽机制是一种用于对象间通信的机制。在捕获到键盘和鼠标事件后,可以通过信号槽机制将这些事件信息传递给Qt应用程序的主界面或其他组件进行处理。
  • 事件处理函数

    • 在Qt中,可以通过重写QWidget或QMainWindow的鼠标和键盘事件处理函数(如mousePressEventkeyPressEvent等)来处理这些事件。
    • 另一种方式是使用事件过滤器,通过安装事件过滤器可以在多个组件中处理事件。

    示例代码

    以下是一个基于Qt/C++的全局键盘和鼠标事件监控工具的示例代码。这个示例展示了如何使用Windows API和Qt信号槽机制来实现全局键盘和鼠标事件的捕获和处理。

    // mhook.h
    #ifndef MHOOK_H
    #define MHOOK_H

    #include <Windows.h>
    #include <QObject>
    #include <QDebug>

    class MyHook : public QObject {
        Q_OBJECT
    public:
        enum Mode {
            eNull = 0// 空模式,不捕获
            eKey = 1,  // 键盘钩子模式
            eMouse = 2,// 鼠标钩子模式
            eMouseKey = 3 // 键盘和鼠标钩子模式
        };

        static MyHook* instance()// 单例模式:获得唯一实例
        void installHook(Mode model);
        void unInstallHook(Mode model);

    signals:
        void keyEventReceived(int vkCode)// 键盘事件信号
        void mouseEventReceived(int x, int y, QString button)// 鼠标事件信号,增加按钮信息

    private:
        MyHook(); // 私有构造函数
        LRESULT CALLBACK keyProc(int nCode, WPARAM wParam, LPARAM lParam);
        LRESULT CALLBACK mouseProc(int nCode, WPARAM wParam, LPARAM lParam);
        static MyHook* hookClass;
        static HHOOK keyHook, mouseHook;
    };

    #endif // MHOOK_H
    // mhook.cpp
    #include "mhook.h"

    static MyHook* hookClass = nullptr;
    static HHOOK keyHook = nullptr, mouseHook = nullptr;

    MyHook* MyHook::instance() {
        if (!hookClass) {
            hookClass = new MyHook();
        }
        return hookClass;
    }

    void MyHook::installHook(Mode model) {
        if (model == eKey) {
            keyHook = SetWindowsHookEx(WH_KEYBOARD_LL, keyProc, GetModuleHandle(nullptr), 0);
        } else if (model == eMouse) {
            mouseHook = SetWindowsHookEx(WH_MOUSE_LL, mouseProc, GetModuleHandle(nullptr), 0);
        }
    }

    void MyHook::unInstallHook(Mode model) {
        if (model == eKey) {
            UnhookWindowsHookEx(keyHook);
        } else if (model == eMouse) {
            UnhookWindowsHookEx(mouseHook);
        }
    }

    LRESULT CALLBACK MyHook::keyProc(int nCode, WPARAM wParam, LPARAM lParam) {
        if (!hookClass) return CallNextHookEx(keyHook, nCode, wParam, lParam);
        if (wParam == WM_KEYDOWN) {
            KBDLLHOOKSTRUCT* pkbhs = (KBDLLHOOKSTRUCT*)lParam;
            emit hookClass->keyEventReceived(pkbhs->vkCode);
        }
        return CallNextHookEx(keyHook, nCode, wParam, lParam);
    }

    LRESULT CALLBACK MyHook::mouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
        if (!hookClass) return CallNextHookEx(mouseHook, nCode, wParam, lParam);
        MOUSEHOOKSTRUCT* mhookstruct = (MOUSEHOOKSTRUCT*)lParam;
        POINT pt = mhookstruct->pt;
        QString button;
        if (wParam == WM_LBUTTONDOWN) button = "左键";
        else if (wParam == WM_RBUTTONDOWN) button = "右键";
        else if (wParam == WM_MBUTTONDOWN) button = "中键";
        emit hookClass->mouseEventReceived(pt.x, pt.y, button);
        return CallNextHookEx(mouseHook, nCode, wParam, lParam);
    }
    // mainwindow.h
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H

    #include <QMainWindow>
    #include <QTextEdit>
    #include "mhook.h"

    namespace Ui {
    class MainWindow;
    }

    class MainWindow : public QMainWindow {
        Q_OBJECT

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

    private slots:
        void handleKeyEvent(int vkCode);
        void handleMouseEvent(int x, int y, QString button);

    private:
        Ui::MainWindow *ui;
        QTextEdit *textEdit;
        MyHook *myHook;
    };

    #endif // MAINWINDOW_H
    // mainwindow.cpp
    #include "mainwindow.h"
    #include "ui_mainwindow.h"

    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow),
        textEdit(new QTextEdit(this)),
        myHook(MyHook::instance())
    {
        ui->setupUi(this);
        setCentralWidget(textEdit);

        connect(myHook, &MyHook::keyEventReceived, this, &MainWindow::handleKeyEvent);
        connect(myHook, &MyHook::mouseEventReceived, this, &MainWindow::handleMouseEvent);

        myHook->installHook(MyHook::eMouseKey);
    }

    MainWindow::~MainWindow() {
        myHook->unInstallHook(MyHook::eMouseKey);
        delete ui;
    }

    void MainWindow::handleKeyEvent(int vkCode) {
        textEdit->append("键盘按键: " + QString::number(vkCode));
    }

    void MainWindow::handleMouseEvent(int x, int y, QString button) {
        textEdit->append("鼠标事件: 位置(" + QString::number(x) + ", " + QString::number(y) + "), 按钮: " + button);
    }
    // main.cpp
    #include "mainwindow.h"
    #include <QApplication>

    int main(int argc, char *argv[]) {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
        return a.exec();
    }

    结论

    通过上述示例代码,我们展示了如何在Qt/C++环境下开发一个全局键盘和鼠标事件监控工具。该工具利用了Windows API实现全局钩子捕获键盘和鼠标事件,并通过Qt信号槽机制将这些事件信息传递给Qt应用程序的主界面进行处理。这种工具在多种应用场景下都非常有用,可以为开发者提供强大的事件监控和处理能力。


    Qt教程
    致力于Qt教程,Qt技术交流,研发
     最新文章