Repo // Deprecating Zonble's InputSourceHelper.
This commit is contained in:
parent
790463d640
commit
abbf94a2d7
1
AUTHORS
1
AUTHORS
|
@ -20,7 +20,6 @@ $ Contributors and volunteers of the upstream repo, having no responsibility in
|
||||||
- Notifier window and Tooltip UI.
|
- Notifier window and Tooltip UI.
|
||||||
- FSEventStreamHelper.
|
- FSEventStreamHelper.
|
||||||
- App-style installer (only preserved for developer purposes).
|
- App-style installer (only preserved for developer purposes).
|
||||||
- InputSource Helper.
|
|
||||||
- mgrPrefs (userdefaults manager).
|
- mgrPrefs (userdefaults manager).
|
||||||
- apiUpdate.
|
- apiUpdate.
|
||||||
- Mengjuei Hsieh:
|
- Mengjuei Hsieh:
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
// requirements defined in MIT License.
|
// requirements defined in MIT License.
|
||||||
|
|
||||||
import Cocoa
|
import Cocoa
|
||||||
|
import InputMethodKit
|
||||||
|
|
||||||
private let kTargetBin = "vChewing"
|
private let kTargetBin = "vChewing"
|
||||||
private let kTargetType = "app"
|
private let kTargetType = "app"
|
||||||
|
@ -47,6 +48,17 @@ class AppDelegate: NSWindowController, NSApplicationDelegate {
|
||||||
private var translocationRemovalStartTime: Date?
|
private var translocationRemovalStartTime: Date?
|
||||||
private var currentVersionNumber: Int = 0
|
private var currentVersionNumber: Int = 0
|
||||||
|
|
||||||
|
let imeURLInstalled = realHomeDir.appendingPathComponent("Library/Input Methods/vChewing.app")
|
||||||
|
|
||||||
|
var allRegisteredInstancesOfThisInputMethod: [TISInputSource] {
|
||||||
|
guard let components = Bundle(url: imeURLInstalled)?.infoDictionary?["ComponentInputModeDict"] as? [String: Any],
|
||||||
|
let tsInputModeListKey = components["tsInputModeListKey"] as? [String: Any]
|
||||||
|
else {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return tsInputModeListKey.keys.compactMap { TISInputSource.generate(from: $0) }
|
||||||
|
}
|
||||||
|
|
||||||
func runAlertPanel(title: String, message: String, buttonTitle: String) {
|
func runAlertPanel(title: String, message: String, buttonTitle: String) {
|
||||||
let alert = NSAlert()
|
let alert = NSAlert()
|
||||||
alert.alertStyle = .informational
|
alert.alertStyle = .informational
|
||||||
|
@ -230,23 +242,20 @@ class AppDelegate: NSWindowController, NSApplicationDelegate {
|
||||||
endAppWithDelay()
|
endAppWithDelay()
|
||||||
}
|
}
|
||||||
|
|
||||||
let imeURLInstalled = realHomeDir.appendingPathComponent("Library/Input Methods/vChewing.app")
|
|
||||||
|
|
||||||
_ = try? shell("/usr/bin/xattr -drs com.apple.quarantine \(kTargetPartialPath)")
|
_ = try? shell("/usr/bin/xattr -drs com.apple.quarantine \(kTargetPartialPath)")
|
||||||
|
|
||||||
guard let imeBundle = Bundle(url: imeURLInstalled),
|
guard let theBundle = Bundle(url: imeURLInstalled),
|
||||||
let imeIdentifier = imeBundle.bundleIdentifier
|
let imeIdentifier = theBundle.bundleIdentifier
|
||||||
else {
|
else {
|
||||||
endAppWithDelay()
|
endAppWithDelay()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let imeBundleURL = imeBundle.bundleURL
|
let imeBundleURL = theBundle.bundleURL
|
||||||
var inputSource = InputSourceHelper.inputSource(for: imeIdentifier)
|
|
||||||
|
|
||||||
if inputSource == nil {
|
if allRegisteredInstancesOfThisInputMethod.isEmpty {
|
||||||
NSLog("Registering input source \(imeIdentifier) at \(imeBundleURL.absoluteString).")
|
NSLog("Registering input source \(imeIdentifier) at \(imeBundleURL.absoluteString).")
|
||||||
let status = InputSourceHelper.registerTnputSource(at: imeBundleURL)
|
let status = (TISRegisterInputSource(imeBundleURL as CFURL) == noErr)
|
||||||
if !status {
|
if !status {
|
||||||
let message = String(
|
let message = String(
|
||||||
format: NSLocalizedString(
|
format: NSLocalizedString(
|
||||||
|
@ -262,8 +271,7 @@ class AppDelegate: NSWindowController, NSApplicationDelegate {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
inputSource = InputSourceHelper.inputSource(for: imeIdentifier)
|
if allRegisteredInstancesOfThisInputMethod.isEmpty {
|
||||||
if inputSource == nil {
|
|
||||||
let message = String(
|
let message = String(
|
||||||
format: NSLocalizedString(
|
format: NSLocalizedString(
|
||||||
"Cannot find input source %@ after registration.", comment: ""
|
"Cannot find input source %@ after registration.", comment: ""
|
||||||
|
@ -285,19 +293,20 @@ class AppDelegate: NSWindowController, NSApplicationDelegate {
|
||||||
NSLog("Installer runs with the pre-macOS 12 flow.")
|
NSLog("Installer runs with the pre-macOS 12 flow.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the IME is not enabled, enable it. Also, unconditionally enable it on macOS 12.0+,
|
// Unconditionally enable the IME on macOS 12.0+,
|
||||||
// as the kTISPropertyInputSourceIsEnabled can still be true even if the IME is *not*
|
// as the kTISPropertyInputSourceIsEnabled can still be true even if the IME is *not*
|
||||||
// enabled in the user's current set of IMEs (which means the IME does not show up in
|
// enabled in the user's current set of IMEs (which means the IME does not show up in
|
||||||
// the user's input menu).
|
// the user's input menu).
|
||||||
|
|
||||||
var mainInputSourceEnabled = InputSourceHelper.inputSourceEnabled(for: inputSource!)
|
var mainInputSourceEnabled = false
|
||||||
if !mainInputSourceEnabled || isMacOS12OrAbove {
|
|
||||||
mainInputSourceEnabled = InputSourceHelper.enable(inputSource: inputSource!)
|
allRegisteredInstancesOfThisInputMethod.forEach {
|
||||||
if mainInputSourceEnabled {
|
if $0.activate() {
|
||||||
NSLog("Input method enabled: \(imeIdentifier)")
|
NSLog("Input method enabled: \(imeIdentifier)")
|
||||||
} else {
|
} else {
|
||||||
NSLog("Failed to enable input method: \(imeIdentifier)")
|
NSLog("Failed to enable input method: \(imeIdentifier)")
|
||||||
}
|
}
|
||||||
|
mainInputSourceEnabled = $0.isActivated
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alert Panel
|
// Alert Panel
|
||||||
|
|
|
@ -1,112 +0,0 @@
|
||||||
// (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
|
||||||
// All possible vChewing-specific modifications are of:
|
|
||||||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
|
||||||
// ====================
|
|
||||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
|
||||||
// ... with NTL restriction stating that:
|
|
||||||
// No trademark license is granted to use the trade names, trademarks, service
|
|
||||||
// marks, or product names of Contributor, except as required to fulfill notice
|
|
||||||
// requirements defined in MIT License.
|
|
||||||
|
|
||||||
import Cocoa
|
|
||||||
import InputMethodKit
|
|
||||||
|
|
||||||
public class InputSourceHelper: NSObject {
|
|
||||||
@available(*, unavailable)
|
|
||||||
override public init() {
|
|
||||||
super.init()
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func allInstalledInputSources() -> [TISInputSource] {
|
|
||||||
TISCreateInputSourceList(nil, true).takeRetainedValue() as! [TISInputSource]
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func inputSource(for sourceID: String) -> TISInputSource? {
|
|
||||||
inputSource(for: kTISPropertyInputSourceID, stringValue: sourceID)
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func enable(inputSource: TISInputSource) -> Bool {
|
|
||||||
let status = TISEnableInputSource(inputSource)
|
|
||||||
return status == noErr
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = enable(inputSource: source)
|
|
||||||
if !modeEnabled {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
enabled = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func disable(inputSource: TISInputSource) -> Bool {
|
|
||||||
let status = TISDisableInputSource(inputSource)
|
|
||||||
return status == noErr
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func registerTnputSource(at url: URL) -> Bool {
|
|
||||||
let status = TISRegisterInputSource(url as CFURL)
|
|
||||||
return status == noErr
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -38,7 +38,6 @@
|
||||||
5B62A34727AE7CD900A19448 /* ctlCandidate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A34027AE7CD900A19448 /* ctlCandidate.swift */; };
|
5B62A34727AE7CD900A19448 /* ctlCandidate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A34027AE7CD900A19448 /* ctlCandidate.swift */; };
|
||||||
5B62A34927AE7CD900A19448 /* TooltipController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A34327AE7CD900A19448 /* TooltipController.swift */; };
|
5B62A34927AE7CD900A19448 /* TooltipController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A34327AE7CD900A19448 /* TooltipController.swift */; };
|
||||||
5B62A34A27AE7CD900A19448 /* NotifierController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A34527AE7CD900A19448 /* NotifierController.swift */; };
|
5B62A34A27AE7CD900A19448 /* NotifierController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A34527AE7CD900A19448 /* NotifierController.swift */; };
|
||||||
5B62A35327AE89C400A19448 /* InputSourceHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33127AE792F00A19448 /* InputSourceHelper.swift */; };
|
|
||||||
5B6C141228A9D4B30098ADF8 /* ctlInputMethod_Common.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6C141128A9D4B30098ADF8 /* ctlInputMethod_Common.swift */; };
|
5B6C141228A9D4B30098ADF8 /* ctlInputMethod_Common.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6C141128A9D4B30098ADF8 /* ctlInputMethod_Common.swift */; };
|
||||||
5B73FB5E27B2BE1300E9BF49 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5B73FB6027B2BE1300E9BF49 /* InfoPlist.strings */; };
|
5B73FB5E27B2BE1300E9BF49 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5B73FB6027B2BE1300E9BF49 /* InfoPlist.strings */; };
|
||||||
5B782EC4280C243C007276DE /* KeyHandler_HandleCandidate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B782EC3280C243C007276DE /* KeyHandler_HandleCandidate.swift */; };
|
5B782EC4280C243C007276DE /* KeyHandler_HandleCandidate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B782EC3280C243C007276DE /* KeyHandler_HandleCandidate.swift */; };
|
||||||
|
@ -250,7 +249,6 @@
|
||||||
5B5948CD289CC04500C85824 /* LMInstantiator_DateTimeExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LMInstantiator_DateTimeExtension.swift; sourceTree = "<group>"; };
|
5B5948CD289CC04500C85824 /* LMInstantiator_DateTimeExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LMInstantiator_DateTimeExtension.swift; sourceTree = "<group>"; };
|
||||||
5B5E535127EF261400C6AA1E /* IME.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = IME.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
5B5E535127EF261400C6AA1E /* IME.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = IME.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||||
5B62A32827AE77D100A19448 /* FSEventStreamHelper.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = FSEventStreamHelper.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
5B62A32827AE77D100A19448 /* FSEventStreamHelper.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = FSEventStreamHelper.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||||
5B62A33127AE792F00A19448 /* InputSourceHelper.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = InputSourceHelper.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
|
||||||
5B62A33527AE795800A19448 /* mgrPrefs.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = mgrPrefs.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
5B62A33527AE795800A19448 /* mgrPrefs.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = mgrPrefs.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||||
5B62A33C27AE7CC100A19448 /* ctlAboutWindow.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlAboutWindow.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
5B62A33C27AE7CC100A19448 /* ctlAboutWindow.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlAboutWindow.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||||
5B62A34027AE7CD900A19448 /* ctlCandidate.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlCandidate.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
5B62A34027AE7CD900A19448 /* ctlCandidate.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlCandidate.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||||
|
@ -886,7 +884,6 @@
|
||||||
5BBBB77827AEDB330023B93A /* Resources */,
|
5BBBB77827AEDB330023B93A /* Resources */,
|
||||||
D4F0BBE0279AF8B30071253C /* AppDelegate.swift */,
|
D4F0BBE0279AF8B30071253C /* AppDelegate.swift */,
|
||||||
D4F0BBDE279AF1AF0071253C /* ArchiveUtil.swift */,
|
D4F0BBDE279AF1AF0071253C /* ArchiveUtil.swift */,
|
||||||
5B62A33127AE792F00A19448 /* InputSourceHelper.swift */,
|
|
||||||
6ACA41F215FC1D9000935EF6 /* Installer-Info.plist */,
|
6ACA41F215FC1D9000935EF6 /* Installer-Info.plist */,
|
||||||
5BC0AACA27F58472002D33E9 /* pkgPostInstall.sh */,
|
5BC0AACA27F58472002D33E9 /* pkgPostInstall.sh */,
|
||||||
5BC0AAC927F58472002D33E9 /* pkgPreInstall.sh */,
|
5BC0AAC927F58472002D33E9 /* pkgPreInstall.sh */,
|
||||||
|
@ -1288,7 +1285,6 @@
|
||||||
files = (
|
files = (
|
||||||
D4F0BBE1279AF8B30071253C /* AppDelegate.swift in Sources */,
|
D4F0BBE1279AF8B30071253C /* AppDelegate.swift in Sources */,
|
||||||
D4F0BBDF279AF1AF0071253C /* ArchiveUtil.swift in Sources */,
|
D4F0BBDF279AF1AF0071253C /* ArchiveUtil.swift in Sources */,
|
||||||
5B62A35327AE89C400A19448 /* InputSourceHelper.swift in Sources */,
|
|
||||||
5BF13B9428C627BB00E99EC1 /* IMKHelper.swift in Sources */,
|
5BF13B9428C627BB00E99EC1 /* IMKHelper.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|
Loading…
Reference in New Issue