How Focus Follows Mouse Integrates with SwiftUI in Vorssaint-utils
Vorssaint-utils implements Focus Follows Mouse as a background service that monitors mouse movements and activates windows after a configurable delay, while SwiftUI provides a reactive settings interface that synchronizes user preferences via UserDefaults.
Vorssaint-utils delivers Focus Follows Mouse functionality through a clean architectural separation between the user interface layer and the background service. The SwiftUI frontend in Sources/Vorssaint/UI/Settings/SettingsView.swift manages configuration through standard AppStorage bindings, while the operational logic resides in Sources/Vorssaint/Services/FocusFollowsMouse/FocusFollowsMouseService.swift using low-level macOS frameworks. This design ensures the settings UI remains responsive while the service continuously tracks pointer activity and manages window activation through AppKit and CoreGraphics APIs.
SwiftUI Settings Interface for Focus Follows Mouse
The SwiftUI layer exposes Focus Follows Mouse configuration through reactive bindings that persist to UserDefaults and immediately propagate changes to the background service. The interface consists of a feature toggle and a configurable delay slider, both wrapped in @AppStorage property wrappers.
Binding the Toggle to UserDefaults
The enablement toggle binds directly to DefaultsKey.focusFollowsMouseEnabled using @AppStorage. When the toggle changes, the view invokes FocusFollowsMouseService.shared.syncWithPreferences() to start or stop monitoring, and requests accessibility permissions if enabling the feature.
@AppStorage(DefaultsKey.focusFollowsMouseEnabled) private var focusFollowsMouseEnabled = false
@AppStorage(DefaultsKey.focusFollowsMouseDelay) private var focusFollowsMouseDelay =
FocusFollowsMouseSupport.defaultDelayMilliseconds
var body: some View {
Section(l10n.s.focusFollowsMouseName) {
Toggle(l10n.s.focusFollowsMouseName, isOn: $focusFollowsMouseEnabled)
.onChange(of: focusFollowsMouseEnabled) { _, enabled in
FocusFollowsMouseService.shared.syncWithPreferences()
if enabled { Permissions.shared.requestAccessibility() }
}
if focusFollowsMouseEnabled {
Slider(value: focusFollowsMouseDelayBinding,
in: Double(FocusFollowsMouseSupport.delayRange.lowerBound)
... Double(FocusFollowsMouseSupport.delayRange.upperBound),
step: 50) {
Text(l10n.s.focusFollowsMouseDelay)
}
Text("\(focusFollowsMouseDelay) ms")
.font(.caption.monospacedDigit())
}
}
}
Managing the Delay Slider Binding
The delay slider uses a custom Binding<Double> that wraps FocusFollowsMouseSupport.sanitizedDelay to clamp values within the allowed range. The setter calls preferencesDidChange() to update the service timer without requiring a full restart.
private var focusFollowsMouseDelayBinding: Binding<Double> {
Binding(
get: { Double(FocusFollowsMouseSupport.sanitizedDelay(focusFollowsMouseDelay)) },
set: {
focusFollowsMouseDelay = Int($0)
FocusFollowsMouseService.shared.preferencesDidChange()
}
)
}
Background Service Implementation
FocusFollowsMouseService operates as a singleton that registers a global event monitor and manages a repeating timer to evaluate cursor stability. The service runs independently of the SwiftUI view hierarchy, observing UserDefaults changes through syncWithPreferences() to adjust its behavior dynamically.
Global Mouse Monitoring Logic
The service registers a global mouse-movement monitor that records pointer coordinates via recordMovement(to:). This method ensures main-thread execution, updates the internal state with the current timestamp, and schedules a 50-millisecond repeating timer with 10-millisecond tolerance to evaluate whether the cursor has settled.
private func recordMovement(to point: CGPoint) {
guard Thread.isMainThread else {
DispatchQueue.main.async { self.recordMovement(to: point) }
return
}
guard isRunning else { return }
state.recordMovement(to: point, at: ProcessInfo.processInfo.systemUptime)
guard timer == nil else { return }
let timer = Timer(timeInterval: 0.05, repeats: true) { _ in self.evaluateIfSettled() }
timer.tolerance = 0.01
RunLoop.main.add(timer, forMode: .common)
self.timer = timer
}
Window Evaluation and Activation
When the timer fires, the service checks FocusFollowsMouseState.nextEvaluation to determine if the cursor has remained stationary longer than the configured delay. If settled, it calls FocusFollowsMouseSupport.queryWindow to identify the window under the pointer, filters excluded window types using shouldActivate, and invokes WindowActivator.activate on the main thread to bring the target window forward.
Support Utilities and Window Query
FocusFollowsMouseSupport.swift provides shared logic used by both the SwiftUI frontend and the background service, ensuring consistent delay validation and safe window identification across Vorssaint-utils.
Delay Sanitization and Constraints
The utility defines defaultDelayMilliseconds and delayRange to constrain user input between acceptable bounds. Both the SwiftUI slider initialization and the service configuration call sanitizedDelay to clamp values, preventing invalid configurations from reaching the activation logic.
Safe Window Query Implementation
The queryWindow method performs defensive checks against the CoreGraphics window list. It validates window bounds, alpha values, and layer types against MouseAppExceptionSupport.appWindowLayers, ensuring the service only activates standard application windows while ignoring system panels, transparent overlays, and the utility's own windows unless explicitly permitted.
static func queryWindow<Result>(in windows: [[String: Any]],
at point: CGPoint,
pointerWindowID: CGWindowID,
ownProcessID: pid_t,
clickThroughWindowIDs: Set<CGWindowID>,
query: (pid_t) -> Result?) -> Result? {
guard pointerWindowID != kCGNullWindowID else { return nil }
for window in windows {
guard let bounds = WindowServerSupport.bounds(from: window),
bounds.contains(point),
(window[kCGWindowAlpha as String] as? NSNumber)?.doubleValue ?? 1 > 0
else { continue }
guard let processID = (window[kCGWindowOwnerPID as String] as? NSNumber)?.int32Value,
processID > 0 else { return nil }
if processID == ownProcessID {
guard let windowID = (window[kCGWindowNumber as String] as? NSNumber)?.uint32Value,
clickThroughWindowIDs.contains(windowID) else { return nil }
continue
}
guard (window[kCGWindowNumber as String] as? NSNumber)?.uint32Value == pointerWindowID else { continue }
guard let layer = (window[kCGWindowLayer as String] as? NSNumber)?.intValue,
MouseAppExceptionSupport.appWindowLayers.contains(layer) else { return nil }
return query(processID)
}
return nil
}
Summary
- Vorssaint-utils implements Focus Follows Mouse through a strict separation between the SwiftUI settings interface and the background service, using UserDefaults as the synchronization bridge.
- The SwiftUI frontend in
SettingsView.swiftuses@AppStoragebindings to persist the enabled state and delay preferences, callingsyncWithPreferences()immediately upon change. - Background monitoring occurs in
FocusFollowsMouseService.swiftthrough a global event monitor and a 50-millisecond evaluation timer that tracks cursor settlement. - Window activation relies on
FocusFollowsMouseSupport.queryWindowto safely identify target windows while filtering excluded layers, followed byWindowActivator.activateon the main thread. - The delay configuration uses
sanitizedDelayto clamp values withindelayRange, ensuring both the UI slider and service logic remain synchronized and valid.
Frequently Asked Questions
Where does Vorssaint-utils store Focus Follows Mouse preferences?
Preferences persist to standard UserDefaults using the @AppStorage property wrapper with keys DefaultsKey.focusFollowsMouseEnabled and DefaultsKey.focusFollowsMouseDelay. The background service reads these values through FocusFollowsMouseService.shared.syncWithPreferences() to determine whether to start monitoring or update the activation delay interval.
How does the service avoid activating system panels or its own transparent windows?
FocusFollowsMouseSupport.queryWindow filters the window list by validating the window layer against MouseAppExceptionSupport.appWindowLayers and checking the process ID against the utility's own PID. It also verifies window alpha values and bounds, ensuring activation occurs only on standard application windows while excluding system panels and Vorssaint-utils overlays.
What timer interval does the Focus Follows Mouse service use?
The service creates a repeating Timer with a 0.05-second (50-millisecond) interval and 0.01-second tolerance, added to RunLoop.main in common mode. This frequent evaluation checks whether the cursor has remained stationary long enough to trigger window activation without blocking the main thread or SwiftUI interactions.
Can users adjust the delay between mouse movement and window activation?
Yes. The SwiftUI settings view exposes a slider bound to FocusFollowsMouseSupport.sanitizedDelay, which clamps values within the predefined delayRange. Changes trigger FocusFollowsMouseService.shared.preferencesDidChange(), updating the service's evaluation threshold immediately without requiring a restart of the background monitoring system.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →