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 e5b0f71ff3d595f7cfa040ea336d280f831f2dee..12338b75fbe0b8d08f512ae199bc810eedac838c 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 10de12fbe1d3104b8140d18643f40a44ee100148..6d841f3962694317aec11d9b21f24faab4ab83ae 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 5d6848cd7bd1311af8f44d8ef804ae3162b736aa..8ce2e9b363214b348b293324bd9fd17b646e0a6c 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 e22db89e3b92ac0eabb1e3677846a4245ae53312..b1b460ff70d96c894ba74583f52cf60efebbcd1c 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 eb7f3514443a0cffcb661ab3d2815e15531a0648..4b0050e943b029b6a5f05947180edcbf500eed86 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 8ce2e9b363214b348b293324bd9fd17b646e0a6c..c6787791448c78d4d1a6e950faf2b9d3070d84a2 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 c6787791448c78d4d1a6e950faf2b9d3070d84a2..ac5073d893b8343b65dc2f70c1c9e64659cc7704 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 } }