✨ Replace event monitors, improve AX permission handling#849
Merged
Conversation
There was a problem hiding this comment.
Pull Request Overview
This PR introduces three new event monitoring classes to replace previous implementations and improve AX permission handling, along with performance optimizations and UI enhancements.
- Replaces event monitoring with specialized classes:
ActiveEventMonitorfor event modification,PassiveEventMonitorfor passive observation, andLocalEventMonitorfor app-specific events - Introduces
WindowActionCachefor efficient keybind-to-action lookups using dictionary-based caching - Updates accessibility permission tracking to use system notifications instead of polling
Reviewed Changes
Copilot reviewed 34 out of 34 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| Loop/Window Management/Window/Window.swift | Adds window level validation and updates string description format |
| Loop/Window Management/Window Action/WindowDirection+Snapping.swift | Renames public method and makes helper methods private |
| Loop/Window Management/Window Action/WindowActionCache.swift | New cache class for efficient keybind-to-action lookups |
| Loop/Window Management/Window Action/WindowAction.swift | Removes static lookup method in favor of cache-based approach |
| Loop/Utilities/Logger+Extensions.swift | New convenience initializer for Logger with app bundle ID |
| Loop/Utilities/EventMonitor.swift | Removes old event monitoring implementation |
| Loop/Utilities/Event Monitoring/*.swift | New specialized event monitoring classes |
| Loop/Utilities/AccessibilityManager.swift | Enhanced AX permission tracking with notification system |
| Loop/Extensions/*.swift | Various extensions for CGEventFlags and Bundle improvements |
| Loop/Core/*.swift | Updates to use new event monitoring and caching systems |
Comments suppressed due to low confidence (1)
Loop/Window Action Indicators/Preview Window/PreviewController.swift:1
- Corrected spelling of 'receieved' to 'received'.
//
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
93eb7cf to
911cea4
Compare
This was
linked to
issues
Oct 13, 2025
4 tasks
ActiveEventMonitor, PassiveEventMonitor, LocalEventMonitor, improve AX permission handlingActiveEventMonitor, PassiveEventMonitor, LocalEventMonitor, improve AX permission handling
This was
linked to
issues
Oct 18, 2025
Closed
71feedd to
715c055
Compare
Closed
4 tasks
# Conflicts: # Loop/Core/WindowDragManager.swift # Loop/Settings Window/Loop/AdvancedConfiguration.swift
6a40045 to
e4decf4
Compare
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 60 out of 60 changed files in this pull request and generated 7 comments.
Comments suppressed due to low confidence (1)
Loop/Core/LoopManager.swift:1
- The method
attemptWindowSnapis called twice on consecutive lines - once withself.and once without. This appears to be duplicate code that should be removed.
//
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
4 tasks
4 tasks
SenpaiHunters
approved these changes
Oct 27, 2025
This was referenced Nov 2, 2025
ActiveEventMonitor, PassiveEventMonitor, LocalEventMonitor, improve AX permission handling
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Introduces three new event monitors (replacing all previous ones):
ActiveEventMonitor: The most powerful option. It creates a CFMachPort via CGEvent.tapCreate, allowing it to receive and optionally modify events. This monitor is used by Loop for handling the trigger key and user-defined shortcuts, enabling it to block events from reaching the frontmost application when Loop is active.PassiveEventMonitor: The default event monitor when event mutation isn’t required. Like ActiveEventMonitor, it uses a CFMachPort created with CGEvent.tapCreate to receive events, but simply passes them to a callback executed on a separate task, helping to avoid downstream lag. Used to track mouse movement, or middle click events.LocalEventMonitor: Built on NSEvent.addLocalMonitorForEvents. This monitor only receives events directed at Loop itself, and is used for recording trigger keys and for UI navigation (e.g. within the action selection popup).Beyond the new event monitors, this update brings some other optimizations and overall improvements:
WindowActionCache: Maintains an up-to-date dictionary mapping all user actions to their keybinds, enabling more efficient action lookups from the active event monitor. This dictionary-based approach dramatically improves performance, where the previous method required iterating through actions to find a match.Logger(category:): New initializer for app-wide Logger instances, which internally initializes a Logger with Loop's bundle ID.AccessibilityManager.stream(initial:): Now listens for system notifications to track changes in AX API access. LoopManager uses this stream to start and stop the event monitor as needed, and the advanced settings view now uses this mechanism instead of polling.CGEventFlagsextensions: By processing CGEvents rather than NSEvents, we can now detect which side each modifier key was pressed on.PreviewControlleranimations: The preview window now scales from/to 80% (instead of 0%) when appearing or disappearing, leading to a much smoother animation :)ScreenUtility:findScreen's implementation has been fixed, where it was previously using the AppKit coordinate space to find windows whose frames were provided in the CoreGraphics coordinate space. Now, it will usescreen.displayBoundswhich is provided in CoreGraphics coordinate space.