Qtアプリケーションにおけるプラットフォーム依存キーフックの実装

Qtフレームワークはクロスプラットフォーム開発を可能にしますが、キーボードフックのようなプラットフォーム固有の機能を実装する場合、条件付きコンパイルによる対応が必要となります。WindowsプラットフォームではSetWindowsHookExなどのAPIを使用できますが、macOSでは同等の機能が提供されていません。

条件付きコンパイルを実現するための主要なポイント:

  1. プロジェクトファイルにおけるシステムライブラリの指定 Windowsシステムでのみuser32.libをリンクするため、.proファイルに以下の記述を追加します:
win32: LIBS += -luser32
  1. プラットフォーム判定によるヘッダーインクルード Qtが提供する定義マクロを使用してシステムを判別します:
#ifdef Q_OS_WIN
#include <windows.h>
#endif
  1. フック機能の実装をWindows環境に限定 フックの初期化と解放処理をプラットフォーム条件で囲います:
#ifdef Q_OS_WIN
// Windows専用のフック処理実装
#endif

実装例:

KeyHook.h

#ifndef KEYHOOK_H
#define KEYHOOK_H

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

class KeyHook
{
public:
    KeyHook();
    bool setupKeyboardHook();
    void removeKeyboardHook();
};

#endif
#endif // KEYHOOK_H

KeyHook.cpp

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

#ifdef Q_OS_WIN

static HHOOD keyboardHookHandle = nullptr;

LRESULT CALLBACK keyboardCallback(int code, WPARAM wparam, LPARAM lparam)
{
    KBDLLHOOKSTRUCT* keyData = (KBDLLHOOKSTRUCT*)lparam;
    
    if (code == HC_ACTION) {
        if (keyData->vkCode == VK_ESCAPE) {
            if (GetAsyncKeyState(VK_CONTROL) & 0x8000) {
                qDebug() << "Ctrl+Esc detected";
                return 1; // メッセージを処理済みとして伝播を停止
            }
        }
    }
    return CallNextHookEx(keyboardHookHandle, code, wparam, lparam);
}

KeyHook::KeyHook() {}

bool KeyHook::setupKeyboardHook()
{
    keyboardHookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, keyboardCallback, nullptr, 0);
    return keyboardHookHandle != nullptr;
}

void KeyHook::removeKeyboardHook()
{
    if (keyboardHookHandle) {
        UnhookWindowsHookEx(keyboardHookHandle);
        keyboardHookHandle = nullptr;
    }
}

#endif

タグ: Qt WindowsAPI キーボードフック 条件コンパイル クロスプラットフォーム

7月20日 02:47 投稿