Skip to content

Commit f1921a3

Browse files
committed
Add fallback functionality related to function key related shortcuts for shortcut resolver
Migrate to latest version of KeyCodes and InputSources
1 parent f2f9d7e commit f1921a3

File tree

6 files changed

+71
-4
lines changed

6 files changed

+71
-4
lines changed

App/Sources/Core/Controllers/SnippetController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ final class SnippetController: @unchecked Sendable, ObservableObject {
6868
return
6969
}
7070

71-
let modifiers = VirtualModifierKey.fromCGEvent(keyCode, flags: event.flags, specialKeys: Array(store.specialKeys().keys))
71+
let modifiers = VirtualModifierKey.modifiers(for: keyCode, flags: event.flags, specialKeys: Array(store.specialKeys().keys))
7272

7373
// Figure out which modifier to apply to get the correct display value.
7474
var modifier: VirtualModifierKey?

App/Sources/Core/MachPort/MachPortRecordValidator.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ final class MachPortRecordValidator {
1616
return .cancel(.empty())
1717
}
1818

19-
let virtualModifiers = VirtualModifierKey.fromCGEvent(keyCode, flags: machPortEvent.event.flags, specialKeys: Array(store.specialKeys().keys))
19+
let virtualModifiers = VirtualModifierKey.modifiers(for: keyCode, flags: machPortEvent.event.flags, specialKeys: Array(store.specialKeys().keys))
2020
let modifiers = virtualModifiers.compactMap({ ModifierKey(rawValue: $0.rawValue) })
2121
let keyboardShortcut = KeyShortcut(
2222
id: UUID().uuidString,

App/Sources/Core/MachPort/ShortcutResolver.swift

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@ protocol KeycodeLocating {
1414
}
1515

1616
protocol LookupToken {
17+
var keyCode: Int64 { get }
18+
var flags: CGEventFlags { get }
1719
var signature: CGEventSignature { get }
1820
}
1921

2022
extension KeyCodesStore: KeycodeLocating { }
2123

2224
extension MachPortEvent: LookupToken {
25+
var flags: CGEventFlags { event.flags }
2326
var signature: CGEventSignature { CGEventSignature.from(event) }
2427
}
2528

@@ -36,7 +39,8 @@ final class ShortcutResolver {
3639
func lookup(_ token: LookupToken,
3740
bundleIdentifier: String,
3841
userModes: [UserMode] = [],
39-
partialMatch: PartialMatch = .init(rawValue: ".")) -> KeyboardShortcutResult? {
42+
partialMatch: PartialMatch = .init(rawValue: "."),
43+
fallback: Bool = true) -> KeyboardShortcutResult? {
4044
let eventSignature = token.signature
4145
if !userModes.isEmpty {
4246
for userMode in userModes {
@@ -76,7 +80,20 @@ final class ShortcutResolver {
7680

7781
if Self.debug { print("globalKey: \(globalKey)") }
7882

79-
return cache[globalKey]
83+
if let globalKeyResult = cache[globalKey] {
84+
return globalKeyResult
85+
} else if fallback && SpecialKeys.functionKeys.contains(Int(token.keyCode)) {
86+
var newFlags = token.flags
87+
if newFlags.contains(.maskSecondaryFn) {
88+
newFlags.remove(.maskSecondaryFn)
89+
} else {
90+
newFlags.insert(.maskSecondaryFn)
91+
}
92+
let fallbackToken = FallbackLookupToken(keyCode: token.keyCode, flags: newFlags)
93+
return lookup(fallbackToken, bundleIdentifier: bundleIdentifier, fallback: false)
94+
} else {
95+
return nil
96+
}
8097
}
8198

8299
func allMatchingPrefix(_ prefix: String, shortcutIndexPrefix: Int) -> [Workflow] {
@@ -289,3 +306,9 @@ struct SpecialKeys {
289306
kVK_JIS_KeypadComma,
290307
]
291308
}
309+
310+
private struct FallbackLookupToken: LookupToken {
311+
var keyCode: Int64
312+
var signature: CGEventSignature { CGEventSignature(keyCode, flags) }
313+
var flags: CGEventFlags
314+
}

Configurations/Release.xcconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ ENABLE_NS_ASSERTIONS = NO
44
VALIDATE_PRODUCT = YES
55
MTL_ENABLE_DEBUG_INFO = NO
66
SWIFT_OPTIMIZATION_LEVEL = -Owholemodule
7+
_EXPERIMENTAL_SWIFT_EXPLICIT_MODULES = YES

UnitTests/Sources/Controllers/MachPortRecordValidatorTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import InputSources
33
@testable import MachPort
44
@testable import Keyboard_Cowboy
55

6+
@MainActor
67
final class MachPortRecordValidatorTests: XCTestCase {
78
func testValidatorMapping_LeftCommand_S() {
89
let validator = MachPortRecordValidator(store: KeyCodesStore(InputSourceController()))

UnitTests/Sources/Controllers/ShortcutResolverTests.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ final class ShortcutResolverTests: XCTestCase {
6969
}
7070

7171
// https://github.com/zenangst/KeyboardCowboy/issues/562
72+
@MainActor
7273
func testFix562() throws {
7374
let fixture = Self.rootPath.appending(path: "Fixtures/json/example_config/bug_562.json")
7475
let fileManager = FileManager.default
@@ -143,6 +144,17 @@ final class ShortcutResolverTests: XCTestCase {
143144
}
144145
}
145146

147+
// Verify F20 (without function-key)
148+
do {
149+
switch shortcutResolver.lookup(
150+
LookupTokenMock(keyCode: Int64(kVK_F20), flags: CGEventFlags(arrayLiteral: [.maskNonCoalesced])),
151+
bundleIdentifier: "*"
152+
) {
153+
case .exact(let workflow): XCTAssertEqual(workflow.name, "Paste")
154+
default: XCTFail("")
155+
}
156+
}
157+
146158
// Verify Home
147159
do {
148160
switch shortcutResolver.lookup(
@@ -192,6 +204,32 @@ final class ShortcutResolverTests: XCTestCase {
192204
}
193205
}
194206

207+
// Verify Command + Control + Shift + Option + Left Arrow without secondary function key
208+
do {
209+
switch shortcutResolver.lookup(
210+
LookupTokenMock(
211+
keyCode: Int64(kVK_LeftArrow),
212+
flags: CGEventFlags(
213+
arrayLiteral: [
214+
.maskShift,
215+
.maskLeftShift,
216+
.maskControl,
217+
.maskLeftControl,
218+
.maskAlternate,
219+
.maskLeftAlternate,
220+
.maskCommand,
221+
.maskLeftCommand,
222+
.maskNumericPad,
223+
.maskNonCoalesced]
224+
)
225+
),
226+
bundleIdentifier: "*"
227+
) {
228+
case .exact(let workflow): XCTAssertEqual(workflow.name, "Next Tab")
229+
default: XCTFail("")
230+
}
231+
}
232+
195233
// Verify Command + Control + Shift + Option + Right Arrow
196234
do {
197235
switch shortcutResolver.lookup(
@@ -234,9 +272,13 @@ fileprivate class KeyCodeLoookupMock: KeycodeLocating {
234272
}
235273

236274
fileprivate struct LookupTokenMock: LookupToken {
275+
var keyCode: Int64
237276
var signature: CGEventSignature
277+
var flags: CGEventFlags
238278

239279
init(keyCode: Int64, flags: CGEventFlags) {
280+
self.keyCode = keyCode
281+
self.flags = flags
240282
self.signature = CGEventSignature(keyCode, flags)
241283
}
242284
}

0 commit comments

Comments
 (0)