Changing Cursor Image

I am making a SpriteKit game and I am trying to change the cursor image from the default pointer to a png image that I have imported into the project, but it’s not really working. when I run the project I can see the cursor image change for a brief second and then return to the default image. Here is my code:

print(NSCursor.current)
if let image = NSImage(named: customImage) {
     print("The image exists")
     cursor = NSCursor(image: image, hotSpot: .zero)
     cursor.push()
     print(cursor)
}
print(NSCursor.current)

The above code is all contained in the didMove(:) function in GameScene. From the print statements I can see that the memory address of the NSCursor.current changes to that of cursor. HOWEVER, in the mouseMoved(:) call back function I print out the mouse location and the current cursor. I can see from these print stamens that the cursor memory address has again changed and no longer matches the custom cursor address… so I am not sure what is going on…

Also, fyi the cursor is a global property within game scene so it should persist. Also, image is not nil. This is verified by the print statements I see

Thanks

Answered by DTS Engineer in 817297022

Hey @PajamaUnks,

Thank you for posting this question to the forums!

The proper API to use for this task is NSTrackingArea. There is lots of subtlety to the behavior of the parameters I am specifying in the code I'm about to share with you, so I strongly recommend that you read the following documentation pages to gain a foundational understanding of NSTrackingArea:

https://developer.apple.com/documentation/appkit/nstrackingarea

https://developer.apple.com/documentation/appkit/nstrackingarea/init(rect:options:owner:userinfo:)

https://developer.apple.com/documentation/appkit/nstrackingarea/options-swift.struct/cursorupdate

https://developer.apple.com/documentation/appkit/nstrackingarea/options-swift.struct/activealways

Ok, now for the code:

override func didMove(to view: SKView) {
        
        let trackingArea = NSTrackingArea(rect: .zero, options: [.cursorUpdate, .inVisibleRect, .activeInActiveApp], owner: self, userInfo: nil)
        view.addTrackingArea(trackingArea)
   
     ... rest of function ...
}
override func cursorUpdate(with event: NSEvent) {
        NSCursor.crosshair.set()
}

Best regards,

Greg

Accepted Answer

Hey @PajamaUnks,

Thank you for posting this question to the forums!

The proper API to use for this task is NSTrackingArea. There is lots of subtlety to the behavior of the parameters I am specifying in the code I'm about to share with you, so I strongly recommend that you read the following documentation pages to gain a foundational understanding of NSTrackingArea:

https://developer.apple.com/documentation/appkit/nstrackingarea

https://developer.apple.com/documentation/appkit/nstrackingarea/init(rect:options:owner:userinfo:)

https://developer.apple.com/documentation/appkit/nstrackingarea/options-swift.struct/cursorupdate

https://developer.apple.com/documentation/appkit/nstrackingarea/options-swift.struct/activealways

Ok, now for the code:

override func didMove(to view: SKView) {
        
        let trackingArea = NSTrackingArea(rect: .zero, options: [.cursorUpdate, .inVisibleRect, .activeInActiveApp], owner: self, userInfo: nil)
        view.addTrackingArea(trackingArea)
   
     ... rest of function ...
}
override func cursorUpdate(with event: NSEvent) {
        NSCursor.crosshair.set()
}

Best regards,

Greg

Changing Cursor Image
 
 
Q