Using Ignition 7.9.11 I am unable to trigger client event scripts from newly spawned desktop instances.
I have an operator console with 4 displays that get initialized with system.gui.openDesktop(), but client keystrokes only trigger events on the initial desktop.
First, you’ll need a reference to the root FPMIApp instance. Technically, I think you can get there via SwingUtilities.getRoot. That should have a getScriptConfig method. The ClientScriptConfig object has a getKeyScripts method that returns a map of keystrokes : scripts. Then you’ll need to get a reference to the SecondaryDesktop you’re on, and get it’s input and action maps. Then loop through the keystroke/script map, creating a new KeystrokeScriptAction and adding it to the action/input map as appropriate.
from javax.swing import SwingUtilities, KeyStroke, JComponent
from com.inductiveautomation.factorypmi.application import FPMIApp, VisionDesktop
from com.inductiveautomation.factorypmi.application.script import KeystrokeScriptAction
# BFS the component tree under 'root' for a specified component type
def findComponentOfType(root, type):
queue = [root]
checked = []
while len(queue) != 0:
comp = queue.pop()
if isinstance(comp, type):
return comp
checked += [comp]
children = comp.getComponents()
queue += [child for child in children if child not in checked]
return None
# Returns dicts containing the FPMIApp's java.xswing.InputMap and ActionMap
# inputMapping - <javax.swing.KeyStroke> : <String>
# actionMapping - <String> : <com.inductiveautomation.factorypmi.application.script.KeystrokeScriptAction>
def genKeyEventMappings(fpmiApp):
scriptManager = fpmiApp.getScriptManager()
scriptConfig = fpmiApp.getScriptConfig()
keyScripts = scriptConfig.getKeyScripts()
inputMapping = {}
actionMapping = {}
for entry in keyScripts.entrySet():
stroke = KeyStroke.getKeyStroke(entry.key.getStroke())
name = entry.key.getDisplay()
inputMapping[stroke] = name
actionMapping[name] = KeystrokeScriptAction(name, scriptManager, entry.value)
return inputMapping, actionMapping
# Adds provided javax.swing.InputMap and ActionMap dicts to the given visionDesktop instance
def addAllVisionKeyEvents(visionDesktop, inputMapping, actionMapping):
actionMap = visionDesktop.getActionMap()
inputMap = visionDesktop.getInputMap()
# update input mapping:
for keystroke in inputMapping.keys():
inputMap.put(keystroke, inputMapping[keystroke])
# update action mapping:
for name in actionMapping.keys():
actionMap.put(name, actionMapping[name])
# write both updated maps back to the VisionDesktop JComponent:
visionDesktop.setInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap)
visionDesktop.setActionMap(actionMap)
# Returns the JRootPanel for a given desktop handle
# TODO: Replace with window-independent solution
def findDesktopRootPanel(handle):
desktop = system.gui.desktop(handle)
window = desktop.getOpenedWindows()[0]
rc = window.getRootContainer()
return SwingUtilities.getRoot(rc)
# Copies all Ignition Client Keystroke Event Scripts from one desktop to another
def copyDesktopKeyStrokeEvents(fromHandle, toHandle):
# find both desktop root panels and shared app reference:
root1 = findDesktopRootPanel(fromHandle)
root2 = findDesktopRootPanel(toHandle)
visionDesktop2 = findComponentOfType(root2, VisionDesktop)
fpmiApp = findComponentOfType(root1, FPMIApp)
# find and copy KeyStrokeEvent mappings from desktop1 and set in desktop2:
inputMapping, actionMapping = genKeyEventMappings(fpmiApp)
addAllVisionKeyEvents(visionDesktop2, inputMapping, actionMapping)
Call CopyDesktopKeyStrokeEvents(fromHandle, toHandle) sometime after both desktops are already opened.
Potential improvements:
Don’t use window instances to find the JRootPanels and FPMIApp instances
Use direct paths to get FPMIApp and VisionDesktop instances instead of searching the tree
Remove fromHandle parameter from copy method, since the Input and Action Maps belong to the shared FPMIApp ancestor and not any one desktop
I’m placing the above utiliy scripts in a shared.gui file along with some initialization functions to call on-startup:
def initDesktops():
system.gui.openDesktop(0, 'second', 'second', 400, 400, 400, 400, ['Main Window'])
# open further desktops or do init-y stuff here
def initAllDesktopKeyEvents():
mainHandle = system.gui.getCurrentDesktop()
handles = system.gui.getDesktopHandles()
for handle in handles:
if handle == mainHandle:
continue
copyDesktopKeyStrokeEvents(mainHandle, handle)
Yes, this is a (low priority) bug on our backlog. I can’t provide a timeline, but it should be an easy enough thing to fix first-party, so I kicked the ticket to get re-prioritized, which is as much as I can do.