CEPガイド6:ツール・パネル間のイベント

本記事はCEPスーパーメガガイドのPart 6です。
エクステンションの参考用ソースはこちら

前回の記事でツール側のスクリプトをほぼカバーしたが、残った課題はツールとHTMLパネルの間のイベントのやり取り。

概要

  • パネルVM側でのイベント処理は簡単。パネル同士、エクステンション同士、ツール同士のイベントやり取りを出来るし、仕組みはツールによって変わらない。
  • ツール側からパネルVMへのイベントはツールで異なる:
    • ExtendScriptに対応するツールでは、Pluginを使ってカスタムイベントをパネルに渡せる。
    • FlashとPhotoshopの場合、ツールの多くのネイティブイベント(ファイル編集など)をパネルから直接取得できる
    • Flash・PS以外のツールではいくつかのネイティブイベントをとれるが、場合によってはツールVM側で取得してからカスタムイベントとしてパネルに渡す必要がある

パネルVMでのイベント取得・発送

パネルVMで出来るイベント処理は全てCSInterface.jsにある。(CSInterfaceの概要についてはPart 3まで)

var cs = new CSInterface();
cs.addEventListener( "hoge", function(e) {
alert("event: "+e);
} );

var event = new CSEvent("hoge", "APPLICATION"); event.data = "こんにちは";
new CSInterface().dispatchEvent(event);

パネル側のカスタムイベントのやり取りは上記の通り。CSEventクラスはCSInterface.jsに定義され、詳細を把握するにはソースを見るのが最も有効的。

エクステンション同士のイベントは、デフォルトの仕組みである。イベント名の名前空間はグローバルなので、イベントのtype さえ一致すれば他のエクステンションに渡せる。イベント名が被らないように、IDをプレフィックスするのがお勧め:

var event = new CSEvent();
event.type = "com.aphall.myExt.myPanel.myEvent";

パネルVMのイベントの使い方

カスタムイベント以外に、CEPの仕組みからのイベントもパネル側で取得できる。各ツールにはUIの背景色を変更できるが、その変更イベントを取ればHTMLパネルのデザインをツールに合わせて、標準UIの一部に見せることが出来る。しかし色情報はイベントオブジェクトに入っていないのでイベントを取ったらCSInterfaceから取得する。方法は:

var cs = new CSInterface();
cs.addEventListener(
CSInterface.THEME_COLOR_CHANGED_EVENT,
setAppTheme
);

function setAppTheme(event) {
var hostEnv = window.__adobe_cep__.getHostEnvironment();
var skinInfo = JSON.parse(hostEnv).appSkinInfo;
var color = skinInfo.panelBackgroundColor.color;
alert( "ツールのbg色➔ " +
"r="+color.red +
", g="+color.green +
", b="+color.blue
);
// ...
}

また、場合によっては特別なイベントをディスパッチするとホストツールの設定変更を出来る。例えば、PhotoshopのHTMLパネルのコンテンツが永続する設定は下記のように出来る:

// 永続性を設定する
var event = new CSEvent();
event.type = "com.adobe.PhotoshopPersistent";
event.scope = "APPLICATION";
event.extensionId = window.__adobe_cep__.getExtensionId();
new CSInterface().dispatchEvent(event);

これでパネルを閉じてもHTMLコンテンツが永続する。私が知る限りでは上記の動作がまだドキュメントされていないが、Photoshopに対応するイベント名リストはCEP担当者のHallgrimurによってこちらに投稿されている

ツール側のネイティブイベントの取得

各ツールがユーザの動作によって発送するイベントをCSInterfaceで取得することが可能だが、取れるイベントはツールで異なる。

● Flash Pro の場合:

Flashのイベント取得には、決まったイベント名を通常通りにリスナーを作るだけ。取得可能なイベントは:

com.adobe.events.flash.documentChanged
com.adobe.events.flash.timelineChanged
com.adobe.events.flash.documentSaved
com.adobe.events.flash.documentOpened
com.adobe.events.flash.documentClosed
com.adobe.events.flash.documentNew
com.adobe.events.flash.layerChanged
com.adobe.events.flash.frameChanged
com.adobe.events.flash.selectionChanged
com.adobe.events.flash.mouseMove

例えばFLAファイルが開かれた時のイベントを取るには:

new CSInterface().addEventListener(
"com.adobe.events.flash.documentOpened",
function(e) {
alert("doc Opened");
}
);

FlashがHTMLパネルに渡すイベントのドキュメンテーションはFlash CC リファレンスのp384にある。

● ExtendScriptの全ツールの場合:

ExtendScriptの場合、一部のツール側のイベントはCSInterfaceで登録できる:

