1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/// @docImport 'package:flutter/material.dart';
6/// @docImport 'package:flutter/rendering.dart';
7library;
8
9import 'dart:async';
10import 'dart:ui';
11
12import 'package:flutter/foundation.dart';
13import 'package:flutter/gestures.dart';
14import 'package:flutter/painting.dart';
15import 'package:flutter/scheduler.dart';
16import 'package:flutter/services.dart';
17
18import 'binding.dart';
19import 'focus_scope.dart';
20import 'focus_traversal.dart';
21import 'framework.dart';
22
23/// Setting to true will cause extensive logging to occur when focus changes occur.
24///
25/// Can be used to debug focus issues: each time the focus changes, the focus
26/// tree will be printed and requests for focus and other focus operations will
27/// be logged.
28bool debugFocusChanges = false;
29
30// When using _focusDebug, always call it like so:
31//
32// assert(_focusDebug(() => 'Blah $foo'));
33//
34// It needs to be inside the assert in order to be removed in release mode, and
35// it needs to use a closure to generate the string in order to avoid string
36// interpolation when debugFocusChanges is false.
37//
38// It will throw a StateError if you try to call it when the app is in release
39// mode.
40bool _focusDebug(
41 String Function() messageFunc, [
42 Iterable<Object> Function()? detailsFunc,
43]) {
44 if (kReleaseMode) {
45 throw StateError(
46 '_focusDebug was called in Release mode. It should always be wrapped in '
47 'an assert. Always call _focusDebug like so:\n'
48 r" assert(_focusDebug(() => 'Blah $foo'));"
49 );
50 }
51 if (!debugFocusChanges) {
52 return true;
53 }
54 debugPrint('FOCUS: ${messageFunc()}');
55 final Iterable<Object> details = detailsFunc?.call() ?? const <Object>[];
56 if (details.isNotEmpty) {
57 for (final Object detail in details) {
58 debugPrint(' $detail');
59 }
60 }
61 // Return true so that it can be used inside of an assert.
62 return true;
63}
64
65/// An enum that describes how to handle a key event handled by a
66/// [FocusOnKeyCallback] or [FocusOnKeyEventCallback].
67enum KeyEventResult {
68 /// The key event has been handled, and the event should not be propagated to
69 /// other key event handlers.
70 handled,
71 /// The key event has not been handled, and the event should continue to be
72 /// propagated to other key event handlers, even non-Flutter ones.
73 ignored,
74 /// The key event has not been handled, but the key event should not be
75 /// propagated to other key event handlers.
76 ///
77 /// It will be returned to the platform embedding to be propagated to text
78 /// fields and non-Flutter key event handlers on the platform.
79 skipRemainingHandlers,
80}
81
82/// Combine the results returned by multiple [FocusOnKeyCallback]s or
83/// [FocusOnKeyEventCallback]s.
84///
85/// If any callback returns [KeyEventResult.handled], the node considers the
86/// message handled; otherwise, if any callback returns
87/// [KeyEventResult.skipRemainingHandlers], the node skips the remaining
88/// handlers without preventing the platform to handle; otherwise the node is
89/// ignored.
90KeyEventResult combineKeyEventResults(Iterable<KeyEventResult> results) {
91 bool hasSkipRemainingHandlers = false;
92 for (final KeyEventResult result in results) {
93 switch (result) {
94 case KeyEventResult.handled:
95 return KeyEventResult.handled;
96 case KeyEventResult.skipRemainingHandlers:
97 hasSkipRemainingHandlers = true;
98 case KeyEventResult.ignored:
99 break;
100 }
101 }
102 return hasSkipRemainingHandlers ?
103 KeyEventResult.skipRemainingHandlers :
104 KeyEventResult.ignored;
105}
106
107/// Signature of a callback used by [Focus.onKey] and [FocusScope.onKey]
108/// to receive key events.
109///
110/// This kind of callback is deprecated and will be removed at a future date.
111/// Use [FocusOnKeyEventCallback] and associated APIs instead.
112///
113/// The [node] is the node that received the event.
114///
115/// Returns a [KeyEventResult] that describes how, and whether, the key event
116/// was handled.
117@Deprecated(
118 'Use FocusOnKeyEventCallback instead. '
119 'This feature was deprecated after v3.18.0-2.0.pre.',
120)
121typedef FocusOnKeyCallback = KeyEventResult Function(FocusNode node, RawKeyEvent event);
122
123/// Signature of a callback used by [Focus.onKeyEvent] and [FocusScope.onKeyEvent]
124/// to receive key events.
125///
126/// The [node] is the node that received the event.
127///
128/// Returns a [KeyEventResult] that describes how, and whether, the key event
129/// was handled.
130typedef FocusOnKeyEventCallback = KeyEventResult Function(FocusNode node, KeyEvent event);
131
132/// Signature of a callback used by [FocusManager.addEarlyKeyEventHandler] and
133/// [FocusManager.addLateKeyEventHandler].
134///
135/// The `event` parameter is a [KeyEvent] that is being sent to the callback to
136/// be handled.
137///
138/// The [KeyEventResult] return value indicates whether or not the event will
139/// continue to be propagated. If the value returned is [KeyEventResult.handled]
140/// or [KeyEventResult.skipRemainingHandlers], then the event will not continue
141/// to be propagated.
142typedef OnKeyEventCallback = KeyEventResult Function(KeyEvent event);
143
144// Represents a pending autofocus request.
145@immutable
146class _Autofocus {
147 const _Autofocus({ required this.scope, required this.autofocusNode });
148
149 final FocusScopeNode scope;
150 final FocusNode autofocusNode;
151
152 // Applies the autofocus request, if the node is still attached to the
153 // original scope and the scope has no focused child.
154 //
155 // The widget tree is responsible for calling reparent/detach on attached
156 // nodes to keep their parent/manager information up-to-date, so here we can
157 // safely check if the scope/node involved in each autofocus request is
158 // still attached, and discard the ones which are no longer attached to the
159 // original manager.
160 void applyIfValid(FocusManager manager) {
161 final bool shouldApply = (scope.parent != null || identical(scope, manager.rootScope))
162 && identical(scope._manager, manager)
163 && scope.focusedChild == null
164 && autofocusNode.ancestors.contains(scope);
165 if (shouldApply) {
166 assert(_focusDebug(() => 'Applying autofocus: $autofocusNode'));
167 autofocusNode._doRequestFocus(findFirstFocus: true);
168 } else {
169 assert(_focusDebug(() => 'Autofocus request discarded for node: $autofocusNode.'));
170 }
171 }
172}
173
174/// An attachment point for a [FocusNode].
175///
176/// Using a [FocusAttachment] is rarely needed, unless building something
177/// akin to the [Focus] or [FocusScope] widgets from scratch.
178///
179/// Once created, a [FocusNode] must be attached to the widget tree by its
180/// _host_ [StatefulWidget] via a [FocusAttachment] object. [FocusAttachment]s
181/// are owned by the [StatefulWidget] that hosts a [FocusNode] or
182/// [FocusScopeNode]. There can be multiple [FocusAttachment]s for each
183/// [FocusNode], but the node will only ever be attached to one of them at a
184/// time.
185///
186/// This attachment is created by calling [FocusNode.attach], usually from the
187/// host widget's [State.initState] method. If the widget is updated to have a
188/// different focus node, then the new node needs to be attached in
189/// [State.didUpdateWidget], after calling [detach] on the previous
190/// [FocusAttachment]. Once detached, the attachment is defunct and will no
191/// longer make changes to the [FocusNode] through [reparent].
192///
193/// Without these attachment points, it would be possible for a focus node to
194/// simultaneously be attached to more than one part of the widget tree during
195/// the build stage.
196class FocusAttachment {
197 /// A private constructor, because [FocusAttachment]s are only to be created
198 /// by [FocusNode.attach].
199 FocusAttachment._(this._node);
200
201 // The focus node that this attachment manages an attachment for. The node may
202 // not yet have a parent, or may have been detached from this attachment, so
203 // don't count on this node being in a usable state.
204 final FocusNode _node;
205
206 /// Returns true if the associated node is attached to this attachment.
207 ///
208 /// It is possible to be attached to the widget tree, but not be placed in
209 /// the focus tree (i.e. to not have a parent yet in the focus tree).
210 bool get isAttached => _node._attachment == this;
211
212 /// Detaches the [FocusNode] this attachment point is associated with from the
213 /// focus tree, and disconnects it from this attachment point.
214 ///
215 /// Calling [FocusNode.dispose] will also automatically detach the node.
216 void detach() {
217 assert(_focusDebug(() => 'Detaching node:', () => <Object>[_node, 'With enclosing scope ${_node.enclosingScope}']));
218 if (isAttached) {
219 if (_node.hasPrimaryFocus || (_node._manager != null && _node._manager!._markedForFocus == _node)) {
220 _node.unfocus(disposition: UnfocusDisposition.previouslyFocusedChild);
221 }
222 // This node is no longer in the tree, so shouldn't send notifications anymore.
223 _node._manager?._markDetached(_node);
224 _node._parent?._removeChild(_node);
225 _node._attachment = null;
226 assert(!_node.hasPrimaryFocus, 'Node ${_node.debugLabel ?? _node} still has primary focus while being detached.');
227 assert(_node._manager?._markedForFocus != _node, 'Node ${_node.debugLabel ?? _node} still marked for focus while being detached.');
228 }
229 assert(!isAttached);
230 }
231
232 /// Ensures that the [FocusNode] attached at this attachment point has the
233 /// proper parent node, changing it if necessary.
234 ///
235 /// If given, ensures that the given [parent] node is the parent of the node
236 /// that is attached at this attachment point, changing it if necessary.
237 /// However, it is usually not necessary to supply an explicit parent, since
238 /// [reparent] will use [Focus.of] to determine the correct parent node for
239 /// the context given in [FocusNode.attach].
240 ///
241 /// If [isAttached] is false, then calling this method does nothing.
242 ///
243 /// Should be called whenever the associated widget is rebuilt in order to
244 /// maintain the focus hierarchy.
245 ///
246 /// A [StatefulWidget] that hosts a [FocusNode] should call this method on the
247 /// node it hosts during its [State.build] or [State.didChangeDependencies]
248 /// methods in case the widget is moved from one location in the tree to
249 /// another location that has a different [FocusScope] or context.
250 ///
251 /// The optional [parent] argument must be supplied when not using [Focus] and
252 /// [FocusScope] widgets to build the focus tree, or if there is a need to
253 /// supply the parent explicitly (which are both uncommon).
254 void reparent({FocusNode? parent}) {
255 if (isAttached) {
256 assert(_node.context != null);
257 parent ??= Focus.maybeOf(_node.context!, scopeOk: true);
258 parent ??= _node.context!.owner!.focusManager.rootScope;
259 parent._reparent(_node);
260 }
261 }
262}
263
264/// Describe what should happen after [FocusNode.unfocus] is called.
265///
266/// See also:
267///
268/// * [FocusNode.unfocus], which takes this as its `disposition` parameter.
269enum UnfocusDisposition {
270 /// Focus the nearest focusable enclosing scope of this node, but do not
271 /// descend to locate the leaf [FocusScopeNode.focusedChild] the way
272 /// [previouslyFocusedChild] does.
273 ///
274 /// Focusing the scope in this way clears the [FocusScopeNode.focusedChild]
275 /// history for the enclosing scope when it receives focus. Because of this,
276 /// calling a traversal method like [FocusNode.nextFocus] after unfocusing
277 /// will cause the [FocusTraversalPolicy] to pick the node it thinks should be
278 /// first in the scope.
279 ///
280 /// This is the default disposition for [FocusNode.unfocus].
281 scope,
282
283 /// Focus the previously focused child of the nearest focusable enclosing
284 /// scope of this node.
285 ///
286 /// If there is no previously focused child, then this is equivalent to
287 /// using the [scope] disposition.
288 ///
289 /// Unfocusing with this disposition will cause [FocusNode.unfocus] to walk up
290 /// the tree to the nearest focusable enclosing scope, then start to walk down
291 /// the tree, looking for a focused child at its
292 /// [FocusScopeNode.focusedChild].
293 ///
294 /// If the [FocusScopeNode.focusedChild] is a scope, then look for its
295 /// [FocusScopeNode.focusedChild], and so on, finding the leaf
296 /// [FocusScopeNode.focusedChild] that is not a scope, or, failing that, a
297 /// leaf scope that has no focused child.
298 previouslyFocusedChild,
299}
300
301/// An object that can be used by a stateful widget to obtain the keyboard focus
302/// and to handle keyboard events.
303///
304/// _Please see the [Focus] and [FocusScope] widgets, which are utility widgets
305/// that manage their own [FocusNode]s and [FocusScopeNode]s, respectively. If
306/// they aren't appropriate, [FocusNode]s can be managed directly, but doing this
307/// is rare._
308///
309/// [FocusNode]s are persistent objects that form a _focus tree_ that is a
310/// representation of the widgets in the hierarchy that are interested in focus.
311/// A focus node might need to be created if it is passed in from an ancestor of
312/// a [Focus] widget to control the focus of the children from the ancestor, or
313/// a widget might need to host one if the widget subsystem is not being used,
314/// or if the [Focus] and [FocusScope] widgets provide insufficient control.
315///
316/// [FocusNode]s are organized into _scopes_ (see [FocusScopeNode]), which form
317/// sub-trees of nodes that restrict traversal to a group of nodes. Within a
318/// scope, the most recent nodes to have focus are remembered, and if a node is
319/// focused and then unfocused, the previous node receives focus again.
320///
321/// The focus node hierarchy can be traversed using the [parent], [children],
322/// [ancestors] and [descendants] accessors.
323///
324/// [FocusNode]s are [ChangeNotifier]s, so a listener can be registered to
325/// receive a notification when the focus changes. Listeners will also be
326/// notified when [skipTraversal], [canRequestFocus], [descendantsAreFocusable],
327/// and [descendantsAreTraversable] properties are updated. If the [Focus] and
328/// [FocusScope] widgets are being used to manage the nodes, consider
329/// establishing an [InheritedWidget] dependency on them by calling [Focus.of]
330/// or [FocusScope.of] instead. [FocusNode.hasFocus] can also be used to
331/// establish a similar dependency, especially if all that is needed is to
332/// determine whether or not the widget is focused at build time.
333///
334/// To see the focus tree in the debug console, call [debugDumpFocusTree]. To
335/// get the focus tree as a string, call [debugDescribeFocusTree].
336///
337/// {@template flutter.widgets.FocusNode.lifecycle}
338/// ## Lifecycle
339///
340/// There are several actors involved in the lifecycle of a
341/// [FocusNode]/[FocusScopeNode]. They are created and disposed by their
342/// _owner_, attached, detached, and re-parented using a [FocusAttachment] by
343/// their _host_ (which must be owned by the [State] of a [StatefulWidget]), and
344/// they are managed by the [FocusManager]. Different parts of the [FocusNode]
345/// API are intended for these different actors.
346///
347/// [FocusNode]s (and hence [FocusScopeNode]s) are persistent objects that form
348/// part of a _focus tree_ that is a sparse representation of the widgets in the
349/// hierarchy that are interested in receiving keyboard events. They must be
350/// managed like other persistent state, which is typically done by a
351/// [StatefulWidget] that owns the node. A stateful widget that owns a focus
352/// scope node must call [dispose] from its [State.dispose] method.
353///
354/// Once created, a [FocusNode] must be attached to the widget tree via a
355/// [FocusAttachment] object. This attachment is created by calling [attach],
356/// usually from the [State.initState] method. If the hosting widget is updated
357/// to have a different focus node, then the updated node needs to be attached
358/// in [State.didUpdateWidget], after calling [FocusAttachment.detach] on the
359/// previous [FocusAttachment].
360///
361/// Because [FocusNode]s form a sparse representation of the widget tree, they
362/// must be updated whenever the widget tree is rebuilt. This is done by calling
363/// [FocusAttachment.reparent], usually from the [State.build] or
364/// [State.didChangeDependencies] methods of the widget that represents the
365/// focused region, so that the [BuildContext] assigned to the [FocusScopeNode]
366/// can be tracked (the context is used to obtain the [RenderObject], from which
367/// the geometry of focused regions can be determined).
368///
369/// Creating a [FocusNode] each time [State.build] is invoked will cause the
370/// focus to be lost each time the widget is built, which is usually not desired
371/// behavior (call [unfocus] if losing focus is desired).
372///
373/// If, as is common, the hosting [StatefulWidget] is also the owner of the
374/// focus node, then it will also call [dispose] from its [State.dispose] (in
375/// which case the [FocusAttachment.detach] may be skipped, since dispose will
376/// automatically detach). If another object owns the focus node, then it must
377/// call [dispose] when the node is done being used.
378/// {@endtemplate}
379///
380/// {@template flutter.widgets.FocusNode.keyEvents}
381/// ## Key Event Propagation
382///
383/// The [FocusManager] receives key events from [HardwareKeyboard] and will pass
384/// them to the focused nodes. It starts with the node with the primary focus,
385/// and will call the [onKeyEvent] callback for that node. If the callback
386/// returns [KeyEventResult.ignored], indicating that it did not handle the
387/// event, the [FocusManager] will move to the parent of that node and call its
388/// [onKeyEvent]. If that [onKeyEvent] returns [KeyEventResult.handled], then it
389/// will stop propagating the event. If it reaches the root [FocusScopeNode],
390/// [FocusManager.rootScope], the event is discarded.
391/// {@endtemplate}
392///
393/// ## Focus Traversal
394///
395/// The term _traversal_, sometimes called _tab traversal_, refers to moving the
396/// focus from one widget to the next in a particular order (also sometimes
397/// referred to as the _tab order_, since the TAB key is often bound to the
398/// action to move to the next widget).
399///
400/// To give focus to the logical _next_ or _previous_ widget in the UI, call the
401/// [nextFocus] or [previousFocus] methods. To give the focus to a widget in a
402/// particular direction, call the [focusInDirection] method.
403///
404/// The policy for what the _next_ or _previous_ widget is, or the widget in a
405/// particular direction, is determined by the [FocusTraversalPolicy] in force.
406///
407/// The ambient policy is determined by looking up the widget hierarchy for a
408/// [FocusTraversalGroup] widget, and obtaining the focus traversal policy from
409/// it. Different focus nodes can inherit difference policies, so part of the
410/// app can go in a predefined order (using [OrderedTraversalPolicy]), and part
411/// can go in reading order (using [ReadingOrderTraversalPolicy]), depending
412/// upon the use case.
413///
414/// Predefined policies include [WidgetOrderTraversalPolicy],
415/// [ReadingOrderTraversalPolicy], [OrderedTraversalPolicy], and
416/// [DirectionalFocusTraversalPolicyMixin], but custom policies can be built
417/// based upon these policies. See [FocusTraversalPolicy] for more information.
418///
419/// {@tool dartpad}
420/// This example shows how a FocusNode should be managed if not using the
421/// [Focus] or [FocusScope] widgets. See the [Focus] widget for a similar
422/// example using [Focus] and [FocusScope] widgets.
423///
424/// ** See code in examples/api/lib/widgets/focus_manager/focus_node.0.dart **
425/// {@end-tool}
426///
427/// See also:
428///
429/// * [Focus], a widget that manages a [FocusNode] and provides access to focus
430/// information and actions to its descendant widgets.
431/// * [FocusTraversalGroup], a widget used to group together and configure the
432/// focus traversal policy for a widget subtree.
433/// * [FocusManager], a singleton that manages the primary focus and distributes
434/// key events to focused nodes.
435/// * [FocusTraversalPolicy], a class used to determine how to move the focus to
436/// other nodes.
437class FocusNode with DiagnosticableTreeMixin, ChangeNotifier {
438 /// Creates a focus node.
439 ///
440 /// The [debugLabel] is ignored on release builds.
441 ///
442 /// To receive key events that focuses on this node, pass a listener to
443 /// `onKeyEvent`.
444 FocusNode({
445 String? debugLabel,
446 @Deprecated(
447 'Use onKeyEvent instead. '
448 'This feature was deprecated after v3.18.0-2.0.pre.',
449 )
450 this.onKey,
451 this.onKeyEvent,
452 bool skipTraversal = false,
453 bool canRequestFocus = true,
454 bool descendantsAreFocusable = true,
455 bool descendantsAreTraversable = true,
456 }) : _skipTraversal = skipTraversal,
457 _canRequestFocus = canRequestFocus,
458 _descendantsAreFocusable = descendantsAreFocusable,
459 _descendantsAreTraversable = descendantsAreTraversable {
460 // Set it via the setter so that it does nothing on release builds.
461 this.debugLabel = debugLabel;
462
463 if (kFlutterMemoryAllocationsEnabled) {
464 ChangeNotifier.maybeDispatchObjectCreation(this);
465 }
466 }
467
468 /// If true, tells the focus traversal policy to skip over this node for
469 /// purposes of the traversal algorithm.
470 ///
471 /// This may be used to place nodes in the focus tree that may be focused, but
472 /// not traversed, allowing them to receive key events as part of the focus
473 /// chain, but not be traversed to via focus traversal.
474 ///
475 /// This is different from [canRequestFocus] because it only implies that the
476 /// node can't be reached via traversal, not that it can't be focused. It may
477 /// still be focused explicitly.
478 bool get skipTraversal {
479 if (_skipTraversal) {
480 return true;
481 }
482 for (final FocusNode ancestor in ancestors) {
483 if (!ancestor.descendantsAreTraversable) {
484 return true;
485 }
486 }
487 return false;
488 }
489 bool _skipTraversal;
490 set skipTraversal(bool value) {
491 if (value != _skipTraversal) {
492 _skipTraversal = value;
493 _manager?._markPropertiesChanged(this);
494 }
495 }
496
497 /// If true, this focus node may request the primary focus.
498 ///
499 /// Defaults to true. Set to false if you want this node to do nothing when
500 /// [requestFocus] is called on it.
501 ///
502 /// If set to false on a [FocusScopeNode], will cause all of the children of
503 /// the scope node to not be focusable.
504 ///
505 /// If set to false on a [FocusNode], it will not affect the focusability of
506 /// children of the node.
507 ///
508 /// The [hasFocus] member can still return true if this node is the ancestor
509 /// of a node with primary focus.
510 ///
511 /// This is different than [skipTraversal] because [skipTraversal] still
512 /// allows the node to be focused, just not traversed to via the
513 /// [FocusTraversalPolicy].
514 ///
515 /// Setting [canRequestFocus] to false implies that the node will also be
516 /// skipped for traversal purposes.
517 ///
518 /// See also:
519 ///
520 /// * [FocusTraversalGroup], a widget used to group together and configure the
521 /// focus traversal policy for a widget subtree.
522 /// * [FocusTraversalPolicy], a class that can be extended to describe a
523 /// traversal policy.
524 bool get canRequestFocus => _canRequestFocus && ancestors.every(_allowDescendantsToBeFocused);
525 static bool _allowDescendantsToBeFocused(FocusNode ancestor) => ancestor.descendantsAreFocusable;
526
527 bool _canRequestFocus;
528 @mustCallSuper
529 set canRequestFocus(bool value) {
530 if (value != _canRequestFocus) {
531 // Have to set this first before unfocusing, since it checks this to cull
532 // unfocusable, previously-focused children.
533 _canRequestFocus = value;
534 if (hasFocus && !value) {
535 unfocus(disposition: UnfocusDisposition.previouslyFocusedChild);
536 }
537 _manager?._markPropertiesChanged(this);
538 }
539 }
540
541 /// If false, will disable focus for all of this node's descendants.
542 ///
543 /// Defaults to true. Does not affect focusability of this node: for that,
544 /// use [canRequestFocus].
545 ///
546 /// If any descendants are focused when this is set to false, they will be
547 /// unfocused. When [descendantsAreFocusable] is set to true again, they will
548 /// not be refocused, although they will be able to accept focus again.
549 ///
550 /// Does not affect the value of [canRequestFocus] on the descendants.
551 ///
552 /// If a descendant node loses focus when this value is changed, the focus
553 /// will move to the scope enclosing this node.
554 ///
555 /// See also:
556 ///
557 /// * [ExcludeFocus], a widget that uses this property to conditionally
558 /// exclude focus for a subtree.
559 /// * [descendantsAreTraversable], which makes this widget's descendants
560 /// untraversable.
561 /// * [ExcludeFocusTraversal], a widget that conditionally excludes focus
562 /// traversal for a subtree.
563 /// * [Focus], a widget that exposes this setting as a parameter.
564 /// * [FocusTraversalGroup], a widget used to group together and configure
565 /// the focus traversal policy for a widget subtree that also has a
566 /// `descendantsAreFocusable` parameter that prevents its children from
567 /// being focused.
568 bool get descendantsAreFocusable => _descendantsAreFocusable;
569 bool _descendantsAreFocusable;
570 @mustCallSuper
571 set descendantsAreFocusable(bool value) {
572 if (value == _descendantsAreFocusable) {
573 return;
574 }
575 // Set _descendantsAreFocusable before unfocusing, so the scope won't try
576 // and focus any of the children here again if it is false.
577 _descendantsAreFocusable = value;
578 if (!value && hasFocus) {
579 unfocus(disposition: UnfocusDisposition.previouslyFocusedChild);
580 }
581 _manager?._markPropertiesChanged(this);
582 }
583
584 /// If false, tells the focus traversal policy to skip over for all of this
585 /// node's descendants for purposes of the traversal algorithm.
586 ///
587 /// Defaults to true. Does not affect the focus traversal of this node: for
588 /// that, use [skipTraversal].
589 ///
590 /// Does not affect the value of [FocusNode.skipTraversal] on the
591 /// descendants. Does not affect focusability of the descendants.
592 ///
593 /// See also:
594 ///
595 /// * [ExcludeFocusTraversal], a widget that uses this property to conditionally
596 /// exclude focus traversal for a subtree.
597 /// * [descendantsAreFocusable], which makes this widget's descendants
598 /// unfocusable.
599 /// * [ExcludeFocus], a widget that conditionally excludes focus for a subtree.
600 /// * [FocusTraversalGroup], a widget used to group together and configure
601 /// the focus traversal policy for a widget subtree that also has an
602 /// `descendantsAreFocusable` parameter that prevents its children from
603 /// being focused.
604 bool get descendantsAreTraversable => _descendantsAreTraversable;
605 bool _descendantsAreTraversable;
606 @mustCallSuper
607 set descendantsAreTraversable(bool value) {
608 if (value != _descendantsAreTraversable) {
609 _descendantsAreTraversable = value;
610 _manager?._markPropertiesChanged(this);
611 }
612 }
613
614 /// The context that was supplied to [attach].
615 ///
616 /// This is typically the context for the widget that is being focused, as it
617 /// is used to determine the bounds of the widget.
618 BuildContext? get context => _context;
619 BuildContext? _context;
620
621 /// Called if this focus node receives a key event while focused (i.e. when
622 /// [hasFocus] returns true).
623 ///
624 /// This property is deprecated and will be removed at a future date. Use
625 /// [onKeyEvent] instead.
626 ///
627 /// This is a legacy API based on [RawKeyEvent] and will be deprecated in the
628 /// future. Prefer [onKeyEvent] instead.
629 ///
630 /// {@macro flutter.widgets.FocusNode.keyEvents}
631 @Deprecated(
632 'Use onKeyEvent instead. '
633 'This feature was deprecated after v3.18.0-2.0.pre.',
634 )
635 FocusOnKeyCallback? onKey;
636
637 /// Called if this focus node receives a key event while focused (i.e. when
638 /// [hasFocus] returns true).
639 ///
640 /// {@macro flutter.widgets.FocusNode.keyEvents}
641 FocusOnKeyEventCallback? onKeyEvent;
642
643 FocusManager? _manager;
644 List<FocusNode>? _ancestors;
645 List<FocusNode>? _descendants;
646 bool _hasKeyboardToken = false;
647
648 /// Returns the parent node for this object.
649 ///
650 /// All nodes except for the root [FocusScopeNode] ([FocusManager.rootScope])
651 /// will be given a parent when they are added to the focus tree, which is
652 /// done using [FocusAttachment.reparent].
653 FocusNode? get parent => _parent;
654 FocusNode? _parent;
655
656 /// An iterator over the children of this node.
657 Iterable<FocusNode> get children => _children;
658 final List<FocusNode> _children = <FocusNode>[];
659
660 /// An iterator over the children that are allowed to be traversed by the
661 /// [FocusTraversalPolicy].
662 ///
663 /// Returns the list of focusable, traversable children of this node,
664 /// regardless of those settings on this focus node. Will return an empty
665 /// iterable if [descendantsAreFocusable] is false.
666 ///
667 /// See also
668 ///
669 /// * [traversalDescendants], which traverses all of the node's descendants,
670 /// not just the immediate children.
671 Iterable<FocusNode> get traversalChildren {
672 if (!descendantsAreFocusable) {
673 return const Iterable<FocusNode>.empty();
674 }
675 return children.where(
676 (FocusNode node) => !node.skipTraversal && node.canRequestFocus,
677 );
678 }
679
680 /// A debug label that is used for diagnostic output.
681 ///
682 /// Will always return null in release builds.
683 String? get debugLabel => _debugLabel;
684 String? _debugLabel;
685 set debugLabel(String? value) {
686 assert(() {
687 // Only set the value in debug builds.
688 _debugLabel = value;
689 return true;
690 }());
691 }
692
693 FocusAttachment? _attachment;
694
695 /// An [Iterable] over the hierarchy of children below this one, in
696 /// depth-first order.
697 Iterable<FocusNode> get descendants {
698 if (_descendants == null) {
699 final List<FocusNode> result = <FocusNode>[];
700 for (final FocusNode child in _children) {
701 result.addAll(child.descendants);
702 result.add(child);
703 }
704 _descendants = result;
705 }
706 return _descendants!;
707 }
708
709 /// Returns all descendants which do not have the [skipTraversal] and do have
710 /// the [canRequestFocus] flag set.
711 Iterable<FocusNode> get traversalDescendants {
712 if (!descendantsAreFocusable) {
713 return const Iterable<FocusNode>.empty();
714 }
715 return descendants.where((FocusNode node) => !node.skipTraversal && node.canRequestFocus);
716 }
717
718 /// An [Iterable] over the ancestors of this node.
719 ///
720 /// Iterates the ancestors of this node starting at the parent and iterating
721 /// over successively more remote ancestors of this node, ending at the root
722 /// [FocusScopeNode] ([FocusManager.rootScope]).
723 Iterable<FocusNode> get ancestors {
724 if (_ancestors == null) {
725 final List<FocusNode> result = <FocusNode>[];
726 FocusNode? parent = _parent;
727 while (parent != null) {
728 result.add(parent);
729 parent = parent._parent;
730 }
731 _ancestors = result;
732 }
733 return _ancestors!;
734 }
735
736 /// Whether this node has input focus.
737 ///
738 /// A [FocusNode] has focus when it is an ancestor of a node that returns true
739 /// from [hasPrimaryFocus], or it has the primary focus itself.
740 ///
741 /// The [hasFocus] accessor is different from [hasPrimaryFocus] in that
742 /// [hasFocus] is true if the node is anywhere in the focus chain, but for
743 /// [hasPrimaryFocus] the node must to be at the end of the chain to return
744 /// true.
745 ///
746 /// A node that returns true for [hasFocus] will receive key events if none of
747 /// its focused descendants returned true from their [onKey] handler.
748 ///
749 /// This object is a [ChangeNotifier], and notifies its [Listenable] listeners
750 /// (registered via [addListener]) whenever this value changes.
751 ///
752 /// See also:
753 ///
754 /// * [Focus.isAt], which is a static method that will return the focus
755 /// state of the nearest ancestor [Focus] widget's focus node.
756 bool get hasFocus => hasPrimaryFocus || (_manager?.primaryFocus?.ancestors.contains(this) ?? false);
757
758 /// Returns true if this node currently has the application-wide input focus.
759 ///
760 /// A [FocusNode] has the primary focus when the node is focused in its
761 /// nearest ancestor [FocusScopeNode] and [hasFocus] is true for all its
762 /// ancestor nodes, but none of its descendants.
763 ///
764 /// This is different from [hasFocus] in that [hasFocus] is true if the node
765 /// is anywhere in the focus chain, but here the node has to be at the end of
766 /// the chain to return true.
767 ///
768 /// A node that returns true for [hasPrimaryFocus] will be the first node to
769 /// receive key events through its [onKey] handler.
770 ///
771 /// This object notifies its listeners whenever this value changes.
772 bool get hasPrimaryFocus => _manager?.primaryFocus == this;
773
774 /// Returns the [FocusHighlightMode] that is currently in effect for this node.
775 FocusHighlightMode get highlightMode => FocusManager.instance.highlightMode;
776
777 /// Returns the nearest enclosing scope node above this node, including
778 /// this node, if it's a scope.
779 ///
780 /// Returns null if no scope is found.
781 ///
782 /// Use [enclosingScope] to look for scopes above this node.
783 FocusScopeNode? get nearestScope => enclosingScope;
784
785 FocusScopeNode? _enclosingScope;
786 void _clearEnclosingScopeCache() {
787 final FocusScopeNode? cachedScope = _enclosingScope;
788 if (cachedScope == null) {
789 return;
790 }
791 _enclosingScope = null;
792 if (children.isNotEmpty) {
793 for (final FocusNode child in children) {
794 if (identical(cachedScope, child._enclosingScope)) {
795 child._clearEnclosingScopeCache();
796 }
797 }
798 }
799 }
800
801 /// Returns the nearest enclosing scope node above this node, or null if the
802 /// node has not yet be added to the focus tree.
803 ///
804 /// If this node is itself a scope, this will only return ancestors of this
805 /// scope.
806 ///
807 /// Use [nearestScope] to start at this node instead of above it.
808 FocusScopeNode? get enclosingScope {
809 final FocusScopeNode? enclosingScope = _enclosingScope ??= parent?.nearestScope;
810 assert(enclosingScope == parent?.nearestScope, '$this has invalid scope cache: $_enclosingScope != ${parent?.nearestScope}');
811 return enclosingScope;
812 }
813
814 /// Returns the size of the attached widget's [RenderObject], in logical
815 /// units.
816 ///
817 /// Size is the size of the transformed widget in global coordinates.
818 Size get size => rect.size;
819
820 /// Returns the global offset to the upper left corner of the attached
821 /// widget's [RenderObject], in logical units.
822 ///
823 /// Offset is the offset of the transformed widget in global coordinates.
824 Offset get offset {
825 assert(
826 context != null,
827 "Tried to get the offset of a focus node that didn't have its context set yet.\n"
828 'The context needs to be set before trying to evaluate traversal policies. '
829 'Setting the context is typically done with the attach method.',
830 );
831 final RenderObject object = context!.findRenderObject()!;
832 return MatrixUtils.transformPoint(object.getTransformTo(null), object.semanticBounds.topLeft);
833 }
834
835 /// Returns the global rectangle of the attached widget's [RenderObject], in
836 /// logical units.
837 ///
838 /// Rect is the rectangle of the transformed widget in global coordinates.
839 Rect get rect {
840 assert(
841 context != null,
842 "Tried to get the bounds of a focus node that didn't have its context set yet.\n"
843 'The context needs to be set before trying to evaluate traversal policies. '
844 'Setting the context is typically done with the attach method.',
845 );
846 final RenderObject object = context!.findRenderObject()!;
847 final Offset topLeft = MatrixUtils.transformPoint(object.getTransformTo(null), object.semanticBounds.topLeft);
848 final Offset bottomRight = MatrixUtils.transformPoint(object.getTransformTo(null), object.semanticBounds.bottomRight);
849 return Rect.fromLTRB(topLeft.dx, topLeft.dy, bottomRight.dx, bottomRight.dy);
850 }
851
852 /// Removes the focus on this node by moving the primary focus to another node.
853 ///
854 /// This method removes focus from a node that has the primary focus, cancels
855 /// any outstanding requests to focus it, while setting the primary focus to
856 /// another node according to the `disposition`.
857 ///
858 /// It is safe to call regardless of whether this node has ever requested
859 /// focus or not. If this node doesn't have focus or primary focus, nothing
860 /// happens.
861 ///
862 /// The `disposition` argument determines which node will receive primary
863 /// focus after this one loses it.
864 ///
865 /// If `disposition` is set to [UnfocusDisposition.scope] (the default), then
866 /// the previously focused node history of the enclosing scope will be
867 /// cleared, and the primary focus will be moved to the nearest enclosing
868 /// scope ancestor that is enabled for focus, ignoring the
869 /// [FocusScopeNode.focusedChild] for that scope.
870 ///
871 /// If `disposition` is set to [UnfocusDisposition.previouslyFocusedChild],
872 /// then this node will be removed from the previously focused list in the
873 /// [enclosingScope], and the focus will be moved to the previously focused
874 /// node of the [enclosingScope], which (if it is a scope itself), will find
875 /// its focused child, etc., until a leaf focus node is found. If there is no
876 /// previously focused child, then the scope itself will receive focus, as if
877 /// [UnfocusDisposition.scope] were specified.
878 ///
879 /// If you want this node to lose focus and the focus to move to the next or
880 /// previous node in the enclosing [FocusTraversalGroup], call [nextFocus] or
881 /// [previousFocus] instead of calling [unfocus].
882 ///
883 /// {@tool dartpad}
884 /// This example shows the difference between the different [UnfocusDisposition]
885 /// values for [unfocus].
886 ///
887 /// Try setting focus on the four text fields by selecting them, and then
888 /// select "UNFOCUS" to see what happens when the current
889 /// [FocusManager.primaryFocus] is unfocused.
890 ///
891 /// Try pressing the TAB key after unfocusing to see what the next widget
892 /// chosen is.
893 ///
894 /// ** See code in examples/api/lib/widgets/focus_manager/focus_node.unfocus.0.dart **
895 /// {@end-tool}
896 void unfocus({
897 UnfocusDisposition disposition = UnfocusDisposition.scope,
898 }) {
899 if (!hasFocus && (_manager == null || _manager!._markedForFocus != this)) {
900 return;
901 }
902 FocusScopeNode? scope = enclosingScope;
903 if (scope == null) {
904 // If the scope is null, then this is either the root node, or a node that
905 // is not yet in the tree, neither of which do anything when unfocused.
906 return;
907 }
908 switch (disposition) {
909 case UnfocusDisposition.scope:
910 // If it can't request focus, then don't modify its focused children.
911 if (scope.canRequestFocus) {
912 // Clearing the focused children here prevents re-focusing the node
913 // that we just unfocused if we immediately hit "next" after
914 // unfocusing, and also prevents choosing to refocus the next-to-last
915 // focused child if unfocus is called more than once.
916 scope._focusedChildren.clear();
917 }
918
919 while (!scope!.canRequestFocus) {
920 scope = scope.enclosingScope ?? _manager?.rootScope;
921 }
922 scope._doRequestFocus(findFirstFocus: false);
923 case UnfocusDisposition.previouslyFocusedChild:
924 // Select the most recent focused child from the nearest focusable scope
925 // and focus that. If there isn't one, focus the scope itself.
926 if (scope.canRequestFocus) {
927 scope._focusedChildren.remove(this);
928 }
929 while (!scope!.canRequestFocus) {
930 scope.enclosingScope?._focusedChildren.remove(scope);
931 scope = scope.enclosingScope ?? _manager?.rootScope;
932 }
933 scope._doRequestFocus(findFirstFocus: true);
934 }
935 assert(_focusDebug(() => 'Unfocused node:', () => <Object>['primary focus was $this', 'next focus will be ${_manager?._markedForFocus}']));
936 }
937
938 /// Removes the keyboard token from this focus node if it has one.
939 ///
940 /// This mechanism helps distinguish between an input control gaining focus by
941 /// default and gaining focus as a result of an explicit user action.
942 ///
943 /// When a focus node requests the focus (either via
944 /// [FocusScopeNode.requestFocus] or [FocusScopeNode.autofocus]), the focus
945 /// node receives a keyboard token if it does not already have one. Later,
946 /// when the focus node becomes focused, the widget that manages the
947 /// [TextInputConnection] should show the keyboard (i.e. call
948 /// [TextInputConnection.show]) only if it successfully consumes the keyboard
949 /// token from the focus node.
950 ///
951 /// Returns true if this method successfully consumes the keyboard token.
952 bool consumeKeyboardToken() {
953 if (!_hasKeyboardToken) {
954 return false;
955 }
956 _hasKeyboardToken = false;
957 return true;
958 }
959
960 // Marks the node as being the next to be focused, meaning that it will become
961 // the primary focus and notify listeners of a focus change the next time
962 // focus is resolved by the manager. If something else calls _markNextFocus
963 // before then, then that node will become the next focus instead of the
964 // previous one.
965 void _markNextFocus(FocusNode newFocus) {
966 if (_manager != null) {
967 // If we have a manager, then let it handle the focus change.
968 _manager!._markNextFocus(this);
969 return;
970 }
971 // If we don't have a manager, then change the focus locally.
972 newFocus._setAsFocusedChildForScope();
973 newFocus._notify();
974 if (newFocus != this) {
975 _notify();
976 }
977 }
978
979 // Removes the given FocusNode and its children as a child of this node.
980 @mustCallSuper
981 void _removeChild(FocusNode node, {bool removeScopeFocus = true}) {
982 assert(_children.contains(node), "Tried to remove a node that wasn't a child.");
983 assert(node._parent == this);
984 assert(node._manager == _manager);
985
986 if (removeScopeFocus) {
987 final FocusScopeNode? nodeScope = node.enclosingScope;
988 if (nodeScope != null) {
989 nodeScope._focusedChildren.remove(node);
990 node.descendants.where((FocusNode descendant) {
991 return descendant.enclosingScope == nodeScope;
992 }).forEach(nodeScope._focusedChildren.remove);
993 }
994 }
995
996 node._parent = null;
997 node._clearEnclosingScopeCache();
998 _children.remove(node);
999 for (final FocusNode ancestor in ancestors) {
1000 ancestor._descendants = null;
1001 }
1002 _descendants = null;
1003 assert(_manager == null || !_manager!.rootScope.descendants.contains(node));
1004 }
1005
1006 void _updateManager(FocusManager? manager) {
1007 _manager = manager;
1008 for (final FocusNode descendant in descendants) {
1009 descendant._manager = manager;
1010 descendant._ancestors = null;
1011 }
1012 }
1013
1014 // Used by FocusAttachment.reparent to perform the actual parenting operation.
1015 @mustCallSuper
1016 void _reparent(FocusNode child) {
1017 assert(child != this, 'Tried to make a child into a parent of itself.');
1018 if (child._parent == this) {
1019 assert(_children.contains(child), "Found a node that says it's a child, but doesn't appear in the child list.");
1020 // The child is already a child of this parent.
1021 return;
1022 }
1023 assert(_manager == null || child != _manager!.rootScope, "Reparenting the root node isn't allowed.");
1024 assert(!ancestors.contains(child), 'The supplied child is already an ancestor of this node. Loops are not allowed.');
1025 final FocusScopeNode? oldScope = child.enclosingScope;
1026 final bool hadFocus = child.hasFocus;
1027 child._parent?._removeChild(child, removeScopeFocus: oldScope != nearestScope);
1028 _children.add(child);
1029 child._parent = this;
1030 child._ancestors = null;
1031 child._updateManager(_manager);
1032 for (final FocusNode ancestor in child.ancestors) {
1033 ancestor._descendants = null;
1034 }
1035 if (hadFocus) {
1036 // Update the focus chain for the current focus without changing it.
1037 _manager?.primaryFocus?._setAsFocusedChildForScope();
1038 }
1039 if (oldScope != null && child.context != null && child.enclosingScope != oldScope) {
1040 FocusTraversalGroup.maybeOf(child.context!)?.changedScope(node: child, oldScope: oldScope);
1041 }
1042 if (child._requestFocusWhenReparented) {
1043 child._doRequestFocus(findFirstFocus: true);
1044 child._requestFocusWhenReparented = false;
1045 }
1046 }
1047
1048 /// Called by the _host_ [StatefulWidget] to attach a [FocusNode] to the
1049 /// widget tree.
1050 ///
1051 /// In order to attach a [FocusNode] to the widget tree, call [attach],
1052 /// typically from the [StatefulWidget]'s [State.initState] method.
1053 ///
1054 /// If the focus node in the host widget is swapped out, the new node will
1055 /// need to be attached. [FocusAttachment.detach] should be called on the old
1056 /// node, and then [attach] called on the new node. This typically happens in
1057 /// the [State.didUpdateWidget] method.
1058 ///
1059 /// To receive key events that focuses on this node, pass a listener to
1060 /// `onKeyEvent`.
1061 @mustCallSuper
1062 FocusAttachment attach(
1063 BuildContext? context, {
1064 FocusOnKeyEventCallback? onKeyEvent,
1065 @Deprecated(
1066 'Use onKeyEvent instead. '
1067 'This feature was deprecated after v3.18.0-2.0.pre.',
1068 )
1069 FocusOnKeyCallback? onKey,
1070 }) {
1071 _context = context;
1072 this.onKey = onKey ?? this.onKey;
1073 this.onKeyEvent = onKeyEvent ?? this.onKeyEvent;
1074 _attachment = FocusAttachment._(this);
1075 return _attachment!;
1076 }
1077
1078 @override
1079 void dispose() {
1080 // Detaching will also unfocus and clean up the manager's data structures.
1081 _attachment?.detach();
1082 super.dispose();
1083 }
1084
1085 @mustCallSuper
1086 void _notify() {
1087 if (_parent == null) {
1088 // no longer part of the tree, so don't notify.
1089 return;
1090 }
1091 if (hasPrimaryFocus) {
1092 _setAsFocusedChildForScope();
1093 }
1094 notifyListeners();
1095 }
1096
1097 /// Requests the primary focus for this node, or for a supplied [node], which
1098 /// will also give focus to its [ancestors].
1099 ///
1100 /// If called without a node, request focus for this node. If the node hasn't
1101 /// been added to the focus tree yet, then defer the focus request until it
1102 /// is, allowing newly created widgets to request focus as soon as they are
1103 /// added.
1104 ///
1105 /// If the given [node] is not yet a part of the focus tree, then this method
1106 /// will add the [node] as a child of this node before requesting focus.
1107 ///
1108 /// If the given [node] is a [FocusScopeNode] and that focus scope node has a
1109 /// non-null [FocusScopeNode.focusedChild], then request the focus for the
1110 /// focused child. This process is recursive and continues until it encounters
1111 /// either a focus scope node with a null focused child or an ordinary
1112 /// (non-scope) [FocusNode] is found.
1113 ///
1114 /// The node is notified that it has received the primary focus in a
1115 /// microtask, so notification may lag the request by up to one frame.
1116 void requestFocus([FocusNode? node]) {
1117 if (node != null) {
1118 if (node._parent == null) {
1119 _reparent(node);
1120 }
1121 assert(node.ancestors.contains(this), 'Focus was requested for a node that is not a descendant of the scope from which it was requested.');
1122 node._doRequestFocus(findFirstFocus: true);
1123 return;
1124 }
1125 _doRequestFocus(findFirstFocus: true);
1126 }
1127
1128 // This is overridden in FocusScopeNode.
1129 void _doRequestFocus({required bool findFirstFocus}) {
1130 if (!canRequestFocus) {
1131 assert(_focusDebug(() => 'Node NOT requesting focus because canRequestFocus is false: $this'));
1132 return;
1133 }
1134 // If the node isn't part of the tree, then we just defer the focus request
1135 // until the next time it is reparented, so that it's possible to focus
1136 // newly added widgets.
1137 if (_parent == null) {
1138 _requestFocusWhenReparented = true;
1139 return;
1140 }
1141 _setAsFocusedChildForScope();
1142 if (hasPrimaryFocus && (_manager!._markedForFocus == null || _manager!._markedForFocus == this)) {
1143 return;
1144 }
1145 _hasKeyboardToken = true;
1146 assert(_focusDebug(() => 'Node requesting focus: $this'));
1147 _markNextFocus(this);
1148 }
1149
1150 // If set to true, the node will request focus on this node the next time
1151 // this node is reparented in the focus tree.
1152 //
1153 // Once requestFocus has been called at the next reparenting, this value
1154 // will be reset to false.
1155 //
1156 // This will only force a call to requestFocus for the node once the next time
1157 // the node is reparented. After that, _requestFocusWhenReparented would need
1158 // to be set to true again to have it be focused again on the next
1159 // reparenting.
1160 //
1161 // This is used when requestFocus is called and there is no parent yet.
1162 bool _requestFocusWhenReparented = false;
1163
1164 /// Sets this node as the [FocusScopeNode.focusedChild] of the enclosing
1165 /// scope.
1166 ///
1167 /// Sets this node as the focused child for the enclosing scope, and that
1168 /// scope as the focused child for the scope above it, etc., until it reaches
1169 /// the root node. It doesn't change the primary focus, it just changes what
1170 /// node would be focused if the enclosing scope receives focus, and keeps
1171 /// track of previously focused children in that scope, so that if the focused
1172 /// child in that scope is removed, the previous focus returns.
1173 void _setAsFocusedChildForScope() {
1174 FocusNode scopeFocus = this;
1175 for (final FocusScopeNode ancestor in ancestors.whereType<FocusScopeNode>()) {
1176 assert(scopeFocus != ancestor, 'Somehow made a loop by setting focusedChild to its scope.');
1177 assert(_focusDebug(() => 'Setting $scopeFocus as focused child for scope:', () => <Object>[ancestor]));
1178 // Remove it anywhere in the focused child history.
1179 ancestor._focusedChildren.remove(scopeFocus);
1180 // Add it to the end of the list, which is also the top of the queue: The
1181 // end of the list represents the currently focused child.
1182 ancestor._focusedChildren.add(scopeFocus);
1183 scopeFocus = ancestor;
1184 }
1185 }
1186
1187 /// Request to move the focus to the next focus node, by calling the
1188 /// [FocusTraversalPolicy.next] method.
1189 ///
1190 /// Returns true if it successfully found a node and requested focus.
1191 bool nextFocus() => FocusTraversalGroup.of(context!).next(this);
1192
1193 /// Request to move the focus to the previous focus node, by calling the
1194 /// [FocusTraversalPolicy.previous] method.
1195 ///
1196 /// Returns true if it successfully found a node and requested focus.
1197 bool previousFocus() => FocusTraversalGroup.of(context!).previous(this);
1198
1199 /// Request to move the focus to the nearest focus node in the given
1200 /// direction, by calling the [FocusTraversalPolicy.inDirection] method.
1201 ///
1202 /// Returns true if it successfully found a node and requested focus.
1203 bool focusInDirection(TraversalDirection direction) => FocusTraversalGroup.of(context!).inDirection(this, direction);
1204
1205 @override
1206 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
1207 super.debugFillProperties(properties);
1208 properties.add(DiagnosticsProperty<BuildContext>('context', context, defaultValue: null));
1209 properties.add(FlagProperty('descendantsAreFocusable', value: descendantsAreFocusable, ifFalse: 'DESCENDANTS UNFOCUSABLE', defaultValue: true));
1210 properties.add(FlagProperty('descendantsAreTraversable', value: descendantsAreTraversable, ifFalse: 'DESCENDANTS UNTRAVERSABLE', defaultValue: true));
1211 properties.add(FlagProperty('canRequestFocus', value: canRequestFocus, ifFalse: 'NOT FOCUSABLE', defaultValue: true));
1212 properties.add(FlagProperty('hasFocus', value: hasFocus && !hasPrimaryFocus, ifTrue: 'IN FOCUS PATH', defaultValue: false));
1213 properties.add(FlagProperty('hasPrimaryFocus', value: hasPrimaryFocus, ifTrue: 'PRIMARY FOCUS', defaultValue: false));
1214 }
1215
1216 @override
1217 List<DiagnosticsNode> debugDescribeChildren() {
1218 int count = 1;
1219 return _children.map<DiagnosticsNode>((FocusNode child) {
1220 return child.toDiagnosticsNode(name: 'Child ${count++}');
1221 }).toList();
1222 }
1223
1224 @override
1225 String toStringShort() {
1226 final bool hasDebugLabel = debugLabel != null && debugLabel!.isNotEmpty;
1227 final String extraData = '${hasDebugLabel ? debugLabel : ''}'
1228 '${hasFocus && hasDebugLabel ? ' ' : ''}'
1229 '${hasFocus && !hasPrimaryFocus ? '[IN FOCUS PATH]' : ''}'
1230 '${hasPrimaryFocus ? '[PRIMARY FOCUS]' : ''}';
1231 return '${describeIdentity(this)}${extraData.isNotEmpty ? '($extraData)' : ''}';
1232 }
1233}
1234
1235/// A subclass of [FocusNode] that acts as a scope for its descendants,
1236/// maintaining information about which descendant is currently or was last
1237/// focused.
1238///
1239/// _Please see the [FocusScope] and [Focus] widgets, which are utility widgets
1240/// that manage their own [FocusScopeNode]s and [FocusNode]s, respectively. If
1241/// they aren't appropriate, [FocusScopeNode]s can be managed directly._
1242///
1243/// [FocusScopeNode] organizes [FocusNode]s into _scopes_. Scopes form sub-trees
1244/// of nodes that can be traversed as a group. Within a scope, the most recent
1245/// nodes to have focus are remembered, and if a node is focused and then
1246/// removed, the original node receives focus again.
1247///
1248/// From a [FocusScopeNode], calling [setFirstFocus], sets the given focus scope
1249/// as the [focusedChild] of this node, adopting if it isn't already part of the
1250/// focus tree.
1251///
1252/// {@macro flutter.widgets.FocusNode.lifecycle}
1253/// {@macro flutter.widgets.FocusNode.keyEvents}
1254///
1255/// See also:
1256///
1257/// * [Focus], a widget that manages a [FocusNode] and provides access to focus
1258/// information and actions to its descendant widgets.
1259/// * [FocusManager], a singleton that manages the primary focus and
1260/// distributes key events to focused nodes.
1261class FocusScopeNode extends FocusNode {
1262 /// Creates a [FocusScopeNode].
1263 ///
1264 /// All parameters are optional.
1265 FocusScopeNode({
1266 super.debugLabel,
1267 super.onKeyEvent,
1268 @Deprecated(
1269 'Use onKeyEvent instead. '
1270 'This feature was deprecated after v3.18.0-2.0.pre.',
1271 )
1272 super.onKey,
1273 super.skipTraversal,
1274 super.canRequestFocus,
1275 this.traversalEdgeBehavior = TraversalEdgeBehavior.closedLoop,
1276 }) : super(descendantsAreFocusable: true);
1277
1278 @override
1279 FocusScopeNode get nearestScope => this;
1280
1281 @override
1282 bool get descendantsAreFocusable => _canRequestFocus && super.descendantsAreFocusable;
1283
1284 /// Controls the transfer of focus beyond the first and the last items of a
1285 /// [FocusScopeNode].
1286 ///
1287 /// Changing this field value has no immediate effect on the UI. Instead, next time
1288 /// focus traversal takes place [FocusTraversalPolicy] will read this value
1289 /// and apply the new behavior.
1290 TraversalEdgeBehavior traversalEdgeBehavior;
1291
1292 /// Returns true if this scope is the focused child of its parent scope.
1293 bool get isFirstFocus => enclosingScope!.focusedChild == this;
1294
1295 /// Returns the child of this node that should receive focus if this scope
1296 /// node receives focus.
1297 ///
1298 /// If [hasFocus] is true, then this points to the child of this node that is
1299 /// currently focused.
1300 ///
1301 /// Returns null if there is no currently focused child.
1302 FocusNode? get focusedChild {
1303 assert(_focusedChildren.isEmpty || _focusedChildren.last.enclosingScope == this,
1304 '$debugLabel: Focused child does not have the same idea of its enclosing scope '
1305 '(${_focusedChildren.lastOrNull?.enclosingScope}) as the scope does.');
1306 return _focusedChildren.lastOrNull;
1307 }
1308
1309 // A stack of the children that have been set as the focusedChild, most recent
1310 // last (which is the top of the stack).
1311 final List<FocusNode> _focusedChildren = <FocusNode>[];
1312
1313 /// An iterator over the children that are allowed to be traversed by the
1314 /// [FocusTraversalPolicy].
1315 ///
1316 /// Will return an empty iterable if this scope node is not focusable, or if
1317 /// [descendantsAreFocusable] is false.
1318 ///
1319 /// See also:
1320 ///
1321 /// * [traversalDescendants], which traverses all of the node's descendants,
1322 /// not just the immediate children.
1323 @override
1324 Iterable<FocusNode> get traversalChildren {
1325 if (!canRequestFocus) {
1326 return const Iterable<FocusNode>.empty();
1327 }
1328 return super.traversalChildren;
1329 }
1330
1331 /// Returns all descendants which do not have the [skipTraversal] and do have
1332 /// the [canRequestFocus] flag set.
1333 ///
1334 /// Will return an empty iterable if this scope node is not focusable, or if
1335 /// [descendantsAreFocusable] is false.
1336 @override
1337 Iterable<FocusNode> get traversalDescendants {
1338 if (!canRequestFocus) {
1339 return const Iterable<FocusNode>.empty();
1340 }
1341 return super.traversalDescendants;
1342 }
1343
1344 /// Make the given [scope] the active child scope for this scope.
1345 ///
1346 /// If the given [scope] is not yet a part of the focus tree, then add it to
1347 /// the tree as a child of this scope. If it is already part of the focus
1348 /// tree, the given scope must be a descendant of this scope.
1349 void setFirstFocus(FocusScopeNode scope) {
1350 assert(scope != this, 'Unexpected self-reference in setFirstFocus.');
1351 assert(_focusDebug(() => 'Setting scope as first focus in $this to node:', () => <Object>[scope]));
1352 if (scope._parent == null) {
1353 _reparent(scope);
1354 }
1355 assert(scope.ancestors.contains(this), '$FocusScopeNode $scope must be a child of $this to set it as first focus.');
1356 if (hasFocus) {
1357 scope._doRequestFocus(findFirstFocus: true);
1358 } else {
1359 scope._setAsFocusedChildForScope();
1360 }
1361 }
1362
1363 /// If this scope lacks a focus, request that the given node become the focus.
1364 ///
1365 /// If the given node is not yet part of the focus tree, then add it as a
1366 /// child of this node.
1367 ///
1368 /// Useful for widgets that wish to grab the focus if no other widget already
1369 /// has the focus.
1370 ///
1371 /// The node is notified that it has received the primary focus in a
1372 /// microtask, so notification may lag the request by up to one frame.
1373 void autofocus(FocusNode node) {
1374 // Attach the node to the tree first, so in _applyFocusChange if the node
1375 // is detached we don't add it back to the tree.
1376 if (node._parent == null) {
1377 _reparent(node);
1378 }
1379
1380 assert(_manager != null);
1381 assert(_focusDebug(() => 'Autofocus scheduled for $node: scope $this'));
1382 _manager?._pendingAutofocuses.add(_Autofocus(scope: this, autofocusNode: node));
1383 _manager?._markNeedsUpdate();
1384 }
1385
1386 /// Requests that the scope itself receive focus, without trying to find
1387 /// a descendant that should receive focus.
1388 ///
1389 /// This is used only if you want to park the focus on a scope itself.
1390 void requestScopeFocus() {
1391 _doRequestFocus(findFirstFocus: false);
1392 }
1393
1394 @override
1395 void _doRequestFocus({required bool findFirstFocus}) {
1396 // It is possible that a previously focused child is no longer focusable, so
1397 // clean out the list if so.
1398 while (_focusedChildren.isNotEmpty &&
1399 (!_focusedChildren.last.canRequestFocus || _focusedChildren.last.enclosingScope == null)) {
1400 _focusedChildren.removeLast();
1401 }
1402
1403 final FocusNode? focusedChild = this.focusedChild;
1404 // If findFirstFocus is false, then the request is to make this scope the
1405 // focus instead of looking for the ultimate first focus for this scope and
1406 // its descendants.
1407 if (!findFirstFocus || focusedChild == null) {
1408 if (canRequestFocus) {
1409 _setAsFocusedChildForScope();
1410 _markNextFocus(this);
1411 }
1412 return;
1413 }
1414
1415 focusedChild._doRequestFocus(findFirstFocus: true);
1416 }
1417
1418 @override
1419 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
1420 super.debugFillProperties(properties);
1421 if (_focusedChildren.isEmpty) {
1422 return;
1423 }
1424 final List<String> childList = _focusedChildren.reversed.map<String>((FocusNode child) {
1425 return child.toStringShort();
1426 }).toList();
1427 properties.add(IterableProperty<String>('focusedChildren', childList, defaultValue: const Iterable<String>.empty()));
1428 properties.add(DiagnosticsProperty<TraversalEdgeBehavior>('traversalEdgeBehavior', traversalEdgeBehavior, defaultValue: TraversalEdgeBehavior.closedLoop));
1429 }
1430}
1431
1432/// An enum to describe which kind of focus highlight behavior to use when
1433/// displaying focus information.
1434enum FocusHighlightMode {
1435 /// Touch interfaces will not show the focus highlight except for controls
1436 /// which bring up the soft keyboard.
1437 ///
1438 /// If a device that uses a traditional mouse and keyboard has a touch screen
1439 /// attached, it can also enter `touch` mode if the user is using the touch
1440 /// screen.
1441 touch,
1442
1443 /// Traditional interfaces (keyboard and mouse) will show the currently
1444 /// focused control via a focus highlight of some sort.
1445 ///
1446 /// If a touch device (like a mobile phone) has a keyboard and/or mouse
1447 /// attached, it also can enter `traditional` mode if the user is using these
1448 /// input devices.
1449 traditional,
1450}
1451
1452/// An enum to describe how the current value of [FocusManager.highlightMode] is
1453/// determined. The strategy is set on [FocusManager.highlightStrategy].
1454enum FocusHighlightStrategy {
1455 /// Automatic switches between the various highlight modes based on the last
1456 /// kind of input that was received. This is the default.
1457 automatic,
1458
1459 /// [FocusManager.highlightMode] always returns [FocusHighlightMode.touch].
1460 alwaysTouch,
1461
1462 /// [FocusManager.highlightMode] always returns [FocusHighlightMode.traditional].
1463 alwaysTraditional,
1464}
1465
1466// By extending the WidgetsBindingObserver class,
1467// we can add a listener object to FocusManager as a private member.
1468class _AppLifecycleListener extends WidgetsBindingObserver {
1469 _AppLifecycleListener(this.onLifecycleStateChanged);
1470
1471 final void Function(AppLifecycleState) onLifecycleStateChanged;
1472
1473 @override
1474 void didChangeAppLifecycleState(AppLifecycleState state) => onLifecycleStateChanged(state);
1475}
1476
1477/// Manages the focus tree.
1478///
1479/// The focus tree is a separate, sparser, tree from the widget tree that
1480/// maintains the hierarchical relationship between focusable widgets in the
1481/// widget tree.
1482///
1483/// The focus manager is responsible for tracking which [FocusNode] has the
1484/// primary input focus (the [primaryFocus]), holding the [FocusScopeNode] that
1485/// is the root of the focus tree (the [rootScope]), and what the current
1486/// [highlightMode] is. It also distributes [KeyEvent]s to the nodes in the
1487/// focus tree.
1488///
1489/// The singleton [FocusManager] instance is held by the [WidgetsBinding] as
1490/// [WidgetsBinding.focusManager], and can be conveniently accessed using the
1491/// [FocusManager.instance] static accessor.
1492///
1493/// To find the [FocusNode] for a given [BuildContext], use [Focus.of]. To find
1494/// the [FocusScopeNode] for a given [BuildContext], use [FocusScope.of].
1495///
1496/// If you would like notification whenever the [primaryFocus] changes, register
1497/// a listener with [addListener]. When you no longer want to receive these
1498/// events, as when your object is about to be disposed, you must unregister
1499/// with [removeListener] to avoid memory leaks. Removing listeners is typically
1500/// done in [State.dispose] on stateful widgets.
1501///
1502/// The [highlightMode] describes how focus highlights should be displayed on
1503/// components in the UI. The [highlightMode] changes are notified separately
1504/// via [addHighlightModeListener] and removed with
1505/// [removeHighlightModeListener]. The highlight mode changes when the user
1506/// switches from a mouse to a touch interface, or vice versa.
1507///
1508/// The widgets that are used to manage focus in the widget tree are:
1509///
1510/// * [Focus], a widget that manages a [FocusNode] in the focus tree so that
1511/// the focus tree reflects changes in the widget hierarchy.
1512/// * [FocusScope], a widget that manages a [FocusScopeNode] in the focus tree,
1513/// creating a new scope for restricting focus to a set of focus nodes.
1514/// * [FocusTraversalGroup], a widget that groups together nodes that should be
1515/// traversed using an order described by a given [FocusTraversalPolicy].
1516///
1517/// See also:
1518///
1519/// * [FocusNode], which is a node in the focus tree that can receive focus.
1520/// * [FocusScopeNode], which is a node in the focus tree used to collect
1521/// subtrees into groups and restrict focus to them.
1522/// * The [primaryFocus] global accessor, for convenient access from anywhere
1523/// to the current focus manager state.
1524class FocusManager with DiagnosticableTreeMixin, ChangeNotifier {
1525 /// Creates an object that manages the focus tree.
1526 ///
1527 /// This constructor is rarely called directly. To access the [FocusManager],
1528 /// consider using the [FocusManager.instance] accessor instead (which gets it
1529 /// from the [WidgetsBinding] singleton).
1530 ///
1531 /// This newly constructed focus manager does not have the necessary event
1532 /// handlers registered to allow it to manage focus. To register those event
1533 /// handlers, callers must call [registerGlobalHandlers]. See the
1534 /// documentation in that method for caveats to watch out for.
1535 FocusManager() {
1536 if (kFlutterMemoryAllocationsEnabled) {
1537 ChangeNotifier.maybeDispatchObjectCreation(this);
1538 }
1539 if (_respondToLifecycleChange) {
1540 _appLifecycleListener = _AppLifecycleListener(_appLifecycleChange);
1541 WidgetsBinding.instance.addObserver(_appLifecycleListener!);
1542 }
1543 rootScope._manager = this;
1544 }
1545
1546 /// It appears that some Android keyboard implementations can cause
1547 /// app lifecycle state changes: adding the app lifecycle listener would
1548 /// cause the text field to unfocus as the user is trying to type.
1549 ///
1550 /// Additionally, on iOS, input fields aren't automatically populated
1551 /// with relevant data when using autofill.
1552 ///
1553 /// Until these are resolved, we won't be adding the listener to mobile platforms.
1554 /// https://github.com/flutter/flutter/issues/148475#issuecomment-2118407411
1555 /// https://github.com/flutter/flutter/pull/142930#issuecomment-1981750069
1556 bool get _respondToLifecycleChange => kIsWeb || switch (defaultTargetPlatform) {
1557 TargetPlatform.android || TargetPlatform.iOS => false,
1558 TargetPlatform.fuchsia || TargetPlatform.linux => true,
1559 TargetPlatform.windows || TargetPlatform.macOS => true,
1560 };
1561
1562 /// Registers global input event handlers that are needed to manage focus.
1563 ///
1564 /// This calls the [HardwareKeyboard.addHandler] on the shared instance of
1565 /// [HardwareKeyboard] and adds a route to the global entry in the gesture
1566 /// routing table. As such, only one [FocusManager] instance should register
1567 /// its global handlers.
1568 ///
1569 /// When this focus manager is no longer needed, calling [dispose] on it will
1570 /// unregister these handlers.
1571 void registerGlobalHandlers() => _highlightManager.registerGlobalHandlers();
1572
1573 @override
1574 void dispose() {
1575 if (_appLifecycleListener != null) {
1576 WidgetsBinding.instance.removeObserver(_appLifecycleListener!);
1577 }
1578 _highlightManager.dispose();
1579 rootScope.dispose();
1580 super.dispose();
1581 }
1582
1583 /// Provides convenient access to the current [FocusManager] singleton from
1584 /// the [WidgetsBinding] instance.
1585 static FocusManager get instance => WidgetsBinding.instance.focusManager;
1586
1587 final _HighlightModeManager _highlightManager = _HighlightModeManager();
1588
1589 /// Sets the strategy by which [highlightMode] is determined.
1590 ///
1591 /// If set to [FocusHighlightStrategy.automatic], then the highlight mode will
1592 /// change depending upon the interaction mode used last. For instance, if the
1593 /// last interaction was a touch interaction, then [highlightMode] will return
1594 /// [FocusHighlightMode.touch], and focus highlights will only appear on
1595 /// widgets that bring up a soft keyboard. If the last interaction was a
1596 /// non-touch interaction (hardware keyboard press, mouse click, etc.), then
1597 /// [highlightMode] will return [FocusHighlightMode.traditional], and focus
1598 /// highlights will appear on all widgets.
1599 ///
1600 /// If set to [FocusHighlightStrategy.alwaysTouch] or
1601 /// [FocusHighlightStrategy.alwaysTraditional], then [highlightMode] will
1602 /// always return [FocusHighlightMode.touch] or
1603 /// [FocusHighlightMode.traditional], respectively, regardless of the last UI
1604 /// interaction type.
1605 ///
1606 /// The initial value of [highlightMode] depends upon the value of
1607 /// [defaultTargetPlatform] and [MouseTracker.mouseIsConnected] of
1608 /// [RendererBinding.mouseTracker], making a guess about which interaction is
1609 /// most appropriate for the initial interaction mode.
1610 ///
1611 /// Defaults to [FocusHighlightStrategy.automatic].
1612 FocusHighlightStrategy get highlightStrategy => _highlightManager.strategy;
1613 set highlightStrategy(FocusHighlightStrategy value) {
1614 if (_highlightManager.strategy == value) {
1615 return;
1616 }
1617 _highlightManager.strategy = value;
1618 }
1619
1620 /// Indicates the current interaction mode for focus highlights.
1621 ///
1622 /// The value returned depends upon the [highlightStrategy] used, and possibly
1623 /// (depending on the value of [highlightStrategy]) the most recent
1624 /// interaction mode that they user used.
1625 ///
1626 /// If [highlightMode] returns [FocusHighlightMode.touch], then widgets should
1627 /// not draw their focus highlight unless they perform text entry.
1628 ///
1629 /// If [highlightMode] returns [FocusHighlightMode.traditional], then widgets should
1630 /// draw their focus highlight whenever they are focused.
1631 // Don't want to set _highlightMode here, since it's possible for the target
1632 // platform to change (especially in tests).
1633 FocusHighlightMode get highlightMode => _highlightManager.highlightMode;
1634
1635 /// Register a closure to be called when the [FocusManager] notifies its listeners
1636 /// that the value of [highlightMode] has changed.
1637 void addHighlightModeListener(ValueChanged<FocusHighlightMode> listener) => _highlightManager.addListener(listener);
1638
1639 /// Remove a previously registered closure from the list of closures that the
1640 /// [FocusManager] notifies.
1641 void removeHighlightModeListener(ValueChanged<FocusHighlightMode> listener) => _highlightManager.removeListener(listener);
1642
1643 /// {@template flutter.widgets.focus_manager.FocusManager.addEarlyKeyEventHandler}
1644 /// Adds a key event handler to a set of handlers that are called before any
1645 /// key event handlers in the focus tree are called.
1646 ///
1647 /// All of the handlers in the set will be called for every key event the
1648 /// [FocusManager] receives. If any one of the handlers returns
1649 /// [KeyEventResult.handled] or [KeyEventResult.skipRemainingHandlers], then
1650 /// none of the handlers in the focus tree will be called.
1651 ///
1652 /// If handlers are added while the existing callbacks are being invoked, they
1653 /// will not be called until the next key event occurs.
1654 ///
1655 /// See also:
1656 ///
1657 /// * [removeEarlyKeyEventHandler], which removes handlers added by this
1658 /// function.
1659 /// * [addLateKeyEventHandler], which is a similar mechanism for adding
1660 /// handlers that are invoked after the focus tree has had a chance to
1661 /// handle an event.
1662 /// {@endtemplate}
1663 void addEarlyKeyEventHandler(OnKeyEventCallback handler) {
1664 _highlightManager.addEarlyKeyEventHandler(handler);
1665 }
1666
1667 /// {@template flutter.widgets.focus_manager.FocusManager.removeEarlyKeyEventHandler}
1668 /// Removes a key handler added by calling [addEarlyKeyEventHandler].
1669 ///
1670 /// If handlers are removed while the existing callbacks are being invoked,
1671 /// they will continue to be called until the next key event is received.
1672 ///
1673 /// See also:
1674 ///
1675 /// * [addEarlyKeyEventHandler], which adds the handlers removed by this
1676 /// function.
1677 /// {@endtemplate}
1678 void removeEarlyKeyEventHandler(OnKeyEventCallback handler) {
1679 _highlightManager.removeEarlyKeyEventHandler(handler);
1680 }
1681
1682 /// {@template flutter.widgets.focus_manager.FocusManager.addLateKeyEventHandler}
1683 /// Adds a key event handler to a set of handlers that are called if none of
1684 /// the key event handlers in the focus tree handle the event.
1685 ///
1686 /// If the event reaches the root of the focus tree without being handled,
1687 /// then all of the handlers in the set will be called. If any of them returns
1688 /// [KeyEventResult.handled] or [KeyEventResult.skipRemainingHandlers], then
1689 /// event propagation to the platform will be stopped.
1690 ///
1691 /// If handlers are added while the existing callbacks are being invoked, they
1692 /// will not be called until the next key event is not handled by the focus
1693 /// tree.
1694 ///
1695 /// See also:
1696 ///
1697 /// * [removeLateKeyEventHandler], which removes handlers added by this
1698 /// function.
1699 /// * [addEarlyKeyEventHandler], which is a similar mechanism for adding
1700 /// handlers that are invoked before the focus tree has had a chance to
1701 /// handle an event.
1702 /// {@endtemplate}
1703 void addLateKeyEventHandler(OnKeyEventCallback handler) {
1704 _highlightManager.addLateKeyEventHandler(handler);
1705 }
1706
1707 /// {@template flutter.widgets.focus_manager.FocusManager.removeLateKeyEventHandler}
1708 /// Removes a key handler added by calling [addLateKeyEventHandler].
1709 ///
1710 /// If handlers are removed while the existing callbacks are being invoked,
1711 /// they will continue to be called until the next key event is received.
1712 ///
1713 /// See also:
1714 ///
1715 /// * [addLateKeyEventHandler], which adds the handlers removed by this
1716 /// function.
1717 /// {@endtemplate}
1718 void removeLateKeyEventHandler(OnKeyEventCallback handler) {
1719 _highlightManager.removeLateKeyEventHandler(handler);
1720 }
1721
1722 /// The root [FocusScopeNode] in the focus tree.
1723 ///
1724 /// This field is rarely used directly. To find the nearest [FocusScopeNode]
1725 /// for a given [FocusNode], call [FocusNode.nearestScope].
1726 final FocusScopeNode rootScope = FocusScopeNode(debugLabel: 'Root Focus Scope');
1727
1728 /// The node that currently has the primary focus.
1729 FocusNode? get primaryFocus => _primaryFocus;
1730 FocusNode? _primaryFocus;
1731
1732 // The set of nodes that need to notify their listeners of changes at the next
1733 // update.
1734 final Set<FocusNode> _dirtyNodes = <FocusNode>{};
1735
1736 // Allows FocusManager to respond to app lifecycle state changes,
1737 // temporarily suspending the primaryFocus when the app is inactive.
1738 _AppLifecycleListener? _appLifecycleListener;
1739
1740 // Stores the node that was focused before the app lifecycle changed.
1741 // Will be restored as the primary focus once app is resumed.
1742 FocusNode? _suspendedNode;
1743
1744 void _appLifecycleChange(AppLifecycleState state) {
1745 if (state == AppLifecycleState.resumed) {
1746 if (_primaryFocus != rootScope) {
1747 assert(_focusDebug(() => 'focus changed while app was paused, ignoring $_suspendedNode'));
1748 _suspendedNode = null;
1749 }
1750 else if (_suspendedNode != null) {
1751 assert(_focusDebug(() => 'requesting focus for $_suspendedNode'));
1752 _suspendedNode!.requestFocus();
1753 _suspendedNode = null;
1754 }
1755 } else if (_primaryFocus != rootScope) {
1756 assert(_focusDebug(() => 'suspending $_primaryFocus'));
1757 _markedForFocus = rootScope;
1758 _suspendedNode = _primaryFocus;
1759 applyFocusChangesIfNeeded();
1760 }
1761 }
1762
1763 // The node that has requested to have the primary focus, but hasn't been
1764 // given it yet.
1765 FocusNode? _markedForFocus;
1766
1767 void _markDetached(FocusNode node) {
1768 // The node has been removed from the tree, so it no longer needs to be
1769 // notified of changes.
1770 assert(_focusDebug(() => 'Node was detached: $node'));
1771 if (_primaryFocus == node) {
1772 _primaryFocus = null;
1773 }
1774 if (_suspendedNode == node) {
1775 _suspendedNode = null;
1776 }
1777 _dirtyNodes.remove(node);
1778 }
1779
1780 void _markPropertiesChanged(FocusNode node) {
1781 _markNeedsUpdate();
1782 assert(_focusDebug(() => 'Properties changed for node $node.'));
1783 _dirtyNodes.add(node);
1784 }
1785
1786 void _markNextFocus(FocusNode node) {
1787 if (_primaryFocus == node) {
1788 // The caller asked for the current focus to be the next focus, so just
1789 // pretend that didn't happen.
1790 _markedForFocus = null;
1791 } else {
1792 _markedForFocus = node;
1793 _markNeedsUpdate();
1794 }
1795 }
1796
1797 // The list of autofocus requests made since the last _applyFocusChange call.
1798 final List<_Autofocus> _pendingAutofocuses = <_Autofocus>[];
1799
1800 // True indicates that there is an update pending.
1801 bool _haveScheduledUpdate = false;
1802
1803 // Request that an update be scheduled, optionally requesting focus for the
1804 // given newFocus node.
1805 void _markNeedsUpdate() {
1806 assert(_focusDebug(() => 'Scheduling update, current focus is $_primaryFocus, next focus will be $_markedForFocus'));
1807 if (_haveScheduledUpdate) {
1808 return;
1809 }
1810 _haveScheduledUpdate = true;
1811 scheduleMicrotask(applyFocusChangesIfNeeded);
1812 }
1813
1814 /// Applies any pending focus changes and notifies listeners that the focus
1815 /// has changed.
1816 ///
1817 /// Must not be called during the build phase. This method is meant to be
1818 /// called in a post-frame callback or microtask when the pending focus
1819 /// changes need to be resolved before something else occurs.
1820 ///
1821 /// It can't be called during the build phase because not all listeners are
1822 /// safe to be called with an update during a build.
1823 ///
1824 /// Typically, this is called automatically by the [FocusManager], but
1825 /// sometimes it is necessary to ensure that no focus changes are pending
1826 /// before executing an action. For example, the [MenuAnchor] class uses this
1827 /// to make sure that the previous focus has been restored before executing a
1828 /// menu callback when a menu item is selected.
1829 ///
1830 /// It is safe to call this if no focus changes are pending.
1831 void applyFocusChangesIfNeeded() {
1832 assert(
1833 SchedulerBinding.instance.schedulerPhase != SchedulerPhase.persistentCallbacks,
1834 'applyFocusChangesIfNeeded() should not be called during the build phase.'
1835 );
1836
1837 _haveScheduledUpdate = false;
1838 final FocusNode? previousFocus = _primaryFocus;
1839
1840 for (final _Autofocus autofocus in _pendingAutofocuses) {
1841 autofocus.applyIfValid(this);
1842 }
1843 _pendingAutofocuses.clear();
1844
1845 if (_primaryFocus == null && _markedForFocus == null) {
1846 // If we don't have any current focus, and nobody has asked to focus yet,
1847 // then revert to the root scope.
1848 _markedForFocus = rootScope;
1849 }
1850 assert(_focusDebug(() => 'Refreshing focus state. Next focus will be $_markedForFocus'));
1851 // A node has requested to be the next focus, and isn't already the primary
1852 // focus.
1853 if (_markedForFocus != null && _markedForFocus != _primaryFocus) {
1854 final Set<FocusNode> previousPath = previousFocus?.ancestors.toSet() ?? <FocusNode>{};
1855 final Set<FocusNode> nextPath = _markedForFocus!.ancestors.toSet();
1856 // Notify nodes that are newly focused.
1857 _dirtyNodes.addAll(nextPath.difference(previousPath));
1858 // Notify nodes that are no longer focused
1859 _dirtyNodes.addAll(previousPath.difference(nextPath));
1860
1861 _primaryFocus = _markedForFocus;
1862 _markedForFocus = null;
1863 }
1864 assert(_markedForFocus == null);
1865 if (previousFocus != _primaryFocus) {
1866 assert(_focusDebug(() => 'Updating focus from $previousFocus to $_primaryFocus'));
1867 if (previousFocus != null) {
1868 _dirtyNodes.add(previousFocus);
1869 }
1870 if (_primaryFocus != null) {
1871 _dirtyNodes.add(_primaryFocus!);
1872 }
1873 }
1874 for (final FocusNode node in _dirtyNodes) {
1875 node._notify();
1876 }
1877 assert(_focusDebug(() => 'Notified ${_dirtyNodes.length} dirty nodes:', () => _dirtyNodes));
1878 _dirtyNodes.clear();
1879 if (previousFocus != _primaryFocus) {
1880 notifyListeners();
1881 }
1882 assert(() {
1883 if (debugFocusChanges) {
1884 debugDumpFocusTree();
1885 }
1886 return true;
1887 }());
1888 }
1889
1890 /// Enables this [FocusManager] to listen to changes of the application
1891 /// lifecycle if it does not already have an application lifecycle listener
1892 /// active, and the app isn't running on a native mobile platform.
1893 ///
1894 /// Typically, the application lifecycle listener for this [FocusManager] is
1895 /// setup at construction, but sometimes it is necessary to manually initialize
1896 /// it when the [FocusManager] does not have the relevant platform context in
1897 /// [defaultTargetPlatform] at the time of construction. This can happen in
1898 /// a test environment where the [BuildOwner] which initializes its own
1899 /// [FocusManager], may not have the accurate platform context during its
1900 /// initialization. In this case it is necessary for the test framework to call
1901 /// this method after it has set up the test variant for a given test, so the
1902 /// [FocusManager] can accurately listen to application lifecycle changes, if
1903 /// supported.
1904 @visibleForTesting
1905 void listenToApplicationLifecycleChangesIfSupported() {
1906 if (_appLifecycleListener == null && _respondToLifecycleChange) {
1907 _appLifecycleListener = _AppLifecycleListener(_appLifecycleChange);
1908 WidgetsBinding.instance.addObserver(_appLifecycleListener!);
1909 }
1910 }
1911
1912 @override
1913 List<DiagnosticsNode> debugDescribeChildren() {
1914 return <DiagnosticsNode>[
1915 rootScope.toDiagnosticsNode(name: 'rootScope'),
1916 ];
1917 }
1918
1919 @override
1920 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
1921 properties.add(FlagProperty('haveScheduledUpdate', value: _haveScheduledUpdate, ifTrue: 'UPDATE SCHEDULED'));
1922 properties.add(DiagnosticsProperty<FocusNode>('primaryFocus', primaryFocus, defaultValue: null));
1923 properties.add(DiagnosticsProperty<FocusNode>('nextFocus', _markedForFocus, defaultValue: null));
1924 final Element? element = primaryFocus?.context as Element?;
1925 if (element != null) {
1926 properties.add(DiagnosticsProperty<String>('primaryFocusCreator', element.debugGetCreatorChain(20)));
1927 }
1928 }
1929}
1930
1931// A class to detect and manage the highlight mode transitions. An instance of
1932// this is owned by the FocusManager.
1933//
1934// This doesn't extend ChangeNotifier because the callback passes the updated
1935// value, and ChangeNotifier requires using VoidCallback.
1936class _HighlightModeManager {
1937 _HighlightModeManager() {
1938 // TODO(polina-c): stop duplicating code across disposables
1939 // https://github.com/flutter/flutter/issues/137435
1940 if (kFlutterMemoryAllocationsEnabled) {
1941 FlutterMemoryAllocations.instance.dispatchObjectCreated(
1942 library: 'package:flutter/widgets.dart',
1943 className: '$_HighlightModeManager',
1944 object: this,
1945 );
1946 }
1947 }
1948
1949 // If set, indicates if the last interaction detected was touch or not. If
1950 // null, no interactions have occurred yet.
1951 bool? _lastInteractionWasTouch;
1952
1953 FocusHighlightMode get highlightMode => _highlightMode ?? _defaultModeForPlatform;
1954 FocusHighlightMode? _highlightMode;
1955
1956 FocusHighlightStrategy get strategy => _strategy;
1957 FocusHighlightStrategy _strategy = FocusHighlightStrategy.automatic;
1958 set strategy(FocusHighlightStrategy value) {
1959 if (_strategy == value) {
1960 return;
1961 }
1962 _strategy = value;
1963 updateMode();
1964 }
1965
1966 /// {@macro flutter.widgets.focus_manager.FocusManager.addEarlyKeyEventHandler}
1967 void addEarlyKeyEventHandler(OnKeyEventCallback callback) => _earlyKeyEventHandlers.add(callback);
1968
1969 /// {@macro flutter.widgets.focus_manager.FocusManager.removeEarlyKeyEventHandler}
1970 void removeEarlyKeyEventHandler(OnKeyEventCallback callback) => _earlyKeyEventHandlers.remove(callback);
1971
1972 // The list of callbacks for early key handling.
1973 final HashedObserverList<OnKeyEventCallback> _earlyKeyEventHandlers = HashedObserverList<OnKeyEventCallback>();
1974
1975 /// {@macro flutter.widgets.focus_manager.FocusManager.addLateKeyEventHandler}
1976 void addLateKeyEventHandler(OnKeyEventCallback callback) => _lateKeyEventHandlers.add(callback);
1977
1978 /// {@macro flutter.widgets.focus_manager.FocusManager.removeLateKeyEventHandler}
1979 void removeLateKeyEventHandler(OnKeyEventCallback callback) => _lateKeyEventHandlers.remove(callback);
1980
1981 // The list of callbacks for late key handling.
1982 final HashedObserverList<OnKeyEventCallback> _lateKeyEventHandlers = HashedObserverList<OnKeyEventCallback>();
1983
1984 /// Register a closure to be called when the [FocusManager] notifies its
1985 /// listeners that the value of [highlightMode] has changed.
1986 void addListener(ValueChanged<FocusHighlightMode> listener) => _listeners.add(listener);
1987
1988 /// Remove a previously registered closure from the list of closures that the
1989 /// [FocusManager] notifies.
1990 void removeListener(ValueChanged<FocusHighlightMode> listener) => _listeners.remove(listener);
1991
1992 // The list of listeners for [highlightMode] state changes.
1993 HashedObserverList<ValueChanged<FocusHighlightMode>> _listeners = HashedObserverList<ValueChanged<FocusHighlightMode>>();
1994
1995 void registerGlobalHandlers() {
1996 assert(ServicesBinding.instance.keyEventManager.keyMessageHandler == null);
1997 // TODO(gspencergoog): Remove this when the RawKeyEvent system is
1998 // deprecated, and replace it with registering a handler on the
1999 // HardwareKeyboard.
2000 ServicesBinding.instance.keyEventManager.keyMessageHandler = handleKeyMessage;
2001 GestureBinding.instance.pointerRouter.addGlobalRoute(handlePointerEvent);
2002 }
2003
2004 @mustCallSuper
2005 void dispose() {
2006 if (kFlutterMemoryAllocationsEnabled) {
2007 FlutterMemoryAllocations.instance.dispatchObjectDisposed(object: this);
2008 }
2009 if (ServicesBinding.instance.keyEventManager.keyMessageHandler == handleKeyMessage) {
2010 GestureBinding.instance.pointerRouter.removeGlobalRoute(handlePointerEvent);
2011 ServicesBinding.instance.keyEventManager.keyMessageHandler = null;
2012 }
2013 _listeners = HashedObserverList<ValueChanged<FocusHighlightMode>>();
2014 }
2015
2016 @pragma('vm:notify-debugger-on-exception')
2017 void notifyListeners() {
2018 if (_listeners.isEmpty) {
2019 return;
2020 }
2021 final List<ValueChanged<FocusHighlightMode>> localListeners = List<ValueChanged<FocusHighlightMode>>.of(_listeners);
2022 for (final ValueChanged<FocusHighlightMode> listener in localListeners) {
2023 try {
2024 if (_listeners.contains(listener)) {
2025 listener(highlightMode);
2026 }
2027 } catch (exception, stack) {
2028 InformationCollector? collector;
2029 assert(() {
2030 collector = () => <DiagnosticsNode>[
2031 DiagnosticsProperty<_HighlightModeManager>(
2032 'The $runtimeType sending notification was',
2033 this,
2034 style: DiagnosticsTreeStyle.errorProperty,
2035 ),
2036 ];
2037 return true;
2038 }());
2039 FlutterError.reportError(FlutterErrorDetails(
2040 exception: exception,
2041 stack: stack,
2042 library: 'widgets library',
2043 context: ErrorDescription('while dispatching notifications for $runtimeType'),
2044 informationCollector: collector,
2045 ));
2046 }
2047 }
2048 }
2049
2050 void handlePointerEvent(PointerEvent event) {
2051 final FocusHighlightMode expectedMode;
2052 switch (event.kind) {
2053 case PointerDeviceKind.touch:
2054 case PointerDeviceKind.stylus:
2055 case PointerDeviceKind.invertedStylus:
2056 _lastInteractionWasTouch = true;
2057 expectedMode = FocusHighlightMode.touch;
2058 case PointerDeviceKind.mouse:
2059 case PointerDeviceKind.trackpad:
2060 case PointerDeviceKind.unknown:
2061 _lastInteractionWasTouch = false;
2062 expectedMode = FocusHighlightMode.traditional;
2063 }
2064 if (expectedMode != highlightMode) {
2065 updateMode();
2066 }
2067 }
2068
2069 bool handleKeyMessage(KeyMessage message) {
2070 // Update highlightMode first, since things responding to the keys might
2071 // look at the highlight mode, and it should be accurate.
2072 _lastInteractionWasTouch = false;
2073 updateMode();
2074
2075 assert(_focusDebug(() => 'Received key event $message'));
2076 if (FocusManager.instance.primaryFocus == null) {
2077 assert(_focusDebug(() => 'No primary focus for key event, ignored: $message'));
2078 return false;
2079 }
2080
2081 bool handled = false;
2082 // Check to see if any of the early handlers handle the key. If so, then
2083 // return early.
2084 if (_earlyKeyEventHandlers.isNotEmpty) {
2085 final List<KeyEventResult> results = <KeyEventResult>[
2086 // Make a copy to prevent problems if the list is modified during iteration.
2087 for (final OnKeyEventCallback callback in _earlyKeyEventHandlers.toList())
2088 for (final KeyEvent event in message.events) callback(event),
2089 ];
2090 final KeyEventResult result = combineKeyEventResults(results);
2091 switch (result) {
2092 case KeyEventResult.ignored:
2093 break;
2094 case KeyEventResult.handled:
2095 assert(_focusDebug(() => 'Key event $message handled by early key event callback.'));
2096 handled = true;
2097 case KeyEventResult.skipRemainingHandlers:
2098 assert(_focusDebug(() => 'Key event $message propagation stopped by early key event callback.'));
2099 handled = false;
2100 }
2101 }
2102 if (handled) {
2103 return true;
2104 }
2105
2106 // Walk the current focus from the leaf to the root, calling each node's
2107 // onKeyEvent on the way up, and if one responds that they handled it or
2108 // want to stop propagation, stop.
2109 for (final FocusNode node in <FocusNode>[
2110 FocusManager.instance.primaryFocus!,
2111 ...FocusManager.instance.primaryFocus!.ancestors,
2112 ]) {
2113 final List<KeyEventResult> results = <KeyEventResult>[
2114 if (node.onKeyEvent != null)
2115 for (final KeyEvent event in message.events)
2116 node.onKeyEvent!(node, event),
2117 if (node.onKey != null && message.rawEvent != null)
2118 node.onKey!(node, message.rawEvent!),
2119 ];
2120 final KeyEventResult result = combineKeyEventResults(results);
2121 switch (result) {
2122 case KeyEventResult.ignored:
2123 continue;
2124 case KeyEventResult.handled:
2125 assert(_focusDebug(() => 'Node $node handled key event $message.'));
2126 handled = true;
2127 case KeyEventResult.skipRemainingHandlers:
2128 assert(_focusDebug(() => 'Node $node stopped key event propagation: $message.'));
2129 handled = false;
2130 }
2131 // Only KeyEventResult.ignored will continue the for loop. All other
2132 // options will stop the event propagation.
2133 assert(result != KeyEventResult.ignored);
2134 break;
2135 }
2136
2137 // Check to see if any late key event handlers want to handle the event.
2138 if (!handled && _lateKeyEventHandlers.isNotEmpty) {
2139 final List<KeyEventResult> results = <KeyEventResult>[
2140 // Make a copy to prevent problems if the list is modified during iteration.
2141 for (final OnKeyEventCallback callback in _lateKeyEventHandlers.toList())
2142 for (final KeyEvent event in message.events) callback(event),
2143 ];
2144 final KeyEventResult result = combineKeyEventResults(results);
2145 switch (result) {
2146 case KeyEventResult.ignored:
2147 break;
2148 case KeyEventResult.handled:
2149 assert(_focusDebug(() => 'Key event $message handled by late key event callback.'));
2150 handled = true;
2151 case KeyEventResult.skipRemainingHandlers:
2152 assert(_focusDebug(() => 'Key event $message propagation stopped by late key event callback.'));
2153 handled = false;
2154 }
2155 }
2156 if (!handled) {
2157 assert(_focusDebug(() => 'Key event not handled by focus system: $message.'));
2158 }
2159 return handled;
2160 }
2161
2162 // Update function to be called whenever the state relating to highlightMode
2163 // changes.
2164 void updateMode() {
2165 final FocusHighlightMode newMode;
2166 switch (strategy) {
2167 case FocusHighlightStrategy.automatic:
2168 if (_lastInteractionWasTouch == null) {
2169 // If we don't have any information about the last interaction yet,
2170 // then just rely on the default value for the platform, which will be
2171 // determined based on the target platform if _highlightMode is not
2172 // set.
2173 return;
2174 }
2175 if (_lastInteractionWasTouch!) {
2176 newMode = FocusHighlightMode.touch;
2177 } else {
2178 newMode = FocusHighlightMode.traditional;
2179 }
2180 case FocusHighlightStrategy.alwaysTouch:
2181 newMode = FocusHighlightMode.touch;
2182 case FocusHighlightStrategy.alwaysTraditional:
2183 newMode = FocusHighlightMode.traditional;
2184 }
2185 // We can't just compare newMode with _highlightMode here, since
2186 // _highlightMode could be null, so we want to compare with the return value
2187 // for the getter, since that's what clients will be looking at.
2188 final FocusHighlightMode oldMode = highlightMode;
2189 _highlightMode = newMode;
2190 if (highlightMode != oldMode) {
2191 notifyListeners();
2192 }
2193 }
2194
2195 static FocusHighlightMode get _defaultModeForPlatform {
2196 // Assume that if we're on one of the mobile platforms, and there's no mouse
2197 // connected, that the initial interaction will be touch-based, and that
2198 // it's traditional mouse and keyboard on all other platforms.
2199 //
2200 // This only affects the initial value: the ongoing value is updated to a
2201 // known correct value as soon as any pointer/keyboard events are received.
2202 switch (defaultTargetPlatform) {
2203 case TargetPlatform.android:
2204 case TargetPlatform.fuchsia:
2205 case TargetPlatform.iOS:
2206 if (WidgetsBinding.instance.mouseTracker.mouseIsConnected) {
2207 return FocusHighlightMode.traditional;
2208 }
2209 return FocusHighlightMode.touch;
2210 case TargetPlatform.linux:
2211 case TargetPlatform.macOS:
2212 case TargetPlatform.windows:
2213 return FocusHighlightMode.traditional;
2214 }
2215 }
2216}
2217
2218/// Provides convenient access to the current [FocusManager.primaryFocus] from
2219/// the [WidgetsBinding] instance.
2220FocusNode? get primaryFocus => WidgetsBinding.instance.focusManager.primaryFocus;
2221
2222/// Returns a text representation of the current focus tree, along with the
2223/// current attributes on each node.
2224///
2225/// Will return an empty string in release builds.
2226String debugDescribeFocusTree() {
2227 String? result;
2228 assert(() {
2229 result = FocusManager.instance.toStringDeep();
2230 return true;
2231 }());
2232 return result ?? '';
2233}
2234
2235/// Prints a text representation of the current focus tree, along with the
2236/// current attributes on each node.
2237///
2238/// Will do nothing in release builds.
2239void debugDumpFocusTree() {
2240 assert(() {
2241 debugPrint(debugDescribeFocusTree());
2242 return true;
2243 }());
2244}
2245