使用低级键盘挂钩来更改键盘字符

3
我正在创建一个自定义键盘布局。作为开始步骤,我希望用户按下一个键,我的键盘钩子拦截它,并输出我选择的不同键。
我发现了这个键盘钩子代码,我正在尝试略微修改以适应我的目的:http://blogs.msdn.com/toub/archive/2006/05/03/589423.aspx 我已将相关方法更改为:
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
    if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
    {
        KBDLLHOOKSTRUCT replacementKey = new KBDLLHOOKSTRUCT();
        Marshal.PtrToStructure(lParam, replacementKey);
        replacementKey.vkCode = 90; // char 'Z'
        Marshal.StructureToPtr(replacementKey, lParam, true);
    }
    return CallNextHookEx(_hookID, nCode, wParam, lParam);
}

我希望它声明一个新的KBD结构对象,将键盘钩子提供的KBD结构复制到其中,将我的对象的vkCode修改为使用不同的字符,然后用我修改后的版本覆盖提供的对象。这样应该能保持一切不变,除了它写入不同的字符。
不幸的是,它没有起作用。原始键盘字符被输入。Visual Studio输出窗格也会出现“MirrorBoard.exe中发生了System.ArgumentException类型的第一次机会异常”错误。
在这里我该怎么办才能拦截键盘钩子并用我选择的字符替换它呢?
谢谢!
1个回答

5
Marshal.PtrToStructure的第二个参数必须是一个类,而不是一个结构体,KBDLLHOOKSTRUCT很可能是一个结构体。

你应该像这样使用它:

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

如果它不是将Ptr保存到Structure中,为什么要称其为PtrToStructure呢?但是,如果我确实需要更改它,我应该怎么做?如果我不能使用KBD结构保存指向KBD结构的指针,那该如何修改呢? - ck_
PtrToStructure 无法保存指向结构体的指针,因为它被装箱了(即它是一个副本)。我在我的答案中添加了正确的解决方案。 - Pent Ploompuu
您还可以查看http://msdn.microsoft.com/en-us/library/30ex8z62.aspx上的文档,其中写道:您不能使用此重载方法来处理值类型。 - Pent Ploompuu
非常好,非常感谢。也许你对下一个问题有建议?我正在更新问题。 - ck_
我认为你应该将那个问题单独拆分成一个独立的问题。 - Pent Ploompuu
显示剩余3条评论

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