feat(rules): add address-bar focus lock/switch rule#29
Conversation
While a browser's address bar (omnibox) has keyboard focus, the user is typing a URL or a search, where a CJK input method is rarely wanted. This adds an optional rule that forces a chosen input source on address-bar focus, so typing web addresses lands in the right source. Detection is event-driven via Accessibility: an AXObserver on the frontmost browser watches focusedUIElementChanged, and the system-wide focused element is classified by AddressBarHeuristic — a per-engine, non-localized identifier (Chromium OmniboxViewViews, Safari WEB_BROWSER_ADDRESS_AND_SEARCH_FIELD, Firefox urlbar-input) confirmed by a chrome-vs-AXWebArea structural check. It mirrors FloatingAppMonitor and reuses the existing Accessibility grant; the permission-free core lock is untouched. Both a continuous "lock" and a one-shot "switch" are supported (some input methods cover both languages). There is no reverse restore: leaving the address bar re-resolves the standard URL/app/default rules rather than restoring a remembered source. When both the address bar and a URL rule apply, a user-configurable priority decides the winner, defaulting to address-bar-first. The rule is off by default and is per-device runtime state, so it is excluded from config backup/import (and preserved across import). The option lives in the URL Rules settings pane as labeled pop-up menus matching the macOS Settings style. Signed-off-by: Kevin Cui <bh@bugs.cc>
Summary by CodeRabbit
WalkthroughA new "Address-bar focus rule" feature is added across Possibly Related PRs
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches✨ Simplify code
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
Sources/LockIMEKit/AppMonitor/AddressBarFocusMonitor.swift (1)
89-94: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick winAlign
stop()behavior with the protocol’s documented callback contract.
AddressBarFocusMonitoringdocuments that stopping observation emitsonChange(false)(seeSources/LockIMEKit/AppMonitor/AddressBarFocusMonitoring.swift, Line 7-10), butstop()currently resets state without notifying listeners. Either emit the false transition before clearingonChange, or update the protocol docs to match actual behavior.Suggested patch
public func stop() { + if current { + onChange?(false) + } detach() onChange = nil observedBundleID = nil current = false }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Sources/LockIMEKit/AppMonitor/AddressBarFocusMonitor.swift` around lines 89 - 94, The stop() method in AddressBarFocusMonitor currently resets state without notifying listeners, but the AddressBarFocusMonitoring protocol documents that stopping observation should emit onChange(false). Before clearing the onChange property and other state in the stop() method, invoke onChange(false) to notify observers that address bar focus monitoring has been halted, ensuring the implementation aligns with the documented contract.Sources/LockIME/AppState.swift (1)
399-400: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick winCorrect the priority default in the doc comment.
The comment states
falseis the default, butaddressBarOutranksURLRulesdefaults totrueinLockConfiguration.Proposed fix
- /// `true` = address bar, `false` = URL rule (the default). + /// `true` = address bar (the default), `false` = URL rule.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Sources/LockIME/AppState.swift` around lines 399 - 400, The doc comment for the priority selection between address-bar rule and URL rule contains incorrect information about the default value. Update the comment to correctly state that true (address bar priority) is the default, not false. The comment currently says "false = URL rule (the default)" but should be corrected to accurately reflect that the default in LockConfiguration sets address bar rules to take priority over URL rules.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@Sources/LockIME/AppState.swift`:
- Around line 399-400: The doc comment for the priority selection between
address-bar rule and URL rule contains incorrect information about the default
value. Update the comment to correctly state that true (address bar priority) is
the default, not false. The comment currently says "false = URL rule (the
default)" but should be corrected to accurately reflect that the default in
LockConfiguration sets address bar rules to take priority over URL rules.
In `@Sources/LockIMEKit/AppMonitor/AddressBarFocusMonitor.swift`:
- Around line 89-94: The stop() method in AddressBarFocusMonitor currently
resets state without notifying listeners, but the AddressBarFocusMonitoring
protocol documents that stopping observation should emit onChange(false). Before
clearing the onChange property and other state in the stop() method, invoke
onChange(false) to notify observers that address bar focus monitoring has been
halted, ensuring the implementation aligns with the documented contract.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c2579244-8065-426e-9d14-522dbe5571c8
📒 Files selected for processing (17)
Sources/LockIME/AppState.swiftSources/LockIME/Localizable.xcstringsSources/LockIME/UI/Settings/ActivationLogPane.swiftSources/LockIME/UI/Settings/URLRulesSettingsPane.swiftSources/LockIMEKit/AppMonitor/AddressBarFocusMonitor.swiftSources/LockIMEKit/AppMonitor/AddressBarFocusMonitoring.swiftSources/LockIMEKit/AppMonitor/AddressBarHeuristic.swiftSources/LockIMEKit/LockEngine/InputSource.swiftSources/LockIMEKit/LockEngine/LockEngine.swiftSources/LockIMEKit/Rules/LockConfiguration.swiftSources/LockIMEKit/Rules/RuleResolver.swiftTests/LockIMEKitTests/AddressBarHeuristicTests.swiftTests/LockIMEKitTests/ImportPlanTests.swiftTests/LockIMEKitTests/LockConfigurationTests.swiftTests/LockIMEKitTests/LockEngineAddressBarTests.swiftTests/LockIMEKitTests/RuleResolverTests.swiftTests/LockIMEKitTests/Support/MockAddressBarMonitor.swift
While a browser's address bar (omnibox) has keyboard focus, the user is typing a URL or a search, where a CJK input method is rarely wanted. This adds an optional rule that forces a chosen input source on address-bar focus, so typing web addresses lands in the right source.
Detection is event-driven via Accessibility: an AXObserver on the frontmost browser watches focusedUIElementChanged, and the system-wide focused element is classified by AddressBarHeuristic — a per-engine, non-localized identifier (Chromium OmniboxViewViews, Safari WEB_BROWSER_ADDRESS_AND_SEARCH_FIELD, Firefox urlbar-input) confirmed by a chrome-vs-AXWebArea structural check. It mirrors FloatingAppMonitor and reuses the existing Accessibility grant; the permission-free core lock is untouched.
Both a continuous "lock" and a one-shot "switch" are supported (some input methods cover both languages). There is no reverse restore: leaving the address bar re-resolves the standard URL/app/default rules rather than restoring a remembered source. When both the address bar and a URL rule apply, a user-configurable priority decides the winner, defaulting to address-bar-first.
The rule is off by default and is per-device runtime state, so it is excluded from config backup/import (and preserved across import). The option lives in the URL Rules settings pane as labeled pop-up menus matching the macOS Settings style.
Closed: #28