- CGEvent cghidEventTap 全局监听 Fn 键 - Apple Speech 流式语音识别(zh-CN 默认) - 实时音频 RMS 电平驱动波形动画 - NSPanel 胶囊浮动窗口 - 剪贴板 + Cmd+V 文本注入,CJK 输入法自动切换 - OpenAI 兼容 LLM 纠错(DeepSeek 预设) - LSUIElement 菜单栏运行 - SPM + Makefile 构建
72 lines
2.8 KiB
Swift
72 lines
2.8 KiB
Swift
import Carbon
|
||
import Foundation
|
||
|
||
/// 管理输入法切换,用于在粘贴前临时切换到 ASCII 输入源
|
||
struct InputSourceManager {
|
||
|
||
/// 获取当前输入源 ID
|
||
static func currentInputSourceID() -> String? {
|
||
guard let source = TISCopyCurrentKeyboardInputSource()?.takeRetainedValue() else {
|
||
return nil
|
||
}
|
||
return TISGetInputSourceProperty(source, kTISPropertyInputSourceID)
|
||
.flatMap { Unmanaged<CFString>.fromOpaque($0).takeUnretainedValue() as String }
|
||
}
|
||
|
||
/// 判断当前输入源是否为 CJK 输入法
|
||
static func isCJKInputSource() -> Bool {
|
||
guard let id = currentInputSourceID() else { return false }
|
||
let cjkPrefixes = [
|
||
"com.apple.inputmethod.Kotoeri", // 日语
|
||
"com.apple.inputmethod.SCIM", // 简体中文
|
||
"com.apple.inputmethod.TCIM", // 繁体中文
|
||
"com.apple.inputmethod.Korean", // 韩语
|
||
"com.apple.inputmethod.2SetHangul",
|
||
"com.apple.inputmethod.3SetHangul",
|
||
"com.apple.inputmethod.390Hangul",
|
||
"com.apple.inputmethod.GongjinCheong",
|
||
"com.apple.inputmethod.HNC"
|
||
]
|
||
return cjkPrefixes.contains(where: { id.hasPrefix($0) })
|
||
}
|
||
|
||
/// 查找 ASCII 输入源(ABC 键盘)
|
||
static func findASCIIInputSource() -> TISInputSource? {
|
||
let properties: [CFString: Any] = [
|
||
kTISPropertyInputSourceType: kTISTypeKeyboardLayout as CFString,
|
||
kTISPropertyInputSourceIsASCIICapable: true as CFBoolean
|
||
]
|
||
guard let list = TISCreateInputSourceList(properties as CFDictionary, false)?
|
||
.takeRetainedValue() as? [TISInputSource] else {
|
||
return nil
|
||
}
|
||
// 优先选择 "ABC" 或 "U.S."
|
||
for source in list {
|
||
if let id = TISGetInputSourceProperty(source, kTISPropertyInputSourceID)
|
||
.flatMap({ Unmanaged<CFString>.fromOpaque($0).takeUnretainedValue() as String }) {
|
||
if id == "com.apple.keylayout.ABC" || id == "com.apple.keylayout.US" {
|
||
return source
|
||
}
|
||
}
|
||
}
|
||
// 回退到第一个 ASCII 能力的输入源
|
||
return list.first
|
||
}
|
||
|
||
/// 切换到指定输入源并返回原输入源
|
||
static func switchToASCII() -> TISInputSource? {
|
||
let original = TISCopyCurrentKeyboardInputSource()?.takeRetainedValue()
|
||
guard let asciiSource = findASCIIInputSource() else {
|
||
return original
|
||
}
|
||
TISSelectInputSource(asciiSource)
|
||
return original
|
||
}
|
||
|
||
/// 恢复到指定输入源
|
||
static func restore(_ source: TISInputSource?) {
|
||
guard let source = source else { return }
|
||
TISSelectInputSource(source)
|
||
}
|
||
}
|