Sending Keystrokes to a Program

Microsoft® Windows® 2000 Scripting Guide

By providing scripts with access to most COM objects, WSH enables you to automate applications that have a COM-based object model. Unfortunately, some applications, especially older ones, do not have a COM-based object model. To automate these applications, WSH provides a way to send keystrokes to these applications.

When you use the WshShell SendKeys method to send keystrokes to an application, your script mimics a human typing on the keyboard. To send a single keyboard character, you pass SendKeys the character itself as a string argument. For example, "x" to send the letter x. To send a space, send the string " ". This is exactly what a user would do if he or she was working with the application: to type the letter x, the user would simply press the x key on the keyboard.

When you use the SendKeys method, special keys that do not have a direct text representation (for example, CTRL or ALT) are represented by special characters. Table 3.16 lists these SendKeys representations for commonly used keys.

Table 3.16 SendKeys Representations of Common Keys

Key

SendKeys Representation

BACKSPACE

{BACKSPACE}, {BS}, or {BKSP}

BREAK

{BREAK}

CAPS LOCK

{CAPSLOCK}

DEL or DELETE

{DELETE} or {DEL}

DOWN ARROW

{DOWN}

END

{END}

ENTER

{ENTER} or ~

ESC

{ESC}

HELP

{HELP}

HOME

{HOME}

INS or INSERT

{INSERT} or {INS}

LEFT ARROW

{LEFT}

NUM LOCK

{NUMLOCK}

PAGE DOWN

{PGDN}

PAGE UP

{PGUP}

PRINT SCREEN

{PRTSC}

RIGHT ARROW

{RIGHT}

SCROLL LOCK

{SCROLLLOCK}

TAB

{TAB}

UP ARROW

{UP}

SHIFT

+

CONTROL

^

ALT

%

BACKSPACE

{BACKSPACE}, {BS}, or {BKSP}

All function keys, like F1, are represented by the button name contained within braces for example, {F1} for the F1 button and {F2} for the F2 button.

For example, the following script starts Notepad and then types the sentence, "This is a test."

Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run "Notepad.exe"
Do Until Success = True
    Success = objShell.AppActivate("Notepad")
    Wscript.Sleep 1000
Loop
objShell.SendKeys "This is a test."

When the script runs, Notepad will open, and the sample sentence will be typed in, as shown in Figure 3.12.

Figure 3.12 Controlling Notepad by Using SendKeys

sas_wsh_114s

Note

  • You can send repeated keystrokes by using the SendKeys method. For example, to send the letter a ten times, you send the string "{a 10}". You must include a space between the keystroke and the number. SendKeys allows you to send only repeated single keystrokes. You cannot send multiple characters using repeated keystrokes; for example, this command will fail: {dog 10}.

You should be aware that sending keystrokes to an application is not the optimal method for automating a procedure. If you have an application in your enterprise that you need to automate and it has no COM-based object model, you might consider this technique. However, you should first examine whether other methods exist for automating that particular application.

Although SendKeys can be used effectively, there are several potential problems with this approach:

  • The script might have difficulty determining which window to send the keystrokes to.

  • Because the application runs in GUI mode, a user might close the application prematurely. Unfortunately, this will not terminate the script, and the script could end up sending keystrokes to the wrong application.

  • The script might have difficulty synchronizing with the application.

This timing issue is especially troublesome, simply because scripts tend to run much faster than GUI applications. For example, this simple script, which starts Calculator and then tries to type the number 2 into the application, is coded correctly but will likely fail when run (Calculator will start, but the number 2 will not be entered):

Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run "Calc.exe"
objShell.AppActivate "Calculator"
objShell.SendKeys "2"

The script fails not because of a syntax issue but because of a timing issue. As quickly as it can, the script issues commands to:

  1. Start Calculator.

  2. Switch the focus to Calculator (using the AppActivate method).

  3. Send the number 2 to Calculator.

Unfortunately, the script runs faster than Calculator can load. As a result, the number 2 is sent, and the script terminates, before Calculator can finish loading and start accepting keystrokes.

There are at least two ways of working around this problem. First, you might be able to estimate how long it will take an application to load and then pause the script for that amount of time. For example, in this script the Run method is called, and then the script pauses for 5 seconds, giving Calculator time to load:

Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run "Calc.exe"
Wscript.Sleep 5000
objShell.AppActivate "Calculator"
objShell.SendKeys "2"

Of course, is some cases it might be difficult to estimate how long it will take before an application is loaded and ready to accept keystrokes. In that case, you can call the AppActivate method and check the return value.

Using AppActivate

Before sending keystrokes to an application, you must first ensure that the application is running and that the focus is on the application (that is, the application is running in the active window). You can use the AppActivate method to set the focus on an application. The AppActivate method brings the specified window to the foreground so that you can then start using the WshShell SendKeys method to send keystrokes to the application.

The AppActivate method takes a single parameter that can be either a string containing the title of the application as it appears in the title bar or the process ID of the application. The AppActivate method returns a Boolean value that indicates whether the procedure call has been successful. If the value is False, AppActivate has failed, usually because it was unable to find the application (possibly because that application had not finished loading).

You can place your script in a loop, periodically calling AppActivate until the return value is True. At that point, the application is loaded and prepared to accept keystrokes.

For example, this script checks the return value for AppActivate. If this value is False, the script pauses for 1 second and then checks the value again. This continues until the return value is True, meaning that the application is loaded and ready for use. At that point, the script continues.

Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run "Calc.exe"
Do Until Success = True
    Success = objShell.AppActivate("Calculator")
    Wscript.Sleep 1000
Loop
objShell.SendKeys "2"

When the script is determining which application to activate, the given title is compared to the title of each window visible on-screen. If no exact match exists, the AppActivate method sets the focus to the first window whose title begins with the given text. If a window still cannot be found, the first window whose title string ends with the text is given the focus. The partial matching with the leading and trailing text of title bars ensures that AppActivate works with applications, such as Notepad, that display the name of the currently opened document on the title bar. (For example, when you first start Notepad, the window title is Untitled - Notepad, not Notepad.)

This means that when setting the focus to the Calculator, you can use one of the following lines of code:

objShell.AppActivate "Calculator"
objShell.AppActivate "Calc"
objShell.AppActivate "C"

Of course, this shortcut method of referring to a window can cause problems. For example, suppose you use this line of code:

objShell.AppActivate "Calc"

If you happen to be working on a Microsoft Word document named Calculations.doc, the keystrokes might be sent to the Word document instead of Calculator.

The script in Listing 3.30 demonstrates a more practical use of the SendKeys method: It starts and sets focus to the Microsoft Management Console (MMC) and then sends keystrokes that cause the Add/Remove Snap-in and Add Standalone Snap-in dialog boxes to be displayed. The script automates the first part of the common task of constructing custom MMC snap-in tools.

Listing 3.30 Sending Keystrokes to a GUI Application

  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Const iNormalFocus = 1
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run "mmc.exe",iNormalFocus
Wscript.Sleep 300
objShell.AppActivate "Console1"
Wscript.Sleep 100
objShell.SendKeys "^m"
Wscript.Sleep 100
objShell.SendKeys "{TAB}"
Wscript.Sleep 100
objShell.SendKeys "{TAB}"
Wscript.Sleep 100
objShell.SendKeys "{ENTER}"