WisdomSoft - for your serial experiences.

4.2 キーボード入力

キーボードのキー入力に反応するプログラムを作成します。どのキーが押されたのかや、文字キーの文字をプログラムで取得できます。

4.2.1 キーボードイベントを受ける

キーボードの入力をプログラムで処理する方法はマウスと同じです。キーボードはボタンの数が多いという意味では複雑ですが、マウスのように座標を持たないという意味では単純です。イベントは単純に何らかのキーを押した時に発生する KeyDown イベントと、キーを離したときに発生する KeyUp イベントで処理することができます。マウスのイベント発生メカニズムとまったく同じで、KeyDown イベントを呼び出すのは OnKeyDown() メソッド、KeyUp を呼び出すのは OnKeyUp() メソッドとなります。

Control クラス OnKeyDown() メソッド
protected virtual void OnKeyDown(KeyEventArgs e)
Control クラス KeyDown イベント
public event KeyEventHandler KeyDown
Control クラス OnKeyUp() メソッド
protected virtual void OnKeyUp(KeyEventArgs e)
Control クラス KeyUp イベント
public event KeyEventHandler KeyUp

KeyDown 及び KeyUp イベントに追加できるのは System.Windows.Forms.KeyEventHandler デリゲート型のオブジェクトです。

System.Windows.Forms.KeyEventHandler デリゲート
[Serializable]
public delegate void KeyEventHandler(object sender, KeyEventArgs e)

これも、MouseEventHandler と基本的な使い方は同じです。sender にはイベントを発生させたオブジェクトが格納され、e にはイベントに関連した情報を提供するオブジェクトが格納されています。

これらのメソッドに渡される KeyEventArgs 型のパラメータ e は、イベント発生時に押されたキーなどの情報を提供する System.Windows.Forms.KeyEventArgs クラスのオブジェクトです。

System.Windows.Forms.KeyEventArgs クラス
System.Object
    System.EventArgs
        System.Windows.Forms.KeyEventArgs
[ComVisible(true)]
public class KeyEventArgs : EventArgs

このクラスは、押されたキーボードのキーに関する情報を提供します。キーは、文字キーや数字キーなど何らかの値を直接表すキーと、Alt や Ctrl、Shift など、キーと組み合わせて使う修飾キーが存在します。通常のキーは KeyCode プロパティから、修飾キーは Modifiers プロパティから取得することができます。

KeyEventArgs クラス KeyCode プロパティ
public Keys KeyCode { get; }
KeyEventArgs クラス Modifiers プロパティ
public Keys Modifiers { get; }

これらのプロパティが提供する値は System.Windows.Forms.Keys 列挙体のメンバのいずれか、または組み合わせです。KeyCode はイベント発生時の単一キーのみを提供しますが、Modifiers はCtrl を押したまま Alt キーを押すなど、修飾キーの組み合わせを提供します。

System.Windows.Forms.Keys 列挙体
[Flags]
[Serializable]
[ComVisible(true)]
public enum Keys

Keys 列挙体はキーボードの各キーのすべてを個々のメンバに対応させているため数多くのメンバをもっていますが名前はシンプルなものです。キーボードの A キーに対応しているのは A メンバ、Alt キーに対応するのは Alt メンバ、Enter キーに対応するのは Enter メンバという形になります。この列挙体は FlagsAttribute 属性を持っているため、メンバを組み合わせることができます。

コード1
using System.Drawing;
using System.Windows.Forms;

public class Test : Form
{
	private string key = "";
	private string modifier = "";
	private void Test_KeyDown(object sender, KeyEventArgs e) 
	{
		key = e.KeyCode.ToString();
		modifier = e.Modifiers.ToString();
		Invalidate();
	}

	protected override void OnPaint(PaintEventArgs e)
	{
		base.OnPaint (e);
		Font font = new Font(Font.Name, 40);
		Brush brush = new SolidBrush(Color.Black);
		e.Graphics.DrawString("Key=" + key, font, brush, 0, 0);
		e.Graphics.DrawString("Modifier=" + modifier, font, brush, 0, font.Height);
	}

	public Test() 
	{
		KeyDown += new KeyEventHandler(Test_KeyDown);
	}

	static void Main() 
	{
		Application.Run(new Test());
	}
}
実行結果
コード1 実行結果

コード1は、KeyDown イベントを受けて、イベント発生時の押されているキーと、修飾キーをそれぞれ KeyCode 及び Modifiers プロパティから取得して、キーの文字列表現を key と modifier フィールドに保存しています。OnPaint() メソッドでは、これらのフィールドをウィンドウに表示しています。このプログラムを実行して任意のキーを押すと、押されたキーが画面に表示されます。

