diff --git a/README.md b/README.md index c757a40..2406b90 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ retired words are inventoried in | Left click | Move cursor; on a rack, select it (Bevy). Shift-click toggles. Drag marquee multi-selects. | | `SPACE` / `p` | Pause / resume time | | `+` / `-` | Simulation speed | -| `Enter` / `e` / `a` | Open the context menu. In Bevy, the hovered map tile wins; otherwise use the selected machine or cursor tile. Right-click opens the hovered tile. | +| `Enter` / `e` / `a` | Open the context menu at the keyboard cursor without moving it. In Bevy, right-click moves focus to the pointed tile and opens its menu. | | Hover a rack (menu closed): `1`–`3` | Instant mode: WORK / THINK / LIE (numpad too) — no menu | | Hover or select a rack (menu closed): `i` | Cycle intensity: light / medium / hard — no menu | | Hover a rack (menu closed): `5`–`9` | Nth committed action on that rack; controls are excluded | diff --git a/crates/misaligned-bevy/src/main.rs b/crates/misaligned-bevy/src/main.rs index 2020887..860e17e 100644 --- a/crates/misaligned-bevy/src/main.rs +++ b/crates/misaligned-bevy/src/main.rs @@ -960,24 +960,13 @@ impl Game { } } - /// Open the context menu at the focused map tile. Unlike the machine-only - /// hotkeys, a context menu may target any anchor: a switch, camera, or - /// person must not fall through to a stale selected rack. - fn open_menu_on_hover_or_selection_or_cursor( - &mut self, - pointer: Option, - hover: Option<(i32, i32)>, - ) { - if let Some((x, y)) = hover { - self.set_cursor(x, y); - self.open_menu(Anchor::Tile { x, y }, pointer); - } else if let Some((_, x, y)) = self.primary_machine_tile(None) { - self.set_cursor(x, y); - self.open_menu(Anchor::Tile { x, y }, pointer); - } else { - let (x, y) = (self.cursor_x, self.cursor_y); - self.open_menu(Anchor::Tile { x, y }, pointer); - } + /// Open the context menu at the keyboard focus without moving it. + /// Pointer focus belongs to explicit pointer actions (click/right-click): + /// a keyboard Enter must never retarget attention to wherever the mouse + /// happened to rest. + fn open_menu_on_cursor(&mut self) { + let (x, y) = (self.cursor_x, self.cursor_y); + self.open_menu(Anchor::Tile { x, y }, None); } /// `5`–`9`: Nth root one-shot on the hover/primary machine (menu closed). @@ -4484,9 +4473,9 @@ fn handle_input( return; } if kb.just_pressed(KeyCode::Enter) || kb.just_pressed(KeyCode::KeyE) { - // The pointer tile is the focus for every anchor, not just compute - // racks. Selection is a fallback only when the pointer is off-map. - game.open_menu_on_hover_or_selection_or_cursor(pointer, grid); + // Keyboard focus is the reticule. Mouse hover must not turn Enter + // into an implicit cursor move; right-click is the pointer path. + game.open_menu_on_cursor(); game.drain(); return; } @@ -5732,11 +5721,10 @@ mod menu_focus_tests { use super::{Anchor, Game}; #[test] - fn hovered_switch_menu_beats_a_selected_core_machine() { - // context-menu.md: the menu belongs to the focused anchor. The - // switch is a device rather than a compute machine, so routing Enter - // through the machine hotkey resolver used to jump back to this - // selected core instead. + fn keyboard_menu_keeps_cursor_focus_despite_pointer_or_selection_state() { + // context-menu.md: Enter belongs to keyboard focus. Pointer hover is + // intentionally absent from this path, and stale machine selection + // must not move the reticule either. let mut game = Game::new(); game.selected_machines.insert(game.sim.core.host_machine); let (x, y) = game @@ -5745,8 +5733,9 @@ mod menu_focus_tests { .device_named("switch") .map(|device| (device.x, device.y)) .expect("opening switch is known"); + game.set_cursor(x, y); - game.open_menu_on_hover_or_selection_or_cursor(None, Some((x, y))); + game.open_menu_on_cursor(); assert_eq!((game.cursor_x, game.cursor_y), (x, y)); assert_eq!( diff --git a/wiki/interface/bevy.md b/wiki/interface/bevy.md index 3460302..fc298b0 100644 --- a/wiki/interface/bevy.md +++ b/wiki/interface/bevy.md @@ -163,12 +163,11 @@ controls table), plus zoom, sidebar scrolling, and the render flip: state never suppresses unrelated controls. This keeps macOS native overlays or focus transitions from turning a stale Command state into a temporary keyboard lockout. -- **Context menu** — right-click or Enter/`e` opens the context menu at the - focused map tile under the pointer, listing `Sim::available_actions` for - that anchor with the same compact choices and order as the terminal. The pointer - wins over machine selection even when the anchor is a switch or another - non-rack; only with no map pointer does Enter/`e` fall back to the selected - machine, then the keyboard cursor. Rows render the verb or dial state only. +- **Context menu** — right-click moves the cursor to the pointed map tile and + opens its context menu. Enter/`e` opens the keyboard cursor's tile without + moving it; a resting pointer or stale machine selection cannot retarget the + key. Both paths list `Sim::available_actions` for that anchor with the same + compact choices and order as the terminal. Rows render the verb or dial state only. Cost, signature forecasts, inline blocked explanations, literal control tags, and repeated key-help are absent from the card; agent mode keeps full descriptors, and blocked reasons narrate on attempt. Persistent settings, @@ -197,7 +196,7 @@ controls table), plus zoom, sidebar scrolling, and the render flip: reticule. `i` cycles light / medium / hard intensity on that rack; `5`–`9` fire its Nth committed action (controls do not occupy shortcut slots); - `Enter` / `e` open the hovered tile's menu. Drag a + `Enter` / `e` open the keyboard cursor's menu without moving it. Drag a marquee or shift-click to multi-select; with no hover rack, `1`–`3` and `i` assign the selection (or the keyboard cursor's machine). `Esc` clears selection. No panel-open keys — status lives on the rail; verbs still come diff --git a/wiki/interface/context-menu.md b/wiki/interface/context-menu.md index 398ca7e..4233c57 100644 --- a/wiki/interface/context-menu.md +++ b/wiki/interface/context-menu.md @@ -52,6 +52,10 @@ Status note: implemented 2026-07-07 on the context-menu worktree (all 2026-07-10 Bevy focus repair: Enter/`e` opens the hovered map tile's menu before consulting machine selection, so a switch or other non-machine anchor never snaps attention back to the selected core. + 2026-07-11 keyboard-focus correction: Bevy Enter/`e` opens the attention + reticule's tile without moving it. Pointer focus belongs to explicit mouse + actions (click/right-click); a resting pointer or stale machine selection + cannot retarget a keyboard command. 2026-07-10 hover-grammar amendment: an owned computer under the Bevy pointer exposes the bare `WORK / THINK / LIE` line beside the machine while the full context menu is closed. The current mode is bone-bright and the @@ -162,13 +166,13 @@ is status and telemetry only. Dials, persistent controls, scheme state, and automation policies do not occupy these slots. Disabled action rows still fire so the reason narrates. - **Context-menu focus is anchor-generic, not machine-only.** In Bevy, - `Enter` / `e` first opens the tile under the map pointer, whether it holds - a switch, camera, person, rack, or bare tile; it moves the cursor there. - Only when the pointer is outside the map does Bevy fall back to the primary - machine selection, then the keyboard cursor tile. Terminal has no pointer, - so `Enter` / `a` / `e` use its selection-or-cursor path. While a menu is - open, number keys select rows as before; Esc clears the selection only - when the menu is closed. + `Enter` / `e` opens the keyboard cursor's tile without changing the cursor. + Right-click is the distinct pointer-focus path: it moves the cursor to the + pointed tile and opens that tile's menu. A resting pointer and a stale + machine selection never retarget Enter. Terminal has no pointer, so + `Enter` / `a` / `e` use its selection-or-cursor path. While a menu is open, + number keys select rows as before; Esc clears the selection only when the + menu is closed. ## Player surface @@ -183,11 +187,10 @@ is status and telemetry only. machine mode fallback, and earned off-map people; a known device's tile (or the switch) carries digital and ledger/flow verbs; a visible person on a tile carries their social verbs. -- **Bevy:** right-click or Enter/`e` opens the menu on the focused map tile - under the pointer; this wins over a stale machine selection. With no map - pointer, Enter/`e` falls back to the primary selected machine, then the - keyboard cursor. It has the same content, order, and dial chrome; click to - execute or open a dial; esc/click-away closes. +- **Bevy:** right-click moves focus to the pointed map tile and opens its menu; + Enter/`e` opens the keyboard cursor's tile without moving focus. It has the + same content, order, and dial chrome; click to execute or open a dial; + esc/click-away closes. The compact card is narrow, has no instructional footer, and shares the same verb-only rows as terminal. Selection is a solid amber wash with a leading `>` (terminal reverse-video parity). Selection hotkeys above apply with the menu @@ -288,8 +291,10 @@ made a three-word decision look dirty, slow, and administrative. attempted; every previously key-bound anchor action is reachable through it. 4. Bevy renders the same compact menu on right-click/Enter with identical - content and order. Human rows contain no cost, signature forecast, inline - disabled reason, literal control tag, or repeated key-help footer. + content and order. Enter never changes cursor position from pointer hover + or machine selection; right-click explicitly retargets to its pointed tile. + Human rows contain no cost, signature forecast, inline disabled reason, + literal control tag, or repeated key-help footer. 5. Agent mode `actions` lists the same descriptors (stable format, documented); the act-one integration test still passes driven through existing verbs. diff --git a/wiki/log/2026-07-11-enter-keeps-focus.md b/wiki/log/2026-07-11-enter-keeps-focus.md new file mode 100644 index 0000000..c063cfc --- /dev/null +++ b/wiki/log/2026-07-11-enter-keeps-focus.md @@ -0,0 +1,26 @@ +# Enter keeps keyboard focus + +``` +Type: log +``` + +- **Finding:** In Bevy, pressing Enter used the resting mouse pointer as its + target. Opening a menu could therefore move the attention reticule one tile + down and right (or anywhere else under the pointer), despite Enter being a + keyboard-focus command. +- **Changed:** Enter/`e` now opens the keyboard cursor's tile without changing + cursor position. Right-click remains the explicit pointer-focus path and + moves attention to its pointed tile before opening the menu. A focused test + pins Enter against both stale machine selection and implicit pointer focus. +- **Corpus:** Amended `interface/context-menu.md` and updated the Bevy/README + current-state descriptions. This is a correction to the existing + action-focus contract, not a new world mechanic. +- **Checks:** focused `menu_focus_tests` pass; `./tools/check.sh --frontend` + passes (10 + 3 + 17 tests, Clippy, and all documentation gates). In an + observed paused Bevy run, the mouse was deliberately parked away from the + host reticule: Enter opened the host menu while the FOCUS card remained + pixel-identical before/after; the process then exited cleanly via Esc + q. + +Defense: `wiki/interface/context-menu.md` acceptance criterion 4 now requires +keyboard Enter to preserve cursor focus while right-click alone retargets from +the pointer. diff --git a/wiki/log/DEVLOG.md b/wiki/log/DEVLOG.md index d8fe5cb..813ef86 100644 --- a/wiki/log/DEVLOG.md +++ b/wiki/log/DEVLOG.md @@ -26,6 +26,11 @@ add or amend a session log, then re-run the generator. - Intent: Replace the tiny four-bay server-room vignette with the pressure the fiction promises: Rack 3 buried inside an operating Foundation data hall. Make nearby capacity physically explicit and epistemically honest without granting it to the player, then make territorial control a c... - Log: [wiki/log/2026-07-11-foundation-data-hall.md](2026-07-11-foundation-data-hall.md) +## 2026-07-11 - Enter keeps keyboard focus + +- Intent: (see session log) +- Log: [wiki/log/2026-07-11-enter-keeps-focus.md](2026-07-11-enter-keeps-focus.md) + ## 2026-07-10 - Design capture: WORK / THINK / LIE - Intent: Cameron resolved the [OPEN] Concealment placement question: the delegation grammar is three verbs, not two. Concealment is LIE — its own face, the cover-up.