生活随笔
收集整理的這篇文章主要介紹了
Qt实现全局键盘事件监听器-Windows
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Qt實現全局鍵盤事件監聽器-Windows版🍇
文章目錄
- Qt實現全局鍵盤事件監聽器-Windows版🍇
- 1、概述🍈
- 2、實現效果🍉
- 3、實現方式🍊
- 4、關鍵代碼🍋
- 5、源代碼🍌
更多精彩內容
| 👉個人內容分類匯總 👈 |
| 👉Qt自定義模塊、工具👈 |
1、概述🍈
- Qt版本:V5.12.5
- 兼容系統:
- Windows:這里測試了Windows10,其它的版本沒有測試;
- Linux:這里測試了ubuntu18.04、20.04,其它的沒有測試;
- Mac:等啥時候我有了Mac電腦再說。
有時候我們想獲取到全局鍵盤事件,使用Qt的鍵盤事件、事件過濾器之類的都無法實現,因為當鼠標移出當前窗口或者當前窗口失去焦點、窗口最小化了就無法獲取到鍵盤事件了;而Windows下想要監聽到全局鍵盤事件就需要使用到Windows的低級鍵盤鉤子來實現;關于Windows的鍵盤鉤子API文檔可以看微軟官網SetWindowsHookExW ;在這個類中通過Windows鍵盤鉤子API監聽到全局鍵盤事件;然后將監聽到的鍵盤事件映射為QKeyEvent事件,便于在Qt里面使用;注意:由于按鍵狀態非常多,想要將Windows鍵盤事件映射為QKeyEvent會比較麻煩,這里可以看Qt源碼怎么實現的D:\Qt\Qt5.12.5\5.12.5\Src\qtbase\src\plugins\platforms\windows\qwindowskeymapper.cpp;
2、實現效果🍉
3、實現方式🍊
使用SetWindowsHookExW()函數掛鉤低級鍵盤鉤子;通過回調函數LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)監聽到全局鍵盤事件;wParam參數表示信號類型: WM_KEYDOWN:按下非系統鍵, 非系統鍵是未按下 ALT 鍵時按下的鍵WM_KEYUP:當釋放非系統鍵WM_SYSKEYDOWN:當用戶按下 F10 鍵 (激活菜單欄) 或按住 Alt 鍵,然后按另一個鍵WM_SYSKEYUP:當用戶釋放按下 Alt 鍵時按下的鍵 使用KBDLLHOOKSTRUCT * kbdll = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam)將lParam轉換為KBDLLHOOKSTRUCT結構體的指針,可通過這個結構體獲取當前鍵盤按下的【虛擬密鑰代碼】、【密鑰的硬件掃描代碼】之類的信息;然后將獲取到的鍵盤事件映射為QKeyEvent事件,發送給當前程序使用; - 將windows鍵盤事件映射為QKeyEvent事件需要考慮按鍵基本鍵值、按下修飾鍵(Shift、Ctrl等)時的鍵值、大小寫字母、小鍵盤數字、各種特殊符號等。
這里我使用的是QKeyEvent指針進行發送,由于QKeyEvent沒有默認無參構造,所以在Linux下不支持使用信號發送QKeyEvent變量,所以只能使用指針;因為傳遞的是指針,所以在接收信號的槽函數里使用完后需要Delete,避免內存泄漏;簡易這個信號只綁定一次,避免多個槽函數里使用同一個指針,一個槽函數釋放了另外一個槽函數里出現野指針或者重復釋放。不使用時需要使用UnhookWindowsHookEx()函數刪除 SetWindowsHookEx ()函數在掛鉤鏈中安裝的掛鉤過程。
4、關鍵代碼🍋
- 由于使用到了系統API,所以pro文件中需要鏈接系統庫
win32 {
LIBS+= -luser32 # 使用WindowsAPI需要鏈接庫
}
#ifndef GLOBALKEYEVENT_H
#define GLOBALKEYEVENT_H#include <QObject>
class QKeyEvent;
class GlobalKeyEvent : public QObject
{Q_OBJECT
public:static GlobalKeyEvent
* getInstance(){static GlobalKeyEvent keyEvent
;return &keyEvent
;}static bool installKeyEvent(); static bool removeKeyEvent(); signals
:void keyEvent(QKeyEvent
* event
);private:GlobalKeyEvent(){}
};#endif
#include "globalkeyevent.h"
#if defined(Q_OS_WIN)
#include "Windows.h"
#include <QDebug>
#include <QKeyEvent>enum WindowsNativeModifiers {ShiftLeft
= 0x00000001,ControlLeft
= 0x00000002,AltLeft
= 0x00000004,MetaLeft
= 0x00000008,ShiftRight
= 0x00000010,ControlRight
= 0x00000020,AltRight
= 0x00000040,MetaRight
= 0x00000080,CapsLock
= 0x00000100,NumLock
= 0x00000200,ScrollLock
= 0x00000400,ExtendedKey
= 0x01000000,ShiftAny
= 0x00000011,ControlAny
= 0x00000022,AltAny
= 0x00000044,MetaAny
= 0x00000088,LockAny
= 0x00000700
};
static const uint KeyTbl
[] = { Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_Cancel
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_Backspace
, Qt
::Key_Tab
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_Clear
, Qt
::Key_Return
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_Shift
, Qt
::Key_Control
, Qt
::Key_Alt
, Qt
::Key_Pause
, Qt
::Key_CapsLock
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_Escape
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_Mode_switch
,Qt
::Key_Space
, Qt
::Key_PageUp
, Qt
::Key_PageDown
, Qt
::Key_End
, Qt
::Key_Home
, Qt
::Key_Left
, Qt
::Key_Up
, Qt
::Key_Right
, Qt
::Key_Down
, Qt
::Key_Select
, Qt
::Key_Printer
, Qt
::Key_Execute
, Qt
::Key_Print
, Qt
::Key_Insert
, Qt
::Key_Delete
, Qt
::Key_Help
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Qt
::Key_Meta
, Qt
::Key_Meta
, Qt
::Key_Menu
, Qt
::Key_unknown
, Qt
::Key_Sleep
, Qt
::Key_0
, Qt
::Key_1
, Qt
::Key_2
, Qt
::Key_3
, Qt
::Key_4
, Qt
::Key_5
, Qt
::Key_6
, Qt
::Key_7
, Qt
::Key_8
, Qt
::Key_9
, Qt
::Key_Asterisk
, Qt
::Key_Plus
, Qt
::Key_unknown
, Qt
::Key_Minus
, Qt
::Key_unknown
, Qt
::Key_Slash
, Qt
::Key_F1
, Qt
::Key_F2
, Qt
::Key_F3
, Qt
::Key_F4
, Qt
::Key_F5
, Qt
::Key_F6
, Qt
::Key_F7
, Qt
::Key_F8
, Qt
::Key_F9
, Qt
::Key_F10
, Qt
::Key_F11
, Qt
::Key_F12
, Qt
::Key_F13
, Qt
::Key_F14
, Qt
::Key_F15
, Qt
::Key_F16
, Qt
::Key_F17
, Qt
::Key_F18
, Qt
::Key_F19
, Qt
::Key_F20
, Qt
::Key_F21
, Qt
::Key_F22
, Qt
::Key_F23
, Qt
::Key_F24
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_NumLock
, Qt
::Key_ScrollLock
, 0, Qt
::Key_Massyo
, Qt
::Key_Touroku
, 0, 0, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_Shift
, Qt
::Key_Shift
, Qt
::Key_Control
, Qt
::Key_Control
, Qt
::Key_Alt
, Qt
::Key_Alt
, Qt
::Key_Back
, Qt
::Key_Forward
, Qt
::Key_Refresh
, Qt
::Key_Stop
, Qt
::Key_Search
, Qt
::Key_Favorites
, Qt
::Key_HomePage
, Qt
::Key_VolumeMute
, Qt
::Key_VolumeDown
, Qt
::Key_VolumeUp
, Qt
::Key_MediaNext
, Qt
::Key_MediaPrevious
, Qt
::Key_MediaStop
, Qt
::Key_MediaPlay
, Qt
::Key_LaunchMail
, Qt
::Key_LaunchMedia
,Qt
::Key_Launch0
, Qt
::Key_Launch1
, Qt
::Key_unknown
, Qt
::Key_unknown
, 0, 0, 0, 0, 0, 0, 0, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, 0, 0, 0, 0, 0, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_Play
, Qt
::Key_Zoom
, Qt
::Key_unknown
, Qt
::Key_unknown
, Qt
::Key_Clear
, 0
};static inline quint32
winceKeyBend(quint32 keyCode
)
{return KeyTbl
[keyCode
];
}
static inline Qt
::KeyboardModifiers
queryKeyboardModifiers()
{Qt
::KeyboardModifiers modifiers
= Qt
::NoModifier
;if (GetKeyState(VK_SHIFT
) < 0)modifiers
|= Qt
::ShiftModifier
;if (GetKeyState(VK_CONTROL
) < 0)modifiers
|= Qt
::ControlModifier
;if (GetKeyState(VK_MENU
) < 0)modifiers
|= Qt
::AltModifier
;if (GetKeyState(VK_LWIN
) < 0 || GetKeyState(VK_RWIN
) < 0)modifiers
|= Qt
::MetaModifier
;return modifiers
;
}static uchar g_buffer
[256];
static inline quint32
toKeyOrUnicode(quint32 vk
, quint32 scancode
, bool *isDeadkey
= nullptr)
{Q_ASSERT(vk
> 0 && vk
< 256);GetKeyboardState(g_buffer
);
g_buffer
[VK_LWIN
] = 0;g_buffer
[VK_RWIN
] = 0;g_buffer
[VK_CAPITAL
] = 0;g_buffer
[VK_NUMLOCK
] = 0;g_buffer
[VK_SCROLL
] = 0;g_buffer
[VK_RSHIFT
] = 0;g_buffer
[VK_RCONTROL
] = 0;g_buffer
[VK_LMENU
] = 0; g_buffer
[VK_CONTROL
] = 0; quint32 code
= 0;QChar unicodeBuffer
[5];int res
= ToUnicode(vk
, scancode
, g_buffer
, reinterpret_cast<LPWSTR>(unicodeBuffer
), 5, 0);if (res
== 0 && g_buffer
[VK_CONTROL
]){const unsigned char controlState
= g_buffer
[VK_CONTROL
];g_buffer
[VK_CONTROL
] = 0;res
= ToUnicode(vk
, scancode
, g_buffer
, reinterpret_cast<LPWSTR>(unicodeBuffer
), 5, 0);g_buffer
[VK_CONTROL
] = controlState
;}if (res
){code
= unicodeBuffer
[0].toUpper().unicode(); }if (code
< 0x20 || code
== 0x7f) {code
= winceKeyBend(vk
);}if (isDeadkey
){*isDeadkey
= (res
== -1);}return code
== Qt
::Key_unknown
? 0 : code
;
}static uchar g_keyState
[256];
static inline QString
getKeyText(quint32 vk
, quint32 scancode
)
{GetKeyboardState(g_keyState
); wchar_t newKey
[3] = {0};int ret
= ToUnicode(vk
, scancode
, g_keyState
, newKey
, 3, 0); if (ret
== 1) {QChar uch
= QChar(newKey
[0]);return uch
;}else {return QString();}
}
static quint32
getNativeModifiers(quint32 flags
)
{quint32 nModifiers
= 0;nModifiers
|= (GetKeyState(VK_LSHIFT
) & 0x80 ? ShiftLeft
: 0);nModifiers
|= (GetKeyState(VK_RSHIFT
) & 0x80 ? ShiftRight
: 0);nModifiers
|= (GetKeyState(VK_LCONTROL
) & 0x80 ? ControlLeft
: 0);nModifiers
|= (GetKeyState(VK_RCONTROL
) & 0x80 ? ControlRight
: 0);nModifiers
|= (GetKeyState(VK_LMENU
) & 0x80 ? AltLeft
: 0);nModifiers
|= (GetKeyState(VK_RMENU
) & 0x80 ? AltRight
: 0);nModifiers
|= (GetKeyState(VK_LWIN
) & 0x80 ? MetaLeft
: 0);nModifiers
|= (GetKeyState(VK_RWIN
) & 0x80 ? MetaRight
: 0);nModifiers
|= (GetKeyState(VK_CAPITAL
) & 0x01 ? CapsLock
: 0);nModifiers
|= (GetKeyState(VK_NUMLOCK
) & 0x01 ? NumLock
: 0);nModifiers
|= (GetKeyState(VK_SCROLL
) & 0x01 ? ScrollLock
: 0);if (flags
& LLKHF_EXTENDED
) {nModifiers
|= ExtendedKey
;}return nModifiers
;
}static HHOOK g_hook
= nullptr;
LRESULT CALLBACK
LowLevelKeyboardProc(int nCode
, WPARAM wParam
, LPARAM lParam
)
{KBDLLHOOKSTRUCT
* kbdll
= reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam
);bool isDeadKey
= false;Qt
::KeyboardModifiers modifiers
= queryKeyboardModifiers();int key
= int(toKeyOrUnicode(kbdll
->vkCode
, kbdll
->scanCode
, &isDeadKey
));QString text
= getKeyText(kbdll
->vkCode
, kbdll
->scanCode
);quint32 nativeModifiers
= getNativeModifiers(kbdll
->flags
);bool autorep
= (g_buffer
[kbdll
->vkCode
] & 0x80);switch (wParam
){case WM_KEYDOWN
: {emit
GlobalKeyEvent::getInstance()->keyEvent(new QKeyEvent(QEvent
::KeyPress
, key
, modifiers
, kbdll
->scanCode
, kbdll
->vkCode
, nativeModifiers
, text
, autorep
));break;}case WM_KEYUP
: emit
GlobalKeyEvent::getInstance()->keyEvent(new QKeyEvent(QEvent
::KeyRelease
, key
, modifiers
, kbdll
->scanCode
, kbdll
->vkCode
, nativeModifiers
, text
, !autorep
));break;case WM_SYSKEYDOWN
: qDebug() << "按下系統鍵 Alt";emit
GlobalKeyEvent::getInstance()->keyEvent(new QKeyEvent(QEvent
::KeyPress
, key
, modifiers
, kbdll
->scanCode
, kbdll
->vkCode
, nativeModifiers
, text
, autorep
));break;case WM_SYSKEYUP
: qDebug() << "釋放系統鍵 Alt";emit
GlobalKeyEvent::getInstance()->keyEvent(new QKeyEvent(QEvent
::KeyRelease
, key
, modifiers
, kbdll
->scanCode
, kbdll
->vkCode
, nativeModifiers
, text
, !autorep
));break;default:break;}return CallNextHookEx(nullptr, nCode
, wParam
, lParam
);
}
bool GlobalKeyEvent::installKeyEvent()
{if(g_hook
) return true; g_hook
= SetWindowsHookExW(WH_KEYBOARD_LL
, LowLevelKeyboardProc
, GetModuleHandleW(nullptr), 0);return g_hook
;
}
bool GlobalKeyEvent::removeKeyEvent()
{if(!g_hook
) return true; bool ret
= UnhookWindowsHookEx(g_hook
);if(ret
){g_hook
= nullptr;return true;}return false;
}#endif
5、源代碼🍌
- gitee
- github
- 全局鼠標鍵盤事件監聽器倉庫github
- 全局鼠標鍵盤事件監聽器倉庫gitee
- CSDN
- 可以使用命令git clone https://gitee.com/mahuifa/QtGlobalEvent.git直接下載倉庫,然后引用到自己的程序中。
🍒🍒🍒🍒🍒🍒🍒🍒🍒🍒🍒🍒🍒🍒🍒🍒
總結
以上是生活随笔為你收集整理的Qt实现全局键盘事件监听器-Windows的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。