如何判断AXUIElement对应的窗口所在的NSScreen?
如何确定外部窗口所属的NSScreen
已通过Accessibility API获取到外部应用窗口的AXUIElement引用及窗口frame,也能设置窗口位置,但用窗口frame或原点是否包含在屏幕frame里的方法判断窗口所属屏幕时失效——比如存在窗口大部分区域在左屏,却被系统判定属于右屏的情况。
原尝试的无效代码:
let window: AXUIElement // 从窗口读取kAXPositionAttribute、kAXSizeAttribute并反转Y轴计算得到 let windowFrame: CGRect // 这些方法无效 let screenWhereWindowIsDisplayed = NSScreen.screens.first(where: { $0.frame.contains(windowFrame) }) let screenWhereWindowIsDisplayed = NSScreen.screens.first(where: { $0.frame.contains(windowFrame.origin) })
解决方案
macOS中窗口的归属屏幕通常由窗口核心区域(如标题栏位置)或与屏幕的交集优先级决定,可采用以下两种更可靠的判断方式:
1. 基于窗口中心位置判断
系统通常会将窗口中心所在的屏幕判定为归属屏幕,这种方式简单高效:
let windowCenter = CGPoint(x: windowFrame.midX, y: windowFrame.midY) let screenWhereWindowIsDisplayed = NSScreen.screens.first { screen in screen.frame.contains(windowCenter) }
2. 基于交集面积判断
如果窗口跨屏且中心位置判断仍不符合预期,可计算窗口与每个屏幕的交集面积,取交集最大的屏幕:
func screenForWindowFrame(_ frame: CGRect) -> NSScreen? { var maxIntersectionArea: CGFloat = 0 var targetScreen: NSScreen? for screen in NSScreen.screens { let intersectionRect = frame.intersection(screen.frame) let area = intersectionRect.width * intersectionRect.height if area > maxIntersectionArea { maxIntersectionArea = area targetScreen = screen } } return targetScreen } // 调用方法 let screenWhereWindowIsDisplayed = screenForWindowFrame(windowFrame)
原方法失效原因
原判断逻辑过于绝对:
$0.frame.contains(windowFrame)要求整个窗口完全处于某一屏幕内,跨屏窗口直接不满足;$0.frame.contains(windowFrame.origin)仅以窗口左上角原点判断,当窗口原点在A屏但主体/标题栏在B屏时,系统仍会将窗口归属到B屏。
内容的提问来源于stack exchange,提问作者Guig
相关产品推荐
相关产品推荐

