vChewing-macOS/Source/InputSourceHelper.swift

143 lines
5.3 KiB
Swift

//
// OVInputSourceHelper.swift
//
// Copyright (c) 2011 The McBopomofo Project.
//
// Contributors:
// Mengjuei Hsieh (@mjhsieh)
// Weizhong Yang (@zonble)
//
// Based on the Syrup Project and the Formosana Library
// by Lukhnos Liu (@lukhnos).
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
import Cocoa
import Carbon
public class InputSourceHelper: NSObject {
@available(*, unavailable)
public override init() {
super.init()
}
public static func allInstalledInputSources() -> [TISInputSource] {
TISCreateInputSourceList(nil, true).takeRetainedValue() as! [TISInputSource]
}
@objc (inputSourceForProperty:stringValue:)
public static func inputSource(for propertyKey: CFString, stringValue: String) -> TISInputSource? {
let stringID = CFStringGetTypeID()
for source in allInstalledInputSources() {
if let propertyPtr = TISGetInputSourceProperty(source, propertyKey) {
let property = Unmanaged<CFTypeRef>.fromOpaque(propertyPtr).takeUnretainedValue()
let typeID = CFGetTypeID(property)
if typeID != stringID {
continue
}
if stringValue == property as? String {
return source
}
}
}
return nil
}
@objc (inputSourceForInputSourceID:)
public static func inputSource(for sourceID: String) -> TISInputSource? {
inputSource(for: kTISPropertyInputSourceID, stringValue: sourceID)
}
@objc (inputSourceEnabled:)
public static func inputSourceEnabled(for source: TISInputSource) -> Bool {
if let valuePts = TISGetInputSourceProperty(source, kTISPropertyInputSourceIsEnabled) {
let value = Unmanaged<CFBoolean>.fromOpaque(valuePts).takeUnretainedValue()
return value == kCFBooleanTrue
}
return false
}
@objc (enableInputSource:)
public static func enable(inputSource: TISInputSource) -> Bool {
let status = TISEnableInputSource(inputSource)
return status == noErr
}
@objc (enableAllInputModesForInputSourceBundleID:)
public static func enableAllInputMode(for inputSourceBundleD: String) -> Bool {
var enabled = false
for source in allInstalledInputSources() {
guard let bundleIDPtr = TISGetInputSourceProperty(source, kTISPropertyBundleID),
let _ = TISGetInputSourceProperty(source, kTISPropertyInputModeID) else {
continue
}
let bundleID = Unmanaged<CFString>.fromOpaque(bundleIDPtr).takeUnretainedValue()
if String(bundleID) == inputSourceBundleD {
let modeEnabled = self.enable(inputSource: source)
if !modeEnabled {
return false
}
enabled = true
}
}
return enabled
}
@objc (enableInputMode:forInputSourceBundleID:)
public static func enable(inputMode modeID: String, for bundleID: String) -> Bool {
for source in allInstalledInputSources() {
guard let bundleIDPtr = TISGetInputSourceProperty(source, kTISPropertyBundleID),
let modePtr = TISGetInputSourceProperty(source, kTISPropertyInputModeID) else {
continue
}
let inputsSourceBundleID = Unmanaged<CFString>.fromOpaque(bundleIDPtr).takeUnretainedValue()
let inputsSourceModeID = Unmanaged<CFString>.fromOpaque(modePtr).takeUnretainedValue()
if modeID == String(inputsSourceModeID) && bundleID == String(inputsSourceBundleID) {
let enabled = enable(inputSource: source)
print("Attempt to enable input source of mode: \(modeID), bundle ID: \(bundleID), result: \(enabled)")
return enabled
}
}
print("Failed to find any matching input source of mode: \(modeID), bundle ID: \(bundleID)")
return false
}
@objc (disableInputSource:)
public static func disable(inputSource: TISInputSource) -> Bool {
let status = TISDisableInputSource(inputSource)
return status == noErr
}
@objc (registerInputSource:)
public static func registerTnputSource(at url: URL) -> Bool {
let status = TISRegisterInputSource(url as CFURL)
return status == noErr
}
}