Skip to content

Commit

Permalink
fix: 修复在safari地址栏输入,候选窗口显示不正确的问题
Browse files Browse the repository at this point in the history
1. 经过实践,在候选窗口中调用inputController的方法获取候选词(candidates)和原始字符串(originalString)会在一些情况下返回为空,所以最好的方案是inputController主动把需要的数据传给候选窗口
2. 实践再次证明,不要试图去重写(override)的现有方法实现功能,比如说commitComposedString, 调用时机不能控制,系统在某些情况下会自动调用,难搞。所以推荐能用自定义方法的就写自定义方法
3. 实践又一次证明,最好把originalString通过setMarkedText方法进行上屏处理,否则在一些输入框中会有异常问题
4. 经过各种实践,在Xcode的文件上方输入搜索时,会在每次输入时,把markedText直接插入到输入框中,这个问题可以通过设置inputController.mark(for:)的for参数为kTSMHiliteSelectedConvertedText解决,但是markedText的样式会表现为选择样式,所以本次提交暂不处理这个问题,后续再观察一下
  • Loading branch information
qwertyyb committed Aug 16, 2020
1 parent 6f35b21 commit 31a71af
Show file tree
Hide file tree
Showing 16 changed files with 361 additions and 388 deletions.
3 changes: 3 additions & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
disabled_rules: # 禁用指定的规则
- identifier_name
- block_based_kvo
43 changes: 23 additions & 20 deletions Fire.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,9 @@
4543349923425C39000950E1 /* PreferencesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4543349823425C39000950E1 /* PreferencesController.swift */; };
45449B4C23535ED000C9EFEF /* InputMethodKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 451E6058232E2787007B0463 /* InputMethodKit.framework */; };
45449B512353627500C9EFEF /* fire.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 45449B502353627500C9EFEF /* fire.tiff */; };
45587F2924E7D3E6005F291B /* showModeTip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45587F2824E7D3E6005F291B /* showModeTip.swift */; };
45587F2B24E7E694005F291B /* checkShiftKeyUp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45587F2A24E7E694005F291B /* checkShiftKeyUp.swift */; };
45587F2D24E8FBFB005F291B /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45587F2C24E8FBFB005F291B /* Utils.swift */; };
459DE990232EB26600A3ACD1 /* FireCandidatesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 459DE98E232EB26500A3ACD1 /* FireCandidatesView.swift */; };
459DE991232EB26600A3ACD1 /* FireCandidatesWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 459DE98F232EB26500A3ACD1 /* FireCandidatesWindow.swift */; };
45A0A81824E7B92900ACFFD7 /* toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45A0A81724E7B92900ACFFD7 /* toast.swift */; };
673CD81C233DCF14006538B8 /* table.sqlite in Resources */ = {isa = PBXBuildFile; fileRef = 673CD81B233DCF14006538B8 /* table.sqlite */; };
67E8B515233B97FD00D7CE80 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67E8B517233B97FD00D7CE80 /* InfoPlist.strings */; };
67E8B520233C537B00D7CE80 /* fire.icns in Resources */ = {isa = PBXBuildFile; fileRef = 67E8B51D233C537B00D7CE80 /* fire.icns */; };
Expand All @@ -39,11 +37,9 @@
451E605E232E400B007B0463 /* Fire.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fire.swift; sourceTree = "<group>"; };
4543349823425C39000950E1 /* PreferencesController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesController.swift; sourceTree = "<group>"; };
45449B502353627500C9EFEF /* fire.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = fire.tiff; sourceTree = "<group>"; };
45587F2824E7D3E6005F291B /* showModeTip.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = showModeTip.swift; sourceTree = "<group>"; };
45587F2A24E7E694005F291B /* checkShiftKeyUp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = checkShiftKeyUp.swift; sourceTree = "<group>"; };
45587F2C24E8FBFB005F291B /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = "<group>"; };
459DE98E232EB26500A3ACD1 /* FireCandidatesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FireCandidatesView.swift; sourceTree = "<group>"; };
459DE98F232EB26500A3ACD1 /* FireCandidatesWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FireCandidatesWindow.swift; sourceTree = "<group>"; };
45A0A81724E7B92900ACFFD7 /* toast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = toast.swift; sourceTree = "<group>"; };
497E90F13FA9A943AC0BE3DB /* Pods-Fire.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Fire.release.xcconfig"; path = "Target Support Files/Pods-Fire/Pods-Fire.release.xcconfig"; sourceTree = "<group>"; };
59F80EA93E8AE7885721524F /* libPods-Fire.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Fire.a"; sourceTree = BUILT_PRODUCTS_DIR; };
673CD81B233DCF14006538B8 /* table.sqlite */ = {isa = PBXFileReference; lastKnownFileType = file; path = table.sqlite; sourceTree = "<group>"; };
Expand Down Expand Up @@ -97,7 +93,6 @@
451E6046232E227B007B0463 /* Fire */ = {
isa = PBXGroup;
children = (
45A0A81624E7B8E700ACFFD7 /* utils */,
67E8B51D233C537B00D7CE80 /* fire.icns */,
67E8B51E233C537B00D7CE80 /* fire.pdf */,
45449B502353627500C9EFEF /* fire.tiff */,
Expand All @@ -114,6 +109,7 @@
451E605E232E400B007B0463 /* Fire.swift */,
4543349823425C39000950E1 /* PreferencesController.swift */,
4514F6DE2343468000410EC2 /* preferences.xib */,
45587F2C24E8FBFB005F291B /* Utils.swift */,
);
path = Fire;
sourceTree = "<group>";
Expand All @@ -127,16 +123,6 @@
name = Frameworks;
sourceTree = "<group>";
};
45A0A81624E7B8E700ACFFD7 /* utils */ = {
isa = PBXGroup;
children = (
45A0A81724E7B92900ACFFD7 /* toast.swift */,
45587F2824E7D3E6005F291B /* showModeTip.swift */,
45587F2A24E7E694005F291B /* checkShiftKeyUp.swift */,
);
path = utils;
sourceTree = "<group>";
};
45E34DC52337C98900CA7E72 /* data */ = {
isa = PBXGroup;
children = (
Expand All @@ -158,6 +144,7 @@
451E6042232E227B007B0463 /* Resources */,
CC4E3CB56A41B3947C0BFEC1 /* [CP] Embed Pods Frameworks */,
45449B4D235360B900C9EFEF /* update version */,
45587F2E24E91513005F291B /* lint */,
);
buildRules = (
);
Expand Down Expand Up @@ -243,6 +230,24 @@
shellPath = /bin/sh;
shellScript = "version=`/usr/libexec/PlistBuddy -c \"Print CFBundleVersion\" $PRODUCT_SETTINGS_PATH`\nversion=`expr $version + 1`\n/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $version\" $PRODUCT_SETTINGS_PATH\n";
};
45587F2E24E91513005F291B /* lint */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = lint;
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\"${PODS_ROOT}/SwiftLint/swiftlint\"\n";
};
B7AF3759D9701C095D62024C /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
Expand Down Expand Up @@ -291,10 +296,8 @@
files = (
4543349923425C39000950E1 /* PreferencesController.swift in Sources */,
451E6056232E24A5007B0463 /* FireInputController.swift in Sources */,
45587F2924E7D3E6005F291B /* showModeTip.swift in Sources */,
45A0A81824E7B92900ACFFD7 /* toast.swift in Sources */,
451E605F232E400B007B0463 /* Fire.swift in Sources */,
45587F2B24E7E694005F291B /* checkShiftKeyUp.swift in Sources */,
45587F2D24E8FBFB005F291B /* Utils.swift in Sources */,
451E6048232E227B007B0463 /* AppDelegate.swift in Sources */,
459DE991232EB26600A3ACD1 /* FireCandidatesWindow.swift in Sources */,
459DE990232EB26600A3ACD1 /* FireCandidatesView.swift in Sources */,
Expand Down
46 changes: 22 additions & 24 deletions Fire/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,53 +12,51 @@ import Sparkle

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

let fire: Fire
override init() {
NSLog("terminate runing")
// let running = NSRunningApplication.runningApplications(withBundleIdentifier: NSRunningApplication.current.bundleIdentifier!).first
// if (running != nil && NSRunningApplication.current != running) {
// running?.forceTerminate()
// }
fire = Fire.shared
}
func applicationDidFinishLaunching(_ aNotification: Notification) {
let installedLocationURL = CFURLCreateFromFileSystemRepresentation(nil, "/Library/Input Methods/Fire.app", "/Library/Input Methods/Fire.app".count, false)
let kSourceID = "com.qwertyyb.inputmethod.Fire";
let installedLocationURL = CFURLCreateFromFileSystemRepresentation(
nil,
"/Library/Input Methods/Fire.app",
"/Library/Input Methods/Fire.app".count,
false
)
let kSourceID = "com.qwertyyb.inputmethod.Fire"

let kInputModeID = "com.qwertyyb.inputmethod.Fire"

let kInputModeID = "com.qwertyyb.inputmethod.Fire";

if (installedLocationURL != nil) {
if installedLocationURL != nil {
TISRegisterInputSource(installedLocationURL)
}

let sourceList = TISCreateInputSourceList(nil, true);
for i in 0...CFArrayGetCount(sourceList!.takeUnretainedValue())-1 {
let sourceList = TISCreateInputSourceList(nil, true)

for index in 0...CFArrayGetCount(sourceList!.takeUnretainedValue())-1 {
// sourceList?.takeUnretainedValue()
let inputSource = Unmanaged<TISInputSource>.fromOpaque(CFArrayGetValueAtIndex(
sourceList?.takeUnretainedValue(), i)).takeUnretainedValue();
sourceList?.takeUnretainedValue(), index)).takeUnretainedValue()
let ptr = TISGetInputSourceProperty(inputSource, kTISPropertyInputSourceID)
let sourceID = Unmanaged<CFString>.fromOpaque(ptr!).takeUnretainedValue() as NSString
// NSLog("examining input source '%@", sourceID);
if (sourceID.isEqual(to: kSourceID) ) || sourceID.isEqual(to: kInputModeID) {
TISEnableInputSource(inputSource);
NSLog("Enabled input source: %@", sourceID);
TISEnableInputSource(inputSource)
NSLog("Enabled input source: %@", sourceID)
let isSelectable = Unmanaged<CFBoolean>.fromOpaque(TISGetInputSourceProperty(
inputSource, kTISPropertyInputSourceIsSelectCapable)).takeUnretainedValue();
if (CFBooleanGetValue(isSelectable)) {
TISSelectInputSource(inputSource);
NSLog("Selected input source: %@", sourceID);
inputSource, kTISPropertyInputSourceIsSelectCapable)).takeUnretainedValue()
if CFBooleanGetValue(isSelectable) {
TISSelectInputSource(inputSource)
NSLog("Selected input source: %@", sourceID)
}
}
}
NSLog("lanched")
}

