Photoshop Eyedropper isn't detected with a listener

I’m using this code to listen which tool the user is using, and I want to run a code after the user have used the eyedropper tool, however this logs the other tools except Eyedropper Tool, is it a bug?

const listener = (e, d) => {
  console.log(d.selectedTool.ID);
}

require('photoshop').action.addNotificationListener([
  {
  event: "toolModalStateChanged"
  }
], listener);

Logs all the tools except the Eyedropper tool, is there a way to make this work?

These are some tools logged and how the Eyedropper tool should be logged after clicking on the canvas.
**
image
**

The event you are observing, toolModalStateChanged, is probably of internal use and too broad in scope.

What about the following events?

  • The moment a tool is changed. Event select, content eyedropperTool
  • The moment a color is captured. Event set, source eyeDropperSample
2 Likes

Thanks for this solution man, this will work. Is there any where I can see a list of all the events that can be listen?

You could try listening to the all event and log the callback event to see what it actually is. all will work only in development I think. Or at least when plugin is not loaded via CCD

1 Like

I made it to work with the eyeDropper Tool by sampling the canvas, but now I have another problem, when it listens seems it runs the listener 4 times and it crashes my workflow, is this a known issue or it can be stopped to just listen once? When it listens and knows it is the eyeDropper Tool I want to run my code just once and it is being run 4 times.

This is my code:

const listener = async (e, d) => {
  if (d.source == "eyeDropperSample" && e == "set") {
    // RUN SOME CODE
    console.log(d);
  }
}

require('photoshop').action.addNotificationListener([
  {
    event: "set"
  }
], listener);

This is what I get the console with a single click on the canvas:

I am using the development version of Alchemist’s listener. It should have more events than the marketplace version.

I actually wrote a listener for set and there is no duplication. It seems we need to remove a listener as you said.

If you write it in React Hooks (Preact Hooks), remove the listener when unmounting the component with useEffect. I don’t know of how to do the same thing with plain JavaScript only.

// preact
import { h } from 'preact' ;
import { useEffect } from 'preact/hooks' ;

// adobe
import photoshop from 'photoshop' ;
const { action } = photoshop ;

export const App = () => {
  useEffect(() => {
    // add listener on componentWillMount
    const onSet = async (event, descriptor) => {
      if ( (event === 'set') && (descriptor.source === 'eyeDropperSample') ) {
        console.log(descriptor) ;
      }
    } ;
    action.addNotificationListener(['set'], onSet) ;

    // remove listener on componentWillUnmount
    return () => {
      action.removeNotificationListener(['set'], onSet) ;
    } ;
  }, []) ;

  return (
    <div className='your-panel'>
      ...
    </div>
  ) ;
} ;

Flipping the opinion around, removeNotificationListener may not be relevant. There was no evidence of it being called when I closed the panel or exited the app. Is it the version?

I checked in this environment.

  • macOS 11.7.6 (Apple Silicon)
  • Photoshop 2023 (24.5.0), Photoshop 2022 (23.5.5)

I used it but won’t work on production probably.

Thanks for this I’ll try to implement it, I use plain JS i don’t know how to use react / React

I found that It was logging four times because I had Alchemist plugin opened, now without Alchemist opened it logs two times, it is still a problem.

I made a little hack to make it work in case this helps to anyone:

When I run the listener() function it runs twice, why? I don’t know… But I used a setTimeout() function to give a little time to its callback function to somehow let the first time it is run to turn false the IS_HUE_EYEDROPPER_ACTIVE variable, so if this variable isn’t true the code won’t run. Does this makes sense for you? It works as I expected, however this shouldn’t be the fix to it but it is a patch meanwhile someone can tell me why it is logged twice.

The update() function is the function that I want to be called each time the user uses the eyeDropper Tool, so what I did, I created a global variable called UPDATED_WITH_EYEDROPPER to update my IS_HUE_EYEDROPPPER_ACTIVE variable at the end of the update() function.

const update = async() => {
  // SOME LOT OF CODE
  //...
  //...
  IS_HUE_EYEDROPPER_ACTIVE = UPDATED_WITH_EYEDROPPER;
}

const listener = async (e, d) => {
  UPDATED_WITH_EYEDROPPER = true;
  setTimeout(async () => {

    if (IS_HUE_EYEDROPPER_ACTIVE && d.source == "eyeDropperSample" && e == "set") {
      console.log(d);
      IS_HUE_EYEDROPPER_ACTIVE = false;
      await update();
    }

  }, 100);
}
  
require('photoshop').action.addNotificationListener([
  {
  event: "set"
  }
], listener);

1. addNotificationListener accepts an array of strings

I was wondering why your code passes an object instead of a string. But it works fine in my environment.

2. is the mouse chattering?

I recall experiencing a similar problem recently. It was caused by the mouse triggering two clicks on its own for a single click. I solved the problem by using a different mouse.

Sometimes Ps produces two event for a single action. One with isCommand: true and another with false. Restarting Ps should leave only one event (at least this usually helps). I believe this double event happens only while developing and it’s a single event on production plugins. This was already mentioned somewhere here, but I don’t recall any reply from Adobe

I saw that the _isCommand true and_isCommand false are produced by the Alchemist plugin, does that happens as well to you if you don’t have the Alchemist plugin loaded?

Interesting what you mention about the double click of the mouse, I don’t is my mouse though, but I wouldn’t be a solution for users to change their mouse if they get a error window because of this bug. I somehow with the code above made it to handle the duplicated call.

Actually never noticed, so can’t tell. Could be the case… :man_shrugging:

1 Like

I second the idea to listen to the select event.
Keep in mind that, when developing and restarting the plugin multiple times (e.g. because webpack, etc.), notifiers may pile up. It happened to me a while ago: I got one callback trigger, then two, then three and finally the bell rang :slight_smile:

3 Likes