Swift Mouse Left Click Listener - swift

I am wondering how I can get this function to work, I just don't understand how to get correct type for NSEvent or where I even find it using developer documentation.
func mouseDown(with event: NSEvent)
I am trying to make an IF Statement that prints "User has clicked mouse" within a console window.
I am not looking for you to solve this problem for me, I am just hoping that you can show me a way that I can solve this for myself using developer documentation, please don't just link me a copy paste thread from another stack overflow unless it teaches me how people are finding the information required to solve these problems.
I just don't understand what goes inside of the parameter (with event: NSEvent) or how you would even find this out without just copying someone else's work.

All you need is to override your view controller func mouseDown(with event: NSEvent) method. Just make sure you dont change the method signature and include the override keyword and dont forget to call super.
import Cocoa
class ViewController: NSViewController {
// ...
override func mouseDown(with event: NSEvent) {
super.mouseDown(with: event)
print(#function)
}
override func rightMouseDown(with event: NSEvent) {
super.rightMouseDown(with: event)
print(#function)
}
}

Related

Adding a Mac trackpad scroll gesture to a SKScene

To scroll a SKNode (called scroller) within a SKScene (called menuScene), I'm doing the following, which works perfectly but I'm not sure if it's the correct way to achieve this.
Within the NSViewController class, I'm overriding the scrollWheel event to call the scene's own scrollWheel event:
override func scrollWheel(with event: NSEvent) {
skView?.scene?.scrollWheel(with: event)
super.scrollWheel(with: event)
}
Then, within menuScene, the function is simply:
override func scrollWheel(with event: NSEvent) {
scroller.position.x = scroller.position.x + (event.deltaX*3)
}
This works perfectly, but is there a better way to achieve the same goal?

How can I respond to a keyUp event?

I am writing a simple menu bar application for MacOS using SwiftUI. I would like the application to respond to the escape key. Using what I have pieced together so far, I have something like this:
extension NSWindow {
open override func keyDown(with event: NSEvent) {
print("keyDown: \(event.keyCode)")
}
open override func keyUp(with event: NSEvent) {
print("keyUp: \(event.keyCode)")
}
}
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
// etc
}
}
The AppDelegate creates and launches a NSPopover.
When I run the application, I do get the keyUp messages, but, not the keyDown for some reason.
The question is how can I respond to the key from within the AppDelegate? Ultimately, I want to close the popover using the escape key, but I would also like to explore other possibilities.

UIView catch touch events and pass throught

I want to implement UIView subclass that will catch all touch events (especially touchesMoved) and pass them through. Is it possible?
class PassthroughView: UIView {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let view = super.hitTest(point, with: event)
return view == self ? nil : view
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("touchesBegan")
super.touchesBegan(touches, with: event)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
print("touchesMoved") //not called
super.touchesMoved(touches, with: event)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
print("touchesEnded")
super.touchesEnded(touches, with: event)
}
}
You can’t really do this. If your view receives touches it can’t pass it on to the view that would have received if your view isn’t there. To do this you’d basically have to reimplement the whole event routing. This would be really hard, or maybe even impossible without access to Apple internal API. But even if you got this right it could break with every iOS update.
But there is a different way to get all touch events while still having them delivered to the appropriate views. For this you create a subclass of UIApplication and override the sendEvent(_:) method. This is called for each event and dispatches it to the appropriate views. From there you can first do your special processing and then call super.sendEvent() to send it to your windows as usual.
Of course there you don’t get different calls for touches began/moved/ended, but the information is there in your event object. First you need to check the event.type property to see if you actually got a touch event. If so you can get all the touches from the event.allTouches property. For each touch you can get the phase which describes whether this touch began, moved, ended and so on.
Of course subclassing is not enough, you also have to tell the system to use your new subclass. To do this you annotate it as #objc(MyApplication) where MyApplication is the name of the class. This makes sure the Objective-C runtime can find the class by the name you gave it. Then you edit your Info.plist file and set this name for the "Principal class" key. (If you are not using the Xcode editor the key is also called NSPrincipalClass).

OSX swift 3 - can't disable keyDown. error sound

