KeyboardNavigationModifier.swift (1603B)
1 import SwiftUI 2 3 struct ShortcutKey: Hashable { 4 let key: KeyEquivalent 5 let modifiers: EventModifiers 6 7 init(key: KeyEquivalent, modifiers: EventModifiers = []) { 8 self.key = key 9 self.modifiers = modifiers 10 } 11 12 static func == (lhs: ShortcutKey, rhs: ShortcutKey) -> Bool { 13 lhs.key == rhs.key && lhs.modifiers == rhs.modifiers 14 } 15 16 func hash(into hasher: inout Hasher) { 17 hasher.combine(key) 18 hasher.combine(modifiers.rawValue) 19 } 20 } 21 22 extension View { 23 func keyboardNavigation(_ bindings: [ShortcutKey: () -> KeyPress.Result]) -> some View { 24 self.onKeyPress { press in 25 let key = normalizeKey(press) 26 let modifiers = normalizeModifiers(press.modifiers) 27 let shortcut = ShortcutKey(key: key, modifiers: modifiers) 28 29 if let action = bindings[shortcut] { 30 return action() 31 } 32 return .ignored 33 } 34 } 35 36 private func normalizeKey(_ press: KeyPress) -> KeyEquivalent { 37 // Normalize backspace/delete key 38 if press.characters == "\u{7F}" { 39 return .delete 40 } 41 return press.key 42 } 43 44 private func normalizeModifiers(_ modifiers: EventModifiers) -> EventModifiers { 45 // Mask to only meaningful shortcut modifiers, excluding system artifacts 46 // like .function (deprecated), .numericPad, .capsLock, etc. 47 let shortcutModifierMask: EventModifiers = [.command, .shift, .option, .control] 48 return EventModifiers(rawValue: modifiers.rawValue & shortcutModifierMask.rawValue) 49 } 50 }