Swift:获取带有桌面号码和位置信息的打开应用窗口列表

发布于 2025-02-10 20:31:37 字数 947 浏览 2 评论 0原文

我正在开发一个可以与应用Windows一起使用的MacOS应用程序。 我现在负担不起的目标是检索所有打开的应用程序窗口的列表,看起来像这样(JSON示例):

[
  {
    "appName": "Google Chrome",
    "appWindows": [
      {
        "size": {"x": 100, "y": 100}, 
        "position": {"height": 100, "width": 100}, 
        "desktopNumber": 2
      },
      {
        "size": {"x": 100, "y": 100}, 
        "position": {"height": 100, "width": 100}, 
        "desktopNumber": 3
      }
    ]
  },
  {
    "appName": "Telegram",
    "appWindows": [
      {
        // full screen app, so has a separate desktop number
        "size": {"x": 1080, "y": 1920}, 
        "position": {"height": 0, "width": 0}, 
        "desktopNumber": 4
      }
    ]
  }
]

每个应用程序都有一系列打开的窗口,并在桌面号码旁边打开。一个全尺寸的应用程序包含一个单独的桌面空间,因此它应该具有单独的桌面号码。

我知道如何使用cgwindowlistcopywindowinfo获得打开的窗口列表,但是我找不到找到桌面号码的方法或确定哪个窗口可见。

如果不可能与Swift一起做,那么也许有Apple脚本解决方案?

I'm developing a macOS app that would work with app windows.
The goal which I couldn't now afford is to retrieve a list of all opened app windows, which would look something like that (JSON example):

[
  {
    "appName": "Google Chrome",
    "appWindows": [
      {
        "size": {"x": 100, "y": 100}, 
        "position": {"height": 100, "width": 100}, 
        "desktopNumber": 2
      },
      {
        "size": {"x": 100, "y": 100}, 
        "position": {"height": 100, "width": 100}, 
        "desktopNumber": 3
      }
    ]
  },
  {
    "appName": "Telegram",
    "appWindows": [
      {
        // full screen app, so has a separate desktop number
        "size": {"x": 1080, "y": 1920}, 
        "position": {"height": 0, "width": 0}, 
        "desktopNumber": 4
      }
    ]
  }
]

Each app has an array of opened windows alongside a desktop number where it's been opened. A full-size app took a separate desktop space, so it should have a separate desktop number.

I know how to get an opened window list with CGWindowListCopyWindowInfo, but I couldn't find a way to find a desktop number or determine which window is visible or not.

If it's not possible to do with Swift, then perhaps there are apple script solutions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

永不分离 2025-02-17 20:31:37

您可以检索应用程序名称,边界&使用以下代码显示显示:

import Cocoa
import CoreGraphics

let windowsInfo = CGWindowListCopyWindowInfo(CGWindowListOption.optionAll, CGWindowID(0))
let maxDisplays: UInt32 = 10
var displays = [CGDirectDisplayID](repeating: 0, count: Int(maxDisplays))
var displayCount: UInt32 = 0
let error = CGGetOnlineDisplayList(maxDisplays, &displays, &displayCount)

for windowInfo in Array<NSDictionary>.fromCFArray(records: windowsInfo) ?? [] {
    if let appName = windowInfo["kCGWindowOwnerName"] as? String {
        print("appName: \(appName)")
    }
    if let bounds = windowInfo["kCGWindowBounds"] as? NSDictionary {
        print ("X: \(bounds["X"] ?? "<unknown>")")
        print ("Y: \(bounds["Y"] ?? "<unknown>")")
        print ("Width: \(bounds["Width"] ?? "<unknown>")")
        print ("Height: \(bounds["Height"] ?? "<unknown>")")

        if
            let x = bounds["X"] as? Double,
            let y = bounds["Y"] as? Double,
            let width = bounds["Width"] as? Double,
            let height = bounds["Height"] as? Double
        {
            for index in 0..<Int(maxDisplays) {
                let display = displays[index]
                let displayRect = CGDisplayBounds(display)
                if displayRect.contains(CGRect(x: x, y: y, width: width, height: height)) {
                    print("Display: \(index)")
                    break
                }
            }
        }

        print("---")
    }
}

extension Array {
    static func fromCFArray(records: CFArray?) -> Array<Element>? {
        var result: [Element]?
        if let records = records {
            for i in 0..<CFArrayGetCount(records) {
                let unmanagedObject: UnsafeRawPointer = CFArrayGetValueAtIndex(records, i)
                let rec: Element = unsafeBitCast(unmanagedObject, to: Element.self)
                if (result == nil){
                    result = [Element]()
                }
                result!.append(rec)
            }
        }
        return result
    }
}

示例输出:

