BatchPlay _obj:"invokeCommand" what's the deal?

I’m very new to UXP programming, but have been doing JS, server, and app programming for years now. I’m looking into how much I can do with a plugin for a client of ours and have already setup a testing plugin that I’m using as a PoC/playground.

I have it set up with an eventNotifier since is appears that the GREAT majority of functionality is only going to be unlocked via batchPlay. This isn’t a big deal, I’ve already made an event “recorder” that I have grabbing those events and reshaping them into ActionDescriptors so I can feed them right back into batchPlay and enjoy!

However, I’ve notice that some events aren’t behaving the same as others and most of them seem to be of type “invokeCommand”. This is fed an ID which I assume corresponds to the internal function for that tool/function/whatever you want to call it.

One example of this is toggling a window. I was wanting to toggle on the timeline window after doing a “load files into stack” and was able to trigger the load files into stack (after using the ScriptListener plugin since the “_obj”: “AdobeScriptAutomation Scripts” doesn’t seem to trigger my event notifier), but am having issue with getting the timeline to toggle on after. The descriptor I’m getting is as follows:

let desc = {
        "_obj": "invokeCommand",
        "commandID": 1188,
        "kcanDispatchWhileModal": true
    };

But this is erroring with:

open timeline results: [
  {
    "message": "The command “<unknown>” is not currently available."
  }
]

Which from my experience with it so far mains that the “_obj” isn’t recognized, so I started trying to find anything I could about “invokeCommand” and have come up with only one post on the internet which is on these forums and basically acts like everyone should know to ignore it( https://forums.creativeclouddeveloper.com/t/certain-actions-not-recording-in-alchemist-using-script-listener-to-get-info/2187 ).

So TL;DR My question is what’s the deal with “invokeCommand” type events? Are they “protected” so they can’t be executed via “batchPlay”? Do they all have another descriptor and are really meant just to be listened to to know that that thing happened? I don’t even see an event in “ScriptListener” and only see the invoke in both my plugin and the Alchemist plugin, so how should I find the descriptor I need? Or have I reached one of the edges of what is possible in a plugin?
Thanks in advance for any relevant info!

You should check the Alchemist plugin and latest videos of @DavideBarranca about batchPlay (video 6-8). Maybe this plugin would actually give you a correct descriptors instead of converting yourself. Not sure though

2 Likes

Hi, here’s my approach to open/close the Timeline window panel in Photoshop using UXP

const batchPlay = require("photoshop").action.batchPlay;

async function toggleTimeline() {
  await batchPlay(
    [{
      _obj: "select",
      _target: [{
        _ref: "$Mn",
        _enum: "$MnIt",
        _value: "toggleAnimationPalette",
      }]
    }], {});
}

In case you’d want to just close the Timeline panel, replace toggleAnimationPalette by closeTimelinePanel

Cheers!

2 Likes

I have watched all of those and installed Alchemist and both were/are VERY helpful, but neither go into invokeCommand and alchemist is only giving those events for this and several other actions. Thanks for pointing those out though!

I’ll have to test it obviously, but looks like what I need! How would I discover that on my own? I would hate to have to make a new post on here for everyone of these I find! There must be a way to figure these out on my own.

“invokeCommand” is for your information only. This tells you what happened in Photoshop. But this can’t be played. Similar to history changed event.

2 Likes

That’s exactly what I thought, but wanted to ask someone in the know! Thanks so much for your input and your plugin!^^

Thank you so much for this little bit of info/code. Scripting the timeline is very problematic because it basically is a black box. I was heavily relying on an Action Manager equivalent to call menu items by their stringID. Again, thank you for sharing.

Is that dollar sign notation the BatchPlay version of charID’s?

btw the latest version of Alchemist adds support for the reading timeline and animation classes. Just a few basic properties.

1 Like

Hi Jarda,

I had no trouble retrieving timeline properties (thanks to your Alchemist plugin).
The only problem I have with the timeline properties is that I can’t get it to work with “multiGet” like you can with a layer reference.

Do you know if it is possible to use multiGet with the timeline reference?

I think multiGet needs explicit support in PS itself. So if it is not added by Adobe it won’t work. Or what exact data do you need to get?

Makes sense… The multiGet came to my attention because I was looking for a clean way to get multiple timeline properties in one call.

I usually only need a combination of two or three timeline properties. I made a function that accepts an array of stringID’s. The function will loop through the array get the requested properties individually and returns it as one “custom” timeline object. So that works.

When I said “problematic” I was referring to the fact that the traces left by the timeline menu functions are the explicit results (time code or offset) of calling the menu item. How much time or offset is needed can’t be calculated because there is no access to the layer timing. This is where the menu item calls are vital. In my CEP extension I had to access the raw data from a saved psd and get layer descriptors from stream to get layer timing and length. (something I don’t know how to do with UXP… argh)

Ah… multiple properties for single element. Not all elements of the timeline. Now it makes sense :slight_smile:

This does work. I am working on next version of Alchemist where it supports also multiGet:

const {batchPlay} = require("photoshop").action;

const result = await batchPlay(
   [
      {
         _obj: "multiGet",
         _target: [
            {
               _ref: "timeline",
               _enum: "ordinal",
               _value: "targetEnum"
            }
         ],
         extendedReference: [
            [
               "frameCount",
               "frameRate",
               "duration",
               "time",
               "currentFrame"
            ]
         ],
         options: {
            failOnMissingProperty: false,
            failOnMissingElement: true
         },
         _options: {
            dialogOptions: "dontDisplay"
         }
      }
   ],
   {}
);

const {batchPlay} = require("photoshop").action;

const result = await batchPlay(
   [
      {
         _obj: "multiGet",
         _target: [
            {
               _ref: "animationClass",
               _enum: "ordinal",
               _value: "targetEnum"
            }
         ],
         extendedReference: [
            [
               "enabled",
               "animationLoopCount",
               "frameCount",
               "currentFrame"
            ]
         ],
         options: {
            failOnMissingProperty: false,
            failOnMissingElement: true
         },
         _options: {
            dialogOptions: "dontDisplay"
         }
      }
   ],
   {}
);
1 Like

Yes, that’s it. I need to check my attempts and see what I did wrong :nerd_face:
Thank you very much!