MacBook Leopardのクリップボードを最もシンプルかつ自由に拡張してみる

クリップボードっていうのは、(おそらく)一日一回はお世話になるはずのコピー&ペーストをする時のコピーデータの一時的な保管場所のこと。にも関わらず、普段使っている分にはクリップボードは目に見えることもなく、コピー&ペーストの仲介人としてひっそりと、でも確実に処理をこなす縁の下の力持ち的な存在なのだ。
もしもクリップボードがない世界*1を考えてみると、それは相当使い難いOS環境になってしまうだろう。(はてな日記の下書きとしてスティッキーズに書いたとしても、さて、どうやってアップロードしようかと悩んでしまう...。)

このとっても便利なクリップボードという仕組みは、OSX標準では常に一つのクリップボードだけが提供されてきた。そうすると、みんな考えることは同じで、複数のクリップボードを使い分け出来たら便利なんじゃないだろうかと。試しにgoogle:OSX クリップボード等で検索してみると、様々なクリップボードの機能を拡張するアプリケーションがヒットする。だけども、自分が求める要件を満たしてくれるアプリケーションはなかなか見つからない...。

検索した多くのアプリケーションは、コピーの履歴を呼び出す方式になっていた。この方式だとコピーする度に対応するショートカットが変化してしまう...。変化するクリップボードの中身を常に気にする必要があり、それが煩わしい。

OS9時代からあるCopyPasteなどは理想的なのだが、シェアウェアで今となってはちょっと割高感がある。自分が求める機能はシンプルな下記用件のみ。

  • 指定したクリップボードにショートカット一発でコピーして、ショートカット一発でペーストできること。
  • 使い分けるクリップボードの数としては5つくらいで十分。
  • クリップボードの中身は確認できなくてもOK。
    • 保存先のクリップボードは自分が指定するので、自分の記憶で覚えておくことにする。
    • 忘れた時はペーストすれば見られるし、間違ってペーストしたらcommand-Zで取り消しする。

そんなクリップボード拡張アプリケーションがどこかにないかな、フリーウェアでないかなと探していたが、なかなか見つからない。考えているうちに自分でも作れるような気がしてきた。いつものAppleScriptQuicksilverの組み合わせで。早速、やってみた。

作業環境

クリップボードの拡張(clipシリーズ)

  • クリップボードの保存用(clip1.scpt)、コピー処理(clip1_copy.scpt)、ペースト処理(clip1_paste.scpt)と3つの役割に分けてみた。
  • 下記コード(clip1.scpt、clip1_copy.scpt、clip1_paste.scpt)をclipフォルダに入れて、ユーザーScriptフォルダに移動すればOK。
  • 3つで一組のファイル名の数字の部分を変更してコピーすることで、使い分けるクリップボードの数を好きなだけ増やせる。
~/Library/Scripts/clip/clip1.scpt
~/Library/Scripts/clip/clip1_copy.scpt
~/Library/Scripts/clip/clip1_paste.scpt
~/Library/Scripts/clip/clip2.scpt
~/Library/Scripts/clip/clip2_copy.scpt
~/Library/Scripts/clip/clip2_paste.scpt
...
  • フォルダ名とファイル名は重要。ルール外に変更すると動作しない。
  • Quicksilverからのショートカット操作で利用することが前提なので、スクリプトメニューからは実行できない。
    • (* ブロック *) 内のコードを有効にすれば、スクリプトメニューからも利用可能になる。
    • その場合、副作用としてショートカット操作した時に対象アプリケーションのウィンドウが前面に出てくる。(アプリケーション切替でアクティブにした状況と同じ)
clip1.scpt
property pb : ""
clip1_copy.scpt
  • 選択部分をクリップボード経由でclip1.scptに保存する。
  • ポイントは(the clipboard as record)という書き方。これで様々なデータを扱えるようになった!
on clipName()
    tell application "Finder"
        set myName to name of (path to me) as text --自分自身のファイル名
        --「_」で区切ったリストに変換
        set text item delimiters of AppleScript to "_"
        set nameList to text items of myName
        set text item delimiters of AppleScript to ""
        
        "clip:" & (item 1 of nameList) & ".scpt"
    end tell
end clipName

delay 0.5 --Quickslverで実行するにはひと呼吸必要だった
set current_clip to (the clipboard as record)
set CB to load script file (((path to scripts folder) as text) & clipName())

tell application "System Events"
    (*
    --操作対象のアプリを最前面に設定する(スクリプトメニューから実行する場合必要)
    set appName to (name of every process whose frontmost is true) as text
    tell process appName
        set frontmost to true
    end tell
    *)
    keystroke "c" using command down
    delay 0.5
end tell

  --set pb of CB to (the clipboard as «class rtfd») --リッチテキスト添付ファイルのみ
  --set pb of CB to (the clipboard as «class RTF ») --リッチテキスト
  --set pb of CB to the clipboard--テキストグループ
set pb of CB to (the clipboard as record) --すべて

store script CB in file (((path to scripts folder) as text) & clipName()) replacing yes
delay 1
set the clipboard to current_clip
clip1_paste.scpt
  --property CB : load script file (((path to scripts folder) as text) & "clipboard.scpt")--実行時に更新されないのでNG
on clipName()
    tell application "Finder"
        set myName to name of (path to me) as text --自分自身のファイル名
        --「_」で区切ったリストに変換
        set text item delimiters of AppleScript to "_"
        set nameList to text items of myName
        set text item delimiters of AppleScript to ""
        
        "clip:" & (item 1 of nameList) & ".scpt"
    end tell
end clipName

delay 0.5 --Quickslverで実行するにはひと呼吸必要だった
set current_clip to (the clipboard as record)
set CB to load script file (((path to scripts folder) as text) & clipName())
set the clipboard to pb of CB

