Evgenii Legotckoi
Evgenii Legotckoi13. Juni 2016 13:35

Qt WinAPI - Lektion 009. SetWindowsHookEx - Mausereignisse über WinAPI protokollieren

Die WinAPI-Funktionalität ermöglicht es Ihnen, Systemereignisse wie Mausbewegungen und Klicks auf niedriger Ebene mithilfe von Hooks zu verfolgen. Diese Funktionalität funktioniert auf der Grundlage von Rückruffunktionen. Wenn Sie also OOP und das Signale und Slots -System verwenden möchten, müssen Sie eines davon übergeben die Methoden als [Callback]-Funktion (https://evileg.com/ru/post/89/) in die Callback-Registrierungsfunktion im Windows-System. Aber die Methode muss statisch sein, also muss die Klasse als Singleton entworfen werden.

SetWindowsHookEx

Diese Funktion wird verwendet, um eine Event-Handler-Funktion in einer Kette von Hooks zu registrieren, um bestimmte Ereignisse im Windows-System zu verfolgen.

HHOOK WINAPI SetWindowsHookEx(
  _In_ int       idHook,
  _In_ HOOKPROC  lpfn,
  _In_ HINSTANCE hMod,
  _In_ DWORD     dwThreadId
);

Parameter

idHook [in]

Typ: int

Der festgelegte Hook-Typ. Der Parameter kann die folgenden Werte annehmen.

  • WH_CALLWNDPROC - Installiert eine Hook-Prozedur, die auf Nachrichten wartet, bevor das System sie zur Verarbeitung an das Zielfenster weiterleitet.
  • WH_CALLWNDPROCRET - Installiert eine Hook-Prozedur, die Nachrichten verfolgt, nachdem sie vom Zielfenster verarbeitet wurden.
  • WH_CBT - Installiert eine Hook-Prozedur, die nützliche Benachrichtigungen für die Anwendung empfängt.
  • WH_DEBUG - Installiert eine Hook-Prozedur, die beim Debuggen anderer Hook-Prozeduren nützlich ist.
  • WH_FOREGROUNDIDLE - Legt die Hook-Prozedur fest, die aufgerufen werden soll, wenn die Anwendung im Leerlauf ist. Kann nützlich sein, um Aufgaben mit niedriger Priorität im Leerlauf auszuführen.
  • WH_GETMESSAGE - Installiert eine Hook-Prozedur, die Nachrichten steuert, die an die Nachrichtenwarteschlange gesendet werden.
  • WH_JOURNALPLAYBACK - Installiert eine Hook-Prozedur, die zuvor mit der WH_JOURNALRECORD-Prozedur aufgezeichnete Nachrichten aufruft.
  • WH_JOURNALRECORD - Installiert eine Hook-Prozedur, die Eingabenachrichten protokolliert, die an die Systemnachrichtenwarteschlange gesendet werden. Dieser Hook ist nützlich zum Aufzeichnen von Makros.
  • WH_KEYBOARD - installiert eine Hook-Prozedur, die auf Tastenanschläge wartet.
  • WH_KEYBOARD_LL - installiert eine Hook-Prozedur, die Tastaturereignisse auf niedriger Ebene steuert.
  • WH_MOUSE - installiert eine Hook-Prozedur, die auf Mausereignisse lauscht.
  • WH_MOUSE_LL - installiert eine Hook-Prozedur, die auf niedriger Ebene auf Mausereignisse lauscht.
  • WH_MSGFILTER - Installiert eine Hook-Prozedur, die Nachrichten steuert, die als Ergebnis eines Eingabeereignisses in einem Dialogfeld, einem Nachrichtenfeld, einem Menü oder einer Bildlaufleiste generiert werden.
  • WH_SHELL - Installiert eine Hook-Prozedur, die Benachrichtigungen empfängt, die für Shell-Anwendungen nützlich sind.
  • WH_SYSMSGFILTER - Installiert eine Hook-Prozedur, die Nachrichten steuert, die als Ergebnis eines Eingabeereignisses in einem Dialogfeld, einem Nachrichtenfeld, einem Menü oder einer Bildlaufleiste generiert werden. Die Hook-Prozedur überwacht diese Nachrichten für alle Anwendungen auf demselben Desktop wie der aufrufende Thread.

lpfn [in]

Typ: HAKENPROZ

Zeiger auf eine Hook-Prozedur. Wenn der dwThreadId -Parameter Null ist oder die ID eines Threads angibt, der von einem anderen Prozess erstellt wurde, muss der lpfn -Parameter auf eine Hook-Prozedur in der DLL zeigen. Andernfalls kann lpfn auf eine Hook-Prozedur im Code zeigen, der dem aktuellen Prozess zugeordnet ist.

hMod [in]

Typ: HINWEIS

Handle auf die DLL, die die Hook-Prozedur enthält, auf die der lpfn-Parameter zeigt. Der hMod -Parameter muss auf NULL gesetzt werden, wenn der dwThreadId -Parameter einen Thread angibt, der vom aktuellen Prozess erstellt wurde, und wenn die Hook-Prozedur innerhalb des zugeordneten Codes ist mit dem aktuellen Prozess.

dwThreadId [in]

Typ: DWORD

Die ID des Threads, dem die Hook-Prozedur zugeordnet werden soll. Wenn dieser Parameter für Desktop-Anwendungen Null ist, wird die Hook-Prozedur allen vorhandenen Threads zugeordnet, die auf demselben Desktop wie der aufrufende Thread ausgeführt werden. Informationen zu Windows Store-Apps finden Sie unter Hinweise.

Rückgabewert

Typ: * HHOOK *

Wenn die Funktion erfolgreich ist, ist der Rückgabewert gleich dem Hook-Handler. Andernfalls wird NULL zurückgegeben. Rufen Sie für weitere Informationen zu dem Fehler GetLastError. auf.

Projektstruktur

Nach einem kurzen Blick auf die Funktion, mit der wir den Hook installieren, werfen wir einen Blick auf die Projektstruktur, die zeigt, wie die Funktion mit der Mausverfolgung verbunden wird.

  • MouseHook.pro - Projektprofil;
  • main.cpp - Datei mit main-Funktion;
  • mouselogger.h - Klassenheaderdatei zur Überwachung von Mausereignissen im System;
  • mouselogger.cpp - Quellcodedatei zum Verfolgen von Mausereignissen im System.

MouseHook.pro

Das Profil wird standardmäßig erstellt.

QT += core
QT -= gui

CONFIG += c++11

TARGET = MouseHook
CONFIG += console
CONFIG -= app_bundle

TEMPLATE = app

SOURCES += main.cpp \
    mouselogger.cpp

HEADERS += \
    mouselogger.h

main.cpp

Um zu demonstrieren, wie Signale und Slots funktionieren, zeigen wir in dieser Datei eine Lambda-Funktion, die mit einem Objekt verbunden ist, um Mausereignisse zu protokollieren, aber mit dem "Singleton"-Muster mit einem Objekt verbunden ist.

#include <QCoreApplication>
#include <QDebug>
#include "mouselogger.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QObject::connect(&MouseLogger::instance(), &MouseLogger::mouseEvent,
                     [](){
        qDebug() << "Mouse Event";
    });

    return a.exec();
}

