diff --git a/CHANGELOG.md b/CHANGELOG.md index c516559..3564dc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,3 +48,6 @@ clippy clean. - Docs: `docs/MACROS.md` "Smart interact shortcut" section, `docs/NOTES.md` callout, `examples/profile.yaml` updated with comments. + +> Note: After this change, `bind: "interact"` is a single Alt+J send (game_binds.interact). +> The full chain trigger is now `bind: "smart_interact"`. Examples and tests updated. diff --git a/docs/MACROS.md b/docs/MACROS.md index 94d4f36..646dda8 100644 --- a/docs/MACROS.md +++ b/docs/MACROS.md @@ -78,11 +78,11 @@ Do not mash. A second interact while they are still pathing is how characters ru If they stop short, raise `walk_delay_ms` (2500–4000), or use `interact.style: auto` (CTM stays on), or `interact.style: hold`. -## Smart interact shortcut (`bind: interact`) +## Smart interact shortcut (`bind: smart_interact`) The example profile's `loot` map (Alt+G) and `interact` map (Alt+I) both use a **smart shortcut**: a single user keypress fires the full chain (CTM on → Interact with Target → sleep `walk_delay_ms` → CTM off). It is what ISBoxer did with a "Mapped Key" — you press one key, the multibox software sends the whole chain. -In enBoxer the shortcut is `bind: interact` in a step: +In enBoxer the shortcut is `bind: smart_interact` in a step: ```yaml - name: loot @@ -90,7 +90,7 @@ In enBoxer the shortcut is `bind: interact` in a step: steps: - bind: assist target: others - - bind: interact # <-- smart shortcut + - bind: smart_interact # <-- smart shortcut target: others ``` diff --git a/docs/NOTES.md b/docs/NOTES.md index 2fe2f97..ca76309 100644 --- a/docs/NOTES.md +++ b/docs/NOTES.md @@ -40,7 +40,7 @@ Visible-pixel capture: `grim` (default). Overlay: `mpv --wayland-app-id=enboxer- ## Smart interact shortcut -`bind: interact` in any map step expands at compile time into the full chain +`bind: smart_interact` in any map step expands at compile time into the full chain (CTM on → Interact with Target → walk delay → CTM off), driven by `profile.interact` (`style` + `walk_delay_ms`). This is the ISBoxer Mapped Key analog — one user keypress, four keystrokes dispatched to every captured diff --git a/examples/profile.yaml b/examples/profile.yaml index 4279f9d..69f60aa 100644 --- a/examples/profile.yaml +++ b/examples/profile.yaml @@ -114,7 +114,7 @@ maps: steps: - bind: assist target: others - - bind: interact + - bind: smart_interact # full chain (use "interact" for a single Alt+J send) target: others - name: loot_manual # Same idea as `loot` but composed by hand. Pick this form if you want to @@ -127,7 +127,7 @@ maps: target: others - bind: ctm_on target: others - - bind: interact + - bind: interact # single Alt+J send (NOT the smart shortcut) target: others - delay_ms: 5000 - bind: ctm_off @@ -140,7 +140,7 @@ maps: steps: - bind: ctm_on target: others - - bind: interact + - bind: interact # single Alt+J send (NOT the smart shortcut) target: others release_steps: - bind: ctm_off diff --git a/src/engine.rs b/src/engine.rs index 8a8a213..a9e1ca5 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -205,11 +205,14 @@ impl Engine { out.push(Action::Sleep(Duration::from_millis(ms))); continue; } - // ISBoxer-style Mapped Key shortcut: `bind: "interact"` fires the - // full CTM-toggle + Interact-with-Target + (optional) wait + CTM-off - // chain driven by profile.interact (style + walk_delay_ms). + // ISBoxer-style Mapped Key shortcut: `bind: "smart_interact"` fires + // the full CTM-toggle + Interact-with-Target + (optional) wait + + // CTM-off chain driven by profile.interact (style + walk_delay_ms). // The user only pressed the map hotkey; the daemon composes the chain. - if step.bind.as_deref() == Some("interact") { + // For per-step control, use `bind: "interact"` to send a single + // Interact-with-Target keystroke (game_binds.interact = Alt+J) and + // compose ctm_on / ctm_off / walk_delay_ms yourself. + if step.bind.as_deref() == Some("smart_interact") { let slots = self.resolve_targets(&step.target, &map_name)?; let interact_key = self .profile @@ -352,7 +355,7 @@ mod tests { target: "others".into(), }, Step { - bind: Some("interact".into()), + bind: Some("smart_interact".into()), key: None, delay_ms: None, target: "others".into(), @@ -505,6 +508,37 @@ mod tests { } } + #[test] + fn interact_simple_sends_only_alt_j() { + // After the smart_interact split, `bind: "interact"` is a single + // Alt+J send (game_binds.interact = "g"). No CTM toggle, no sleep, + // no second send. Use this from manual chains or release_steps. + let mut e = sample(); + let map = crate::profile::Map { + name: "interact_simple".into(), + hotkey: Hotkey("Alt+U".into()), + hold: false, + steps: vec![crate::profile::Step { + key: None, + bind: Some("interact".into()), + delay_ms: None, + target: "others".into(), + }], + release_steps: vec![], + }; + e.profile.maps.push(map); + let acts = e.fire("Alt+U", Hold::Tap).unwrap(); + assert_eq!(acts.len(), 1, "exactly one action: {acts:?}"); + match &acts[0] { + Action::Send { key, slots, hold } => { + assert_eq!(key, "g"); + assert_eq!(*hold, Hold::Tap); + assert_eq!(slots, &vec![2, 3]); + } + other => panic!("expected Send, got {other:?}"), + } + } + #[test] fn interact_smart_shortcut_standard_emits_full_sequence() { // bind: "interact" should fire CTM-on, Interact with Target, @@ -518,7 +552,7 @@ mod tests { hold: false, steps: vec![crate::profile::Step { key: None, - bind: Some("interact".into()), + bind: Some("smart_interact".into()), delay_ms: None, target: "others".into(), }], @@ -555,7 +589,7 @@ mod tests { hold: false, steps: vec![crate::profile::Step { key: None, - bind: Some("interact".into()), + bind: Some("smart_interact".into()), delay_ms: None, target: "others".into(), }], @@ -585,7 +619,7 @@ mod tests { hold: true, steps: vec![crate::profile::Step { key: None, - bind: Some("interact".into()), + bind: Some("smart_interact".into()), delay_ms: None, target: "others".into(), }],