From f013d9960876fa26a22226c100dd6db3c0e2a0e4 Mon Sep 17 00:00:00 2001 From: Kai Azim <68963405+MrKai77@users.noreply.github.com> Date: Fri, 15 Sep 2023 22:37:03 -0600 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20#35=20Don't=20activate=20Loop=20?= =?UTF-8?q?when=20`Caps=20Lock`=20key=20is=20enabled?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Loop/Managers/LoopManager.swift | 10 ++- Loop/Settings/KeybindingSettingsView.swift | 26 +++++-- Loop/Utilities/Keycorder.swift | 87 ++++++++++------------ 3 files changed, 66 insertions(+), 57 deletions(-) diff --git a/Loop/Managers/LoopManager.swift b/Loop/Managers/LoopManager.swift index c5255224..345747bb 100644 --- a/Loop/Managers/LoopManager.swift +++ b/Loop/Managers/LoopManager.swift @@ -71,15 +71,16 @@ class LoopManager { } private func handleLoopKeypress(_ event: NSEvent) { + if event.modifierFlags.intersection(.deviceIndependentFlagsMask).contains(.capsLock) { + self.closeLoop(forceClose: true) + return + } if event.keyCode == Defaults[.triggerKey].keycode { let useTriggerDelay = Defaults[.triggerDelay] > 0.1 let useDoubleClickTrigger = Defaults[.doubleClickToTrigger] - if event.modifierFlags.rawValue == 256 { - if useTriggerDelay { - self.cancelTriggerDelayTimer() - } + if event.modifierFlags.rawValue == 256 { self.closeLoop() } else { if useDoubleClickTrigger { @@ -130,6 +131,7 @@ class LoopManager { private func closeLoop(forceClose: Bool = false) { var willResizeWindow: Bool = false + self.cancelTriggerDelayTimer() radialMenuController.close() previewController.close() diff --git a/Loop/Settings/KeybindingSettingsView.swift b/Loop/Settings/KeybindingSettingsView.swift index 116f7e41..e41b699d 100644 --- a/Loop/Settings/KeybindingSettingsView.swift +++ b/Loop/Settings/KeybindingSettingsView.swift @@ -18,17 +18,33 @@ struct KeybindingSettingsView: View { let loopTriggerKeyOptions = TriggerKey.options @State var suggestAddingTriggerDelay: Bool = false + @State var suggestDisablingCapsLock: Bool = false var body: some View { Form { Section("Keybindings") { VStack(alignment: .leading) { - Keycorder("Trigger Key", key: self.$triggerKey, onChange: { event in - for key in TriggerKey.options where key.keycode == event.keyCode { - return key + HStack { + Text("Trigger Key") + Spacer() + Keycorder(key: self.$triggerKey) { event in + if event.modifierFlags.intersection(.deviceIndependentFlagsMask).contains(.capsLock) { + self.suggestDisablingCapsLock = true + return nil + } else { + self.suggestDisablingCapsLock = false + } + + for key in TriggerKey.options where key.keycode == event.keyCode { + return key + } + return nil } - return nil - }) + .popover(isPresented: $suggestDisablingCapsLock, arrowEdge: .bottom, content: { + Text("Your Caps Lock key is on! Disable it to correctly assign a key.") + .padding(8) + }) + } if triggerKey.keycode == .kVK_RightControl { Text("Tip: To use caps lock, remap it to control in System Settings!") diff --git a/Loop/Utilities/Keycorder.swift b/Loop/Utilities/Keycorder.swift index 447f7037..c93205a1 100644 --- a/Loop/Utilities/Keycorder.swift +++ b/Loop/Utilities/Keycorder.swift @@ -8,7 +8,6 @@ import SwiftUI struct Keycorder: View { - private let label: String @State private var validCurrentKey: Binding private let onChange: (NSEvent) -> TriggerKey? @@ -20,10 +19,8 @@ struct Keycorder: View { @State private var isActive: Bool = false init( - _ label: String, key: Binding, onChange: @escaping (NSEvent) -> (TriggerKey?)) { - self.label = label self.validCurrentKey = key self.selectionKey = key.wrappedValue self.onChange = onChange @@ -33,70 +30,63 @@ struct Keycorder: View { let noAnimation = Animation.linear(duration: 0) var body: some View { - HStack(spacing: 5) { - Text(label) - - Spacer() - - Button(action: { - self.selectionKey = nil - }, label: { - HStack(spacing: 5) { - if let symbol = selectionKey?.symbol { - Image(systemName: symbol) - } - Text(self.selectionKey?.name ?? "Click a modifier key...") - - Image(systemName: "xmark") - .fontWeight(.bold) - .scaleEffect(0.7) - .foregroundStyle(.white) - .padding(1) - .background { - RoundedRectangle(cornerRadius: 4) - .foregroundStyle(.quaternary) - .opacity(!(self.isHovering || self.isActive) ? 1 : 0) - } + Button(action: { + self.selectionKey = nil + }, label: { + HStack(spacing: 5) { + if let symbol = selectionKey?.symbol { + Image(systemName: symbol) } - .padding(2) - .padding(.leading, 5) - .background { - RoundedRectangle(cornerRadius: 6) - .foregroundStyle(.secondary.shadow(.inner(color: .white, radius: 0, x: 0, y: 0.5))) - .shadow(color: .black, radius: 0.5, x: 0, y: 1) - .opacity(0.5) - .opacity(isActive ? 0.5 : 1) - .animation(isActive ? activeAnimation : noAnimation, value: isActive) - .opacity((self.isHovering || self.isActive) ? 1 : 0) - } - }) - .modifier(ShakeEffect(shakes: self.shouldShake ? 2 : 0)) - .animation(Animation.default, value: shouldShake) - .onHover { hovering in - self.isHovering = hovering + Text(self.selectionKey?.name ?? "Click a modifier key...") + + Image(systemName: "xmark") + .fontWeight(.bold) + .scaleEffect(0.7) + .foregroundStyle(.white) + .padding(1) + .background { + RoundedRectangle(cornerRadius: 4) + .foregroundStyle(.quaternary) + .opacity(!(self.isHovering || self.isActive) ? 1 : 0) + } + } + .padding(2) + .padding(.leading, 5) + .background { + RoundedRectangle(cornerRadius: 6) + .foregroundStyle(.secondary.shadow(.inner(color: .white, radius: 0, x: 0, y: 0.5))) + .shadow(color: .black, radius: 0.5, x: 0, y: 1) + .opacity(0.5) + .opacity(isActive ? 0.5 : 1) + .animation(isActive ? activeAnimation : noAnimation, value: isActive) + .opacity((self.isHovering || self.isActive) ? 1 : 0) } + }) + .modifier(ShakeEffect(shakes: self.shouldShake ? 2 : 0)) + .animation(Animation.default, value: shouldShake) + .onHover { hovering in + self.isHovering = hovering } .buttonStyle(.plain) .onChange(of: self.selectionKey) { _ in if self.selectionKey == nil { - self.isActive = true self.startObservingKeys() } } } func startObservingKeys() { + self.isActive = true self.eventMonitor = NSEventMonitor(scope: .local, eventMask: .flagsChanged) { event in self.selectionKey = self.onChange(event) - let keyUp = 256 + let keyUpValue = 256 - if event.modifierFlags.rawValue == keyUp && self.selectionKey != nil { - self.isActive = false + if event.modifierFlags.rawValue == keyUpValue && self.selectionKey != nil { self.finishedObservingKeys() return } - if event.modifierFlags.rawValue != keyUp && self.selectionKey == nil { + if event.modifierFlags.rawValue != keyUpValue && self.selectionKey == nil { self.shouldShake.toggle() } @@ -109,6 +99,7 @@ struct Keycorder: View { } func finishedObservingKeys() { + self.isActive = false self.eventMonitor?.stop() self.eventMonitor = nil }