QWidget継承クラスでRegisterHotKey使おうとしてハマった
作成中のファイラーにグローバルホットキーを実装しようとしてハマった話。
Qt5.11を使っている。
RegisterHotKeyはWindowsでグローバルホットキーを実装するときの選択肢の一つだが、このメッセージハンドラをQtWidget継承クラスのoverrideしたnativeEventFilterで受けようとしたけどメッセージが来なかった。
最終的にqApp->installNativeEventFilterでハンドラーを登録してやって実装できた。
下記コードは実装例(※色々省いた擬似コードみたいなものなのでコンパイルは通らない)
static const int HOTKEY_EVENT_ID = 100; class Filer : public QWidget { Filer(QWidget *parent) : QWidget(parent) { qApp->installNativeEventFilter(&_globalShortcutEvent); //コストラクタなどで購読開始 HWND hwnd = (HWND)winId(); auto result = ::RegisterHotKey( hwnd, HOTKEY_EVENT_ID, MOD_CONTROL, 0x32 //2キー ); if(!result) {/*登録エラー*/} } void closeEvent(QCloseEvent* ) { //closeEventなどで購読解除 ::UnregisterHotKey(HWND(winId()), HOTKEY_EVENT_ID); } class EventFilter : public QAbstractNativeEventFilter { public: bool nativeEventFilter(const QByteArray& eventType, void* message, long* result); }; static EventFilter _globalShortcutEvent; #if 0 //最初は基底クラスにあるこの関数をOverrideしていたけど、WM_HOTKEYメッセージが来ることがなかった・・・ virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result); #endif } bool Filer::EventFilter::nativeEventFilter(const QByteArray& eventType, void* message, long* result) { Q_UNUSED(eventType) Q_UNUSED(result) // Transform the message pointer to the MSG WinAPI MSG* msg = reinterpret_cast<MSG*>(message); // If the message is a HotKey, then ... if (msg->message == WM_HOTKEY) { // ... check HotKey if (msg->wParam == HOTKEY_EVENT_ID) { // We inform about this to the console qDebug() << "HotKey worked"; return true; } } return false; }