pub fn scroll_on_keys(
keys: MessageReader<'_, '_, KeyPressed>,
tracker: Res<'_, FocusTracker>,
parents: Query<'_, '_, &ChildOf>,
text_inputs: Query<'_, '_, (), With<TextInput>>,
key_owning_widgets: Query<'_, '_, (), Or<(With<DropdownButton>, With<DropdownOptionButton>, With<MenuItemButton>, With<TabStripButton>, With<PopupPanel>)>>,
children: Query<'_, '_, (&ChildOf, &Transform)>,
scrolls: Query<'_, '_, (&Transform, &mut Scroll, &mut ScrollOffset)>,
)Expand description
Keyboard scrolling for the focused entity, or - when the focused
entity isn’t itself scrollable - its nearest Scroll-bearing
ancestor. Walks the [ChildOf] chain the same way
apply_a11y_scroll_into_view does for AT-driven ScrollIntoView.
ArrowUp/ArrowDown/ArrowLeft/ArrowRight: one line (crate::physics::LINE_HEIGHT_PX) along the arrow’s direction, masked to the container’s allowedScrollAxis(a horizontal-only scroller ignores Up/Down and vice versa).PageUp/PageDown(forwarded by the winit backend asKey::Character("PageUp"/"PageDown")- no dedicatedNamedKeyvariant exists yet): one viewport height.Home/End: jump to the top / bottom of the content.
Every target value - including Home/End - is computed against
the container’s own content-extent bbox (the same bounding-box scan
clamp_scroll_offsets does) and clamped inline, so this system is
self-contained: it doesn’t depend on clamp_scroll_offsets running
afterward to land in bounds, and (unlike a naive “seek to
f32::MAX”) End lands exactly at the max offset even under
macOS’s rubber-band overshoot curve rather than asymptotically
approaching it.
A focused TextInput owns arrows/Home/End for caret movement
(type_into_focused in lumen-input runs on the same raw key bus);
this system no-ops whenever the focused entity is itself a text
input, so a <textarea> sitting inside a scroll container doesn’t
have its arrow keys double-handled - moving the caret AND scrolling
the container out from under it.
The same double-handling guard covers the widgets that own their
arrow / Home / End keys while focused (Qt: a focused control that
accepts a key consumes it - the view never also scrolls):
dropdown headers (crate::tabs::DropdownButton - closed-state
value stepping), popup rows (crate::tabs::DropdownOptionButton
/ crate::tabs::MenuItemButton - highlight movement), and tab
strip buttons (crate::tabs::TabStripButton - tab switching).