標籤:

【指南】自動化操作輕鬆入門

轉者按:本文屬於新手指南系列教程,原發表於博客中國(已失效),我曾轉載到中文論壇,作者 yonken(此處是他現在的博客,但原來的很多 AutoHotkey 內容丟失了)。本系列選取一些通俗易懂的基礎入門教程(目前計劃 3 ~ 5 篇),經適當整理(以反映目前 AutoHotkey 現狀)後集中發表,以方便零基礎的朋友入門(幫助中的初學者嚮導也是很好的入門教程)。註:原文所附圖片難以找到,後面的圖片來自網路,若含 logo,均非原作者或我所加。

前言:據我了解需要編寫 AutoHotkey/AutoIt 腳本來實現自動化操作的用戶很多都是網管,其它則可能是一些個人用戶,他們一般都具有相當的技術水平,而且都希望能藉助腳本來完成某些以往需要人工操作的重複性勞動,但限於語言條件上的限制可能對官方的幫助文檔有較難理解之處。為方便讀者,我將從最簡單的說起,每個示例儘可能同時給出相應的 AHK 和 AU3 版本代碼。本文將儘可能用較通俗的語言描述,但並不打算講解語法基礎,所以不一定適合新手閱讀。

文中涉及到的 AHK/AU3 版本(註:這個是最初編寫時的版本):

  • AutoHotkey 1.0.44 .08
  • AutoIt 3.1.1

關於腳本

什麼是腳本?

這是個非常「流行」的術語了,通俗而言腳本(Script)一般都是指根據某種語法規則編寫的具有特定格式的文本文件。可能大家已經聽說過很多種腳本:VBScript、JScript、PHP、ASP、JSP、CGI、CS 腳本,甚至遊戲工具腳本。

這些腳本文件都是可執行文件,可執行相應的操作。

  • AHK 腳本文件擴展名:*.ahk
  • AU3 腳本文件擴展名:*.au3

腳本和程序的不同?

嚴格來說,所謂「程序」就是指以各種編程語言(比如說 C/C++/C#/Delphi)編寫、由編譯器編譯好後的二進位文件,一般就是機器代碼,可由系統執行。而腳本則是只是些純文本文件,包含了各種定義好的命令,這一點很像批處理文件。這樣,我們得出一個簡單的結論,那就是用戶一般無法獲得「程序」的源代碼,我們只能進行反彙編把它逆向還原為彙編語言代碼(或其它),當然,也有些「程序」是可以獲得源代碼的(比如 Java);腳本則是用戶可直接查看的代碼文件,而 AHK/AU3 則提供了把腳本文件「轉換」成可執行文件的方法。

腳本如何運行?

腳本是「解釋性」的語言,它 的運行依賴一個「解釋器」,由這個解釋器來「翻譯並解釋」腳本的每條命令(或者說代碼),然後執行相應操作。如果不嚴格定義的話,HTML 和 Java 都可以認為是解釋性語言。AHK/AU3 的主程序(分別是 AutoHotkey.exe 和 AutoIt3.exe)就是它們的「解釋器」,上面提到腳本可「轉換」成可脫離相應的解釋器而獨立運行的可執行文件,而我們還可以使用相應的工具把它們「還原」成腳本文件,由此我們完全可以這麼理解:腳本代碼是被 「壓縮」到這個可執行文件中,解釋器也是在裡面,在運行可執行文件時實際上是先「解壓」腳本代碼然後運行解釋器並解釋該腳本。

如何創建腳本?

使用資源管理器的右鍵菜單即可創建相應腳本文件,或者新建一個文本文件後改擴展名即可。

稍微介紹一點語法規則?

A)對 AHK 而言,每個內建的功能是以「命令」的形式提供:

Command, param1, param2,…

而 AU3 則以「函數」的形式提供:

Function(param1, param2, …)

命令或函數中被符號「[」和「]」圍住的參數是可選參數,表示在使用這些命令或函數時可省略它們(不給出具體數值)。

若某個參數含有空格,則最好使用雙引號圍住該參數。

B)解釋器自上而下(從第一行到最後一行)「解釋」腳本中的每行語句,除非遇到「Return」、「Goto」、「Gosub」、「Exit」等語句、函數、熱鍵或其它能使腳本「跳」到某個標識符的條件成立。

C)關鍵字和標識符(包括變數名、命令名、函數名等)都不區分大小寫。

運行程序或打開文件

運行程序

Run 命令或者函數用來運行外部可執行文件,AHK還可利用它來直接打開文件。

AHK:Run, 目標文件 [, 工作目錄, Max|Min|Hide|UseErrorLevel, 輸出PID變數]

