CocosSharp icon indicating copy to clipboard operation
CocosSharp copied to clipboard

Allow to control "ControllerUserInteractionEnabled" on tvOS

Open Krumelur opened this issue 9 years ago • 4 comments

Apple's HIG requires that the menu button of the remote exits the game to the home screen if you are on the first screen of an app. This is achieved by

  • Setting GCEventViewController.ControllerUserInteractionEnabled = true
  • Calling base.PressesBegan() when handling input
  • Afterwards, the property can be set to false again.

MonoGame handles this already correctly. IMHO it would not be the worst idea to derive from iOSGameViewController (which is unfortunately not public in MonoGame). This would prevent reinventing the wheel. Otherwise, CocosSharp should provide its own GCEventViewContrller subclass which handles this.

At the moment I handle it like this (changed CCGameView.tvOS.cs):

public override void PressesBegan (NSSet<UIPress> presses, UIPressesEvent evt)
        {
            FillPressesCollection (presses);

            if(this.UseDefaultBackButtonHandling && presses.AnyObject != null && presses.AnyObject.Type == UIPressType.Menu)
            {
                var eventController = UIApplication.SharedApplication.Delegate.GetWindow().RootViewController as GCEventViewController;
                if(eventController != null)
                {
                    eventController.ControllerUserInteractionEnabled = true;
                }
                base.PressesBegan (presses, evt);
                if(eventController != null)
                {
                    eventController.ControllerUserInteractionEnabled = false;
                }
            }
        }

Krumelur avatar Dec 16 '15 14:12 Krumelur

@Krumelur I think you are on the right track. In MG we only call base.PressesXXXX if we get a Menu press AND want to exit.. but that only really works if you View is derived from GCEventViewController.

Also it seemed that ControllerUserInteractionEnabled needed to be true for all the PressesBegin/Ended events, so we reset it to false when the app comes back into focus again.

dellis1972 avatar Dec 16 '15 15:12 dellis1972

@Krumelur I might need to see the code, but I'm not following your approach of moving this logic to the game view. As of CocosSharp 1.7.0.0-pre1, the setup is to essentially bring your own view controller and associate it with a CCGameView. So with respect to tvOS, why can't you simply subclass GCEventViewController and slap a CCGameView onto it? As in, make sure the current ViewController is of type GCEventViewController rather than simply UIViewController. Then you can put the above logic within your subclassed view controller.

Yes, I suppose this is slightly more cumbersome than the current MG approach, but there's a few things to keep in mind. Firstly, the project templates can simply be updated to ensure the view controller is correctly setup when targeting tvOS. I think this is something that will have to be addressed not just for CocosSharp, but for all tvOS apps.

Secondly, what happens when a user wants a multiple tabbed tvOS application? With the MG setup of taking over the entire application, this simply isn't possible. This was precisely the motivation for us to bring our interface up to the View level, to give developers control of the layout of their native application and the freedom to attach their game view where ever they see fit.

rtabbara avatar Dec 17 '15 00:12 rtabbara

@rtabbara Yes, I can use my own GCEventViewController and in fact, I do. But the question is: how much responsibility should I have as the user of CS and how much can CS do for me? If a tvOS app must exit if the menu button is clicked, I'd like to be able to handle this inside CS, without any native code. The problem I see is:

  • CocosSharp allows me to detect the press of the menu button conveniently via an abstraction (some listener)
  • This allows me to find out that "menu" has been pressed
  • However, now it is already too late to handle the press natively: PressesBegan() has already been run when I get the callback
  • If I want to exit the game if "menu" is pressed, PressesBegan() would have to call base.PressesBegan() and set eventController.ControllerUserInteractionEnabled = true (if I'm using GCEventViewController) to allow tvOS to handle the press and run the exit procedure (there is no way on tvOS to exit to the main menu directly - tvOS handles this internally if the press bubbles all the way up)
  • Problem 1: CS does not call base
  • Problem 2: CS does not set ControllerUserInteractionEnabled, after all, it is not aware of the GVEventViewController

If we change CS to always call base, my only option is to override PressesBegan() in my GCEventViewController, do the detection of "menu" in there natively and handle it. But like I already said: why provide an abstraction and then we require users to use native code to handle the same thing again.

I'd like to see something where I can set a button click to a handled or not handled state. CS would tell me "menu was pressed!" and my code decides to return a value that indicates that I don't want to handle it but let the default behavior run instead. On tvOS this would let the event bubble up and exit my game.

Bottom line is: I'd really like Apple to provide a proper method to exit to the home screen instead of having the current behavior. If you google for this issue, you'll find that many Apps have been rejected because they don't exit properly. If so many people fail in using an API, the API is no good.

Krumelur avatar Dec 17 '15 07:12 Krumelur

If we change CS to always call base, my only option is to override PressesBegan() in my GCEventViewController, do the detection of "menu" in there natively and handle it. But like I already said: why provide an abstraction and then we require users to use native code to handle the same thing again.

Because CCGameView is not an abstraction. It's just a UIView that happens to render game content. To me, it would be akin to requiring a UITableView to handle the exit code. It just seems very strange.

But I understand the frustration. To me the crux of the issue is this requirement of having to toggle ControllerUserInteractionEnabled. As you've said, this is a very bizarre setup.

We'll have to think a bit more carefully about how to do this right. Something along your suggestion of having a listener/event handler for when the menu-button is pressed seems to be a good compromise.

rtabbara avatar Dec 17 '15 12:12 rtabbara