From e1fbee8ebc91022b7e1a9848906c7127b142579f Mon Sep 17 00:00:00 2001 From: prxnvt <53838599+prxnvt@users.noreply.github.com> Date: Sat, 31 Oct 2026 16:37:49 -0400 Subject: [PATCH] Form controls: holding Enter or Space presses a focused button once The focused control took every pressed key event, the system's key repeats included, so holding Enter or Space on a focused button ran its macro or command again for each repeat. A repeat now still belongs to the button (it doesn't reach the grid) but doesn't press it; arrows, Page Up and Page Down held on a slider or spin button keep stepping. --- crates/ui-egui/src/form_controls.rs | 9 ++++++--- crates/ui-egui/src/grid/keyboard.rs | 4 +++- crates/ui-egui/tests/it/form_controls.rs | 23 +++++++++++++++++++++++ 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/crates/ui-egui/src/form_controls.rs b/crates/ui-egui/src/form_controls.rs index c4fff919a..fb6d41c03 100644 --- a/crates/ui-egui/src/form_controls.rs +++ b/crates/ui-egui/src/form_controls.rs @@ -357,8 +357,9 @@ fn step_part(app: &mut SheetApp, c: &FormControl, part: Part) { } /// Keys for the focused control: arrows move by a step, Page Up and Page Down by a page, Home and -/// End to the ends; Space or Enter presses a button. True when the key was used. -pub fn key(app: &mut SheetApp, sh: &Sheet, key: egui::Key) -> bool { +/// End to the ends; Space or Enter presses a button. True when the key was used. `repeat` is a key +/// held down: it steps a slider or spin button again, but a button runs once per press. +pub fn key(app: &mut SheetApp, sh: &Sheet, key: egui::Key, repeat: bool) -> bool { use egui::Key; let Some(c) = app.grid.focused_control.and_then(|id| find(sh, id)).cloned() else { return false }; if app.selected_object.is_some() { @@ -370,7 +371,9 @@ pub fn key(app: &mut SheetApp, sh: &Sheet, key: egui::Key) -> bool { true } (ControlKind::Button, Key::Space | Key::Enter) => { - app.press_button(c.id); + if !repeat { + app.press_button(c.id); + } true } (ControlKind::Button, _) => false, diff --git a/crates/ui-egui/src/grid/keyboard.rs b/crates/ui-egui/src/grid/keyboard.rs index f2d571bb3..81f4b432f 100644 --- a/crates/ui-egui/src/grid/keyboard.rs +++ b/crates/ui-egui/src/grid/keyboard.rs @@ -170,7 +170,9 @@ fn grid_events(app: &mut SheetApp, ctx: &egui::Context, sh: &Sheet) -> Vec bool { match ev { egui::Event::Text(text) => text == " " && app.grid.focused_control.is_some() && app.selected_object.is_none(), - egui::Event::Key { key, pressed: true, modifiers: m, .. } => !m.command && !m.ctrl && !m.alt && crate::form_controls::key(app, sh, *key), + egui::Event::Key { key, pressed: true, repeat, modifiers: m, .. } => { + !m.command && !m.ctrl && !m.alt && crate::form_controls::key(app, sh, *key, *repeat) + } _ => false, } } diff --git a/crates/ui-egui/tests/it/form_controls.rs b/crates/ui-egui/tests/it/form_controls.rs index 79823f62c..09b57c4a8 100644 --- a/crates/ui-egui/tests/it/form_controls.rs +++ b/crates/ui-egui/tests/it/form_controls.rs @@ -241,6 +241,29 @@ fn a_button_runs_its_macro_and_cmd_or_right_click_only_selects() { assert_eq!(cell(&h, "H1"), Value::Empty); } +#[test] +fn holding_enter_or_space_presses_a_focused_button_once() { + let (mut h, ids) = fixture(); + let r = rect(&h, ids.button); + click(&mut h, r.center()); + assert_eq!(h.state().grid.focused_control, Some(ids.button)); + for k in [Key::Enter, Key::Space] { + let before = undo_len(&h); + // A held key: one press, then the system's repeats, then the release. + h.input_mut().events.push(Event::Key { key: k, physical_key: None, pressed: true, repeat: false, modifiers: Modifiers::NONE }); + h.run_steps(1); + for _ in 0..5 { + h.input_mut().events.push(Event::Key { key: k, physical_key: None, pressed: true, repeat: true, modifiers: Modifiers::NONE }); + h.run_steps(1); + } + h.input_mut().events.push(Event::Key { key: k, physical_key: None, pressed: false, repeat: false, modifiers: Modifiers::NONE }); + h.run_steps(2); + assert_eq!(undo_len(&h), before + 1, "{k:?} ran the macro once"); + assert_eq!(cell(&h, "H1"), Value::text("pressed")); + assert_eq!(cell(&h, "A20"), Value::Empty, "{k:?} typed nothing into the cell"); + } +} + #[test] fn a_button_from_a_file_asks_before_it_runs() { use egui_kittest::kittest::Queryable as _;