func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}


}

73 changes: 43 additions & 30 deletions Fire/Fire.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ struct Candidate {
}

enum CodeMode: Int {
case Wubi
case Pinyin
case WubiPinyin
case wubi
case pinyin
case wubiPinyin
}

struct NetCandidate: Codable {
Expand All @@ -37,10 +37,8 @@ struct CandidatesResponse: Codable {
let list: [NetCandidate]
}

extension UserDefaults
{
@objc dynamic var codeMode: Int
{
extension UserDefaults {
@objc dynamic var codeMode: Int {
get {
return integer(forKey: "codeMode")
}
Expand All @@ -51,54 +49,62 @@ extension UserDefaults
}

class Fire: NSObject {
var codeMode: CodeMode = .WubiPinyin
var codeMode: CodeMode = .wubiPinyin
var candidateCount: Int = 5
var cloudinput: Bool = false

override init() {
UserDefaults.standard.register(defaults: ["codeMode": 2, "candidateCount": 5, "cloudinput": false])
codeMode = CodeMode(rawValue: UserDefaults.standard.integer(forKey: "codeMode"))!
candidateCount = UserDefaults.standard.integer(forKey: "candidateCount")
cloudinput = UserDefaults.standard.bool(forKey: "cloudinput")
super.init()
UserDefaults.standard.addObserver(self, forKeyPath: "codeMode", options: [.new, .old, .initial], context: nil)
UserDefaults.standard.addObserver(self, forKeyPath: "candidateCount", options: [.new, .old, .initial], context: nil)
UserDefaults.standard.addObserver(self, forKeyPath: "cloudinput", options: [.new, .old, .initial], context: nil)
UserDefaults.standard.addObserver(
self, forKeyPath: "codeMode", options: [.new, .old, .initial], context: nil)
UserDefaults.standard.addObserver(
self, forKeyPath: "candidateCount", options: [.new, .old, .initial], context: nil)
UserDefaults.standard.addObserver(
self, forKeyPath: "cloudinput", options: [.new, .old, .initial], context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
override func observeValue(
forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey: Any]?,
context: UnsafeMutableRawPointer?
) {
let newVal = change![NSKeyValueChangeKey.newKey]
// print(newVal)
if keyPath == "codeMode" {
codeMode = CodeMode.init(rawValue: newVal as! Int)!
if let rawValue = newVal as? Int { codeMode = CodeMode(rawValue: rawValue)! }
} else if keyPath == "candidateCount" {
candidateCount = newVal as! Int
if let count = newVal as? Int { candidateCount = count }
} else if keyPath == "cloudinput" {
cloudinput = newVal as! Bool
if let cloud = newVal as? Bool { cloudinput = cloud }
}
}

private func getQuerySql(code: String = "", page: Int = 1) -> String {
let tableType = codeMode == .WubiPinyin ? "" : "type = '\(codeMode == .Pinyin ? "py" : "wb")' and "
let tableType = codeMode == .wubiPinyin ? "" : "type = '\(codeMode == .pinyin ? "py" : "wb")' and "
// swiftlint:disable:next line_length
let sql = "select case when t2.type = 'wb' then min(t1.code) else max(t1.code) end as code, t1.text, t2.type from dict_default t1 inner join (select min(id) as id, code, text, type from dict_default where \(tableType)code like '\(code)%' group by id, text order by length(code)) t2 on t1.text = t2.text and t1.type = 'wb' group by t1.text order by case when t2.code = '\(code)' then t2.id when t2.code like '\(code)%' then 10000000 + t2.id end limit \((page - 1) * candidateCount), \(candidateCount)"
print(sql)
return sql
}

var server: IMKServer = IMKServer.init(name: kConnectionName, bundleIdentifier: Bundle.main.bundleIdentifier)
func getCandidates(origin: NSAttributedString = NSAttributedString(), page: Int = 1) -> [Candidate] {
if origin.length <= 0 {
func getCandidates(origin: String = String(), page: Int = 1) -> [Candidate] {
if origin.count <= 0 {
return []
}
NSLog("get local candidate, origin: \(origin.string)")
NSLog("get local candidate, origin: \(origin)")
var db: OpaquePointer?
var candidates: [Candidate] = []
let dbPath = Bundle.main.path(forResource: "table", ofType: "sqlite")
if sqlite3_open(dbPath, &db) == SQLITE_OK {
let sql = getQuerySql(code: origin.string, page: page)
let sql = getQuerySql(code: origin, page: page)
var queryStatement: OpaquePointer?
if sqlite3_prepare_v2(db, sql, -1, &queryStatement, nil) == SQLITE_OK {
// NSLog("list")
while(sqlite3_step(queryStatement) == SQLITE_ROW) {
while sqlite3_step(queryStatement) == SQLITE_ROW {
let code = String.init(cString: sqlite3_column_text(queryStatement, 0))
let text = String.init(cString: sqlite3_column_text(queryStatement, 1))
let type = String.init(cString: sqlite3_column_text(queryStatement, 2))
Expand All @@ -112,21 +118,28 @@ class Fire: NSObject {
sqlite3_close(db)
return candidates
}



func getCandidateFromNetwork(origin: String, sender: (IMKTextInput & NSObjectProtocol)!) {
if origin.count != 4 { return }
URLSession.shared.dataTask(with: URL.init(string: "http://localhost:8000/dict/candidates?origin=" + origin)!) { (data, response, error) in
URLSession.shared.dataTask(
with: URL.init(string: "http://localhost:8000/dict/candidates?origin=" + origin)!
) { (data, _, error) in
if error != nil {
print(error!)
return
}
let res = try! JSONDecoder().decode(CandidatesResponse.self, from: data!)
guard let res = try? JSONDecoder().decode(CandidatesResponse.self, from: data!) else { return }
let candidates = res.list.map { (netCandidate) -> Candidate in
return Candidate(code: netCandidate.wbcode, text: netCandidate.text, type: "wb")
}
// print(res.list)
NotificationCenter.default.post(Notification.init(name: Notification.Name(rawValue: "NetCandidatesUpdate-\(sender.bundleIdentifier() ?? "Fire")"), object: candidates, userInfo: nil))
NotificationCenter.default.post(Notification.init(
name: Notification.Name(
rawValue: "NetCandidatesUpdate-\(sender.bundleIdentifier() ?? "Fire")"),
object: candidates,
userInfo: nil
)
)
}.resume()
}

Expand Down
Loading

0 comments on commit 31a71af

Please sign in to comment.