標準愚痴出力

個人的なIT作業ログです。もしかしたら一般的に参考になることが書いているかもしれません(弱気

ReadConsoleInput の U+2000~U+2FFFの一部の文字に対する奇妙な挙動

そもそもの発端は、この issue:

∞ (U+221E) という文字が入力できないという話。どうも、Unicode の U+2000~U+2FFF の一部のコードを右クリックで Windows のコンソールにペーストすると、ReadConsoleInput で得られるデータが妙なことになるようだ(だが、それにも関わらず、CMD.EXE はうまいこと拾ってるんだよな)

それを確認するために、go-console-test という検証プログラムを作った。

まずは正常に入力される 「Ç (U+00C7)」を右クリックでペーストした結果:

KeyEventRecord: &{KeyDown:1 RepeatCount:1 VirtualKeyCode:0 VirtualScanCode:0 UnicodeChar:199 ControlKeyState:0}
KeyEventRecord: &{KeyDown:0 RepeatCount:1 VirtualKeyCode:0 VirtualScanCode:0 UnicodeChar:199 ControlKeyState:0}

UnicodeChar フィールドに 199=0xC7 に対する KeyDown と KeyUp がペアで順に入ってくる。

次に問題の「∞ (U+221E)」。これがおかしい

KeyEventRecord: &{KeyDown:1 RepeatCount:1 VirtualKeyCode:18 VirtualScanCode:56 UnicodeChar:0 ControlKeyState:2}
KeyEventRecord: &{KeyDown:0 RepeatCount:1 VirtualKeyCode:18 VirtualScanCode:56 UnicodeChar:8734 ControlKeyState:0}

KeyDown の UnicodeChar がゼロになっているのだ。だが、KeyUp の時の UnicodeChar はちゃんと8734=0x221E が入っている。

報告者によると、⌂(U+2302)、⌐ (U+2310)、░(U+2591)、▒(U+2592)、▓(U+2593)も同じ傾向があるようだ。共通することは

  • KeyDown 時に UnicodeChar が 0、ControleKeyState=2 (左ALT)、VirtualKeyCode==0x12 (VK_MENU) というデータがくる
  • その KeyDown ~ KeyUp までに0個以上の謎の KeyDown イベントが入ることがある
  • 最後に来る KeyUp イベントについては、ちゃんと UnicodeChar に期待する Unicode が入ってくる。

とりあえず、エンドユーザには分からない話だから(彼は nyagos が1文字3バイト以上の UTF8文字を扱えないからだと勘違いしていて、なかなか失礼な話である)、とりあえず以下のようなアドホックな回避コードを go-tty にあてた。

  1. KeyDown された時に、左ALT (ContolKeyState=2) + VK_MENU (VirtualKeyCode==0x12) の時は、フラグをセットする
  2. KeyUp された時、普通はこれを無視するところだが、フラグがたっていて、かつ UnicodeChar != 0 の時はその UnicodeChar が入力されたと見なす。この後、当然だがフラグはクリアする

これで一応、同文字が普通にペーストできるようはなった。go-tty に対するプルリクも受理され、マージいただけたようだ。先生もさぞ困惑されたことだろう。ちょっと無理やりな対応コードで申し訳ないことである(リジェクトされても仕方ないと思っていた)。

しかし、これ、どう考えても合理的な挙動に見えない。ReadConsoleInput に、何か、理解できていない仕様があるのだろうなぁ

追記

どうも、このような挙動がまったく起こらない環境もあるようだ。自分の手元の環境では、

  • Windows 8.1 :問題なし(KeyDown時にも ∞ の Unicode 出てる)
  • Windows10 1909:問題あり(KeyDown時に ∞ の Unicode 出ない=ゼロになる)

でも、Windows10 で問題が出ていない環境もあるそうなので、OS のバージョンとも決めつけられない。どういう条件で発生するんだろう。

追々記

得られた情報を総合すると:

  • Windows 8.1 : OK
  • Windows 10
    • 1803 : OK
    • 1909 : NG (KeyDown で UnicodeChar がゼロになってしまう)
    • 2004 : NG (KeyDown で UnicodeChar がゼロになってしまう)

どうも、1803~1909 の間で、ReadConsoleInput の挙動が変わった疑いがありますね。
( k_takata さん、情報ありがとうございました (← 追々々記:お名前間違えてすみません。直しました) )