Pseudo TotalTerminal(偽の TotalTerminal)を書いていて思ったのですが、アプリケーションを起動させるってことだけでも
AppleScript ではいろいろ書き方があります。
ちょっと思いついただけでも activate
、launch
、open
、reopen
、run
...と、さまざま。これらすべて挙動が異なっているのですが、どうも違いが分かりにくい。だからかどうかは分からないのですが、System Events を使ったプロセスの制御を行うスクリプトをよく見かけます。
どうもその手のスクリプトをみていると...修正したくなります。いやいやそんな面倒なことをしなくても...なんて。
たぶん日本語で読める AppleScript の説明が少ないのが一番の問題なのでしょうが。そういうことを踏まえてちょっと AppleScript の基本的なことをまとめてみます。
まずはアプリケーションの制御...起動と終了についてです。
アプリケーションの起動
activate
はアプリケーションが起動していないなら起動させ、最前面に表示します。Finder でアプリケーションアイコンをダブルクリックしたときの挙動ですね。
アプリケーション起動の最も一般的な命令です。
-- アプリケーションを必要なら起動し、最前面に表示
tell application id "com.apple.Terminal" to activate
activate application id "com.apple.Terminal"
並べて書いていますが、どちらも効果は同じです(意味はちょっと違うけど、そこを深く追求しだすと分かりにくくなるので)。
activate
は表示されているアプリケーションに対して使う命令です。つまり、バックグラウンドアプリケーションに対しては本来使いません(そもそもバックグラウンドアプリケーションは最前面に表示されない)。
launch
もアプリケーションを起動させる命令ですが、すでにアプリケーションが起動しているならなにも効果はありません。activate
のように最前面にしたりはしません。
また、アプリケーションが起動していないなら起動を行いますが、初期化処理は行いません。Terminal は通常なら、起動時にウィンドウを表示させますが、launch
で起動させた場合はウィンドウ表示が行われません。
-- アプリケーションを起動させるが、初期化処理は行わない
tell application id "com.apple.Terminal" to launch
launch application id "com.apple.Terminal"
run
命令でもアプリケーションを起動させます。しかし、アプリケーションは非表示で起動されます。
-- アプリケーションを起動させるが、非表示
tell application id "com.apple.Terminal" to run
run application id "com.apple.Terminal"
すでにアプリケーションが起動している場合、run
ではなにが実行されるかアプリケーションの設定により異なります。この辺りが activate
や launch
と異なるところです。アプリケーション側が run
命令を受け取った時にこうしなさい、というプログラムが組まれているならそれを行います。
多くの場合はなにも起こりませんが、再度、初期化処理が行われる場合もあります。
open
命令は直接アプリケーションを起動する命令ではありません。
分かりやすくいうと「ファイルをアプリケーションアイコンにドラッグ & ドロップする動作」と同じです。結果としてアプリケーションを起動させてファイルを開かせることになります。
今までの命令と異なるのは引数として開かせる対象のファイルやフォルダが必要になることです。
-- 画像ファイル
set imageFile to (path to pictures folder as text) & "2016.jpg"
-- テキストファイル
set textFile to (path to desktop as text) & "目次.md"
-- フォルダ
set theFolder to path to documents folder
-- 全てをリストでまとめる
set fileList to {imageFile, textFile, theFolder}
-- Finder の open は Finder でファイルをダブルクリックした時と同じ効果
-- 結果的に目的のアプリケーションを起動しファイル表示を行う
tell application id "com.apple.finder" to open fileList
-- 画像ファイルを他のアプリケーションで開きたいならそのアプリケーションで open
-- Safari に先のリストを渡すと...
-- 画像とテキストファイルは開く
tell application "Safari" to open fileList
-- AppleScript に対応していない Day One なら?
-- 起動はするけどなにも行われない
-- ただ、Day One が起動している時に実行すると画像ファイルを添付した新規エントリ作成
tell application "Day One" to open fileList
open
命令は AppleScript で定義されている命令ですが、多くのアプリケーションで利用できます。
もう少し詳しく説明すると、AppleScript からみてアプリケーションは以下の 3 つのタイプに分類できます。
- AppleScript に対応している
- AppleScript に対応していないが、基本的な命令を受け付ける
- AppleScript に全く対応していない
Day One は 2 番の「AppleScript に対応していないが、基本的な命令を受け付ける」アプリケーションです。この手のアプリケーションは多く、AppleScript でちょっとした処理が出来たりします。
最後の reopen
もアプリケーションの起動として利用できます。
すでに起動しているアプリケーションの Dock にあるアイコンをクリックした時と同じ挙動を行わせる命令...といえば分かりやすいでしょうか。
run
命令に似ているのですが、reopen
の場合必ずなんらかの処理が行われます。多くの場合は起動時と同じ処理...例えば、新規ウィンドウを作る等。Terminal の場合、ウィンドウがない場合は新しいウィンドウを表示します。すでにウィンドウがあるならなにもしません。
まとめましょう。
単純にアプリケーションを最前面に持ってきたいなら activate
を使います。
静的にアプリケーションを起動させたいだけなら launch
を使います。アプリケーションを静的に起動させ、かつ、起動時の処理も行わせたいなら run
と組み合わせます。
起動しているアプリケーションに起動時の処理を再度行わせたいなら reopen
を使います。
アプリケーションを起動し、ついでになんらかのファイルを開きたいなら open
を使うと効率的です。
注意しなければいけないのは run
や launch
を起動しているアプリケーションに使ったときにどういう処理をするかはアプリケーションに依存する...というところでしょうか。実際のところこれら以外の命令であってもどのように処理するかはアプリケーション依存なのだけど。だから AppleScript でアプリケーションを操作する場合はテストが必須です。
配布されているようなスクリプトならなおさら。長いこと AppleScript を使っているけど、いまだに人が書いたスクリプトが読めないことがありますし...(これはこれで問題だ)。
アプリケーションの終了
起動したアプリケーションは終了しなければいけません(そんなことはない)。
終了は起動に比べてシンプルで quit
命令しかありません。この命令は通常の終了であり、強制終了ではありません。
quit application id "com.apple.Terminal"
ただ、アプリケーションによってはファイルの保存が必要になることがあります。ファイルが未保存の場合、多くの場合アプリケーションが保存されていないが本当に終了してもいいか?と問いかけてくることでしょう。
ときどき保存が必要なのにその確認を行わないアプリケーションもあります。こういった命令を利用するときは事前に動作確認をしておく必要があります。
また、保存は行わずに直ちに終了させたい場合があります。そういうときは quit
のオプションを使います。
-- 保存されていなくても直ちに終了する
quit application id "com.apple.TextEdit" saving no
-- 保存をしてから終了する
quit application id "com.apple.TextEdit" saving yes
-- 保存するかどうか尋ねる
quit application id "com.apple.TextEdit" saving ask
状況によってこれらのオプションを使い分けます。
この命令は通常なら終了できないようなアプリケーションでも終了させることができます。分かりやすいのが Finder でしょうか。Finder は通常なら終了メニューがないので終了できませんが、quit
で終了させることができます。
-- Finder の再起動
quit application id "com.apple.finder"
-- 終了処理が終わらないうちに起動命令が伝わるのでちょっと待つ
delay 1
activate application id "com.apple.finder"
Finder なら別にいいのですが、logwinwindow や SystemUIServer などという背後で動いている重要なアプリケーションでも quit
を送ることができます。おそらくそれらが終了することはないのですが、なにが起きるかは分からないのでやめておきましょう。
quit
命令でよくあるのがアプリケーションの一括終了。
コメントはいつもより多めにしています。
AppleScript に対応していないアプリケーションについて
アプリケーションの起動と終了に関して見てきましたが、以上の命令は特別に AppleScript に対応していなくても使えるものです。
先にも書きましたが「AppleScript に対応していないが、基本的な命令を受け付けるアプリケーション」は AppleScript から操作できます。
では、基本的な命令とはなんでしょうか?
- アプリケーションを開く
- 書類を開く
- 書類を印刷する
- アプリケーションを終了する
これらの処理です。では、これらの処理ができるのかどうかをどうやって調べるのかというと System Events を使います。
System Events というのは OS やシステムに関する設定などを行ってくれるバックグラウンドアプリケーションです。このアプリケーションは process
というクラスを持っていて、これを使うとプロセスに関する情報を調べることができます。
tell application id "com.apple.SystemEvents"
-- Terminal が起動していないなら終了
if not (process "Terminal" exists) then return
tell process "Terminal"
-- バンドル ID
bundle identifier
--> "com.apple.Terminal"
-- 表示されているか隠されているか?
visible
--> true
-- 最前面かどうか?
frontmost
--> false
-- Unix でのプロセス番号
unix id
--> 16448
-- kill してみる
do shell script "kill 16448"
end tell
end tell
AppleScript に関連する情報は process
クラスの has scripting terminology
と accepts high level events
属性を調べます。AppleScript に対応しているなら has scripting terminology
が真になり、対応していなくても accepts high level events
が真なら基本的な命令を受け付けることができます。
tell application id "com.apple.SystemEvents"
-- Terminal が起動していないなら終了
if not (process "Terminal" exists) then return
tell process "Terminal"
-- 基本的な命令を受け付けるか?
accepts high level events
--> true
-- AppleScript 対応か?
has scripting terminology
--> true
end tell
end tell
accepts high level events
が真なら activate
や quit
といった命令は受け取れます(...と教科書通りにいけばいいのですが、実際はそうじゃないこともあります。結局、最終的には手作業で調べなきゃいけないはめになる。それが AppleScript)。
System Events にはこの他に UI Element というクラスが定義されていて、(個人的には)最終手段ともいえるプロセス自身の泥臭い操作もできます。
activate
、open
、quit
が使えればなんとかなる...と個人的には思っているのですが、世の中の大半の人はそうではないようで、この UI Element を使ってナニか面倒なことをよくやっている人が多いです。もっと楽をしようよ。
AppleScript を使う場合、そのアプリケーションに精通している必要があります(そもそもそのアプリケーションでなにができるが分からないのに操作したいなんてナンセンス)。AppleScript を使うまでもなく、アプリケーション自体に自動化できる装置がついていたりすることもあります。
Day One のようなアプリケーションは AppleScript に対応していませんが、シェルで操作できるツールが提供されていたりします(ところで、Day One 2 が出るんですね。AppleScript 対応...とかないかな)。このツールでできるのは新規作成だけですが、Day One はユーザーの Library フォルダに記事をファイルで保存しています。これは SQLite で SQLite ならシェルで操作できます。
また、有名どころの Web サービスなんかだと API が提供されていたりします。do shell script
で curl 使えばなんとかなるでしょう。
Mac 版の Kindle だと AppleScript に対応していないし、そもそも API もない。それでも URL Scheme があったりするので特定のページや書籍を開くことはできます。
こういうふうに方法はいろいろあります。もちろん状況次第ですが、なるべくなら UI Elements の利用は控えておく方がいいです。すぐに使えなくなるから。
tell application id "com.apple.SystemEvents"
tell process "Terminal"
-- 「ターミナル」メニュー
tell menu bar item 2 of menu bar 1
-- 「環境設定」を表示
click menu item 3 of menu 1
end tell
end tell
end tell
メンテナンスが大変なスクリプトの一例。こういうのやウィンドウのボタンをクリックするのとか。こういうのはメニューやボタンがその場にないと動かなくなるから。で、メニューやボタンなんてバージョンアップでわりと簡単に移動するから。そもそもコメントがないとなにをやっているか分からない。
最後の方はアプリケーションの起動や終了と関係ない話でしたね。といってもこのメニューを操作してアプリケーションを終了させるなんてスクリプトをわりと見かけたりします。もう、みんな大丈夫だよね。そう、こういうときは
quit
を使え
最低でも kill
にしておきましょう。
0 件のコメント :
コメントを投稿