0

On macOS, I have an application that should move the cursor to the center of the NSView when the window is loaded.

class ViewController: NSViewController {
    override func viewDidLayout() {
        super.viewDidLayout()
        
        let view = super.view
        let point = NSPoint(x: view.frame.midX, y:view.frame.midY)
        let pointInWindow = view.convert(point, to: nil)
        let pointOnScreen = view.window?.convertToScreen(NSRect(origin: pointInWindow, size: .zero)).origin ?? .zero
        CGWarpMouseCursorPosition(NSPoint(x:pointOnScreen.x, y:pointOnScreen.y))
    }
}

(The code was taken from: Mac OS X: Convert between NSView coordinates and global screen coordinates)

But it seems to be placing the cursor above the window instead of inside it— x-position looks correct but the y-position is off. Thank you for any help.

Shaun Lebron
  • 2,501
  • 28
  • 29
  • 1
    `view.frame` is in the super view's coordinates, but you when you call `view.convert` you need it in the view's own coordinates. For that use `view.bounds`. – Chip Jarred Jan 04 '23 at 06:37
  • `view.bounds` and `view.frame` both evaluated to the same values. – Shaun Lebron Jan 04 '23 at 17:23
  • I wasn't sure it would fix the problem, but noticed that it seemed to be a potential bug. That's why I commented rather than answered. That they are the same for your `view` is just an accident of the specific view you're using. If you were to choose a more deeply nested view, they would likely be different and would affect the calculation. – Chip Jarred Jan 04 '23 at 18:04

1 Answers1

1

I found a usage example on GitHub by searching for CGWarpMousePosition:

https://github.com/chockenberry/Notchmeister/blob/9e9308f0803a4e0faf27790c02081689545a989d/Notchmeister/Notchmeister/PortalEffect.swift#L162-L171

This ended up working. The y-position needed to be subtracted from the bottom screen coordinate:

class ViewController: NSViewController {
    override func viewDidLayout() {
        super.viewDidLayout()

        let view = super.view
        let window = view.window
        let screen = window!.screen

        let viewPoint = NSPoint(x: view.frame.midX, y:view.frame.midY)
        let windowPoint = view.convert(viewPoint, to: nil)
        let screenPoint = window!.convertPoint(toScreen: windowPoint)
        let globalPoint = CGPoint(
            x: screen!.frame.origin.x + screenPoint.x,
            y: screen!.frame.origin.y + screen!.frame.height - screenPoint.y
        )

        CGWarpMouseCursorPosition(globalPoint)
    }
}
Shaun Lebron
  • 2,501
  • 28
  • 29
  • 1
    Interesting. The need to add the screen height and subtract suggests that there is a flipped coordinate system involved. Good to know. I would suggest adding `screen!.frame.origin.x` to the `x` coordinate as well, in case it's not 0, which I suppose would be the case if the window is on a screen other than the main screen. – Chip Jarred Jan 04 '23 at 18:27
  • 1
    @ChipJarred Good catch. Thank you! I added your edit to the answer. – Shaun Lebron Jan 04 '23 at 19:04