From 73c91cbac5efb2474239c7edfa4ffb633895186d Mon Sep 17 00:00:00 2001 From: MarekSpodBiedry <73122968+MarekSpodBiedry@users.noreply.github.com> Date: Sun, 11 Oct 2026 20:03:55 +0200 Subject: [PATCH] Command line keyboard input works while the command line is hidden (#497) (#595) Squash of PR #595 by @MarekSpodBiedry. Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/canvas.rs | 2 + crates/ui-egui/src/cmdline.rs | 1 - crates/ui-egui/tests/hidden_command_line.rs | 58 +++++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 crates/ui-egui/tests/hidden_command_line.rs diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs index 6f065868e..34e99c7ce 100644 --- a/crates/ui-egui/src/canvas.rs +++ b/crates/ui-egui/src/canvas.rs @@ -1017,6 +1017,8 @@ pub fn show(app: &mut CadApp, ui: &mut egui::Ui) { draw_viewcube(app, ui, rect); } viewport_label(&painter, rect); + // Typing and Escape reach the command line even when its overlay is hidden. + crate::cmdline::keyboard(app, ui.ctx()); // Command line overlay. if app.ui.show_command_line { crate::cmdline::show(app, ui, full); diff --git a/crates/ui-egui/src/cmdline.rs b/crates/ui-egui/src/cmdline.rs index 65f5a9c52..a72488b52 100644 --- a/crates/ui-egui/src/cmdline.rs +++ b/crates/ui-egui/src/cmdline.rs @@ -344,7 +344,6 @@ fn visible_lines(app: &CadApp, canvas: Rect, bar: Rect) -> usize { pub fn show(app: &mut CadApp, ui: &mut egui::Ui, canvas: Rect) { let t = Tokens::get(); - keyboard(app, ui.ctx()); let w = (canvas.width() * 0.48).clamp(360.0, 760.0).min((canvas.width() - 8.0).max(0.0)); let h = 24.0; let bar = Rect::from_min_size(pos2(canvas.center().x - w / 2.0, canvas.bottom() - h - 10.0), vec2(w, h)); diff --git a/crates/ui-egui/tests/hidden_command_line.rs b/crates/ui-egui/tests/hidden_command_line.rs new file mode 100644 index 000000000..cf5259564 --- /dev/null +++ b/crates/ui-egui/tests/hidden_command_line.rs @@ -0,0 +1,58 @@ +//! Escape and typed command names reach the command line whether or not its overlay is shown. + +use cadcraft_engine::Session; +use cadcraft_ui_egui::control::{ControlRequest, Outcome, handle}; +use cadcraft_ui_egui::{CadApp, Services}; +use serde_json::{Value, json}; + +fn call(app: &mut CadApp, ctx: &egui::Context, method: &str, params: Value) -> Value { + let (req, _reply) = ControlRequest::new(method, params); + match handle(app, ctx, &req) { + Outcome::Done(v) => { + assert_eq!(v["ok"], true, "{v}"); + v["result"].clone() + } + _ => panic!("unexpected screenshot"), + } +} + +fn frame(app: &mut CadApp, ctx: &egui::Context) { + let mut raw = egui::RawInput { screen_rect: Some(egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(1280.0, 800.0))), ..Default::default() }; + app.raw_input_hook(&mut raw); + cadcraft_ui_egui::cmdline::capture_tab(ctx, &mut raw); + let _ = ctx.run_ui(raw, |ui| { + app.logic(ui.ctx()); + app.ui(ui); + }); + assert!(!ctx.egui_wants_keyboard_input(), "a text field must not hold focus"); +} + +fn pump(app: &mut CadApp, ctx: &egui::Context) { + for _ in 0..3 { + frame(app, ctx); + } + assert!(app.synthetic.is_empty()); + assert!(app.canvas.rect.is_some()); +} + +#[test] +fn hidden_command_line_keyboard() { + for visible in [true, false] { + let ctx = egui::Context::default(); + let mut app = CadApp::new(Session::new(), Services::default()); + pump(&mut app, &ctx); + call(&mut app, &ctx, "ui.set", json!({"showCommandLine": visible})); + + call(&mut app, &ctx, "cmdline.input", json!({"text": "LINE"})); + assert_eq!(call(&mut app, &ctx, "cmdline.state", json!({}))["running"], "line"); + call(&mut app, &ctx, "ui.key", json!({"key": "escape"})); + pump(&mut app, &ctx); + assert!(call(&mut app, &ctx, "cmdline.state", json!({}))["running"].is_null(), "escape, visible={visible}"); + + call(&mut app, &ctx, "ui.text", json!({"text": "LINE"})); + call(&mut app, &ctx, "ui.key", json!({"key": "enter"})); + pump(&mut app, &ctx); + assert_eq!(call(&mut app, &ctx, "cmdline.state", json!({}))["running"], "line", "typed LINE, visible={visible}"); + assert_eq!(app.cmd.history, ["LINE"], "visible={visible}"); + } +}