tell application "System Events"
    (*
    --操作対象のアプリを最前面に設定する(スクリプトメニューから実行する場合必要)
    set appName to (name of every process whose frontmost is true) as text
    tell process appName
        set frontmost to true
    end tell
    *)
    keystroke "v" using command down
end tell

delay 1
set the clipboard to current_clip
ショートカットの割り当て

Quicksilverには以下のように登録してみた。

  • 例えば、クリップ1を利用するには...
    • control-shift-1でコピー(clip1_paste.scpt)
    • control-option-1でペースト(clip1_copy.scpt)


操作感
  • Quicksilverからのショートカット操作は快適で、気持ち良くコピー&ペーストの操作ができた。
  • プレーンテキストに限らず、リッチテキスト、画像、ファイルなどもコピーできる。(通常のcommand-Cのコピーと同じだと思う。...ではなかった。

自由な拡張(wrapシリーズ)

AppleScriptクリップボードをこんなに簡単に扱えることが分かれば、あとは想像力と創意工夫次第で、自分好みに自由に拡張することができそう!

括弧で囲む
  • 選択範囲の文字列を「括弧」で囲む。
delay 0.5 --Quickslverで実行するにはひと呼吸必要だった
(*
--操作対象のアプリを最前面に設定する(スクリプトメニューから実行する場合必要)
set current_app to short name of (info for (path to frontmost application))
activate application current_app --tell application "System Events"ブロック内ではエラーになる
*)
tell application "System Events"
    keystroke "c" using command down
    delay 0.5
    set the clipboard to "「" & (the clipboard as string) & "」"
    keystroke "v" using command down
end tell
  • バリエーションで""、''、[]、{}、()、<>なども作ってみた。
  • 特殊な括弧を登録するのもありかも。


両端を1文字ずつ削除
  • 選択範囲の両端を1文字ずつ削除する。(括弧を取り除きたい時などに)
delay 0.5 --Quickslverで実行するにはひと呼吸必要だった
(*
--操作対象のアプリを最前面に設定する(スクリプトメニューから実行する場合必要)
set current_app to short name of (info for (path to frontmost application))
activate application current_app --tell application "System Events"ブロック内ではエラーになる
*)
tell application "System Events"
    keystroke "c" using command down
    delay 0.5
    set the clipboard to text 2 thru -2 of (the clipboard as string)
    keystroke "v" using command down
end tell
スタイルの復活(文字の大きさや太さなど)
  • 括弧付きに変換や両端削除をした時、スタイル情報は失われてしまう...。
    • スタイルを復活させたいそんな時は、以下のショートカットの連続技で幸せ。
    • command-Z、shift-option-command-V
タグで囲む
  • さらに、現在のクリップボードの文字列をタグとして認識して、選択範囲の文字列を囲むようにしてみた。
    • 現在のクリップボードの文字列は<div>、</div>、divのどれでもOK。(divは一例。abcならのようなタグを生成する。)
    • 「文字列」を選択して実行すると「<div>文字列</div>」に変換される。
delay 0.5 --Quickslverで実行するにはひと呼吸必要だった

set aWord to (the clipboard as string)
if aWord starts with "<" then set aWord to text 2 thru -1 of aWord
if aWord starts with "/" then set aWord to text 2 thru -1 of aWord
if aWord ends with ">" then set aWord to text 1 thru -2 of aWord
set startTag to "<" & aWord & ">"
set endTag to "</" & aWord & ">"
(*
--操作対象のアプリを最前面に設定する(スクリプトメニューから実行する場合必要)
set current_app to short name of (info for (path to frontmost application))
activate application current_app --tell application "System Events"ブロック内ではエラーになる
*)
set current_clip to the clipboard
tell application "System Events"
    keystroke "c" using command down
    delay 0.5
    set the clipboard to startTag & (the clipboard as string) & endTag
    keystroke "v" using command down
end tell
delay 1
set the clipboard to current_clip
ショートカットの割り当て

ショートカットは複合キー押しまくりで、もう訳解らん感じだが、以下のようにしてみた。


使い始めるまでのQuicksilverの設定が面倒かもしれないが、ショートカットは自分好みに設定できるし、AppleScriptなので欲しい機能は工夫次第で自分好みに自由に追加できる。自分スペシャルな手に馴染む操作環境を手に入れられるかも。

解決できない問題・実現したい課題

  • ショートカットの連続技で操作したい。
    • CopyPasteのようにcommand-Cのあと、commandを押し続けたまま1を押すとクリップ1に保存できるようになると便利。
    • (他のショートカットとの重複を避けるため)複合キー押しまくりの現状では、ちょっと操作し難い。
  • リッチテキストのまま括弧やタグで囲うようにしたい。
    • wrapシリーズの操作をすると、プレーンテキストとして変換されてしまう。
    • AppleScriptでリッチテキストのまま操作する方法ってあるのだろうか?
  • 文字列の選択範囲の両端を1文字広げる操作をしたい。

  • ファイル(またはフォルダ)を複数選択してコピーすると、先頭の1ファイル(または1フォルダ)しかコピー出来ない。
    • クリップボードの情報をプロパティに保存して復元する時に、何らかの情報が欠落しているのかもしれない...。
    • 原因調査中。

  • 問題は解決していないが、ファイル(またはフォルダ)を複数選択してコピーした場合、そのパスをコピーする仕様に変更した。

ダウンロード

以下のリンクからダウンロードページへ移動します。

*1:iPhoneiPod Touchに未だにコピー&ペーストの機能がない。ゲーム機ならOKだが、手のひらパソコンとして考えると大問題だと思う。