« 2025年11月 | トップページ | 2026年1月 »

2025年12月

2025年12月23日 (火)

IME on/off の切換 - その4

macos の入力ソースの切換プログラミングでは、kTISPropertyInputSourceIsSelected プロパティや selectedKeyboardInputSource で、現在の入力ソースを調べることができる。プログラムのロジックとしては、これを使って、現在のソースと違うソースが要求されたときだけ、ソース切換処理をするというふうにしたいところである。

しかし、ここには大きな落とし穴があった。実はこの変数は、プロセス起動時点の入力ソースは取れるもの、その後はプロセス内で処理した値しか取れないのであった。つまり、例えば手動で入力ソースを切り替えてしまうと、切換後の入力ソースをプログラム側で検知することはできない。色々調べてみたが、APIを通じてリアルタイムに、かつ確実に現在のソースを取得する術は見当たらなかった。

何かいい方法はないかと考えていたとき、ふと「APIが頼れないなら、表示されている情報を直接読み取ればいいのでは」と思いついた。メニューバーの右端には、常に現在の入力ソース名が表示されているではないか。

そこで、Swift で作っていた TISServer を改造して、メニューバーの表示を利用した判定ロジックを組み込んでみた。原理はシンプルで、メニューバーの入力ソース表示領域をスクリーンキャプチャしで、OCR機能でテキストに変換することで現在のソースを特定するという、いかにもシロウトが考えそうな方法である。ChatGPT に聞いてみたところ、Swift ではスクリーンキャプチャも OCR も標準でできるようになっていて、使い方も教えてくれた。

早速プログラミングしてみたが、キャプチャからOCR完了までにかかる時間は100ミリ秒程度、実用的な速度ではある。執念でプログラムしてみたものの、一体そこまでこだわらなくても、いいのかもしれないと、思いそうになった。

2025年12月20日 (土)

IME on/off の切換 - その3

JNI の後継である Foreign Function and Memory (FFM) API が、Java 25 から --enable-preview なしで利用可能になった。興味があったので、Swift で書いて動かしていた IME 切換の TISServer を、FFM で書き直す 実験をしてみた。JNI と違い、FFM では dylib を用意しなくても、Carbon を読み込んで、その中の TIS 関連のネイティブ関数を呼び出すことができる。

しかし実際に試してみると、基本的なメソッドは普通に呼び出せたものの、TIS 関連の関数を呼ぶとコアを吐いて強制終了になってしまうことが判明した。条件をいろいろ変えて実験した結果、Swing を使うと TIS 関連の呼び出しができなくなることが判明、どうやら Swing の EDT とネイティブスレッドが干渉しているようであった。

そこで、TIS 関連のコードを、Swing を使わないクラスにまとめて conveyor の cli 化、それを子プロセスとして立ち上げて本体と通信する構造にして、TIS 関連関数を呼び出せるようにした。しかし今度は、子プロセスが Swing を使っていないため、cli の launch が完了せず、ドックでアイコンが永遠にバウンスし続けることになってしまった。これは、無理矢理 RunApplicationEventLoop を呼んで、launch 完了したように擬態することで解決した。

散々苦労した割に、やってることは子プロセス呼び出しなので、Swift で作った今までの TISServer と同じである。ただ、コードが Java で統一されて、IntelliJ と Xcode を行き来しなくてもよくなる利点はあるかもしれない。実験としても楽しかった。

« 2025年11月 | トップページ | 2026年1月 »