3

I'm creating a custom keyboard layout. As the beginning step, I want to have the user press a key, have my keyboard hook intercept it, and output a different key of my choosing.

I found this keyboard hook code, which I'm trying to slightly modify for my purposes: http://blogs.msdn.com/toub/archive/2006/05/03/589423.aspx

I've changed the relevant method to this:

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);
}

I want it to declare a new KBD structure object, copy the KBD structure supplied by the keyboard hook into it, modify my object's vkCode to use a different character, and then overwrite the supplied object with my modified version. This should hopefully keep everything the same except for the fact that it writes a different character.

Unfortunately, it's not working. The original keyboard character is typed. The Visual Studio output pane also gets a A first chance exception of type 'System.ArgumentException' occurred in MirrorBoard.exe error.

What can I do here to intercept the keyboard hook and replace it with a character of my choosing?

Thanks!

ck_
  • 3,719
  • 10
  • 49
  • 76

1 Answers1

5

The second parameter for Marshal.PtrToStructure must be a class not a struct and KBDLLHOOKSTRUCT is probably a struct.

Instead you should use it like this:

KBDLLHOOKSTRUCT replacementKey = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
replacementKey.vkCode = 90; // char 'Z'
Marshal.StructureToPtr(replacementKey, lParam, false);
Pent Ploompuu
  • 5,364
  • 1
  • 27
  • 47
  • Visual Studio tells me it's `Marshal.PtrToStructure(IntPtr ptr, object structure);` ... does that jive with what you're saying? It doesn't throw an error or anything, compiles just fine. – ck_ Jan 14 '10 at 07:39
  • It compiles fine but throws an `ArgumentException` at runtime. – Pent Ploompuu Jan 14 '10 at 07:41
  • Why would it be called PtrToStructure if it wasn't saving the Ptr into a Structure? But if I do need to change it, what should I do here? If I can't use a KBD structure to save the pointer to a KBD structure how do I modify it? – ck_ Jan 14 '10 at 07:47
  • `PtrToStructure` cannot save the ptr to a struct because it's boxed (i.e. it's a copy). I added the correct solution to my answer. – Pent Ploompuu Jan 14 '10 at 07:52
  • You can also look at the documentation at http://msdn.microsoft.com/en-us/library/30ex8z62.aspx - it says there: You cannot use this overload method with value types. – Pent Ploompuu Jan 14 '10 at 07:56
  • Great, thank you very much. Maybe you have a suggestion for the next issue that's popped up? I'm updating the question. – ck_ Jan 14 '10 at 07:58
  • I think you should make a separate question out of that. – Pent Ploompuu Jan 14 '10 at 08:07
  • Thanks, marked you as the answer for this one. Here's the new question: http://stackoverflow.com/questions/2062978 – ck_ Jan 14 '10 at 08:36