AU3:Run ( "文件名" [, "工作目錄" [, 標誌]] )

【示例 2.1.1 】

AHK:Run, Notepad.exe

AU3:Run("Notepad.exe")

上面的示例中都沒有給出程序「Notepad.exe」的路徑,為什麼仍能執行?這是因為它們都會自動在腳本所在目錄下搜尋目標文件,如有則運行,否則就到系統文件夾(%PATH%)中搜尋。

注意:

A)某些程序必須給定「工作目錄」才能成功運行!

B)給出完整的文件路徑有助於輕微提高程序的可靠性。

C)AHK 的 Run 命令可以用來運行程序和直接打開文件,而 AU3 的 Run 函數則只能用來運行程序(可執行文件)或傳遞參數讓某個程序打開目標文件。

當然,運行程序的功能還不僅僅是這麼簡單,我們還可以指定運行程序的初始狀態,比如讓運行的記事本窗口以最大化狀態顯示(或者最小化、隱藏):

【示例 2.1.2 】

AHK:Run, Notepad.exe, , Max

AU3:Run("Notepad.exe", "", @SW_MAXIMIZE)

打開文件

前面已經提到,AHK 的 Run 命令可以直接打開文件,而 AU3 的 Run 函數則只能用來運行程序,因此在打開文件的方式上有點不同:AHK 腳本中可直接給出目標文件,而 AHK 將自動運行該文件的關聯程序來打開它;而 AU3 則必須由用戶自己傳遞參數讓某個程序打開目標文件。

【示例 2.2.1 】

AHK:

Run, MyFile.txt

Run, Notepad.exe MyFile.txt

AU3:Run("Notepad.exe MyFile.txt")

以命令行形式運行程序

可以考慮運行系統的命令行解釋器(cmd.exe/command.com),然後指定要執行的命令並傳遞參數。

假設我們要執行命令「dir C:WINDOWSsystem 32」 ,用以列出指定目錄的所有文件及子目錄。

【示例 2.3.1 】

AHK:Run, %ComSpec% /k dir C:WINDOWSsystem32

AU3:Run(@ComSpec & " /k dir C:WINDOWSsystem32")

注意:

A)%ComSpec% 是腳本內建的用以指示命令行解釋器位置的變數或宏。

B)/k 參數表示「執行字元串指定的命令但保留」,若改為 /c 則表示「執行字元串指定的命令然後終斷」。對此比較直觀的解釋是 /k 將在執行完命令後保留命令提示窗口,而 /c 則將在執行完命令之後關閉命令提示窗口。

C)符號「&」是 AU3 定義的字元串連接符。

特殊應用

A)打開網頁

【示例 2.4.1 】

AHK:

Run, ahkscript.org/

Run, %A_ProgramFiles%Internet ExplorerIEXPLORE.EXE ahkscript.org/

AU3:Run(@ProgramFilesDir & "Internet ExplorerIEXPLORE.EXE ahkscript.org/")

B)打開特殊文件夾

系統的某些特殊文件夾被定義了相應的 CLSID(請查看 CLSID 列表),我們可利用它來打開相應的文件夾,比如打開回收站:

【示例 2.4.2 】

AHK:Run ::{645ff040-5081-101b -9f 08-00aa 002f 954e}

AU3:不適用!

C)運行控制面板工具

微軟已經為我們提供了通過命令行打開控制面板某個工具或項目的方式,比如打開系統屬性窗口:

【示例 2.4.3 】

AHK:Run control sysdm.cpl

AU3:Run("control sysdm.cpl")

關於訪問控制面板項目的詳細介紹請查看此文:文章地址(原網址已丟失,請自行搜索命令行方式訪問控制面板項目的方法查找其他轉載)。

D)指定搜索位置並打開搜索窗口

假設我們要打開一個搜索窗口,而且要指定搜索位置,比如 C::

【示例 2.4.4 】

AHK:Run, find C:

AU3:不適用!

E)顯示指定文件的屬性窗口

假設我們要打開文件「MyFile.txt」的屬性窗口,則使用關鍵字 properties 然後接上目標文件即可:

【示例 2.4.5 】

AHK:Run, properties MyFile.txt

AU3:不適用!

注意:AHK 在退出前將自動關閉打開的屬性窗口!

F)用「資源管理器」打開指定文件夾

我們知道使用 Run, explorer C: 或 Run("explorer C:") 即可打開指定的文件夾,可是有時候我們需要在資源管理器中打開它,這時可使用關鍵字 explore(註:前面的 explorer 實際上是資源管理器 explorer.exe 省略擴展名的寫法,而 explore 是 Run 的關鍵字,為動詞,類似於 find/print):

