From d21d0342bfc0894059973b9ecb2c4862b4eb01f5 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Sun, 11 Sep 2022 18:32:15 +0800 Subject: [PATCH] Repo // Introduce ClientListMgr. --- Source/Modules/AppDelegate.swift | 12 ++ .../ctlInputMethod_Menu.swift | 11 ++ .../Resources/Base.lproj/Localizable.strings | 11 ++ Source/Resources/en.lproj/Localizable.strings | 11 ++ Source/Resources/ja.lproj/Localizable.strings | 11 ++ .../zh-Hans.lproj/Localizable.strings | 11 ++ .../zh-Hant.lproj/Localizable.strings | 11 ++ .../WindowControllers/ctlClientListMgr.swift | 167 ++++++++++++++++++ Source/WindowNIBs/frmClientListMgr.xib | 133 ++++++++++++++ vChewing.xcodeproj/project.pbxproj | 8 + 10 files changed, 386 insertions(+) create mode 100644 Source/WindowControllers/ctlClientListMgr.swift create mode 100644 Source/WindowNIBs/frmClientListMgr.xib diff --git a/Source/Modules/AppDelegate.swift b/Source/Modules/AppDelegate.swift index 50a27f92..19fce5a2 100644 --- a/Source/Modules/AppDelegate.swift +++ b/Source/Modules/AppDelegate.swift @@ -25,6 +25,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele // let vChewingKeyLayoutBundle = Bundle.init(path: URL(fileURLWithPath: Bundle.main.resourcePath ?? "").appendingPathComponent("vChewingKeyLayout.bundle").path) @IBOutlet var window: NSWindow? + private var ctlClientListMgrInstance: ctlClientListMgr? private var ctlPrefWindowInstance: ctlPrefWindow? private var ctlAboutWindowInstance: ctlAboutWindow? // New About Window public lazy var folderMonitor = FolderMonitor( @@ -80,6 +81,17 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele folderMonitor.startMonitoring() } + func showClientListMgr() { + if ctlClientListMgrInstance == nil { + ctlClientListMgrInstance = ctlClientListMgr.init(windowNibName: "frmClientListMgr") + } + ctlClientListMgrInstance?.window?.center() + ctlClientListMgrInstance?.window?.orderFrontRegardless() // 逼著屬性視窗往最前方顯示 + ctlClientListMgrInstance?.window?.level = .statusBar + ctlClientListMgrInstance?.window?.titlebarAppearsTransparent = true + NSApp.setActivationPolicy(.accessory) + } + func showPreferences() { if ctlPrefWindowInstance == nil { ctlPrefWindowInstance = ctlPrefWindow.init(windowNibName: "frmPrefWindow") diff --git a/Source/Modules/ControllerModules/ctlInputMethod_Menu.swift b/Source/Modules/ControllerModules/ctlInputMethod_Menu.swift index 31b35756..9cf870e3 100644 --- a/Source/Modules/ControllerModules/ctlInputMethod_Menu.swift +++ b/Source/Modules/ControllerModules/ctlInputMethod_Menu.swift @@ -156,6 +156,12 @@ extension ctlInputMethod { withTitle: NSLocalizedString("vChewing Preferences…", comment: ""), action: #selector(showPreferences(_:)), keyEquivalent: "" ) + } + menu.addItem( + withTitle: NSLocalizedString("Client Manager", comment: "") + "…", + action: #selector(showClientListMgr(_:)), keyEquivalent: "" + ) + if !optionKeyPressed { menu.addItem( withTitle: NSLocalizedString("Check for Updates…", comment: ""), action: #selector(checkForUpdate(_:)), keyEquivalent: "" @@ -208,6 +214,11 @@ extension ctlInputMethod { NSWorkspace.shared.openFile(url.path, withApplication: "Safari") } + @objc func showClientListMgr(_: Any?) { + (NSApp.delegate as? AppDelegate)?.showClientListMgr() + NSApp.activate(ignoringOtherApps: true) + } + @objc func toggleSCPCTypingMode(_: Any? = nil) { resetKeyHandler() NotifierController.notify( diff --git a/Source/Resources/Base.lproj/Localizable.strings b/Source/Resources/Base.lproj/Localizable.strings index 5c83469d..a52613a2 100644 --- a/Source/Resources/Base.lproj/Localizable.strings +++ b/Source/Resources/Base.lproj/Localizable.strings @@ -1,4 +1,15 @@ "vChewing" = "vChewing"; +"Please enter the client app bundle identifier(s) you want to register." = "Please enter the client app bundle identifier(s) you want to register."; +"One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed." = "One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed."; +"Just Select" = "Just Select"; +"Client Manager" = "Client Manager"; +"Please manage the list of IMKTextInput-incompatible clients here. Clients listed here will trigger vChewing's built-in popup composition buffer window with maximum 20 reading counts holdable." = "Please manage the list of IMKTextInput-incompatible clients here. Clients listed here will trigger vChewing's built-in popup composition buffer window with maximum 20 reading counts holdable."; +"Add Client" = "Add Client"; +"Remove Selected" = "Remove Selected"; +"Choose the target application bundle." = "Choose the target application bundle."; +"The selected item is not a valid macOS application bundle." = "The selected item is not a valid macOS application bundle."; +"Please try again." = "Please try again."; +"The selected item's identifier is already in the list." = "The selected item's identifier is already in the list."; "Update Check Completed" = "Update Check Completed"; "You are already using the latest version." = "You are already using the latest version."; "Plist downloaded is nil." = "Plist downloaded is nil."; diff --git a/Source/Resources/en.lproj/Localizable.strings b/Source/Resources/en.lproj/Localizable.strings index 5c83469d..a52613a2 100644 --- a/Source/Resources/en.lproj/Localizable.strings +++ b/Source/Resources/en.lproj/Localizable.strings @@ -1,4 +1,15 @@ "vChewing" = "vChewing"; +"Please enter the client app bundle identifier(s) you want to register." = "Please enter the client app bundle identifier(s) you want to register."; +"One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed." = "One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed."; +"Just Select" = "Just Select"; +"Client Manager" = "Client Manager"; +"Please manage the list of IMKTextInput-incompatible clients here. Clients listed here will trigger vChewing's built-in popup composition buffer window with maximum 20 reading counts holdable." = "Please manage the list of IMKTextInput-incompatible clients here. Clients listed here will trigger vChewing's built-in popup composition buffer window with maximum 20 reading counts holdable."; +"Add Client" = "Add Client"; +"Remove Selected" = "Remove Selected"; +"Choose the target application bundle." = "Choose the target application bundle."; +"The selected item is not a valid macOS application bundle." = "The selected item is not a valid macOS application bundle."; +"Please try again." = "Please try again."; +"The selected item's identifier is already in the list." = "The selected item's identifier is already in the list."; "Update Check Completed" = "Update Check Completed"; "You are already using the latest version." = "You are already using the latest version."; "Plist downloaded is nil." = "Plist downloaded is nil."; diff --git a/Source/Resources/ja.lproj/Localizable.strings b/Source/Resources/ja.lproj/Localizable.strings index a7cd23b8..3e465824 100644 --- a/Source/Resources/ja.lproj/Localizable.strings +++ b/Source/Resources/ja.lproj/Localizable.strings @@ -1,4 +1,15 @@ "vChewing" = "威注音入力アプリ"; +"Please enter the client app bundle identifier(s) you want to register." = "登録したい客体アプリの唯一識別子(Bundle Identifier)をご入力ください。"; +"One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed." = "毎行は1つ記録とみなす。Option+Enter キーで改行。\n空白の記録値は無視される。"; +"Just Select" = "直接に選ぶ"; +"Client Manager" = "客体アプリの管理"; +"Please manage the list of IMKTextInput-incompatible clients here. Clients listed here will trigger vChewing's built-in popup composition buffer window with maximum 20 reading counts holdable." = "IMKTextInput 議定規約に従っていない客体アプリはここでご登録ください。登録済みのアプリは客体アプリ(文字入力を受くアプリ)とされた時に、威注音入力アプリは「吹き出し入力緩衝列ウィンドウ」と「緩衝列容量制限」を起用し、その容量制限は最大限音読み20箇とする。"; +"Add Client" = "入れる"; +"Remove Selected" = "外す"; +"Choose the target application bundle." = "登録したいアプリのバンドルのお選びを。"; +"The selected item is not a valid macOS application bundle." = "今選んだんのは正しい macOS アプリバンドルではないと考えられる。"; +"Please try again." = "お選び直しください。"; +"The selected item's identifier is already in the list." = "今選んだバンドルの唯一識別子(Bundle Identifier)は既に登録済みである。"; "Update Check Completed" = "新バージョンチェック完了"; "You are already using the latest version." = "現在稼働中のは最新バージョンである。"; "Plist downloaded is nil." = "受けた新バージョンお知らせ情報データは Plist ではないため、失敗とみなす。"; diff --git a/Source/Resources/zh-Hans.lproj/Localizable.strings b/Source/Resources/zh-Hans.lproj/Localizable.strings index bb23e1fd..e989b8d8 100644 --- a/Source/Resources/zh-Hans.lproj/Localizable.strings +++ b/Source/Resources/zh-Hans.lproj/Localizable.strings @@ -1,4 +1,15 @@ "vChewing" = "威注音输入法"; +"Please enter the client app bundle identifier(s) you want to register." = "请键入您要登记的客体应用的唯一标帜(Bundle Identifier)。"; +"One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed." = "每行一笔记录,用 Option+Enter 换行。\n空白值会被无视。"; +"Just Select" = "直接选取"; +"Client Manager" = "管理客体应用"; +"Please manage the list of IMKTextInput-incompatible clients here. Clients listed here will trigger vChewing's built-in popup composition buffer window with maximum 20 reading counts holdable." = "请在此管理那些不遵守 IMKTextInput 协定的客体应用。威注音输入法对于任何位列在此的客体应用均启用浮动组字窗、且对组字区内容设定容量上限(最多二十个读音)。"; +"Add Client" = "登记新客体"; +"Remove Selected" = "移除所选条目"; +"Choose the target application bundle." = "请选择要登记的应用程式的封包。"; +"The selected item is not a valid macOS application bundle." = "当前所选之物并非 macOS 应用程式封包。"; +"Please try again." = "请重试。"; +"The selected item's identifier is already in the list." = "当前所选之封包的唯一标帜(Bundle Identifier)已被登记。"; "Update Check Completed" = "更新检查完毕"; "You are already using the latest version." = "您正在使用目前最新的发行版。"; "Plist downloaded is nil." = "下载来的更新资讯并非 Plist 档案。"; diff --git a/Source/Resources/zh-Hant.lproj/Localizable.strings b/Source/Resources/zh-Hant.lproj/Localizable.strings index 42538fd8..2d686182 100644 --- a/Source/Resources/zh-Hant.lproj/Localizable.strings +++ b/Source/Resources/zh-Hant.lproj/Localizable.strings @@ -1,4 +1,15 @@ "vChewing" = "威注音輸入法"; +"Please enter the client app bundle identifier(s) you want to register." = "請鍵入您要登記的客體應用的唯一標幟(Bundle Identifier)。"; +"One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed." = "每行一筆記錄,用 Option+Enter 換行。\n空白值會被無視。"; +"Just Select" = "直接選取"; +"Client Manager" = "管理客體應用"; +"Please manage the list of IMKTextInput-incompatible clients here. Clients listed here will trigger vChewing's built-in popup composition buffer window with maximum 20 reading counts holdable." = "請在此管理那些不遵守 IMKTextInput 協定的客體應用。威注音輸入法對於任何位列在此的客體應用均啟用浮動組字窗、且對組字區內容設定容量上限(最多二十個讀音)。"; +"Add Client" = "登記新客體"; +"Remove Selected" = "移除所選條目"; +"Choose the target application bundle." = "請選擇要登記的應用程式的封包。"; +"The selected item is not a valid macOS application bundle." = "當前所選之物並非 macOS 應用程式封包。"; +"Please try again." = "請重試。"; +"The selected item's identifier is already in the list." = "當前所選之封包的唯一標幟(Bundle Identifier)已被登記。"; "Update Check Completed" = "更新檢查完畢"; "You are already using the latest version." = "您正在使用目前最新的發行版。"; "Plist downloaded is nil." = "下載來的更新資訊並非 Plist 檔案。"; diff --git a/Source/WindowControllers/ctlClientListMgr.swift b/Source/WindowControllers/ctlClientListMgr.swift new file mode 100644 index 00000000..8dc51cbc --- /dev/null +++ b/Source/WindowControllers/ctlClientListMgr.swift @@ -0,0 +1,167 @@ +// (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 + +class ctlClientListMgr: NSWindowController, NSTableViewDelegate, NSTableViewDataSource { + @IBOutlet var tblClients: NSTableView! + @IBOutlet var btnRemoveClient: NSButton! + @IBOutlet var btnAddClient: NSButton! + @IBOutlet var lblClientMgrWindow: NSTextField! + override func windowDidLoad() { + super.windowDidLoad() + localize() + tblClients.delegate = self + tblClients.dataSource = self + tblClients.reloadData() + } +} + +// MARK: - Implementations + +extension ctlClientListMgr { + func numberOfRows(in _: NSTableView) -> Int { + mgrPrefs.clientsIMKTextInputIncapable.count + } + + func callAlert(_ window: NSWindow, title: String, text: String? = nil) { + let alert = NSAlert() + alert.messageText = title + if let text = text { + alert.informativeText = text + } + alert.addButton(withTitle: NSLocalizedString("OK", comment: "")) + alert.beginSheetModal(for: window) + } + + @IBAction func btnAddClientClicked(_: Any) { + guard let window = window else { return } + let alert = NSAlert() + alert.messageText = NSLocalizedString( + "Please enter the client app bundle identifier(s) you want to register.", comment: "" + ) + alert.informativeText = NSLocalizedString( + "One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed.", comment: "" + ) + alert.addButton(withTitle: NSLocalizedString("OK", comment: "")) + alert.addButton(withTitle: NSLocalizedString("Just Select", comment: "") + "…") + alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "")) + + let maxFloat = CGFloat(Float.greatestFiniteMagnitude) + let scrollview = NSScrollView(frame: NSRect(x: 0, y: 0, width: 370, height: 380)) + let contentSize = scrollview.contentSize + scrollview.borderType = .noBorder + scrollview.hasVerticalScroller = true + scrollview.hasHorizontalScroller = true + scrollview.horizontalScroller?.scrollerStyle = .legacy + scrollview.verticalScroller?.scrollerStyle = .legacy + scrollview.autoresizingMask = [.width, .height] + let theTextView = NSTextView(frame: NSRect(x: 0, y: 0, width: contentSize.width, height: contentSize.height)) + theTextView.minSize = NSSize(width: 0.0, height: contentSize.height) + theTextView.maxSize = NSSize(width: maxFloat, height: maxFloat) + theTextView.isVerticallyResizable = true + theTextView.isHorizontallyResizable = false + theTextView.autoresizingMask = .width + theTextView.textContainer?.containerSize = NSSize(width: contentSize.width, height: maxFloat) + theTextView.textContainer?.widthTracksTextView = true + scrollview.documentView = theTextView + theTextView.enclosingScrollView?.hasHorizontalScroller = true + theTextView.isHorizontallyResizable = true + theTextView.autoresizingMask = [.width, .height] + theTextView.textContainer?.containerSize = NSSize(width: maxFloat, height: maxFloat) + theTextView.textContainer?.widthTracksTextView = false + + alert.accessoryView = scrollview + alert.beginSheetModal(for: window) { result in + switch result { + case .alertFirstButtonReturn: + theTextView.textContainer?.textView?.string.components(separatedBy: "\n").filter { !$0.isEmpty }.forEach { + self.applyNewValue($0) + } + case .alertSecondButtonReturn: + IME.dlgOpenPath.title = NSLocalizedString( + "Choose the target application bundle.", comment: "" + ) + IME.dlgOpenPath.showsResizeIndicator = true + IME.dlgOpenPath.showsHiddenFiles = true + IME.dlgOpenPath.canChooseFiles = true + IME.dlgOpenPath.canChooseDirectories = false + IME.dlgOpenPath.beginSheetModal(for: window) { result in + switch result { + case .OK: + guard let url = IME.dlgOpenPath.url else { return } + var title = NSLocalizedString("The selected item is not a valid macOS application bundle.", comment: "") + let text = NSLocalizedString("Please try again.", comment: "") + guard let bundle = Bundle(url: url) else { + self.callAlert(window, title: title, text: text) + return + } + guard let identifier = bundle.bundleIdentifier else { + self.callAlert(window, title: title, text: text) + return + } + if mgrPrefs.clientsIMKTextInputIncapable.contains(identifier) { + title = NSLocalizedString( + "The selected item's identifier is already in the list.", comment: "" + ) + self.callAlert(window, title: title) + return + } + self.applyNewValue(identifier) + default: return + } + } + default: return + } + } + } + + private func applyNewValue(_ newValue: String) { + guard !newValue.isEmpty else { return } + var arrResult = mgrPrefs.clientsIMKTextInputIncapable + arrResult.append(newValue) + mgrPrefs.clientsIMKTextInputIncapable = arrResult.sorted() + tblClients.reloadData() + btnRemoveClient.isEnabled = (0..= mgrPrefs.clientsIMKTextInputIncapable.count { return } + if tblClients.selectedRow < 0 { return } + let isLastRow: Bool = { + if mgrPrefs.clientsIMKTextInputIncapable.count < 2 { return false } + return tblClients.selectedRow == mgrPrefs.clientsIMKTextInputIncapable.count - 1 + }() + mgrPrefs.clientsIMKTextInputIncapable.remove(at: tblClients.selectedRow) + if isLastRow { + tblClients.selectRowIndexes(.init(arrayLiteral: tblClients.selectedRow - 1), byExtendingSelection: false) + } + tblClients.reloadData() + btnRemoveClient.isEnabled = (0.. Any? { + defer { + self.btnRemoveClient.isEnabled = (0.. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index 744b2dca..32de0cc3 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -9,6 +9,8 @@ /* Begin PBXBuildFile section */ 5B09307628B6FC3B0021F8C5 /* shortcuts.html in Resources */ = {isa = PBXBuildFile; fileRef = 5B09307828B6FC3B0021F8C5 /* shortcuts.html */; }; 5B0AF8B527B2C8290096FE54 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B0AF8B427B2C8290096FE54 /* StringExtension.swift */; }; + 5B0EF55D28CDBF7100F8F7CE /* frmClientListMgr.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5B0EF55C28CDBF7100F8F7CE /* frmClientListMgr.xib */; }; + 5B0EF55F28CDBF8E00F8F7CE /* ctlClientListMgr.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B0EF55E28CDBF8E00F8F7CE /* ctlClientListMgr.swift */; }; 5B11328927B94CFB00E58451 /* AppleKeyboardConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B11328827B94CFB00E58451 /* AppleKeyboardConverter.swift */; }; 5B16B84C28C9A89000ABA692 /* FolderMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B16B84B28C9A89000ABA692 /* FolderMonitor.swift */; }; 5B175FFB28C5CDDC0078D1B4 /* IMKHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B175FFA28C5CDDC0078D1B4 /* IMKHelper.swift */; }; @@ -211,6 +213,8 @@ 5B09307B28B6FC410021F8C5 /* ja */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; lineEnding = 0; name = ja; path = ja.lproj/shortcuts.html; sourceTree = ""; }; 5B0AF8B427B2C8290096FE54 /* StringExtension.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = StringExtension.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B0C5EDF27C7D9870078037C /* dataCompiler.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = dataCompiler.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; + 5B0EF55C28CDBF7100F8F7CE /* frmClientListMgr.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = frmClientListMgr.xib; sourceTree = ""; }; + 5B0EF55E28CDBF8E00F8F7CE /* ctlClientListMgr.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ctlClientListMgr.swift; sourceTree = ""; }; 5B11328827B94CFB00E58451 /* AppleKeyboardConverter.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = AppleKeyboardConverter.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B16B84B28C9A89000ABA692 /* FolderMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderMonitor.swift; sourceTree = ""; }; 5B175FFA28C5CDDC0078D1B4 /* IMKHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMKHelper.swift; sourceTree = ""; }; @@ -594,6 +598,7 @@ isa = PBXGroup; children = ( 5B62A33C27AE7CC100A19448 /* ctlAboutWindow.swift */, + 5B0EF55E28CDBF8E00F8F7CE /* ctlClientListMgr.swift */, D47F7DCD278BFB57002F9DD7 /* ctlPrefWindow.swift */, ); path = WindowControllers; @@ -602,6 +607,7 @@ 5B62A33B27AE7C7F00A19448 /* WindowNIBs */ = { isa = PBXGroup; children = ( + 5B0EF55C28CDBF7100F8F7CE /* frmClientListMgr.xib */, 5BBBB76927AED5DB0023B93A /* frmAboutWindow.xib */, 5B7BC4AE27AFFBE800F66C24 /* frmPrefWindow.xib */, 6A187E2816004C5900466B2E /* MainMenu.xib */, @@ -1079,6 +1085,7 @@ D4E33D8A27A838CF006DB1CF /* Localizable.strings in Resources */, 5BF9DA2828840E6200DBD48E /* template-exclusions.txt in Resources */, 5B7DA80328BF6BC600D7B2AD /* fixinstall.sh in Resources */, + 5B0EF55D28CDBF7100F8F7CE /* frmClientListMgr.xib in Resources */, 5BDCBB2E27B4E67A00D0CC59 /* vChewingPhraseEditor.app in Resources */, 5BBBB76027AED54C0023B93A /* Fart.m4a in Resources */, 6A2E40F6253A69DA00D1AE1D /* Images.xcassets in Resources */, @@ -1225,6 +1232,7 @@ 5B5F8AEE28C8826D007C11F1 /* ctlTooltip.swift in Sources */, 5BD0113B28180D6100609769 /* LMInstantiator.swift in Sources */, 5B2170E7289FACAD00BE7304 /* 1_Compositor.swift in Sources */, + 5B0EF55F28CDBF8E00F8F7CE /* ctlClientListMgr.swift in Sources */, 5B21177028753B9D000443A9 /* ctlInputMethod_Delegates.swift in Sources */, 5B21176E28753B35000443A9 /* ctlInputMethod_HandleDisplay.swift in Sources */, 5B84579F2871AD2200C93B01 /* HotenkaChineseConverter.swift in Sources */,