Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
937 views
in Technique[技术] by (71.8m points)

swift - Activate a window using its Window ID

How would I programmatically activate i.e move-to-front-and-focus a window on macOS (not belonging to my app) given its Window ID. My app would run with user granted Accessibility permissions etc.

Surprisingly, none of the functions described on the Quartz Window Services page seem to do that.

Am using Swift currently, but am open to using Objective-C, AppleScript or whatever.

EDIT:

I don't want to bring to front all windows of the parent app - only the specific that matches the window ID.

Edit:

I know that the NSWindow type is only meant to refer to windows of the current process, but is there no class that represents windows owned by external apps? Like we have NSRunningApplication to refer to any running app including external ones, I was expecting an API to deal all open windows (assuming the right permissions). Is there some class like NSOpenWindow or CGWindow buried somewhere?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I didn't find a way to switch to a specific window yet, but you can switch to the app that contains a specific window using this function:

func switchToApp(withWindow windowNumber: Int32) {
    let options = CGWindowListOption(arrayLiteral: CGWindowListOption.excludeDesktopElements, CGWindowListOption.optionOnScreenOnly)
    let windowListInfo = CGWindowListCopyWindowInfo(options, CGWindowID(0))
    guard let infoList = windowListInfo as NSArray? as? [[String: AnyObject]] else { return }
    if let window = infoList.first(where: { ($0["kCGWindowNumber"] as? Int32) == windowNumber}), let pid = window["kCGWindowOwnerPID"] as? Int32 {
        let app = NSRunningApplication(processIdentifier: pid)
        app?.activate(options: .activateIgnoringOtherApps)
    }
}

It is probably usefull to switch by name as well:

func switchToApp(named windowOwnerName: String) {
    let options = CGWindowListOption(arrayLiteral: CGWindowListOption.excludeDesktopElements, CGWindowListOption.optionOnScreenOnly)
    let windowListInfo = CGWindowListCopyWindowInfo(options, CGWindowID(0))
    guard let infoList = windowListInfo as NSArray? as? [[String: AnyObject]] else { return }

    if let window = infoList.first(where: { ($0["kCGWindowOwnerName"] as? String) == windowOwnerName}), let pid = window["kCGWindowOwnerPID"] as? Int32 {
        let app = NSRunningApplication(processIdentifier: pid)
        app?.activate(options: .activateIgnoringOtherApps)
    }
}

Example: switchToApp(named: "OpenOffice")

On my mac OpenOffice was started with a window with kCGWindowNumber = 599, so this has the same effect: switchToApp(withWindow: 599)

As far as I found out so far, your options seem to be to show the currently active window of the app, or to show all windows (using .activateAllWindows as activation option)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...