Merge pull request #268 from gdmka/feature/middle-click-record-toggle
Add Middle-Click to Toggle Recording
This commit is contained in:
commit
1d7022d190
@ -26,6 +26,17 @@ class HotkeyManager: ObservableObject {
|
||||
setupHotkeyMonitoring()
|
||||
}
|
||||
}
|
||||
@Published var isMiddleClickToggleEnabled: Bool {
|
||||
didSet {
|
||||
UserDefaults.standard.set(isMiddleClickToggleEnabled, forKey: "isMiddleClickToggleEnabled")
|
||||
setupHotkeyMonitoring()
|
||||
}
|
||||
}
|
||||
@Published var middleClickActivationDelay: Int {
|
||||
didSet {
|
||||
UserDefaults.standard.set(middleClickActivationDelay, forKey: "middleClickActivationDelay")
|
||||
}
|
||||
}
|
||||
|
||||
private var whisperState: WhisperState
|
||||
private var miniRecorderShortcutManager: MiniRecorderShortcutManager
|
||||
@ -39,6 +50,10 @@ class HotkeyManager: ObservableObject {
|
||||
private var globalEventMonitor: Any?
|
||||
private var localEventMonitor: Any?
|
||||
|
||||
// Middle-click event monitoring
|
||||
private var middleClickMonitors: [Any?] = []
|
||||
private var middleClickTask: Task<Void, Never>?
|
||||
|
||||
// Key state tracking
|
||||
private var currentKeyState = false
|
||||
private var keyPressStartTime: Date?
|
||||
@ -118,6 +133,11 @@ class HotkeyManager: ObservableObject {
|
||||
// ---- normal initialisation ----
|
||||
self.selectedHotkey1 = HotkeyOption(rawValue: UserDefaults.standard.string(forKey: "selectedHotkey1") ?? "") ?? .rightCommand
|
||||
self.selectedHotkey2 = HotkeyOption(rawValue: UserDefaults.standard.string(forKey: "selectedHotkey2") ?? "") ?? .none
|
||||
|
||||
self.isMiddleClickToggleEnabled = UserDefaults.standard.bool(forKey: "isMiddleClickToggleEnabled")
|
||||
let storedDelay = UserDefaults.standard.integer(forKey: "middleClickActivationDelay")
|
||||
self.middleClickActivationDelay = storedDelay > 0 ? storedDelay : 200
|
||||
|
||||
self.whisperState = whisperState
|
||||
self.miniRecorderShortcutManager = MiniRecorderShortcutManager(whisperState: whisperState)
|
||||
|
||||
@ -144,6 +164,7 @@ class HotkeyManager: ObservableObject {
|
||||
|
||||
setupModifierKeyMonitoring()
|
||||
setupCustomShortcutMonitoring()
|
||||
setupMiddleClickMonitoring()
|
||||
}
|
||||
|
||||
private func setupModifierKeyMonitoring() {
|
||||
@ -166,6 +187,40 @@ class HotkeyManager: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
private func setupMiddleClickMonitoring() {
|
||||
guard isMiddleClickToggleEnabled else { return }
|
||||
|
||||
// Mouse Down
|
||||
let downMonitor = NSEvent.addGlobalMonitorForEvents(matching: .otherMouseDown) { [weak self] event in
|
||||
guard let self = self, event.buttonNumber == 2 else { return }
|
||||
|
||||
self.middleClickTask?.cancel()
|
||||
self.middleClickTask = Task {
|
||||
do {
|
||||
let delay = UInt64(self.middleClickActivationDelay) * 1_000_000 // ms to ns
|
||||
try await Task.sleep(nanoseconds: delay)
|
||||
|
||||
guard self.isMiddleClickToggleEnabled, !Task.isCancelled else { return }
|
||||
|
||||
Task { @MainActor in
|
||||
guard self.canProcessHotkeyAction else { return }
|
||||
await self.whisperState.handleToggleMiniRecorder()
|
||||
}
|
||||
} catch {
|
||||
// Cancelled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mouse Up
|
||||
let upMonitor = NSEvent.addGlobalMonitorForEvents(matching: .otherMouseUp) { [weak self] event in
|
||||
guard let self = self, event.buttonNumber == 2 else { return }
|
||||
self.middleClickTask?.cancel()
|
||||
}
|
||||
|
||||
middleClickMonitors = [downMonitor, upMonitor]
|
||||
}
|
||||
|
||||
private func setupCustomShortcutMonitoring() {
|
||||
// Hotkey 1
|
||||
if selectedHotkey1 == .custom {
|
||||
@ -198,6 +253,14 @@ class HotkeyManager: ObservableObject {
|
||||
localEventMonitor = nil
|
||||
}
|
||||
|
||||
for monitor in middleClickMonitors {
|
||||
if let monitor = monitor {
|
||||
NSEvent.removeMonitor(monitor)
|
||||
}
|
||||
}
|
||||
middleClickMonitors = []
|
||||
middleClickTask?.cancel()
|
||||
|
||||
resetKeyStates()
|
||||
}
|
||||
|
||||
|
||||
@ -118,6 +118,48 @@ struct SettingsView: View {
|
||||
}
|
||||
}
|
||||
|
||||
SettingsSection(
|
||||
icon: "computermouse.fill",
|
||||
title: "Middle-Click Toggle",
|
||||
subtitle: "Optionally use your middle mouse button to toggle recording"
|
||||
) {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
Toggle("Enable Middle-Click Toggle", isOn: $hotkeyManager.isMiddleClickToggleEnabled.animation())
|
||||
.toggleStyle(.switch)
|
||||
|
||||
if hotkeyManager.isMiddleClickToggleEnabled {
|
||||
HStack {
|
||||
Text("Activation Delay")
|
||||
.font(.system(size: 13, weight: .medium))
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
TextField("", value: $hotkeyManager.middleClickActivationDelay, formatter: {
|
||||
let formatter = NumberFormatter()
|
||||
formatter.numberStyle = .none
|
||||
formatter.minimum = 0
|
||||
return formatter
|
||||
}())
|
||||
.textFieldStyle(PlainTextFieldStyle())
|
||||
.padding(EdgeInsets(top: 3, leading: 6, bottom: 3, trailing: 6))
|
||||
.background(Color(NSColor.textBackgroundColor))
|
||||
.cornerRadius(5)
|
||||
.frame(width: 70)
|
||||
|
||||
Text("ms")
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.transition(.opacity.combined(with: .move(edge: .top)))
|
||||
|
||||
Text("A short delay to prevent accidental toggles when closing browser tabs.")
|
||||
.font(.system(size: 12))
|
||||
.foregroundColor(.secondary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsSection(
|
||||
icon: "speaker.wave.2.bubble.left.fill",
|
||||
title: "Recording Feedback",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user