クリップボード活用のススメ

クリップボードはアプリケーション間でデータのやり取りを行うときに非常に重宝します。

クリップボードの中には様々なデータが格納されます。AppleScript に対応していないアプリケーションでもコピー & ペーストは使えることがほとんどなので、

  1. 対象アプリケーションでデータをコピー
  2. AppleScript でデータを加工
  3. クリップボードに加工したデータを格納
  4. 対象アプリケーションでペースト

と、このようにクリップボードを介して AppleScript を利用することがあります。その昔、Script Editor が AppleScript に対応していなかったとき、よく使っていました。また、TextEdit は AppleScript に対応していますが、選択範囲を取得できないのでクリップボードに選択範囲をコピーし、クリップボード内のデータを加工し、TextEdit でペーストするということもよく行います。

使いようによっては便利なクリップボード。そのクリップボードの中身を調べるとなかなか興味深いものがあります。AppleScript でクリップボードを扱う命令は、StandardAdditions.osax が提供していて、以下の命令があります。

  • clipboard info(クリップボードの情報を取得)
  • the clipboard(クリップボードのデータを取り出す)
  • set the clipboard to(クリップボードにデータを格納する)

AppleScript は文字列をバイトで数えるのではなく、多バイト文字でも一文字は一文字として数えます。そうではなく、単純にバイト数を知りたいときにクリップボードは使えます。

Script Editor で開く

set theText to "文字列"
set the clipboard to (theText as text)
clipboard info
--> {{string, 6}}

string クラスで 6 バイトになります。どうしてリストの中にリストがあるのかというと、クリップボードは複数のデータを保管するからです。例えば、修飾された文字列をコピーしたなら、修飾された文字列のデータと修飾されていない文字列のデータ、また、ユニコード文字列のデータ、ユニコードでも UTF-8 や UTF-16 などの異なったエンコードの文字列データ...これらがクリップボードに一緒に保管されます。複数のデータが入っているので対応アプリケーションでペーストしたときに適切なデータが取り出されて貼り付けられます。

クリップボードは様々なデータが扱えます。それらのデータの中に目的のデータがあるかどうかを調べるには clipboard info 命令の for オプションを使います。for オプションの引数に目的のデータ型を指定します。

Script Editor で開く

clipboard info for string
--> {{string, 61}}

目的のデータがあれば、このような結果になります。ない場合は空のリストが返ってきます。

Script Editor で開く

on dataIsInClipboard for dataType
    return (clipboard info for dataType) is not {}
end dataIsInClipboard

このようなハンドラにしておけば、目的のデータが存在するかどうかを調べることができます。目的のデータを取り出すには、the clipboard 命令を使います。しかし、このままでは目的のデータを取り出すことはできないので、as を使って取り出します。

Script Editor で開く

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 で指定することでクリップボードに格納されている複数のデータから目的のものを取り出すことができます。これも、以下のようなハンドラにしておきます。

Script Editor で開く

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 ファイルを作ることができます。

Script Editor で開く

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 で表示することも可能です。

Script Editor で開く

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 のアートワークでも使えます。

Script Editor で開く

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 命令でクリップボードに格納し、アプリケーションでペーストするということもできます。

Script Editor で開く

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» は以下のように作ることが可能です。

Script Editor で開く

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 のように複数の項目をコピーすることはできません。もし、複数の項目をコピーしたいなら、以下のような方法があります。

Script Editor で開く

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 が使えるようになります。

一応、ダミーのスクリプタブルアプリケーションの作り方を書いておくと、

  1. Xcode で AppleScript Application の新規プロジェクトを作る
  2. Info.plist を開き NSBGOnly = 1 を追加する
  3. ビルドする
  4. 完成

となります。バックグラウンドで動作するので邪魔になりません。で、先のコードを以下のように修正。

Script Editor で開く

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 さんの記事によって広まってしまいますね。

0 件のコメント :

コメントを投稿