吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2554|回复: 1
收起左侧

[Java 转载] 【Javascript】【CEP教程-6】面板与宿主之间的交互

[复制链接]
TR小米哥 发表于 2022-2-28 16:21

bKdVPS.md.png

前面的文章我们讲到了插件面板是运行在CEF这个浏览器运行时下,而需要操作Photoshop的时候,要用到运行在宿主环境下的ExtendScript(以下简称JSX),那这两个独立的运行时之间是如何进行交互通信,且有哪些通信方式的呢,这篇文章我们来扒一扒。

面板调用宿主(JS -> JSX)

当我们在面板上点击一个按钮,然后让Photshop执行一个行为,这个时候,就需要JS调用JSX来完成,这个操作通过CSInterface提供的方法来完成,该对象提供了一个叫evalScript的方法,让我们可以在JS环境下执行一段JSX的代码,这里记得是执行一段代码,它好比原生JS的eval方法,将一串字符串代码执行,如下代码执行,就会在PS上出现一个alert弹窗:


var cs = new CSInterface();
cs.evalScript(`alert("Hi there")`);

这个函数提供了一个通往JSX世界的入口,但是光执行一段字符串代码显然在实际开发中是不够用的,因为我们的JSX代码通常都会很多很多,不可能全部都塞成一段字符串,于是我们一般将工程里的所有JSX文件都预先加载进来,然后暴露出函数,再通过evalScript函数去执行函数调用的过程。比如我在JSX文件里头有一个函数,该函数获取当前图层的名称:

// main.jsx
// 获取当前选中图层的名称
function getActiveLayerName() {
    var doc = app.activeDocument;
    return doc.activeLayer.name;
}

main.jsx文件已经有了,它放在我们的插件的jsx目录下

bKdZ8g.png

那我们如何将这个jsx文件加载进来呢,这里就涉及到前面文章【CEP教程-3】 CEP插件面板结构介绍提到的CSXS/manifest.xml文件中的配置


<Resources>
    <MainPath>./index.html</MainPath>
    <ScriptPath>./jsx/main.jsx</ScriptPath>
    <CEFCommandLine>
        <Parameter>--enable-nodejs</Parameter>
    </CEFCommandLine>
</Resources>

里面有一个ScriptPath的配置,它就是插件在启动的时候载入的入口JSX文件,按照我们上面的配置,它就能加载main.jsx文件了,这就好比我们在做网页开发的时候用script标签引用js文件一样。


<script src="./jsx/main.jsx"></script>

加载了main.jsx文件之后,我们就可以随时随地调用getActiveLayerName函数了


cs.evalScript(`getActiveLayerName()`);

我们注意到getActiveLayerName函数return返回了当前的图层名称,这个JSX的数据返回,我们可以在evalScript函数的回调方法中获取,该回调函数会将JSX返回结果输出


cs.evalScript(`getActiveLayerName()`, function(result) {
    console.log(result);
});

我们就可以在控制台中看到JSX返回的图层名称

bKduKs.md.gif

整体evalScript函数的使用非常简单,一看就会,有几个地方需要注意:

1. 参数传递

很多时候,我们需要在JS调用JSX的时候,传递一些参数进去,由于evalScript执行的是字符串,我们需要特别关注参数的拼接


// 传递基本类型
cs.evalScript(`foo("abc", 100)`);

如果传递的是对象类型参数,调用的时候需要转换成字符串,但是在JSX接收的地方并不需要做parse,系统会自动给你转化成对象


// JS
var params = {a: 100, b: "hi"};
cs.evalScript(`foo(${JSON.stringify(params)})`);

// JSX
function foo(params) {
    // 不需要做JSON.parse(params);
    alert(params.a); // 100
}

2. 错误

当我们的JSX代码执行错误的时候,evalScript返回的result就会显示 EvalScript error. ,如果我们不做处理就会导致面板的交互出现非预期的现象,于是我们可以对返回结果做一下判断


cs.evalScript(`fool()`, function(result) {
    // EvalScript_ErrMessage 是一个定义在CSInterface.js中的一个常量,值就是EvalScript error.
    if (result === EvalScript_ErrMessage) {
        console.error(result);
    } else {
        // do your code stuff
    }
});

总结: 上面我们介绍了插件面板主动调用宿主完成操作并返回结果的过程,这些过程都是面板主动发起的,那如果某些场景希望宿主主动发起一些动作让面板来处理呢,这里就涉及到插件开发过程中的事件了。

宿主调用面板 JSX->JS

说到事件,Photoshop && 插件系统提供了许多种事件场景和类型,在上一篇文章插件面板的样式中,我们就第一次说到了事件:为了能够监听Ps的主题发生变化,我们监听com.adobe.csxs.events.ThemeColorChanged事件

1. CSXSEvent


csInterface.addEventListener('com.adobe.csxs.events.ThemeColorChanged', () => {
        syncTheme();
});

这些CSXSEvent是Photoshop自身派发的事件,它们都是CSXSEvent的一部分,它也给我们提供了自定义事件的能力,这个事件可以在JSX层进行派发,然后在JS层进行监听,这样就可以实现JSX->JS这样一条通道。我们来看看实现过程,CSXSEvent是在一个叫PlugPlug插件模块提供的,我们需要先进行加载,然后通过CSXSEvent对象来实现事件派发的过程


