Fix add button. Fix hotkeys in settings. Add Workspace hotkeys

This commit is contained in:
2026-03-13 17:25:00 +11:00
parent fe6c7d8c12
commit 1e30e9bf9e
17 changed files with 232 additions and 50 deletions

View File

@@ -5,7 +5,7 @@ import Combine
/// Manages global and local hotkeys.
///
/// The toggle hotkey uses Carbon's `RegisterEventHotKey` which works
/// system-wide without Accessibility permission. Tab-level hotkeys
/// system-wide without Accessibility permission. Notch-scoped hotkeys
/// use a local `NSEvent` monitor (only fires when our app is active).
@MainActor
class HotkeyManager {
@@ -19,21 +19,29 @@ class HotkeyManager {
var onCloseTab: (() -> Void)?
var onNextTab: (() -> Void)?
var onPreviousTab: (() -> Void)?
var onNextWorkspace: (() -> Void)?
var onPreviousWorkspace: (() -> Void)?
var onDetachTab: (() -> Void)?
var onApplySizePreset: ((TerminalSizePreset) -> Void)?
var onSwitchToTab: ((Int) -> Void)?
var onSwitchToWorkspace: ((WorkspaceID) -> Void)?
/// Tab-level hotkeys only fire when the notch is open.
/// Notch-scoped hotkeys only fire when the notch is open.
var isNotchOpen: Bool = false
private var hotKeyRef: EventHotKeyRef?
private var eventHandlerRef: EventHandlerRef?
private var localMonitor: Any?
private let settingsProvider: TerminalSessionConfigurationProviding
private let workspaceRegistry: WorkspaceRegistry
private var settingsCancellable: AnyCancellable?
init(settingsProvider: TerminalSessionConfigurationProviding? = nil) {
init(
settingsProvider: TerminalSessionConfigurationProviding? = nil,
workspaceRegistry: WorkspaceRegistry? = nil
) {
self.settingsProvider = settingsProvider ?? AppSettingsController.shared
self.workspaceRegistry = workspaceRegistry ?? WorkspaceRegistry.shared
}
// MARK: - Resolved bindings from typed runtime settings
@@ -53,6 +61,12 @@ class HotkeyManager {
private var prevTabBinding: HotkeyBinding {
settingsProvider.hotkeySettings.previousTab
}
private var nextWorkspaceBinding: HotkeyBinding {
settingsProvider.hotkeySettings.nextWorkspace
}
private var previousWorkspaceBinding: HotkeyBinding {
settingsProvider.hotkeySettings.previousWorkspace
}
private var detachBinding: HotkeyBinding {
settingsProvider.hotkeySettings.detachTab
}
@@ -173,7 +187,7 @@ class HotkeyManager {
}
}
// MARK: - Local monitor (tab-level hotkeys, only when our app is active)
// MARK: - Local monitor (notch-level hotkeys, only when our app is active)
private func installLocalMonitor() {
localMonitor = NSEvent.addLocalMonitorForEvents(matching: .keyDown) { [weak self] event in
@@ -189,9 +203,9 @@ class HotkeyManager {
}
}
/// Handles tab-level hotkeys. Returns true if the event was consumed.
/// Handles notch-scoped hotkeys. Returns true if the event was consumed.
private func handleLocalKeyEvent(_ event: NSEvent) -> Bool {
// Tab hotkeys only when the notch is open and focused
// Local shortcuts only fire when the notch is open and focused.
guard isNotchOpen else { return false }
if newTabBinding.matches(event) {
@@ -210,10 +224,25 @@ class HotkeyManager {
onPreviousTab?()
return true
}
if nextWorkspaceBinding.matches(event) {
onNextWorkspace?()
return true
}
if previousWorkspaceBinding.matches(event) {
onPreviousWorkspace?()
return true
}
if detachBinding.matches(event) {
onDetachTab?()
return true
}
for summary in workspaceRegistry.workspaceSummaries {
guard let binding = summary.hotkey else { continue }
if binding.matches(event) {
onSwitchToWorkspace?(summary.id)
return true
}
}
for preset in sizePresets {
guard let binding = preset.hotkey else { continue }
if binding.matches(event) {