Is there a way to detect if the user clicks on the right or left side of the Apple tv remote? - tvos

I can detect press by overriding pressesEnded method, but how can I find if user pressed on the right or the left side of the remote?

Directional taps can be detected inspecting the press type:
override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
for press in presses {
switch press.type {
case .upArrow:
print("⬆️")
case .downArrow:
print("⬇️")
default:
super.pressesBegan(presses, with: event)
}
}
}
Directional clicks, on the other hand, requires the use of the GameControler SDK, you can find it explained here: https://medium.com/#dcordero/directional-clicks-on-tvos-c711a2faf71a

Related

MarkupCore - Is it possible to disable rightClick on a hovered markup in ForgeViewer?

Whenever I hover a markup and right click it, it locks the mouse movement to the drawing and makes it impossible to move the mouse without moving the drawing.
Is it possible to disable this behaviour?
Depending on your specific scenario, there's a few things you can try:
If you're trying to enable camera pan while in the markup mode on a 2D drawing, you can simply "enable navigation" for the markup tool:
viewer.toolController.getTool('markups.core').allowNavigation(true);
If that's not sufficient for your case, you could also try and modify the handleButtonDown method that the markup tool uses to decide whether and how it should handle the mouse button down event. Currently the method looks like this:
this.handleButtonDown = function(event, button) {
if (this.allowNav || (this.is2d && (avp.isRightClick(event, this.viewer.navigation) || avp.isMiddleClick(event)))) {
// If pan tool won't handle button down, then pass over the event
if (this.panTool && this.panTool.handleButtonDown) {
return this.panTool.handleButtonDown(event, button);
} else return false;
}
return true; // Consume event
};
Where avp is just a shortcut to the Autodesk.Viewing.Private namespace.
viewer.toolController.getTool('markups.core').handleButtonDown = function (event, button) {
// Return true when you want the measure tool to "capture" the event and process it somehow,
// or false when you want to ignore the event and allow other tools on the stack to handle it
};

Make JavaFX Button visually appear to be clicked on right click

I converted some old Java Swing code to JavaFX. The JavaFX code had explicit doClick() for the right mouse button calls:
myButton.addMouseListener(new MouseAdapter() {
#Override
public final void mousePressed(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {
// ...
}
else if (SwingUtilities.isRightMouseButton(e)) {
// ...
myButton.doClick();
}
}
});
Left clicks make the button visually appear to be clicked in Java Swing. However right clicks do not visually do this without adding myButton.doClick()
I am seeing the same visual behavior in JavaFX and I want right clicks to visually make the button look clicked. Below is my JavaFX code:
myButton.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(final MouseEvent event) {
if (event.getButton() == MouseButton.PRIMARY) {
// ...
}
else if (event.getButton() == MouseButton.SECONDARY) {
// ...
}
}
});
What do I have to add to make right clicks visually click myButton?
That visual appearance of button click is usually referred as "armed" pseudo state. So you can turn on/off the armed pseudo state of the button when doing right button pressed&released.
Something like..
myButton.setOnMousePressed(e->{
if(e.getButton()== MouseButton.SECONDARY){
myButton.pseudoClassStateChanged(PseudoClass.getPseudoClass("armed"), true);
}
});
myButton.setOnMouseReleased(e->{
if(e.getButton()== MouseButton.SECONDARY){
myButton.pseudoClassStateChanged(PseudoClass.getPseudoClass("armed"), false);
}
});
Updating the :armed pseudo class is not enough if you want the Button's action to be fired by a right click. You actually need to arm the Button. In other words, you need to make the armed property change to true. Also, updating the armed property will update the pseudo class for you.
As the armed property is read-only, you can't set it directly; you need to call arm() and disarm(). You may also need to manually call fire() (expanded on below). Here's an example:
Button button = new Button("Click Me!");
button.setOnAction(event -> System.out.println("Button clicked!"));
button.setOnMousePressed(event -> {
if (event.getButton() == MouseButton.SECONDARY) {
button.arm();
}
});
button.setOnMouseReleased(event -> {
if (button.isArmed()) {
button.disarm();
button.fire();
}
});
However, you don't appear to need the onMouseReleased handler at all—at least in JavaFX 11 and 12, using the default Button's skin/behavior. The Button's behavior class will fire the action if said Button is armed at the time the mouse is released (and no keys are down). Note that the default behavior class does a more complex check regarding which MouseButton was used (i.e. it does more then just check event.getButton() == MouseButton.PRIMARY). You can see the implementation for yourself here.
All that said, if you only want the visuals to change then you should use the approach shown in Sai's answer.

