Skip to content

Commit

Permalink
Merge pull request #1 from chase-miller/per-section-previous-window-b…
Browse files Browse the repository at this point in the history
…indings

feat: per-section previousWindowShortcut bindings
  • Loading branch information
chase-miller authored Feb 10, 2023
2 parents b57a39d + e2172e6 commit 9962653
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 37 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@
**AltTab** brings the power of Windows alt-tab to macOS

[Find out more on the official website](https://alt-tab-macos.netlify.app/)

## Contributing
[See contributing on the official website](https://alt-tab-macos.netlify.app/contributing)
6 changes: 3 additions & 3 deletions src/logic/KeyRepeatTimer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ class KeyRepeatTimer {
static var timer: Timer?
static var isARepeat = false

static func toggleRepeatingKeyPreviousWindow() {
if let shortcut = ControlsTab.shortcuts["previousWindowShortcut"],
static func toggleRepeatingKeyPreviousWindow(_ shortcutIndex: Int) {
if let shortcut = ControlsTab.shortcuts[Preferences.indexToName("previousWindowShortcut", shortcutIndex)],
// events already repeat when using a shortcut with a keycode; no need for artificial repeat
shortcut.shortcut.keyCode == .none {
toggleRepeatingKey(shortcut) {
App.app.previousWindowShortcutWithRepeatingKey()
ControlsTab.shortcutsActions[Preferences.indexToName("previousWindowShortcut", shortcutIndex)]!()
}
}
}
Expand Down
59 changes: 37 additions & 22 deletions src/logic/Preferences.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ class Preferences {
"nextWindowShortcut5": "",
"focusWindowShortcut": "Space",
"previousWindowShortcut": "",
"previousWindowShortcut2": "",
"previousWindowShortcut3": "",
"previousWindowShortcut4": "",
"previousWindowShortcut5": "",
"cancelShortcut": "",
"closeWindowShortcut": "W",
"minDeminWindowShortcut": "M",
Expand Down Expand Up @@ -111,7 +115,7 @@ class Preferences {
static var holdShortcut: [String] { ["holdShortcut", "holdShortcut2", "holdShortcut3", "holdShortcut4", "holdShortcut5"].map { defaults.string($0) } }
static var nextWindowShortcut: [String] { ["nextWindowShortcut", "nextWindowShortcut2", "nextWindowShortcut3", "nextWindowShortcut4", "nextWindowShortcut5"].map { defaults.string($0) } }
static var focusWindowShortcut: String { defaults.string("focusWindowShortcut") }
static var previousWindowShortcut: String { defaults.string("previousWindowShortcut") }
static var previousWindowShortcut: [String] { ["previousWindowShortcut", "previousWindowShortcut2", "previousWindowShortcut3", "previousWindowShortcut4", "previousWindowShortcut5"].map { defaults.string($0) } }
static var cancelShortcut: String { defaults.string("cancelShortcut") }
static var closeWindowShortcut: String { defaults.string("closeWindowShortcut") }
static var minDeminWindowShortcut: String { defaults.string("minDeminWindowShortcut") }
Expand Down Expand Up @@ -201,27 +205,30 @@ class Preferences {
}

private static func updateToNewPreferences(_ currentVersion: String) {
if currentVersion.compare("6.42.0", options: .numeric) != .orderedDescending {
migrateBlacklists()
if currentVersion.compare("6.28.1", options: .numeric) != .orderedDescending {
migrateMinMaxWindowsWidthInRow()
if currentVersion.compare("6.27.1", options: .numeric) != .orderedDescending {
// "Start at login" new implem doesn't use Login Items; we remove the entry from previous versions
(Preferences.self as AvoidDeprecationWarnings.Type).migrateLoginItem()
if currentVersion.compare("6.23.0", options: .numeric) != .orderedDescending {
// "Show windows from:" got the "Active Space" option removed
migrateShowWindowsFrom()
if currentVersion.compare("6.18.1", options: .numeric) != .orderedDescending {
// nextWindowShortcut used to be able to have modifiers already present in holdShortcut; we remove these
migrateNextWindowShortcuts()
// dropdowns preferences used to store English text; now they store indexes
migrateDropdownsFromTextToIndexes()
// the "Hide menubar icon" checkbox was replaced with a dropdown of: icon1, icon2, hidden
migrateMenubarIconFromCheckboxToDropdown()
// "Show minimized/hidden/fullscreen windows" checkboxes were replaced with dropdowns
migrateShowWindowsCheckboxToDropdown()
// "Max size on screen" was split into max width and max height
migrateMaxSizeOnScreenToWidthAndHeight()
if currentVersion.compare("6.52.1", options: .numeric) != .orderedDescending {
migratePreviousWindowShortcuts()
if currentVersion.compare("6.42.0", options: .numeric) != .orderedDescending {
migrateBlacklists()
if currentVersion.compare("6.28.1", options: .numeric) != .orderedDescending {
migrateMinMaxWindowsWidthInRow()
if currentVersion.compare("6.27.1", options: .numeric) != .orderedDescending {
// "Start at login" new implem doesn't use Login Items; we remove the entry from previous versions
(Preferences.self as AvoidDeprecationWarnings.Type).migrateLoginItem()
if currentVersion.compare("6.23.0", options: .numeric) != .orderedDescending {
// "Show windows from:" got the "Active Space" option removed
migrateShowWindowsFrom()
if currentVersion.compare("6.18.1", options: .numeric) != .orderedDescending {
// nextWindowShortcut used to be able to have modifiers already present in holdShortcut; we remove these
migrateNextWindowShortcuts()
// dropdowns preferences used to store English text; now they store indexes
migrateDropdownsFromTextToIndexes()
// the "Hide menubar icon" checkbox was replaced with a dropdown of: icon1, icon2, hidden
migrateMenubarIconFromCheckboxToDropdown()
// "Show minimized/hidden/fullscreen windows" checkboxes were replaced with dropdowns
migrateShowWindowsCheckboxToDropdown()
// "Max size on screen" was split into max width and max height
migrateMaxSizeOnScreenToWidthAndHeight()
}
}
}
}
Expand Down Expand Up @@ -315,6 +322,14 @@ class Preferences {
}
}

private static func migratePreviousWindowShortcuts() {
if let old = defaults.string(forKey: "previousWindowShortcut") {
for suffix in 2...5 {
defaults.set(old, forKey: "previousWindowShortcut\(suffix)")
}
}
}

private static func migrateMaxSizeOnScreenToWidthAndHeight() {
if let old = defaults.string(forKey: "maxScreenUsage") {
defaults.set(old, forKey: "maxWidthOnScreen")
Expand Down
9 changes: 7 additions & 2 deletions src/ui/App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,14 @@ class App: AppCenterApplication, NSApplicationDelegate {
}
}

func previousWindowShortcutWithRepeatingKey() {
func previousWindowShortcutWithRepeatingKey(_ shortcutIndex: Int) {
// Prevent another group's previousWindowShortcut key binding from invoking
if (shortcutIndex != App.app.shortcutIndex) {
return
}

cycleSelection(.trailing)
KeyRepeatTimer.toggleRepeatingKeyPreviousWindow()
KeyRepeatTimer.toggleRepeatingKeyPreviousWindow(shortcutIndex)
}

func focusSelectedWindow(_ selectedWindow: Window?) {
Expand Down
31 changes: 21 additions & 10 deletions src/ui/preferences-window/tabs/ControlsTab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ class ControlsTab {
"nextWindowShortcut3": { App.app.showUiOrCycleSelection(2) },
"nextWindowShortcut4": { App.app.showUiOrCycleSelection(3) },
"nextWindowShortcut5": { App.app.showUiOrCycleSelection(4) },
"previousWindowShortcut": { App.app.previousWindowShortcutWithRepeatingKey() },
"previousWindowShortcut": { App.app.previousWindowShortcutWithRepeatingKey(0) },
"previousWindowShortcut2": { App.app.previousWindowShortcutWithRepeatingKey(1) },
"previousWindowShortcut3": { App.app.previousWindowShortcutWithRepeatingKey(2) },
"previousWindowShortcut4": { App.app.previousWindowShortcutWithRepeatingKey(3) },
"previousWindowShortcut5": { App.app.previousWindowShortcutWithRepeatingKey(4) },
"": { App.app.cycleSelection(.right) },
"": { App.app.cycleSelection(.left) },
"": { App.app.cycleSelection(.up) },
Expand All @@ -31,7 +35,6 @@ class ControlsTab {

static func initTab() -> NSView {
let focusWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Focus selected window", comment: ""), "focusWindowShortcut", Preferences.focusWindowShortcut, labelPosition: .right)
let previousWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Select previous window", comment: ""), "previousWindowShortcut", Preferences.previousWindowShortcut, labelPosition: .right)
let cancelShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Cancel and hide", comment: ""), "cancelShortcut", Preferences.cancelShortcut, labelPosition: .right)
let closeWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Close window", comment: ""), "closeWindowShortcut", Preferences.closeWindowShortcut, labelPosition: .right)
let minDeminWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Minimize/Deminimize window", comment: ""), "minDeminWindowShortcut", Preferences.minDeminWindowShortcut, labelPosition: .right)
Expand All @@ -45,13 +48,13 @@ class ControlsTab {
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 shortcuts = StackView([focusWindowShortcut, 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(0)
let (holdShortcut2, nextWindowShortcut2, tab2View) = toShowSection(1)
let (holdShortcut3, nextWindowShortcut3, tab3View) = toShowSection(2)
let (holdShortcut4, nextWindowShortcut4, tab4View) = toShowSection(3)
let (holdShortcut5, nextWindowShortcut5, tab5View) = toShowSection(4)
let (holdShortcut, nextWindowShortcut, previousWindowShortcut, tab1View) = toShowSection(0)
let (holdShortcut2, nextWindowShortcut2, previousWindowShortcut2, tab2View) = toShowSection(1)
let (holdShortcut3, nextWindowShortcut3, previousWindowShortcut3, tab3View) = toShowSection(2)
let (holdShortcut4, nextWindowShortcut4, previousWindowShortcut4, tab4View) = toShowSection(3)
let (holdShortcut5, nextWindowShortcut5, previousWindowShortcut5, tab5View) = toShowSection(4)
let tabView = TabView([
(NSLocalizedString("Shortcut 1", comment: ""), tab1View),
(NSLocalizedString("Shortcut 2", comment: ""), tab2View),
Expand All @@ -64,6 +67,7 @@ class ControlsTab {
// trigger shortcutChanged for these shortcuts to trigger .restrictModifiers
[holdShortcut, holdShortcut2, holdShortcut3, holdShortcut4, holdShortcut5].forEach { ControlsTab.shortcutChangedCallback($0[1] as! NSControl) }
[nextWindowShortcut, nextWindowShortcut2, nextWindowShortcut3, nextWindowShortcut4, nextWindowShortcut5].forEach { ControlsTab.shortcutChangedCallback($0[0] as! NSControl) }
[previousWindowShortcut, previousWindowShortcut2, previousWindowShortcut3, previousWindowShortcut4, previousWindowShortcut5].forEach { ControlsTab.shortcutChangedCallback($0[0] as! NSControl) }

let grid = GridView([
[tabView],
Expand All @@ -90,11 +94,12 @@ class ControlsTab {
return grid
}

private static func toShowSection(_ index: Int) -> ([NSView], [NSView], GridView) {
private static func toShowSection(_ index: Int) -> ([NSView], [NSView], [NSView], GridView) {
let toShowExplanations = LabelAndControl.makeLabel(NSLocalizedString("Show windows from:", comment: ""))
let toShowExplanations2 = LabelAndControl.makeLabel(NSLocalizedString("Minimized windows:", comment: ""))
let toShowExplanations3 = LabelAndControl.makeLabel(NSLocalizedString("Hidden windows:", comment: ""))
let toShowExplanations4 = LabelAndControl.makeLabel(NSLocalizedString("Fullscreen windows:", comment: ""))
let toShowExplanations5 = LabelAndControl.makeLabel(NSLocalizedString("While open, press:", comment: ""))
var holdShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Hold", comment: ""), Preferences.indexToName("holdShortcut", index), Preferences.holdShortcut[index], false, labelPosition: .leftWithoutSeparator)
holdShortcut.append(LabelAndControl.makeLabel(NSLocalizedString("and press:", comment: "")))
let holdAndPress = StackView(holdShortcut)
Expand All @@ -108,6 +113,9 @@ class ControlsTab {
separator.boxType = .separator
let nextWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Select next window", comment: ""), Preferences.indexToName("nextWindowShortcut", index), Preferences.nextWindowShortcut[index], labelPosition: .right)
let shortcutStyle = LabelAndControl.makeLabelWithDropdown(NSLocalizedString("Then release:", comment: ""), Preferences.indexToName("shortcutStyle", index), ShortcutStylePreference.allCases)
let separator2: NSBox = NSBox()
separator2.boxType = .custom // provides the slightest bit of whitespace in between next and previous tab switchers
let previousWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Select previous window", comment: ""), Preferences.indexToName("previousWindowShortcut", index), Preferences.previousWindowShortcut[index], labelPosition: .right)
let toShowDropdowns = StackView([appsToShow, spacesToShow, screensToShow], .vertical, false)
toShowDropdowns.spacing = TabView.padding
toShowDropdowns.fit()
Expand All @@ -119,11 +127,14 @@ class ControlsTab {
[separator],
[holdAndPress, StackView(nextWindowShortcut)],
shortcutStyle,
[separator2],
[toShowExplanations5, StackView(previousWindowShortcut)],
], TabView.padding)
tab.column(at: 0).xPlacement = .trailing
tab.mergeCells(inHorizontalRange: NSRange(location: 0, length: 2), verticalRange: NSRange(location: 4, length: 1))
tab.mergeCells(inHorizontalRange: NSRange(location: 0, length: 2), verticalRange: NSRange(location: 7, length: 1))
tab.fit()
return (holdShortcut, nextWindowShortcut, tab)
return (holdShortcut, nextWindowShortcut, previousWindowShortcut, tab)
}

private static func addShortcut(_ triggerPhase: ShortcutTriggerPhase, _ scope: ShortcutScope, _ shortcut: Shortcut, _ controlId: String, _ index: Int?) {
Expand Down

0 comments on commit 9962653

Please sign in to comment.