Grabbing the user cancellation (ESC key) with executionContext.isCancelled

Hi everybody

I’m not able to use executionContext.isCancelled to grab the user cancellation (ESC key) happening while executing a function

This is the code, any suggestion ?

  const suspendHistory = async (theSuspendName, functionName) => {
     
    async function doStuff(executionContext){
      
      let hostControl = executionContext.hostControl;
      let documentID = await app.activeDocument._id;
      // Suspend history state on the target document
      let suspensionID = await hostControl.suspendHistory({
          "historyStateInfo": {
              "name": theSuspendName,
              "target": [ {_ref: "document", _id: documentID}]
          }
      });

      await core.executeAsModal(functionName);
   
      if (executionContext.isCancelled) {
        console.log("TEST User has pressed ESC")
        return
      }
          
      await hostControl.resumeHistory(suspensionID);
    
    }; 

    await core.executeAsModal(doStuff, {"commandName" :  children });   
 
  };

  const clickHandler = async () => {     
    
    let historyName = "PS_FLOW: " + t(children);
    await suspendHistory(historyName,  FunctionToBeExecuted);
  } 

Instead   it  works if  executionContext.isCancelled is inserted inside a loop 
similar to the example present in the Adobe documentation   
[https://developer.adobe.com/photoshop/uxp/2022/ps_reference/media/executeasmodal/](https://developer.adobe.com/photoshop/uxp/2022/ps_reference/media/executeasmodal/)
but obviously I don't need to repeatedly execute the same function until the user presses ESC !

 
 const suspendHistory = async (theSuspendName, functionName) => {
     
    async function doStuff(executionContext){
      
      let hostControl = executionContext.hostControl;
      let documentID = await app.activeDocument._id;
      // Suspend history state on the target document
      let suspensionID = await hostControl.suspendHistory({
          "historyStateInfo": {
              "name": theSuspendName,
              "target": [ {_ref: "document", _id: documentID}]
          }
      });

      await core.executeAsModal(functionName);
   
      while (true) {
        await core.executeAsModal(functionName);
        if (executionContext.isCancelled) {
          app.showAlert("TEST User has pressed ESC")
          break
        }
      }    
          
      await hostControl.resumeHistory(suspensionID);
    
    }; 

    await core.executeAsModal(doStuff, {"commandName" :  children });   
 
  };

  const clickHandler = async () => {     
    
    let historyName = "PS_FLOW: " + t(children);
    await suspendHistory(historyName,  FunctionToBeExecuted);
  } 


I believe you don’t have executionContext in your while loop. Check Console

1 Like

thanks @Karmalakas

I’m not sure I understand what you mean, however in both cases I have executionContext

To better describe the situation, I edited my initial post and put both cases in full. The first code is the one that doesn’t work, the second is the one that works, but has the loop as for Adobe example and I don’t need the loop. I need executionContext.isCancelled to work in the first case, where there is no loop. I guess is possible someway but I’m not sure, there is something I have not understood about how this mechanism works

In your initial code sample you had a standalone loop:

while (true) {
    await core.executeAsModal(functionName);
    if (executionContext.isCancelled) {
      console.log("TEST User has pressed ESC")
      break
    }
  } 

I’d bet you didn’t have executionContext there :man_shrugging:


Anyway, what is functionName in your case? How long does it take for that function to complete? Maybe it finishes before user manages to click Esc. while (true) {} is only there in examples to make process infinite and show the dialog with a Cancel button.

BTW, your:

if (executionContext.isCancelled) {
        console.log("TEST User has pressed ESC")
        return
      }

is for doStuff and not for functionName. Which one are you canceling? You have there executeAsModal inside executeAsModal

Thanks @Karmalakas, I found the solution : executionContext.isCancelled has to be inserted inside the called function (functionname is a pointer to the function to be called) and the called function has to properly receive executionContext. I was really confused about how to implement it …

As much as regard having executeAsModal inside executeAsModal I agree that it is always better avoid redundancy nevertheless it seems to me that, according to adobe documentation itr is still possible :
https://developer.adobe.com/photoshop/uxp/2022/ps_reference/media/executeasmodal/

"You can have nested modal scopes. A target function can use executeAsModal to execute another target function. All modal scopes share the same global modal state. This mean that any nested scope can modify the state on the (single) progress bar. Similarly, you can suspend the history state of a document in one scope, and resume the state in another.!