SDK primer 2 CEPエンジンのカスタムイベントについて

| コメント(0) | トラックバック(0)

IllustratorSDKの解説に入りたいのは山々ですが、まずはSDK周辺の諸事情について解説しなければ真価を発揮できないと思います。ですから実際にヘッダファイルの解説など先の話になります。
そして今回がAdobeExtensionSDKというエクステンションパネルに関する部分の補足を行うことにします。
アンディ・ホール氏がとてもわかり易いリファレンスを日本語で書いてくれましたから少し理解しやすくなった感じがするAdobeExtensionSDKです。
わたしがちまちま書いたものよりよっぽどわかり易くて大助かりなのですが、カスタムリスナ関連の部分について少々補足しておきます。このあたりについてはネイティブ系とExtendScript及びCEPエンジンを完全にシンクロさせる為に必須の技術となります。この記事は先にEB3フォーラムに投稿したものの翻訳+詳細を付け足したものになります。

まずサンプルエクステンションです。

callbacktest.zxp

こちらをダウンロードしてください。
ディレクトリ構造は以下の様になります。

*Directory Structure
/css/styles.css
/css/topcoat-desktop-dark.min.css
/css/topcoat-desktop-darkdark.min.css
/css/topcoat-desktop-light.min.css
/css/topcoat-desktop-lightlight.min.css
/css/topcoat-host.css
/CSXS/manifest.xml
/index.html
/js/libs/CSInterface.js
/js/libs/jquery-2.0.2.min.js
/js/main.js
/js/themeManager.js
/jsx/jsxfunc.jsx

ここで使われているCSSはDavide Barranca氏の手によるAdobeExtensionSDK向けに作られたライブラリより流用しています。CSInterface.jsのバージョンは5.2で最新を利用していますのでAI18.1以降が対象となります。しかしながら、構成としてはベーシックなHTMLパネルの実装ですから17.0でも動くでしょう(未確認)。
また、重要なのはパネルのボディであるindex.htmlとそのスクリプトであるmain.js、ExtendScriptファイルであるjsxfunc.jsxファイルです。その他のものは汎用のテーマの切り替えに関するものとかjquery等なので細かい解説は省きます。
パネル自体の構造はシンプルで返り値を表示するためのテキストエリアとExtendScriptファンクションを呼び出すためのボタンのみの構成です。

*index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<!-- Will contain Topcoat original CSS href -->
<link id="topcoat" rel="stylesheet"/>
<!-- Topcoat overrides (Font, etc) -->
<link id="topcoat-host" rel="stylesheet" href="css/topcoat-host.css"/>
<link rel="stylesheet" href="css/styles.css"/>
<title></title>
</head>
<body>
    <div id="content">
        <div>
            <h3>Callback test</h3>
            <textarea class="topcoat-textarea" id="textarea" placeholder="ExtendScript function return here..."></textarea>
        <button id="btn_evalFunction" class="topcoat-button--cta">Call ExtendScript Routine</button>
        </div>   
    </div>
    <script src="js/libs/CSInterface.js"></script>
    <script src="js/libs/jquery-2.0.2.min.js"></script>
    <script src="js/themeManager.js"></script>
    <script src="js/main.js"></script>
</body>
</html>

続いてHTMLに付随するJavascriptです。HTML読み込み時に全体が実行される構成です。
initファンクションによってカスタムイベントリスナの登録と、ボタンクリック時のevalScriptの設定を行っています。

*main.js
(function () {
    'use strict';
    var csInterface = new CSInterface();
    var message = "";
    function init() {
        themeManager.init();
        csInterface.addEventListener("getCallback", function(evt) {
            message = evt.data;
            $("#textarea").text(message);
            });
        $("#btn_evalFunction").click(function () {
            csInterface.evalScript("testFunc()", function(e){
            });
        });
    }
    init();
}());

イベントリスナについて見てみましょう。
グローバル部分で

var csInterface = new CSInterface();

とCSInterfaceクラスを定義しています。CEPエンジンにおいてExtendScriptとのブリッジを行うのはほとんどがこのクラスのオブジェクトです。
addEventListenerメソッドによるカスタムリスナのセット方法ですが、まずCSInterface.jsのコメントを引用してみましょう。
Registers an interest in a CEP event of a particular type, and assigns an event handler.
The event infrastructure notifies your extension when events of this type occur, passing the event object to the registered handler function.
 @param type     The name of the event type of interest.
 @param listener The JavaScript handler function or method.
 @param obj      Optional, the object containing the handler method, if any. Default is null.

引数には監視するイベント名(ユーザー定義)とJavascriptで記述されたハンドラが必要になります。ご覧のとおり、CEPエンジン内でのカスタムイベントをやりとりする為の実装です。しかしながら、PlugPlugExternalオブジェクトというインターフェースが用意されており、ExtendScriptからダイレクトに呼び出すことができます。

