早在去年,落格輸入法的用戶就有報告說落格輸入法 macOS 在 有道云筆記 的 MarkDown 模式下無法正常鍵入中文,經過測試證明確實如此,體現為打中文字的時候,buffer的刷新會奇怪的刪除掉光標前的一個字符——對,不多不少,就刪一個。
搗鼓了很久未果,最後我沒招了打印出了所有內容,發現了謎團:
當我把輸入法獲取到的光標左邊的文字打印出來後,我發現文字的後邊被追加了一個奇怪的字符:
你可能看不見,它實際上也是一個無法表達的字符,一般來說文本編輯器都用來表示一個壞掉的字符。不過,經過字符編碼轉換後,我還是找到了它的原本,這是一個 ASCII 字符,編碼是 0X01 ……嗯,無法表達的字符——那麼答案就明顯了,顯然是在系統在設定 buffer 的時候判斷到了這個字符的數量(也就是1),但在替換的時候這個字符沒了,於是把末尾的字給替換了。
於是,我就根據有道云筆記的 BundleID 進行判斷,一旦找到這個字符,那說明就是在它的 MarkDown 模式裡,然後在鍵入 buffer 之前,手動把這個字符給它補回去——好吧它至少真的管用:
1 2 3 4 5 6 7 8 9 |
//修复有道云笔记 MD 模式的奇葩问题 if let id = self.bundleIdentifier(), id == "com.youdao.note.YoudaoNoteMac" { if self.selectedRange().length == 1 { if self.attributedSubstring(from: self.selectedRange()).string == "\u{01}" { self.insert(text: "\u{01}") } } } //补丁结束 |
不過好景不長,時隔半年,在另一個 app, Quiver 中又遇到了這個問題,這次就沒那麼容易解決了,同樣的辦法會導致無限遞歸……好吧,是時候使用真正的技術了。
經過詢問大佬(是的是問出來的……),macOS 的 InputMethodKit 中 上市 FUNC setMarkedText(_ 串: Any!, selectionRange: NSRange, replacementRange: NSRange) 這個方法,雖然在 Swift 中聲明的是接收 Any 類型,也就是說不論是 String 還是 NSAttributedString 均可(聲明中也是如此說明),但實際上它需要的是後者,很簡單,生成一個 NSAttributedString 再寫入 buffer ,問題解決。
同時,細心的我還發現了一個有趣的問題,落格輸入法的 buffer 下劃線總是比系統的下劃線要粗那麼一點(這裡我用 QIM 做比較):
原來, IMKInputController 中是有這麼一個方法的:
1 |
func mark(forStyle style: Int, at range: NSRange) -> [AnyHashable : Any]! |
它可以返回一個包含富文本標籤的字典,這個字典可以標記某條 buffer,從而讓系統認識這個 buffer。
那麼大概用法是這樣:
1 |
let attr = mark(forStyle: kTSMHiliteConvertedText, at: NSMakeRange(NSNotFound,0)) |
然後把這個屬性附加到設置 buffer 時生成的 NSAttributedString 即可,這才是 macOS 輸入法正確設置 buffer 的姿勢:
1 2 |
let att = NSAttributedString(string: t, attributes: attr) setMarkedText(att, selectionRange: NSMakeRange(NSNotFound, NSNotFound), replacementRange: NSMakeRange(NSNotFound, NSNotFound)) |
這樣,輸入法的 buffer 區域就和系統的一模一樣了:
本文由 落格博客 原創撰寫:落格博客 » 落格輸入法 macOS 是如何處理 ascii 0x01 的兼容問題的-macOS 輸入法如何正確設置 buffer
轉載請保留出處和原文鏈接:https://www.logcg.com/archives/2959.html