Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 带有WH_键盘LL和keybd_事件的全局键盘挂钩(windows)_C++_Hook_Keyboard Events_Keyboard Hook - Fatal编程技术网

C++ 带有WH_键盘LL和keybd_事件的全局键盘挂钩(windows)

C++ 带有WH_键盘LL和keybd_事件的全局键盘挂钩(windows),c++,hook,keyboard-events,keyboard-hook,C++,Hook,Keyboard Events,Keyboard Hook,我正在尝试编写一个简单的全局键盘钩子程序来重定向一些键。例如,当程序执行时,我按下键盘上的“a”,程序可以禁用它并模拟“b”点击。我不需要图形用户界面,只要一个控制台就足够了(让它继续运行) 我的计划是使用全局钩子捕捉按键输入,然后使用keybd_事件模拟键盘。但是我有一些问题 第一个问题是程序可以正确地阻止'A',但是如果我在键盘上按一次'A',回调函数中的printf会执行两次,keybd_事件也会执行两次。因此,如果我打开一个txt文件,单击一次“a”,就会有两个“B”输入。为什么呢 第二

我正在尝试编写一个简单的全局键盘钩子程序来重定向一些键。例如,当程序执行时,我按下键盘上的“a”,程序可以禁用它并模拟“b”点击。我不需要图形用户界面,只要一个控制台就足够了(让它继续运行)

我的计划是使用全局钩子捕捉按键输入,然后使用keybd_事件模拟键盘。但是我有一些问题

第一个问题是程序可以正确地阻止'A',但是如果我在键盘上按一次'A',回调函数中的printf会执行两次,keybd_事件也会执行两次。因此,如果我打开一个txt文件,单击一次“a”,就会有两个“B”输入。为什么呢

第二个问题是,为什么使用WH_KEYBOARD_LL的钩子可以在没有dll的情况下在其他进程上工作?在我写这个例子之前,我一直认为我们必须使用dll来创建一个全局钩子

#include "stdafx.h"
#include <Windows.h>
#define _WIN32_WINNT 0x050

LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    BOOL fEatKeystroke = FALSE;

    if (nCode == HC_ACTION)
    {
        switch (wParam)
        {
        case WM_KEYDOWN:
        case WM_SYSKEYDOWN:
        case WM_KEYUP:
        case WM_SYSKEYUP:
            PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
            if (fEatKeystroke = (p->vkCode == 0x41)) {     //redirect a to b
            printf("Hello a\n");
            keybd_event('B', 0, 0, 0);
            keybd_event('B', 0, KEYEVENTF_KEYUP, 0);
            break;
            }
            break;
        }
    }
    return(fEatKeystroke ? 1 : CallNextHookEx(NULL, nCode, wParam, lParam));
}

int main()
{
    // Install the low-level keyboard & mouse hooks
    HHOOK hhkLowLevelKybd = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, 0, 0);

    // Keep this app running until we're told to stop
    MSG msg;
    while (!GetMessage(&msg, NULL, NULL, NULL)) {    //this while loop keeps the hook
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    UnhookWindowsHookEx(hhkLowLevelKybd);

    return(0);
}
#包括“stdafx.h”
#包括
#定义_WIN32_WINNT 0x050
LRESULT回调LowLevelKeyboardProc(int-nCode、WPARAM-WPARAM、LPARAM-LPARAM)
{
BOOL fEatKeystroke=FALSE;
如果(nCode==HC\U动作)
{
交换机(wParam)
{
案例WM_键控:
案例WM_SYSKEYDOWN:
案例WM_KEYUP:
案例WM_SYSKEYUP:
PKBDLLHOOKSTRUCT p=(PKBDLLHOOKSTRUCT)lParam;
如果(fEatKeystroke=(p->vkCode==0x41)){//将a重定向到b
printf(“你好a\n”);
keybd_事件('B',0,0,0);
keybd_事件('B',0,KEYEVENTF_KEYUP,0);
打破
}
打破
}
}
返回(fEatKeystroke?1:CallNextHookEx(NULL、nCode、wParam、lParam));
}
int main()
{
//安装低级键盘和鼠标挂钩
HHOOK hhkLowLevelKybd=setWindowshookx(WH_KEYBOARD,LL,LowLevelKeyboardProc,0,0);
//保持此应用程序运行,直到我们被告知停止
味精;
while(!GetMessage(&msg,NULL,NULL,NULL)){//此while循环保留钩子
翻译信息(&msg);
发送消息(&msg);
}
UnhookWindowsHookEx(hhkLowLevelKybd);
返回(0);
}

非常感谢

第一个很简单。一个用于向下键,另一个用于向上键。:)

至于为什么它可以在没有DLL的情况下工作,那是因为它是一个全局钩子。与线程特定的进程不同,它是在您自己的进程中执行的,而不是在发生键盘事件的进程中执行。它是通过向安装了钩子的线程发送消息来完成的——这正是您需要消息循环的原因。没有它,你的钩子就无法运行,因为没有人来监听传入的消息


特定于线程的挂钩需要DLL,因为它们是在另一个进程的上下文中调用的。要使其工作,应该将DLL注入该进程。这里的情况并非如此。

由于
WM\u KEYDOWN
WM\u keydup
的原因,回调函数执行了两次。 当您按下键盘上的某个键时,windows会使用
WM\u KEYDOWN
消息调用回调函数,当您松开该键时,windows会使用
WM\u keydup
消息调用回调函数。这就是回调函数执行两次的原因

您应该将switch语句更改为:

switch (wParam)
{
    case WM_KEYDOWN:
    case WM_SYSKEYDOWN:
    case WM_KEYUP:
    case WM_SYSKEYUP:
        PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
        if (fEatKeystroke = (p->vkCode == 0x41))  //redirect a to b
        {     
            printf("Hello a\n");

            if ( (wParam == WM_KEYDOWN) || (wParam == WM_SYSKEYDOWN) ) // Keydown
            {
                keybd_event('B', 0, 0, 0);
            }
            else if ( (wParam == WM_KEYUP) || (wParam == WM_SYSKEYUP) ) // Keyup
            {
                keybd_event('B', 0, KEYEVENTF_KEYUP, 0);
            }
            break;
        }
        break;
}
关于你的第二个问题,我想你已经从@Ivan Danilov那里得到了答案

  • 我已经运行了你的代码,但什么也没发生?我怎么了
  • 基于键盘上的WH\u LL message是“仅限全局”这一点,它的含义不止于此。 此消息是特殊情况。您还需要一个DLL来为其他消息创建一个真正的全局钩子


  • 全局钩子不阻止输入,只允许您预览。@CodyGray根据-“…可能返回非零值,以防止系统将消息传递给钩子链的其余部分或目标窗口过程”。对于我来说,阻止系统将消息传递到目标窗口过程看起来就像是阻塞。对于那些试图让它工作,但收到错误的人,HOOK需要HMOD(1428):根据“如果HMOD参数为NULL,dwThreadId参数为零,则可能会发生错误”。因此,您必须指定
    hMod
    ,但在这种情况下,您可以使用任何合法值,因为对于低级钩子,不会注入任何DLL。例如,您可以使用
    GetModuleHandle(“kernel32.dll”)
    。唯一奇怪的是,MSDN说“所有全局钩子函数都必须在库中。”这完全是错误的。所有全局钩子必须在DLL中,除非它是低级钩子。在这方面缺乏文件。这里的语言是C++,但是C语言可以使用低级钩子,因为它们不需要DLL。