csInterface.addEventListener("getCallback", function(evt) {
            message = evt.data;
            $("#textarea").text(message);
            });

先ほどのサンプルからリスナ登録部分を抜き出したものです。getCallbackというイベントを監視し、トリガされた場合はテキストエリアにペイロードを投入する動作をします。
では、ExtendScript側からどのようにdispatch(呼び出し)するのか見てみましょう。

*jsxfunc.jsx
function testFunc() {
    try {
        var xLib = new ExternalObject("lib:\PlugPlugExternalObject");
        } catch (e) {alert(e);}
    var eventObj = new CSXSEvent();
    eventObj.type = "getCallback";
    eventObj.data = "no selection";
    if (app.activeDocument.selection.length>0){
        var bnds = app.activeDocument.selection[0].geometricBounds;
        eventObj.data = "x1:"+ bnds[0] + "\ny1:" + bnds[1] + "\nx2:"+ bnds[2] + "\ny2:" + bnds[3];
        }
    eventObj.dispatch();
    xLib.unload();
    return true;
}

ExtendScriptのコード自体は全てがJavascript側からevalScriptメソッドにて呼び出されるファンクションとなっています。
冒頭のエラーコレクト部分ではPlugPlugExternalObjectを読み込みます。このエクスターナルオブジェクトはCC2014より実装が開始されたものです。現状ではAE、AI、PSのみの実装ですが、ExtendScriptインターフェース上での運用となりますので、このエクスターナルオブジェクトはAIからIDにコピーしての利用なども可能となっています。
イベントオブジェクト自体はCSXSEventに関連するオブジェクトですので、

var eventObj = new CSXSEvent();

という具合に用意するとよいでしょう。このオブジェクトのプロパティとしてtypeとdataが存在します。typeは先にCEPエンジン側のイベント名称そのものとなります。dataはイベントに付随して送られるペイロードです。今回はファンクションが呼び出された時に選択されていたオブジェクトのgeometricBoundsをペイロードとして返します。ペイロードの組み立て自体は単純な操作なのでコードを追ってください。
イベントのトリガはdispatchメソッド一発です。

eventObj.dispatch();

こうすると設定されたオブジェクトをエクスターナルオブジェクトを介してCEPエンジン側へ投げることができます。
最後にマニフェストを

*manifest.xml
<?xml version="1.0" encoding="UTF-8"?>
<ExtensionManifest Version="5.0"
ExtensionBundleId="net.sytes.chuwa.callbacktest"
ExtensionBundleVersion="1.0.0"
ExtensionBundleName="callbacktest"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <ExtensionList>
        <Extension Id="net.sytes.chuwa.callbacktest" Version="1.0" />
    </ExtensionList>
    <ExecutionEnvironment>
        <HostList>
            <Host Name="ILST" Version="[17.0,18.9]" />
        </HostList>
        <LocaleList>
            <Locale Code="All" />
        </LocaleList>
        <RequiredRuntimeList>
            <RequiredRuntime Name="CSXS" Version="5.0" />
        </RequiredRuntimeList>
    </ExecutionEnvironment>
    <DispatchInfoList>
        <Extension Id="net.sytes.chuwa.callbacktest">
            <DispatchInfo >
                <Resources>
                <MainPath>./index.html</MainPath>
                <ScriptPath>./jsx/jsxfunc.jsx</ScriptPath>
                </Resources>
                <Lifecycle>
                    <AutoVisible>true</AutoVisible>
                </Lifecycle>
                <UI>
                    <Type>Panel</Type>
                    <Menu>callBackTest</Menu>
                    <Geometry>
                        <Size>
                            <Height>440</Height>
                            <Width>300</Width>
                        </Size>
                    </Geometry>
                    <Icons>
                    </Icons>                    
                </UI>
            </DispatchInfo>
        </Extension>
    </DispatchInfoList>
</ExtensionManifest>

この様にバージョンは17.0〜18.9への対応としています。18.9というのはマイナーバージョンが変化しただけの場合、そのまま対応できる場合がほとんどなのでこう記述されているのだと思います。(サンプル見本にやっているだけで本当の所に関しては良くわかっていなかったりします。)

さて、実際の動作です。書類上にある四角等を選択した上でこのパネルのボタンをクリックします。すると、パネルのテキストエリアに選択対象のバウンズが表示されます。このデータはevalScriptメソッドの返り値ではなく、トリガされたイベントのペイロードより取得しています。

callbacktest.png


追記
invokeする際にIntやReal等、Number系の型でデータを渡した場合、アプリケーションがクラッシュするようです。