【示例 2.4.6 】

AHK:Run, explore C:

AU3:run("explorer.exe /e,C:")

G)列印指定文件

要列印指定文件,可使用關鍵字 print:

【示例 2.4.7 】

AHK:Run, print MyFile.txt

AU3:不適用!

窗口操作

注意:窗口標題和窗口文本參數總是對大小寫敏感的。

等待窗口系列命令/函數

AHK 和 AU3 都提供了用法類似的一組窗口等待命令/函數:WinWait/WinWaitActive/WinWaitClose。

它們分別用於等待窗口出現、等待窗口被激活、等待窗口被關閉。由於這些命令/函數的參數類似,現僅以WinWait為例說明。

AHK:WinWait [, 窗口標題, 窗口文本, 超時時間, 排除標題, 排除文本]

AU3:WinWait ( "窗口標題" [, "窗口文本" [, 超時時間]] )

WinWait 的作用是在目標窗口出現之前不再執行後面的所有語句。

假設我們要運行記事本程序,並在其窗口出現時提示用戶:

【示例 3.1.1 】

AHK:

Run NotepadWinWait, 無標題 - 記事本MsgBox 記事本窗口已被打開!

AU3:

Run("Notepad")WinWait("無標題 - 記事本")MsgBox(0, "", "記事本窗口已被打開!")

激活窗口相關命令/函數

讓目標窗口成為活動窗口的辦法就是激活它,可用的命令/函數是 WinActivate:

AHK:WinActivate [,窗口標題, 窗口文本, 排除標題, 排除文本]

AU3:WinActivate ( "窗口標題" [, "窗口文本"] )

關閉窗口

關閉窗口有兩種方式,一種是正常的關閉窗口(WinClose),另一種則是強行關閉窗口(WinKill):

AHK:WinClose/WinKill [,窗口標題, 窗口文本, 超時時間,, 排除標題, 排除文本]

AU3:WinClose/WinKill ( "窗口標題" [, "窗口文本"] )

現在我們已經可以實現一個比較簡單的功能了,比如我們可以打開系統屬性窗口並等待其出現,窗口出現後激活它,接著等待 3 秒再關閉它:

【示例 3.1.2 】

AHK:

Run, Sysdm.cplWinWait, 系統屬性WinActivate, 系統屬性WinWaitActive, 系統屬性Sleep, 3000WinClose, 系統屬性WinWaitClose, 系統屬性

AU3:

Run("Control Sysdm.cpl")WinWait("系統屬性")WinActivate("系統屬性")WinWaitActive("系統屬性")Sleep(3000)WinClose("系統屬性")WinWaitClose("系統屬性")

建議:如果程序中頻繁地出現要用到這些窗口標題的地方,會帶來一個問題:腳本的可讀性,也許你會想,這不是很直觀嗎?可問題是如果這個重複出現的窗口標題是個很長的字元串呢?這將嚴重影響整個代碼的排版美觀。而且我們也無從了解這些窗口標題的「來頭」,不知道這個窗口標題究竟是怎麼來的。而如果我們定義一個變數(假設變數名是「AppWindow1」)保存這個窗口標題,我們就能在命令/函數中用變數來表示它,這樣就達到了讓代碼用意更清晰一點的目的。另外,就算目標軟體因某些原因(比如升級)而改變了它的窗口標題,我們也能很方便地作出修改。

更準確的標識窗口的方法(主要針對 AHK 腳本)

程序在運行時起碼會有一個進程,如果能獲得這個進程 ID 就能在一定程度上保證對窗口的準確標識。另外,每個窗口都有定義窗口類名(Class,比如說記事本窗口的類名就是 Notepad),所以我們可以以此排除與目標窗口不同的其它窗口類。其實,我們還有一個更準確的方法:

每個窗口(包括控制項在內)都被Windows指派了一個可區別於其它窗口的唯一的標識符(ID),我們稱之為窗口句柄(HWND)。

直接給定窗口標題來表示窗口的一個缺點就是無法保證在腳本運行的過程中始終以該窗口為操作目標,因為在這個過程中很有可能會有其它「同名」窗口(或者說滿足匹配條件的窗口)出現,而如果我們使用這個標識符來表示窗口自然就能保證命令/函數的操作窗口總是同一個窗口了。

我們先來了解一下獲得窗口句柄的命令/函數:

AHK:WinGet[, 輸出變數, ID, 窗口標題, 窗口文本, 排除標題, 排除文本]

AU3:WinGetHandle ( "窗口標題" [, "窗口文本"] )