// 下記は Illustrator、InCopy、InDesign のみに対応
new CSInterface().addEventListener(
"documentAfterActivate",
function(event) {
alert("Event type:" + event.type +
"\nData: " + event.data );
}
)

しかし上記対応のイベントは数少ない。リストの確認にはCEP 5のドキュメンテーションのP41-42をご参照。

● Photoshopの場合

Photoshopではツールの各イベントを取得出来るが、Flashのように直接CSInterfaceからは取得しない。逆に、Photoshopから取得したイベントのコード番号をオブジェクトに詰めて、それをcom.adobe.PhotoshopRegisterEvent のイベントとしてディスパッチする。そしてそのイベントが発送すると、CSInterfaceのコールバックで取れる。

例えばコピー・ペーストのイベントを取得するには:

var event = new CSEvent();
event.type = "com.adobe.PhotoshopRegisterEvent";
event.scope = "APPLICATION";
event.data = "1668247673, 1885434740";

var cs = new CSInterface();
cs.dispatchEvent(event);

cs.addEventListener(
"PhotoshopCallback",
function(e) {
alert("イベント: " + e.data);
}
);

これでPhotoshopのネイティブイベントを取得できる。しかし謎はイベントのdata プロパティを"1668247673, 1885434740" に設定するところ。実は、その数字はコピーとペーストのことを指しているコードで、PhotoshopのツールVMで確認できる:

// Photoshop用のJSX:
charIDToTypeID( "copy" ) // 1668247673
charIDToTypeID( "past" ) // 1885434740

Photoshopは内部的に色んな動作を指す4文字コード(上記では”copy”と”past”)があって、そのコードをツールVMのcharIDToTypeID に渡せば、動作のイベントコードを取得できる。そしてそれを上記のイベント登録に使えば、結局はPhotoshopのネイティブ動作のイベントを確認できることになる。各動作を指す4文字コードは、PhotoshopのJavascriptリファレンスの最後のAppendix Aセクションにある。

ツールVMからカスタムイベントの発送

ツールがネイティブに発送するイベント以外にも、好きなイベントをツールVMから発送するExtendScriptのAPIもある。(現時点ではJSFL用のAPIは無いので、ネイティブイベントを利用する必要となる。)

方法は、PlugPlugExternalObject というプラグインを使う。現状ではPhotoshop、Illustrator、Premiere ProとAfter Effectsはそれぞれこのプラグインを内部的に実装するので、エクステンションに追加する必要は無い。InDesign、InCopyで使うには、プラグインをエクステンションのソースに置いて、CEPドキュメンテーションのp41のようなコードを実装する必要がある。

そしてイベントを発送仕方は:

var xLib;
try {
xLib = new ExternalObject("lib:\PlugPlugExternalObject");
} catch(e) { alert("Missing ExternalObject: "+e); }

// ツールVMからカスタムイベントを発送
$.sendEvent = function(type) {
if (xLib) {
var eventObj = new CSXSEvent();
eventObj.type = type;
eventObj.data = app.toString();
eventObj.dispatch();
}
}

一見すると上半分のnew ExternalObject() が必要なさそうだが、それが実行されるまではCSXSEvent クラスが読み込まれないので、エクステンションの初期に一度行う必要がある。その後でCSXSEvent を作ってディスパッチすると、type プロパティに一致するパネル側のリスナーにイベントが届く。

ツール同士のイベント

最後に、ちょっと意外だがツール同士のイベント取得、または宛先のツールのインストールチェックや起動も可能となる。ツール同士のやり取りには、Vulcan.jsを利用する。CEPリソースのリポジトリから手に入れて、CSInterface.jsと同じ用に使う。メッセージの渡し方はこんな感じ:

// ツール同士 メッセージ登録
VulcanInterface.addMessageListener(
VulcanMessage.TYPE_PREFIX + "com.hoge.piyo",
function(message) {
var str = VulcanInterface.getPayload(message);
alert("ツール同士イベント: " + str );
}
);

// ツール同士 状況確認
var installCheck = VulcanInterface.isAppInstalled( "flash" )
var versionCheck = VulcanInterface.isAppInstalled( "flash-14.0" )
var runningCheck = VulcanInterface.isAppRunning( "flash" )

// ツール同士 起動させる
VulcanInterface.launchApp( "illustrator-18" )

// ツール同士 メッセージ発送
var msg = new VulcanMessage (
VulcanMessage.TYPE_PREFIX + "com.hoge.piyo" );
msg.setPayload( "こんにちは" );
VulcanInterface.dispatchMessage(msg);

Vulcan.jsのさらなる詳細は、ソースまたはドキュメンテーションのp39 (IPC message handling)のご参照を。

以上かなり詳細な記事でしたが、誰かの役に立てたらな!と。
次回の最終の投稿:エクステンションのパッケージと配布