【问题标题】:Can I change a user's keyboard input?我可以更改用户的键盘输入吗?
【发布时间】:2011-01-05 06:15:33
【问题描述】:

我找到了这个键盘钩子代码,我正在尝试对其进行稍微修改以用于我的目的:http://blogs.msdn.com/toub/archive/2006/05/03/589423.aspx

作为一个概述,我想让用户按下一个键,比如“E”,并让键盘返回一个不同的字符“Z”,无论应用程序处于焦点状态。

我现在改的相关方法如下:

    private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
        {
            //The truely typed character:
            int vkCode = Marshal.ReadInt32(lParam);
            Console.WriteLine((Keys)vkCode);

            KBDLLHOOKSTRUCT replacementKey = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
            replacementKey.vkCode = 90; // char 'Z'
            Marshal.StructureToPtr(replacementKey, lParam, false);

            //Now changed to my set character
            vkCode = Marshal.ReadInt32(lParam);
            Console.WriteLine((Keys)vkCode);
        }
        return CallNextHookEx(_hookID, nCode, wParam, lParam);
    }

控制台正确输出如下:

E
Z
T
Z
G
Z
etc.

但是,焦点应用仍然键入“E”而不是“Z”。为什么?我将挂钩的键盘输入更改为包含“Z”而不是“E”,控制台行显示它已正确更改!

据我了解,调用return CallNextHookEx(_hookID, nCode, wParam, lParam); 是向打开的应用程序发送“立即打印”命令的原因。这不是它的工作原理吗?有什么东西阻止我输入我想要的字符吗?我知道像 AutoHotkey 这样的应用程序需要一个输入键,检查它,然后返回一个不同的字符。我如何在这里做同样的事情?

谢谢!

【问题讨论】:

  • 出于好奇,这个有什么用途?
  • 这不是键盘记录器! :) 该应用程序是辅助技术。想想 iPhone 键盘;它在后台修改关键区域,更正明显错误,并运行其他智能代码,帮助您更快、更准确地打字。这是一个类似的应用程序,但适用于全键盘。

标签: c# low-level keyboard-layout keyboard-hook


【解决方案1】:

我以前做过这个,但有点不同。
我没有尝试更改发送到CallNextHookEx 的参数,而是“吞下”了按键(您可以通过从挂钩过程返回一个非零值来做到这一点,以防止后续过程被调用)。

然后我使用SendInput 发送我想“注入”的新密钥。

所以基本上它是这样工作的:

  • 钩子程序识别目标键被按下
  • 使用新键调用 SendInput
  • 从挂钩过程中返回 1 以忽略原始密钥

小心循环重定向,即'a'重定向到'b'重定向到'a',它很容易炸毁;)

【讨论】:

  • 酷,我已经成功忽略了原来的密钥,返回(IntPtr)1; 现在,我该如何SendInput?我需要在标题中包含特定的using XXX,还是需要添加其他代码才能使用该命令?
  • pinvoke.net 拥有调用SendInput - pinvoke.net/default.aspx/user32/SendInput.html 所需的所有代码
  • 好的,使用[DllImport("coredll.dll", SetLastError = true)] static extern uint SendInput(uint cInputs, /* [MarshalAs(UnmanagedType.LPArray)] */ KEYBOARDINPUT[] inputs, int cbSize); 和 KEYBOARDINPUT 结构得到它。现在我正在向 SendInput() 传递正确的参数。
  • coredll.dll 用于 Windows CE,使用 user32.dll 变体,您可能还想看看这个:inputsimulator.codeplex.com
  • 哦,看起来棒极了。真的希望他们在该网站上包含一个“如何在您的代码中工作”页面。不过,我正在处理它……我必须像上面那样导入那个 DLL,对吧?我必须对 .zip 中的其他文件做任何事情吗?
【解决方案2】:

您很可能安装了“线程范围”而不是“系统范围”的挂钩,这意味着密钥转换只会发生在安装挂钩的线程中。

为了在“系统范围内”安装它,您需要两部分:一个具有“钩子提供程序”的 dll 和一个管理它的 exe。 这是一个很好的教程 http://www.codeproject.com/KB/system/hooksys.aspx 这里有一个例子: http://www.codeguru.com/cpp/com-tech/shell/article.php/c4509/

但是: 1. 安装系统范围的挂钩可能会严重破坏您的系统(确保转发您不翻译的密钥)。 2. 请...不要创建另一个键盘记录器

【讨论】:

  • 他使用的是低级键盘钩子,而不是普通的键盘钩子。低级挂钩不需要加载到每个进程中的单独 dll。来自msdn.microsoft.com/en-us/library/ms644985.aspx - 但是,WH_KEYBOARD_LL 挂钩没有注入到另一个进程中。相反,上下文切换回安装钩子的进程,并在其原始上下文中调用它。然后上下文切换回生成事件的应用程序。
  • 代码项目:@ 987654324@“来自 C# 的低级 Windows API 挂钩以阻止不需要的击键”,作者:Emma Burrows。 2007 年的文章。
猜你喜欢
  • 2013-11-17
  • 2012-04-22
  • 1970-01-01
  • 1970-01-01
  • 2012-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多