tvOS UIPress gestures not being recognized in subclass of SKScene - swift

I am trying to respond to a press in a subclass of SKScene. I can override the responder pressesEnded inside of my ViewController just fine, but when I move my pressesEnded override into my SKScene sub class I no longer receive any calls.
Below is my pressesEnabled override, which works as intended inside of ViewController
override func pressesEnded(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
print("press")
}
Anybody know how to receive button presses inside of a SKScene?

You need to forward your press events from your ViewController to the SKScene, like so...
override func pressesBegan(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
gameScene.pressesBegan(presses, withEvent: event)
}
override func pressesEnded(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
gameScene.pressesEnded(presses, withEvent: event)
}
Then in gameScene (SKScene) do something like:
override func pressesBegan(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
for press in presses {
switch press.type {
case .UpArrow:
print("Up Arrow")
case .DownArrow:
print("Down arrow")
case .LeftArrow:
print("Left arrow")
case .RightArrow:
print("Right arrow")
case .Select:
print("Select")
case .Menu:
print("Menu")
case .PlayPause:
print("Play/Pause")
}
}
}
override func pressesEnded(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
print("Presses Ended.")
}
The "Arrow" presses are sent when the user taps the edges of the touchpad, but aren't recognized in the simulator. "Select" is sent when the center of the touchpad is tapped.
I hope this helps!

Use pressesBegan to map a physical button (Menu, PlayPause), and pressesBegan or pressesEnded for the trackpad of the Apple TV Remote (left, right, etc).
If you press on a "button" of the trackpad and move to another location and release, the method pressesEnded is not called, you can't do this with a physical button.
Presses Began:
override func pressesBegan(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
print("Press began")
for item in presses {
if item.type == .PlayPause {
print("PlayPause")
}
}
}
Presses Ended:
override func pressesEnded(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
print("Press Ended")
for item in presses {
if item.type == .RightArrow {
print("Right Arrow")
}
}
}

Related

tvOS: pressesEnded is called intermittently

I am creating a subclass of a UIButton, the reason why I'm trying to intercept the touch is because I cant seem to find another way to receive 'press up' or 'press ended' events for the standard UIButton in tvOS. If I could find a way to do that then I wouldn't need to bother with the solution below.
pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) doesn't seem to be getting called every time I release the 'select' button on the Apple TV Remote.
pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) is being called every time without any issues. I've attached my code below. Any ideas what could be causing this issue?
class EVLPTZButton: UIButton
{
var command: PTZCommand!
var delegate: EVLPTZButtonCommandDelegate?
override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?)
{
super.pressesBegan(presses, with: event)
delegate?.ptzButton(pressesBeganFor: self, with: command)
}
override func pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?)
{
super.pressesEnded(presses, with: event)
delegate?.ptzButton(pressesEndedFor: self)
}
}
After some more testing it seems that when the 'select' button is released tvOS calls either pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) OR pressesCancelled(_ presses: Set<UIPress>, with event: UIPressesEvent?).
I found this solution by jumping to the definition of pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) and finding this comment:
Your responder will receive either pressesEnded:withEvent or
pressesCancelled:withEvent: for each press it is handling (those
presses it received in pressesBegan:withEvent:).

presses not working tvos - swift

I am trying to detect presses in swift, and I am unable to detect a press. Here is my code:
override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
print("test1")
}
override func pressesChanged(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
print("test2")
}
override func pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
print("test3")
}
override func pressesCancelled(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
print("test4")
}
After executing the code on a physical apple tv and on a simulator, the console remains empty. Why are presses not being detected? Any help would be appreciated.
I have found the answer, but I am not sure why the override method didn't work.
let press:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(pressed))
press.allowedPressTypes = [NSNumber(value: UIPressType.select.rawValue)]
view.addGestureRecognizer(press)

tvOS pressesBegan() not updating in GameScene

In my GameScene, when I update variables using 'touchesBegan()' it works fine, but when I pass 'pressesBegan()' from the GameViewController to the GameScene, the code gets excited, but the changes get ignored.
GameViewController:
class GameViewController: UIViewController {
...
override func pressesBegan(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
let scene = GameScene(fileNamed: "GameScene")
scene?.pressesBegan(presses, withEvent: event)
}
GameScene:
class GameScene: SKScene {
var test = true
...
override func pressesBegan(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
test = false
print(test)
}
override func update(currentTime: CFTimeInterval) {
print(test)
}
}
This code will result in "false" then "true" in the console.
Every time you call pressesBegan, you are creating a new Gamescene, you need to do
override func pressesBegan(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
if let skView = self.view as? SKView
{
skView.scene?.pressesBegan(presses, withEvent: event)
}
}

Forced Touch with tvOS

Does anybody know how to detect a forced touch/click on the remote control with tvOS?
I want to use the click in a Sprite Kit scene to open a 'game paused alert'. I have no UIKit controls which have the focus and will react on the click.
I'm already using the 'normal' touch events on the remote control to move my sprites around.
Apple suggests using UIPressesEvent's to detect presses/clicks.
override func pressesBegan(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
for item in presses {
if item.type == .Select {
self.view.backgroundColor = UIColor.greenColor()
}
}
}
override func pressesEnded(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
for item in presses {
if item.type == .Select {
self.view.backgroundColor = UIColor.whiteColor()
}
}
}
override func pressesChanged(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
// ignored
}
override func pressesCancelled(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
for item in presses {
if item.type == .Select {
self.view.backgroundColor = UIColor.whiteColor()
}
}
}

Override UIGestureRecognizer touchesBegan

I have 1 Main View and 1 SubView:
Main View > SubView
I think that the Main View is "stealing" the events from the SubView.
For example, when I tap on the SubView, only the Main View GestureRecognizer is fire.
Here is my custom GestureRecognizer (which intercepts every touch event):
import UIKit
import UIKit.UIGestureRecognizerSubclass
class MainGestureRecognizer: UIGestureRecognizer {
override func touchesBegan(touches: NSSet!, withEvent event: UIEvent!) {
super.touchesBegan(touches, withEvent: event);
//nextResponder() ??
state = UIGestureRecognizerState.Began;
}
override func touchesMoved(touches: NSSet!, withEvent event: UIEvent!) {
super.touchesMoved(touches, withEvent: event);
//nextResponder() ??
state = UIGestureRecognizerState.Changed;
}
override func touchesEnded(touches: NSSet!, withEvent event: UIEvent!) {
super.touchesEnded(touches, withEvent: event);
//nextResponder() ??
state = UIGestureRecognizerState.Ended;
}
override func touchesCancelled(touches: NSSet!, withEvent event: UIEvent!) {
super.touchesCancelled(touches, withEvent: event);
//nextResponder() ??
state = UIGestureRecognizerState.Cancelled;
}
}
Maybe I should use nextResponder, but I have only found Obj-C code like:
[self.nextResponder touchesBegan:touches withEvent:event];
What's the trick to pass an event to the next responder in the responder chain?
Is there a way to pass touches through on the iPhone?
So the question is, what should I do to make the second event (the SubView Event) fire too?
Is there a function like nextResponder in Swift?
Ôh ! Here is the Swift code for nextResponder :
https://stackoverflow.com/a/26510277/4135158