---
status: resolved
regression: true
trigger: "search-steals-focus — When any key is typed, the search bar steals focus even when: (a) a modal dialog is in the foreground, or (b) a modifier key is held (Ctrl, Alt, or Win)."
created: 2026-04-06T00:00:00Z
updated: 2026-04-06T00:01:00Z
symptoms_prefilled: true
---

## Current Focus

hypothesis: CONFIRMED — When a modal closes, focus is left on the modal's FocusScope or TextInput (which are either destroyed or hidden), not returned to global-keys. global-keys only receives key events when it has focus. Since the click-outside TouchArea (dashboard.slint ~line 472) is the only path that restores focus to global-keys, typing only works again after clicking in the cards area.
test: Verified by reading: settings-modal uses `if root.modal-open` with `modal-focus := FocusScope { init => { self.focus(); } }` — when modal-open goes false, the whole tree is destroyed with no focus handoff. Lookup modal uses `visible:` so elements persist but focus is on search-input inside. Neither path calls global-keys.focus() on close.
expecting: N/A
next_action: In dashboard.slint, add `changed settings-modal-open` and `changed lookup-modal-open` handlers on the root element that call `global-keys.focus()` whenever the property transitions to false.

## Symptoms

expected: Search bar should only capture keystrokes when no modal is open and no modifier keys are held. Modifier combos (Ctrl+C, Alt+Tab, etc.) should not trigger search focus. Modals should keep focus.
actual: Any keypress — including modified keys and keys while a modal is open — causes the search bar to steal focus and capture the input.
errors: No errors, purely a UX/focus-handling bug.
reproduction: 1) Open the app, 2) Press Ctrl+anything or Alt+anything — search bar takes focus. OR: Open any modal dialog, type anything — search bar steals focus from the modal.
started: Discovered just now. May have always been this way.

## Eliminated

(none yet)

## Evidence

- timestamp: 2026-04-06T00:01:00Z
  checked: dashboard.slint global-keys FocusScope key-pressed handler (lines 318-360)
  found: The character-pressed branch at line 349 only checks `!root.text-input-focused` plus filtering out a few key constants. It does NOT check event.modifiers.control, event.modifiers.alt, or event.modifiers.meta, and does NOT check lookup-modal-open or settings-modal-open.
  implication: Any printable keypress — regardless of held modifiers or modal state — calls root.character-pressed(event.text), which in Rust (main.rs:2433) appends to search text, sets search_focused=true, and calls focus-search-end(). This is the direct cause of the bug.

- timestamp: 2026-04-06T00:01:00Z
  checked: main.rs on_character_pressed handler (lines 2433-2448)
  found: Handler unconditionally appends character to search text and steals focus. No modal or modifier checks here either.
  implication: The Slint-side fix is the right place — the Rust handler is correct given that it only fires when the Slint callback fires. Fix belongs in the dashboard.slint condition guard.

- timestamp: 2026-04-06T01:00:00Z
  checked: settings-modal.slint — full file read
  found: The `if root.modal-open : Rectangle` block contains `modal-focus := FocusScope { init => { self.focus(); } }`. When modal-open becomes false, the entire `if`-branch tree is destroyed. In Slint, destroying a focused element leaves focus in a dead zone — it does NOT automatically return to the previously focused element.
  implication: After settings modal closes (cancel or save), global-keys has no focus. The click-outside TouchArea in dashboard.slint (line 472) is the only way to restore it, which matches the reported symptom: "works after clicking outside the cards view area."

- timestamp: 2026-04-06T01:00:00Z
  checked: lookup-modal.slint + dashboard.slint lookup-modal-inst wiring
  found: Lookup modal uses `visible: root.lookup-modal-open` (not `if`), so elements persist. The search-input TextInput gets focused via search-focus-trigger. When the modal closes (via close-requested, item-selected, or create-confirmed), focus stays on the hidden search-input or in a dead zone.
  implication: Same dead-zone symptom for lookup modal as for settings modal.

- timestamp: 2026-04-06T01:00:00Z
  checked: dashboard.slint click-outside TouchArea (lines 472-482)
  found: This is the existing path that restores focus: `search-bar-inst.remove-focus(); global-keys.focus();`. It only fires when the user clicks in the card area (below y=60px, outside modal).
  implication: This confirms the fix direction: call `global-keys.focus()` in the modal-close callback handlers in dashboard.slint.

## Resolution

root_cause: Two distinct bugs, both in dashboard.slint:
  Bug 1 (original): global-keys FocusScope forwarded all printable keypresses to search without checking modifiers or modal state.
  Bug 2 (regression): When a modal closes, the focused element (modal's FocusScope or TextInput) is either destroyed (settings: `if modal-open`) or hidden (lookup: `visible:`). Slint does not automatically return focus to the previously focused element. global-keys only receives key events when it has focus, so typing was broken until the user clicked the click-outside TouchArea which calls global-keys.focus().
fix: Bug 1: Added modifier guards (!event.modifiers.control/alt/meta) and modal-open guards (!root.lookup-modal-open, !root.settings-modal-open) to the character-pressed branch in global-keys.
  Bug 2: Added `global-keys.focus()` calls in all modal-close callback handlers inside dashboard.slint: settings save-clicked, settings cancel-clicked, lookup close-requested, lookup item-selected, and lookup create-confirmed.
verification: cargo build -p app succeeded cleanly. Awaiting manual UX verification.
files_changed: ["crates/app/ui/dashboard.slint"]