tvOS - catch MENU button presses during push-view-controller transition

I have a UIViewController in my tvOS app which will only appear for a few seconds, and needs totally customizable MENU button handling. I create it like so:
- (void)viewDidLoad
{
[super viewDidLoad];
// Add a tap gesture recognizer to handle MENU presses.
UITapGestureRecognizer *tapGestureRec = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
tapGestureRec.allowedPressTypes = #[#(UIPressTypeMenu)];
[self.view addGestureRecognizer:tapGestureRec];
}
- (void)handleTap:(UITapGestureRecognizer *)sender
{
// Code to process the MENU button is here.
}
I display the view controller using pushViewController:animated::
UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:identifier];
[self pushViewController:controller animated:isAnimated];
I've found that if the user presses MENU as soon as the screen starts to appear, while the cross-fade transition effect is still displaying, they are able to dodge the UITapGestureRecognizer and go back to a previous screen, which is not intended. They can also cause issues by mashing MENU over and over again--eventually they will escape out of things that they should not be able to.
How can I ensure that the MENU press always reaches my override? Is there a way to specify an app-encompassing MENU button handler and still use a UINavigationController?
A solution that worked for me was to install a UITapGestureRecognizer onto self.navigationController.view. Any taps which get missed by the regular UIViewControllers end up getting caught by the navigation controller's recognizer instead. If you install UITapGestureRecognizers on each view controller you create, the only taps which will fall through the cracks to the navigation controller are taps that occur mid-transition, and it is safe to just ignore those taps completely.
Note that when you want MENU to go back to the home screen, you will need to temporarily remove this tap recognizer and let tvOS handle the tap on its own, as I could find no clean way to escape to the home screen in my code (short of exit(0)).
I have very similar problem because of this behaviour.
In my case I have custom focus management depending on MENU button click detected on pressesEnded and managed by preferredFocusedView. But when navigation controller is poping ViewController and user at this time make second click on MENU button, then UINavigationController class detect pressesEnded and then call preferredFocusedView on my destination ViewController where is my management but pressesEnded will be not called, because was "stolen" by UINavigationController.
Solution for this problem in my case is to create "dummy" class that will be used by UINavigationController like this:
class MenuPhysicalHackNavigationController: UINavigationController {
override func pressesBegan(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
}
override func pressesEnded(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
}
override func pressesCancelled(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
}
override func pressesChanged(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
}
}

Apple TV – How to only change focus when "Menu" button is tapped

I'm working on a simple board game. I have buttons in the left column like "New Game", "Settings" etc.(let's call it "Menu View"). The rest of the screen is the "Board View" with the current state of the game.
Is it possible to handle when user taps the "Menu" button on the Apple TV Remote control just to navigate from the "Board View" to my "Menu View" instead of closing my app? I have both "Menu View" and "Board View" in the same controller, maybe I need to adjust the controller hierarchy?
Thanks for help!
Eventually, I noticed overriding pressesEnded won't cancel the Menu button press for the first time after launching the app. Using UITapGestureRecognizer on the other hand does:
let menuTapGestureRegocnizer = UITapGestureRecognizer(target: self, action: "menuTapped")
menuTapGestureRegocnizer.allowedPressTypes = [UIPressType.Menu.rawValue]
view.addGestureRecognizer(menuTapGestureRegocnizer)
You can override the pressesEnded method and trigger the navigation segues manually
override func pressesEnded(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
for press in presses {
if(press.type == UIPressType.Menu) {
// Do what you want
// ...
} else {
super.pressesEnded(presses, withEvent: event)
}
}
}

Is it possible to handle screensaver event from flash file?

I have created a flash file, which will play another scene and will stop on mouse over. Then i converted this to a screensaver format.But i need to put a delay on mouse over before the screensaver will disappear .
By using fs commands i can ignore/ accept mouse events.
For example :
fscommand("mousequit","variable_name");
The value "0" means that the screensaver is set to quit on mouse events, "1" means it ignores mouse events.
I can ignore the mouse events until i reached the expected frame.So i can give a delay or what ever.
You can use Event.ACTIVATE/Event.DEACTIVATE events for handling app focus.
private function addActivationEvents():void
{
addEventListener(flash.events.Event.ACTIVATE, handleAppActivationEvent);
addEventListener(flash.events.Event.DEACTIVATE, handleAppActivationEvent);
}
private function handleAppActivationEvent(event:flash.events.Event):void
{
switch (event.type)
{
case flash.events.Event.ACTIVATE:
break;
case flash.events.Event.DEACTIVATE:
break;
}
}