From abbf94a2d7ade75cb18e0a4d4a05c0d488387ed6 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Mon, 5 Sep 2022 21:24:59 +0800 Subject: [PATCH] Repo // Deprecating Zonble's InputSourceHelper. --- AUTHORS | 1 - Installer/AppDelegate.swift | 39 ++++++---- Installer/InputSourceHelper.swift | 112 ----------------------------- vChewing.xcodeproj/project.pbxproj | 4 -- 4 files changed, 24 insertions(+), 132 deletions(-) delete mode 100644 Installer/InputSourceHelper.swift diff --git a/AUTHORS b/AUTHORS index 0a69d5fe..8a513d36 100644 --- a/AUTHORS +++ b/AUTHORS @@ -20,7 +20,6 @@ $ Contributors and volunteers of the upstream repo, having no responsibility in - Notifier window and Tooltip UI. - FSEventStreamHelper. - App-style installer (only preserved for developer purposes). - - InputSource Helper. - mgrPrefs (userdefaults manager). - apiUpdate. - Mengjuei Hsieh: diff --git a/Installer/AppDelegate.swift b/Installer/AppDelegate.swift index 5383f960..f9415522 100644 --- a/Installer/AppDelegate.swift +++ b/Installer/AppDelegate.swift @@ -9,6 +9,7 @@ // requirements defined in MIT License. import Cocoa +import InputMethodKit private let kTargetBin = "vChewing" private let kTargetType = "app" @@ -47,6 +48,17 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { private var translocationRemovalStartTime: Date? 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) { let alert = NSAlert() alert.alertStyle = .informational @@ -230,23 +242,20 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { endAppWithDelay() } - let imeURLInstalled = realHomeDir.appendingPathComponent("Library/Input Methods/vChewing.app") - _ = try? shell("/usr/bin/xattr -drs com.apple.quarantine \(kTargetPartialPath)") - guard let imeBundle = Bundle(url: imeURLInstalled), - let imeIdentifier = imeBundle.bundleIdentifier + guard let theBundle = Bundle(url: imeURLInstalled), + let imeIdentifier = theBundle.bundleIdentifier else { endAppWithDelay() return } - let imeBundleURL = imeBundle.bundleURL - var inputSource = InputSourceHelper.inputSource(for: imeIdentifier) + let imeBundleURL = theBundle.bundleURL - if inputSource == nil { + if allRegisteredInstancesOfThisInputMethod.isEmpty { NSLog("Registering input source \(imeIdentifier) at \(imeBundleURL.absoluteString).") - let status = InputSourceHelper.registerTnputSource(at: imeBundleURL) + let status = (TISRegisterInputSource(imeBundleURL as CFURL) == noErr) if !status { let message = String( format: NSLocalizedString( @@ -262,8 +271,7 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { return } - inputSource = InputSourceHelper.inputSource(for: imeIdentifier) - if inputSource == nil { + if allRegisteredInstancesOfThisInputMethod.isEmpty { let message = String( format: NSLocalizedString( "Cannot find input source %@ after registration.", comment: "" @@ -285,19 +293,20 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { 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* // enabled in the user's current set of IMEs (which means the IME does not show up in // the user's input menu). - var mainInputSourceEnabled = InputSourceHelper.inputSourceEnabled(for: inputSource!) - if !mainInputSourceEnabled || isMacOS12OrAbove { - mainInputSourceEnabled = InputSourceHelper.enable(inputSource: inputSource!) - if mainInputSourceEnabled { + var mainInputSourceEnabled = false + + allRegisteredInstancesOfThisInputMethod.forEach { + if $0.activate() { NSLog("Input method enabled: \(imeIdentifier)") } else { NSLog("Failed to enable input method: \(imeIdentifier)") } + mainInputSourceEnabled = $0.isActivated } // Alert Panel diff --git a/Installer/InputSourceHelper.swift b/Installer/InputSourceHelper.swift deleted file mode 100644 index 7face9d8..00000000 --- a/Installer/InputSourceHelper.swift +++ /dev/null @@ -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.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.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.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.fromOpaque(bundleIDPtr) - .takeUnretainedValue() - let inputsSourceModeID = Unmanaged.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 - } -} diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index a4724f9b..3f11c3f0 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -38,7 +38,6 @@ 5B62A34727AE7CD900A19448 /* ctlCandidate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A34027AE7CD900A19448 /* ctlCandidate.swift */; }; 5B62A34927AE7CD900A19448 /* TooltipController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A34327AE7CD900A19448 /* TooltipController.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 */; }; 5B73FB5E27B2BE1300E9BF49 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5B73FB6027B2BE1300E9BF49 /* InfoPlist.strings */; }; 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 = ""; }; 5B5E535127EF261400C6AA1E /* IME.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = IME.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B62A32827AE77D100A19448 /* FSEventStreamHelper.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = FSEventStreamHelper.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; - 5B62A33127AE792F00A19448 /* InputSourceHelper.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = InputSourceHelper.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B62A33527AE795800A19448 /* mgrPrefs.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = mgrPrefs.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B62A33C27AE7CC100A19448 /* ctlAboutWindow.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlAboutWindow.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B62A34027AE7CD900A19448 /* ctlCandidate.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlCandidate.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; @@ -886,7 +884,6 @@ 5BBBB77827AEDB330023B93A /* Resources */, D4F0BBE0279AF8B30071253C /* AppDelegate.swift */, D4F0BBDE279AF1AF0071253C /* ArchiveUtil.swift */, - 5B62A33127AE792F00A19448 /* InputSourceHelper.swift */, 6ACA41F215FC1D9000935EF6 /* Installer-Info.plist */, 5BC0AACA27F58472002D33E9 /* pkgPostInstall.sh */, 5BC0AAC927F58472002D33E9 /* pkgPreInstall.sh */, @@ -1288,7 +1285,6 @@ files = ( D4F0BBE1279AF8B30071253C /* AppDelegate.swift in Sources */, D4F0BBDF279AF1AF0071253C /* ArchiveUtil.swift in Sources */, - 5B62A35327AE89C400A19448 /* InputSourceHelper.swift in Sources */, 5BF13B9428C627BB00E99EC1 /* IMKHelper.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0;