gpui: Add cx.intercept_keystrokes
API to intercept keystrokes before action dispatch (#34084)
Closes #ISSUE `cx.intercept_keystrokes` functions as a sibling API to `cx.observe_keystrokes`. Under the hood the two API's are basically identical, however, `cx.observe_keystrokes` runs _after_ all event dispatch handling (including action dispatch) while `cx.intercept_keystrokes` runs _before_. This allows for `cx.stop_propagation()` calls within the `cx.intercept_keystrokes` callback to prevent action dispatch. The motivating example usage behind this API is also included in this PR. It is used as part of a keystroke input component that needs to intercept keystrokes before action dispatch to display them. cc: @mikayla-maki Release Notes: - N/A *or* Added/Fixed/Improved ...
This commit is contained in:
parent
862e733ef5
commit
9b63ba6205
3 changed files with 92 additions and 16 deletions
|
@ -1369,6 +1369,31 @@ impl Window {
|
|||
});
|
||||
}
|
||||
|
||||
pub(crate) fn dispatch_keystroke_interceptors(
|
||||
&mut self,
|
||||
event: &dyn Any,
|
||||
context_stack: Vec<KeyContext>,
|
||||
cx: &mut App,
|
||||
) {
|
||||
let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() else {
|
||||
return;
|
||||
};
|
||||
|
||||
cx.keystroke_interceptors
|
||||
.clone()
|
||||
.retain(&(), move |callback| {
|
||||
(callback)(
|
||||
&KeystrokeEvent {
|
||||
keystroke: key_down_event.keystroke.clone(),
|
||||
action: None,
|
||||
context_stack: context_stack.clone(),
|
||||
},
|
||||
self,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
/// Schedules the given function to be run at the end of the current effect cycle, allowing entities
|
||||
/// that are currently on the stack to be returned to the app.
|
||||
pub fn defer(&self, cx: &mut App, f: impl FnOnce(&mut Window, &mut App) + 'static) {
|
||||
|
@ -3522,6 +3547,13 @@ impl Window {
|
|||
return;
|
||||
};
|
||||
|
||||
cx.propagate_event = true;
|
||||
self.dispatch_keystroke_interceptors(event, self.context_stack(), cx);
|
||||
if !cx.propagate_event {
|
||||
self.finish_dispatch_key_event(event, dispatch_path, self.context_stack(), cx);
|
||||
return;
|
||||
}
|
||||
|
||||
let mut currently_pending = self.pending_input.take().unwrap_or_default();
|
||||
if currently_pending.focus.is_some() && currently_pending.focus != self.focus {
|
||||
currently_pending = PendingInput::default();
|
||||
|
@ -3570,7 +3602,6 @@ impl Window {
|
|||
return;
|
||||
}
|
||||
|
||||
cx.propagate_event = true;
|
||||
for binding in match_result.bindings {
|
||||
self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
|
||||
if !cx.propagate_event {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue