Plug-Ins: Modifier Keys

The Application class for Omni applications, on both macOS and iPadOS (with Magic Keyboard), contains instance properties for identifying the use of modifier keys when action are triggered:

These properties can be used in Omni Automation actions to determine if the user has pressed any of the standard Apple modifier keys.

Here’s a simple plug-in that will display a dialog indicating which modifier keys (if any) are pressed when the action is executed:

Modifier Key Sensor
  

/*{ "type": "action", "targets": ["omnioutliner","omnigraffle","omniplan","omnifocus"], "author": "Otto Automator", "identifier": "com.omni-automation.all.modifier-key-sensor", "version": "1.1", "description": "This action will display an alert showing which modifier keys are pressed when the action is triggered.", "label": "Modifier Key Sensor", "shortLabel": "Modifier Key Sensor", "paletteLabel": "Modifier Key Sensor", "image": "gear" }*/ (() => { const action = new PlugIn.Action(function(selection, sender){ // action code keys = new Array() if (app.commandKeyDown){keys.push("Command Key " + '\u2318')} if (app.optionKeyDown){keys.push("Option Key " + '\u2325')} if (app.shiftKeyDown){keys.push("Shift Key " + '\u21E7')} if (app.controlKeyDown){keys.push("Control Key " + '\u2303')} if (keys.length === 0){keys = ["No modifier keys were pressed."]} alertStr = keys.join("\n") alert = new Alert('\uF8FF' + ' Modifier Keys',alertStr) alert.show() }); action.validate = function(selection, sender){ // validation code return true }; return action; })();
modifiers-ios
modifiers-og-none modifiers-oo-all

Attach|Detach Actions using Modifiers

In OmniGraffle, Omni Automation actions can be “attached to” or “assigned to” graphic objects in documents. A graphic’s “assigned” action can be triggered using the Browser tool (hold down B key):

og-action-browse-tool

Using Omni Automation in OmniGraffle, you can programmatically attach and detach actions to and from graphic objects. In your actions, you can add routines for attaching and detaching the action based upon the use of modifier keys.

In the following action example, if the user presses the Option key (⌥) while selecting the action from the Automation memu, a dialog will be presented to the user for confirming that they wish to attach the action to the currently selected graphics.

If approved by the user, the action will attach itself to the selected graphics.

Conversely, if the user presses the Shift key (⇧) while selecting the action from the Automation menu, a dialog will be presented to the user for confirming the detachment of any existing actions assigned to the selected graphics.

Detailed explanation of the script is placed above and below the featured code:

 01-08  Action metadata object contains the Automation and ToolBar menu titles and description.

 12-28  The first conditional checks to see if the Option key is currently pressed. If true, the user is prompted to approve the attachement of the this action to the selected graphics.

 29-43  The second conditional checks to see if the Shift key is currently pressed. If true, the user is prompted to approve the detachment of all actions from the selected graphics.

 23, 38  The automationAction property is used to attach and detach a PlugIn action to a graphic. The value of the automationAction property of a graphic is an array of two strings, the first being the plugin id and the second being the name for an automation action. This automation action is performed when this graphic is clicked/tapped with the action tool or in presentation mode. NOTE: solitary (single-file) actions like this example use the value of the identifier in the metadata at the top of the file for the Plug-In ID.

 44-111  The third condition is performed if neither the Option nor Shift keys are pressed. In this example, the graphic is replicated and styled in a “flower-like” pattern, by manipulating the properties of the Rect class.

Flower-tize the Selected Graphic

  

/*{ "type": "action", "targets": ["omnigraffle"], "identifier": "com.omni-automation.og.flowertize-graphic", "author": "Otto Automator", "version": "1.5", "description": "Creates a flower pattern of clones from the selected graphic.", "label": "Flower-tize Selected Graphic", "shortLabel": "Flower-tize Graphic", "paletteLabel": "Flower-tize Graphic", "image":"tree.fill" }*/ (() => { const action = new PlugIn.Action(function(selection, sender){ try { if(app.optionKeyDown){ alertTitle = 'CONFIRM ACTION ATTACHMENT' alertMessage = 'Attach this action to each of the selected graphics?' var alert = new Alert(alertTitle, alertMessage) alert.addOption("Attach") alert.addOption("Cancel") alert.show(buttonIndex => { if (buttonIndex == 0){ pluginID = action.plugIn.identifier actionID = action.name selection.solids.forEach(solid => { solid.automationAction = [pluginID, actionID] }) console.log('Action attached') } }) } else if(app.shiftKeyDown){ alertTitle = 'CONFIRM ACTION DETACHMENT' alertMessage = 'Detach any actions from each of the selected graphics?' var alert = new Alert(alertTitle, alertMessage) alert.addOption("Detach") alert.addOption("Cancel") alert.show(buttonIndex => { if (buttonIndex == 0){ selection.solids.forEach(solid => { solid.automationAction = [] }) console.log('Action detached.') } }) } else { var cnvs = document.windows[0].selection.canvas selection.solids.forEach(s => { g = s.geometry c = s.fillColor c1 = Color.RGB(c.red * 0.9,c.green * 0.9,c.blue * 0.9) c2 = Color.RGB(c.red * 0.2,c.green * 0.2,c.blue * 0.2) // 1 d = s.duplicateTo(new Point(g.maxX,g.maxY),null) d.fillType = FillType.Linear d.gradientColor = c2 d.gradientAngle = 225 // 2 d = s.duplicateTo(new Point(g.minX-g.width,g.maxY),null) d.fillType = FillType.Linear d.gradientColor = c2 d.gradientAngle = 315 // 3 d = s.duplicateTo(new Point(g.minX-g.width,g.minY-g.height),null) d.fillType = FillType.Linear d.gradientColor = c2 d.gradientAngle = 45 //4 d = s.duplicateTo(new Point(g.maxX,g.minY-g.height),null) d.fillType = FillType.Linear d.gradientColor = c2 d.gradientAngle = 135 // 5 d = s.duplicateTo(new Point(g.maxX,g.minY),null) d.rotation = 45 d.fillType = FillType.Linear d.fillColor = Color.white d.gradientColor = c1 d.gradientAngle = 135 // 6 d = s.duplicateTo(new Point(g.x,g.maxY),null) d.rotation = 45 d.fillType = FillType.Linear d.fillColor = Color.white d.gradientColor = c1 d.gradientAngle = 225 // 7 d = s.duplicateTo(new Point(g.x-g.width,g.minY),null) d.rotation = 45 d.fillType = FillType.Linear d.fillColor = Color.white d.gradientColor = c1 d.gradientAngle = 315 // 8 d = s.duplicateTo(new Point(g.x,g.minY-g.height),null) d.rotation = 45 d.fillType = FillType.Linear d.fillColor = Color.white d.gradientColor = c1 d.gradientAngle = 45 // center circle aRect = g.insetBy(g.width/5,g.height/5) circle = cnvs.addShape('Circle', aRect) circle.fillType = FillType.Radial circle.fillColor = Color.white circle.gradientColor = c2 // original square s.fillType = FillType.Radial s.fillColor = Color.white s.gradientColor = c2 }) } } catch(err){ new Alert(err.name, err.message).show() } }); action.validate = function(selection, sender){ return (selection.solids.length > 0) }; return action; })();

 114-118  The function that is the value of the validate property, returns a boolean value of true if one or more solid graphics (not lines) are selected in the document. If true the menu item is enabled, if false the menu item is disabled.

 09-121  The main action function.

OmniGraffle Action Attach/Detach Template

OmniGraffle Action Attach/Detach Template


/*{ "type": "action", "targets": ["omnigraffle"], "identifier": "com.omni-automation.og.xxxxxxxxx", "author": "Your Name or Org", "version": "1.0", "description": "Description.", "label": "Menu Title", "shortLabel": "Menu Title", "paletteLabel": "Menu Title", "image":"gear" }*/ (() => { const action = new PlugIn.Action(async function(selection, sender){ try { if(app.optionKeyDown){ alertTitle = 'CONFIRM ACTION ATTACHMENT' alertMessage = 'Attach this action to each of the selected graphics?' var alert = new Alert(alertTitle, alertMessage) alert.addOption("Attach") alert.addOption("Cancel") alert.show(buttonIndex => { if (buttonIndex == 0){ pluginID = action.plugIn.identifier actionID = action.name selection.solids.forEach(solid => { solid.automationAction = [pluginID, actionID] }) console.log('Plug-in action attached.') } }) } else if(app.shiftKeyDown){ alertTitle = 'CONFIRM ACTION DETACHMENT' alertMessage = 'Detach any actions from each of the selected graphics?' var alert = new Alert(alertTitle, alertMessage) alert.addOption("Detach") alert.addOption("Cancel") alert.show(buttonIndex => { if (buttonIndex == 0){ selection.solids.forEach(solid => { solid.automationAction = [] }) console.log('Plug-in action detached.') } }) } else { // PROCESSING STATEMENTS GO HERE } } catch(err){ if(!err.causedByUserCancelling){ new Alert(err.name, err.message).show() } } }); action.validate = function(selection, sender){ // ONE OR MORE SOLID GRAPHICS SELECTED return (selection.solids.length > 0) }; return action; })();