feature: user-selectable capture hotkey with recorder in Settings
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import AppKit
|
||||
import Carbon.HIToolbox
|
||||
import Foundation
|
||||
import Observation
|
||||
import SwiftUI
|
||||
@@ -37,6 +36,9 @@ public final class AppModel {
|
||||
public private(set) var outboxURL: URL
|
||||
/// Live watch folder; WP-4c updates this alongside `ReturnWatcher.updateWatchFolder`.
|
||||
public private(set) var watchFolderURL: URL
|
||||
/// Currently bound capture combo (the last one Carbon accepted, or the preferred load).
|
||||
private(set) var captureHotkey: HotkeyPreference
|
||||
var hotkeyDisplayString: String { captureHotkey.displayString }
|
||||
|
||||
let paths: AppSupportPaths
|
||||
let spool: SpoolStore
|
||||
@@ -80,6 +82,7 @@ public final class AppModel {
|
||||
self.watchFolderURL = folders.watch
|
||||
self.outboxDisplayName = folders.outbox.lastPathComponent
|
||||
self.watchFolderDisplayName = folders.watch.lastPathComponent
|
||||
self.captureHotkey = HotkeyPreference.load()
|
||||
}
|
||||
|
||||
// MARK: Seam mutators — the only way a WP-4b/4c extension changes state.
|
||||
@@ -146,16 +149,39 @@ public final class AppModel {
|
||||
setStatus((error as? ShotdeckError)?.errorDescription ?? "Could not watch the return folder.")
|
||||
}
|
||||
|
||||
let registered = hotkeys.register(
|
||||
let pref = HotkeyPreference.load()
|
||||
captureHotkey = pref
|
||||
if !bindCaptureHotkey(pref) {
|
||||
setStatus("\(pref.displayString) is already used by another app — capture only works from the menu.")
|
||||
}
|
||||
}
|
||||
|
||||
/// Unregisters `capture` and binds `HotkeyPreference.load()`. If Carbon rejects the new
|
||||
/// combo, restores the previous preference (UserDefaults + Carbon) so the old one keeps working.
|
||||
func reRegisterHotkey() {
|
||||
let previous = captureHotkey
|
||||
let next = HotkeyPreference.load()
|
||||
hotkeys.unregister(id: "capture")
|
||||
if bindCaptureHotkey(next) {
|
||||
captureHotkey = next
|
||||
return
|
||||
}
|
||||
setStatus("That combination is taken — pick another.")
|
||||
previous.save()
|
||||
if bindCaptureHotkey(previous) {
|
||||
captureHotkey = previous
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
private func bindCaptureHotkey(_ pref: HotkeyPreference) -> Bool {
|
||||
hotkeys.register(
|
||||
id: "capture",
|
||||
keyCode: UInt32(kVK_ANSI_2),
|
||||
modifiers: UInt32(optionKey | shiftKey)
|
||||
keyCode: pref.keyCode,
|
||||
modifiers: pref.modifiers
|
||||
) { [weak self] in
|
||||
Task { await self?.captureNow() }
|
||||
}
|
||||
if !registered {
|
||||
setStatus("⌥⇧2 is already used by another app — capture only works from the menu.")
|
||||
}
|
||||
}
|
||||
|
||||
public func captureNow() async {
|
||||
|
||||
Reference in New Issue
Block a user