07. GUI Scriptingで作業自動化(2)2013-04-25

本項のスクリプトでは、「メモ書き倉庫」さんの「AppleScriptであれこれする」から以下のハンドラを拝借して外部参照しています。
ここに巡り会ったおかげで、今回の作業は偶然的に成立しました。素晴らしい仕事に感謝します。
http://memogakisouko.appspot.com/AppleScript.html#mouseClick

画像編集の老舗アプリGraphicConverterの機能のひとつに各種バッチ処理があります。画像の縮尺率の数字、4.5とか0.6などクリップボードに入れておいてスクリプト実行するとバッチファイルが書き換わる、そんな用途です。
マウス・キー操作9回をまとめられて現実に重宝しているのですが、今回の話のポイントは最初のwindowのブロックのところです。

property ExHandler : load script file "MyHD:MyScripts:library:_mouseClick.scpt"

tell application "System Events"

tell process "GraphicConverter"
set frontmost to true
keystroke "m" using {command down, control down}

tell window "Convert & Modify"
set {_x, _y} to get position
ExHandler's mouseClick({_x + 200, _y + 370}, "left", 1, "", 0.1)
end tell

tell window "Batch"
set {_x, _y} to get position
ExHandler's mouseClick({_x + 400, _y + 70}, "left", 1, "", 1)
delay 1
keystroke "v" using command down
keystroke tab
keystroke "v" using command down
keystroke tab
set {_x, _y} to get position
ExHandler's mouseClick({_x + 600, _y + 125}, "left", 2, "", 4)
end tell

tell window "Save"
keystroke return
delay 1
click button "Replace" of sheet 1
end tell

tell window "Batch"
keystroke return
end tell

tell window "Convert & Modify"
set {_x, _y} to get position
ExHandler's mouseClick({_x + 10, _y + 5}, "left", 2, "", 1)
end tell

if not (exists (window "Convert & Modify")) then
display dialog "GC Scale finished " giving up after 1
end if

end tell
end tell

window "Convert & Modify"において、set {_x, _y} to get positionとはモニタ上でのwindowの最左上の座標取得です。
その座標から左200下370ピクセルの位置をクリックしていますが、モニタ上ではそこに目標の"• Edit Batches…"ボタンがあります。
実はUI Browserによって当該ボタンのUI element要素は、「button "• Edit Batches…" of window "Convert & Modify"」と取得できるのですが、なぜかclickコマンドが利きません。
これがGUI Scriptingができない場合なのかと隔靴掻痒していた中で、偶然mouseClickハンドラを思い出してピクセル値を実測、試してみたらたまたま救われた、それが本項の顛末。
スクリーンショットを撮って実測したり、クリックの秒数をあれこれ試したり、掛け値無しに泥縄です(苦笑)。
スクリプトの以下も同様で、全体作業が成功した時は嬉しさよりも疲れが前面に出ました。

以上2回が自分のGUI Scriptingに関しての実体験です。
GUI Scriptingは確かに最終手段と認識しました(笑)。

06. GUI Scriptingで作業自動化(1)2013-04-24

GUI Scriptingがどんなものかについては自由にお調べ願いますが、ぜひ読んでいただきたいのは「AS Hole(AppleScriptの穴)」さんの以下の記事です。
http://piyocast.com/as/archives/538
「GUI Scriptingによる記述」は飛び飛びですが(4)まであります。スクリプトとしては避けようの無い場合の最終手段であること、UI Browser.appを用いてUI element要素を調べるのが現実的で、それでも駄目な場合がいろいろある、など端的と思われます。

マウスやキー操作を実現していくわけですが、いざ取り組んでみると大変というお話は続きで述べるとして、本稿では自作の簡単な例を。
作業内容は「ブラウザに表示させたモデム管理ページで再起動を実行、環境設定からクッキーの一覧windowを表示させて終了」です。モデム再起動の間に不要なクッキーを手動削除しますので。

tell application "iCab"
GetURL "http://web.setup/index_frame.html"
end tell

tell application "System Events"

tell process "iCab"
set frontmost to true

tell window "Aterm WARPSTAR クイック設定Web"
click button "登録" of UI element 1 of row 2 of table 2 of UI element 1 of scroll area 1 of UI element 1 of scroll area 1
delay 1
click button "OK" of sheet 1
delay 1
click button "OK" of sheet 1
delay 1
click button 1
end tell

set frontmost to true
keystroke "," using command down

tell window "iCab 環境設定"
click button "Cookie"
end tell
tell window "Cookie"
click button "Cookie を表示"
end tell
tell window 1
click radio button "共用 Cookie" of tab group 1
end tell
tell window 2
click button 1
end tell

end tell
end tell

clickとkeystroke合計9個をまとめて、画面をあちこちマウス移動させられる苦痛?が解消、自分としては重宝しています。
作成方法ですが、やはりUI Browser.appを用いてUI elementを調べています。
例えば最初にclickしている"登録"ボタン(押すと再起動開始)はhtmlで動的に作成されているのですが、スクリプトに書くべきUI element要素は私の努力ではUI Browserでしか調べようがありませんでした。次に2回"OK"させられる?確認ボタンも同様です。
それからスクリプトを実行して案外驚くのが、速度の遅さ?とそれをコントロールもできないことです。手作業の苦痛はありませんが作業の進行速度自体は同じ。一発実行には違いなくても今までのスクリプトのような爽快感に欠ける、そんな妙な不満は全く贅沢なのでしょうが(苦笑)。

05. Home Pictureを設定する2013-04-23

