左右 Command キーで日本語入力をオフ/オンするやつの Windows 版を作った
US 配列のキーボードで日本語入力をする時に困るのが、日本語入力のオンオフ切り替えに特化したキーが存在しないことです。US 配列であっても、マウス操作や何らかのショートカットキー (Windows では alt + ` など) を使うことで一応は日本語入力のオンオフを切り替えられますが、頻繁に使うのであればやはりそれ専用のキーが欲しいところです。
Mac では⌘英かなや Karabinar-Elements といったサードパーティーのキーリマップソフトウエアを入れるとこの問題を解決できます。これらのソフトウエアを使うと、左右のコマンドキー (Windows での Ctrl に近い) に英数/かなキーの機能を兼任させることができます。例えば、左コマンドキーを単体で押すと日本語入力がオフ、右コマンドキーを単体で押すと日本語入力がオンになるよう設定でき、これが大変に便利なのです[1]。
Windows にも⌘英かなが欲しい。Windows 用のキーリマップソフトウエアとしては AutoHotKey があり、これを使えば⌘英かなと同じことができるようではありましたが、AutoHotKey は私が求めているものに対して多機能すぎました。求めているのは左右の Ctrl キーでIMEのオンオフを切り替えるプログラム。それぐらいなら自作できるのでは? ということで作りました。本体は C# コードで、PowerShell から呼び出すことができます。
ykiu/ctrl-ja: 💬Handy IME hotkeys for Windows
技術解説
「左右の Ctrl キーでIMEのオンオフを切り替えるプログラム」を実現するには大きく分けて二つのことをする必要があります。一つは OS レベルのキー入力を監視し、左右の Ctrl キーが押された時に何らかのアクションを実行することです。もう一つは IME の状態をプログラムで制御することです。
一つ目のキー入力の監視を実装するにあたってはかなりの困難を予想していました。自ウィンドウに発生したキー入力を検知するならいざ知らず、OS 全体のキー入力を検知するには何か特別なことをする必要がありそうです。が、これは案外あっさり実現できることがわかりました。キー入力などのイベントを監視するための Win32 API 関数 SetWindowsHookEx()
が存在し、実質的にこれにコールバックを渡すだけなのです。
問題はどの言語から SetWindowsHookEx()
を呼ぶかですが、今回はポータビリティを考慮して PowerShell を使うことにしました。PowerShell には C# のコードをインラインで埋め込むことができ、埋め込まれた C# のコードから Win32 の関数を呼ぶことができます。PowerShell + C# で Win32 API を使いキー入力を検知する具体的な方法は、このキーロガーの記事に拠りました。
二つ目の IME の制御については、そのための API が Windows から提供されていると予想していました。事実、Win32 API に IME 制御用の関数が存在したのですが、使い方に関する情報が少なく、思いの外苦戦しました。結果的にもらかなさんの AutoHotKey の記事のやり方を参考にして IME を制御することに成功しました。
意外だったのは、Windows における IME のインスタンスの概念です。私は当初、IME のインスタンスは OS 全体で一個しかない、シングルトン的なものだと想像していました。しかし実際にはウィンドウ一個ごとに、そのウィンドウを担当する IME のインスタンス (IME ウィンドウと呼ぶ) が作られるようです。そのため、IME の状態を切り替えるには次のような手順を踏むことになります。
- 現在アクティブなウィンドウを取得: GetForegroundWindow()
- そのウィンドウに対応する IME ウィンドウを取得: ImmGetDefaultIMEWnd()
- IME ウィンドウにメッセージを送信: SendMessage()
詳しくはこのあたりを見てください。
おわりに
メインで使っている Windows マシンでは、タスクスケジューラを使ってOS起動時にこのプログラムが自動的に立ち上がるようにしています[2]。かれこれ一か月くらい使っていますが、壊れることもなく順調に動いています。この記事も左右の Ctrl キーで IME を入れたり切ったりしながら書きました。
詳しい使い方は README に記載してありますので、気になる方は見てみてください。
Discussion