ターミナルで無変換キーを押すとアットマーク(@)が挿入される問題の調査と解決方法
概要
いわゆる「Mac方式」のIMEにカスタマイズしている場合に発生する問題で、「無変換キー=IMEオフ」「変換キー=IMEオン」に割り当てているとき、無変換キーを押すとターミナルに半角@(アットマーク)が入力される問題がある。
とりあえずアルファベットを打ちたいときに無変換キーを連打することに慣れてしまった人(私)にとって地獄のような状態であるため、原因を調査した。
この記事の内容は、GitHubのIssueで語られている内容を引用している。
結論
発生原因は、旧Microsoft IME の仕様 および ターミナルの実装が不運にもミスマッチしたためと考えられる。解決方法は以下の2種類がある。
(1)IMEを変える
古い Microsoft IME の利用をやめ、新しいMicrosoft IMEを使う。新しいMicrosoft IMEの設定方法は以下の記事が参考になる。
(2)キー割り当てを変更する(一時的な対処)
下記の記事を参考に、Windows ターミナルの設定から、vk29
を別の機能に割り当てる。これはWindowsターミナルでは有効だが、PowerShellを直接起動した際には無効。
調査
IMEにより「無変換キー」を押したときに送出されるキーコード(一覧はこちら)を調べた。
No. | 条件 | 旧IME | 新IME |
---|---|---|---|
1 | IMEオフ & KeyDown | 0x1D | 0xE5 |
2 | IMEオフ & KeyUp | 0x1D | 0x1D |
3 | IMEオン & KeyDown | 0xE5 | 0xE5 |
4 | IMEオン & KeyUp | 0x1D | 0x1D |
表の横方向が同じ値になっている場合、新旧IMEが同じ動作であることを表す。
注目すべきはNo.1 「IMEオフで無変換キーを押下したとき」 であり、新旧で送出される仮想キーコードが異なる。
これが旧IMEで無変換キーを連打するとアットマークが挿入される正体である。
考察
- 無変換キー押下(KeyDown)で送出される仮想キーコードは、
VK_PROCESSKEY
とVK_NONCONVERT
のどちらが正しいのか?- 調べても分からなかった。
- 個人的感想だが、何が正しいかというよりは、何が使われてきたかという歴史的経緯であると思った。
VK_PROCESSKEY
の意味は?VK_PROCESSKEY
は、IMEによって処理されたキー入力であることを表す。VK_PROCESSKEY
は、ImmGetVirtualKey function (imm.h)で実際に入力されたキーボードの仮想キーコードを取り出すことができる。
というわけで以下のようなコード(抜粋)を使い、TextBoxで無変換キーを押したときの VK_PROCESSKEY
から仮想キーコードを取り出してみた。
public override bool PreProcessMessage(ref Message msg) { if (msg.Msg == 0x0100 /*WM_KEYDOWN*/) { Console.WriteLine($"WParam: {msg.WParam}"); if (msg.WParam.ToInt32() == 0xE5 /*VK_PROCESSKEY*/) { uint vk = ImmGetVirtualKey(msg.HWnd); Console.WriteLine($"VK: {vk}"); } } return base.PreProcessMessage(ref msg); }
無変換キーを押したときに得られた出力は以下。IMEが処理した無変換キー(0x1D = 29)であることが分かる。
WParam: 229 VK: 29
結局どうすれば良いか?
先の結論に挙げた通り、Windowsターミナルは新IMEの仕様に合わせて作られているため、新IMEを使用すればよい。ただし、新IMEは Windows 10 (2004) 以降でのみ使用可能。
追記 2022/7/6:
新しいIMEを使っていると、日本語が2重に入力される現象が発生中。これが発生すると変換ができず、「テスト」と入力すると「ttええssううttおお」となる。 仕方なく旧IMEに戻したがアットマークは再燃した...
参考
- PowerShellで無変換キーを押すとアットマークが入力される問題を回避する - Qiita
- Some keys on Japanese layout keyboards are incorrectly interpreted as @ · Issue #2206 · PowerShell/PSReadLine · GitHub
- Virtual-Key Codes (Winuser.h) - Win32 apps | Microsoft Docs
- PSReadLine/Keys.cs at ad74cef2501709d2a60a58f61d7cac32d185209f · PowerShell/PSReadLine · GitHub
- Re[8]: IME入力中のキー入力を取得したい
- API 関数解説