KeyCode はキーの組み合わせではなく常に単一のキーのみが保存されます。これに対して Modifier は修飾キーのみを保存するため文字キーなどを押しても None が返されるだけです。キーと修飾キーのすべての組み合わせが必要な場合は KeyDate プロパティを利用してください。

KeyEventArgs クラス KeyDate プロパティ
public Keys KeyData { get; }

キーの組み合わせが重要になる入力処理を監視する場合は KeyData を使ってください。

4.2.2 キー入力から文字を得る

KeyDown や KeyUp イベントから押されたキーを知ることができますが、押されたキーに関する情報は Keys 列挙体のメンバとして得られます。どのキーが押されたのか、またはどのようなキーの組み合わせなのかが重要な場合はこれで十分対応することができます。例えば、ゲームプログラミングの場合はキーボードの方向キーや何らかの動作に対応付けられたキーであるかどうかを調べれば様々な操作を実現できるでしょう。

しかし、目的が押されたキーの監視ではなく文字の入力であれば、KeyDown や KeyUp イベントで発生した Keys 列挙体から文字に変換するという作業は冗長な処理になります。この場合、修飾キーや方向キーなどには興味がなく、一般的な文字入力操作の結果として得られる文字だけが重要になります。

例えば、文字入力では Shift + 文字キーという組み合わせで入力されれば、得られる文字は大文字と小文字が切り替わったり、数字の代わりに記号が入力されたりしなければなりませんが、これを KeyCode プロパティと Modifier プロパティを調べて変換するという作業は不要です。

キーボードイベントの結果で文字が発生すると、OnKeyPress() メソッドが呼び出され、OnKeyPress() メソッドは KeyPress イベントを発生させます。性質的に KeyPress イベントが発生する前には必ず KeyDown イベントが発生しています。

Control クラス OnKeyPress() メソッド
protected virtual void OnKeyPress(KeyPressEventArgs e)
Control クラス KeyPress イベント
public event KeyPressEventHandler KeyPress

KeyPress イベントに登録できるのは System.Windows.Forms.KeyPressEventHandler デリゲート型のオブジェクトです。

System.Windows.Forms.KeyPressEventHandler デリゲート
[Serializable]
public delegate void KeyPressEventHandler(object sender, KeyPressEventArgs e);

sender パラメータにはイベントを発生させたソースオブジェクトが格納されます。OnKeyPress() メソットと KeyPressEventHandler デリゲートの e パラメータには、ユーザーがキーを入力した結果として発生した文字を提供する System.Windows.Forms.KeyPressEventArgs クラスのオブジェクトが格納されています。

System.Windows.Forms.KeyPressEventArgs クラス
System.Object
    System.EventArgs
        System.Windows.Forms.KeyPressEventArgs
[ComVisible(true)]
public class KeyPressEventArgs : EventArgs

発生した文字を取得するには KeyPressEventArgs オブジェクトの KeyChar プロパティから取得することができます。

KeyPressEventArgs クラス KeyChar プロパティ
public char KeyChar { get; }

KeyChar は修飾キーによる文字の切り替えを意識する必要はありません。単純に 1 キーを押せば数字の 1 が生成されますが、Shift キーを押しながら 1 キーを押せば記号 ! が文字として生成されます。文字以外のキーが押されても、文字が発生しないので KeyPress イベントは発生しません。

コード2
using System.Drawing;
using System.Windows.Forms;

public class Test : Form
{
	private char keyChar;
	private void Test_KeyPress(object sender, KeyPressEventArgs e) 
	{
		keyChar = e.KeyChar;
		Invalidate();
	}

	protected override void OnPaint(PaintEventArgs e)
	{
		base.OnPaint (e);
		Font font = new Font(Font.Name, 40);
		Brush brush = new SolidBrush(Color.Black);
		e.Graphics.DrawString("KeyChar=" + keyChar, font, brush, 0, 0);
	}

	public Test() 
	{
		KeyPress += new KeyPressEventHandler(Test_KeyPress);
	}

	static void Main() 
	{
		Application.Run(new Test());
	}
}
実行結果
コード2 実行結果

コード2は、KeyPress イベントを監視して文字を受け取ります。タイピングゲームなど、キーによる操作そのものではなく生成された文字が重要な場合はこのイベントを使うことになると思われます。文字が発生しないキー入力に対しては KeyPress は発生しないため、修飾キーを押しただけでは KeyPress イベントが呼び出されることはありません。しかし、Shift キーを押しながら 1 キーを押すと、記号 ! が生成されて KeyPress が発生します。