DuckMaestro
DuckMaestro

Reputation: 15885

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?

Upvotes: 3

Views: 7041

Answers (5)

Ulyouth
Ulyouth

Reputation: 61

You have have to use PostMessage instead of SendMessage, then it should work.

PS: 9 years late I know

Upvotes: 0

Blaine Fredrickson
Blaine Fredrickson

Reputation: 91

I found I could do movement around an HTML form (Chrome Browser) from within a C# program by using sendmessage to the process #.

However, I couldn't insert text into an input field. Tried most everything (from pure C#).

While hacking, I noticed I could pop-up a context editing menu while the cursor was on the input I was trying to set, and one of the items on the menu was paste! WhatDoYouKnow! I could interact with that!

Here are the codes I used, once I had tabbed to the input I wanted to set:

Clipboard.SetText("52118"); // from C#, put the input value onto the clipboard

chrome.SendKey((char)93); // char 93 opens pop-up menu that includes paste
System.Threading.Thread.Sleep(30);
chrome.SendKey((char)0x28); // down to the first menu item
System.Threading.Thread.Sleep(30);
chrome.SendKey((char)0x28); // down to the second menu item (paste)
System.Threading.Thread.Sleep(100);
chrome.SendKey((char)0x0D); // fire the paste

Check here for the code used for the ChromeWrapper (Thanks for that!):

Sending keyboard key to browser in C# using sendkey function

Upvotes: 0

Drew Delano
Drew Delano

Reputation: 1499

You were so close! The handle reported by WebBrowser.Handle is the outter most handle, while all of the input is directed to the inner most handle:

var hwnd = _browser.Handle;
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Shell Embedding", null);
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Shell DocObject View", null);
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Internet Explorer_Server", null);

SendMessage(hwnd, WM_CHAR, new IntPtr(0x0D), IntPtr.Zero);

FindWindowEx definition from pinvoke.net:

[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

Highlighted is the WebBrowser control: Highlighted is the WebBrowser control

Upvotes: 1

DuckMaestro
DuckMaestro

Reputation: 15885

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 }

.

Upvotes: 3

Erx_VB.NExT.Coder
Erx_VB.NExT.Coder

Reputation: 4856

Well i'm only used to using this in VB6 but Try sending to myWebBrowser.object.Handle or myWebBrowser.object.HWND is what i see in VB6, but you probably have .Handle in your .net version.

try the .object and let me know how it goes!!

Upvotes: 0

Related Questions