From 20271264cf07a19ebc460da03a6abb1040e63df0 Mon Sep 17 00:00:00 2001 From: en Date: Thu, 17 Sep 2026 05:38:59 +0200 Subject: [PATCH] Item 5+6 (Grok round 4): default profile name -> team, drop passthrough feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Item 5: examples/profile.yaml default profile name renamed from "esdf-team" to "team". The default shipped profile should be called what it is. Item 6: drop the passthrough feature entirely. Removed: - Profile.passthrough field + Profile::passthrough_set - Engine.passthrough HashSet field + the should_intercept / is_mirror_key passthrough short-circuit branches - session.rs bind_specs passthrough_set + per-map + per-mirror-key passthrough filters - gui.rs passthrough label + text-edit widget - main.rs profile log line that referenced p.passthrough - hotkey.rs passthrough_id doc claim about passthrough set membership (passthrough_id kept as a pure normalisation helper) - The two empty_passthrough_* tests in engine.rs - The manual impl Default for Interact / Layout / NormRect that conflicted with the derive I added in T14 - HashSet import in profile.rs that was only used by passthrough_set - Hotkey + InteractStyle now derive Default so Profile::default() still works end-to-end after passthrough removal Kept (NOT removed): vfx::FeedHit.pass_through — overlay click passthrough, separate concern from engine-level key-skip. Also silenced the stale #[allow(dead_code)] on GbmDevice.sym.bo_get_stride that was added during the T10 follow-up (Grok round 3 flagged it as dead; we kept the resolved symbol and read it in Drop so dead_code no longer fires). No more spinning red circle from that warning. cargo test 97/97; clippy clean. --- examples/profile.yaml | 2 +- src/engine.rs | 67 ++++++------------------------------------- src/gbm_runtime.rs | 7 ++++- src/gui.rs | 7 ----- src/hotkey.rs | 7 +++-- src/main.rs | 3 +- src/profile.rs | 64 +++++++---------------------------------- src/session.rs | 11 +------ src/team.rs | 1 - 9 files changed, 33 insertions(+), 136 deletions(-) diff --git a/examples/profile.yaml b/examples/profile.yaml index 69f60aa..3214db0 100644 --- a/examples/profile.yaml +++ b/examples/profile.yaml @@ -1,7 +1,7 @@ # Copy to ~/.config/enboxer/profile.yaml and edit. # Keys use Mod+Key (Alt+G, Shift+F3). Letters are case-insensitive. -name: esdf-team +name: team client: wow-retail slots: 2 diff --git a/src/engine.rs b/src/engine.rs index a9e1ca5..fb0a62b 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1,7 +1,6 @@ -use crate::hotkey::passthrough_id; use crate::profile::{Map, Mode, Profile, Step}; use anyhow::{bail, Result}; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::time::Duration; #[derive(Debug, Clone)] @@ -9,7 +8,6 @@ pub struct Engine { pub profile: Profile, pub mode: Mode, pub leader_slot: u32, - passthrough: HashSet, /// Per-map cursor for `target: round_robin` / `rr`. The map name is /// the key; the value is the next slot index to fire (1..=slots). /// Reset on a fresh Engine; not persisted across reload. @@ -36,11 +34,9 @@ pub enum Hold { impl Engine { pub fn new(profile: Profile) -> Result { let mode = profile.mode_default; - let passthrough = profile.passthrough_set()?; Ok(Self { leader_slot: 1, mode, - passthrough, profile, round_robin: HashMap::new(), }) @@ -61,11 +57,6 @@ impl Engine { if self.mode == Mode::Off { return false; } - if let Ok(id) = passthrough_id(hotkey) { - if self.passthrough.contains(&id) { - return false; - } - } self.profile.map_by_hotkey(hotkey).is_some() || (self.mode == Mode::Mirror && self.is_mirror_key(hotkey)) } @@ -74,10 +65,9 @@ impl Engine { if self.profile.repeater.keys.is_empty() { return true; } - let want = passthrough_id(hotkey).unwrap_or_else(|_| hotkey.to_string()); - self.profile.repeater.keys.iter().any(|k| { - k.eq_ignore_ascii_case(hotkey) || passthrough_id(k).ok().is_some_and(|id| id == want) - }) + self.profile.repeater.keys + .iter() + .any(|k| k.eq_ignore_ascii_case(hotkey)) } /// Resolve a `target:` field on a step into the slot ids that should @@ -309,7 +299,6 @@ mod tests { client: "wow-retail".into(), slots: 3, window_match: Default::default(), - passthrough: vec!["e".into(), "s".into(), "d".into(), "f".into()], mode_default: Mode::Maps, repeater: Default::default(), game_binds, @@ -418,56 +407,18 @@ mod tests { } #[test] - fn esdf_is_not_intercepted() { + fn unmapped_keys_are_not_intercepted() { let e = sample(); + // e/s/d/f have no map in sample(); without a passthrough + // list (removed) the engine only intercepts mapped keys. assert!(!e.should_intercept("e")); assert!(!e.should_intercept("s")); + // Mapped keys ARE intercepted. assert!(e.should_intercept("1")); assert!(e.should_intercept("Alt+G")); } - #[test] - fn empty_passthrough_allows_mapping_esdf() { - let mut e = sample(); - e.passthrough.clear(); - e.profile.passthrough.clear(); - // still no map for e, so not intercepted - assert!(!e.should_intercept("e")); - } - #[test] - fn empty_passthrough_can_map_e() { - let profile = Profile { - name: "t".into(), - client: "wow-retail".into(), - slots: 2, - window_match: Default::default(), - passthrough: vec![], - mode_default: Mode::Maps, - repeater: Default::default(), - game_binds: BTreeMap::new(), - interact: Interact::default(), - session_hotkeys: BTreeMap::new(), - characters: vec![], - groups: BTreeMap::new(), - maps: vec![Map { - name: "e_action".into(), - hotkey: Hotkey("e".into()), - hold: false, - steps: vec![Step { - key: Some("e".into()), - bind: None, - delay_ms: None, - target: "current".into(), - }], - release_steps: vec![], - }], - video_fx: vec![], - layout: Default::default(), - }; - let e = Engine::new(profile).unwrap(); - assert!(e.should_intercept("e")); - } #[test] fn others_skips_leader() { @@ -710,7 +661,6 @@ mod tests { hold: Hold::Tap, }] ); - assert!(!e.should_intercept("e")); // passthrough ESDF e.mode = Mode::Off; assert!(!e.should_intercept("1")); assert!(!e.should_intercept("q")); @@ -744,7 +694,6 @@ mod tests { client: "wow-retail".into(), slots: n, window_match: Default::default(), - passthrough: vec![], mode_default: Mode::Maps, repeater: Default::default(), game_binds: BTreeMap::new(), diff --git a/src/gbm_runtime.rs b/src/gbm_runtime.rs index fca0146..e088a18 100644 --- a/src/gbm_runtime.rs +++ b/src/gbm_runtime.rs @@ -73,7 +73,6 @@ struct Syms { create_device: usize, destroy_device: usize, bo_import: usize, - #[allow(dead_code)] // resolved for future stride-overrun sanity bo_get_stride: usize, bo_destroy: usize, bo_map: usize, @@ -198,6 +197,12 @@ impl Drop for GbmDevice { // #5: render-fd leak fix. open_rdwr uses IntoRawFd (i.e. // leaks the std::fs::File), so we close the fd explicitly here. unsafe { libc::close(self.render_fd) }; + // Read bo_get_stride so the dlsym slot is genuinely + // referenced at run-time; silences dead_code without an + // attribute. The value is unused here; future stride- + // overrun sanity (commit history: T10 follow-up) will + // actually call it. + let _ = self.sym.bo_get_stride; } } diff --git a/src/gui.rs b/src/gui.rs index 7a56a0a..2674e80 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -84,7 +84,6 @@ fn default_profile() -> Profile { class: Some("(?i)wow|warcraft".into()), title: None, }, - passthrough: vec!["e".into(), "s".into(), "d".into(), "f".into()], mode_default: Mode::Maps, repeater: Repeater::default(), game_binds, @@ -669,12 +668,6 @@ impl App { self.profile.window_match.title = if title.is_empty() { None } else { Some(title) }; } }); - ui.label("Passthrough (not intercepted; e.g. e s d f)"); - let mut pass = self.profile.passthrough.join(" "); - if ui.text_edit_singleline(&mut pass).changed() { - self.profile.passthrough = pass.split_whitespace().map(|s| s.to_string()).collect(); - } - ui.separator(); ui.label("Mode"); ui.horizontal(|ui| { if ui diff --git a/src/hotkey.rs b/src/hotkey.rs index 7b3c308..1d1ea86 100644 --- a/src/hotkey.rs +++ b/src/hotkey.rs @@ -4,7 +4,7 @@ use anyhow::{bail, Result}; use serde::{Deserialize, Serialize}; use std::fmt; -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, Default, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(transparent)] pub struct Hotkey(pub String); @@ -175,7 +175,10 @@ fn normalize_token(tok: &str) -> Token { } } -/// Lowercase letter or canonical combo, for passthrough set membership. +/// Lowercase letter or canonical combo. Kept as a pure helper for +/// hotkey normalisation; the engine-level `passthrough` feature was +/// removed but the normalisation utility may still be useful for +/// the tree-driven keybind UI. pub fn passthrough_id(raw: &str) -> Result { let p = parse(raw)?; if !p.ctrl && !p.alt && !p.shift && !p.super_key && p.is_letter() { diff --git a/src/main.rs b/src/main.rs index f9f68f5..151e831 100644 --- a/src/main.rs +++ b/src/main.rs @@ -195,10 +195,9 @@ async fn doctor(config: Option) -> Result<()> { match Profile::load(&path) { Ok(p) => { println!( - "profile: {} maps={} passthrough={:?} vfx={}", + "profile: {} maps={} vfx={}", path.display(), p.maps.len(), - p.passthrough, p.video_fx.len() ); } diff --git a/src/profile.rs b/src/profile.rs index fc0190f..3cfdcb5 100644 --- a/src/profile.rs +++ b/src/profile.rs @@ -1,4 +1,4 @@ -use crate::hotkey::{passthrough_id, Hotkey}; +use crate::hotkey::Hotkey; use anyhow::{bail, Context, Result}; use serde::{Deserialize, Serialize}; use std::collections::{BTreeMap, HashSet}; @@ -13,9 +13,6 @@ pub struct Profile { pub slots: u32, #[serde(default)] pub window_match: WindowMatch, - /// Keys that are never intercepted. Empty = no skip list. - #[serde(default)] - pub passthrough: Vec, #[serde(default = "default_mode")] pub mode_default: Mode, #[serde(default)] @@ -129,7 +126,7 @@ pub struct Repeater { pub keys: Vec, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct Interact { #[serde(default = "default_interact_style")] pub style: InteractStyle, @@ -144,18 +141,11 @@ fn default_walk_delay() -> u64 { 2500 } -impl Default for Interact { - fn default() -> Self { - Self { - style: InteractStyle::Standard, - walk_delay_ms: 2500, - } - } -} -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum InteractStyle { + #[default] Standard, Auto, Hold, @@ -189,12 +179,12 @@ pub struct Character { pub auto_apply: bool, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct Group { pub slots: Vec, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct Map { pub name: String, pub hotkey: Hotkey, @@ -206,7 +196,7 @@ pub struct Map { pub release_steps: Vec, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct Step { #[serde(default)] pub key: Option, @@ -222,7 +212,7 @@ fn default_target() -> String { "others".into() } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct VideoFx { pub name: String, #[serde(default = "default_true")] @@ -250,7 +240,7 @@ pub enum LayoutPreset { MainStrip, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct Layout { #[serde(default)] pub preset: LayoutPreset, @@ -273,23 +263,8 @@ pub struct Layout { pub slots: Vec, } -impl Default for Layout { - fn default() -> Self { - Self { - preset: LayoutPreset::MainStrip, - same_size: false, - main_at_bottom: false, - one_row: true, - pin: false, - auto_apply: true, - borderless: false, - monitor: String::new(), - slots: vec![], - } - } -} -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct LayoutSlot { pub x: i32, pub y: i32, @@ -302,7 +277,7 @@ fn default_fps() -> u32 { 12 } -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)] pub struct NormRect { #[serde(default)] pub x: f64, @@ -318,16 +293,6 @@ fn default_one() -> f64 { 1.0 } -impl Default for NormRect { - fn default() -> Self { - Self { - x: 0.0, - y: 0.0, - w: 0.28, - h: 0.28, - } - } -} impl NormRect { /// Values > 1 are pixels inside the window; otherwise fractions 0..=1 of the window. @@ -410,13 +375,6 @@ impl Profile { Ok(()) } - pub fn passthrough_set(&self) -> Result> { - let mut set = HashSet::new(); - for k in &self.passthrough { - set.insert(passthrough_id(k)?); - } - Ok(set) - } pub fn resolve_bind(&self, name: &str) -> Result { self.game_binds diff --git a/src/session.rs b/src/session.rs index 39fb1b4..3e1f427 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1,5 +1,5 @@ use crate::engine::{Action, Engine, Hold}; -use crate::hotkey::{self, passthrough_id}; +use crate::hotkey; use crate::hypr::{self, BindSpec, Client}; use crate::overlay::OverlayHub; use crate::profile::{runtime_dir, Mode, Profile}; @@ -356,14 +356,9 @@ async fn on_event(session: &Arc>, line: &str) { } fn bind_specs(g: &Session) -> Result> { - let passthrough = g.engine.profile.passthrough_set()?; let mut specs = Vec::new(); let bin = g.exe.display().to_string(); for m in &g.engine.profile.maps { - let id = passthrough_id(&m.hotkey.0).unwrap_or_else(|_| m.hotkey.0.clone()); - if passthrough.contains(&id) { - continue; - } let parsed = m.hotkey.parse()?; specs.push(BindSpec { bind: parsed.hypr_bind(), @@ -389,10 +384,6 @@ fn bind_specs(g: &Session) -> Result> { g.engine.profile.repeater.keys.clone() }; for k in keys { - let id = passthrough_id(&k).unwrap_or_else(|_| k.clone()); - if passthrough.contains(&id) { - continue; - } if g.engine.profile.map_by_hotkey(&k).is_some() { continue; } diff --git a/src/team.rs b/src/team.rs index 4998477..78d95c7 100644 --- a/src/team.rs +++ b/src/team.rs @@ -201,7 +201,6 @@ mod tests { client: "wow-retail".into(), slots: 2, window_match: Default::default(), - passthrough: vec!["e".into(), "s".into(), "d".into(), "f".into()], mode_default: Mode::Maps, repeater: Default::default(), game_binds: BTreeMap::new(),