代码之家  ›  专栏  ›  技术社区  ›  Lasse V. Karlsen

键盘挂钩更改键的行为

  •  4
  • Lasse V. Karlsen  · 技术社区  · 14 年前

    我正在创建一个程序,安装一个键盘挂钩来捕获所有键并显示与它们相关的一些文本。

    然而,我遇到了一个障碍,这是一些键在安装钩子时改变行为。

    我将看到关于发布一个小的,但完整的测试程序,但现在我只描述这个问题。

    这个问题出现在Windows7 64位的C程序.NET 4.0中。我认为这些都不重要。

    我的钩子通过 SetWindowsHookEx 然后处理系统中处理的所有密钥。

    如果hook方法只是返回,或者对键进行最小的处理(我将在一秒钟内发布更改行为的内容),那么键盘将在程序中按预期工作。

    但是,如果我调用这个函数, ToAscii 从user32.dll,要想知道我的键盘上的哪个键是Oemtild或类似的键,任何“覆盖下一个键”的键都会停止工作。我不知道这些键的正确名称,但这两个撇号类型是``和 , as well as ~ and ¨`,停止工作。

    例如,如果我击中 ~ 然后 N ,显示如下:

    • 未安装键盘挂钩:±
    • 安装键盘挂钩:n(注意上面的编号)

    有人知道为什么会发生这种情况吗?我如何解决这个问题?

    现在,我将决定只在其他程序中正确地处理密钥,即使这意味着我无法在自己的程序中正确地检测到正确的密钥序列。

    更多信息:

    如果我打电话给 托阿西西 作为hook方法的一部分,则会出现另一个问题。类密钥 ¨ 被处理两次 一次,记事本收到两个 ¨¨ 人物和打击 n 现在只需添加 n .

    但是,如果我使用 BeginInvoke 要在单独的线程上处理键,从键盘挂钩方法返回后,会出现第一个问题。


    我的程序可能有点特别:

    • 我不使用键盘状态(即,我传递的“键状态”256字节数组中只有0个字节)
    • 我不在乎死键(从我的程序不会处理它们的意义上说,我只关心它们,不希望我的程序使它们对系统的其余部分无效)

    因此,我的代码最终如下所示:

    private bool IsDeadKey(uint key)
    {
        return ((Hook.Interop.MapVirtualKey(key, 2) & 2147483648) == 2147483648);
    }
    
    void _Hook_KeyDown_Async(KeyDownEventArgs e)
    {
        var inBuffer = new byte[2];
        char key = '\0';
        if (!IsDeadKey((uint)e.KeyCode))
        {
            int ascii = Hook.Interop.ToAscii((int) e.KeyCode,
                                                e.ScanCode,
                                                _KeyState,
                                                inBuffer,
                                                e.Flags);
            if (ascii == 1)
            {
                key = Char.ToUpper((char) inBuffer[0]);
            }
        }
    
        BeginInvoke(
            new Action<Keys, Boolean, Boolean, Boolean, Char>(ProcessKeyboardEvent),
            e.KeyCode, e.Control, e.Shift, e.Alt, key);
    }
    
    4 回复  |  直到 14 年前
        1
  •  2
  •   Community Nick Dandoulakis    7 年前

    这些钥匙叫做 dead keys 您可以通过取消对的调用来解决问题。 ToAscii . 另请参见以下相关线程:

    ToAscii/ToUnicode in a keyboard hook destroys dead keys.

    更新:我没有看到您的代码,但是在处理 KeyboardProc 回拨功能,你能检查一下当你把键盘信息传到 code 参数小于0?文件上说:

    代码 [在] int

    钩子过程用于确定如何处理消息的代码。 如果 代码 小于零,钩子过程必须将消息传递给 CallNextHookEx 函数而不进行进一步处理,应返回 长喙鱼 .

    有一个样品 setting up a managed hook 在MSDN中:

    if (nCode < 0)
    {
        return CallNextHookEx(hHook, nCode, wParam, lParam);
    }
    else
    {
        // process message here
    
        return CallNextHookEx(hHook, nCode, wParam, lParam); 
    }
    
        2
  •  2
  •   Hans Passant    14 年前

    你的问题缺少一点关键信息,你用哪一个键盘挂钩?简单的键盘就不能用了。您最终将使用程序的键盘状态,而不是实际获得按键的程序。死掉的钥匙确实起到了作用。

    硬键盘,wh_需要一个钩子,你不能用托管代码来写。您需要一个可以在每个进程中注入的非托管DLL。一旦你知道了,我就不必再费心键盘钩子了,还不如用wh-callwndproc来记录wm-char消息。

    示例dll可用 here .

        3
  •  1
  •   Community Nick Dandoulakis    10 年前

    你在这里看到的可能是当涉及到一个死键时,试图映射一个键的效果。键盘映射是一个相当复杂的过程,在产生这种行为的某些类型的键上有很多陷阱。

    我鼓励你读一下迈克尔·卡普兰的博客系列文章。它帮助我解决了许多错误。

        4
  •  0
  •   JustBoo    14 年前

    鉴于目前的答案和对国际行为的参考,您可能需要考虑“代码页”。代码页根据国家而变化。

    国家代码页示例

    • 美国,英国437
    • 多语种850
    • 斯拉夫852
    • 葡萄牙语860
    • 冰岛语861
    • 加拿大、法国863
    • 斯堪的纳维亚语/北欧865

    More Info

    MSDN Info

    Internationalization for Windows Applications