fix(tv): back button Menu on Siri Remote

This commit is contained in:
edde746
2026-05-12 22:46:38 +02:00
parent de62c8530f
commit b0f1a5d4f1
3 changed files with 25 additions and 6 deletions
+18 -4
View File
@@ -62,10 +62,18 @@ KeyEventResult handleBackKeyAction(KeyEvent event, VoidCallback onBack) {
return KeyEventResult.handled; return KeyEventResult.handled;
} }
if (PlatformDetector.isAppleTV() && event.isPhysicalKeyboardEvent && event is KeyDownEvent) { // AppleTV physical-keyboard back (Siri Remote Menu via engine-synthesized
BackKeyCoordinator.markHandled(); // escape): run onBack on KeyDown only; consume KeyUp silently. The
BackKeyUpSuppressor.suppressBackUntilKeyUp(); // suppressor-based "arm-on-KeyDown, clear-on-KeyUp" pattern leaks here
onBack(); // because onBack typically calls Navigator.pop, swapping the focus tree
// before the matching KeyUp is dispatched — the orphaned KeyUp then never
// reaches a consumeIfSuppressed call, pinning the suppressor armed and
// silently swallowing the next press's KeyDown.
if (PlatformDetector.isAppleTV() && event.isPhysicalKeyboardEvent) {
if (event is KeyDownEvent) {
BackKeyCoordinator.markHandled();
onBack();
}
return KeyEventResult.handled; return KeyEventResult.handled;
} }
@@ -174,6 +182,12 @@ FocusOnKeyEventCallback dpadKeyHandler({
class BackKeySuppressorObserver extends NavigatorObserver { class BackKeySuppressorObserver extends NavigatorObserver {
@override @override
void didPop(Route route, Route? previousRoute) { void didPop(Route route, Route? previousRoute) {
// On AppleTV, handleBackKeyAction consumes the KeyUp silently regardless,
// so the suppressor isn't needed and arming it would pin state across the
// pop's focus-tree swap. (The atomic engine fix delivers KeyDown+KeyUp in
// a single recognizer Began callback, so didPop fires squarely inside the
// window where BackKeyPressTracker.isBackKeyDown is true.)
if (PlatformDetector.isAppleTV()) return;
if (BackKeyPressTracker.isBackKeyDown) { if (BackKeyPressTracker.isBackKeyDown) {
BackKeyUpSuppressor.suppressBackUntilKeyUp(); BackKeyUpSuppressor.suppressBackUntilKeyUp();
} }
+6 -1
View File
@@ -954,14 +954,19 @@ class _MainScreenState extends State<MainScreen>
return KeyEventResult.handled; return KeyEventResult.handled;
} }
// AppleTV: KeyDown does the work, KeyUp is consumed silently. See the
// matching comment in handleBackKeyAction for why the suppressor pattern
// doesn't fit here.
if (PlatformDetector.isAppleTV() && event is KeyDownEvent) { if (PlatformDetector.isAppleTV() && event is KeyDownEvent) {
final result = _handleMainBack(allowTvSystemExit: true); final result = _handleMainBack(allowTvSystemExit: true);
if (result == KeyEventResult.handled) { if (result == KeyEventResult.handled) {
BackKeyCoordinator.markHandled(); BackKeyCoordinator.markHandled();
BackKeyUpSuppressor.suppressBackUntilKeyUp();
} }
return result; return result;
} }
if (PlatformDetector.isAppleTV() && event is KeyUpEvent) {
return KeyEventResult.handled;
}
if (event is KeyUpEvent) { if (event is KeyUpEvent) {
final result = _handleMainBack(allowTvSystemExit: PlatformDetector.isAppleTV()); final result = _handleMainBack(allowTvSystemExit: PlatformDetector.isAppleTV());
+1 -1
View File
@@ -1 +1 @@
3.41.6+7 3.41.6+8