// JSX

// 加载plugplug模块
try {
    var xLib = new ExternalObject("lib:\PlugPlugExternalObject");
} catch (e) {
    // do nothing
}

// 事件派发函数
function dispatch(message) {
    var eventObj = new CSXSEvent();
    eventObj.type = "my_custom_event_type";
    eventObj.data = '[CSXSEvent] ' + message + '';
    eventObj.dispatch()
}

// 给JS层发送事件
dispatch('message from jsx');

紧接着,和监听Ps主题变化的事件一样,我们在JS层监听事件名称my_custom_event_type,然后就可以在控制台看到输出的结果了


// JS
csInterface.addEventListener('my_custom_event_type', (data) => {
    console.log(data);
});

至于my_custom_event_type只是一个示例,你可以根据情况自己去定义事件的类型来满足实际需要,这个事件通道非常适合用来打log调试使用,因为JSX本身并没有提供浏览器输出的console.log这样的日志打印功能,那我们就可以通过CSXSEvent来模拟一个

严格来说,上面的说法不对,JSX提供了$.write/$.writeln方法用来输出日志,但是只能在ExtendTookit和相关的官方debug环境下才能用

// JSX
var console = {
    log: function(message) {
        var eventObj = new CSXSEvent();
        eventObj.type = "console_log_event";
        eventObj.data = '[JSXLog] ' + message + '';
        eventObj.dispatch();
    }
};

console.log('log message from jsx');

2. CSEvent

上面我们介绍了CSXSEvent,它可以通过宿主进行派发,也支持自定义事件类型,从JSX层进行派发,JS层监听。但是有了这些还不够,自定义的事件类型,只能做一些自己代码内部的通信,很多时候,我们希望监听Ps的一些行为,比如用户选中了一个图层,切换了一个工具等,然后通过这些行为我们继续做一些操作。这就需要用到CSEvent,它是CSInterface里头给JS层提供的一个事件对象,通过它我们可以监听宿主的一些操作事件。

为了监听这些事件,我们先要派发一个事件!

对,你没看错,为了监听Ps的事件,我们需要先派发一个注册事件的事件

// JS
var appId = csInterface.getApplicationID();
var extId = csInterface.getExtensionID();

 var csEvent = new CSEvent();
csEvent.type = 'com.adobe.PhotoshopRegisterEvent';
csEvent.scope = 'APPLICATION';
csEvent.appId = appId;
csEvent.extensionId = extId;
csEvent.data = data;    // data 是某个事件的ID,下文详述
csInterface.dispatchEvent(csEvent);

上面这个事件的派发,就是告诉宿主,我要开始监听data这个事件了,接着我们监听它的回调

// JS
csInterface.addEventListener('com.adobe.PhotoshopJSONCallback' + extId, function(result) {
        console.log(result);
});

在CC2015之前的版本,监听的事件名叫做 PhotoshopCallback,之后的版本事件名称叫’com.adobe.PhotoshopJSONCallback’ + extId

这样,当Ps发生指定的动作时候,我们就能收到回调了。

在上面的代码中data是个什么?它指明的是我们要关心的宿主发生的事件动作,那它到底填什么呢, 下面是一个监听图层选择事件的代码

// JS
csInterface.evalScript(`app.stringIDToTypeID('select')`, function (data) {
    var csEvent = new CSEvent();
    csEvent.type = 'com.adobe.PhotoshopRegisterEvent';
    csEvent.scope = 'APPLICATION';
    csEvent.appId = appId;
    csEvent.extensionId = extId;
    csEvent.data = data;
    csInterface.dispatchEvent(csEvent);
});

从我们前面学习到的知识告诉我们,JS调用了JSX的函数app.stringIDToTypeID(‘select’),得到了一个data,它就是我们需要监听的事件ID,把它赋值给csEvent.data。我们大概可以猜出来select就是选择的意思,代表了选择图层这个操作,那app.stringIDToTypeID又是什么?这里涉及到ActionManager相关的知识,我们后续会专门开篇介绍,这里不做展开,只要记住需要这么做就行了。

代码设置好之后,我们通过切换选择图层,就能在控制台里头打印输出了
bKBFV1.md.png
从上面的日志输出可以看到当前图层选择的一些数据,通过加工处理这个返回的结果,就可以拿到当前图层的信息了。 通过这种机制,我们的示例项目实现了一个实时显示用户选择图层的功能,如下图。bKde2Q.md.png

总结

这篇文章介绍了Js和JSX之间的几种交互方式,JS层通过evalScript方法来执行JSX的代码,JSX通过CSXSEvent来派发事件通知JS,JS通过注册Ps的事件来监听Ps的指定行为。

后面的教程,我们会进入JSX核心,讲述JSX DOM和Action Manager的使用,敬请期待~~

免费评分

参与人数 1吾爱币 +5 热心值 +1 收起 理由
wushaominkk + 5 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

cy102030 发表于 2023-1-5 15:02
学到东西,谢谢
mailab 发表于 2023-3-27 21:28
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-28 18:24

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表