Qt-Qt使用鍵盘钩子Hook(支持判断按下、弹起、自动)
相关资料:
https://www.cnblogs.com/chyshx/p/12614148.html 钩子的使用
http://www.bubuko.com/infodetail-3073312.html 虚拟键码表(供函数GetAsyncKeyState()使用)
https://blog.csdn.net/joyopirate/article/details/109077913 Qt利用钩子函数实现键盘监听
https://download.csdn.net/download/zhujianqiangqq/71923476 csdn代码包下载
实例代码:
.pro
1 QT += core gui 2 3 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 4 5 CONFIG += c++11 6 7 # The following define makes your compiler emit warnings if you use 8 # any Qt feature that has been marked deprecated (the exact warnings 9 # depend on your compiler). Please consult the documentation of the 10 # deprecated API in order to know how to port your code away from it. 11 DEFINES += QT_DEPRECATED_WARNINGS 12 13 # You can also make your code fail to compile if it uses deprecated APIs. 14 # In order to do so, uncomment the following line. 15 # You can also select to disable deprecated APIs only up to a certain version of Qt. 16 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 17 18 SOURCES += \ 19 Hook.cpp \ 20 main.cpp \ 21 mainwindow.cpp 22 23 HEADERS += \ 24 Hook.h \ 25 mainwindow.h 26 27 FORMS += \ 28 mainwindow.ui 29 30 LIBS += -luser32 31 32 # Default rules for deployment. 33 qnx: target.path = /tmp/$${TARGET}/bin 34 else: unix:!android: target.path = /opt/$${TARGET}/bin 35 !isEmpty(target.path): INSTALLS += target
main.cpp
1 #include "mainwindow.h" 2 3 #include4 5 int main(int argc, char *argv[]) 6 { 7 QApplication a(argc, argv); 8 MainWindow w; 9 w.show(); 10 return a.exec(); 11 }
manwindow.h
1 #ifndef MAINWINDOW_H 2 #define MAINWINDOW_H 3 4 #include5 #include 6 7 8 #include 9 #include 10 #include 11 #include 12 #include "Hook.h" 13 14 QT_BEGIN_NAMESPACE 15 namespace Ui { class MainWindow; } 16 QT_END_NAMESPACE 17 18 class MainWindow : public QMainWindow 19 { 20 Q_OBJECT 21 22 public: 23 MainWindow(QWidget *parent = nullptr); 24 ~MainWindow(); 25 private slots: 26 void on_pushButton_clicked(); 27 void UpdateCapslockTip(int keyCode, bool downOrUp, bool aotu); 28 private: 29 Ui::MainWindow *ui; 30 Hook *m_pHook; 31 }; 32 #endif // MAINWINDOW_H
mainwindow.cpp
1 #include "mainwindow.h" 2 #include "ui_mainwindow.h" 3 4 MainWindow::MainWindow(QWidget *parent) 5 : QMainWindow(parent) 6 , ui(new Ui::MainWindow) 7 { 8 ui->setupUi(this); 9 setWindowTitle(QStringLiteral("Qt使用鍵盘钩子Hook(支持判断按下、弹起、自动)")); 10 11 #ifdef Q_OS_WIN 12 m_pHook = new Hook(); 13 m_pHook->installHook(); 14 m_pHook->SetKeyboardCall(std::bind(&MainWindow::UpdateCapslockTip, this, std::placeholders::_1,std::placeholders::_2,std::placeholders::_3)); 15 #endif 16 } 17 18 MainWindow::~MainWindow() 19 { 20 m_pHook->unInstallHook(); 21 delete ui; 22 } 23 24 void MainWindow::on_pushButton_clicked() 25 { 26 ui->textEdit->clear(); 27 } 28 29 void MainWindow::UpdateCapslockTip(int keyCode, bool downOrUp, bool aotu) 30 { 31 QString s = "key pressed:--------:%1 downOrUp:%2 aotu:%3"; 32 s = s.arg(keyCode).arg(downOrUp).arg(aotu); 33 ui->textEdit->append(s); 34 qDebug() << "key pressed:--------:" << keyCode 35 << "downOrUp:" << downOrUp 36 << "aotu:" << aotu; 37 }
hook.h
1 #ifndef HOOK_H 2 #define HOOK_H 3 4 #include5 #include 6 #ifdef Q_OS_WIN // 代表只有WIN系统才会启用 7 #include"Windows.h" 8 #include // 回调函数引入 9 #include // 时间函数引入 10 11 class Hook 12 { 13 public: 14 Hook(); 15 void installHook(); 16 void unInstallHook(); 17 static LRESULT CALLBACK keyProc(int nCode,WPARAM wParam,LPARAM lParam); 18 void SetKeyboardCall(const std::function<void (int,bool,bool)> & func){ m_func = func; } 19 private: 20 static std::function<void(int,bool,bool)> m_func; 21 }; 22 #endif 23 24 #endif // HOOK_H
hook.cpp
1 #include "Hook.h" 2 3 #ifdef Q_OS_WIN 4 Hook::Hook() 5 { 6 7 } 8 9 static HHOOK keyHook = nullptr; 10 std::function<void(int,bool,bool)> Hook::m_func = nullptr; 11 bool m_bAuto = false;// 是否为自动按键,false代表是手动按下,true代表是自动按下。 12 int m_nKey = 0;// 上次的按键值 13 bool m_bDownOrUp = false;// 是否按下,false弹起,true按下。 14 15 LRESULT CALLBACK Hook::keyProc(int nCode,WPARAM wParam,LPARAM lParam) 16 { 17 // GetAsyncKeyState 判断正在按下某键 取异步键状态 物理键状态(实际的) 18 // GetKeyState GetKeyboardState 判断刚按过了某键 逻辑键状态(虚拟的) 19 // KBDLLHOOKSTRUCT *pkbhs=(KBDLLHOOKSTRUCT*)lParam; 20 // if(nCode == HC_ACTION){ 21 // if(pkbhs->vkCode == VK_ESCAPE && GetAsyncKeyState(VK_CONTROL)& 0x8000 && GetAsyncKeyState(VK_SHIFT)&0x8000){ 22 // qDebug() << "Ctrl+Shift+Esc"; 23 // }else if(pkbhs->vkCode == VK_ESCAPE && GetAsyncKeyState(VK_CONTROL) & 0x8000){ 24 // qDebug() << "Ctrl+Esc"; 25 // }else if(pkbhs->vkCode == VK_TAB && pkbhs->flags & LLKHF_ALTDOWN){ 26 // qDebug() << "Alt+Tab"; 27 // }else if(pkbhs->vkCode == VK_ESCAPE && pkbhs->flags &LLKHF_ALTDOWN){ 28 // qDebug() << "Alt+Esc"; 29 // }else if(pkbhs->vkCode == VK_LWIN || pkbhs->vkCode == VK_RWIN){ 30 // qDebug() << "LWIN/RWIN"; 31 // }else if(pkbhs->vkCode == VK_F4 && pkbhs->flags & LLKHF_ALTDOWN){ 32 // qDebug() << "Alt+F4"; 33 // } 34 // return CallNextHookEx(keyHook, nCode, wParam, lParam);//返回1表示截取消息不再传递,返回0表示不作处理,消息继续传递 35 // } 36 37 // 当前进程 38 HWND hwnd = GetForegroundWindow(); 39 DWORD Fid = GetWindowThreadProcessId(hwnd, NULL); 40 DWORD Cid = GetCurrentThreadId(); 41 if (Fid != Cid) 42 { 43 return CallNextHookEx(keyHook, nCode, wParam, lParam); 44 } 45 46 KBDLLHOOKSTRUCT *pKBDLLHook= (KBDLLHOOKSTRUCT*)lParam; 47 48 if(nCode == HC_ACTION){ 49 // 处理自动按下 50 if (m_nKey == (int)pKBDLLHook->vkCode) 51 { 52 m_bAuto = true; 53 }else 54 { 55 m_bAuto = false; 56 m_nKey = pKBDLLHook->vkCode; 57 } 58 59 if (wParam== WM_KEYDOWN) 60 { 61 m_bDownOrUp = true; 62 } 63 if (wParam== WM_KEYUP) 64 { 65 m_bDownOrUp = false; 66 m_bAuto = false; 67 m_nKey = 0; 68 } 69 } 70 71 if (m_func) 72 { 73 m_func(pKBDLLHook->vkCode, m_bDownOrUp, m_bAuto); 74 } 75 76 // if (GetAsyncKeyState(VK_LSHIFT)&0x8000) 77 // { 78 // QDateTime dateTime; 79 // QString s; 80 // s = "WM_KEYUP:" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - VK_LSHIFT"; 81 // qDebug() << s; 82 // } 83 // if (GetAsyncKeyState(VK_RSHIFT)&0x8000) 84 // { 85 // QDateTime dateTime; 86 // QString s; 87 // s = "WM_KEYUP:" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - VK_RSHIFT"; 88 // qDebug() << s; 89 // } 90 // if (GetAsyncKeyState(VK_UP)&0x8000) 91 // { 92 // QDateTime dateTime; 93 // QString s; 94 // s = "WM_KEYUP:" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - VK_UP"; 95 // qDebug() << s; 96 // } 97 // if (GetAsyncKeyState(VK_DOWN)&0x8000) 98 // { 99 // QDateTime dateTime; 100 // QString s; 101 // s = "WM_KEYUP:" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - VK_DOWN"; 102 // qDebug() << s; 103 // } 104 // if (GetAsyncKeyState(VK_LEFT)&0x8000) 105 // { 106 // QDateTime dateTime; 107 // QString s; 108 // s = "WM_KEYUP:" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - VK_LEFT"; 109 // qDebug() << s; 110 // } 111 // if (GetAsyncKeyState(VK_RIGHT)&0x8000) 112 // { 113 // QDateTime dateTime; 114 // QString s; 115 // s = "WM_KEYUP:" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - VK_RIGHT"; 116 // qDebug() << s; 117 // } 118 // if (GetAsyncKeyState(VK_RETURN)&0x8000) 119 // { 120 // QDateTime dateTime; 121 // QString s; 122 // s = "WM_KEYUP:" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - VK_RETURN"; 123 // qDebug() << s; 124 // } 125 // if (GetAsyncKeyState(VK_ESCAPE )&0x8000) 126 // { 127 // QDateTime dateTime; 128 // QString s; 129 // s = "WM_KEYUP:" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - VK_ESCAPE "; 130 // qDebug() << s; 131 // } 132 133 // if (wParam== WM_KEYUP && pKBDLLHook->vkCode== VK_F10) 134 // { 135 // QDateTime dateTime; 136 // QString s; 137 // s = "WM_KEYUP:" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - VK_F10"; 138 // qDebug() << s; 139 // } 140 // if (wParam== WM_KEYDOWN && pKBDLLHook->vkCode== VK_F10) 141 // { 142 // QDateTime dateTime; 143 // QString s; 144 // s = "WM_KEYDOWN:" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - VK_F10"; 145 // qDebug() << s; 146 // } 147 // if (wParam== WM_KEYUP && pKBDLLHook->vkCode== VK_TAB) 148 // { 149 // QDateTime dateTime; 150 // QString s; 151 // s = "WM_KEYUP:" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - VK_TAB"; 152 // qDebug() << s; 153 // } 154 // if (wParam== WM_KEYDOWN && pKBDLLHook->vkCode== VK_TAB) 155 // { 156 // QDateTime dateTime; 157 // QString s; 158 // s = "WM_KEYDOWN:" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - VK_TAB"; 159 // qDebug() << s; 160 // } 161 // if (wParam== WM_KEYUP && pKBDLLHook->vkCode== 'A') 162 // { 163 // QDateTime dateTime; 164 // QString s; 165 // s = "WM_KEYUP:" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - A"; 166 // qDebug() << s; 167 // } 168 // if (wParam== WM_KEYDOWN && pKBDLLHook->vkCode== 'A') 169 // { 170 // QDateTime dateTime; 171 // QString s; 172 // s = "WM_KEYDOWN:" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - A"; 173 // qDebug() << s; 174 // } 175 // if (pKBDLLHook->flags & LLKHF_ALTDOWN) 176 // { 177 // QDateTime dateTime; 178 // QString s; 179 // s = ":" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - LLKHF_ALTDOWN"; 180 // qDebug() << s; 181 // } 182 // if (GetAsyncKeyState(VK_CONTROL)& 0x8000) 183 // { 184 // QDateTime dateTime; 185 // QString s; 186 // s = ":" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - VK_CONTROL"; 187 // qDebug() << s; 188 // } 189 // if (GetAsyncKeyState(VK_SHIFT)&0x8000) 190 // { 191 // QDateTime dateTime; 192 // QString s; 193 // s = ":" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - VK_SHIFT"; 194 // qDebug() << s; 195 // } 196 // if (GetKeyState(VK_CONTROL)&0x8000) 197 // { 198 // QDateTime dateTime; 199 // QString s; 200 // s = ":" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - GetKeyState VK_CONTROL"; 201 // qDebug() << s; 202 // } 203 // if (GetKeyState(VK_SHIFT)&0x8000) 204 // { 205 // QDateTime dateTime; 206 // QString s; 207 // s = ":" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - GetKeyState VK_SHIFT"; 208 // qDebug() << s; 209 // } 210 // if (wParam== WM_KEYUP && (pKBDLLHook->vkCode == VK_LWIN || pKBDLLHook->vkCode == VK_RWIN)) 211 // { 212 // QDateTime dateTime; 213 // QString s; 214 // s = "WM_KEYUP:" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - WM_KEYUP WIN"; 215 // qDebug() << s; 216 // } 217 // if (wParam== WM_KEYDOWN && (pKBDLLHook->vkCode == VK_LWIN || pKBDLLHook->vkCode == VK_RWIN)) 218 // { 219 // QDateTime dateTime; 220 // QString s; 221 // s = "WM_KEYDOWN:" + dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + " - WM_KEYDOWN WIN"; 222 // qDebug() << s; 223 // } 224 return CallNextHookEx(keyHook, nCode, wParam, lParam); 225 } 226 227 void Hook::unInstallHook() 228 { 229 if(keyHook != nullptr)// 原作者说是担心一次释放不稳定,才释放二次的。 230 { 231 UnhookWindowsHookEx(keyHook);//键盘钩子句不为空时销毁掉 232 keyHook = nullptr; 233 } 234 if(keyHook != nullptr) 235 { 236 UnhookWindowsHookEx(keyHook);//键盘钩子句不为空时销毁掉 237 keyHook = nullptr; 238 } 239 } 240 241 void Hook::installHook() 242 { 243 keyHook = SetWindowsHookEx(WH_KEYBOARD_LL, keyProc, nullptr, 0); 244 } 245 246 #endif