Can I use JXA to read/write to KM Named Clipboards?

Continuing the discussion from Using KM variables in Yosemite Javascript for Applications (JXA):

If so, can I tie this into an existing Javascript? I want to copy and paste different elements in Adobe Illustrator. Until now I have transferred a named clipboard to the System Clipboard with KM then run a JSX. When I need a different named clipboard I go back to KM, update the clipboard and run another JSX. Just wondering if there's a better way of accessing KM clipboards using JXA.

See Clipboard Tokens.

You can use Clipboard Tokens in a script to GET a Named Clipboard, but NOT set one. See Using Keyboard Maestro Engine commands from AppleScript. You'll have to convert those to JXA.

However to set a KM Named Clipboard requires using a KM Action. You could setup a KM Macro designed to be called/triggered from a script that would use the current System Clipboard to set a specific Named Clipboard.

The first question one should always ask when considering use of Clipboards, is "Do I really need to use clipboards?"

Clipboards are really only needed when dealing with objects other than plain text.
So, if you're just dealing with plain text, you're usually better off using either KM Variables (global or local) and/or text files.

HTH.

2 Likes

@JMichaelTX, thanks for the reply. Yes, the clipboards are for graphics, not text. I'll read the link you provided.

I've been looking for documentation on how to "convert a JSX to JXA". Not finding much. This JXA was written by a associate. I've learned to edit it for parsing a JSON. I don't know though, how to convert my Adobe Illustrator JSX scripts to JXA. They use Adobe's flavor of Javascript called "ExtendScript". I usually use Adobe's antiquated "ExtendScript Toolkit" for actual editing then paste to KM or run the script from disk using AppleScript.

(function(myJSONstring) {
  'use strict';
  //parse the string into a useable object
  var myJSONobject = JSON.parse(myJSONstring);
  //define our variables that we are going to use
  var kme = Application('Keyboard Maestro Engine');
  var currentLineId = kme.getvariable("lineId");
  var myLayouts = myJSONobject.layouts;

  kme.setvariable('creativeWorkId', {
    to: myJSONobject.creativeWorkId
  });
  kme.setvariable('vectorFileName', {
    to: myJSONobject.vectorFileName
  });
  kme.setvariable('totalLayouts', {
    to: myJSONobject.layouts.length
  });
  for (var n = 0; n < myLayouts.length; n++) {
    if (myLayouts[n].lineId == currentLineId) {
      //set KM variables for simple values
      kme.setvariable('Order_1', {
        to: myLayouts[n].orderId
      });
      kme.setvariable('filePrefix', {
        to: myLayouts[n].filePrefix
      });
      kme.setvariable('frontFileName', {
        to: myLayouts[n].frontFileName
      });
      kme.setvariable('backFileName', {
        to: myLayouts[n].backFileName
      });
      kme.setvariable('tertiaryFileName', {
        to: myLayouts[n].tertiaryFileName
      });
      kme.setvariable('pdfFileName', {
        to: myLayouts[n].pdfFileName
      });
      //first check to see if there is an assignedRing
      if (myLayouts[n].assignedRing) {
        //if there is a ring, set the ring variables
        kme.setvariable('ringCircumference', {
          to: myLayouts[n].assignedRing.circumference
        });
        kme.setvariable('ringWidth', {
          to: myLayouts[n].assignedRing.width
        });
      } //end if ring

      //loop through all the options in the first layout
      for (var i = 0; i < myLayouts[n].options.length; i++) {
        //variables for the description and value
        var desc = myLayouts[n].options[i].description;
        var myVal = myLayouts[n].options[i].value;

        if (desc.indexOf('Back Engraving') != -1) {
          kme.setvariable('backEngraving', {
            to: myVal
          });
        } else if (desc.indexOf('Front Engraving') != -1) {
          kme.setvariable('frontEngraving', {
            to: myVal
          });
        } else if (desc.indexOf('Inside Engraving') != -1) {
          kme.setvariable('backEngraving', {
            to: myVal
          });
        } else if (desc.indexOf('Front Inscription') != -1) {
          kme.setvariable('frontInscription', {
            to: myVal
          });
        } else if (desc.indexOf('Back Inscription') != -1) {
          kme.setvariable('backInscription', {
            to: myVal
          });
        } else if (desc.indexOf('Back First Initial') != -1) {
          kme.setvariable('backFirstInitial', {
            to: myVal
          });
        } else if (desc.indexOf('Back Middle Initial') != -1) {
          kme.setvariable('backMiddleInitial', {
            to: myVal
          });
        } else if (desc.indexOf('Back Last Initial') != -1) {
          kme.setvariable('backLastInitial', {
            to: myVal
          });
        } else if (desc.indexOf('Front First Initial') != -1) {
          kme.setvariable('frontFirstInitial', {
            to: myVal
          });
        } else if (desc.indexOf('Front Middle Initial') != -1) {
          kme.setvariable('frontMiddleInitial', {
            to: myVal
          });
        } else if (desc.indexOf('Front Last Initial') != -1) {
          kme.setvariable('frontLastInitial', {
            to: myVal
          });
        } else if (desc.indexOf('name') != -1) {
          kme.setvariable('name', {
            to: myVal
          });
        } else if (desc.indexOf('Last Name') != -1) {
          kme.setvariable('lastName', {
            to: myVal
          });
        } else if (desc.indexOf('First Name') != -1) {
          kme.setvariable('firstName', {
            to: myVal
          });
        } else if (desc.indexOf('Date of Death') != -1) {
          kme.setvariable('dateOfDeath', {
            to: myVal
          });
        } else if (desc.indexOf('Date of Birth') != -1) {
          kme.setvariable('dateOfBirth', {
            to: myVal
          });
        } else if (desc.indexOf('Dates') != -1) {
          kme.setvariable('dates', {
            to: myVal
          });
        } else if (desc.indexOf('Name') != -1) {
          kme.setvariable('Name', {
            to: myVal
          });
        } else if (desc.indexOf('Inscription') != -1) {
          kme.setvariable('insideInscription', {
            to: myVal
          });
        }
      } //end options loop
    } //end line id check
  } //end layouts loop
})(Application('Keyboard Maestro Engine')
  .getvariable('capturedJSON'));

