...ing logging 4.0

はてなブログに移行しました。D言語の話とかいろいろ。

DFLのTextBoxがリターンキーとタブキーを正しく受け付けなかったバグを修正

github.com

全般的なこと

当初の想定よりも大規模な改修になってしまった。

基本的には、WinFormsのキー入力イベントシステムを踏襲した形に修正していく方針とし、DFLが元々使っているFormMessageFilterクラスへの依存を減らした。 キー入力イベントシステムの構造が複雑になったが、本家WinFormsではMessageFilterは使われていないし、この当たりの処理は20年前からのWinFormsの解説記事が潤沢にあるので、こちらの方がいいと判断した。

元々のコードでは、Win32にあるControlStyles列挙体をハックして項目を追加し、TextBoxクラスやTextBoxBaseからFormクラスに情報を伝える方法を採っていたので、それをなくそうとしていた。 テキストボックスの挙動を調べていると、リターンキーやタブキーの受入可否設定と、デフォルトボタンの有無の組み合わせによって、正しく動作していないことが分かった。

本来であれば、TextBoxクラスはそれ自身がリターンキーを受け付けるかどうかを知っているので、TextBoxクラスから親Formに対し、フォームがデフォルトボタンを持っているかを問い合わせるべきなので、そのように変更した。これにより、リターンキーの受入可否設定によらず、RETURN単独、ctrl+RETURNの処理が正しく動作するようになった。

また、本来であれば、TextBoxBaseクラスはそれ自身がタブキーを受け付けるかどうかを知っているので、次のコントロールへタブストップするために親クラスに処理を任せるか、タブキーを受け入れるかの判断を自身で行うように変更した。 元々のコードでは、クラス間のメソッド呼び出し方向が逆になっており、FormクラスからTextBoxBaseクラスに対しタブキーを受け付けるか確認するためのメソッドが追加されていた。このメソッドはWinFormsにはない。 修正により、タブキーの受入可否設定によらず、TAB単独、ctrl+TABの処理が正しく動作するようになった。

ただ、もしかすると、参考文献にあるように、WM_CHARメッセージとWM_SYSCHARメッセージに対するプリプロセスの方で書くべきなのかもしれない。 無駄に複雑化している可能性があるので、今後調査が必要だ。

この変更の動作確認のために書いたテストコードをテキストボックスのサンプルコードとして追加した。

その他のこと

キー入力イベントの動作がどうなっているのかさっぱり分からず、ブレークポイントを使う必要があったので、やっとvscodeを入れた。すぐserve-dが応答不能になって、プロセス・キルが必要になるけど、なんだろうか。

DScanerが構文の問題点を一杯指摘してくれるのでいくつかはついでに直した。 特に古いalias構文がたくさんあって、直し切れていない。

ひとつのファイルに親子のクラスが定義されているとどっちを修正しているのか分かりにくかったのでTextBoxBaseとTextBoxを別ファイルに分離した。 また、分離が簡単にできそうだったControlとSharedControlを別ファイルに分離した。

これからのこと

一応動作確認はしたが、大規模に改修したので、テキストボックス以外への波及がもしかしたらあるかもしれない。 一旦、すべてのGUIコントロールを追加したフォームを作ってみた方がいいかもしれない。

まだ完全にはフォームからコントロールへの方向のタブキー受付可否照会を削除できていないが、まともに動作するようになった段階で一旦コミットしておく。

フォームのデフォルトボタンの処理は修正したが、キャンセルボタンの処理はまだ 。

英語的なこと

コメントを頑張って英語で書くようにしたが、ソースコードのコメントだと割と定形文になるようだ。 三単現がよく分からないけど、何とか伝わればいいなあ。