perf: merge mouseevents into cursorevents

This commit is contained in:
lwouis committed 2026-02-11 21:35:37 +01:00
1 parent d89bc29425
commit 9edf31244a
6 files changed
+102 -147

No files matched your search

-4
View File
@@ -284,7 +284,6 @@
D04BAD1BE9DC22C48C53D195 /* AboutTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA4A26987F67DD94C827F /* AboutTab.swift */; };
D04BAD2A7F2E8BF64EE982E9 /* TextArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA7C836A8CE8C0B8D128B /* TextArea.swift */; };
D04BAD395C7146A49734E0A5 /* about@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D04BA4FC0DEB8B44FF460F90 /* about@2x.png */; };
D04BAD43C122A1C7E88B0362 /* MouseEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAF320F4D43F0DDFE063E /* MouseEvents.swift */; };
D04BAD451966B43720120D2E /* Menubar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAD905546AA93E5117B0A /* Menubar.swift */; };
D04BADA3F2DAB820D6FC6E75 /* AppCenterApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = D04BA48BC82D3060C3A1AB11 /* AppCenterApplication.m */; };
D04BADCDA9F9A6C3D6499877 /* SystemPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA7C6F2519091717F4B4E /* SystemPermissions.swift */; };
@@ -728,7 +727,6 @@
D04BAEF1D194C2379C9970F1 /* setup_ci_master.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = setup_ci_master.sh; sourceTree = "<group>"; };
D04BAF076A30A1BAFEDBEA66 /* 5 windows - 2 lines.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "5 windows - 2 lines.jpg"; sourceTree = "<group>"; };
D04BAF1058D2599E6E8ABBA6 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.info; path = Info.plist; sourceTree = "<group>"; };
D04BAF320F4D43F0DDFE063E /* MouseEvents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MouseEvents.swift; sourceTree = "<group>"; };
D04BAF6E2AB002763931645A /* general@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "general@2x.png"; sourceTree = "<group>"; };
D04BAF6F617FCA44D1F75B60 /* alt_tab_macos.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = alt_tab_macos.entitlements; sourceTree = "<group>"; };
D04BAFA20F13FB588F6CCB81 /* bug_report.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = bug_report.md; sourceTree = "<group>"; };
@@ -1955,7 +1953,6 @@
D04BA4A621A8A15660F973C1 /* KeyboardEvents.swift */,
D04BA76AEE37D6656EB80126 /* RunningApplicationsEvents.swift */,
D04BA5D9B4EBEB9E4333AE39 /* UserDefaultsEvents.swift */,
D04BAF320F4D43F0DDFE063E /* MouseEvents.swift */,
5883F0A729A5182C0071DB65 /* TrackpadEvents.swift */,
BF0C870C14C20C936BA4AF40 /* DockEvents.swift */,
BF0C8DF008F1EB5F23291A13 /* SpacesEvents.swift */,
@@ -2512,7 +2509,6 @@
D04BAFB90E00AA5D662EAF24 /* PermissionsWindow.swift in Sources */,
D04BA7E39FA539DD8316447A /* PermissionView.swift in Sources */,
D04BA446D702C5E252AF2319 /* TitleLabel.swift in Sources */,
D04BAD43C122A1C7E88B0362 /* MouseEvents.swift in Sources */,
D04BAFF30A98CF287F85DA1E /* BlacklistsTab.swift in Sources */,
D04BA56789A2AF52557A9BFF /* AppCenterCrashes.swift in Sources */,
D04BADA3F2DAB820D6FC6E75 /* AppCenterApplication.m in Sources */,
+96 -13
View File
@@ -4,6 +4,8 @@ import Carbon.HIToolbox.Events
class CursorEvents {
private static var eventTap: CFMachPort!
private static var shouldBeEnabled: Bool!
private static var mouseDownTileView: TileView?
private static var mouseDownButton: TrafficLightButton?
static var deadZoneInitialPosition: CGPoint?
static var isAllowedToMouseHover = true
@@ -23,7 +25,7 @@ class CursorEvents {
}
private static func observe_() {
let eventMask = [CGEventType.mouseMoved].reduce(CGEventMask(0), { $0 | (1 << $1.rawValue) })
let eventMask = [CGEventType.leftMouseDown, CGEventType.leftMouseUp, CGEventType.otherMouseUp, CGEventType.mouseMoved].reduce(CGEventMask(0), { $0 | (1 << $1.rawValue) })
// CGEvent.tapCreate returns nil if ensureAccessibilityCheckboxIsChecked() didn't pass
eventTap = CGEvent.tapCreate(
tap: .cgSessionEventTap,
@@ -35,7 +37,7 @@ class CursorEvents {
if let eventTap {
toggle(false)
let runLoopSource = CFMachPortCreateRunLoopSource(nil, eventTap, 0)
// we run on main-thread directly since all we do is check NSEvent data, which we must do on main-thread
// we run on main-thread directly since all we do is check NSEvent and UI coordinates, which we must do on main-thread
CFRunLoopAddSource(CFRunLoopGetMain(), runLoopSource, .commonModes)
} else {
App.app.restart()
@@ -43,15 +45,98 @@ class CursorEvents {
}
private static let handleEvent: CGEventTapCallBack = { _, type, cgEvent, _ in
if type == .mouseMoved {
updateDeadzoneSituation(cgEvent)
if isAllowedToMouseHover {
App.app.thumbnailsPanel.tilesView.thumbnailOverView.updateHover()
}
} else if (type == .tapDisabledByUserInput || type == .tapDisabledByTimeout) && shouldBeEnabled {
CGEvent.tapEnable(tap: eventTap!, enable: true)
switch type {
case .leftMouseDown: return handleLeftMouseDown()
case .leftMouseUp where cgEvent.getIntegerValueField(.mouseEventClickState) >= 1: return handleLeftMouseUp()
case .otherMouseUp: return handleOtherMouseUp(cgEvent)
case .mouseMoved: return handleMouseMoved(cgEvent)
case .tapDisabledByUserInput, .tapDisabledByTimeout:
if shouldBeEnabled { CGEvent.tapEnable(tap: eventTap!, enable: true) }
return Unmanaged.passUnretained(cgEvent)
default: return Unmanaged.passUnretained(cgEvent)
}
return Unmanaged.passUnretained(cgEvent) // focused app will receive the event
}
private static func handleLeftMouseDown() -> Unmanaged<CGEvent>? {
guard isPointerInsideUi() else { return nil }
if let button = findButtonUnderPointer() {
mouseDownButton = button
button.isHighlighted = true
button.setNeedsDisplay()
} else {
mouseDownTileView = findTileViewUnderPointer()
}
return nil
}
private static func handleLeftMouseUp() -> Unmanaged<CGEvent>? {
guard isPointerInsideUi() else {
App.app.hideUi()
return nil
}
if let button = mouseDownButton {
mouseDownButton = nil
button.isHighlighted = false
button.setNeedsDisplay()
if findButtonUnderPointer() === button {
button.onClick()
}
return nil
}
if let target = mouseDownTileView {
mouseDownTileView = nil
if isPointerOver(target) {
target.mouseUpCallback()
}
return nil
}
return nil
}
private static func handleOtherMouseUp(_ cgEvent: CGEvent) -> Unmanaged<CGEvent>? {
guard isPointerInsideUi(),
cgEvent.getIntegerValueField(.mouseEventButtonNumber) == 2,
let target = findTileViewUnderPointer(),
let window = target.window_ else {
return Unmanaged.passUnretained(cgEvent)
}
window.isWindowlessApp ? window.application.quit() : window.close()
return nil
}
private static func handleMouseMoved(_ cgEvent: CGEvent) -> Unmanaged<CGEvent>? {
updateDeadzoneSituation(cgEvent)
if isAllowedToMouseHover {
App.app.thumbnailsPanel.tilesView.thumbnailOverView.updateHover()
}
return Unmanaged.passUnretained(cgEvent)
}
private static func pointerLocationInWindow() -> NSPoint {
App.app.thumbnailsPanel.mouseLocationOutsideOfEventStream
}
private static func isPointerInsideUi() -> Bool {
App.app.thumbnailsPanel.contentLayoutRect.contains(pointerLocationInWindow())
}
private static func isPointerOver(_ view: NSView) -> Bool {
view.bounds.contains(view.convert(pointerLocationInWindow(), from: nil))
}
private static func pointerInOverlay() -> (TileOverView, NSPoint) {
let overlay = App.app.thumbnailsPanel.tilesView.thumbnailOverView
return (overlay, overlay.convert(pointerLocationInWindow(), from: nil))
}
private static func findButtonUnderPointer() -> TrafficLightButton? {
let (overlay, point) = pointerInOverlay()
return overlay.findButton(point)
}
private static func findTileViewUnderPointer() -> TileView? {
let (overlay, point) = pointerInOverlay()
return overlay.findTarget(point)
}
/// when using the trackpad, the user may swipe with a slight mistake. This will create a small cursor movement
@@ -65,8 +150,6 @@ class CursorEvents {
}
let deltaX = event.locationInWindow.x - deadZoneInitialPosition.x
let deltaY = event.locationInWindow.y - deadZoneInitialPosition.y
let d = hypot(deltaX, deltaY)
isAllowedToMouseHover = d > 25
isAllowedToMouseHover = hypot(deltaX, deltaY) > 25
}
}
-123
View File
@@ -1,123 +0,0 @@
import Cocoa
import Carbon.HIToolbox.Events
class MouseEvents {
private static var eventTap: CFMachPort!
private static var shouldBeEnabled: Bool!
private static var mouseDownTileView: TileView?
private static var mouseDownButton: TrafficLightButton?
static func observe() {
observe_()
}
static func toggle(_ enabled: Bool) {
guard enabled != shouldBeEnabled else { return }
shouldBeEnabled = enabled
if let eventTap {
CGEvent.tapEnable(tap: eventTap, enable: enabled)
}
}
private static func observe_() {
let eventMask = [CGEventType.leftMouseDown, CGEventType.leftMouseUp, CGEventType.otherMouseUp].reduce(CGEventMask(0), { $0 | (1 << $1.rawValue) })
// CGEvent.tapCreate returns nil if ensureAccessibilityCheckboxIsChecked() didn't pass
eventTap = CGEvent.tapCreate(
tap: .cgSessionEventTap,
place: .headInsertEventTap,
options: .defaultTap,
eventsOfInterest: eventMask,
callback: handleEvent,
userInfo: nil)
if let eventTap {
toggle(false)
let runLoopSource = CFMachPortCreateRunLoopSource(nil, eventTap, 0)
// we run on main-thread directly since all we do is check UI coordinates, which we must do on main-thread
CFRunLoopAddSource(CFRunLoopGetMain(), runLoopSource, .commonModes)
} else {
App.app.restart()
}
}
private static let handleEvent: CGEventTapCallBack = { _, type, cgEvent, _ in
if type == .leftMouseDown {
if !isPointerInsideUi() {
return nil // focused app won't receive the event
}
if let button = findButtonUnderPointer() {
mouseDownButton = button
button.isHighlighted = true
button.setNeedsDisplay()
return nil // swallow - we handle button clicks centrally
}
mouseDownTileView = findTileViewUnderPointer()
return nil // swallow - we handle tile clicks centrally
} else if type == .leftMouseUp && cgEvent.getIntegerValueField(.mouseEventClickState) >= 1 {
if !isPointerInsideUi() {
App.app.hideUi()
return nil // focused app won't receive the event
}
if let button = mouseDownButton {
mouseDownButton = nil
button.isHighlighted = false
button.setNeedsDisplay()
if findButtonUnderPointer() === button {
button.onClick()
}
return nil
}
if let target = mouseDownTileView {
mouseDownTileView = nil
if isPointerOverTileView(target) {
target.mouseUpCallback()
}
return nil
}
} else if type == .otherMouseUp {
guard isPointerInsideUi() else { return Unmanaged.passUnretained(cgEvent) }
if cgEvent.getIntegerValueField(.mouseEventButtonNumber) == 2 {
handleMiddleClick()
return nil
}
} else if (type == .tapDisabledByUserInput || type == .tapDisabledByTimeout) && shouldBeEnabled {
CGEvent.tapEnable(tap: eventTap!, enable: true)
}
return Unmanaged.passUnretained(cgEvent) // focused app will receive the event
}
private static func isPointerInsideUi() -> Bool {
return App.app.thumbnailsPanel.contentLayoutRect.contains(App.app.thumbnailsPanel.mouseLocationOutsideOfEventStream)
}
private static func findButtonUnderPointer() -> TrafficLightButton? {
let panel = App.app.thumbnailsPanel!
let overlay = panel.tilesView.thumbnailOverView
let windowLocation = panel.mouseLocationOutsideOfEventStream
let overlayLocation = overlay.convert(windowLocation, from: nil)
return overlay.findButton(overlayLocation)
}
private static func findTileViewUnderPointer() -> TileView? {
let panel = App.app.thumbnailsPanel!
let overlay = panel.tilesView.thumbnailOverView
let windowLocation = panel.mouseLocationOutsideOfEventStream
let overlayLocation = overlay.convert(windowLocation, from: nil)
return overlay.findTarget(overlayLocation)
}
private static func isPointerOverTileView(_ tileView: TileView) -> Bool {
let panel = App.app.thumbnailsPanel!
let windowLocation = panel.mouseLocationOutsideOfEventStream
let localPoint = tileView.convert(windowLocation, from: nil)
return tileView.bounds.contains(localPoint)
}
private static func handleMiddleClick() {
guard let target = findTileViewUnderPointer(), let window = target.window_ else { return }
if window.isWindowlessApp {
window.application.quit()
} else {
window.close()
}
}
}
-2
View File
@@ -64,7 +64,6 @@ class App: AppCenterApplication {
appIsBeingUsed = false
isFirstSummon = true
forceDoNothingOnRelease = false
MouseEvents.toggle(false)
CursorEvents.toggle(false)
TrackpadEvents.reset()
hideTilesPanelWithoutChangingKeyWindow()
@@ -337,7 +336,6 @@ extension App: NSApplicationDelegate {
self.preferencesWindow = PreferencesWindow()
self.feedbackWindow = FeedbackWindow()
KeyboardEvents.addEventHandlers()
MouseEvents.observe()
CursorEvents.observe()
TrackpadEvents.observe()
CliEvents.observe()
+6 -4
View File
@@ -40,16 +40,18 @@ class TileOverView: FlippedView {
let location = convert(App.app.thumbnailsPanel.mouseLocationOutsideOfEventStream, from: nil)
updateButtonHover(location)
let newTarget = findTarget(location)
if let target = newTarget ?? previousTarget {
let statusFrame = target.convert(target.statusIcons.frame, to: superview)
if statusFrame.contains(location) {
target.statusIcons.ensureTooltipsInstalled()
}
}
guard newTarget !== previousTarget else { return }
caTransaction {
if let newTarget {
hideWindowControls()
newTarget.mouseMoved()
showWindowControls(for: newTarget)
let statusFrame = newTarget.convert(newTarget.statusIcons.frame, to: superview)
if statusFrame.contains(location) {
newTarget.statusIcons.ensureTooltipsInstalled()
}
} else {
resetHoveredWindow()
}
-1
View File
@@ -62,7 +62,6 @@ class TilesPanel: NSPanel {
updateAppearance()
alphaValue = 1
makeKeyAndOrderFront(nil)
MouseEvents.toggle(true)
CursorEvents.toggle(true)
DispatchQueue.main.async { self.tilesView.scrollView.flashScrollers() }
}