AppleScriptの実行を途中で任意に停止したい、という場合があります。そのための方法についてまとめておきました。
# Blog消失前の投稿を再構成して「たぶんこんな内容」と推測して投稿したものです
実行を中断させる方法はいくつか存在します。ただし、そのためには「何によってAppleScriptが実行されているか」、つまり「ランタイム環境が何なのか?」を明らかにする必要があります。
AppleScriptのランタイム環境は、つきつめると数種類「しか」ないわけですが、そのランタイム環境を呼び出している側のアプリケーションにどの程度の制約を課されているか、という要素も加わってきます。
システムのあちらこちらに存在しているAppleScriptのランタイム環境のうち、ユーザーに近い部分のものについて述べることにしましょう。
ランタイム環境が「スクリプトエディタ」の場合の止め方
スクリプトエディタ上で実行中のAppleScriptは、Command-.(ピリオド)で停止できるようになっています。
ただし、すでに操作対象のアプリケーション側に制御が移っている場合には、アプリケーション側の処理が終わるまで待たされますし、アプリケーションが最前面にくるように(activate)AppleScriptが書かれていた場合には、スクリプトエディタに対して停止のキーボードショートカットを送ることは困難です。
最終的には、Command-Option-Escapeで実行中のプロセス一覧を表示させて、スクリプトエディタを強制終了させることになります。
もちろん、Terminal.app上で、Script Editor.appのプロセス番号を調べて、
% kill -7 xxx
などと野蛮な止め方をしてもよいでしょう。AppleScriptの実行を野蛮な方法で停止しても、AppleScriptの内容が壊れることはまずありません。ただし、処理していたデータは中途半端な状態のままになってしまいます。こうした処理を行う場合には、くれぐれも元データを保持しておいて、AppleScriptによる処理が失敗したり途中で停止するようなことになっても、再度実行できるようにしておきましょう。
ランタイム環境がアプレットの場合の止め方
個人的に、AppleScriptアプレットというランタイム環境はスクリプトエディタ上と挙動が変わってくるので、あまり好きではありません。それでも、タイマー割り込みやドラッグ&ドロップなどの機能を使う場合にはアプレット(ドロップレット)として保存する必要が出てきます。
アプレットの場合も、スクリプトエディタ同様Command-.(ピリオド)で止めることになりますが、たいてい止まらないのでCommand-Option-Escapeによる強制終了、あるいはターミナルから実行中のアプレットのプロセスIDを調べて強制終了、でもよいでしょう。
ランタイム環境がスクリプトメニューの場合の止め方
スクリプトメニューをどのプログラムが受け持っているか、Mac OS Xの歴史を振り返ると、いろいろ移り変わりがありました。実行するアプリケーションが単独で存在していたり、System Eventsが受け持っていたり、osascriptを呼び出していたり、ふたたび単体のアプリケーションに戻ったり。OSのバージョンを限定して話をすると、macOS 10.10〜10.13の環境ではosascriptによって実行されてきました。
スクリプトメニューからAppleScriptを実行させると、メニューに回転する歯車アイコンが表示されます。この歯車アイコンをクリックすると実行中のAppleScript一覧が表示され(複数のScriptを並行して同時に実行させることもできます)各Scriptの右下の×ボタンを押すと停止できます。
これでも止まらない場合には、Terminalからosascriptのプロセスをkillすれば大丈夫です。
macOS 10.14ではスクリプトメニューが「スクリプトメニュー」という別のアプリケーションとして実装されたので、macOS 10.14上のスクリプトメニューのランタイム環境は「スクリプトメニュー」です。Command-Option-Escapeでは終了できないので、ターミナルから「スクリプトメニュー」のプロセスIDを調べてkillすることになります。
その他の止め方
Xcode上でAppleScriptによるGUIアプリケーションを作成し、InDesignやIllustratorなどのアプリケーションを操作する処理を実行。この外部アプリケーションの操作を行う処理を止めたいといった場合もあります。
AppleScript Studioの頃とは異なり、最近のAppleScriptObjCによるGUIアプリケーション作成時には、GUIアプリケーション側と外部アプリケーション操作側は完全に分離され、後者についてはXcode上では編集すらできません。データの受け渡しはuser defaults経由で行ったりしています。
難易度の低いやり方は、外部アプリ制御側Scriptで、「処理ループ内で何らかのシグナルを監視する」というものです。特定フォルダの有無でも「メッセージ」アプリケーションのステータスメッセージでも特定Webサーバー上の特定URLのファイルでもよいのですが、それらが存在した場合には停止、というプログラム自体を組んでおきます。デスクトップ上に「Stop」という名前のフォルダが存在していたら終了、というあたりがわかりやすくて簡単な実装例でしょう。
難易度の高いやり方は、外部アプリ制御Scriptを、メモリ上に作成したOSAScriptView上で実行し、停止時にはOSAScriptControllerにstopScript:メソッドを実行するというものです。もちろん、外部アプリ制御Scriptはアプリケーションバンドル内に暗号化したファイルに保存しておき、実行時に復号化してOSAScriptViewにロードすることになります。ユーザーからの停止の仕組みを受け取るのは、Shiftキーなどのキースキャンを定期的に行うことで実現できます。
難易度の高い方が柔軟に止められますが、おすすめは難易度の低いほうです。
AppleScriptのプログラムの実行を止める – AppleScriptの穴 says:
[…] 以前に、AppleScriptの実行を止めるためにさまざまな方法で、「止めるためのアクション」を検出する方法について紹介したことがあります。 […]