如何从 JXA 中的对象获取多个属性?
How to get multiple properties from objects in JXA?
JXA 中有没有一种方法可以通过一次调用从多个对象中获取多个属性?
例如,我想从菜单项中获取 name
和 enabled
属性,可以对每个人 属性 进行如下操作:
Application("System Events").processes.byName('Finder').menuBars[0].menuBarItems.name()
Application("System Events").processes.byName('Finder').menuBars[0].menuBarItems.enabled()
但是是否可以通过单个函数调用来获取它们?类似于:
Application("System Events").processes.byName('Finder').menuBars[0].menuBarItems.select('name', 'enabled')
我知道,我可以遍历 menuBarItems
并从 .properties()
方法收集属性,但这种方法太慢了,这就是我寻找其他选择的原因。
更新
我正在寻找更好的性能,而不是更好的语法,即我希望在对 System Events
.[=17= 的一次调用中检索属性]
我可能会这样做:
sys = Application('com.apple.systemevents');
FinderProc = sys.processes['Finder'];
FinderMenuBarItems = FinderProc.menuBars[0].menuBarItems();
Array.from(FinderMenuBarItems,x=>[x.name(),x.enabled()]);
通过首先将 object
转换为 array
,这允许 map
每个元素并一次检索所有元素所需的属性。为了便于阅读,代码分为几行。
编辑: 添加于 2019-07-27
根据您关于 Objective-C 实施的评论,我今天有一点时间来编写一个 JSObjc 脚本。它与上面的普通 JXA 版本做同样的事情,而且,是的,它显然进行了多个函数调用,这是必要的。但它执行这些功能的级别低于 System Events(此处根本不涉及),因此希望您会发现它的性能更高。
ObjC.import('ApplicationServices');
ObjC.import('CoreFoundation');
ObjC.import('Foundation');
ObjC.import('AppKit');
var err = {
'-25211':'APIDisabled',
'-25206':'ActionUnsupported',
'-25205':'AttributeUnsupported',
'-25204':'CannotComplete',
'-25200':'Failure',
'-25201':'IllegalArgument',
'-25202':'InvalidUIElement',
'-25203':'InvalidUIElementObserver',
'-25212':'NoValue',
'-25214':'NotEnoughPrecision',
'-25208':'NotImplemented',
'-25209':'NotificationAlreadyRegistered',
'-25210':'NotificationNotRegistered',
'-25207':'NotificationUnsupported',
'-25213':'ParameterizedAttributeUnsupported',
'0':'Success'
};
var unwrap = ObjC.deepUnwrap.bind(ObjC);
var bind = ObjC.bindFunction.bind(ObjC);
bind('CFMakeCollectable', [ 'id', [ 'void *' ] ]);
Ref.prototype.nsObject = function() {
return unwrap($.CFMakeCollectable(this[0]));
}
function getAttrValue(AXUIElement, AXAttrName) {
var e;
var _AXAttrValue = Ref();
e = $.AXUIElementCopyAttributeValue(AXUIElement,
AXAttrName,
_AXAttrValue);
if (err[e]!='Success') return err[e];
return _AXAttrValue.nsObject();
}
function getAttrValues(AXUIElement, AXAttrNames){
var e;
var _AXAttrValues = Ref();
e = $.AXUIElementCopyMultipleAttributeValues(AXUIElement,
AXAttrNames,
0,
_AXAttrValues);
if (err[e]!='Success') return err[e];
return _AXAttrValues.nsObject();
}
function getAttrNames(AXUIElement) {
var e;
var _AXAttrNames = Ref();
e = $.AXUIElementCopyAttributeNames(AXUIElement, _AXAttrNames);
if (err[e]!='Success') return err[e];
return _AXAttrNames.nsObject();
}
(() => {
const pid_1 = $.NSWorkspace.sharedWorkspace
.frontmostApplication
.processIdentifier;
const appElement = $.AXUIElementCreateApplication(pid_1);
const menuBar = getAttrValue(appElement,"AXMenuBar");
const menuBarItems = getAttrValue(menuBar, "AXChildren");
return menuBarItems.map(x => {
return getAttrValues(x, ["AXTitle", "AXEnabled"]);
});
})();
JXA 中有没有一种方法可以通过一次调用从多个对象中获取多个属性?
例如,我想从菜单项中获取 name
和 enabled
属性,可以对每个人 属性 进行如下操作:
Application("System Events").processes.byName('Finder').menuBars[0].menuBarItems.name()
Application("System Events").processes.byName('Finder').menuBars[0].menuBarItems.enabled()
但是是否可以通过单个函数调用来获取它们?类似于:
Application("System Events").processes.byName('Finder').menuBars[0].menuBarItems.select('name', 'enabled')
我知道,我可以遍历 menuBarItems
并从 .properties()
方法收集属性,但这种方法太慢了,这就是我寻找其他选择的原因。
更新
我正在寻找更好的性能,而不是更好的语法,即我希望在对 System Events
.[=17= 的一次调用中检索属性]
我可能会这样做:
sys = Application('com.apple.systemevents');
FinderProc = sys.processes['Finder'];
FinderMenuBarItems = FinderProc.menuBars[0].menuBarItems();
Array.from(FinderMenuBarItems,x=>[x.name(),x.enabled()]);
通过首先将 object
转换为 array
,这允许 map
每个元素并一次检索所有元素所需的属性。为了便于阅读,代码分为几行。
编辑: 添加于 2019-07-27
根据您关于 Objective-C 实施的评论,我今天有一点时间来编写一个 JSObjc 脚本。它与上面的普通 JXA 版本做同样的事情,而且,是的,它显然进行了多个函数调用,这是必要的。但它执行这些功能的级别低于 System Events(此处根本不涉及),因此希望您会发现它的性能更高。
ObjC.import('ApplicationServices');
ObjC.import('CoreFoundation');
ObjC.import('Foundation');
ObjC.import('AppKit');
var err = {
'-25211':'APIDisabled',
'-25206':'ActionUnsupported',
'-25205':'AttributeUnsupported',
'-25204':'CannotComplete',
'-25200':'Failure',
'-25201':'IllegalArgument',
'-25202':'InvalidUIElement',
'-25203':'InvalidUIElementObserver',
'-25212':'NoValue',
'-25214':'NotEnoughPrecision',
'-25208':'NotImplemented',
'-25209':'NotificationAlreadyRegistered',
'-25210':'NotificationNotRegistered',
'-25207':'NotificationUnsupported',
'-25213':'ParameterizedAttributeUnsupported',
'0':'Success'
};
var unwrap = ObjC.deepUnwrap.bind(ObjC);
var bind = ObjC.bindFunction.bind(ObjC);
bind('CFMakeCollectable', [ 'id', [ 'void *' ] ]);
Ref.prototype.nsObject = function() {
return unwrap($.CFMakeCollectable(this[0]));
}
function getAttrValue(AXUIElement, AXAttrName) {
var e;
var _AXAttrValue = Ref();
e = $.AXUIElementCopyAttributeValue(AXUIElement,
AXAttrName,
_AXAttrValue);
if (err[e]!='Success') return err[e];
return _AXAttrValue.nsObject();
}
function getAttrValues(AXUIElement, AXAttrNames){
var e;
var _AXAttrValues = Ref();
e = $.AXUIElementCopyMultipleAttributeValues(AXUIElement,
AXAttrNames,
0,
_AXAttrValues);
if (err[e]!='Success') return err[e];
return _AXAttrValues.nsObject();
}
function getAttrNames(AXUIElement) {
var e;
var _AXAttrNames = Ref();
e = $.AXUIElementCopyAttributeNames(AXUIElement, _AXAttrNames);
if (err[e]!='Success') return err[e];
return _AXAttrNames.nsObject();
}
(() => {
const pid_1 = $.NSWorkspace.sharedWorkspace
.frontmostApplication
.processIdentifier;
const appElement = $.AXUIElementCreateApplication(pid_1);
const menuBar = getAttrValue(appElement,"AXMenuBar");
const menuBarItems = getAttrValue(menuBar, "AXChildren");
return menuBarItems.map(x => {
return getAttrValues(x, ["AXTitle", "AXEnabled"]);
});
})();