This tip shows you the first way to make an HTML Panel listen and react to Photoshop Events: via PhotoshopRegisterEvent
.
Back in the Flash land, there were two ways to register callbacks for Photoshop Events: using either a PSHosttAdapter library, or an ExternalInterface object and PhotoshopCallback. Today’s tip is about the latter (see Tip #8 for the PSHostAdapter libraries).
What we used to write in ActionScript was something like:
1 2 3 4 5 6 7 8 9 10 11 12 |
// Set TypeID for desired events private const COPY_INT:int = Photoshop.app.charIDToTypeID(’copy’); private const PASTE_INT:int = Photoshop.app.charIDToTypeID(’past’); // Register for events CSInterface.PhotoshopRegisterEvent(COPY_INT + "," + PASTE_INT); // attach a callback ExternalInterface.addCallback("PhotoshopCallback" + CSInterface.getExtensionId(), myPhotoshopCallback); // Define the callback private function myPhotoshopCallback(eventID:Number, descID:Number):void { // } |
Things are slightly different now in Javascript. and are based on CSInterface
and the dispatching of a custom Event. As follows the mechanism in a nutshell, then I’ll show you an actual example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
var csInterface = new CSInterface(); // Create a new Event var event = new CSEvent("com.adobe.PhotoshopRegisterEvent", "APPLICATION"); // Set Event properties: extension id event.extensionId = "com.example.psevents"; // Set Event properties: data (as Type ID string, comma separated) // 1668247673 = charIDToTypeID( "copy" ) = copy // 1885434740 = charIDToTypeID( "past" ) = paste // 1668641824 = charIDToTypeID( "cut " ) = cut event.data = "1668247673, 1885434740, 1668641824"; // Dispatch the Event csInterface.dispatchEvent(event); // Attach a callback csInterface.addEventListener("PhotoshopCallback", PSCallback); // Define the callback function PSCallback(csEvent) { /* ... */ } |
Example
This Panel has a switch to turn ON/OFF the listener for few PS Events (cut, copy, paste). When the listener is active and the user cuts, copies or pastes, the Event’s StringID is written in the text area. In case you need a refresh of HTML Panels related topics to go through this one, here’s the whole list.
You might need a refresh because this example uses Topcoat CSS (see HTML Panels Tip #6) and communication between HTML and JSX (Tip #4).
HTML
The Panel uses boilerplate code by David Deraedt with the addition of Topcoat CSS (refer to HTML Panels Tip #6 for the details). I’ve set up a Topcoat Switch and a Text Area:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<!doctype html> <html> <head> <meta charset="utf-8"> <link id="hostStyle" rel="stylesheet" href="css/theme.css"/> <link id="theme" rel="stylesheet" href="css/light.css"/> <title></title> </head> <body> <div style="width: 80%; margin:0 auto"> <h3 class="center">PS Events</h3> <label class="topcoat-switch"> <input id="registerEvent" type="checkbox" class="topcoat-switch__input"> <div class="topcoat-switch__toggle"></div> </label> <input type="text" id ="result" class="topcoat-text-input" style="margin-left:10px" placeholder="Listen for Events" value=""> </div> <script src="js/libs/CSInterface-4.0.0.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> |
Javascript
In main.js
it’s defined the Register() function that attaches (or remove) the listener, dispatching a CSEvent as you’ve already seen.
A jQuery function binds the switch to Register()
and finally a PSCallback
function is defined: there, the Event data String is split and passed for evaluation to JSX (see Tip #4 for details about HTML to JSX data exchange). The evalScript
callback (that is, the JSX return value) is displayed in the Text Area.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
(function () { 'use strict'; var csInterface = new CSInterface(); function Register(inOn) { if (inOn) { var event = new CSEvent("com.adobe.PhotoshopRegisterEvent", "APPLICATION"); } else { var event = new CSEvent("com.adobe.PhotoshopUnRegisterEvent", "APPLICATION"); } event.extensionId = "com.example.psevents"; // some events: // 1668247673 = charIDToTypeID( "copy" ) = copy // 1885434740 = charIDToTypeID( "past" ) = paste // 1668641824 = charIDToTypeID( "cut " ) = cut event.data = "1668247673, 1885434740, 1668641824"; csInterface.dispatchEvent(event); } function init() { themeManager.init(); // Switch onChange callback $('#registerEvent').change(function() { Register( $(this).is(':checked') ); // true or false }); } function PSCallback(csEvent) { var dataArray = csEvent.data.split(","); // send to JSX to convert typeIDs to stringIDs csInterface.evalScript('convertTypeID(' + JSON.stringify(dataArray[0]) + ')', function(res) { $('#result').val(res.toString()); }); } init(); csInterface.addEventListener("PhotoshopCallback", PSCallback); }()); |
JSX
In the JSX file there’s just a function, that converts the TypeID to StringID and returns it.
1 2 3 |
function convertTypeID (typeArray) { return typeIDToStringID(Number(typeArray)); } |

Hi David,
Can you suggest how to register for indesign events?
Thanks
Hi David,
Thank you for your articles about Photoshop Events, I according to the way you did (tried both ways), events that did not work, COPY/CUT/… without any response, I don’t know where is the problem.
My environment:
OSX10.9.2
photoshop 14.2.1 x64
Eclipse Version: Kepler Service Release 2,Build id: 20140224-0627
Extension Builder 3
thanks
xiaohui
Hi David,
Do you have a list of the event names mapped to the charIDToTypeID? Or how would you recommend I go about finding them?
I’m especially interested in listening to a foregroundColor/backgroundColor change.
Thanks,
Petar
Hi,
For anyone who may need it, here’s a link to a lits of all PS enums, for event see those who’s name begin with phEvent :
HTH,
Arnaud.
Hi Davide
Thank you for this article and the rest re CS html extensions, they are very helpful.
Do you know if its also possible to trigger custom events from the JSX and catch them in the applications JS ?
Thanks a bunch …
Hi Dani,
thanks for the kind words – as per custom events, according to this article introducing CEP 5 it’s going to be possible! Let’s see when next CEP version will be released.
Great. Thanks! 🙂
Hi
What is the use of descID, the number after ‘,’ as in 31800 in 1 936483188, 31800 ?
Thanks
Hi Rishabh, where do you actually read the number 31800?
Hi (again) Davide,
Do you know if it’s possible to listen to color change and/or ‘paint with brush’ events? I think color change is borrowed within SET event but I’m not sure if it’s possible to distinguish color events and other Set events
Hello Sergey,
I think only via scripting notifiers it is possible to add an extra eventClass property, see pag. 137 of the JS reference – not (yet?) from panels.
I have problems with PhotoshopCallback function, the problem is that when I open a document, function receives ,in theory, one event, but the functions that are inside ‘if (eventID == 1332768288)’ are executing twice, or three times.. or only once (the correct)… You know a solution?
I will be crazy
Thankyou!
function PhotoshopCallback(eventDesc) {
var dataArray = eventDesc.data.split(“,”);
var eventID = dataArray[0];
var descID = dataArray[1];
if (eventID == 1332768288) { //eventOpen=1332768288
alert(“eventOpen”+eventID);
callReadResource(“photoshopcallback open”);
callReadPreview()
}
…
}
I’m having troubles too – I’m investigating Sergio.
Callback fires each time you close/reopen the panel one extra time (you close/reopen the panel 9 times, you get 9 callback calls). Strangely enough, Chrome Dev Tools seem to prevent the callback from firing altogether. I’m quite puzzled.
Hello!
Have you news about this?
Thanks!
Ciao Sergio,
have you tried with the new PhotoshopCallbackUnique (see one of the latest tip, available since CC2015)?
I have it!!!
I am doing the register just after unregister.. and its stupid but now works fine!
Something like this:
case 16: // CC 2015
registerEvents(false);
registerEvents(true);
break;
Thanks!
Thanks, this was great!
I know it’s super-legacy, but really worth adding to the post.
Be EXTREMELY SURE to ONLY PUT STRINGS into data of CSEvent.
I was parsing the output of evalScript and ended up having integers there and nothing was working, took me quite some time to figure out