I'm writing a logger plugin to write UI interactions to a text file. To get fine-grained information, I'd like to include the values that the user enters in native Commands such as extrusion values etc. However, in order to get access to the Command object to define the appropriate listeners such as KeyboardEvents, I need to listen for the CommandCreatedEvent on the native CommandDefinitions. The code below does exactly that (and returns True for every .add() call). However, the notify function in the CommandCreatedHandler is never triggered.
Any help or input would be greatly appreciated.
import adsk.core, adsk.fusion, adsk.cam, traceback
handlers = []
def run(context):
ui = adsk.core.Application.get().userInterface
try:
for i in range(ui.commandDefinitions.count):
command_definition = ui.commandDefinitions.item(i)
onCommandCreated = CommandCreatedHandler(print_text)
success = command_definition.commandCreated.add(onCommandCreated) #success is true in every iteration.
handlers.append(onCommandCreated)
except:
if ui:
ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
def stop(context):
ui = None
try:
app = adsk.core.Application.get()
ui = app.userInterface
ui.messageBox('Stop addin')
except:
if ui:
ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
class CommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
def __init__(self, callback):
super().__init__()
def notify(self, args): #this is never triggered
eventArgs = adsk.core.CommandCreatedEventArgs(args)
command = eventArgs.command #this is what I need for defining the listeners
adsk.core.Application.get().userInterface.messageBox("TEST")
According to the documentation, the above should be possible:
Any command (standard Fusion 360 or API created commands) can be run by the user clicking a button or by a program calling the command definitions execute method. In either case, Fusion 360 creates a new Command object and fires the commandCreated event where it passes the Command object to your add-in. Your add-in reacts to this event by connecting to other command related events and defining the contents of the command dialog, if it has one.
Solved! Go to Solution.
Solved by kandennti. Go to Solution.
Hi @tomveuskens .
I don't know why CommandCreatedEvent is not called for native commands, but if you want to create a logger of commands used, I think it would be easier to combine commandTerminated Event and activeCommand Property.
https://help.autodesk.com/view/fusion360/ENU/?guid=GUID-E381414E-1CFF-4007-B1DF-C413D7E6841A
https://help.autodesk.com/view/fusion360/ENU/?guid=GUID-635C6C94-BA41-44D6-A97D-61BFA56C6688
I have created one that uses commandStarting and published it here.
https://github.com/kantoku-code/Fusion360_Small_Tools_for_Developers/tree/master/CommandLogger
Hi @kandennti
Thanks for your quick reply. Unfortunately, the activeCommand property returns a string with the command identifier instead of the command itself. As a result, the question of how to get access to the specifics on each command (e.g. the entered values, the deleted entities, etc.) remains unsolved sadly. Thanks for sharing your logger plugin as well, however, if I'm not mistaken this implementation also does not access the values of the commands that are started.
I tried a few things.
Since there is no event immediately after pressing the OK button of the dialog, I made CustomEvent to always monitor the dialog.
It is possible to get some information, but it does not accept keyboard input.
Therefore, I don't think it will be useful.
# Fusion360API Python add-inns
import adsk.core, adsk.fusion, traceback
import re, threading, json
_app = None
_ui = None
_handlers = []
_stopFlag = None
_myCustomEvent = 'MyCustomEventId'
_customEvent = None
_dialogInfos = []
class MyCommandTerminatedHandler(adsk.core.ApplicationCommandEventHandler):
def __init__(self):
super().__init__()
def notify(self, args):
blackList = [
'SelectCommand',
'CommitCommand'
]
try:
# command
global _ui
cmdId :str = args.commandId
if cmdId in blackList:
return
cmdDef :adsk.core.CommandDefinition = _ui.commandDefinitions.itemById(cmdId)
cmdName :str = cmdDef.name if cmdDef else '(unknown)'
infos = [f'---{cmdName}---']
# dialog
global _dialogInfos
infos.extend(_dialogInfos)
dumpMsg('\n'.join(infos))
except:
if _ui:
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
class ThreadEventHandler(adsk.core.CustomEventHandler):
def __init__(self):
super().__init__()
def notify(self, args):
def getDialogInfo() -> list:
app = adsk.core.Application.get()
txtCmdRes = app.executeTextCommand(u'Toolkit.cmdDialog')
infos =[]
for tmpInfo in txtCmdRes.split('MenuItems:\n')[:-1]:
stateInfo = tmpInfo.split('\n')[-2]
lst = [s.split('\n')[0] for s in stateInfo.split(',')]
label = re.sub(r"\s+|Label=", "", lst[-2])
value = re.sub(r"\s+", "", lst[-1])
infos.append(f'{label}:{value}')
app.executeTextCommand(u'Toolkit.hud')
return infos
try:
global _dialogInfos
_dialogInfos = getDialogInfo() #It's interfering with keyboard input.
except:
if _ui:
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
class MyThread(threading.Thread):
def __init__(self, event):
threading.Thread.__init__(self)
self.stopped = event
def run(self):
global _app, _myCustomEvent
while not self.stopped.wait(0.1):
args = {'dmy': ''}
_app.fireCustomEvent(_myCustomEvent, json.dumps(args))
def dumpMsg(msg :str):
adsk.core.Application.get().userInterface.palettes.itemById('TextCommands').writeText(str(msg))
def run(context):
try:
dumpMsg('-- start add-ins --')
global _app, _ui
_app = adsk.core.Application.get()
_ui = _app.userInterface
global _myCustomEvent, _customEvent, _handlers
_customEvent = _app.registerCustomEvent(_myCustomEvent)
onThreadEvent = ThreadEventHandler()
_customEvent.add(onThreadEvent)
_handlers.append(onThreadEvent)
global _stopFlag
_stopFlag = threading.Event()
myThread = MyThread(_stopFlag)
myThread.start()
onCommandTerminated = MyCommandTerminatedHandler()
_ui.commandTerminated.add(onCommandTerminated)
_handlers.append(onCommandTerminated)
adsk.autoTerminate(False)
except:
if _ui:
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
def stop(context):
try:
dumpMsg('-- stop add-ins --')
global _handlers, _customEvent
_handlers.clear()
_customEvent = None
global _stopFlag, _app
_stopFlag.set()
_app.unregisterCustomEvent(_myCustomEvent)
except:
if _ui:
_ui.messageBox(_('AddIn Stop Failed: {}').format(traceback.format_exc()))
That's a very creative solution, @kandennti! Thank you very much for your help, greatly appreciated.
Can't find what you're looking for? Ask the community or share your knowledge.