- Input Method Kitとも
- macOSのInput Method用ライブラリ
- とにかくドキュメントがない(kekeho)
参考資料
- 日本語入力を作るときに必要だった本
- IMKitでIMEを作ってみる本
- Swift対応
- チュートリアルとして大変良くできている本。最新のIMKit情報が詰まっている。神本といえる。まずはこれを読むべき。(kekeho)
- 公式ドキュメント
- InputMethodKit: InputMethodKit | Apple Developer Documentation
- IMKTextInput: オンラインドキュメントがないので、大人しくヘッダファイルを読みましょう。
- 一部はNSTextInputClientと共通しているので、そのドキュメントも参考になる
- NSTextInputClient: NSTextInputClient | Apple Developer Documentation
- Client側
- Input Method Kit Release Note for OS X v10.5
- Info.plistの書き方
- その他
- Technical Q&A QA1644: How do I add annotations to my IMKit Input Method
- 変換候補にアノテーションをつける
- どうも動かないらしい: https://openradar.appspot.com/34911503
- Technical Q&A QA1644: How do I add annotations to my IMKit Input Method
実装例
- GyaimMotion: 増井先生による実装
- Mozc: Google日本語入力のOSS版
- Objective-Cによる実装
- GitHub: https://github.com/google/mozc/tree/master/src/mac
- AquaSKK
- NumberInput_IMKit_Sample
- Appleのサンプルコード (Objective-C)
- かなり古い。色々動かなくなってる気がする(kekeho)
Tips
- IMKCandidatesは色々と壊れている(# ゚Д゚)
- 参考: Input Method Kit (IMKit) Apple Radars and Bug Reports · Issue #2 · pkamb/NumberInput_IMKit_Sample · GitHub
- 結局、しっかりしたIMEを作ろうと思うと自前で候補リストを描画する羽目になる(kekeho)
- Cocoa何もわからない民としては、WKWebViewとかで作るのがラクそう(kekeho)
- カーソルの画面上の位置(座標)を知りたい
- たとえば、自作変換候補ウィンドウをカーソルのそばに表示したいときなど
- 方法1: この方法は一部のネイティブCocoaアプリケーションでしか動作しないので、方法2推奨
- クライアント(IMKTextInput)のselectedRangeを取得して、それをNSRectに変換することでx, y, w, hが取得できる(kekeho)
-
...省略 func getCursorPos() -> NSRect { let selectedRange = self.client().selectedRange() return self.client().firstRect(forCharacterRange: selectedRange, actualRange: nil) } }
- 方法2
- クライアント(IMKTextInput)のattributes関数を呼びだし、カーソルの位置を取得
-
var p: NSRect = NSRect(x: 0, y: 0, width: 0, height: 0) self.client().attributes(forCharacterIndex: 0, lineHeightRectangle: &p) return p }
- 参考(GyaimMotion): https://github.com/masui/GyaimMotion/blob/0eab00612afe1e3a313bb34b205e14667efdc7d4/app/GyaimController.rb#L310
insertText(_ string: Any!, replacementRange: NSRange)
の仕様- 文字の置換(挿入)
- string: String, NSString, NSAttributedStringなど
- replacementRange: NSRange位置のテキストを置換する
- locationがNSNotFoundの場合: カーソル位置指定
- lengthがNSNotFoundの場合: Not置換、挿入になる
setMarkedText(_ string: Any!, selectionRange: NSRange, replacementRange: NSRange)
の仕様- 未確定文字列の置換(挿入)
- string: String, NSString, NSAttributedStringなど
- 未確定文字列の一部を選択(色付け)するには? (変換候補選択などで”となりのいぬ”の”いぬ”だけを色付けしたいときがある)
- こういう感じのをつくりたいとき:
- AttributedStringをつかってハイライトをつける
- これが参考になる: https://github.com/google/mozc/blob/f3514b090743d23fdcc6824b7af4be4acda283fb/src/mac/GoogleJapaneseInputController.mm#L679
- Swiftで書くとこんな感じ
-
let hIdx = 0 // ハイライトしたいインデックス。「となりの」だけをハイライトしたい let attrMarkedText = NSMutableAttributedString() for (i, text) in texts.enumerated() { let attrText = NSMutableAttributedString(string: text) let attr: [AnyHashable: Any] if i == hIdx { // Hilight attr = self.mark(forStyle: kTSMHiliteSelectedConvertedText, at: NSMakeRange(0, NSNotFound)) } else { // Underline attr = self.mark(forStyle: kTSMHiliteConvertedText, at: NSRange(location: 0, length: attrText.length)) } if let attr = attr as? [NSAttributedString.Key : Any] { attrText.addAttributes(attr, range: NSRange(location: 0, length: attrText.length)) } attrMarkedText.append(attrText) } self.client().setMarkedText(attrMarkedText, selectionRange: cursorPosition, replacementRange: cursorPosition)
-
- こういう感じのをつくりたいとき:
- 自前で変換候補ウィンドウを作って表示するときのNSWindow
- styleMaskを.borderlessにするとそれっぽい
- NSWindowのlevelは、.popUpMenuにするとよい
- Mozcの実装もそうなっている
- .floatingでは足りないケースがある: SpotlightやLaunchpadのテキストエリアはもっと上に位置しているので、下に隠れてしまう
- 連続的にclientのinsertTextを追記で呼び出すと、たまに文字が吹き飛ぶ・前後する
-
for c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" { self.client().insertText(String(c), replacementRange: range) } // クライアントアプリの画面に表示される文字列は「AGHDEFIJKLMNOPQRSTUVWXYZ」みたいなことになる
- クライアントも非同期的に処理していると思われる(kekeho)
- ある程度はまとめて書き込んでやったほうがよさそう(kekeho)
- OTのテクニックが使えないか?
-
謎
- MacのChromeでGoogle Docsを開くと、変換候補ウィンドウの位置が狂う
- Google日本語入力やAppleの純正IMEでもそうなる