swift - NSWindow定位

标签 swift macos

我是 Hearthstone tracker 的作者,我必须在炉石传说窗口上移动几个 NSWindow

我使用 CGWindowListCopyWindowInfo 获取炉石传说的框架。 然后,我必须将我的窗口移动到一些相对于《炉石传说》的位置。

HSTracker overlays 红色箭头在对手卡片上方,绿色箭头在回合按钮上方,蓝色箭头在窗口左右两侧。

我的实际屏幕设置如下:

Screen setup

这给了我以下框架

// screen 1 : {x 0 y 0 w 1.440 h 900}
// screen 2 : {x 1.440 y -180 w 1.920 h 1.080}

要将对手跟踪器(左框架)放置在正确的位置,这是最简单的情况,我使用 {x 0 y somepadding w 185 h hearthstoneHeight - somepadding} 并得到正确的以此为框架

func relativeFrame(frame: NSRect) -> NSRect {
    var relative = frame
    relative.origin.x = NSMinX(hearthstoneFrame) + NSMinX(frame)
    relative.origin.y = NSMinY(hearthstoneFrame) + NSMinY(frame)

    return relative
}

正确的跟踪器使用 {x hearthstoneWidth - trackerWidth, ...}

对于其他叠加层,我使用我当前的(炉石传说)分辨率来放置它们并使用简单的数学计算它们

x = x / 1404.0 * NSWidth(hearthstoneFrame)
y = y / 840.0 * NSHeight(hearthstoneFrame)

这很好用。除非我使用我的第二个屏幕。在这种情况下,框架似乎是正确的,但窗口的位置不好。

这是带有 {x 0 y 0 w hearthstoneWidth h hearthsoneHeight } 的调试窗口的屏幕截图。如果我比较《炉石传说》的框架和我的叠加层,它们是相同的。 Debug overlay

完整的功能如下(我在“静态类”中,我只显示相关代码)。我想我在计算中遗漏了一些东西,但我找不到什么。

class frameRelative {
   static var hearthstoneFrame = NSZeroRect
   static func findHearthstoneFrame() {
       let options = CGWindowListOption(arrayLiteral: .ExcludeDesktopElements)
       let windowListInfo = CGWindowListCopyWindowInfo(options, CGWindowID(0))
       if let info = (windowListInfo as NSArray? as? [[String: AnyObject]])?
           .filter({
              !$0.filter({ $0.0 == "kCGWindowName" && $0.1 as? String == "Hearthstone" }).isEmpty
            })
            .first {
              var rect = NSRect()
              let bounds = info["kCGWindowBounds"] as! CFDictionary
              CGRectMakeWithDictionaryRepresentation(bounds, &rect)
              rect.size.height -= titleBarHeight // remove the 22px from the title
              hearthstoneFrame = rect
       }
  }

  static func frameRelative(frame: NSRect, _ isRelative: Bool = false) -> NSRect {
      var relative = frame
      var pointX = NSMinX(relative)
      var pointY = NSMinY(relative)

      if isRelative {
          pointX = pointX / 1404.0 * NSWidth(hearthstoneFrame)
          pointY = pointY / 840.0 * NSHeight(hearthstoneFrame)
      }

      let x: CGFloat = NSMinX(hearthstoneFrame) + pointX
      let y = NSMinY(hearthstoneFrame) + pointY

      relative.origin = NSMakePoint(x, y)
      return relative
  }
}

// somewhere here
let frame = NSMakeRect(0, 0, hearthstoneWidth, hearthstoneHeight)
let relativeFrame = SizeHelper.frameRelative(frame)
myWindow.setFrame(relativeFrame, display: true)

任何帮助将不胜感激:)

最佳答案

我最终解决了这个问题,所以我决定发布答案以关闭此线程...也许有一天有人会遇到同样的问题。

解决方案是用《炉石传说》窗口的max y第一个屏幕中减去max y

findHearthstoneFrame的最终代码为

static func findHearthstoneFrame() {
   let options = CGWindowListOption(arrayLiteral: .ExcludeDesktopElements)
        let windowListInfo = CGWindowListCopyWindowInfo(options, CGWindowID(0))
        if let info = (windowListInfo as NSArray? as? [[String: AnyObject]])?.filter({
            !$0.filter({ $0.0 == "kCGWindowName"
                && $0.1 as? String == "Hearthstone" }).isEmpty
        }).first {
            if let id = info["kCGWindowNumber"] as? Int {
                self.windowId = CGWindowID(id)
            }
            var rect = NSRect()
            let bounds = info["kCGWindowBounds"] as! CFDictionary
            CGRectMakeWithDictionaryRepresentation(bounds, &rect)

            if let screen = NSScreen.screens()?.first {
                rect.origin.y = NSMaxY(screen.frame) - NSMaxY(rect)
            }

            self._frame = rect
        }
 }

frameRelative

static let BaseWidth: CGFloat = 1440.0
static let BaseHeight: CGFloat = 922.0
var scaleX: CGFloat {
    return NSWidth(_frame) / SizeHelper.BaseWidth
}

var scaleY: CGFloat {
    // 22 is the height of the title bar
    return (NSHeight(_frame) - 22) / SizeHelper.BaseHeight
}
func frameRelative(frame: NSRect, relative: Bool = true) -> NSRect {
    var pointX = NSMinX(frame)
    var pointY = NSMinY(frame)
    let width = NSWidth(frame)
    let height = NSHeight(frame)

    if relative {
        pointX = pointX * scaleX
        pointY = pointY * scaleY
    }

    let x: CGFloat = NSMinX(self.frame) + pointX
    let y: CGFloat = NSMinY(self.frame) + pointY

    let relativeFrame = NSRect(x: x, y: y, width: width, height: height)
    return relativeFrame
}

关于swift - NSWindow定位,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36766266/

相关文章:

ios - 将 UILabel 在 UITableView header 中居中

ios - 在 PromiseKit 中获取第一个响应对象,然后完成 block

ios - 如何明智地将 FirebaseFirestoreSwift 与 Carthage 结合使用?

ios - 如何防止 UIPageViewController 的 setViewControllers 方法崩溃?

ios - Mac 蓝牙 MAP 配置文件

xcode - Swift Radio App--链接不规范怎么办?

c++ - 使用 g++ : Undefined symbols for architecture x86_64 在 OS X 上编译

macos - 配置脚本在 mac 上找不到 libxml2

javascript - 任务 'browser-sync' 不在您的 gulpfile 中

python - 如何在 OS X 中为 Django 正确设置 GEOIP_PATH?