Skip to content

tvOS Menu button: root menu to Home (investigation)

tvOS Menu button on the root menu (RELEASE-1.1 §3a)

Section titled “tvOS Menu button on the root menu (RELEASE-1.1 §3a)”

Verdict: no game change is justified without a device result. Confidence tags: [Certain] = read in source, [Likely] = inferred, [Guessing] = unverified.

(a) How the fork handles the Menu press [Certain]

Section titled “(a) How the fork handles the Menu press [Certain]”

~/Claude/godot-tvos/godot-48/drivers/apple_embedded/godot_view_controller.mm (class GDTViewController : GCEventViewController):

  • pressesEnded: under TVOS_ENABLED: for a UIPressTypeMenu press it asks SceneTree::is_quit_on_go_back().
    • true (the Godot default): calls [super pressesEnded:], so UIKit/the system handles Menu. On a tvOS app’s root view this exits to the Home screen.
    • false: sends WINDOW_EVENT_GO_BACK_REQUEST (becomes NOTIFICATION_WM_GO_BACK_REQUEST on the main window/nodes). Nothing is synthesised as ui_cancel.
    • Either way it returns before the key path, so Menu never becomes a key or ui_cancel.
  • pressesBegan: skips Menu (Siri Remote presses carry no UIKey).
  • godot_commonInit has self.controllerUserInteractionEnabled = NO commented out, so it is the default YES: controller input is also delivered as UIKit presses.
  • Joypads (incl. the Siri Remote as a micro gamepad) come from the SDL joypad driver (os_apple_embedded.mm), a separate path from the UIPress one. InputRouter filters the Siri Remote out of gameplay scans.

The game never sets quit_on_go_back (git grep over *.gd, project.godot, both export presets: zero hits), so it is the default true.

(b) What the game does today [Certain for code, Likely for outcome]

Section titled “(b) What the game does today [Certain for code, Likely for outcome]”
  • start_menu.gd has no Menu/ui_cancel handling, and does not need one if (a) holds: the Siri Remote Menu press goes to UIKit before Godot sees it, so the root menu already exits to Home. This matches 1.0 passing review.
  • In-run: main.gd:4164 pauses on JOY_BUTTON_START/BACK and Esc. Sub-screens (shop, ship config, drone bay, codex, lobbies) close on ui_cancel / JOY_BUTTON_B / Esc (docs/reference/improvement-punch-list.md:285).
  • Likely gap, the opposite of the filed item: with quit_on_go_back == true, the Siri Remote Menu press also goes Home from inside shop / pause / mid-run, not just on the root menu. Apple’s convention (Menu = back, Home only from root) is therefore probably violated off-root, but the Siri Remote cannot play the game, so it only bites a player holding the remote at those screens. [Likely]
  • Unknown, more serious: with controllerUserInteractionEnabled == YES, a gamepad’s B (or Menu) may also arrive as UIPressTypeMenu, which would exit the app on B in the shop. The shop and sub-screens use B to go back and shipped without that report, so probably not, but nothing in docs/memory records a check. [Guessing]

Searched docs/ and the memory dir for “Menu button”, “GCEventViewController”, “Menu/Home”: only docs/research/2026-10-14-qol-and-marketing-audit-1.1.md:51 (the audit that raised this, itself unverified) and RELEASE-1.1.md. No 1.0/1.0.1 review rejection or note about Menu. dev-tools.md:12 (BUILD 58) records a controller Menu doing nothing until the pause menu bound START/BACK.

A GDScript-only fix exists as a hook (get_tree().quit_on_go_back: true on the root menu, false elsewhere, then handle NOTIFICATION_WM_GO_BACK_REQUEST as back/pause) but it is not low-risk blind: it changes Menu from “system handles it” to “game must handle it” on every non-root screen, and if any screen misses the notification Menu does nothing there, which is the exact App Review failure we are trying to avoid. The right design depends on the device result below.

What Chris must check on the ATV (BUILD 332 or any Dev install)

Section titled “What Chris must check on the ATV (BUILD 332 or any Dev install)”
  1. Siri Remote, root start menu: Menu. Expect: back to tvOS Home. (If yes, the §3a item is already satisfied; tick it.)
  2. Siri Remote, inside SHOP / SHIP / SETTINGS / pause menu / mid-run (pad paired): Menu. Does the app exit to Home, or go back/pause?
  3. Gamepad (Xbox/PS), same screens: B and Menu/Start. Does B ever exit the app? Any exit is a bug (breaks back-navigation).
  4. Note whether the Siri Remote Menu in a run does anything in-game before exiting.
  • 1 yes, 2 and 3 never exit: nothing to do. Tick the item.
  • 2 exits Home off-root only: GDScript-only. In main.gd set get_tree().quit_on_go_back = (start menu showing and no overlay open) whenever the screen changes (a tiny pure helper MenuHomePolicy.should_exit_to_home(menu_visible, overlays_open) with a GUT test), and handle NOTIFICATION_WM_GO_BACK_REQUEST in main.gd by routing to the existing back/pause action. Needs a Dev install to verify; no fork rebuild.
  • 3 shows B exits the app: fork change in godot_view_controller.mm: uncomment self.controllerUserInteractionEnabled = NO; in godot_commonInit (tvOS only). Then Siri Remote Menu no longer arrives as a press; handle it from the SDL joypad START event and give the root menu an explicit exit, which UIKit offers no API for. Must be fork-verified on device first; repackage the tvOS template zip per platform/tvos/CLAUDE.md. Do not do this unless step 3 fails.