Evgenii Legotckoi
Evgenii LegotckoiМаусым 13, 2016, 1:35 Т.Қ.

Qt WinAPI - Сабақ 009. SetWindowsHookEx - WinAPI арқылы тінтуір оқиғаларын тіркеу

Функционал WinAPI позволяет на низком уровне с помощью хуков отслеживать события системы, такие как движение и клики мыши. Данный функционал работает на основе функций callback, поэтому если хочется использовать ООП и систему сигналов и слотов , то нужно будет один из методов передавать в качестве функции callback в функцию по регистрации callback в системе Windows. Но метод должен быть статическим, поэтому требуется разрабатывать класс в качестве Синглтона.

SetWindowsHookEx

Данная функция используется для регистрации функции-обработчика событий в цепочке hook-обработчиков для отслеживания некоторых событий в системе Windows

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

Параметры

idHook [in]

Тип: int

Тип хука, который был установлен. Параметр может принимать следующие значения.

  • WH_CALLWNDPROC - Устанавливает hook процедуру, которая отслеживает сообщения до того, как система перешлёт их в обработку окну назначения.
  • WH_CALLWNDPROCRET - Устанавливает hook процедуру, которая отслеживает сообщения после того, как они были обработаны окном назначения.
  • WH_CBT - Устанавливает hook процедуру, которая принимает полезные уведомления для прикладной программы.
  • WH_DEBUG - устанавливает hook процедуру, которая полезна при отладке других hook процедур.
  • WH_FOREGROUNDIDLE -  Устанавливает hook процедуру, которая будет вызываться в том случае, когда приложение простаивает. Может быть полезно для выполнения задач с низким приоритетом во время простоя.
  • WH_GETMESSAGE - устанавливает hook процедуру, которая контролирует сообщения, отправленные в очередь сообщений.
  • WH_JOURNALPLAYBACK - устанавливает hook процедуру, вызывающую сообщения, ранее записанные с помощью процедуры WH_JOURNALRECORD.
  • WH_JOURNALRECORD - устанавливает hook процедуру, которая записывает входные сообщения, отправленные в системную очередь сообщений. Данный hook полезен для записи макросов.
  • WH_KEYBOARD - устанавливает hook процедуру, которая отслеживает нажатия клавиш.
  • WH_KEYBOARD_LL - устанавливает hook процедуру, которая контролирует события клавиатуры на низком уровне.
  • WH_MOUSE - устанавливает hook процедуру, которая отслеживает события мыши.
  • WH_MOUSE_LL - устанавливает hook процедуру, которая отслеживает события мыши на низком уровне.
  • WH_MSGFILTER - устанавливает hook процедуру, которая контролирует сообщения, сгенерированные в результате события ввода в диалоговом окне, окне сообщений, меню или полосы прокрутки.
  • WH_SHELL - устанавливает hook процедуру, которая получает уведомления, полезные для приложений оболочки.
  • WH_SYSMSGFILTER - устанавливает hook процедуру, которая контролирует сообщения, сгенерированные в результате события ввода в диалоговом окне, окне сообщений, меню или полосы прокрутки. Подключаемая процедура контролирует эти сообщения для всех приложений в том же рабочем столе, что и вызывающий поток.

lpfn [in]

Тип: HOOKPROC

Указатель на hook процедуру. Если dwThreadId параметр равен нулю или определяет идентификатор треда, созданного другим процессом, параметр lpfn должен указывать на подключаемую процедуру в DLL. В противном случае lpfn может указывать на подключаемую процедуру в коде, связанном с текущим процессом.

hMod [in]

Тип: HINSTANCE

Дескриптор библиотеки DLL, содержащей процедуру hook, на который указывает параметр lpfn. Параметр hMod должен быть установлен в NULL, если dwThreadId параметр определяет поток, созданный текущим процессом и если hook процедура находится в пределах кода, связанного с текущим процессом.

dwThreadId [in]

Тип: DWORD

Идентификатор потока, с которым подключаемая процедура должна быть связана. Для настольных приложений, если этот параметр равен нулю, подключаемая процедура связана со всеми существующими потоками, запущенными в том же рабочем столе, что и вызывающий поток. Для приложений Windows Store, в разделе Замечания.

Возвращаемое значение

Тип: *HHOOK *

Если функция завершается успешно, то возвращаемое значение равно обработчику хука. В противном случае будет возвращён NULL. Для большей информации об ошибке вызывайте GetLastError.

Структура проекта

После краткого ознакомления с функцией, которую будем использовать для установки hook, посмотрим на структуру проекта, который продемонстрирует вариант подключения функции к отслеживанию мыши.

  • MouseHook.pro - профайл проекта;
  • main.cpp - файл с main функцией;
  • mouselogger.h - заголовочный файл класса для отслеживания событий мыши в системе;
  • mouselogger.cpp - файл исходных кодов для отслеживания событий мыши в системе.

MouseHook.pro

Профайл создаётся по умолчанию.

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

В данном файле, чтобы продемонстрировать работу сигналов и слотов, показано подключение лямбда функции к объекту для логирования событий мыши, но применёно подключение к объекту с использованием паттерна "Синглтон".

#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

Заголовочный файл класса для логирования сообщений о событиях мыши. В данном файле необходимо объявить статические методы:

  1. Для возвращения ссылки на объект синглтона, через которую был подключен слот к сигналу о событии мыши.
  2. Статический метод mouseProc , который будет использоваться для обработки событий.
#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);
}

Итог

В результате получится отслеживать события мыши в независимости от того, находится ли курсор мыши в фокусе программы, если приложение имеет графический интерфейс, или не находится в фокусе программы.

Видеоурок

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
OI
  • Ora Iro
  • Жел. 24, 2024, 6:38 Т.Ж.

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:40ұпай,
  • Бағалау ұпайлары-8
AD

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:50ұпай,
  • Бағалау ұпайлары-4
m
  • molni99
  • Қаз. 26, 2024, 1:37 Т.Ж.

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:80ұпай,
  • Бағалау ұпайлары4
Соңғы пікірлер
ИМ
Игорь МаксимовҚар. 22, 2024, 11:51 Т.Ж.
Django - Оқулық 017. Теңшелген Django кіру беті Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii LegotckoiҚаз. 31, 2024, 2:37 Т.Қ.
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZEҚаз. 19, 2024, 8:19 Т.Ж.
Qt Creator көмегімен fb3 файл оқу құралы Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь МаксимовҚаз. 5, 2024, 7:51 Т.Ж.
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas5Шілде 5, 2024, 11:02 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Енді форумда талқылаңыз
Evgenii Legotckoi
Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey1Қар. 15, 2024, 6:04 Т.Ж.
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProjectМаусым 4, 2022, 3:49 Т.Ж.
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9AnonimҚаз. 25, 2024, 9:10 Т.Ж.
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

Бізді әлеуметтік желілерде бақылаңыз