我正在写一个应用程序,需要周期性的获取活动窗口的PID、进程名、窗口ID和窗口名。该程序是用 Go 编写的,但问题与进入 Mac 生态系统的任何 FFI 相关。我有两种方法,通过 AppleScript 和通过 Objective C。
两者都给出了75%的解决方案;缺少窗口 ID 或窗口名称。我想找到一个统一的解决方案来提供所有四个属性,而不是必须拼凑一个取决于我拥有的两种方法的解决方案。
AppleScript 方法;大多数情况下不提供 WindowNumber。
global activeApp, activePID, activeName, windowName
set windowName to ""
tell application "System Events"
set activeApp to first application process whose frontmost is true
set activePID to unix id of activeApp
set activeName to name of activeApp
tell process activeName
try
tell (1st window whose value of attribute "AXMain" is true)
set windowName to value of attribute "AXTitle"
end tell
end try
end tell
end tell
return ("{\"pid\":" & activePID & ",\"name\":\"" & activeName & "\",\"window\":\"" & windowName & "\"}" as text)
Objective C 方法;大多数情况下不提供 WindowName。
#include <Cocoa/Cocoa.h>
#include <CoreGraphics/CGWindow.h>
struct details {
int wid;
int pid;
const char* name;
const char* window;
};
int activeWindow(struct details *d)
{
if (d == NULL) {
return 0;
}
NSArray *windows = (NSArray *)CGWindowListCopyWindowInfo(kCGWindowListExcludeDesktopElements|kCGWindowListOptionOnScreenOnly,kCGNullWindowID);
for(NSDictionary *window in windows){
int WindowLayer = [[window objectForKey:(NSString *)kCGWindowLayer] intValue];
if (WindowLayer == 0) {
d->wid = [[window objectForKey:(NSString *)kCGWindowNumber] intValue];
d->pid = [[window objectForKey:(NSString *)kCGWindowOwnerPID] intValue];
d->name = [[window objectForKey:(NSString *)kCGWindowOwnerName] UTF8String];
d->window = [[window objectForKey:(NSString *)kCGWindowName] UTF8String];
return 1;
}
}
return 0;
}
tell application "System Events"
set frontProcess to 1st process whose frontmost is true
set activePID to unix id of frontProcess
set bundleID to bundle identifier of frontProcess
set activeName to name of frontProcess
end tell
tell application id bundleID
try
set appName to name
set windowID to id of front window
set windowName to name of front window
on error
set windowID to my getFrontWindowID(appName)
try
tell application "System Events" to tell frontProcess to tell window 1 to set windowName to value of attribute "AXTitle"
on error
set windowName to ""
end try
end try
end tell
return {pid:activePID, processName:activeName, appName:appName, windowID:windowID, windowName:windowName}
--> {pid:9893, processName:"Avidemux2.7", appName:"Avidemux_2.7.8", windowID:5969, windowName:"Avidemux"}
on getFrontWindowID(appName)
set JS to "ObjC.import('CoreGraphics');
Ref.prototype.$ = function() {
return ObjC.deepUnwrap(ObjC.castRefToObject(this));
}
Application.prototype.getWindowList = function() {
let pids = Application('com.apple.systemevents')
.processes.whose({ 'bundleIdentifier':
this.id() }).unixId();
return $.CGWindowListCopyWindowInfo(
$.kCGWindowListExcludeDesktopElements,
$.kCGNullWindowID).$()
.filter(x => pids.indexOf(x.kCGWindowOwnerPID) + 1
&& x.kCGWindowLayer == 0
&& x.kCGWindowStoreType == 1
&& x.kCGWindowAlpha == 1
).map(x => [x.kCGWindowNumber]);
}
Application('" & appName & "').getWindowList();"
return (word 1 of (do shell script "osascript -l JavaScript -e " & quoted form of JS)) as integer
end getFrontWindowID