Skip to content

Commit b8b11c9

Browse files
committed
🐞 Correctly treat right/left modifiers for trigger-bypassed keybinds
1 parent 3766c3f commit b8b11c9

2 files changed

Lines changed: 19 additions & 31 deletions

File tree

Loop/Core/Observers/KeybindTrigger.swift

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,10 @@ final class KeybindTrigger {
152152
private func performKeybind(keyCode: CGKeyCode, type: CGEventType, isARepeat: Bool, flags: CGEventFlags, isLoopOpen: Bool) -> PerformKeybindResult {
153153
let flagKeys = sideDependentTriggerKey ? flags.keyCodes : flags.keyCodes.baseModifiers
154154
let allPressedKeys: Set<CGKeyCode> = pressedKeys.union(flagKeys)
155+
155156
let actionKeys: Set<CGKeyCode> = Set(allPressedKeys.subtracting(triggerKey).map(\.baseModifier))
156157
let containsTrigger = allPressedKeys.isSuperset(of: triggerKey)
158+
let allPressedKeysBaseModifiers: Set<CGKeyCode> = Set(allPressedKeys.map(\.baseModifier))
157159

158160
if isLoopOpen {
159161
if pressedKeys.contains(.kVK_Escape) {
@@ -172,19 +174,10 @@ final class KeybindTrigger {
172174
}
173175

174176
if type != .keyUp { // keyDown for flagsChanged
175-
if let bypassedAction = windowActionCache.bypassedActionsByKeybind[allPressedKeys] {
176-
if !isARepeat || bypassedAction.canRepeat {
177-
openLoop(startingAction: bypassedAction, overrideExistingTriggerDelayTimerAction: true)
178-
}
179-
180-
return checkIfLoopOpen() ? .consume : .opening
181-
}
182-
183177
if containsTrigger {
184178
// Try an match directly with the action keys first, then fallback to just the key code.
185179
// This prevents failures when the user is tapping the keys in rapid succession.
186-
let match = windowActionCache.actionsByKeybind[actionKeys]
187-
?? windowActionCache.actionsByKeybind[[keyCode]]
180+
let match = windowActionCache.actionsByKeybind[actionKeys] ?? windowActionCache.actionsByKeybind[[keyCode]]
188181

189182
if let action = match {
190183
if !isARepeat || action.canRepeat {
@@ -204,6 +197,12 @@ final class KeybindTrigger {
204197
)
205198
return .opening
206199
}
200+
} else if let bypassedAction = windowActionCache.bypassedActionsByKeybind[allPressedKeysBaseModifiers] {
201+
if !isARepeat || bypassedAction.canRepeat {
202+
openLoop(startingAction: bypassedAction, overrideExistingTriggerDelayTimerAction: true)
203+
}
204+
205+
return checkIfLoopOpen() ? .consume : .opening
207206
} else {
208207
if allPressedKeys.isEmpty {
209208
doubleClickTimer.handleKeyUp()

Loop/Settings Window/Settings/Keybinds/Keybind Recorder/Keycorder.swift

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,10 @@ struct Keycorder: View {
138138
let currentKeys = selectionKeybind + [event.keyCode]
139139
.map { $0.baseKey(flags: event.modifierFlags) }
140140

141-
var flags = CGEventFlags(cocoaFlags: event.modifierFlags)
141+
var flags = CGEventFlags(
142+
cocoaFlags: event.modifierFlags
143+
.intersection(.deviceIndependentFlagsMask) // Prevents right/left dependence
144+
)
142145

143146
if event.keyCode.isFnSpecialKey {
144147
flags.remove(.maskSecondaryFn)
@@ -193,26 +196,12 @@ struct Keycorder: View {
193196
}
194197

195198
// Validate keybind requirements when in bypass mode
196-
if bypassTriggerKey == true {
197-
let normalizedKeys = selectionKeybind.map(\.baseModifier)
198-
let modifierKeys = normalizedKeys.filter(\.isModifier)
199-
let nonModifierKeys = normalizedKeys.filter { !$0.isModifier }
200-
201-
// Check: at least one modifier key
202-
if modifierKeys.isEmpty {
203-
errorMessage = "Please include at least one modifier key."
204-
shake()
205-
shouldError = true
206-
return false
207-
}
208-
209-
// Check: at least one non-modifier key
210-
else if nonModifierKeys.isEmpty {
211-
errorMessage = "Please include at least one non-modifier key."
212-
shake()
213-
shouldError = true
214-
return false
215-
}
199+
if bypassTriggerKey == true,
200+
selectionKeybind.filter(\.isModifier).isEmpty {
201+
errorMessage = "Please include at least one modifier key."
202+
shake()
203+
shouldError = true
204+
return false
216205
}
217206

218207
let effectiveSelection = bypassTriggerKey == true

0 commit comments

Comments
 (0)