From a7556785673f5ff2264b4afd8d6a621f11fed42e Mon Sep 17 00:00:00 2001 From: CrispyPin Date: Sat, 12 Apr 2025 20:51:55 +0200 Subject: [PATCH] prevent bindings from triggering when a modifier is held down that matches a different binding --- src/input.rs | 62 ++++++++++--- src/layout.rs | 245 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 +- src/ui2.rs | 142 +++++++++++++++++++++++++++++ 4 files changed, 440 insertions(+), 12 deletions(-) create mode 100644 src/layout.rs create mode 100644 src/ui2.rs diff --git a/src/input.rs b/src/input.rs index 4d695b0..bc4241b 100644 --- a/src/input.rs +++ b/src/input.rs @@ -54,6 +54,7 @@ impl Default for Input { let mut bindings = [(); ActionId::SIZE].map(|_| Vec::new()); let mut bind_key = |action, mods, trigger| { bindings[action as usize].push(Binding { + blocking_modifiers: Vec::new(), modifiers: mods, trigger, }); @@ -141,21 +142,26 @@ impl Input { if text_button(d, &globals.mouse, buttons_x + 85, y, 45, "edit") { self.editing_binding = Some((action, binding_index, BindingEdit::Init)); } + // let trigger = format!("{:?}", binding.trigger); - d.draw_text(&trigger, binding_text_x, y + 5, 20, Color::LIMEGREEN); - let x = binding_text_x + 10 + d.measure_text(&trigger, 20); + let mut x = binding_text_x; + d.draw_text(&trigger, x, y + 5, 20, Color::LIMEGREEN); + x += 10 + d.measure_text(&trigger, 20); + // let modifiers = format!("{:?}", binding.modifiers); d.draw_text(&modifiers, x, y + 5, 20, Color::LIGHTBLUE); + x += 10 + d.measure_text(&modifiers, 20); + // let conflicts = conflicts(&self.bindings, binding, action); if !conflicts.is_empty() { - let x = x + 10 + d.measure_text(&modifiers, 20); - d.draw_text( - &format!("also used by: {conflicts:?}"), - x, - y + 5, - 20, - Color::ORANGERED, - ); + let conflict_text = format!("also used by: {conflicts:?}"); + d.draw_text(&conflict_text, x, y + 5, 20, Color::ORANGERED); + x += 10 + d.measure_text(&conflict_text, 20); + } + // + if !binding.blocking_modifiers.is_empty() { + let blocking_text = format!("not while: {:?}", binding.blocking_modifiers); + d.draw_text(&blocking_text, x, y + 5, 20, Color::GRAY); } y += 32; } @@ -193,6 +199,7 @@ impl Input { BindingEdit::Init => { if key.just_pressed(d) { *edit_state = BindingEdit::Adding(Binding { + blocking_modifiers: Vec::new(), modifiers: Vec::new(), trigger: key, }); @@ -218,6 +225,7 @@ impl Input { globals.mouse.is_over(ok_btn_rect) && key == Button::MouseLeft; if key.just_pressed(d) && !clicking_ok { *edit_state = BindingEdit::Adding(Binding { + blocking_modifiers: Vec::new(), modifiers: Vec::new(), trigger: key, }); @@ -255,6 +263,7 @@ impl Input { binding_list.push(binding.clone()); } self.editing_binding = None; + self.update_modifier_blocks(); } } if text_button(d, &globals.mouse, x + 100, y + 40, 80, "cancel") { @@ -268,7 +277,9 @@ impl Input { let bindings = &self.bindings[i]; let mut is_active = false; for binding in bindings { - if binding.modifiers.iter().all(|&m| m.is_down(rl)) { + if binding.modifiers.iter().all(|&m| m.is_down(rl)) + && !binding.blocking_modifiers.iter().any(|&m| m.is_down(rl)) + { is_active |= binding.trigger.is_down(rl); } } @@ -299,6 +310,33 @@ impl Input { pub fn is_released(&self, action: ActionId) -> bool { self.states[action as usize] == BindingState::Released } + + /// Must be called after any binding has changed. + /// Ensures a binding "S" is not triggered by "Ctrl+S", if "Ctrl+S" is bound to something else. + pub fn update_modifier_blocks(&mut self) { + for i in 0..ActionId::SIZE { + let bindings = &self.bindings[i]; + for binding_index in 0..bindings.len() { + let binding = &self.bindings[i][binding_index]; + let mut blocking_mods = Vec::new(); + for i in 0..ActionId::SIZE { + let other_bindings = &self.bindings[i]; + for other_binding in other_bindings { + if other_binding.trigger == binding.trigger { + for modifier in &other_binding.modifiers { + if !blocking_mods.contains(modifier) + && !binding.modifiers.contains(modifier) + { + blocking_mods.push(*modifier); + } + } + } + } + } + self.bindings[i][binding_index].blocking_modifiers = blocking_mods; + } + } + } } fn conflicts( @@ -338,6 +376,8 @@ impl ActionId { #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Binding { + #[serde(skip)] + blocking_modifiers: Vec