vorfee's Tech Blog

Just another tech blog

ターミナルで無変換キーを押すとアットマーク(@)が挿入される問題の調査と解決方法

概要

いわゆる「Mac方式」のIMEにカスタマイズしている場合に発生する問題で、「無変換キー=IMEオフ」「変換キー=IMEオン」に割り当てているとき、無変換キーを押すとターミナルに半角@(アットマーク)が入力される問題がある。

とりあえずアルファベットを打ちたいときに無変換キーを連打することに慣れてしまった人(私)にとって地獄のような状態であるため、原因を調査した。

この記事の内容は、GitHubのIssueで語られている内容を引用している。

github.com

結論

発生原因は、旧Microsoft IME の仕様 および ターミナルの実装が不運にもミスマッチしたためと考えられる。解決方法は以下の2種類がある。

(1)IMEを変える

古い Microsoft IME の利用をやめ、新しいMicrosoft IMEを使う。新しいMicrosoft IMEの設定方法は以下の記事が参考になる。

atmarkit.itmedia.co.jp

(2)キー割り当てを変更する(一時的な対処)

下記の記事を参考に、Windows ターミナルの設定から、vk29を別の機能に割り当てる。これはWindowsターミナルでは有効だが、PowerShellを直接起動した際には無効。

qiita.com

調査

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 = 0x1D = VK_NONCONVERT
  • IME = 0xE5 = VK_PROCESSKEY

これが旧IMEで無変換キーを連打するとアットマークが挿入される正体である。

考察

  • 無変換キー押下(KeyDown)で送出される仮想キーコードは、VK_PROCESSKEYVK_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を使用すればよい。ただし、新IMEWindows 10 (2004) 以降でのみ使用可能。

追記 2022/7/6:

新しいIMEを使っていると、日本語が2重に入力される現象が発生中。これが発生すると変換ができず、「テスト」と入力すると「ttええssううttおお」となる。 仕方なく旧IMEに戻したがアットマークは再燃した...

参考