mouselogger.h

Klassenheaderdatei zum Protokollieren von Mausereignismeldungen. In dieser Datei müssen Sie statische Methoden deklarieren:

  1. Um die Referenz auf das Singleton-Objekt zurückzugeben, durch das der Schlitz mit dem Mausereignissignal verbunden war.
  2. Statische Methode mouseProc , die zur Behandlung von Ereignissen verwendet wird.
#ifndef MOUSELOGGER_H
#define MOUSELOGGER_H

#include <QObject>
#include <windows.h>

class MouseLogger : public QObject
{
    Q_OBJECT
    Q_DISABLE_COPY(MouseLogger)
public:
    static MouseLogger &instance();
    explicit MouseLogger(QObject *parent = nullptr);
    virtual ~MouseLogger(){}

    // Статический метод, который будет выступать в качестве
    // callback-функции
    static LRESULT CALLBACK mouseProc(int Code, WPARAM wParam, LPARAM lParam);

signals:
    // Сигнал, который будет сообщать о возникновении события
    void mouseEvent();

public slots:

private:
    // обработчик хука
    HHOOK   mouseHook;
};

#endif // MOUSELOGGER_H

mouselogger.cpp

#include "mouselogger.h"
#include <QDebug>

MouseLogger &MouseLogger::instance()
{
    static MouseLogger _instance;
    return _instance;
}

