Copy link to clipboard
Copied
Hello Community,
I have a problem with passing information from jsx to js file.
my jsx file:
$.extendScript = {
test : function() {
return "string";
},
}
my js file.
(function () {
var cs = new CSInterface();
var variable = "";
cs.evalScript('$.extendScript.test()', function(result) {
variable = result;
alert("variable in evalScript =" + variable);
});
alert("variable in outside = " + variable);
}());
In evalScript function the variable get's the string from jsx function but when I want to use it outside I get empty string again.
Also I get the alert outside evalScript first in order. Why this happens?
Does anyone know why this happens and how to fix this?
Best Regards
I don't know about 'Why', but...
See PProPanel for a working implementation.
JavaScript: Samples/ext.js at master · Adobe-CEP/Samples · GitHub
https://github.com/Adobe-CEP/Samples/blob/master/PProPanel/ext.js#L66
ExtendScript: Samples/Premiere.jsx at master · Adobe-CEP/Samples · GitHub
Copy link to clipboard
Copied
I don't know about 'Why', but...
See PProPanel for a working implementation.
JavaScript: Samples/ext.js at master · Adobe-CEP/Samples · GitHub
https://github.com/Adobe-CEP/Samples/blob/master/PProPanel/ext.js#L66
ExtendScript: Samples/Premiere.jsx at master · Adobe-CEP/Samples · GitHub
Copy link to clipboard
Copied
bbb_999, Could You please tell me how I can create callback on this event?
csInterface.evalScript('$._PPP_.registerProjectPanelSelectionChangedFxn()'); // Project panel selection changed
I want that the trackitem of currently selected clip will be in the input box of my Panel.
My goal is to create button on panel that if I push it, will change scale of currently selected clip.
Therefore I decide to take trackitem path from input box and send it to jsx.
May be it can be done with another algorythm?
Copy link to clipboard
Copied
n.abola wrote
bbb_999 , Could You please tell me how I can create callback on this event?
csInterface.evalScript('$._PPP_.registerProjectPanelSelectionChangedFxn()'); // Project panel selection changed
I want that the trackitem of currently selected clip will be in the input box of my Panel.
My goal is to create button on panel that if I push it, will change scale of currently selected clip.
Therefore I decide to take trackitem path from input box and send it to jsx.
May be it can be done with another algorythm?
csInterface.evalScript('$._PPP_.registerProjectPanelSelectionChangedFxn()', function( ResultsFromJsxContext ){
//Command block here
});
Copy link to clipboard
Copied
With this code You will get callback only the first time when execute this script.
But I need get callback on every changing of selection on timeline.
Copy link to clipboard
Copied
n.abola wrote
With this code You will get callback only the first time when execute this script.
But I need get callback on every changing of selection on timeline.
One approach: run your evalScript on an interval, JSX context testing timeline state with each call.
I've done it. It works.
You do raise interesting questions for bbb_999
- What is going on behind-the-scenes with evalScript? Is it wrapping an AJAX call to the JSX context? Trade secret?
- Is it possible to set up a WebSocket between JS and JSX?
Copy link to clipboard
Copied
My goal is to create button on panel that if I push it, will change scale of currently selected clip.
Change it...to what? What's the entire workflow, you're trying to support?
Also, "Allow panels to register for notification when the timeline selection changes" is a pretty popular API feature request; I'll add your vote.
What is going on behind-the-scenes with evalScript?
Yes, carefully-defended trade secret...
[Looks both ways, leans in conspiratorially...]
It passes the script...to ExtendScript engine...where it's evaluated.
Sssssh!
Web socket connections are totally possible between panels, in JavaScript; I've not heard of anyone using a web socket connection, between JavaScript and ExtendScript.
Copy link to clipboard
Copied
What's the entire workflow, you're trying to support?
I want that when I press hotkey "Q" it increases scale effect of currently selected clip on timeline to +1.
And if I press hotkey "W" it decrease scale effect of currently selected clip on timeline to -1.
I want to make it like this:
I understand that this palette uses another API, but it possible to do it with ExtendScript + Autohotkey.
It is only 1 problem - get selected trackitem object index.
Now I do it like this:
C:\Program Files (x86)\Common Files\Adobe\CEP\extensions\test\index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script src="./lib/CSInterface.js"></script>
<script type="text/javascript">
var csInterface = new CSInterface();
csInterface.registerKeyEventsInterest(JSON.stringify([
{"keyCode": 0x51}, //q
{"keyCode": 0x57} //w
]));
function evalScriptCallback(result)
{
if (result !== "undefined")
document.getElementById("selected").value = result;
}
function keyDownInBody(event)
{
if (event.keyCode == 0x51) //q
{
var ControlledEffect = "AE.ADBE Motion"; //effect matchName
var ControlledProperty = 1; //effect property scale
var step = 1; //increase/decrease value
csInterface.evalScript('var ControlledEffect = "' + ControlledEffect + '"; var ControlledProperty = ' + ControlledProperty + '; var step = ' + step + '; ' + document.getElementById("selected").value + '$._PPP_.ChangeEffectParameters()', evalScriptCallback);
}
else if (event.keyCode == 0x57) //w
{
var ControlledEffect = "AE.ADBE Motion"; //effect matchName
var ControlledProperty = 1; //effect property scale
var step = -1; //increase/decrease value
csInterface.evalScript('var ControlledEffect = "' + ControlledEffect + '"; var ControlledProperty = ' + ControlledProperty + '; var step = ' + step + '; ' + document.getElementById("selected").value + '$._PPP_.ChangeEffectParameters()', evalScriptCallback);
}
}
</script>
</head>
<body onkeydown="keyDownInBody(event)">
<input type="text" id="selected" value="var SelectedTrack = 0; var SelectedClip = 0; var SelectedEffect = 0;">
</body>
</html>
C:\Program Files (x86)\Common Files\Adobe\CEP\extensions\test\PProPanel.jsx
$._PPP_={
ChangeEffectParameters: function()
{
var NowSelectedTrack = SelectedTrack; var NowSelectedClip = SelectedClip; var NowSelectedEffect = SelectedEffect;
try {
var videoTracks = app.project.activeSequence.videoTracks;
}
catch(err) {
alert("Error!\nNo active sequence!");
return
}
try {
if (videoTracks[SelectedTrack].clips[SelectedClip].isSelected())
var clip = videoTracks[SelectedTrack].clips[SelectedClip];
}
catch(err) {
}
if (!clip)
{
exit_loops:
for (var i=0 ; i< videoTracks.numTracks ; i++)
{
for (var k=0 ; k< videoTracks[i].clips.numItems ; k++)
{
if (videoTracks[i].clips[k].isSelected())
{
var NowSelectedTrack = i; var NowSelectedClip = k;
var clip = videoTracks[i].clips[k];
break exit_loops;
}
}
}
}
if (!clip)
{
alert("Error!\nNo clip selected!");
return
}
var effects = clip.components;
try {
if (effects[SelectedEffect].matchName == ControlledEffect)
var effect = effects[SelectedEffect];
}
catch(err) {
}
if (!effect)
{
for (var l=0 ; l< effects.numItems ; l++)
{
if (effects[l].matchName == ControlledEffect)
{
var NowSelectedEffect = l;
var effect = effects[l];
break;
}
}
}
if (!effect)
{
alert("Error!\nNo such effect!");
return
}
var property = effect.properties[ControlledProperty];
if (property.isTimeVarying())
{
alert("Error!\nParameter has keyframes!");
return
}
var value = property.getValue();
property.setValue(value + step, true);
if (NowSelectedTrack == SelectedTrack && NowSelectedClip == SelectedClip && NowSelectedEffect == SelectedEffect)
return
else
return ('var SelectedTrack = ' + NowSelectedTrack + '; var SelectedClip = ' + NowSelectedClip + '; var SelectedEffect = ' + NowSelectedEffect + ';');
}
}
C:\Program Files (x86)\Common Files\Adobe\CEP\extensions\test\CSXS\manifest.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*************************************************************************
* ADOBE CONFIDENTIAL
* ___________________
*
* Copyright 2014 Adobe
* All Rights Reserved.
*
* NOTICE: Adobe permits you to use, modify, and distribute this file in
* accordance with the terms of the Adobe license agreement accompanying
* it. If you have received this file from a source other than Adobe,
* then your use, modification, or distribution of it requires the prior
* written permission of Adobe.
**************************************************************************/
-->
<ExtensionManifest Version="5.0" ExtensionBundleId="com.adobe.PProPanel" ExtensionBundleVersion="11.1"
ExtensionBundleName="Premiere Pro sample panel"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ExtensionList>
<Extension Id="com.adobe.PProPanel" Version="10.3.0" />
</ExtensionList>
<ExecutionEnvironment>
<HostList>
<Host Name="PPRO" Version="9.0" />
</HostList>
<LocaleList>
<Locale Code="All" />
</LocaleList>
<RequiredRuntimeList>
<RequiredRuntime Name="CSXS" Version="6.0" />
</RequiredRuntimeList>
</ExecutionEnvironment>
<DispatchInfoList>
<Extension Id="com.adobe.PProPanel">
<DispatchInfo >
<Resources>
<MainPath>./index.html</MainPath>
<ScriptPath>./PProPanel.jsx</ScriptPath>
<CEFCommandLine>
<Parameter>--allow-file-access</Parameter>
<Parameter>--allow-file-access-from-files</Parameter>
</CEFCommandLine>
</Resources>
<Lifecycle>
<AutoVisible>false</AutoVisible>
<StartOn>
<!-- Premiere Pro dispatches this event on startup -->
<Event>com.adobe.csxs.events.ApplicationActivate</Event>
</StartOn>
</Lifecycle>
<UI>
<Type>Modeless</Type>
<Menu>PProPanel (SDK sample panel)</Menu>
<Geometry>
<Size>
<Height>300</Height>
<Width>180</Width>
</Size>
</Geometry>
</UI>
</DispatchInfo>
</Extension>
</DispatchInfoList>
</ExtensionManifest>
Autohotkey script:
SleepDuration := 5
FirstPressDelay := 0.15
#InstallKeybdHook
#InstallMouseHook
#UseHook
DetectHiddenWindows, On
#If WinActive("ahk_exe Adobe Premiere Pro.exe") and WinExist("Script Alert ahk_exe Adobe Premiere Pro.exe")
q::
w::
return
#If WinActive("ahk_exe Adobe Premiere Pro.exe")
q::
w::
SetBatchLines -1
SetKeyDelay, -1, -1
If (A_PriorKey != "q") and (A_PriorKey != "w")
{
SetControlDelay -1
ControlClick, Chrome_WidgetWin_01, ahk_exe Adobe Premiere Pro.exe, Chrome Legacy Window,,, NA
loop
{
ControlGetFocus, Focus, ahk_exe Adobe Premiere Pro.exe, Chrome Legacy Window
if (Focus = "Chrome_WidgetWin_01")
break
}
}
KeyWait, %A_ThisHotkey%, T%FirstPressDelay%
If ErrorLevel
{
DllCall("Winmm\timeBeginPeriod", UInt, 3)
loop
{
if !GetKeyState(A_ThisHotKey, "P")
break
SendInput {%A_ThisHotKey%}
loop % SleepDuration
DllCall("Sleep", UInt, 1)
}
DllCall("Winmm\timeEndPeriod", UInt, 3)
}
Else
SendInput {%A_ThisHotKey%}
Now When we press hotkeys "Q" or "W" - selected clip on timiline will be scaled to +-1 point.
I have written autorun in manifest in hidden mode of my panel.
Autohotkey after pressing hotkey detects what control is focused in Premiere and if it is not my panel it sends click on panel.
Then it sends hotkey.
SleepDuration - pause between sending hotkeys when hotkey is hold.
FirstPressDelay - time of first pressing hotkey needed for detecting - hotkey is hold or just pressed.
And the question is - will it be possible to get trackitem object index of selected clip without looping and checking for isSelected()?
PS I can not find code tag to format post, therefore I use tag quote.
Copy link to clipboard
Copied
cs.evalScript() is an asyncronous call, meaning it will wait until it receives a reply from your jsx script before setting ‘result’ and executing the callback function your evalScript.
While asyncronous functions wait patiently before executing their callbacks, that ‘waiting’ does not halt execution of the next line of code, which in your case is the ‘outside’ alert.
So your code will execute your second ‘outside’ alert first and your first ‘in evalscript’ second.
More on asyncronous coding here Introduction to asynchronous JavaScript (Example) | hack.guides()
Copy link to clipboard
Copied
klemenm wrote
In evalScript function the variable get's the string from jsx function but when I want to use it outside I get empty string again.
Also I get the alert outside evalScript first in order. Why this happens?
Does anyone know why this happens and how to fix this?
As others have pointed out, CSInterface.evalScript is an asynchronous* function.
* There is currently a bug on Adobe apps in macOS that causes evalScript to run synchronously. This doesn't help you, however, because the callback still gets scheduled to occur after the current context completes.
Here's how your code is evaluated:
What you really want to do is run your "outside" alert after the "inside" code has had a chance to run. To do this you need to somehow get #2 to occur after #7. This is where the setTimeout function comes in handy. Try this:
(function () {
var cs = new CSInterface();
var variable = "";
cs.evalScript('"string"', function(result) {
variable = result;
alert("variable in evalScript =" + variable);
});
setTimeout(() => {alert("variable in outside = " + variable);}, 0);
}());
Note that I got rid of the special JSX-side function that simply returns "string". Rather, I just made the evalScript simply return that directly.
The important part is line 8. That schedules the anonymous, inline function to be called at a later date (the 0 at the end means "as soon as possible" - if you had heavy script in your JSX [on applications running in Windows] then you might need to delay even further with larger numbers). Honestly, though, the correct thing to do is simply trigger another function call that makes use of that captured variable from within the function itself. Both the callback passed to evalScript and the one passed to setTimeout capture a reference to the same variable instance which means that when one changes, both do. It's merely a matter of determining which callback is triggered earlier.
I hope this helps!
Copy link to clipboard
Copied
Most of this topic went over my head. Is there a way to get information from the jsx file back to the js script in your html file? I am trying to use a folder picker in the form of:
var fPath = decodeURIComponent(Folder.selectDialog("Choose the output directory"));
I can get the path and alert from the jsx file but I cannot seem to set it to a variable to display to the user in a panel field. Is this possible? Thanks
Copy link to clipboard
Copied
Is there a way to get information from the jsx file back to the js script in your html file?
Yes; see PProPanel's usage of getUserName.
Copy link to clipboard
Copied
Hi, thanks so much for the reply. I am still having no luck with what I am trying to accomplish. So that function is similar to the one I have created. Using the one you show as an example, how would I get the userName (returned) variable to be persistent so that I could update a field in my panel with its value? Thanks
Copy link to clipboard
Copied
> Using the one you show as an example, how would I get the userName (returned) variable to be persistent so that I could update a field in my panel with its value?
If you look at the JavaScript side, you'll see that getUserName is called both from within the panel's OnLoaded() function, and when PProPanel is copying presets into the user's directory, and needs the user name.
In both cases, the returned name is passed to the callback function specified, when invoking the ExtendScript. That callback function displays the user's name in the panel.
Copy link to clipboard
Copied
Thank you again, all that you have posted help me understand better. I see what you are talking about now. I think my problem is that I do not understand how to work with the "when" thing are happening. I noticed that the examples are all when things are initialized, meaning when the script starts up. I am trying to do something after the script has already started. I would like to have a field and browse button and let a user of the script choose a directory, or even manually type on in. If I start my script reporting some system variable it is fine. However, I when I refer to that variable again it is always undefined. Thanks.
Copy link to clipboard
Copied
I'll need a better understanding of the _entire_ workflow you're trying to support, from the user's perspective.
[day job address = b b b at adobe dot com]
Copy link to clipboard
Copied
Once that panel is up displaying the users name how could you refer to that property in the JavaScript file? Is there then an property that can be used again. I cannot seem to call it again. All I recieve is undefined.Thanks
Copy link to clipboard
Copied
Take a look at this JavaScript function, in PProPanel; it receives the userName returned by the ExtendScript function, and modifies the innerHTML of the object displaying the user name, in the panel.
Copy link to clipboard
Copied
I see that and under stand, however when I try to do this
===jsx file ===
getPath: function() {
fPath = decodeURIComponent(Folder.selectDialog("Choose the output directory"));
//alert(fPath);
return fPath;
},
===js file===
var mypath; var userName; var cs = new CSInterface(); function getFolder() { mypath = cs.evalScript('$.runScript.getPath()'); //document.getElementById('ppath').value = $.runScript.getPath();
} function newPath () { // Updates username with whatever ExtendScript function returns. var path_name = document.getElementById("ppath"); path_name.value = mypath; } //cs.evalScript('$.runScript.getPath()'cs.evalScript('$.runScript.getPath()', newPath);); function runAll() { cs.evalScript('$.runScript.meInOut()') } |
I cannot reffence the value to the choosen path?
Copy link to clipboard
Copied
I have changed the code so many times it might be off now. But my point is that after the first load of the panel I am not able to get the value of the Folder.selectDialog("Choose the output directory"). Thanks
Copy link to clipboard
Copied
The CSInterface.evalScript function does not return the value. It is intended to be an asynchronous call.
Instead, the callback you pass to evalScript is passed the value returned from the ExtendScript-side function.
Try this:
var cs = new CSInterface();
function getFolder() {
cs.evalScript('$.runScript.getPath()', onNewPath);
}
function onNewPath(path) {
// Updates username with whatever ExtendScript function returns.
var path_name = document.getElementById("ppath");
path_name.value = path;
}
Copy link to clipboard
Copied
That worked like a charm... funny I thought I tried to do this already. The first time @bbb_999 sugested the code in the PProPanel's example (scratching my head ). However that is great to know. I really thank you guys for suggesting so many helpful things. What @bbb directed me to is a big help also in building better scripts. Once again @sberic Thank you so much!