注册全局热键而不禁用其按键

3

我想制作一个程序,即使它在任何时刻都不处于活动状态,也可以捕获键盘事件。挂钩(Hooks)需要我做很多事情才能使其工作(创建DLL、读取等),因此我决定继续使用热键。

但现在我有一个问题。注册热键会禁用键盘上的该按键,因此我只能将该按键发送到程序中,而无法在其他程序(例如Notepad)中输入。

这是我的代码:

#include <iostream>
#include <windows.h>
using namespace std;

int main(int argc, char* argv[]) {
    RegisterHotKey(NULL, 1, NULL, 0x41); //Register A
    MSG msg = {0};

    while (GetMessageA(&msg, NULL, 0, 0) != 0) {
        if (msg.message == WM_HOTKEY) {
            cout << "A"; //Print A if I pressed it
        }
    }

    UnregisterHotKey(NULL, 1);
    return 0;
}

// and now I can't type A's

有没有解决这个问题的简单方法? 谢谢。

2
如果缺点不重要,您可以使用非 DLL 钩子(使用WH_KEYBOARD_LL)。它只是几个钩子 / 解钩子调用和回调。对其进行一些处理,然后传递它。 - chris
1
你也可以退而使用循环的 GetAsyncKeyState - chris
4
钩子和热键之间的区别在于,钩子会告诉你何时按下了它,而热键会覆盖默认的处理方式。 - Deanna
感谢上面的评论,我已经做到了。 谢谢! - SmRndGuy
1个回答

5
我建议您的程序模拟键盘按键,与您实际执行的按键相匹配。具体而言:
  1. 您按下 'A' 按键。
  2. 程序捕获到 'A' 按键信号。
  3. 程序模拟键盘按键。
这非常简单。唯一的问题是您的程序也会捕获模拟的键盘按键信号。为了避免这种情况,您可以采取以下措施:
  1. 您按下 'A' 按键。
  2. 程序接收到 'A' 按键信号。
  3. 程序注销热键监听。
  4. 程序模拟键盘按键。
  5. (程序不再捕获 'A' 按键信号。)
  6. 程序重新注册热键监听。
这就是整个循环过程。
要实现按键模拟,您需要添加一些额外的代码。看一下这段代码:
#include <iostream>
#include <windows.h>
using namespace std;

int main(int argc, char* argv[]) {
    RegisterHotKey(NULL, 1, 0, 0x41);            //Register A; Third argument should also be "0" instead of "NULL", so it is not seen as pointer argument
    MSG msg = {0};
    INPUT ip;
    ip.type = INPUT_KEYBOARD;
    ip.ki.wScan = 0;
    ip.ki.time = 0;
    ip.ki.dwExtraInfo = 0;
    ip.ki.wVk = 0x41;                            //The key to be pressed is A.

    while (GetMessage(&msg, NULL, 0, 0) != 0) {
        if (msg.message == WM_HOTKEY) {
            UnregisterHotKey(NULL, 1);           //Prevents the loop from caring about the following
            ip.ki.dwFlags = 0;                   //Prepares key down
            SendInput(1, &ip, sizeof(INPUT));    //Key down
            ip.ki.dwFlags = KEYEVENTF_KEYUP;     //Prepares key up
            SendInput(1, &ip, sizeof(INPUT));    //Key up
            cout << "A";                         //Print A if I pressed it
            RegisterHotKey(NULL, 1, 0, 0x41);    //you know...
        }
    }

    UnregisterHotKey(NULL, 1);
    return 0;
}

我尝试过了,感觉还不错。 希望我能帮到你 ;)


连续调用 SendInput 并将 nInputs 参数设置为 1 是一个错误。keybd_eventSendInput 之间唯一的区别是,后者能够原子地注入整个输入批次到输入队列中,以便它不会与来自其他来源的输入交错。 - IInspectable
(disregard comment) - unsynchronized

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接