頻繁にdesktop pictureを手動切替される方向け。切り替えた後で「いつもの絵がいいかな」という場合のためにHome Pictureを設定、戻れるようにしました。
本スクリプトでは、「メモ書き倉庫」さんの「AppleScriptであれこれする」から以下のハンドラを拝借して外部参照しています。
本スクリプトを動作確認される前に、当該ハンドラを皆さんのマックにスクリプトとして保存する必要があります。
http://memogakisouko.appspot.com/AppleScript.html#getModifierKeys

拙作スクリプトは以下。selection物なのでアプリとした場合は01.のようにウィンドウツールバーやランチャーから使って下さい。

property HomePict : ""
--次のファイルパス指定を書き換えてください
property ExHandler : load script file "MyHD:MyScripts:library:getModifierKeys.scpt"

on setDTP(xxx)
tell application "System Events"
tell current desktop
if picture rotation = 1 then
set picture rotation to 0
end if
set picture to xxx
end tell
end tell
end setDTP

tell application "Finder"
if ExHandler's getModifierKeys() contains "shift" then
set HomePict to selection as alias
set ppp to name of HomePict
display dialog "Home Picture set to " & ppp giving up after 2
my setDTP(HomePict)

else
if (selection is not {}) then
set tgtpict to (selection as alias)
my setDTP(tgtpict)

else
set ppp to name of HomePict
display dialog "Back to Home Picture " & ppp giving up after 2
my setDTP(HomePict)

end if
end if
end tell

動作はスクリプトの内容順に、起動時に
・シフトキーを押しながら画像選択→Home Pictureとして設定
・単純に画像選択→通常のdesktop pictureとして設定
・何もファイル選択無し→Home Pictureへ復帰
エラー処理を全く入れていませんが、わかって使う分にはそれでいいかなと。
ハンドラを使うと、予備処理や繰り返し部分を外に出してスクリプトをわかり易く短縮できますね。

04. ファイルやフォルダのリネームと1階層上移動2013-04-22

リネームも移動も02.で述べたようなFinder上で選択しているファイルやフォルダが対象です。どちらも一時期何度も手作業に迫られて書きました。

まずリネームですが、クリップボードのテキストを対象の名前とします。

set new_name to the clipboard as text
tell application "Finder"
set select_item to (selection as alias)
if class of select_item = folder then
set name of select_item to new_name
else
set item_ext to name extension of select_item
if item_ext = "" then
set name of select_item to new_name
else
set name of select_item to new_name & "." & item_ext
end if
end if
activate
tell application "System Events"
keystroke return
end tell
end tell

最後のkeystroke return部分は変更後の名前を短くすることが多かったので付け加えたのですが、不要なら外してください。
この名前変更はredoが利きませんのでご注意ください。
これは単数の対象向けですが、複数対象ならpropertyを設定して(同一タスク名+日付や連番)のような名前変更ができますね。

次に1階層上移動ですが、親フォルダ内で子フォルダの▶マークをクリックした時に見えた対象を選択して実行する、そんな用途です。

tell application "Finder"
set alist to selection
repeat with theAlias in alist
set tgtFolder to parent of (parent of theAlias as alias) as alias
move theAlias to tgtFolder
end repeat
end tell

複数対象可能です。マウス操作でもできますが案外難しいので作りました。
こんな小さなスクリプトでも必要なものをちょこちょこ書き貯めておくと、いざという時助かります。

03. Macの起動・再起動時に補助動作を行う2013-04-21

補助と書きましたが、実際にどんな作業を行うかはユーザーによりますので、一例としてご覧ください。

まず起動時の方から。保存したアプリをログイン項目に登録して使っています。
tell application "Finder"
quit
delay 1
launch
open application file "XtraFinder.app" of folder "Applications" of startup disk
end tell
do shell script "killall -HUP KeyRemap4MacBook"

Finderをわざわざ再起動させていますが、これは主要なアプリを置いている外付HDを読み込み直させるためです。起動時の外付HDの読み込みタイミングがどうも遅いために使っているランチャーアプリの表示が変になる症状が続いたので、こんな羽目に(笑)。必然的にXtraFinderも起動し直しです。
KeyRemap4MacBookは立ち上がっていても設定を読み込んでいないようで、再起動すれば直ることがわかりました。
他にここでできることは、ログイン項目で扱うようなことを好みの順番で行わせる、などでしょうか。

次に再起動時、です。
set msg to "Ready to restart Mac now ?"
display dialog msg buttons {"Cancel", "Forward"} default button "Forward"
if (button returned of result) is "Forward" then
tell application "System Events"
set currentProcessNames to name of every application process whose visible is true and name is not "Finder"
repeat with i from 1 to count of currentProcessNames
try
tell application (item i of currentProcessNames) to quit
end try
end repeat
if login item "XtraFinder" exists then
delete login item "XtraFinder"
end if
end tell
tell application "Finder"
delete every item of folder "MainBoot:Users:darzilin:Library:Caches:"
delete every item of folder "MainBoot:Users:darzilin:Library:Preferences:iCab:Databases:"
restart
end tell
end if

行っている順番に
・再起動の確認
そもそも通常終了の確認ダイアログへの応答が面倒で作り始めたのですが、これは無いとやはり痛い目に遭いました(笑)。なのでせめてデフォルトをOKで設置。
・Finder以外のアプリを終了
・ログイン項目XtraFinder削除(現在は不要)
初期のXtraFinderはログイン項目に自動で登録される仕様でした。それがあると上の起動時スクリプトとバッティングすることを発見するのが大変でした。現在は仕様が改良されたので不要な作業ですが、まあ記念ですね(笑)。
・ユーザーキャッシュ、ブラウザの不要ファイル削除
残したFinder担当業務。ブラウザが肥大化するのを好まないので捨てています。

スクリプトからのrestartは待ち時間がありません。起動時にはゴミ箱に排出されたファイルをチラッと見るのが恒例です。