From 607903eed561c192522763fac693094541d18cfe Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 17 Jun 2022 17:09:16 +0200 Subject: [PATCH 1/3] Return true in the `Window::on_event` callback if event was handled --- crates/gpui/src/app.rs | 6 ++++-- crates/gpui/src/platform.rs | 2 +- crates/gpui/src/platform/mac/window.rs | 4 ++-- crates/gpui/src/platform/test.rs | 4 ++-- crates/gpui/src/presenter.rs | 8 ++++++-- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index e5b0f71ff3..12338b75fb 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -1774,11 +1774,13 @@ impl MutableAppContext { presenter.borrow().dispatch_path(cx.as_ref()), keystroke, ) { - return; + return true; } } - presenter.borrow_mut().dispatch_event(event, cx); + presenter.borrow_mut().dispatch_event(event, cx) + } else { + false } }) })); diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 10de12fbe1..6d841f3962 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -90,7 +90,7 @@ pub trait Dispatcher: Send + Sync { pub trait Window: WindowContext { fn as_any_mut(&mut self) -> &mut dyn Any; - fn on_event(&mut self, callback: Box); + fn on_event(&mut self, callback: Box bool>); fn on_active_status_change(&mut self, callback: Box); fn on_resize(&mut self, callback: Box); fn on_close(&mut self, callback: Box); diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index 5d6848cd7b..8ce2e9b363 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -164,7 +164,7 @@ pub struct Window(Rc>); struct WindowState { id: usize, native_window: id, - event_callback: Option>, + event_callback: Option bool>>, activate_callback: Option>, resize_callback: Option>, close_callback: Option>, @@ -331,7 +331,7 @@ impl platform::Window for Window { self } - fn on_event(&mut self, callback: Box) { + fn on_event(&mut self, callback: Box bool>) { self.0.as_ref().borrow_mut().event_callback = Some(callback); } diff --git a/crates/gpui/src/platform/test.rs b/crates/gpui/src/platform/test.rs index e22db89e3b..b1b460ff70 100644 --- a/crates/gpui/src/platform/test.rs +++ b/crates/gpui/src/platform/test.rs @@ -34,7 +34,7 @@ pub struct Window { size: Vector2F, scale_factor: f32, current_scene: Option, - event_handlers: Vec>, + event_handlers: Vec bool>>, resize_handlers: Vec>, close_handlers: Vec>, pub(crate) title: Option, @@ -233,7 +233,7 @@ impl super::Window for Window { self } - fn on_event(&mut self, callback: Box) { + fn on_event(&mut self, callback: Box bool>) { self.event_handlers.push(callback); } diff --git a/crates/gpui/src/presenter.rs b/crates/gpui/src/presenter.rs index eb7f351444..4b0050e943 100644 --- a/crates/gpui/src/presenter.rs +++ b/crates/gpui/src/presenter.rs @@ -224,7 +224,7 @@ impl Presenter { } } - pub fn dispatch_event(&mut self, event: Event, cx: &mut MutableAppContext) { + pub fn dispatch_event(&mut self, event: Event, cx: &mut MutableAppContext) -> bool { if let Some(root_view_id) = cx.root_view_id(self.window_id) { let mut invalidated_views = Vec::new(); let mut mouse_down_out_handlers = Vec::new(); @@ -366,7 +366,7 @@ impl Presenter { } if !handled { - event_cx.dispatch_event(root_view_id, &event); + handled = event_cx.dispatch_event(root_view_id, &event); } invalidated_views.extend(event_cx.invalidated_views); @@ -384,6 +384,10 @@ impl Presenter { } cx.dispatch_action_any(self.window_id, &dispatch_path, directive.action.as_ref()); } + + handled + } else { + false } } From 8f6d081de84309b13188c70090a075b6c89df1e4 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 17 Jun 2022 17:12:56 +0200 Subject: [PATCH 2/3] Override `performKeyEquivalent` to handle key events This lets us bypass the application menu and invoke the event handler in Zed first. If that doesn't handle the event, the application menu item corresponding to the shortcut will be actioned. Prior to this commit the opposite would happen, which would dramatically limit the throughput at which we could handle events. --- crates/gpui/src/platform/mac/window.rs | 61 +++++++++++++++++--------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index 8ce2e9b363..c678779144 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -92,8 +92,8 @@ unsafe fn build_classes() { decl.add_method(sel!(dealloc), dealloc_view as extern "C" fn(&Object, Sel)); decl.add_method( - sel!(keyDown:), - handle_view_event as extern "C" fn(&Object, Sel, id), + sel!(performKeyEquivalent:), + handle_key_equivalent as extern "C" fn(&Object, Sel, id) -> BOOL, ); decl.add_method( sel!(mouseDown:), @@ -528,6 +528,45 @@ extern "C" fn dealloc_view(this: &Object, _: Sel) { } } +extern "C" fn handle_key_equivalent(this: &Object, _: Sel, native_event: id) -> BOOL { + let window_state = unsafe { get_window_state(this) }; + let mut window_state_borrow = window_state.as_ref().borrow_mut(); + + let event = unsafe { Event::from_native(native_event, Some(window_state_borrow.size().y())) }; + if let Some(event) = event { + match &event { + Event::KeyDown { + keystroke, + input, + is_held, + } => { + let keydown = (keystroke.clone(), input.clone()); + // Ignore events from held-down keys after some of the initially-pressed keys + // were released. + if *is_held { + if window_state_borrow.last_fresh_keydown.as_ref() != Some(&keydown) { + return true; + } + } else { + window_state_borrow.last_fresh_keydown = Some(keydown); + } + } + _ => return false, + } + + if let Some(mut callback) = window_state_borrow.event_callback.take() { + drop(window_state_borrow); + let handled = callback(event); + window_state.borrow_mut().event_callback = Some(callback); + handled + } else { + false + } + } else { + false + } +} + extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { let window_state = unsafe { get_window_state(this) }; let weak_window_state = Rc::downgrade(&window_state); @@ -551,24 +590,6 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { Event::LeftMouseUp { .. } => { window_state_borrow.synthetic_drag_counter += 1; } - - // Ignore events from held-down keys after some of the initially-pressed keys - // were released. - Event::KeyDown { - input, - keystroke, - is_held, - } => { - let keydown = (keystroke.clone(), input.clone()); - if *is_held { - if window_state_borrow.last_fresh_keydown.as_ref() != Some(&keydown) { - return; - } - } else { - window_state_borrow.last_fresh_keydown = Some(keydown); - } - } - _ => {} } From a35d7c5e158e181716713605401f4b750cf61240 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 17 Jun 2022 17:19:18 +0200 Subject: [PATCH 3/3] Use `BOOL` instead of Rust booleans in `handle_key_equivalent` --- crates/gpui/src/platform/mac/window.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index c678779144..ac5073d893 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -545,25 +545,25 @@ extern "C" fn handle_key_equivalent(this: &Object, _: Sel, native_event: id) -> // were released. if *is_held { if window_state_borrow.last_fresh_keydown.as_ref() != Some(&keydown) { - return true; + return YES; } } else { window_state_borrow.last_fresh_keydown = Some(keydown); } } - _ => return false, + _ => return NO, } if let Some(mut callback) = window_state_borrow.event_callback.take() { drop(window_state_borrow); let handled = callback(event); window_state.borrow_mut().event_callback = Some(callback); - handled + handled as BOOL } else { - false + NO } } else { - false + NO } }