This is a sample "ExtendScript JSX" for Adobe Illustrator run from KM. I'd like to convert it to JXA so I could do things like paste directly from a KM Named Clipboard without first loading it in KM. Is it just a matter of adding the "var kme = Application('Keyboard Maestro Engine');" and run it through the JXA Action? Guess I"ll try that. Edit: Nope, that didn't work.

var aDoc = app.activeDocument;  
var sel = aDoc.selection;
var ilayer = aDoc.layers['FINGERPRINT'];  
aDoc.activeLayer = ilayer;  

//Paste Fingerprint
app.paste();
app.executeMenuCommand("sendBackward"); 

var AlignObj = aDoc.pageItems.getByName('FingerprintAlign');
    
//Scale Down Print Function
function sclDnProp(item, maxSize) {  
    var W = item.width,  
        H = item.height,  
        MW = maxSize.W,  
        MH = maxSize.H,  
        factor = W / H > MW / MH ? MW / W * 100 : MH / H * 100;  
  
     if (W > MW || H > MH) {  
     item.resize(factor, factor);  
    }  
};  

sclDnProp(app.selection[0], {W: %Variable%FP_Width%*%Variable%DND_mm%, H: %Variable%FP_Width%*%DND_mm%});  

var sel = aDoc.selection;
//Align Fingerprint Function
function alignToObj()  
{  
    var keyCenter = getCenterPoint(AlignObj); 
    var curItem,curCenter; 
    const ALIGNMENT_PREFERENCE_VERTICAL = true;  
    const ALIGNMENT_PREFERENCE_HORIZONTAL = true;  
 
//~     for (var x = 0, len = sel.length - 1; x < len; x++)
    for (var x = 0, len = sel.length; x < len; x++)
    {  
        curItem = sel[x];  
        if(ALIGNMENT_PREFERENCE_HORIZONTAL)  
        {  
            //align the object horizontally  
            curItem.left = keyCenter.h - curItem.width/2;  
        }  
        if(ALIGNMENT_PREFERENCE_VERTICAL)  
        {  
            //align the object vertically  
            curItem.top = keyCenter.v + curItem.height/2;  
        }  
    }  
    function getCenterPoint(item)  
    {  
        return {"h":item.left + item.width/2, "v":item.top - item.height/2};  
    }  
}  
alignToObj();  

How do I convert my JS to JXA?

And I doubt that you will.

It is mostly a matter of understanding/using core JavaScript, and the target app scripting model, to use JXA.

So, for example, where you have:

var aDoc = app.activeDocument;  
var sel = aDoc.selection;

you are going to need to first create the reference to the target app.

var app = application("Adobe Illustrator")

then hopefully your other statements should work:

var app = application("Adobe Illustrator")

// -- Now these statements should work
//    provided they are in the AI scripting model used by Apple

var aDoc = app.activeDocument;  
var sel = aDoc.selection;

I don't know anything about JSX, but I would guess that it mostly just extends core JavaScript to use the Adobe scripting model.

For more info about JXA, see

But to explore the scripting model for any app, I'd highly recommend using Script Debugger 7. This uses AppleScript, but the JXA app elements and commands will be the same, just need to be converted from AppleScript to JavaScript.

Several on the Adobe Illustrator Scripting Forum have provided some sample scripts and guidance on JXA and Illustrator. Here is a script that updates text fields sharing the same names as their corresponding KM variables. I tried using the "%Variable%" syntax but it does not work in this case:

function run() {  
  setContents('dates') ;  
  setContents('Name') ;  
  setContents('frontInscription') ;
  
}  
  
function setContents(myText) {  
  // get contents of variable from Keyboard Maestro  
  const kmEngine = Application('Keyboard Maestro Engine') ;  
  varText = kmEngine.getvariable(myText) ;  
        
  // set contents of selected text frame to variable contents  
  const aiApp = Application('Adobe Illustrator') ;  
  const doc = aiApp.documents[0] ;  
  const theFrame = doc.textFrames[myText] ;  
  theFrame.contents = varText ;  
}