KeyBindings
Keyboard shortcuts for a subtree: each KeyBinding fires while focus is
inside child.
See also: KeyDetector for low-level key handling inside a custom control.
Learn more: Key handling
Import: package:fleury/fleury.dart, or package:fleury/fleury_core.dart in browser code.
KeyBindings( bindings: [ KeyBinding(.ctrl.s, label: 'Bookmark', onTrigger: (_) => toggleBookmark()), // Movement keys opt in to key repeat, so holding j keeps moving. KeyBinding( .j, aliases: [.down], label: 'Down', includeRepeats: true, onTrigger: (_) => move(1), ), KeyBinding( .k, aliases: [.up], label: 'Up', includeRepeats: true, onTrigger: (_) => move(-1), ), KeyBinding(.g.g, label: 'Top', onTrigger: (_) => jumpToTop()), KeyBinding(.space.c, label: 'Clear ★', onTrigger: (_) => clearBookmarks()), ], child: Focus( autofocus: true, child: Column( children: [ Expanded(child: list), const KeyHintBar(), // lists the labelled bindings above ], ), ),)Details
Section titled “Details”While nothing has focus, such as before anything has claimed it, keys go
to every KeyBindings instead, the deepest first, so the bindings of
sibling panes fire too. While a dialog or another focus trap is open, that
is only the ones inside it and the ones enclosing it. A subtree under
ExcludeFocus, such as a route covered by another, takes no part.
A binding’s first argument is a KeySequence. Where a KeySequence is
expected, Dart’s dot shorthand lets you drop the type name: .ctrl.s is
KeySequence.ctrl.s, and .g.g is the two-key sequence g g.
Keys travel outward from the focused widget. A control such as a text field
handles its own keys first; then the nearest enclosing KeyBindings gets
the key, then the next one out, so an inner binding shadows an outer one for
the same key. If two bindings in one list match, the first wins. A matched
key is consumed unless its handler calls KeyBindingEvent.bubble. The
widget itself never takes focus, so it doesn’t affect Focus.of.
A focused text field takes typed characters before any binding sees them,
so a binding whose first key is a bare printable key (q, ?, Space, or a
Shift+letter) never fires while a text field has focus, and hint bars leave
it out. Chords with Ctrl, Alt, or Super, and keys such as Escape, still
reach bindings unless the field handles them itself.
A multi-key sequence (.g.g, .ctrl.x.ctrl.s, or a .space leader) fires
when its keys arrive in order. While the user is partway through one,
pendingOf reports the keys typed so far and the keys that can follow,
which the bundled WhichKey widget shows as a popup. A key that
doesn’t continue the sequence ends it. Esc backs out and does nothing else:
the keys typed so far are dropped, and the Esc doesn’t also close a dialog
or go back a page. Any other key cancels the sequence and is then handled
as usual. When a single-key binding in the same list or an enclosing one
shares the first key (g beside g g), it fires once a key other than Esc
rules out the sequence, or after the sequence timeout (500 ms by default;
see runApp’s sequenceTimeout). If focus moves away from these bindings
partway through, for example into a dialog that opens in front of them, the
sequence ends there and the keys typed so far are dropped: they never reach
what has focus now.
With modal set, keys that nothing inside this subtree handles stop here.
Navigator sets it for dialogs shown with present.
Constructors
Section titled “Constructors”KeyBindings()
Section titled “KeyBindings()”| Parameter | Type | Default | Description |
|---|---|---|---|
bindings: | List<KeyBinding> | required | The shortcuts that fire while focus is inside child, or while nothing has focus (see KeyBindings); if two match the same key, the first in the list wins. Hint bars and help overlays list the bindings that have a KeyBinding.label (see activeOf); a binding without one still fires. More |
modal: | bool | false | Whether keys that nothing inside this subtree handles stop here instead of reaching enclosing KeyBindings and KeyDetectors. Defaults to false; Navigator sets it for dialogs shown with present. More |
child: | Widget | required | The subtree these bindings cover. While something has focus, a key fires them only when focus is in this subtree — the scope is where the widget sits, not the whole app. While nothing has focus, see KeyBindings. |
-
bindings: A binding here shadows a binding for the same key in an enclosingKeyBindings, without either one knowing about the other. -
modal: A dialog that binds y, n, and Esc uses it so that a strayjdoesn’t reach the screen behind the dialog. To let one particular key through, bind it here and callKeyBindingEvent.bubblein its handler. This doesn’t keep focus inside the subtree; for a custom overlay, pair it withFocusScope(trapFocus: true), asNavigatordoes for dialogs.Hint bars stop here too: while focus is inside,
activeOflists these bindings and the ones inside, not the ones beyond. A key let through withKeyBindingEvent.bubbleis listed under its binding here, so give that binding a label to show it.
Source
Section titled “Source”KeyBindings is defined in packages/fleury/lib/src/widgets/key_bindings.dart.
Category: Input handling & focus · All widgets