0 libsystem_c.dylib 0x00007fff8f291172 strlen + 18
1 libstdc++.6.dylib 0x00007fff8ea62dd5 std::string::operator=(char const*) + 21
2 com.adobe.PlugPlugOwl 0x0000000126ae1faa csxs::event::EventManager::DispatchApplicationEvent(csxs::event::Event const*) + 44
3 com.adobe.PlugPlugOwl 0x0000000126ae1ea3 csxs::event::EventManager::DispatchEvent(csxs::event::Event const*) + 129 4 com.adobe.PlugPlugOwl 0x0000000126ac6545 PlugPlugDispatchEvent + 121
5 com.adobe.CEP.PlugPlugExternalObject 0x00000001287d8604 objectCall(long*, SoCClientName_s*, int, TaggedData_s*, TaggedData_s*) + 140
6 com.adobe.illustrator.plugins.ScriptingSupport 0x000000011e4990dc PluginMain + 1451628
7 com.adobe.AdobeExtendScript 0x0000000107166b5c ScScript::LiveObjectFunction::propCall(ScScript::Object&, ScCore::BasicArray const&, ScScript::ESVariant&) + 428
8 com.adobe.AdobeExtendScript 0x00000001070f9783 jsOpCall::run(jsRunner&, ScScript::ESVariant&) const + 899
9 com.adobe.AdobeExtendScript 0x0000000107101c25 jsOpStatements::run(jsRunner&, ScScript::ESVariant&) const + 213
10 com.adobe.AdobeExtendScript 0x00000001070fbd23 jsOpFunction::run(jsRunner&, ScScript::ESVariant&) const + 419
11 com.adobe.AdobeExtendScript 0x000000010712836a jsRunner::run(ScScript::ESVariant&) + 122
12 com.adobe.AdobeExtendScript 0x0000000107113976 jsFunction::propCall(ScScript::Object&, ScCore::BasicArray const&, ScScript::ESVariant&) + 406
13 com.adobe.AdobeExtendScript 0x00000001070f9783 jsOpCall::run(jsRunner&, ScScript::ESVariant&) const + 899
14 com.adobe.AdobeExtendScript 0x0000000107101c25 jsOpStatements::run(jsRunner&, ScScript::ESVariant&) const + 213
15 com.adobe.AdobeExtendScript 0x00000001070fbd23 jsOpFunction::run(jsRunner&, ScScript::ESVariant&) const + 419
16 com.adobe.AdobeExtendScript 0x000000010712836a jsRunner::run(ScScript::ESVariant&) + 122
17 com.adobe.AdobeExtendScript 0x00000001071138be jsFunction::propCall(ScScript::Object&, ScCore::BasicArray const&, ScScript::ESVariant&) + 222
18 com.adobe.AdobeExtendScript 0x000000010714affb ScScript::RealEngine::exec(int, ScScript::Object&, ScScript::Object&, ScCore::BasicArray const&, ScScript::ESVariant&, int) + 763
19 com.adobe.AdobeExtendScript 0x000000010714cde6 ScScript::RealEngine::eval(ScScript::Script&, ScCore::Variant*, int, int, ScCore::Variant const*) + 646
20 com.adobe.AdobeExtendScript 0x000000010714cab1 ScScript::RealEngine::eval(ScCore::String const&, ScCore::Variant*, int, int, ScCore::Variant const*, ScCore::String const*, int) + 193
21 com.adobe.illustrator.plugins.ScriptingSupport 0x000000011e4330b6 PluginMain + 1033798
22 com.adobe.illustrator.plugins.ScriptingSupport 0x000000011e433abf PluginMain + 1036367
23 com.adobe.illustrator.plugins.ScriptingSupport 0x000000011e43a13d PluginMain + 1062605
24 com.adobe.illustrator.plugins.ScriptingSupport 0x000000011e439625 PluginMain + 1059765
25 com.adobe.illustrator.plugins.Services 0x0000000126a5e4bd 0x126a31000 + 185533
26 com.adobe.illustrator.plugins.Services 0x0000000126a5e304 0x126a31000 + 185092
27 com.adobe.PlugPlugOwl 0x0000000126af2f8b PlugPlugErrorCode boost::_bi::bind_t, boost::arg<2>, boost::arg<3> > >::operator()(char const*&, char const*&, char const**&) + 49
28 com.adobe.PlugPlugOwl 0x0000000126af2fb9 boost::detail::function::function_obj_invoker3, boost::arg<2>, boost::arg<3> > >, PlugPlugErrorCode, char const*, char const*, char const**>::invoke(boost::detail::function::function_buffer&, char const*, char const*, char const**) + 37
29 com.adobe.PlugPlugOwl 0x0000000126af52f2 boost::function3::operator()(char const*, char const*, char const**) const + 86
30 com.adobe.PlugPlugOwl 0x0000000126af8a84 csxs::services::host::ApplicationCallbacksLogger::EvaluateScript(char const*, char const*, char const**) + 82
31 com.adobe.PlugPlugOwl 0x0000000126b30d5b csxs::commands::CmdEvalRawScriptImpl::Execute() + 237
32 com.adobe.PlugPlugOwl 0x0000000126b2e7e0 csxs::dom::PlugPlugClassJS::evalScript(vcfoundation::data::IVCString*, vcfoundation::data::IVCString*, vcfoundation::data::IVCString*) + 34
33 com.adobe.PlugPlugOwl 0x0000000126b1fd82 __-[PlugPlugHtmlIpcServerEndpoint evalScript:internalID:]_block_invoke_5 + 205
34 com.adobe.PlugPlugOwl 0x0000000126b1a763 -[PlugPlugHtmlIpcServerEndpoint runBlockOnMainQueueSync:] + 101
35 com.adobe.PlugPlugOwl 0x0000000126b1f9e5 -[PlugPlugHtmlIpcServerEndpoint evalScript:internalID:] + 83
36 com.apple.CoreFoundation 0x00007fff87d2933c __invoking___ + 140
37 com.apple.CoreFoundation 0x00007fff87d29192 -[NSInvocation invoke] + 290
38 com.apple.CoreFoundation 0x00007fff87dc7e56 -[NSInvocation invokeWithTarget:] + 54
39 com.apple.CoreFoundation 0x00007fff87d9a886 ___forwarding___ + 518
40 com.apple.CoreFoundation 0x00007fff87d9a5f8 _CF_forwarding_prep_0 + 120
41 com.apple.CoreFoundation 0x00007fff87d2933c __invoking___ + 140
42 com.apple.CoreFoundation 0x00007fff87d29192 -[NSInvocation invoke] + 290
43 com.apple.Foundation 0x00007fff85773942 -[NSConnection dispatchInvocation:] + 138
44 com.apple.Foundation 0x00007fff8577360d -[NSConnection handleRequest:sequence:] + 1360
45 com.apple.Foundation 0x00007fff857221a5 -[NSConnection handlePortCoder:] + 657
46 com.apple.Foundation 0x00007fff85721ae9 -[NSConnection dispatchWithComponents:] + 50
47 com.apple.Foundation 0x00007fff85705ff1 __NSFireMachPort + 254
48 com.apple.CoreFoundation 0x00007fff87d6ea0d __CFMachPortPerform + 285
49 com.apple.CoreFoundation 0x00007fff87d6e8d9 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 41
50 com.apple.CoreFoundation 0x00007fff87d6e84b __CFRunLoopDoSource1 + 475
51 com.apple.CoreFoundation 0x00007fff87d603c7 __CFRunLoopRun + 2375
52 com.apple.CoreFoundation 0x00007fff87d5f838 CFRunLoopRunSpecific + 296
53 com.apple.HIToolbox 0x00007fff85bab43f RunCurrentEventLoopInMode + 235
54 com.apple.HIToolbox 0x00007fff85bab1ba ReceiveNextEventCommon + 431
55 com.apple.HIToolbox 0x00007fff85baaffb _BlockUntilNextEventMatchingListInModeWithFilter + 71
56 com.apple.AppKit 0x00007fff912fe821 _DPSNextEvent + 964
57 com.apple.AppKit 0x00007fff912fdfd0 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 194
58 com.apple.AppKit 0x00007fff912f1f73 -[NSApplication run] + 594
59 com.adobe.exo.framework 0x000000010ab07bb8 exo::app::OS_AppBase::RunEventLoop() + 56
60 com.adobe.illustrator 0x00000001004e24a5 boost::exception_detail::copy_boost_exception(boost::exception*, boost::exception const*) + 4459765
61 com.adobe.illustrator 0x00000001004715e6 boost::exception_detail::copy_boost_exception(boost::exception*, boost::exception const*) + 3997238
62 com.adobe.illustrator 0x0000000100462480 boost::exception_detail::copy_boost_exception(boost::exception*, boost::exception const*) + 3935440
63 com.adobe.illustrator 0x0000000100002f74 0x100000000 + 12148

Davide Barranca氏より報告があったのですが、上記が、わたしが再現した際のクラッシュ時のトレースです。どうやらPlugPlugExternalObjectがプッシュするPlugPlugOwlフレームワーク側がNumberを受け付けないようです。
これは仕様と考えるべきかもしれないですね。しかしながら、それならそれで情報を開示しておくべきでしょう。

トラックバック(0)

トラックバックURL: /525

コメントする

このブログ記事について

このページは、tenが2014年11月26日 12:34に書いたブログ記事です。

ひとつ前のブログ記事は「Illustrator SDK Primer 1」です。

次のブログ記事は「Made by Configurator」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

OpenID対応しています OpenIDについて
Powered by Movable Type 5.12

    follow? twitter...     
    available on exchange