快捷键(加速键),系统热键,键盘钩子的不同
昨天刚刚了解到系统热键的API: RegisterHotKey(),当时很感慨,因为这些年来,经常用到的是【快捷键】或用【键盘钩子】实现的全局快键键,因为我不知道有现成的系统热键的API可用,有点丢人了。
现在想想,系统的快捷键,系统热键,键盘钩子他们各有各的特点,简单做个总结:
1. 快捷键(Accelerator:加速键),特点是:窗口必须在获得焦点(激活的状态)下,才能响应快捷键。
我一般都是在 res.rc 中添加:
// // Accelerator resources 加速键 // 详细介绍: https://docs.microsoft.com/en-us/windows/win32/menurc/accelerators-resource // LANGUAGE 0, SUBLANG_NEUTRAL IDR_ACCELERATOR1 ACCELERATORS { /* //快捷键的映射关系 "^C", ID_ACCELERATOR_DELETE // control C "K", ID_ACCELERATOR_DELETE // shift K "k", ID_ACCELERATOR_DELETE, ALT // alt k 98, ID_ACCELERATOR_DELETE, ASCII // b 66, ID_ACCELERATOR_DELETE, ASCII // B (shift b) "g", ID_ACCELERATOR_DELETE // g "G", ID_ACCELERATOR_DELETE // G (shift G) VK_F1, ID_ACCELERATOR_DELETE, VIRTKEY // F1 VK_F1, ID_ACCELERATOR_DELETE, CONTROL, VIRTKEY // control F1 VK_F1, ID_ACCELERATOR_DELETE, SHIFT, VIRTKEY // shift F1 VK_F1, ID_ACCELERATOR_DELETE, ALT, VIRTKEY // alt F1 VK_F2, ID_ACCELERATOR_DELETE, ALT, SHIFT, VIRTKEY // alt shift F2 VK_F2, ID_ACCELERATOR_DELETE, CONTROL, SHIFT, VIRTKEY // ctrl shift F2 VK_F2, ID_ACCELERATOR_DELETE, ALT, CONTROL, VIRTKEY // alt control F2 */ //"H", ID_ACCELERATOR_SCREENSHOT_STATIC, ALT, CONTROL, VIRTKEY // ctrl + alt + h, 注意, 前面必须使用大写的 "H" VK_DELETE, ID_ACCELERATOR_DELETE, VIRTKEY }
然后在主程序中 main() 中添加:
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1)); // 加载加速键表 //printf("hAccelTable:%ld\n", hAccelTable); /* Run the message loop. It will run until GetMessage() returns 0 */ while (GetMessage (&messages, NULL, 0, 0)) { //参考 - http://dec3.jlu.edu.cn/webcourse/T000024/files/bjjx/bjjx3.htm 和 http://itzone.hk/article/article.php?aid=200406211205229426 //TranslateAccelerator()函数确定存放在msg消息结构中的消息是不是键盘消息。 //如果是,该函数将查找句柄为hAccel的加速键表。如果找到了一个匹配,则调用句桶为hwnd的窗口的窗口过程。 //如果加速键ID与系统菜单的菜单项一致,则消息就是WM_SYSCOMMAND;否则,消息为WM_COMMAND。 if(!TranslateAccelerator(hwnd, hAccelTable, &messages)) //启用加速键 { /* Translate virtual-key messages into character messages */ TranslateMessage(&messages); /* Send message to WindowProcedure */ DispatchMessage(&messages); } else { //printf("按下了加速键...\n"); } }
2. 系统热键,特点:窗口不激活也能接收到键盘消息。使用 RegisterHotKey() 注册,操作上很简单,但由于是全局性的,容易和别的软件发生热键冲突,导致热键注册失败。
3. 键盘钩子,特点:窗口不激活也能接收到键盘消息。使用上有点麻烦,但是这玩意一般情况下不会因与别软件冲突,而无法接收键盘消息。当然如果别的软件也有键盘钩子,同时禁止了键盘消息向下传递,会不会也无法接收键盘消息,我没测试)
//全局键盘钩子 //参考 - http://blog.csdn.net/one_six_mix/article/details/52044406 hook_keyboard = SetWindowsHookExA(WH_KEYBOARD_LL, keyboardHook, GetModuleHandleA(0), 0); //GetModuleHandleA(0)或 NULL, 都行
//钩子回调 - 全局键盘钩子 LRESULT CALLBACK keyboardHook(int nCode, WPARAM wParam, LPARAM lParam) { if(nCode == HC_ACTION) //当 nCode等于HC_ACTION时,要求得到处理 { //参考 - http://bbs.csdn.net/topics/320236776 //参考 - http://www.51hei.com/bbs/dpj-30393-1.html //BOOL bControlKeyDown = GetAsyncKeyState(VK_CONTROL) >> ((sizeof(SHORT) * 8 ) - 1);// 检查是否Ctrl键被按下 KBDLLHOOKSTRUCT *ks = (KBDLLHOOKSTRUCT*)lParam; //printf("是否Ctrl键被按下:%d\n", bControlKeyDown); //printf("ks->vkCode:%c\n", ks->vkCode); if(ks->vkCode == VK_ESCAPE) { //printf("esc\n"); if(currentMouseLocationTarget == TARGET_NULL) { } else { ... if(hook_keyboard) { UnhookWindowsHookEx(hook_keyboard); //解锁 hook_keyboard = NULL; } return 1; //屏蔽掉, 不再向下传递 } } } return CallNextHookEx(hook_keyboard, nCode, wParam, lParam); //返回给下一个钩子子程处理 (==不屏蔽) }