Skip to content
This repository was archived by the owner on Nov 17, 2025. It is now read-only.

Commit fdfb412

Browse files
steipeteclaude
andcommitted
Final KeyboardShortcuts concurrency fixes for Swift 6
- Wrap notification observer closures in Task { @mainactor } blocks - Handle event capture safely in Carbon callback wrapper - Update Name.swift setter and initializer for async MainActor calls - All Swift 6 strict concurrency compliance now achieved 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 7f1eea2 commit fdfb412

4 files changed

Lines changed: 45 additions & 21 deletions

File tree

LocalPackages/KeyboardShortcuts/Sources/KeyboardShortcuts/CarbonKeyboardShortcuts.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,10 @@ enum CarbonKeyboardShortcuts {
230230

231231
// Synchronous wrapper for Carbon callback
232232
fileprivate static func handleEventSynchronously(_ event: EventRef?) -> OSStatus {
233-
MainActor.assumeIsolated {
234-
handleEvent(event)
233+
// Create a copy of the event reference for safe capture
234+
let eventRef = event
235+
return MainActor.assumeIsolated {
236+
handleEvent(eventRef)
235237
}
236238
}
237239

LocalPackages/KeyboardShortcuts/Sources/KeyboardShortcuts/KeyboardShortcuts.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,11 +174,15 @@ public enum KeyboardShortcuts {
174174
}
175175

176176
openMenuObserver = NotificationCenter.default.addObserver(forName: NSMenu.didBeginTrackingNotification, object: nil, queue: .main) { _ in
177-
isMenuOpen = true
177+
Task { @MainActor in
178+
isMenuOpen = true
179+
}
178180
}
179181

180182
closeMenuObserver = NotificationCenter.default.addObserver(forName: NSMenu.didEndTrackingNotification, object: nil, queue: .main) { _ in
181-
isMenuOpen = false
183+
Task { @MainActor in
184+
isMenuOpen = false
185+
}
182186
}
183187

184188
isInitialized = true

LocalPackages/KeyboardShortcuts/Sources/KeyboardShortcuts/Name.swift

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ extension KeyboardShortcuts {
2727
public var shortcut: Shortcut? {
2828
get { KeyboardShortcuts.getShortcut(for: self) }
2929
nonmutating set {
30-
KeyboardShortcuts.setShortcut(newValue, for: self)
30+
Task { @MainActor in
31+
KeyboardShortcuts.setShortcut(newValue, for: self)
32+
}
3133
}
3234
}
3335

@@ -43,10 +45,15 @@ extension KeyboardShortcuts {
4345
let initialShortcut,
4446
!userDefaultsContains(name: self)
4547
{
46-
setShortcut(initialShortcut, for: self)
48+
Task { @MainActor in
49+
setShortcut(initialShortcut, for: self)
50+
KeyboardShortcuts.initialize()
51+
}
52+
} else {
53+
Task { @MainActor in
54+
KeyboardShortcuts.initialize()
55+
}
4756
}
48-
49-
KeyboardShortcuts.initialize()
5057
}
5158
}
5259
}

LocalPackages/KeyboardShortcuts/Sources/KeyboardShortcuts/RecorderCocoa.swift

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,21 @@ extension KeyboardShortcuts {
122122
private func setUpEvents() {
123123
shortcutsNameChangeObserver = NotificationCenter.default.addObserver(forName: .shortcutByNameDidChange, object: nil, queue: .main) { [weak self] notification in
124124
guard
125-
let self,
126-
let nameInNotification = notification.userInfo?["name"] as? KeyboardShortcuts.Name,
127-
nameInNotification == self.shortcutName
125+
let nameInNotification = notification.userInfo?["name"] as? KeyboardShortcuts.Name
128126
else {
129127
return
130128
}
129+
130+
Task { @MainActor in
131+
guard
132+
let self,
133+
nameInNotification == self.shortcutName
134+
else {
135+
return
136+
}
131137

132-
self.setStringValue(name: nameInNotification)
138+
self.setStringValue(name: nameInNotification)
139+
}
133140
}
134141
}
135142

@@ -182,20 +189,24 @@ extension KeyboardShortcuts {
182189
// Ensures the recorder stops when the window is hidden.
183190
// This is especially important for Settings windows, which as of macOS 13.5, only hides instead of closes when you click the close button.
184191
windowDidResignKeyObserver = NotificationCenter.default.addObserver(forName: NSWindow.didResignKeyNotification, object: window, queue: .main) { [weak self] _ in
185-
guard
186-
let self,
187-
let window = self.window
188-
else {
189-
return
190-
}
192+
Task { @MainActor in
193+
guard
194+
let self,
195+
let window = self.window
196+
else {
197+
return
198+
}
191199

192-
self.endRecording()
193-
window.makeFirstResponder(nil)
200+
self.endRecording()
201+
window.makeFirstResponder(nil)
202+
}
194203
}
195204

196205
// Ensures the recorder does not receive initial focus when a hidden window becomes unhidden.
197206
windowDidBecomeKeyObserver = NotificationCenter.default.addObserver(forName: NSWindow.didBecomeKeyNotification, object: window, queue: .main) { [weak self] _ in
198-
self?.preventBecomingKey()
207+
Task { @MainActor in
208+
self?.preventBecomingKey()
209+
}
199210
}
200211

201212
preventBecomingKey()

0 commit comments

Comments
 (0)