Search code examples
c#wpfwinapikeyboardwebbrowser-control

How to send keystrokes to WebBrowser?


I would like to simulate keystrokes within an embedded System.Windows.Controls.WebBrowser. Various techniques for simulating keystrokes are documented already here on StackOverflow, however they do not seem to work for the WebBrowser control.

Knowing that the control wraps another window/hwnd, I would have expected the following to work however it's not:

[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);

...

SendMessage(myWebBrowser.Handle, WM_CHAR, key, 0);

I am already using SendMessage to forward simulated keystrokes to other parts of the WPF application, and would prefer a consistent solution; however this is failing for the WebBrowser.

How can I forward simulated keystrokes to WebBrowser?


Solution

  • My solution was to use SendInput() instead of SendMessage().

    The import:

    [DllImport("user32.dll", SetLastError = true)]
    public static extern uint SendInput(uint nInputs, User32.Input[] pInputs, int cbSize);
    

    For the additional types and constants see here: http://pinvoke.net/default.aspx/user32/SendInput.html

    For the expected behavior see here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v=vs.85).aspx.

    My virtual keypress method:

    private void VirtualKeypress(Key keyCode, bool shift, char keyChar)
    {
        User32.Input[] inputSequence;
        if (keyChar == '\0' && keyCode == Key.None)
        {
            throw new ArgumentException("Expected a key code or key char, not both.");
        }
        else if (keyChar != '\0')
        {
            inputSequence = KeyboardUtils.ConvertCharToInputArray(keyChar);
        }
        else
        {
            inputSequence = KeyboardUtils.ConvertKeyToInputArray(keyCode, shift);
        }
    
        User32.SendInput(
            (uint)inputSequence.Length, 
            inputSequence, 
            Marshal.SizeOf(typeof(User32.Input))
        );
    }
    

    I have two helper methods, ConvertCharToInputArray() and ConvertKeyToInputArray(), which return an array of length 2 or 4 depending if we need to tell windows that the shift key is depressed. For example:

    'A' -> [] { shift down, A down, A up, shift up }
    

    while just

    'a' -> [] { A down, A up }
    

    .