SendKeys

Description

The existing SendKeys class does not have a managed way to activate an external application. MSDN recommends that you should use the FindWindow and SetForegroundWindow APIs. However, this alone does not ensure that the desired application will have keyboard focus while the keys are being sent. This replacement module sends keys directly to the specified window without error. I hope!

Before I get into any details of what’s under the hood of the attached SendKeys modules, I want to explain how developers can get working with it right away. Download the SendKeys module—choose either the .NET or VB 6 version—at the bottom of this post and unzip it. Add it to your project by pressing the Ctrl+d key combination. Now, point and click on the module you’ve downloaded and unzipped.

Once you’ve added the module to your project, all you have to do is type in “SendKeys” to view available methods. The Intellisense window in VB2005-VB2008 will pop up with a detailed description of how to use a function or any one of its parameters.

Get a Handle on Things

In many cases, you can send or post a message directly to a window, without changing the foreground window at all. Create a new Notepad document on the desktop and then open it. It should be named “New Text Document – Notepad” for the following demo. To obtain the handles of the windows with focus, just use the WINFOCUS structure returned by the GetWinFocus or the GetWinHandles function. If true is specified in the showNames parameter of the GetWinFocus function, the text and class names of the ancestors will be shown in a messagebox. This helps you find the path of the windows, which can be used in GetWinHandles.

If you want to get the handles of the windows that currently have keyboard focus.

'Place focus on that window during the next 3 seconds
SendKeys.Sleep(3000)
Dim w As New SendKeys.WINFOCUS
w = SendKeys.GetWinFocus(True, True)
MessageBox.Show(w.Foreground.ToString & vbCrLf & w.Focus.ToString)

If you want to get the handle of a child window that’s on a main window, that is to receive keyboard focus. This will get the handle of the first editable window inside of a notepad, and the handle of the first notepad itself.

Dim w As New SendKeys.WINFOCUS
w = SendKeys.GetWinHandles("New Text Document - Notepad", 1, "Edit", 1)
MessageBox.Show(w.Foreground.ToString & vbCrLf & w.Focus.ToString)

If you want to get the handle of the main window by its application title.

Dim w As New SendKeys.WINFOCUS
w = SendKeys.GetWinHandles("New Text Document - Notepad")
MessageBox.Show(w.Foreground.ToString & vbCrLf & w.Focus.ToString)

If you want to get the handle of the main window by its class name.

Dim w As New SendKeys.WINFOCUS
w = SendKeys.GetWinHandles("Notepad")
MessageBox.Show(w.Foreground.ToString & vbCrLf & w.Focus.ToString)

If you want to get the handle of the main window by its process name.

Dim w As New SendKeys.WINFOCUS
w = SendKeys.GetWinHandles("notepad.exe")
MessageBox.Show(w.Foreground.ToString & vbCrLf & w.Focus.ToString)

If you want to get the handle of the main window of a new process with a valid file path.

Dim sSystem As String = ""
sSystem =  System.Environment.SystemDirectory.Substring _
(0, System.Environment.SystemDirectory.Length - 9)
Dim w As New SendKeys.WINFOCUS
w = SendKeys.GetWinHandles(sSystem & "\notepad.exe")
MessageBox.Show(w.Foreground.ToString & vbCrLf & w.Focus.ToString)

If you want to get the handle of window, by using special commands, enclose them in brackets. See the GetCommands sub for more info.

SendKeys.Sleep(3000)
Dim w As New SendKeys.WINFOCUS
w = SendKeys.GetWinHandles("{foreground}")
MessageBox.Show(w.Foreground.ToString & vbCrLf & w.Focus.ToString)

Recommended

All you need to do now is insert the focus handle structure into the parameter of the Text function. This will erase any existing text and write “Hello!” to the window with the blinking caret—a Notepad.

SendKeys.Text("Hello!", w)

If you want to press a key only down or up, use the Message function.

SendKeys.Message(Keys.Space, w)

This will send the space key down, and up, to safely press a button, or a checkbox that is in focus. You may specify up or down if you want to send key combinations. If these methods do not work on an external window, it’s usually because there is some dynamic operation being invoked by your input.

For example, pressing a button can cause some dynamic operation to be invoked before the key message is sent up. You can try setting the last parameter to True, so that the message is posted into the queue, instead of waiting for a return.

Secondary

In some cases, this is just not enough, and you may need to inject these keys, similar to the way that the SendKeys class does, by typing them in, on a virtual keyboard. For more information about the SendKeys class, visit MSDN.

If you want to inject text into a window.

Dim w As New SendKeys.WINFOCUS
w = SendKeys.GetWinHandles("New Text Document - Notepad", 1, "Edit", 1)
SendKeys.Send("Hello", w)

If you want to send a key command, enclose it within brackets.

Dim w As New SendKeys.WINFOCUS
w = SendKeys.GetWinHandles("Form1", 1, "GroupBox1", 1, "GroupBox2", _
   1, "GroupBox3", 1, "Start", 1)
SendKeys.Send("{space}", w)

If you want to call the send method in one line, insert the return value of the GetWinHandles function.

SendKeys.Send("Hello", SendKeys.GetWinHandles("New Text Document - _
   Notepad", 1, "Edit", 1))

If you want to send input to the current foreground window.

'Place focus on notepad during these 3 seconds
SendKeys.Sleep(3000)
SendKeys.Send("Hello", Nothing)

If you want to send keys as an event, and then return the foreground window to it’s previous position before the call, specify false in the asMessage parameter, and true in the rForeground parameter.

'Place focus on a second notepad during these 3 seconds
SendKeys.Sleep(3000)
Dim w As New SendKeys.WINFOCUS
w = SendKeys.GetWinHandles("New Text Document - Notepad", 1, "Edit", 1)
SendKeys.Send("Hello", w, False, True)

More by Author

Must Read