appName: Xcode.app
X: 1284
Y: -1074
Width: 1029
Height: 557
Display: 1
---
appName: Xcode.app
X: 1284
Y: -954
Width: 1029
Height: 261
Display: 1
---
appName: Control Centre
X: 0
Y: 900
Width: 32
Height: 24
---
appName: Control Centre
X: 1294
Y: 0
Width: 146
Height: 24
Display: 0
---
appName: Notes
X: 0
Y: 0
Width: 3200
Height: 24
---
appName: Notes
X: 0
Y: 0
Width: 3200
Height: 24
---
appName: Notes
X: 0
Y: 0
Width: 3200
Height: 24
---
appName: Notes
X: -887
Y: -1333
Width: 3200
Height: 24
Display: 1
---
appName: Notes
X: 0
Y: 0
Width: 1440
Height: 24
Display: 0
---
appName: Notes
X: 0
Y: 0
Width: 1440
Height: 24
Display: 0
---
appName: Notes
X: 0
Y: 0
Width: 1440
Height: 24
Display: 0
---
appName: Notes
X: 0
Y: 0
Width: 1440
Height: 24
Display: 0
---
appName: Notes
X: 0
Y: 0
Width: 1440
Height: 24
Display: 0
---
...

使用此代码创建JSON对象是微不足道的。顺便说一句,您可能需要更改:

"size": {"x": 1080, "y": 1920}, 
"position": {"height": 0, "width": 0},

"position": {"x": 1080, "y": 1920}, 
"size": {"height": 0, "width": 0},

注意,没有UI的应用程序可能没有display值。

You can retrieve app names, bounds & displays using following code:

import Cocoa
import CoreGraphics

let windowsInfo = CGWindowListCopyWindowInfo(CGWindowListOption.optionAll, CGWindowID(0))
let maxDisplays: UInt32 = 10
var displays = [CGDirectDisplayID](repeating: 0, count: Int(maxDisplays))
var displayCount: UInt32 = 0
let error = CGGetOnlineDisplayList(maxDisplays, &displays, &displayCount)

for windowInfo in Array<NSDictionary>.fromCFArray(records: windowsInfo) ?? [] {
    if let appName = windowInfo["kCGWindowOwnerName"] as? String {
        print("appName: \(appName)")
    }
    if let bounds = windowInfo["kCGWindowBounds"] as? NSDictionary {
        print ("X: \(bounds["X"] ?? "<unknown>")")
        print ("Y: \(bounds["Y"] ?? "<unknown>")")
        print ("Width: \(bounds["Width"] ?? "<unknown>")")
        print ("Height: \(bounds["Height"] ?? "<unknown>")")

        if
            let x = bounds["X"] as? Double,
            let y = bounds["Y"] as? Double,
            let width = bounds["Width"] as? Double,
            let height = bounds["Height"] as? Double
        {
            for index in 0..<Int(maxDisplays) {
                let display = displays[index]
                let displayRect = CGDisplayBounds(display)
                if displayRect.contains(CGRect(x: x, y: y, width: width, height: height)) {
                    print("Display: \(index)")
                    break
                }
            }
        }

        print("---")
    }
}

extension Array {
    static func fromCFArray(records: CFArray?) -> Array<Element>? {
        var result: [Element]?
        if let records = records {
            for i in 0..<CFArrayGetCount(records) {
                let unmanagedObject: UnsafeRawPointer = CFArrayGetValueAtIndex(records, i)
                let rec: Element = unsafeBitCast(unmanagedObject, to: Element.self)
                if (result == nil){
                    result = [Element]()
                }
                result!.append(rec)
            }
        }
        return result
    }
}

Example output:

appName: Xcode.app
X: 1284
Y: -1074
Width: 1029
Height: 557
Display: 1
---
appName: Xcode.app
X: 1284
Y: -954
Width: 1029
Height: 261
Display: 1
---
appName: Control Centre
X: 0
Y: 900
Width: 32
Height: 24
---
appName: Control Centre
X: 1294
Y: 0
Width: 146
Height: 24
Display: 0
---
appName: Notes
X: 0
Y: 0
Width: 3200
Height: 24
---
appName: Notes
X: 0
Y: 0
Width: 3200
Height: 24
---
appName: Notes
X: 0
Y: 0
Width: 3200
Height: 24
---
appName: Notes
X: -887
Y: -1333
Width: 3200
Height: 24
Display: 1
---
appName: Notes
X: 0
Y: 0
Width: 1440
Height: 24
Display: 0
---
appName: Notes
X: 0
Y: 0
Width: 1440
Height: 24
Display: 0
---
appName: Notes
X: 0
Y: 0
Width: 1440
Height: 24
Display: 0
---
appName: Notes
X: 0
Y: 0
Width: 1440
Height: 24
Display: 0
---
appName: Notes
X: 0
Y: 0
Width: 1440
Height: 24
Display: 0
---
...

Creating the JSON object with this code is trivial. Btw, you may want to change:

"size": {"x": 1080, "y": 1920}, 
"position": {"height": 0, "width": 0},

to

"position": {"x": 1080, "y": 1920}, 
"size": {"height": 0, "width": 0},

Also, note that apps without a UI may not have a Display value.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文