キューに溜まらないキー入力受け付け処理

特に使うプログラムを組む訳でもないですし、他にやらないといけないことも一杯あるのですが、何故が思いついてしまったので、取り組んでみたいと思います。

やりたいことはキー入力を受け付けることなのですが、普通に KeyPress イベントでやってしまうとキューにたまってしまい、ゲーム等では使えません*1DirectX を使えば簡単に解決するんでしょうけど、これをなんとか C# + .NET だけで実現出来ないだろうかという訳です。

早速試してみたのがイベントハンドラ内でイベントを空処理するコード(溜まるけど、溜まった分は破棄)

private bool key_input_accept; // 初期値を true にする

private void WinForm_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
	e.Handled = true;
	if (key_input_accept) {
		key_input_accept = false;
		Debug.WriteLine(e.KeyChar);
		System.Threading.Thread.Sleep(300);
		Application.DoEvents();
		key_input_accept = true;
	}
}

他の言語に良くある sleep とかがどこにあるのか分からなかったので強引に空ループ^^;これでいいのかどうか分かりませんが、とりあえず目的は達成してるような気が少しだけします。

一応解説。初めて KeyPress イベントが発生すると key_input_accept に false をセットして、以降 KeyPress イベントが発生しても何も処理しないようにしておきます(スルーさせる)。そして処理の中で Application.DoEvents() を呼び出して、その時点で溜まっているメッセージキューをお掃除。最後に key_input_accept に true をセットして以降のキー入力に備えます。

シングルスレッドであれば、key_input_accept の比較と代入の間に処理が挟まることは無いので排他処理は期待通りに行われると期待して良いです。マルチスレッドだと当然ヤバいので、lock を使う等の変更が必要になってきますが。

当然同時押し等の判定は出来ませんし、リピート前の空白時間(なんて言うんでしょうか…)の存在という致命的な問題がありますのでとても実用には耐えません。その辺りは今後の課題ということで。現在の押されているキーがいつでもどこでも取得出来るのであれば Timer 使ってちょいちょいで出来るんですけどね〜。ゲームだったらどっちにしろ Timer 使うから処理の流れも綺麗にまとまりますし。

いろいろ面倒そうなのでやっぱり DirectX 使ってみようかな^^;

*1:移動キーの処理が溜まったりすると致命的なのです