其中 WinGet 獲得的窗口 ID 將通過「輸出變數」返回,而 WinGetHandle 的返回值就是獲得的窗口 ID。

我 們在進行自動化操作時是要先運行某個程序,如何獲得這個程序成功運行後顯示的窗口句柄?一個比較保險的辦法是先獲得這個程序的進程 ID,然後根據這個進程 ID獲得它的窗口句柄,AHK 支持使用進程 ID 作為窗口標題使用;但 AU3 不支持這樣使用,只能先獲得該窗口的類名再根據該類名來獲得窗口句柄(不夠保險):

【示例 3.1.3 】

AHK:

Run, NotePad, , , ThisPIDWinWait, ahk_pid %ThisPID% ;這裡的ahk_pid表明跟在後面的變數是進程IDWinGet, ThisID, ID, ahk_pid %ThisPID% ;ThisID將保存獲得的窗口句柄

AU3:

Opt("WinTitleMatchMode", 4)Run("Notepad")$handle = WinGetHandle("classname=Notepad")

現在暫且先忘記了 AU3 吧,因為它的窗口函數一般都不支持使用窗口句柄作為(窗口標題)參數。

至於如何在 AHK 中使用窗口句柄,簡單的說,凡是有「窗口標題」參數的命令就可以用窗口句柄來代替,比如:

【示例 3.1.4 】

AHK:

Run, Notepad, , , ThisPID ;先獲得運行的記事本程序的進程IDWinWait, 無標題 - 記事本 ahk_pid %ThisPID% ;等待該進程窗口的出現WinGet, ThisHWND, ID, 無標題 - 記事本 ahk_pid %ThisPID% ;獲得窗口句柄WinActivate, ahk_id %ThisHWND% ;這裡的 ahk_id 表明跟在後面的變數是窗口句柄WinWaitActive, ahk_id %ThisHWND%Sleep, 3000WinClose, ahk_id %ThisHWND%WinWaitClose, ahk_id %ThisHWND%

模擬鍵擊和滑鼠點擊

模擬滑鼠點擊(按鈕等)控制項

既然是模擬用戶操作,自然就包括了模擬滑鼠點擊在內。

適用命令/函數:Click/MouseClick/ControlClick

其中 Click/MouseClick 用來模擬用戶的物理操作(點擊),把滑鼠點擊事件發送到指定坐標位置(相對當前窗口或絕對位置)上,但這種方法並不能保證 100% 的準確性,屏幕解析度、用戶干擾和系統環境等都會影響到它們的執行結果,而 ControlClick 則直接把滑鼠點擊事件發送到目標窗口的目標控制項上,因而更準確,一般我們不考慮使用坐標位置方式的點擊,下面僅以 ControlClick 為例說明:

AHK:ControlClick [, 目標控制項或坐標位置, 窗口標題, 窗口文本, 滑鼠按鈕, 點擊次數, 選項,排除標題, 排除文本]

AU3:ControlClick ( "窗口標題", "窗口文本", 控制項ID [, 按鈕] [, 點擊次數]] )

對 AHK 而言,「目標控制項」參數是指要點擊的控制項的類別名(ClassNN)或控制項文本,另外還可以使用控制項句柄(若用的是控制項句柄則第一個參數需留空,並在第二個參數中使用 ahk_id %控制項句柄%)。

Q:用什麼工具來獲得目標控制項的這些信息呢?

A:AHK 用戶請使用 Window Spy,AU3 用戶則請使用 AutoIt Window Info,你可以在相應的開始菜單項目里找到它們,或者到安裝目錄下尋找。

Q:如何使用這兩個工具?

A:先打開你要進行操作的目標窗口,然後運行 Window Spy 或 AutoIt Window Info,接下來就是把滑鼠移到目標控制項上(比如某個按鈕):

Window Spy 使用演示截圖:

AutoIt Window Info 使用演示截圖:

現在我們假設已打開並激活了「系統屬性」窗口,而任務是點擊它的「確定」按鈕,則可用以下幾種方法:

【示例4.1.1】

AHK:

ControlClick, 確定, 系統屬性ControlClick, Button2, 系統屬性

AU3:

ControlClick("系統屬性", "", 1)ControlClick("系統屬性", "", "Button2")ControlClick("系統屬性", "", "確定")

提醒:即使目標窗口或控制項是隱藏狀態,ControlClick 命令還是可以「點擊」目標控制項,但不能保證成功率。

模擬鍵盤操作

鍵盤也是我們在操作窗口時會用到的工具,比如說在安裝軟體的時候經典的「一路回車大法」。下面簡單介紹一下模擬鍵盤操作的方法。