MouseLogger::MouseLogger(QObject *parent) : QObject(parent)
{
    HINSTANCE hInstance = GetModuleHandle(NULL);

    // Устанавливаем хук
    mouseHook = SetWindowsHookEx(WH_MOUSE_LL, mouseProc, hInstance, 0);
    // Проверяем, что установка хука прошла успешно
    if (mouseHook == NULL) {
        qWarning() << "Mouse Hook failed";
    }
}

LRESULT CALLBACK MouseLogger::mouseProc(int Code, WPARAM wParam, LPARAM lParam)
{
    Q_UNUSED(Code)

    // Получив событие хука, кастуем аргумент lParam
    // к структуре именно хука мыши.
    MOUSEHOOKSTRUCT * pMouseStruct = (MOUSEHOOKSTRUCT *)lParam;

    // Далее проверяем, какое именно событие пришло,
    // если структура не является указателем на nullptr
    if(pMouseStruct != nullptr) {
        switch (wParam) {
        case WM_MOUSEMOVE:
            qDebug() << "WM_MOUSEMOVE";
            break;
        case WM_LBUTTONDOWN:
            qDebug() << "WM_LBUTTONDOWN";
            break;
        case WM_LBUTTONUP:
            qDebug() << "WM_LBUTTONUP";
            break;
        case WM_RBUTTONDOWN:
            qDebug() << "WM_RBUTTONDOWN";
            break;
        case WM_RBUTTONUP:
            qDebug() << "WM_RBUTTONUP";
            break;
        case WM_MBUTTONDOWN:
            qDebug() << "WM_MBUTTONDOWN";
            break;
        case WM_MBUTTONUP:
            qDebug() << "WM_MBUTTONUP";
            break;
        case WM_MOUSEWHEEL:
            qDebug() << "WM_MOUSEWHEEL";
            break;
        default:
            break;
        }
        emit instance().mouseEvent();
    }

    // После чего событие хука необходимо вернуть обратно в цепочку обработчиков
    return CallNextHookEx(NULL, Code, wParam, lParam);
}

Insgesamt

Dadurch wird es möglich, Mausereignisse zu verfolgen, unabhängig davon, ob sich der Mauszeiger im Fokus des Programms befindet, ob die Anwendung über eine grafische Oberfläche verfügt oder sich nicht im Fokus des Programms befindet.

Videoanleitung

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Stabiles Hosting des sozialen Netzwerks EVILEG. Wir empfehlen VDS-Hosting für Django-Projekte.

Magst du es? In sozialen Netzwerken teilen!

Kommentare

Nur autorisierte Benutzer können Kommentare posten.
Bitte Anmelden oder Registrieren
Letzte Kommentare
A
ALO1ZE19. Oktober 2024 08:19
Fb3-Dateileser auf Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь Максимов5. Oktober 2024 07:51
Django – Lektion 064. So schreiben Sie eine Python-Markdown-Erweiterung Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas55. Juli 2024 11:02
QML - Lektion 016. SQLite-Datenbank und das Arbeiten damit in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssr8. Februar 2024 18:43
Qt Linux - Lektion 001. Autorun Qt-Anwendung unter Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lektion 007. Arbeiten mit ICMP-Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
Jetzt im Forum diskutieren
J
JacobFib17. Oktober 2024 03:27
добавить qlineseries в функции Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты https://topdecorpro.ru…
JW
Jhon Wick1. Oktober 2024 15:52
Indian Food Restaurant In Columbus OH| Layla’s Kitchen Indian Restaurant If you're looking for a truly authentic https://www.laylaskitchenrestaurantohio.com/ , Layla’s Kitchen Indian Restaurant is your go-to destination. Located at 6152 Cleveland Ave, Colu…
КГ
Кирилл Гусарев27. September 2024 09:09
Не запускается программа на Qt: точка входа в процедуру не найдена в библиотеке DLL Написал программу на C++ Qt в Qt Creator, сбилдил Release с помощью MinGW 64-bit, бинарнику напихал dll-ки с помощью windeployqt.exe. При попытке запуска моей сбилженной программы выдаёт три оши…
F
Fynjy22. Juli 2024 04:15
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

Folgen Sie uns in sozialen Netzwerken