fix: one-shot select key activation in focus helpers
This commit is contained in:
@@ -152,9 +152,8 @@ mixin FocusableChipStateMixin<T extends StatefulWidget> on State<T> {
|
||||
_isSelectKeyDown = false;
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
} else if (event.isActionable && callbacks.onSelect != null) {
|
||||
callbacks.onSelect!();
|
||||
return KeyEventResult.handled;
|
||||
} else if (callbacks.onSelect != null) {
|
||||
return handleOneShotSelect(event, callbacks.onSelect!);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -366,12 +366,8 @@ class _FocusableWrapperState extends State<FocusableWrapper> with SingleTickerPr
|
||||
_isSelectKeyDown = false;
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
} else {
|
||||
// Simple select handling without long-press
|
||||
if (event is KeyDownEvent) {
|
||||
widget.onSelect?.call();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
} else if (widget.onSelect != null) {
|
||||
return handleOneShotSelect(event, widget.onSelect!);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,6 +87,18 @@ KeyEventResult handleBackKeyNavigation<T>(BuildContext context, KeyEvent event,
|
||||
return handleBackKeyAction(event, () => Navigator.pop(context, result));
|
||||
}
|
||||
|
||||
/// Handles a select key as a one-shot button activation.
|
||||
///
|
||||
/// Fires [onActivate] on the initial [KeyDownEvent] only.
|
||||
/// Consumes all select key events (down, repeat, up) to prevent
|
||||
/// unhandled events from reaching platform-level handling.
|
||||
/// Returns [KeyEventResult.ignored] for non-select keys.
|
||||
KeyEventResult handleOneShotSelect(KeyEvent event, VoidCallback onActivate) {
|
||||
if (!event.logicalKey.isSelectKey) return KeyEventResult.ignored;
|
||||
if (event is KeyDownEvent) onActivate();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
|
||||
/// Creates a [FocusOnKeyEventCallback] that dispatches d-pad / arrow keys to
|
||||
/// the provided directional callbacks.
|
||||
///
|
||||
@@ -94,7 +106,8 @@ KeyEventResult handleBackKeyNavigation<T>(BuildContext context, KeyEvent event,
|
||||
/// (passed through to the framework). Directions mapped to a callback
|
||||
/// automatically return [KeyEventResult.handled].
|
||||
///
|
||||
/// Only [KeyDownEvent] and [KeyRepeatEvent] are handled (via [isActionable]).
|
||||
/// Directional keys repeat on [KeyRepeatEvent] (via [isActionable]).
|
||||
/// Select is one-shot: fires on [KeyDownEvent] only, consumes repeat and up.
|
||||
///
|
||||
/// ```dart
|
||||
/// Focus(
|
||||
@@ -115,6 +128,13 @@ FocusOnKeyEventCallback dpadKeyHandler({
|
||||
VoidCallback? onSelect,
|
||||
}) {
|
||||
return (FocusNode _, KeyEvent event) {
|
||||
// Select: one-shot activation (no repeat), must run before isActionable
|
||||
// filter so KeyUpEvent is also consumed.
|
||||
if (onSelect != null) {
|
||||
final result = handleOneShotSelect(event, onSelect);
|
||||
if (result != KeyEventResult.ignored) return result;
|
||||
}
|
||||
|
||||
if (!event.isActionable) return KeyEventResult.ignored;
|
||||
final key = event.logicalKey;
|
||||
|
||||
@@ -134,10 +154,6 @@ FocusOnKeyEventCallback dpadKeyHandler({
|
||||
onRight();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
if (key.isSelectKey && onSelect != null) {
|
||||
onSelect();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
|
||||
return KeyEventResult.ignored;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user