Key bindings
Navigation, edit, accept and cancel keys are configurable. A widget asks for a
semantic action - MoveUp, Accept, Toggle, NewLine and so on - rather
than a fixed key, and a key map binds each action to one or more keys. Set it
on the form with ->keys(...), mirroring ->theme(...):
$form = Form::create('My form')->keys('vim'); // built-in vim navigation (h/j/k/l)
Two presets ship: default (the bindings described in Panels and
navigation) and vim, which adds h/j/k/l alongside the arrow
keys - only where a letter is not typed input, so text and filter fields keep the
arrows.
Per-widget-type overrides
Bindings are layered by scope: a base layer shared by every widget, a navigation layer for the panel browser, and one layer per widget type that overrides the base only where it differs (Enter inserts a newline in a textarea, Space toggles a checkbox option). Retune individual bindings by passing overrides on top of a preset - each names a scope, an action and its keys:
use DrevOps\Tui\Config\FieldType;
use DrevOps\Tui\Input\Action;
use DrevOps\Tui\Input\Binding;
use DrevOps\Tui\Input\KeyName;
use DrevOps\Tui\Input\Scope;
$form = Form::create('My form')->keys('default', [
// Quit with x as well as q.
new Binding(Scope::navigation(), Action::Quit, 'x'),
// In the single-choice list, Tab accepts too.
new Binding(Scope::field(FieldType::Select), Action::Accept, KeyName::Tab, KeyName::Enter),
]);
A binding's keys accept a KeyName for a named key or a single-character string
for a printable one. The panel and editor hints are drawn from the live bindings,
so they always reflect the active keys.
Presets and validation
A preset is a class listing its bindings. Subclass DefaultKeyMap to ship your
own, name it directly with ->keys('\App\MyKeyMap'), or register a short alias
with KeyMapManager::register('mine', MyKeyMap::class) and then ->keys('mine').
Bindings are validated when the form is built, so a bad key map is caught at declaration time, not mid-session:
- a key bound to two different actions in the same scope is a conflict;
- a printable character bound in the base scope, or in a scope whose widget consumes typed input (text, search, checkbox), would be un-typeable and is rejected;
- an unknown preset name, or a character binding that is not exactly one character, is rejected.
See playground/8-key-bindings
for the default map, the vim preset and a custom override side by side.