git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

commit478aaebf8fecbad67382c411f9f51cf7090f8576
parent332091f151
authorLucas Galante <[email protected]>
date2026-07-31 15:40
feat: Escape dismisses the shared context menu — toolkit-wide default

Intercepted in the engine's key path before app dispatch and consumed,
mirroring the click-outside dismissal. Every client gets it for free;
no per-app Escape wiring.

Co-Authored-By: Claude Fable 5 <[email protected]>

 src/backend/window_runner.rs | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/backend/window_runner.rs b/src/backend/window_runner.rs
index b9fb9f4..66cf2b2 100644
--- a/src/backend/window_runner.rs
+++ b/src/backend/window_runner.rs
@@ -3684,6 +3684,18 @@ impl<A: Application> EngineState<A> {
             ctx.logo_pressed = self.logo_pressed;
         }
 
+        // Escape dismisses the shared context menu before app dispatch — the
+        // toolkit-wide default, mirroring the click-outside dismissal. Consumed:
+        // while a menu is open, Escape means "close it", nothing else.
+        if state == ElementState::Pressed
+            && custom_event.logical_key == Key::Named(NamedKey::Escape)
+            && crate::widget::context_menu::is_visible()
+        {
+            crate::widget::context_menu::hide();
+            self.redraw = true;
+            return;
+        }
+
         let mut rebuild = false;
         if let Some(msg) = self.inner.as_mut().unwrap().handle_key_input(&custom_event, &mut rebuild) {
             let mut update_rebuild = false;