-
-
Notifications
You must be signed in to change notification settings - Fork 412
Automation With Autohotkey
If you need to send keystrokes or mouse clicks to a Windows app (e.g. an installer), AutoHotkey is usually the tool for the job.
It has quite a bit of documentation, and a quick-start tutorial. The most useful documentation is its command reference. AutoHotkey for Winetricks contributors
Winetricks takes care of installing and starting autohotkey for you; all you have to do is call w_ahk_do with the desired autohotkey commands.
Let's try the canonical autohotkey example: starting Notepad and typing some text. To do this, create a file named hello.verb
containing these lines:
w_metadata hello apps \
title="Hello, Autohotkey"
load_hello()
{
w_ahk_do "
Run notepad.exe ; Comments start with semicolons
WinWait Untitled - Notepad ; Wait for a window with this exact title to appear
Send hello, autohotkey ; Act as if the user typed those words at the keyboard
"
}
Then try running it with winetricks hello.verb
.
You should see Notepad open, and "Hello, autohotkey" appear in its document window.
Documentation for the AutoHotkey commands used above:
Run
WinWait
Send
Here's a simple verb that doesn't (yet) support winetricks' -q option for silent installation. Create a file called aoe_example.verb
containing:
w_metadata aoe_example games \
title="Age of Empires Demo" \
publisher="Microsoft" \
year="1997" \
media="download" \
file1="MSAoE.exe" \
installed_exe1="$W_PROGRAMS_X86_WIN/Microsoft Games/Age of Empires Trial/empires.exe"
load_aoe_example()
{
w_download http://download.microsoft.com/download/aoe/Trial/1.0/WIN98/EN-US/MSAoE.exe
cd "$W_CACHE/$W_PACKAGE"
w_try $WINE MSAoE.exe
}
It's a good verb. You can use it with winetricks aoe_example.verb
, and it will run the installer faithfully.
If you want your verb to obey winetricks -q
(unattended install) option, though, you'll have to do a bit more.
The goal of unattended mode is to complete the installation without asking the user any questions. It's good to show progress bars during long operations even in unattended mode, so don't suppress those if you can help it.
First, check to see if the installer supports a command-line option for unattended or silent install (e.g. /S
). If it does, use that instead of autohotkey; see OpenTTD for an example.
If you've looked and looked, and there's no way to script an unattended install from the command-line, you can use autohotkey to script the installer's GUI.
The basic motif of scripting an install with Autohotkey is to wait for a window with a particular name (and maybe particular body text) to show up, answer its question (if any) by clicking a button, and then click the 'next' button.
For example, to get past the welcome dialog of an installer, you might try:
WinWait, Microsoft Age of Empires ControlClick, Button1 ; Next
To figure out what commands are needed, start by changing your function so Autohotkey just runs the installer and then waits forever. Here's an example including standard boilerplate options:
load_aoe_example()
{
w_download http://download.microsoft.com/download/aoe/Trial/1.0/WIN98/EN-US/MSAoE.exe
cd "$W_CACHE/$W_PACKAGE"
w_ahk_do "
SetWinDelay 1000 ; wait extra second after each WinWait
SetTitleMatchMode, 2 ; allow matching substrings
Run MSAoE.exe
WinWait nosuchwindow ; We will change this later
"
}
SetWinDelay is needed because installers often aren't ready for keystrokes or mouse clicks right after a window appears.
SetTitleMatchMode, 2 means future WinWait
statements should match windows given only a fragment of their full title.
Run that as before with winetricks aoe_example.verb
. Note that an 'H' icon will show up in your system tray; this is Autohotkey's status icon. Right-click on that 'H' icon and select "Window Spy", then click on the installer window's title bar. This will bring up a little window that tells you interesting stuff about the active window and whatever the mouse is pointing at in that window.
Go ahead and install as normal, but before you answer the installer's questions, fire up your editor, put the cursor in between the run and WinWait
lines in your function, and start writing the Autohotkey commands for what you do as you do it. A few examples:
- Do you have to press the Enter key? Then write send {Enter}.
- Do you have to click a button? Then use the Spy utility you started above to find out the button's name, and write ControlClick, buttonName. Alternately, figure out what key to send, and use send to send it.
- After you click 'Next', be sure to wait for the change to take effect, e.g. by writing
WinWait, windowname, unique text in window
. Otherwise your next click might be sent before the installer is ready! - Be sure to wait for the last window to close by writing WinWaitClose.
You should end up with something like this:
load_aoe_demo()
{
w_download http://download.microsoft.com/download/aoe/Trial/1.0/WIN98/EN-US/MSAoE.exe
cd "$W_CACHE/$W_PACKAGE"
w_ahk_do "
SetWinDelay 1000
SetTitleMatchMode, 2
Run, MSAoE.exe
WinWait, Microsoft Age of Empires
ControlClick, Button1
WinWait, End User License
ControlClick, Button1
WinWait, Microsoft Age of Empires, Setup will install
ControlClick Button2
WinWait, Microsoft Age of Empires, Setup has successfully
ControlClick Button1
WinWaitClose
"
}
But this will always install automatically, regardless of whether the user invokes winetricks with -q
. Let's make sure it only runs the Autohotkey script when the user wants an unattended install. Here's how:
load_aoe_demo()
{
w_download http://download.microsoft.com/download/aoe/Trial/1.0/WIN98/EN-US/MSAoE.exe
cd "$W_CACHE/$W_PACKAGE"
w_ahk_do "
SetWinDelay 1000
SetTitleMatchMode, 2
Run, MSAoE.exe
WinWait, Microsoft Age of Empires
if ( w_opt_unattended > 0 ) {
ControlClick, Button1
WinWait, End User License
ControlClick, Button1
WinWait, Microsoft Age of Empires, Setup will install
ControlClick Button2
WinWait, Microsoft Age of Empires, Setup has successfully
ControlClick Button1
}
WinWaitClose
"
}
Finally, test your verb again with sh winetricks -q aoe_example
(shouldn't require any user intervention), and and sh winetricks aoe_example
(should require user to answer all questions).
Help! The installer is ignoring something I'm sending it!
The most common cause of this is the previous WinWait
being too general, and returning before the previous input takes effect. Each WinWait
should wait for some unique text; since titles usually don't change, that means you need to do WinWait, windowtitle, unique text
from body of new screen.
Some installers have dialogs that only show up under certain conditions. The general technique for handling these is to have a loop which waits for either of the optional dialog(s), and handles them. The loop continues until it sees the dialog after the optional ones, at which point it exits and flow returns to normal. For examples, here's how the dotnet11
verb does it:
Loop
{
Sleep 1000
If WinExist, Fatal error, Failed to delay load library
{
WinClose, Fatal error, Failed to delay load library
Continue
}
Process, exist, dotnetfx.exe
dotnet_pid = %ErrorLevel% ; Save the value immediately since ErrorLevel is often changed.
If dotnet_pid = 0
{
Break
}
}
Documentation for the AutoHotkey commands/control flow statements/expressions used above:
Loop
Block
Sleep
IfExpression
WinExist
WinClose
Continue
Process
ErrorLevel
Break
To find more examples, search for Loop
in the winetricks script.