Search code examples
swiftmacosnsviewnswindowcgrect

How can I CGWarpMouseCursorPosition() to the center of an NSView?


I am trying to create a game where the mouse is locked at the center of the screen. To complete this task, I found the appropriate method: CGWarpMouseCursorPosition

Then I searched for how to get the center of an NSView and found this: Getting the center point of an NSView

I used the provided answers but get incorrect results. No matter where window is is, the point the mouse is moved to is always half of the frame width and height away from the top left corner of the screen. It is as if the frame.origin of the view is always {0, 0} even when the window is somewhere else.

In my code, window is a member inherited from implementing NSWindowController and NSWindowDelegate:

override func mouseMoved(with Event: NSEvent) {
    if let window = window, let view = window.contentView {
        let frame = view.frame
        CGWarpMouseCursorPosition(CGPoint(x: frame.midX, y: frame.midY))
        // ...
    }
}

What is the correct way to get the center point of an NSView for use with the CGWarpMouseCursorPosition() function?


Solution

  • There are 2 problems with the existing implementation. The reason why view.frame.origin is always {0, 0} is because the view.frame is relative to the window and not absolute. As the other answer states the frame origin is always at {0, 0} 'inside' the window. I was expecting the frame to be absolute.

    This can be solved by using window.frame directly instead of view.frame.

    A second problem is that even if the frame is 'absolute' the coordinate system used by NSView is different from the coordinate system used by CGWarpMouseCursorPosition(). The answer here explains how to convert between them.

    Corrected code:

    if let window = window, let view = window.contentView {
        let frame = window.frame
        let originY = NSScreen.main.frame.maxY-frame.maxY;
        CGWarpMouseCursorPosition(CGPoint(x: frame.midX, y: originY+frame.height*0.5))
        // ...
    }