そもそもの発端は、この issue:
- Unicode · Issue #390 · zetamatta/nyagos
(2023.04.28追記:起案者の @nu8 氏のアカウントと issue 本体が消えてしまったので、通知メールなどから復元 → Recovery issue 390 Unicode · Issue #394 · nyaosorg/nyagos)
∞ (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 にあてた。
- KeyDown された時に、左ALT (ContolKeyState=2) + VK_MENU (VirtualKeyCode==0x12) の時は、フラグをセットする
- 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 さん、情報ありがとうございました (← 追々々記:お名前間違えてすみません。直しました) )