From 12e7737a9eda1fffb3cfc883c383fef4f463861e Mon Sep 17 00:00:00 2001 From: Nikita Bobko Date: Mon, 18 Dec 2023 01:16:24 +0100 Subject: [PATCH] Fix unwanted animations when some accessibility features are enabled https://github.com/nikitabobko/AeroSpace/issues/51 should be fixed --- docs/guide.adoc | 15 --------------- src/tree/MacApp.swift | 2 +- src/tree/MacWindow.swift | 25 ++++++++++++++++++++++--- src/util/accessibility.swift | 5 +++++ 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/docs/guide.adoc b/docs/guide.adoc index aa5406f0..de5a58ef 100644 --- a/docs/guide.adoc +++ b/docs/guide.adoc @@ -437,21 +437,6 @@ xref:commands.adoc#move-workspace-to-monitor[move-workspace-to-monitor] command [#caveats] == Caveats -=== Unwanted animations - -If you use some of the Accessibility features `System Settings -> Accessibility`, you may see weird animations, for no reasons, when AeroSpace moves windows around. -(Shame on you, Apple! 🤦) - -Known accessibility features that cause the problem: - -* Full Keyboard Access -* Accessibility Keyboard -* Voice Control -* Switch Control -* Maybe something else... - -Please reboot after you disable the accessibility features that cause the problem. - === Dialog heuristics * Apple provides accessibility API for apps to let others know which of their windows are dialogs diff --git a/src/tree/MacApp.swift b/src/tree/MacApp.swift index 51709a16..56d1d2ba 100644 --- a/src/tree/MacApp.swift +++ b/src/tree/MacApp.swift @@ -1,6 +1,6 @@ final class MacApp: AbstractApp { let nsApp: NSRunningApplication - private let axApp: AXUIElement + let axApp: AXUIElement private var axObservers: [AxObserverWrapper] = [] // keep observers in memory diff --git a/src/tree/MacWindow.swift b/src/tree/MacWindow.swift index 1ce3375f..6f08196c 100644 --- a/src/tree/MacWindow.swift +++ b/src/tree/MacWindow.swift @@ -124,8 +124,10 @@ final class MacWindow: Window, CustomStringConvertible { } override func setSize(_ size: CGSize) { - previousSize = getSize() - axWindow.set(Ax.sizeAttr, size) + disableAnimations { + previousSize = getSize() + axWindow.set(Ax.sizeAttr, size) + } } override func getSize() -> CGSize? { @@ -133,7 +135,9 @@ final class MacWindow: Window, CustomStringConvertible { } override func setTopLeftCorner(_ point: CGPoint) { - axWindow.set(Ax.topLeftCornerAttr, point) + disableAnimations { + axWindow.set(Ax.topLeftCornerAttr, point) + } } override func getTopLeftCorner() -> CGPoint? { @@ -145,6 +149,21 @@ final class MacWindow: Window, CustomStringConvertible { guard let size = getSize() else { return nil } return Rect(topLeftX: topLeftCorner.x, topLeftY: topLeftCorner.y, width: size.width, height: size.height) } + + // Some undocumented magic + // References: https://github.com/koekeishiya/yabai/commit/3fe4c77b001e1a4f613c26f01ea68c0f09327f3a + // https://github.com/rxhanson/Rectangle/pull/285 + private func disableAnimations(_ body: () -> Void) { + let app = (app as! MacApp).axApp + let wasEnabled = app.get(Ax.enhancedUserInterfaceAttr) == true + if wasEnabled { + app.set(Ax.enhancedUserInterfaceAttr, false) + } + body() + if wasEnabled { + app.set(Ax.enhancedUserInterfaceAttr, true) + } + } } private func isWindow(_ axWindow: AXUIElement, _ app: MacApp) -> Bool { diff --git a/src/util/accessibility.swift b/src/util/accessibility.swift index c9a048c6..6e402a4b 100644 --- a/src/util/accessibility.swift +++ b/src/util/accessibility.swift @@ -197,6 +197,11 @@ enum Ax { getter: { $0 as? Bool }, setter: { $0 as CFTypeRef } ) + static let enhancedUserInterfaceAttr = WritableAttrImpl( + key: "AXEnhancedUserInterface", + getter: { $0 as? Bool }, + setter: { $0 as CFTypeRef } + ) static let sizeAttr = WritableAttrImpl( key: kAXSizeAttribute, getter: {