From be5075845138fcac681dc9da8060625c88e937ee Mon Sep 17 00:00:00 2001 From: Grzegorz Kazana Date: Sat, 29 Jan 2022 17:30:33 +0100 Subject: [PATCH] feat: allow cursor follow focus behavior --- resources/l10n/Localizable.strings | 6 ++++++ resources/l10n/en.lproj/Localizable.strings | 6 ++++++ src/logic/Preferences.swift | 2 ++ src/ui/App.swift | 20 ++++++++++++++++--- .../preferences-window/tabs/ControlsTab.swift | 10 +++++++--- 5 files changed, 38 insertions(+), 6 deletions(-) diff --git a/resources/l10n/Localizable.strings b/resources/l10n/Localizable.strings index efb97031..91f1a322 100644 --- a/resources/l10n/Localizable.strings +++ b/resources/l10n/Localizable.strings @@ -37,6 +37,12 @@ /* No comment provided by engineer. */ "Also select windows using:" = "Also select windows using:"; +/* No comment provided by engineer. */ +"Miscellaneous:" = "Miscellaneous:"; + +/* No comment provided by engineer. */ +"Cursor follows focus" = "Cursor follows focus" + /* No comment provided by engineer. */ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed"; diff --git a/resources/l10n/en.lproj/Localizable.strings b/resources/l10n/en.lproj/Localizable.strings index 173070d7..ad4f78b2 100644 --- a/resources/l10n/en.lproj/Localizable.strings +++ b/resources/l10n/en.lproj/Localizable.strings @@ -41,6 +41,12 @@ /*No comment provided by engineer.*/ "Also select windows using:" = "Also select windows using:"; +/* No comment provided by engineer. */ +"Miscellaneous:" = "Miscellaneous:"; + +/* No comment provided by engineer. */ +"Cursor follows focus" = "Cursor follows focus" + /*No comment provided by engineer.*/ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed"; diff --git a/src/logic/Preferences.swift b/src/logic/Preferences.swift index 2c4eb11a..d12b90e1 100644 --- a/src/logic/Preferences.swift +++ b/src/logic/Preferences.swift @@ -24,6 +24,7 @@ class Preferences { "hideShowAppShortcut": "H", "arrowKeysEnabled": "true", "mouseHoverEnabled": "true", + "cursorFollowFocusEnabled": "false", "showMinimizedWindows": ShowHowPreference.show.rawValue, "showMinimizedWindows2": ShowHowPreference.show.rawValue, "showHiddenWindows": ShowHowPreference.show.rawValue, @@ -90,6 +91,7 @@ class Preferences { static var hideShowAppShortcut: String { defaults.string("hideShowAppShortcut") } static var arrowKeysEnabled: Bool { defaults.bool("arrowKeysEnabled") } static var mouseHoverEnabled: Bool { defaults.bool("mouseHoverEnabled") } + static var cursorFollowFocusEnabled: Bool { defaults.bool("cursorFollowFocusEnabled") } static var showTabsAsWindows: Bool { defaults.bool("showTabsAsWindows") } static var hideColoredCircles: Bool { defaults.bool("hideColoredCircles") } static var windowDisplayDelay: DispatchTimeInterval { DispatchTimeInterval.milliseconds(defaults.int("windowDisplayDelay")) } diff --git a/src/ui/App.swift b/src/ui/App.swift index 16329739..214cf67d 100644 --- a/src/ui/App.swift +++ b/src/ui/App.swift @@ -189,10 +189,24 @@ class App: AppCenterApplication, NSApplicationDelegate { KeyRepeatTimer.toggleRepeatingKeyPreviousWindow() } - func focusSelectedWindow(_ window: Window?) { + func focusSelectedWindow(_ selectedWindow: Window?) { hideUi() - guard !CGWindow.isMissionControlActive() else { return } - window?.focus() + guard let window = selectedWindow, !CGWindow.isMissionControlActive() else { return } + window.focus() + if Preferences.cursorFollowFocusEnabled { + moveCursorToSelectedWindow(window) + } + } + + func moveCursorToSelectedWindow(_ window: Window) { + guard let position = window.position, let size = window.size else { return } + + let point = CGPoint( + x: position.x + size.width / 2, + y: position.y + size.height / 2 + ) + + CGWarpMouseCursorPosition(point) } func reopenUi() { diff --git a/src/ui/preferences-window/tabs/ControlsTab.swift b/src/ui/preferences-window/tabs/ControlsTab.swift index 940627e5..95f600b8 100644 --- a/src/ui/preferences-window/tabs/ControlsTab.swift +++ b/src/ui/preferences-window/tabs/ControlsTab.swift @@ -32,8 +32,11 @@ class ControlsTab { let hideShowAppShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Hide/Show app", comment: ""), "hideShowAppShortcut", Preferences.hideShowAppShortcut, labelPosition: .right) let enableArrows = LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Arrow keys", comment: ""), "arrowKeysEnabled", extraAction: ControlsTab.arrowKeysEnabledCallback, labelPosition: .right) let enableMouse = LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Mouse hover", comment: ""), "mouseHoverEnabled", labelPosition: .right) - let checkboxesExplanations = LabelAndControl.makeLabel(NSLocalizedString("Also select windows using:", comment: "")) - let checkboxes = StackView([StackView(enableArrows), StackView(enableMouse)], .vertical) + let enableCursorFollowFocus = LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Cursor follows focus", comment: ""), "cursorFollowFocusEnabled", labelPosition: .right) + let selectWindowcheckboxesExplanations = LabelAndControl.makeLabel(NSLocalizedString("Also select windows using:", comment: "")) + let selectWindowCheckboxes = StackView([StackView(enableArrows), StackView(enableMouse)], .vertical) + let miscCheckboxesExplanations = LabelAndControl.makeLabel(NSLocalizedString("Miscellaneous:", comment: "")) + let miscCheckboxes = StackView([StackView(enableCursorFollowFocus)], .vertical) let shortcuts = StackView([focusWindowShortcut, previousWindowShortcut, cancelShortcut, closeWindowShortcut, minDeminWindowShortcut, quitAppShortcut, hideShowAppShortcut].map { (view: [NSView]) in StackView(view) }, .vertical) let orPress = LabelAndControl.makeLabel(NSLocalizedString("While open, press:", comment: ""), shouldFit: false) let (holdShortcut, nextWindowShortcut, tab1View) = toShowSection("") @@ -48,7 +51,8 @@ class ControlsTab { let grid = GridView([ [tabView], [orPress, shortcuts], - [checkboxesExplanations, checkboxes], + [selectWindowcheckboxesExplanations, selectWindowCheckboxes], + [miscCheckboxesExplanations, miscCheckboxes] ]) grid.column(at: 0).xPlacement = .trailing grid.mergeCells(inHorizontalRange: NSRange(location: 0, length: 2), verticalRange: NSRange(location: 0, length: 1))