Im am trying to disable error sound when I push down space bar and arrow keys. I tryed handling events with super.keyDown(with: event) no luck. Cant find any other working solutions apart from using global key frameworks. Are there any other options I have?
NSEvent.addLocalMonitorForEvents(matching: .keyDown) { (aEvent) -> NSEvent? in
self.keyDown(with: aEvent)
return aEvent
}
}
override func keyDown(with event: NSEvent) {
super.keyDown(with: event)
}
Update: I've found out that the root cause of the problem was, that a view was the first responder that shouldn't be actually. After setting the responder to nil self.view.window?.makeFirstResponder(nil) I was able to fix this. I've also used performKeyEquivalent as this answer suggested.
I know my answer is very late, but maybe it will help you or someone else in the future. I'm not sure if that's the best way to do it but it does work. Simply return nil instead of the event.
NSEvent.addLocalMonitorForEvents(matching: .keyDown) { (aEvent) -> NSEvent? in
self.keyDown(with: aEvent)
return nil
}
override func keyDown(with event: NSEvent) {
super.keyDown(with: event)
}
Apple's documentation of the method says the following for the block parameter:
The event handler block object. It is passed the event to monitor. You can return the event unmodified, create and return a new NSEvent object, or return nil to stop the dispatching of the event.
The only downside is, that there will be no sound at all. Even if the key event is not handled by you.

Swift / SpriteKit Button Drag Off Cancel Not Working?

Hello I need your help I have been looking a while now to find the Answer to this.
I also have simplified the code to get rid of allot of the information/junk you don't need to know.
I have a main menu scene in for a IOS game using SpriteKit And Swift. There Is a main menu play button. What I want is When the button is pressed the button get bigger by a little. When the my finger is release the button gets smaller. This works fine using override func touchesBegan / touchesEnded. my problem is when my finger gets dragged off the button like to cancel. The button does not return to the original size. I am pretty sure I need to use
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {}
But upon many attempts I am not getting the the desired result of returning the button to original size when my finger is dragged off the button. Thanks for any help.
import Foundation
import SpriteKit
import UIKit
class StartScene: SKScene {
var playButton: SKNode! = nill
override func didMoveToView(view: SKView) {
// Create PlayButton image
playButton = SKSpriteNode(imageNamed: "playButtonStatic")
// location of Button
playButton.position = CGPoint(x:CGRectGetMidX(self.frame), y:520);
self.addChild(playButton)
playButton.setScale(0.5)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if playButton.containsPoint(location) {
playButton.setScale(0.6)}}}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if playButton.containsPoint(location) {
playButton.setScale(0.5)
}}}
// Problem Area
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
for touch: AnyObject in touches! {
let location = touch.locationInNode(self)
if playButton.containsPoint(location) {
playButton.setScale(0.5)
}}}
}
Thanks for any response
Found the solution use a Else statement in TouchesEnded
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if playButton.containsPoint(location) {
playButton.setScale(0.5)
}
else
{
playButton.setScale(0.5)
}}
You say you found a solution but here's an easier solution: use a custom class I created designed specifically for buttons for SpriteKit. Link to the GitHub that has the class file. With this class, you don't have to worry about it at all, and it removes unnecessary code from your touches functions. JKButtonNodes have 3 states: normal, highlighted, and disabled. You also don't have to worry about setting it to nil if you have removed it from the parent.
To declare a variable, do this. Ignore the playButtonAction error for now.
var playButton = JKButtonNode(background: SKTexture(imageNamed: "playButtonStatic"), action: playButtonAction)
The action is the function to call when the button is pressed and let go. Create a function like this anywhere in your class.
func playButtonAction(button: JKButtonNode) {
//Whatever the button does when pressed goes here
}
Then you can set its properties in didMoveToView.
playButton.position = CGPoint(x:CGRectGetMidX(self.frame), y:520)
//These are the 3 images you want to be used when pressed/disabled
//You can create a bigger image for when pressed as you want.
playButton.setBackgroundsForState(normal: "playButtonStatic", highlighted: "playButtonHighlighted", disabled: "")
addChild(playButton)
And that's it! The JKButtonNode class itself already cancels touches if the user moves their finger off, it also doesn't call the function unless the user has successfully pressed the button and released their finger on it. You can also do other things like disable it from playing sounds, etc.
A good pro of using JKButtonNode is that you don't have to have code all over the place anymore since it doesn't require ANY code in the touches functions.