46 lines
1.7 KiB
Swift
46 lines
1.7 KiB
Swift
import Carbon
|
|
|
|
class KeyboardLayout {
|
|
/// Return a string ID of the current keyboard input source.
|
|
static var id: String? {
|
|
if let source = TISCopyCurrentKeyboardInputSource()?.takeRetainedValue(),
|
|
let sourceIdPointer = TISGetInputSourceProperty(source, kTISPropertyInputSourceID) {
|
|
let sourceId = Unmanaged<CFString>.fromOpaque(sourceIdPointer).takeUnretainedValue()
|
|
return sourceId as String
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
/// Translate a physical keyCode to the unmodified character under the current keyboard layout.
|
|
static func character(forKeyCode keyCode: UInt16) -> String? {
|
|
guard let source = TISCopyCurrentKeyboardInputSource()?.takeRetainedValue(),
|
|
let layoutDataPointer = TISGetInputSourceProperty(source, kTISPropertyUnicodeKeyLayoutData) else {
|
|
return nil
|
|
}
|
|
|
|
let layoutData = unsafeBitCast(layoutDataPointer, to: CFData.self)
|
|
guard let bytes = CFDataGetBytePtr(layoutData) else { return nil }
|
|
let keyboardLayout = UnsafeRawPointer(bytes).assumingMemoryBound(to: UCKeyboardLayout.self)
|
|
|
|
var deadKeyState: UInt32 = 0
|
|
var chars = [UniChar](repeating: 0, count: 4)
|
|
var length = 0
|
|
|
|
let status = UCKeyTranslate(
|
|
keyboardLayout,
|
|
keyCode,
|
|
UInt16(kUCKeyActionDisplay),
|
|
0,
|
|
UInt32(LMGetKbdType()),
|
|
UInt32(kUCKeyTranslateNoDeadKeysBit),
|
|
&deadKeyState,
|
|
chars.count,
|
|
&length,
|
|
&chars
|
|
)
|
|
|
|
guard status == noErr, length > 0 else { return nil }
|
|
return String(utf16CodeUnits: chars, count: length).lowercased()
|
|
}
|
|
}
|