enBoxer/CHANGELOG.md
en 6028987a6e Overlay: set_margin order + click handler no longer kills the badge
- set_margin (wayland_layer.rs:234): correct arg order to
  (top, right, bottom, left). The previous code passed rect.x as
  the right margin, a no-op under TOP+LEFT anchoring, so the
  overlay's x offset was silently dropped. Comment updated to
  document the protocol's true shape.

- click handler (wayland_layer.rs:466): drop 'state.exited = true'
  after send_swap. Flipping exited destroyed the badge but left
  OverlayHub.by_slot still holding the slot, so the hub refused to
  respawn it. The compositor's zwlr_layer_surface::Closed event
  is the only path that drives thread teardown — the click now
  just fires the swap IPC and returns.

- CHANGELOG entries.

cargo test 96+/0; clippy clean.
2026-09-16 05:58:27 +02:00

84 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Changelog
## 0.1.0 — unreleased
- Rust CLI daemon: `enboxer run|press|status|macros|doctor`
- YAML profile: maps, targets (`current` / `others` / `all` / groups), `game_binds`
- Configurable `passthrough` (empty by default; example profile uses ESDF)
- Hyprland 0.56 Lua binds installed only while a managed game or VFX overlay is focused
- Key delivery via `hl.dsp.send_shortcut` / `send_key_state` (no game injection)
- Stock loot map: assist → CTM on → Interact with Target once → delay → CTM off
- Video FX: `grim` region capture, overlay viewer, hover pass-through to source slot
- Unit tests for hotkey parse, passthrough, targets, loot sequence, example profile load
- Bind IPC line no longer duplicated `ipc` (Hyprland hotkeys actually reach the daemon)
- Video FX overlay is `mpv` (`--wayland-app-id=enboxer-vfx`) with JSON reload; `grim` capture
- `enboxer run` clears binds on ctrl-c; empty `window_match` matches nothing
- Live check: `send_shortcut` to an unfocused XWayland window; overlay window class `enboxer-vfx`
- Per-character `assist_key` / `follow_key`; map steps using `bind: assist|follow` resolve to the current main's keys
- Layout wizard `borderless` toggle installs a Hyprland `window_rule` (rounding 0, border_size 0) on `run`
- Layout page: drag canvas over the monitor rectangle; tile moves clamp to the monitor bounds
- T8: clipboard IPC verb `clipboard` reads `wl-paste` / `xclip` and delivers Ctrl+V to every non-leader captured slot; GUI button on Session page; routing plan unit-tested
- T11: named-profiles list in File menu (`Load named…` submenu) with Refresh; listing helper unit-tested against a tempdir
- T12: unit test for `type_to_others` routing (`others_clients` helper, excludes leader, per-char × per-slot plan) and for `apply_layout` short-circuiting when `ENBOXER_ALLOW_LAYOUT` is unset
- T9 (real): `src/wayland_layer.rs``zwlr_layer_shell_v1` Wayland client with shm-backed buffers, 3×5 bitmap digit glyphs, `wl_pointer` click routing; per-slot `OverlayHandle` via `OverlayHub` in `session::run`. Live path gated behind `ENBOXER_ENABLE_OVERLAY=1`; `cargo test` does not connect to Wayland
- T10 (real): `src/toplevel_export.rs``zwlr_export_dmabuf_unstable_v1` Wayland client; per-frame format negotiation (ARGB8888 / XRGB8888), synthetic-PNG fallback for tests. Live path gated behind `ENBOXER_ENABLE_TOPLEVEL=1`; `gbm_bo_map` is documented as the upgrade step for actual pixel reads
- T13: mirror-mode mouse click broadcast — `hypr::deliver_click` posts compositor pointer events to every non-leader captured slot; press-and-hold guard deferred
- T14: round-robin bind target (`round_robin` / `rr`) — rotates through ALL slots including the leader, in slot-number order, wrapping; per-map cursor
- T15: Teams + Lutris launcher. `src/team.rs` (Team, list_teams, teams_dir, current_team), `src/lutris.rs` (LutrisGame parser, `load_all` with bad-YAML tolerance), `src/launcher.rs` (SpawnPlan merging Lutris config with per-character wine-prefix override). GUI: Teams menu (New / Switch / Refresh / Show / Delete) and Launch menu (per-character + Launch all); Lutris picker visible only in the New-team flow. Direct Wine spawn — never calls `lutris` CLI
- `game_binds.interact` example uses **Alt+J** (Master's request). Interact with Target is a built-in WoW keybind; enBoxer just routes the keystroke.
- `docs/MACROS.md` rewritten for current retail (The War Within era, 2026): rename "CTM" → Auto-Interact (the CVar), document Alt+J for Interact with Target, document per-character Assist / Follow macro override, add optional Pet Attack / Target Last Target keybinds.
## Unreleased — Interact chain (ISBoxer-style mapped key)
- **Smart interact shortcut.** A step with `bind: interact` now expands at
compile time into the full CTM-on → Interact-with-Target → sleep
`walk_delay_ms` → CTM-off chain, driven by `profile.interact` (`style`
+ `walk_delay_ms`). One user keypress, four keystrokes dispatched to
every captured slot. Styles:
- `standard` (default): chain runs, CTM ends off.
- `auto`: chain runs, CTM stays on (toggle via `ctm_off` later).
- `hold`: press fires CTM-on + Alt+J; put `bind: ctm_off` in
`release_steps` to fire it on hotkey release.
- The example `loot` map (Alt+G) and `interact` map (Alt+I) now use the
shortcut. A `loot_manual` map (Ctrl+Alt+G) exercises the explicit
chain for users who want per-step control.
- New tests: `interact_smart_shortcut_standard_emits_full_sequence`,
`interact_smart_shortcut_auto_emits_two_no_tail`,
`interact_smart_shortcut_hold_emits_press_only`. 92/92 unit tests pass;
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.
- **Security:** IPC runtime dir is now `chmod 0o700` and the Unix socket is
`chmod 0o600` immediately after `UnixListener::bind`. Any local user with
read access could speak our IPC protocol (`Command::Type` etc.); this is
the cheapest defense. Helpers: `profile::chmod_runtime_dir()` and
`profile::chmod_socket(path)`.
- **GUI:** New-team wizard now pads `profile.characters` to `slots` before
stamping `lutris_game`. A wizard with 5 members and an empty character
list previously saved a team with zero Launch rows; it now fills the
rows with `Character::default()` and applies the Lutris game to each.
- **GUI:** `arm_auto_apply` now waits for a client matching
`profile.window_match.class` / `.title` regexes before firing
`layout-apply`, instead of firing on the first non-empty client list.
With no patterns configured it still requires a non-empty class on the
matched client, so existing profiles behave the same. This prevents
`layout-apply` against the desktop when only a terminal (or any
unrelated window) is open.
- **Profile:** `Character` derives `Default` (needed for the padding).
- **Overlay:** `set_margin` arguments corrected to `(top, right, bottom,
left)`. The previous `(rect.y, rect.x, 0, 0)` passed `rect.x` as the
*right* margin, which is a no-op under TOP+LEFT anchoring — so the
overlay's x offset was silently dropped. Now `(y, 0, 0, x)` which
pushes the surface down by `y` and right by `x`.
- **Overlay:** Left-click on a slot no longer sets `state.exited = true`.
Doing so dropped the badge and left `OverlayHub.by_slot` still
holding the slot, so the hub refused to respawn it. The compositor's
`zwlr_layer_surface::Closed` event is the only path that tears the
live thread down — click just sends the swap IPC and returns.