I am currently making a slideshow application for Mac using Swift. In this application I want to hide the mouse while the slideshow is running and the mouse has not been moved for a while, pretty much like it is done in Quick Time Player for example.
Now I have tried a bunch of ways using NSCursor.hide()
and NSCursor.unhide()
as well as NSCursor.setHiddenUntilMouseMoves()
, but non of it quite worked.
Firstly I failed to make it call the mouseMoved function in my main ViewController and secondly NSCursor.setHiddenUntilMouseMoves()
doesn't always seem to work even though I have not touched my trackpad at all. It is right after the code that changes the image in the slideshow and I see the image being changed, but using the debugger it doesn't stop on that line of code when the cursor isn't hidden.
Would someone be able to show me a general way how to get this to work? I'm pretty sure this is not such an exotic thing to do and there is much easier ways to do it than what I am trying.
The following is what I've tried:
import Cocoa
class DiashowViewController: NSViewController {
enum DiashowState {
case playing
case paused
case stopped
}
var files: [URL]?
var diaTimer = Timer()
var diashowState: DiashowState = .stopped
var mouseTimer = Timer()
@IBOutlet weak var diaView: NSImageView!
override func viewDidLoad() {
super.viewDidLoad()
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
func playDiashow() {
if diashowState == .paused {
diaTimer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(self.changeDia), userInfo: nil, repeats: true)
diashowState = .playing
NSCursor.setHiddenUntilMouseMoves(true)
}
}
func playDiashow(withFiles files: [URL]) {
stopDiashow()
self.files = files
diashowState = .paused
playDiashow()
changeDia()
}
func pauseDiashow() {
if diashowState == .playing {
diaTimer.invalidate()
diashowState = .paused
}
}
override func mouseMoved(with event: NSEvent) {
print("MOUSE MOVED")
}
func stopDiashow() {
pauseDiashow()
diaView.image = nil
files = nil
diashowState = .stopped
}
func changeDia() {
if diashowState == .playing {
let i = Int(arc4random_uniform(UInt32(files!.count)))
let thisDiaURL = files![i]
let thisDia = NSImage(contentsOf: thisDiaURL)
thisDia?.size = NSSize(width: (thisDia?.representations.first?.pixelsWide)!, height: (thisDia?.representations.first?.pixelsHigh)!)
diaView.image = thisDia
NSCursor.setHiddenUntilMouseMoves(true)
print("HIDE MOUSE")
}
}
}
Thanks a lot in advance!
To receive
mouseMoved
events you need to add aNSTrackingArea
to the view and as you have probably discovered thesetHiddenUntilMouseMoves
setting is single shot and needs to be reasserted after a mouse move in that state.Rather than trying to unravel your code i made a demo project where I setup a window with a view and a button. The view changes color from red to green to show state.
What going on here is.
NSTrackingArea
to the view. The owner is this view controller so it will receive themouseMoved:
event. The option.mouseMoved
is required to set this up.setHiddenUntilMouseMoves
to false.mouseMoved:
handlersetHiddenUntilMouseMoves
is set true after two seconds as long as the tracking area exists and its not already waiting. Note the weak reference toself
prevents a possible retain cycle here.This isn't perfect as you might find that the cursor hides once after leaving your window but should get you going in the right direction.