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:
- Um die Referenz auf das Singleton-Objekt zurückzugeben, durch das der Schlitz mit dem Mausereignissignal verbunden war.
- 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.