Driving Altium's interface, and confining what that costs #20
salitronic
announced in
Announcements
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
What has gone into eda-agent since the library and schematic batch, for anyone catching up.
The largest piece is that Altium's interface can now be driven as tools. This exists because parts of Altium have no other route.
application.execute_menureports success while invoking nothing,GetMenuon the main frame returns 0 because the menus are DevExpress bars with no menu ids, and whole dialogs such as Update From Libraries and Preferences have no scripting API at all: nothing opens them, reads a page, or reports a setting. Menus are now reachable by path, dialogs can be listed, read and answered, and dockable panels are addressable for the first time. A panel is a child of the main frame rather than a top level window, so the dialog machinery never found one and Projects, Navigator and Properties were invisible. Combo boxes, tree nodes, grid cells and tabs had readers and no setters, which is the same shape as a property that reads and will not write. There is also a UI Automation layer for Altium's newer WPF dialogs, whose buttons are not child windows at all, so the older accessible route found nothing to press and a character read off the screen was the only answer.That capability carries a real risk and most of the work went into confining it. Synthesised input is not addressed to a window: a keystroke reaches whatever is active at the instant it fires, and a click lands on whatever is under the pointer. Measured here, a menu walk kept sending keys after Altium had lost the foreground. So a check now runs immediately before every event rather than once per operation, including between a key press and its release, since a key held while focus moves releases into another application. The check brings Altium forward instead of refusing, because focus moves for ordinary reasons and an automation that fails whenever you glance at another window would only create pressure to remove the guard. Bringing it forward needs
AttachThreadInput: a bareSetForegroundWindowfrom a background process is denied by Windows and fails silently, which is how the older code reported a success it had never confirmed. Coordinates are refused unless the point is over a window belonging to Altium, since knowing which application is active says nothing about where the pointer is, and no tool accepts a window handle from the caller, so an arbitrary window cannot be addressed. All of it can be switched off withEDA_AGENT_UI_AUTOMATION=0, which refuses every synthesised event while leaving reads working, because dialog detection is how the rest of the system notices Altium is blocked on a modal.One case is not solvable and is documented rather than papered over. Altium's menu bar carries entries that are commands rather than menus, and nothing distinguishes them: across all seventeen bar items the accessible state is identical including the flag that is supposed to mean "has a popup", the default action is identical, and the UI Automation control type is identical. Listing such an entry clicks it, and clicking it runs it. A keyboard walk was tried as a way around this and rejected, because menu mode resumes at the last menu used rather than the first, so it returned another menu's contents under the requested name, which is worse than the problem it solved.
Several things that reported success now report the truth, which continues a theme from the last batch.
obj_modifyreported property writes it never made. PCB property writes had no error channel at all, so an unknown property and a successful one were indistinguishable. A dialog button press reported success when nothing had happened. Handlers reported what they had assumed rather than what they checked, and a few read a value back without ever comparing it. A footprint height could go up and not come down.On EasyEDA, the editor now says why the extension is not connected instead of leaving you to guess, and a server occupying our port range that is not ours is refused rather than talked to. On the Altium side, library reads no longer move the document you were looking at, and the Run Script dialog lists one entry instead of fifty nine.
Continuous integration was quietly not running two things it claimed to. The Pascal cross validation had never run because the compiler was never on the path, so thirty seven tests were skipping silently, and twenty nine EasyEDA guards never ran because the reference they need was not checked out. Both now run, and the second immediately caught a drift in vendor quoting. Every skip is named with its reason.
Thanks to @darshp848, whose pull request added setting a primitive's layer by name and is in this release.
The risks, the reasons and the limitation above are written up in
docs/ui-automation.md, and summarised in the readme's limitations section.All reactions