Evgenii Legotckoi
Evgenii Legotckoi13 червня 2016 р. 13:35

Qt WinAPI - Урок 009. SetWindowsHookEx - Реєстрація подій миші через WinAPI

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

ВстановитиWindowsHookEx

Ця функція використовується для реєстрації функції-обробника подій у ланцюжку hook-обробників для відстеження деяких подій у Windows

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

Параметри

idHook [в]

Тип: 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 [в]

Тип: HOOKPROC

Вказівник на hook процедуру. Якщо dwThreadId параметр дорівнює нулю або визначає ідентифікатор треда, створеного іншим процесом, параметр lpfn повинен вказувати на процедуру, що підключається в DLL. В іншому випадку lpfn може вказувати на процедуру, що підключається в коді, пов'язаному з поточним процесом.

hMod [в]

Тип: HINSTANCE

Дескриптор бібліотеки DLL, що містить процедуру hook, на який вказує параметр lpfn. .

dwThreadId [в]

Тип: 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 хостинг.

Вам це подобається? Поділіться в соціальних мережах!

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
AD

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

  • Результат:50бали,
  • Рейтинг балів-4
m
  • molni99
  • 26 жовтня 2024 р. 01:37

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

  • Результат:80бали,
  • Рейтинг балів4
m
  • molni99
  • 26 жовтня 2024 р. 01:29

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

  • Результат:20бали,
  • Рейтинг балів-10
Останні коментарі
ИМ
Игорь Максимов22 листопада 2024 р. 11:51
Django - Підручник 017. Налаштуйте сторінку входу до Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii Legotckoi31 жовтня 2024 р. 14:37
Django - Урок 064. Як написати розширення для Python Markdown Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZE19 жовтня 2024 р. 08:19
Читалка файлів fb3 на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь Максимов05 жовтня 2024 р. 07:51
Django - Урок 064. Як написати розширення для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas505 липня 2024 р. 11:02
QML - Урок 016. База даних SQLite та робота з нею в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Тепер обговоріть на форумі
Evgenii Legotckoi
Evgenii Legotckoi24 червня 2024 р. 15:11
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey115 листопада 2024 р. 06:04
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProject04 червня 2022 р. 03:49
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9Anonim25 жовтня 2024 р. 09:10
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

Слідкуйте за нами в соціальних мережах