[#macOS](macOS) [#Swift](Swift) - [[Input Method Kit]]とも - macOSの[[Input Method]]用ライブラリ - とにかくドキュメントがない(kekeho) 参考資料 - [日本語入力を作るときに必要だった本](https://booth.pm/ja/items/809262) - IMKitでIMEを作ってみる本 - Swift対応 - チュートリアルとして大変良くできている本。最新のIMKit情報が詰まっている。神本といえる。まずはこれを読むべき。(kekeho) - 公式ドキュメント - InputMethodKit: [InputMethodKit | Apple Developer Documentation](https://developer.apple.com/documentation/inputmethodkit) - [[IMKTextInput]]: オンラインドキュメントがないので、大人しくヘッダファイルを読みましょう。 - 一部はNSTextInputClientと共通しているので、そのドキュメントも参考になる - [[NSTextInputClient]]: [NSTextInputClient | Apple Developer Documentation](https://developer.apple.com/documentation/appkit/nstextinputclient) - Client側 - [Input Method Kit Release Note for OS X v10.5](https://developer.apple.com/library/archive/releasenotes/Cocoa/RN-InputMethodKit/index.html#//apple_ref/doc/uid/TP40004740) - Info.plistの書き方 - [https://github.com/google/mozc/blob/master/src/mac/Info.plist](https://github.com/google/mozc/blob/master/src/mac/Info.plist) - [[Mozc]]の例 - [https://github.com/rime/squirrel/blob/master/Info.plist](https://github.com/rime/squirrel/blob/master/Info.plist) - [[Rime]]の例 - その他 - [Technical Q&A QA1644: How do I add annotations to my IMKit Input Method](https://developer.apple.com/library/archive/qa/qa1644/_index.html#//apple_ref/doc/uid/DTS40009583) - 変換候補にアノテーションをつける - どうも動かないらしい: [https://openradar.appspot.com/34911503](https://openradar.appspot.com/34911503) 実装例 - [[GyaimMotion]]: 増井先生による実装 - 公式サイト: [https://masui.github.io/GyaimMotion/](https://masui.github.io/GyaimMotion/) - GitHub: [https://github.com/masui/GyaimMotion](https://github.com/masui/GyaimMotion) - [[Mozc]]: Google日本語入力のOSS版 - Objective-Cによる実装 - GitHub: [https://github.com/google/mozc/tree/master/src/mac](https://github.com/google/mozc/tree/master/src/mac) - [[AquaSKK]] - GitHub: [https://github.com/t-suwa/aquaskk](https://github.com/t-suwa/aquaskk) - [NumberInput_IMKit_Sample](https://developer.apple.com/library/archive/samplecode/NumberInput_IMKit_Sample/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007466-Intro-DontLinkElementID_2) - Appleのサンプルコード (Objective-C) - かなり古い。色々動かなくなってる気がする(kekeho) Tips - IMKCandidatesは色々と壊れている(# ゚Д゚) - 参考: [Input Method Kit (IMKit) Apple Radars and Bug Reports · Issue #2 · pkamb/NumberInput_IMKit_Sample · GitHub](https://github.com/pkamb/NumberInput_IMKit_Sample/issues/2) - 結局、しっかりしたIMEを作ろうと思うと自前で候補リストを描画する羽目になる(kekeho) - Cocoa何もわからない民としては、WKWebViewとかで作るのがラクそう(kekeho) - カーソルの画面上の位置(座標)を知りたい - たとえば、自作変換候補ウィンドウをカーソルのそばに表示したいときなど - 方法1: この方法は一部のネイティブCocoaアプリケーションでしか動作しないので、方法2推奨 - クライアント(IMKTextInput)のselectedRangeを取得して、それをNSRectに変換することでx, y, w, hが取得できる(kekeho) - ```sample.swift, class HogeController: IMKInputController { ...省略 func getCursorPos() -> NSRect { let selectedRange = self.client().selectedRange() return self.client().firstRect(forCharacterRange: selectedRange, actualRange: nil) } } ``` - 方法2 - クライアント(IMKTextInput)のattributes関数を呼びだし、カーソルの位置を取得 - ```sample.swift, func getCursorPos() -> NSRect { 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](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など - 未確定文字列の一部を選択(色付け)するには? (変換候補選択などで"となりのいぬ"の"いぬ"だけを色付けしたいときがある) - こういう感じのをつくりたいとき: - ![[assets/64f7a2bd8f035f001c4a0056.png]] - AttributedStringをつかってハイライトをつける - これが参考になる: [https://github.com/google/mozc/blob/f3514b090743d23fdcc6824b7af4be4acda283fb/src/mac/GoogleJapaneseInputController.mm#L679](https://github.com/google/mozc/blob/f3514b090743d23fdcc6824b7af4be4acda283fb/src/mac/GoogleJapaneseInputController.mm#L679) - Swiftで書くとこんな感じ - ```swift, let texts = ["となりの", "いぬ"] 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](https://developer.apple.com/documentation/appkit/nswindow) - [styleMask](https://developer.apple.com/documentation/appkit/nswindow/stylemask)を[.borderless](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644698-borderless)にするとそれっぽい - NSWindowの[level](https://developer.apple.com/documentation/appkit/nswindow/1419511-level)は、[.popUpMenu](https://developer.apple.com/documentation/appkit/nswindow/level/1419344-popupmenu)にするとよい - [Mozcの実装もそうなっている](https://github.com/google/mozc/blob/f3514b090743d23fdcc6824b7af4be4acda283fb/src/renderer/mac/CandidateController.mm#L112C31-L112C31) - [.floating](https://developer.apple.com/documentation/appkit/nswindow/level/1419352-floating)では足りないケースがある: SpotlightやLaunchpadのテキストエリアはもっと上に位置しているので、下に隠れてしまう - 連続的にclientのinsertTextを追記で呼び出すと、たまに文字が吹き飛ぶ・前後する - ```code, let range = NSRange(location: NSNotFound, length: NSNotFound) // 追記 for c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" { self.client().insertText(String(c), replacementRange: range) } // クライアントアプリの画面に表示される文字列は「AGHDEFIJKLMNOPQRSTUVWXYZ」みたいなことになる ``` - クライアントも非同期的に処理していると思われる(kekeho) - ある程度はまとめて書き込んでやったほうがよさそう(kekeho) - [[OT]]のテクニックが使えないか? 謎 - MacのChromeでGoogle Docsを開くと、変換候補ウィンドウの位置が狂う - Google日本語入力やAppleの純正IMEでもそうなる