クリップボードはアプリケーション間でデータのやり取りを行うときに非常に重宝します。
クリップボードの中には様々なデータが格納されます。AppleScript に対応していないアプリケーションでもコピー & ペーストは使えることがほとんどなので、
- 対象アプリケーションでデータをコピー
- AppleScript でデータを加工
- クリップボードに加工したデータを格納
- 対象アプリケーションでペースト
と、このようにクリップボードを介して AppleScript を利用することがあります。その昔、Script Editor が AppleScript に対応していなかったとき、よく使っていました。また、TextEdit は AppleScript に対応していますが、選択範囲を取得できないのでクリップボードに選択範囲をコピーし、クリップボード内のデータを加工し、TextEdit でペーストするということもよく行います。
使いようによっては便利なクリップボード。そのクリップボードの中身を調べるとなかなか興味深いものがあります。AppleScript でクリップボードを扱う命令は、StandardAdditions.osax が提供していて、以下の命令があります。
- clipboard info(クリップボードの情報を取得)
- the clipboard(クリップボードのデータを取り出す)
- set the clipboard to(クリップボードにデータを格納する)
AppleScript は文字列をバイトで数えるのではなく、多バイト文字でも一文字は一文字として数えます。そうではなく、単純にバイト数を知りたいときにクリップボードは使えます。
set theText to "文字列"
set the clipboard to (theText as text)
clipboard info
--> {{string, 6}}
string クラスで 6 バイトになります。どうしてリストの中にリストがあるのかというと、クリップボードは複数のデータを保管するからです。例えば、修飾された文字列をコピーしたなら、修飾された文字列のデータと修飾されていない文字列のデータ、また、ユニコード文字列のデータ、ユニコードでも UTF-8 や UTF-16 などの異なったエンコードの文字列データ...これらがクリップボードに一緒に保管されます。複数のデータが入っているので対応アプリケーションでペーストしたときに適切なデータが取り出されて貼り付けられます。
クリップボードは様々なデータが扱えます。それらのデータの中に目的のデータがあるかどうかを調べるには clipboard info 命令の for オプションを使います。for オプションの引数に目的のデータ型を指定します。
clipboard info for string
--> {{string, 61}}
目的のデータがあれば、このような結果になります。ない場合は空のリストが返ってきます。
on dataIsInClipboard for dataType
return (clipboard info for dataType) is not {}
end dataIsInClipboard
このようなハンドラにしておけば、目的のデータが存在するかどうかを調べることができます。目的のデータを取り出すには、the clipboard 命令を使います。しかし、このままでは目的のデータを取り出すことはできないので、as を使って取り出します。
set str to the clipboard as Unicode text
class of str
--> Unicode text
set str to the clipboard as string
class of str
--> string
set str to the clipboard as «class RTF »
class of str
--> «class RTF »
Script Editor 上で編集中のドキュメントの文字列をコピーして実行してみました。このように as で指定することでクリップボードに格納されている複数のデータから目的のものを取り出すことができます。これも、以下のようなハンドラにしておきます。
on dataFromClipboard for dataType
return the clipboard as dataType
end dataFromClipboard
さて。ここからが、応用。いろんなアプリケーションでいろんなデータをコピーして clipboard info 命令で返ってくる結果を見てみると、«» という括弧で囲まれたデータ型が返ってくることがあります。これらは、AppleScript で定義されていないデータ型です。以下、その一部。
- «class ut16»
- «class utf8»
- «class RTF »
- «class rtfd»
- «class hfs »
- «class furl»
- «class urln»
- «class PDF »
- «class icns»
- «class moov»
パッと見て、どんなデータか概ね想像がつくと思います。これらのデータ型は AppleScript で扱える(加工できる)ものもあり、そうでないものもあります。文字列ならそのまま扱える場合もあります。画像に関するデータ型もありますが、これらは as として型を変換することはできません。
ほとんどのデータ型は AppleScript で加工できないのですが、ファイルに書き出すことはできます。例えば、QuickTime Player で動画の一部分をコピーするとクリップボードには «class moov» というデータが格納されます。このデータを write 命令で書き出すと QuickTime の mov ファイルを作ることができます。
on run
set theFile to (path to desktop as Unicode text) & "tmp.mov"
if (dataIsInClipboard for «class moov») then
set theData to dataFromClipboard for «class moov»
set errInfo to {|number|:0, |error message|:""}
set errRef to a reference to errInfo
if not (writeFile(theFile, theData, errRef)) then
return errInfo
end if
end if
end run
on dataIsInClipboard for dataType
return (clipboard info for dataType) is not {}
end dataIsInClipboard
on dataFromClipboard for dataType
return the clipboard as dataType
end dataFromClipboard
on writeFile(theFile, theData, errRef)
try
set fh to open for access file theFile with write permission
set eof fh to 0
write theData to fh starting at eof
close access fh
return true
on error errMsg number errNum
try
close access fh
end try
set contents of errRef to {|number|:errNum, |error message|:errMsg}
log {errNum, errMsg}
return false
end try
end writeFile
AppleScript の write 命令で書き出したファイルは TextEdit で開くように関連づけられている(「iTunes のアートワークをファイルに書き出す」参照)ので、クリエータータイプとファイルタイプを変更する必要があります。
ちなみに、«class RTF » を拡張子 rtf のファイルに書き出すと RTF 書類として保存できます。iCal のイベントをコピーするとこのクラスが返ってきます。ファイルに書き出すことでイベントの一覧が簡単にファイルに出力できます。Mail のメッセージ(件名や差出人が表示されている部分)をコピーすると «class rtfd» が返ってきます。RTFD のデータなのですが、RTFD はパッケージ形式のファイルなのでそのまま書き出しても開くことはできないファイルになります。RTFD ファイルとして開けるようにするには面倒なので、省略。
このようにアプリケーションで選択した項目がどのようなデータ型でクリップボードに入っているかが分かると RTF やテキストファイル、その他のファイルとして保存することが可能です。
Preview で開いている PDF ファイルは選択範囲を指定してコピーすることができます。このとき、クリップボードには «class PDF » のデータが格納されます。これを write 命令で PDF ファイルで書き出せば、選択範囲をファイルに保存することができます。
Finder で項目をコピーします。すると、クリップボードにはファイルの名前やパスといった情報とともにアイコンデータ(«class icns»)も格納されます(複数項目のコピーではアイコンデータは格納されません)。もちろん、このデータもファイルに書き出すことでアイコンファイルとして保存できます。また、Preview.app で表示することも可能です。
on run
pictureFromClipboardAtPreview()
end run
on pictureFromClipboardAtPreview()
if not (dataIsInClipboard for «class icns») then return
tell application "Preview" to activate
tell application "System Events"
tell process "preview"
try
keystroke "n" using command down
end try
end tell
end tell
end pictureFromClipboardAtPreview
on dataIsInClipboard for dataType
return (clipboard info for dataType) is not {}
end dataIsInClipboard
Finder の項目をコピーしたとき、アイコンのデータと一緒に PICT データもクリップボードに格納されるのですが、こちらは 32 x 32 のサイズの画像が格納されるのでアイコンを抜き出すという目的では使えません。
このクリップボードの内容を Preview で表示するというのは iTunes のアートワークでも使えます。
tell application "iTunes"
activate
set thisTrack to current track
if (exists artworks of thisTrack) then
repeat with thisArtwork in artworks of thisTrack
set pictData to data of thisArtwork
set the clipboard to pictData
my pictureFromClipboardAtPreview()
end repeat
beep 2
end if
end tell
on pictureFromClipboardAtPreview()
if not (dataIsInClipboard for picture) then return
tell application "Preview" to activate
tell application "System Events"
tell process "preview"
try
keystroke "n" using command down
end try
end tell
end tell
end pictureFromClipboardAtPreview
on dataIsInClipboard for dataType
return (clipboard info for dataType) is not {}
end dataIsInClipboard
アプリケーションが返す picture データをそのまま set the clipboard to 命令でクリップボードに格納するだけです。
read 命令でファイルを画像データとして書き出し、それを set the clipboard to 命令でクリップボードに格納し、アプリケーションでペーストするということもできます。
set theData to read (choose file without invisibles) as TIFF picture
set the clipboard to theData
ただし、これは TIFF か PICT だけに限られます。アプリケーション間での画像データのやり取りは、どうもこれらのファイル形式に限られているようで(どんな形式の画像でもクリップボードの中では PICT、または、PICT と TIFF に変換されて保持される)。
では、最後。Finder では選択項目をコピーして別の場所にペーストすることで複製を作ることができます。このときクリップボードには、ファイルのパスが格納されます。«class hfs » と «class furl» がそうです。前者のパスは AppleScript で作ることはできませんが、«class furl» は以下のように作ることが可能です。
set theFile to POSIX path of (choose file without invisibles)
set theFile to theFile as POSIX file
set the clipboard to theFile
選択したファイルを POSIX file に変換します。そして、クリップボードに格納します。この後 Finder でどこかの場所にペーストすれば、そのファイルが複製されます。
ただし、この方法では Finder のように複数の項目をコピーすることはできません。もし、複数の項目をコピーしたいなら、以下のような方法があります。
set fileList to choose file with multiple selections allowed without invisibles
set tmp to {}
repeat with thisItem in fileList
set end of tmp to POSIX path of thisItem
end repeat
tell application "Automator"
set preferred type of pasteboard "general" to "file names"
set contents of pasteboard "general" to tmp
end tell
いちいち Automator を起動するのが嫌というときは Xcode でダミーのスクリプタブルアプリケーションを作ってもいいでしょう。実際、ダミーのスクリプタブルアプリケーションって使い道が多々あって重宝します。最近、hetimaの日記 - Xcode の AppleScript で call method でも触れられていましたが、なんといっても call method が使えるようになります。
一応、ダミーのスクリプタブルアプリケーションの作り方を書いておくと、
- Xcode で AppleScript Application の新規プロジェクトを作る
- Info.plist を開き NSBGOnly = 1 を追加する
- ビルドする
- 完成
となります。バックグラウンドで動作するので邪魔になりません。で、先のコードを以下のように修正。
set fileList to choose file with multiple selections allowed without invisibles
set tmp to {}
repeat with thisItem in fileList
set end of tmp to POSIX path of thisItem
end repeat
tell application "Dummy"
set preferred type of pasteboard "general" to "file names"
set contents of pasteboard "general" to tmp
quit
end tell
hetimaの日記 - Xcode の AppleScript で call method では、AppleScriptKit.framework をプロジェクトにリンクし、NSAppleScriptEnabled = YES を Info.plist に追加していますが、AppleScript Application はどちらも最初から設定されています。もちろん、その他のプロジェクトで作成するアプリケーションに AppleScript の機能を追加するというのであれば、hetima さんのように行う必要があります。このダミーのアプリケーションは非常に便利なので AppleScript 使いの少数の人間だけで共有されていたトップシークレット(嘘)だったのですが、hetima さんの記事によって広まってしまいますね。