/* * Atoll (DynamicIsland) * Copyright (C) 2024-2026 Atoll Contributors * * Originally from boring.notch project * Modified and adapted for Atoll (DynamicIsland) * See NOTICE for details. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import KeyboardShortcuts import SwiftUI import Carbon extension View { public func keyboardShortcut(_ shortcut: KeyboardShortcuts.Name) -> some View { if let shortcut = shortcut.shortcut { if let keyEquivalent = shortcut.toKeyEquivalent() { return AnyView(self.keyboardShortcut(keyEquivalent, modifiers: shortcut.toEventModifiers())) } } return AnyView(self) } } extension KeyboardShortcuts.Shortcut { func toKeyEquivalent() -> KeyEquivalent? { let carbonKeyCode = UInt16(self.carbonKeyCode) let maxNameLength = 4 var nameBuffer = [UniChar](repeating: 0, count : maxNameLength) var nameLength = 0 let modifierKeys = UInt32(alphaLock >> 8) & 0xFF // Caps Lock var deadKeys: UInt32 = 0 let keyboardType = UInt32(LMGetKbdType()) let source = TISCopyCurrentKeyboardLayoutInputSource().takeRetainedValue() guard let ptr = TISGetInputSourceProperty(source, kTISPropertyUnicodeKeyLayoutData) else { NSLog("Could not get keyboard layout data") return nil } let layoutData = Unmanaged.fromOpaque(ptr).takeUnretainedValue() as Data let osStatus = layoutData.withUnsafeBytes { UCKeyTranslate($0.bindMemory(to: UCKeyboardLayout.self).baseAddress, carbonKeyCode, UInt16(kUCKeyActionDown), modifierKeys, keyboardType, UInt32(kUCKeyTranslateNoDeadKeysMask), &deadKeys, maxNameLength, &nameLength, &nameBuffer) } guard osStatus == noErr else { NSLog("Code: 0x%04X Status: %+i", carbonKeyCode, osStatus); return nil } return KeyEquivalent(Character(String(utf16CodeUnits: nameBuffer, count: nameLength))) } func toEventModifiers() -> SwiftUI.EventModifiers { var modifiers: SwiftUI.EventModifiers = [] if self.modifiers.contains(NSEvent.ModifierFlags.command) { modifiers.update(with: EventModifiers.command) } if self.modifiers.contains(NSEvent.ModifierFlags.control) { modifiers.update(with: EventModifiers.control) } if self.modifiers.contains(NSEvent.ModifierFlags.option) { modifiers.update(with: EventModifiers.option) } if self.modifiers.contains(NSEvent.ModifierFlags.shift) { modifiers.update(with: EventModifiers.shift) } if self.modifiers.contains(NSEvent.ModifierFlags.capsLock) { modifiers.update(with: EventModifiers.capsLock) } if self.modifiers.contains(NSEvent.ModifierFlags.numericPad) { modifiers.update(with: EventModifiers.numericPad) } return modifiers } }