Skip to content

Commit 848ae5f

Browse files
committed
fix: command+backtick not working if stage manager is on (closes #2053)
1 parent b5da4e0 commit 848ae5f

File tree

3 files changed

+31
-11
lines changed

3 files changed

+31
-11
lines changed

src/api-wrappers/PrivateApis.swift

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,15 +203,22 @@ func SLSRequestScreenCaptureAccess() -> UInt8
203203
let kAXFullscreenAttribute = "AXFullScreen"
204204
let kAXStatusLabelAttribute = "AXStatusLabel"
205205

206+
enum CGSSymbolicHotKey: Int, CaseIterable {
207+
case commandTab = 1
208+
case commandShiftTab = 2
209+
case commandKeyAboveTab = 6 // see keyAboveTabDependingOnInputSource
210+
}
211+
206212
// enables/disables a symbolic hotkeys. These are system shortcuts such as command+tab or Spotlight
207213
// it is possible to find all the existing hotkey IDs by using CGSGetSymbolicHotKeyValue on the first few hundred numbers
208214
// note: the effect of enabling/disabling persists after the app is quit
209215
@_silgen_name("CGSSetSymbolicHotKeyEnabled") @discardableResult
210-
func CGSSetSymbolicHotKeyEnabled(_ hotKey: Int, _ isEnabled: Bool) -> CGError
216+
func CGSSetSymbolicHotKeyEnabled(_ hotKey: CGSSymbolicHotKey.RawValue, _ isEnabled: Bool) -> CGError
211217

212-
func setNativeCommandTabEnabled(_ isEnabled: Bool) {
213-
CGSSetSymbolicHotKeyEnabled(1, isEnabled) // command+tab
214-
CGSSetSymbolicHotKeyEnabled(2, isEnabled) // command+shift+tab
218+
func setNativeCommandTabEnabled(_ isEnabled: Bool, _ hotkeys: [CGSSymbolicHotKey] = CGSSymbolicHotKey.allCases) {
219+
for hotkey in hotkeys {
220+
CGSSetSymbolicHotKeyEnabled(hotkey.rawValue, isEnabled)
221+
}
215222
}
216223

217224
// returns info about a given psn

src/logic/Preferences.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ class Preferences {
370370
return "6"
371371
}
372372

373+
/// key-above-tab is ` on US keyboard, but can be different on other keyboards
373374
static func keyAboveTabDependingOnInputSource() -> String {
374375
return LiteralKeyCodeTransformer.shared.transformedValue(NSNumber(value: kVK_ANSI_Grave)) ?? "`"
375376
}

src/ui/preferences-window/tabs/ControlsTab.swift

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,15 +136,27 @@ class ControlsTab {
136136
toggleNativeCommandTabIfNeeded()
137137
}
138138

139-
private static func toggleNativeCommandTabIfNeeded() {
140-
for atShortcut in shortcuts.values {
141-
let shortcut = atShortcut.shortcut
142-
if (shortcut.carbonModifierFlags == cmdKey || shortcut.carbonModifierFlags == (cmdKey | shiftKey)) && shortcut.carbonKeyCode == kVK_Tab {
143-
setNativeCommandTabEnabled(false)
144-
return
139+
/// commandTab and commandKeyAboveTab are self-contained in the "nextWindowShortcut" shortcuts
140+
/// but the keys of commandShiftTab can be spread between holdShortcut and a local shortcut
141+
static func combinedModifiersMatch(_ modifiers1: UInt32, _ modifiers2: UInt32) -> Bool {
142+
return (0..<5).contains {
143+
if let holdShortcut = shortcuts[Preferences.indexToName("holdShortcut", $0)] {
144+
return (holdShortcut.shortcut.carbonModifierFlags | modifiers1) == (holdShortcut.shortcut.carbonModifierFlags | modifiers2)
145145
}
146+
return false
146147
}
147-
setNativeCommandTabEnabled(true)
148+
}
149+
150+
private static func toggleNativeCommandTabIfNeeded() {
151+
let nativeHotkeys: [CGSSymbolicHotKey: (Shortcut) -> Bool] = [
152+
.commandTab: { (shortcut) in shortcut.carbonKeyCode == kVK_Tab && shortcut.carbonModifierFlags == cmdKey },
153+
.commandShiftTab: { (shortcut) in shortcut.carbonKeyCode == kVK_Tab && combinedModifiersMatch(shortcut.carbonModifierFlags, UInt32(cmdKey | shiftKey)) },
154+
.commandKeyAboveTab: { (shortcut) in shortcut.carbonModifierFlags == cmdKey && shortcut.carbonKeyCode == kVK_ANSI_Grave },
155+
]
156+
let overlappingHotkeys = shortcuts.values.compactMap { (atShortcut) in nativeHotkeys.first { $1(atShortcut.shortcut) }?.key }
157+
let nonOverlappingHotkeys: [CGSSymbolicHotKey] = Array(Set(nativeHotkeys.keys).symmetricDifference(Set(overlappingHotkeys)))
158+
setNativeCommandTabEnabled(false, overlappingHotkeys)
159+
setNativeCommandTabEnabled(true, nonOverlappingHotkeys)
148160
}
149161

150162
@objc static func shortcutChangedCallback(_ sender: NSControl) {

0 commit comments

Comments
 (0)