Send 是最直接的方法,就是模擬用戶按鍵行為,直接發送鍵擊命令,用法請參考官方文檔,在此不予說明。

最簡單的應用――按回車:

AHK:

Run, Control Sysdm.cplWinWait, 系統屬性Send, {Enter}

AU3:

Run("Control Sysdm.cpl")WinWait("系統屬性")Send("{Enter}")

常見的組合鍵――Alt+X / Ctrl+N 等等,在安裝軟體的時候經常會有提供一個按鈕「下一步(N)」,表示按下 Alt+N 即可觸發等同於點擊該按鈕的效果,其它的可觸類旁通。以打開記事本窗口的「文件」菜單為例:

AHK:

Run, NotepadWinWait, 無標題 - 記事本WinActivate, 無標題 - 記事本WinWaitActive, 無標題 - 記事本Send, !f

AU3:

Run("Notepad")WinWait("無標題 - 記事本")WinActivate("無標題 - 記事本")WinWaitActive("無標題 - 記事本")Send("!f")

控制項操作

然而,在真正實現自動化時僅靠上面的技術往往難以達到預期目的。下面開始進入最為重要的控制項操作。

設置文本

在安裝軟體的過程中用戶往往需要提供一些必需信息,比如安裝目錄。很多用戶並不喜歡把軟體安裝到默認的 C 盤而更願意把它們安裝到別的地方,那麼腳本究竟提供了什麼方法能讓我們修改如下圖所示的路徑呢?

我們先用上文中提到的 Window Spy 或 AutoIt Window Info 來獲得這個路徑的編輯框的信息,假設這個窗口的標題為 Setup foobar,該路徑編輯框的類名是 Edit1,而我們需要把它改成「D:foobar2000」,接下來就可以使用下列命令/函數來設置它的文本了:

AHK:ControlSetText [, 目標控制項, 新文本, 窗口標題, 窗口文本, 排除標題, 排除文本]

AU3:ControlSetText ( "窗口標題", "窗口文本", 控制項ID, "新文本")

具體用法如下:

【示例5.1.1】

AHK:ControlSetText, Edit1, D:foobar2000, Setup foobar

AU3:ControlSetText("Setup foobar", "", "Edit1", "D:foobar2000")

選中和取消選中單選框和複選框項目

有時程序為了滿足用戶的個性化設置而需要用戶提供更多的信息,我們經常會遇到這樣的情況:

如何保證選中所需項目並取消某些項目呢?

下面先來介紹 AHK 和 AU3 中用來對控制項進行各種屬性設置的命令/函數:

AHK:Control [, 命令, 值, 目標控制項, 窗口標題, 窗口文本, 排除標題, 排除文本]

AU3:ControlCommand ( "窗口標題", "窗口文本", 控制項ID, "命令", "選項")

其中,「命令」就是讓我們指定要進行何種設置的參數。對這些單選框/複選框按鈕來說,適用的命令是「Check」和「UnCheck」。

假設這個窗口的標題是為 Setup foobar,我們打算進行下來操作:

選中它的「桌面」複選框(Button5)、取消選中「快速啟動欄」複選框(Button7);

選中「0.7x」單選框(Button14)。

那麼具體的用法示例如下:

【示例5.1.2】

AHK:

Control, Check, , Button5, foobarControl, UnCheck, , Button7, foobarControl, Check, , Button14, foobar

AU3:

ControlCommand("foobar", "", "Button5", "Check", "")ControlCommand("foobar", "", "Button7", "UnCheck", "")ControlCommand("foobar", "", "Button14", "Check", "")

選擇下拉列表的項目

相信你肯定遇到過下面這種情況:

問題又來了:如何選中自己需要的項目?

答案仍是使用上面提到的命令/函數。對這種控制項而言,AHK 適用的命令是「Choose, N」和「ChooseString, String」,分別表示選中第 N 個項目和選中與字元串 String 匹配的項目;而 AU3 適用的命令則是「SetCurrentSelection, N」和「SelectString, String」,分別表示選中第 N+1(注意是從零開始表示!)個項目和選中與字元串 String 匹配的項目。

假設我們要選中第五個項目「簡體中文」,那麼具體的用法示例如下:

【示例5.1.3】

AHK:

Control, Choose, 5, ComboBox1, InstallerControl, ChooseString, 簡體中文, ComboBox1, Installer

AU3:

ControlCommand("Installer", "", "ComboBox1", "SetCurrentSelection", 4)ControlCommand("Installer", "", "ComboBox1", "SelectString", "簡體中文")

TAG: |