F-Script で Mac の様々なアプリケーションを操作する

2009年 9月 改訂

記事一覧

      基 礎
  1. F-Script で Cocoa 探検 [原文]
  2. F-Script を20分で学び、Core Image で遊んでみよう [原文]
  3. F-Script で Cocoa スクリプティング [原文]
  4. F-Script で Cocoa クラスを創る [原文]
  5. F-Script で Mac の様々なアプリケーションを操作する [原文]
  6. Cocoa アプリケーションに F-Script を埋め込む [原文]
  7. F-Script で Mac OS X のフレームワーク群にアクセスする [原文]
      その他
  1. Cocoa と F-Script で Google Chart API をいじってみよう [原文]
  2. F-Script 版 Reverse ゲーム [原文]

はじめに

AppleScript と同様に、F-Script は、スクリプタブルアプリケーションと交信することができ、そのアプリケーションを使った作業プロセスを自動化したり、複数のアプリケーションを跨いだ ワークフローを創ったりすることができるが、このシステムワイドなスクリプティング能力は、スクリプティングブリッジ と呼ばれる Mac OS X の標準的な技術の一つを使って実現されている:

スクリプティングブリッジとは、Cocoa 開発者が、スクリプタブルアプリケーションを制御したり、それらと交信したりするのを、非常に容易にしてくれるフレームワークであり、技術である。 [...] スクリプティングブリッジフレームワークを使えば、AppleScript のコマンドや、Apple-Event 記述子の代わりに、Objective-C のメッセージを使って、Apple-Event の送受信をすることができる。 スクリプティングブリッジは、Cocoa プログラマに対して、スクリプタブルアプリケーションを制御する為の、易しくて明快なモデルを提供してくれる。 これを使えば、Cocoa プログラマは、より効率的に Apple-Event を送受信でき、しかも、ターゲットアプリケーションの Apple-Event モデルがどうなっているのかに関する詳しい知識を持っている必要がない。 スクリプティングブリッジは、既存の Objective-C コードをうまく統合し、キー値-コーディング、ターゲット-アクション、それに、デクレアド-プロパティの様な、標準的な Cocoa の設計と連携して機能する。

スクリプティングブリッジを使うと、基本的に、交信の詳細(つまり、Apple-Event の生成や送信)が自動的に処理される為に、スクリプタブルアプリケーションが まるで Cocoa オブジェクトであるかのように 操作できるようになるのだ。この仕組みのお陰で、標準的なスクリプティングインタフェースを経由することで、F-Script を使って、他のアプリケーションを操作することができるのである。

注:AppleScript や Apple-Event 等々について改めて見直してみたい方には、William R.Cook が HOPL III コンファレンス の為に書いた AppleScript を一読されることをお薦めする。 これは、ユニークな歴史的視野を与えてくれる、大変良い読み物の一つである。

アプリケーションに接続する

では、F-Script でスクリプティングブリッジを使うにはどうすれば良いのか? 最初にまず、Cocoa が提供する SBApplication クラスを使って、 アプリケーションに接続する。 例えば、こうすれば iTunes に接続することができる:

iTunes := SBApplication applicationWithBundleIdentifier:'com.apple.iTunes'

applicationWithBundleIdentifier: メソッドは、ターゲットアプリケーションの内部を覗き込んで、自動的にスクリプティングインタフェースを見つけ出し、 それらと相互作用する為に必要なクラスやメソッドを動的に生成して、ターゲットアプリケーションを表すオブジェクトを返してくる。 これが、F-Script によるターゲットアプリケーションの操作を始める為に利用するオブジェクトだ。 上の例では、このオブジェクトを「iTunes」という名前の変数に代入している。 このオブジェクトが、必要に応じて自動的に、ターゲットアプリケーションとの交信の面倒を見てくれるのである。

アプリケーションとの相互作用

一度ターゲットアプリケーションとの接続ができてしまえば、そのアプリケーションと、F-Script を使って相互に遣り取りを行うことができる。 例えば、iTunes に現在のトラックの名前を尋ねてみよう:

iTunes currentTrack name

もし、現在のトラックが存在しなければ、スクリプティングブリッジからエラーが返り、F-Script がそれを表示するが、さもなければ、現在のトラックの名前が返ってくる。

では、iTunes に次のトラックに進むように頼んでみよう:

iTunes nextTrack

今度は、ファインダに接続して、デスクトップにあるファイルの名前を問い合わせてみよう:

Finder := SBApplication applicationWithBundleIdentifier:'com.apple.finder'.
Finder desktop files name

これらのファイル名を、配列インスペクタに表示させてみよう:

Finder desktop files name inspect

ファインダに、今日更新されたデスクトップ上のファイルの名前を訊いてみよう:

files := Finder desktop files.
files name where:files modificationDate >= 'today' asDate

ご覧のように、いつでも F-Script の配列プログラミングモデルを利用することができる。

以下の例では、ファインダに、起動ディスクの アプリケーション フォルダにあるファイルの総数を訊いている:

(Finder startupDisk folders objectWithName:'Applications') files count

次の例では、Mail アプリケーションに接続して、現在の inbox にあって、既に返信済みのメッセージの表題を訊いている:

Mail := SBApplication applicationWithBundleIdentifier:'com.apple.mail'.
Mail inbox messages subject where:Mail inbox messages wasRepliedTo

以下のスクリプトは、Scripting Bridge Programming Guide for Cocoa にある例を基にしている。 このスクリプトは(iTunes が動いていれば)現在選択されている曲を再生して、その音量がゼロから最終的にオリジナルのレベルに達するまで、ボリュームを変化させる。

iTunes := SBApplication applicationWithBundleIdentifier:'com.apple.iTunes'.

iTunes isRunning ifTrue:
[
    |rampVolume originalVolume|
  
    originalVolume := iTunes soundVolume.
    iTunes setSoundVolume:0; pause; playpause.
    rampVolume := 0.

    [rampVolume < originalVolume] whileTrue:
    [
        iTunes setSoundVolume:rampVolume.
        "Pause 1/10th of a second between adjustments"
        NSThread sleepUntilDate:(NSDate dateWithTimeIntervalSinceNow:0.1).
        rampVolume := rampVolume + (originalVolume / 32).
    ].
    
    iTunes setSoundVolume:originalVolume.
]

次のスクリプトも、Scripting Bridge Programming Guide for Cocoa にある例を基にしている。 このスクリプトは、Mail の選択されたメッセージのテキストの内容を TextEdit 文書にコピーする。

TextEdit := SBApplication applicationWithBundleIdentifier:'com.apple.TextEdit'.
Mail := SBApplication applicationWithBundleIdentifier:'com.apple.Mail'.

Mail messageViewers do:[:viewer| 
    viewer selectedMessages do:[:message|  
        doc := (TextEdit classForScriptingClass:'document') alloc init.
        TextEdit documents addObject:doc.
        doc setText:message content get.
    ] 
]

スクリプティングインタフェースの調査

各アプリケーションは、それぞれ独自のスクリプティングインタフェースを持っているが、F-Script のオブジェクトブラウザを使うと、ある特定のアプリケーションで利用可能なメソッドについて調べたり、 それを使って実験したりすることができて便利である。 もしアプリケーションとの接続が既に確立しているのならば、以下の例のように、オブジェクトブラウザに、プログラム的にそのアプリケーションを表すオブジェクトを渡して、ブラウザを開くことができる。

sys browse:iTunes

そうする代わりに、以下のステップに従って、オブジェクトブラウザ自身から、アプリケーションとの正しい接続を確立することもできる。

  1. もしも、オブジェクトブラウザがまだ表示されていなければ、ワークスペースメニューから「Open object browser」を選択する。

  2. オブジェクトブラウザの「Classes」ボタンをクリックすると、現在リンクしている全てのクラスの一覧が表示される。

  3. クラス一覧の中の SBApplication クラスをクリックすると、SBApplication のクラスメソッドが表示される。

  4. メソッド一覧の中の applicationWithBundleIdentifier: をクリックして、入力を求められた引数(つまり、接続したいアプリケーションの識別子を含む文字列); 例えば、'com.apple.iTunes' を入力する。

こうして、対象となるアプリケーションのスクリプティングインタフェースを調査したり、それを使った実験を行う為にも、オブジェクトブラウザを使うことができるのだ。

上のスクリーンショットに示すように、ブラウザには、スクリプティングブリッジが自動的に生成した iTunes アプリケーションを表す Cocoa オブジェクトのメソッド群が表示される。 ある特定のメソッドを起動するには、それをクリックするだけで良い(引数が必要な場合、ブラウザがその入力を求めてくる)。 一度メソッドが返ってくると、その結果がブラウザの新しい列に表示され、それを更に操作することができる。 オブジェクトブラウザは、オブジェクトを調査したり、ナビゲートしたりするのを助ける機能をたくさん提供しているが、 F-Script で Cocoa 探検 を見れば、その詳しいチュートリアルが見つかるだろう。

あるアプリケーションのスクリプティングインタフェースについて、更に情報を得る為に、そのアプリケーションのスクリプティングインタフェースが記述されている Objective-C インタフェースファイル (つまり .h ファイルのことだ)を生成することができる。 それを実行するには、Mac OS X が提供する sdef(スクリプティング定義抽出)と sdp(スクリプティング定義処理)という二つのコマンドを使用する。 まず最初に、sdef を使って、アプリケーションからそのスクリプティング定義を訊き出し、次にその結果を sdp に渡して Objective-C インタフェースファイルを作らせる。 例えば、iTunes が、スクリプティングブリッジを使ってどのように制御できるのかに関する詳しい記述を得る為には、UNIX のシェルで、次のコマンドを実行すれば良い。

sdef /Applications/iTunes.app | sdp -fh --basename "iTunes"

このコマンドを実行すると、iTunes.h という名前のファイルができる。 Xcode が表示するこのファイルの内容の、短い抜粋を以下に示そう。

sdp コマンドがうまく動かないアプリケーションもあるが、そのような場合でも、sdef の出力を見れば、そのアプリケーションのインタフェースに関する役立つ情報を得ることができる。

sdpsdef を使って得られる情報と、対話的な実験を組み合わせれば、 F-Script から(同様にまた Objective-C からでも)どのようにアプリケーションを制御できるかを学ぶことができるし、クールなスクリプトがきっと書けるはずだ。

楽しいスクリプティングを!


Copyright © 2009 Philippe Mougin
Translation-ja © 2012 Hideo Haga[日本語版]