コントロールによっては、矢印、Tab、Enter、Escキーなどが押されてもKeyDown、KeyUpなどのキーイベントが発生しません。例えば、ボタンコントロールでは、矢印キーの押下を捕捉できません。ここではボタンコントロールを例にして、これらのキーが押されたことを知るための方法を紹介します。
.NET Framework 2.0からはPreviewKeyDownイベントが追加され、これを使えば簡単です。
PreviewKeyDownイベントはKeyDownイベントの前に発生します。KeyDownやKeyUpイベントが発生しないようなキーが押された場合も発生し、押されたキーを知ることができます。
さらに、KeyDownやKeyUpイベントが発生しないようなキーが押された場合でも、PreviewKeyDownイベントハンドラでPreviewKeyDownEventArgs.IsInputKeyプロパティをTrueにすることにより、KeyDownやKeyUpイベントが発生するようになります。ただしこの場合は、そのキー本来の機能(例えば、矢印キーであれば、フォーカスの移動)は失われます。
以下の例では、ボタン(Button1)で矢印キーが押された時にそのことを表示し、また、Tabキーが押された時に本来の機能であるフォーカスの移動を無効にして、KeyDown、KeyUpイベントが発生するようにしています。
'PreviewKeyDownイベントハンドラ Private Sub Button1_PreviewKeyDown(ByVal sender As Object, _ ByVal e As PreviewKeyDownEventArgs) _ Handles Button1.PreviewKeyDown Select Case e.KeyCode '矢印キーが押されたことを表示する Case Keys.Up, Keys.Left, Keys.Right, Keys.Down Console.WriteLine("矢印キーが押されました。") 'Tabキーが押されてもフォーカスが移動しないようにする Case Keys.Tab e.IsInputKey = True End Select End Sub
//PreviewKeyDownイベントハンドラ private void Button1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) { switch (e.KeyCode) { //矢印キーが押されたことを表示する case Keys.Up: case Keys.Left: case Keys.Right: case Keys.Down: Console.WriteLine("矢印キーが押されました。"); break; //Tabキーが押されてもフォーカスが移動しないようにする case Keys.Tab: e.IsInputKey = true; break; } }
ButtonクラスのIsInputKeyメソッドをオーバーライドしてtrueを返すようにすることにより、矢印キーを押した場合でもKeyDownやKeyUpイベントが発生するようになります。ただし、矢印キーが押されたときの本来の機能(フォーカスの移動)は無くなります。
まず次のようなButtonクラスの派生クラスを作成し、IsInputKeyメソッドをオーバーライドします。ここで、矢印キーが押された時に、trueを返すようにします。ここでは、Altキーが同時に押されている場合は、矢印キー本来の機能が行われるようにしています。
Imports System Imports System.Windows.Forms Public Class ButtonEx Inherits Button Protected Overrides Function IsInputKey(ByVal keyData As Keys) As Boolean 'Altキーが押されているか確認する If (keyData And Keys.Alt) <> Keys.Alt Then '矢印キーが押されたときは、trueを返す Dim kcode As Keys = keyData And Keys.KeyCode If kcode = Keys.Up Or kcode = Keys.Down Or _ kcode = Keys.Left Or kcode = Keys.Right Then Return True End If End If Return MyBase.IsInputKey(keyData) End Function End Class
using System; using System.Windows.Forms; public class ButtonEx : Button { protected override bool IsInputKey(Keys keyData) { //Altキーが押されているか確認する if ((keyData & Keys.Alt) != Keys.Alt) { //矢印キーが押されたときは、trueを返す Keys kcode = keyData & Keys.KeyCode; if (kcode == Keys.Up || kcode == Keys.Down || kcode == Keys.Left || kcode == Keys.Right) { return true; } } return base.IsInputKey(keyData); } }
この様にして作成したButtonExクラスをSystem.Windows.Forms.Buttonクラスの代わりに使うようにします。
注意:新しく作成したクラスを、基のコントロールクラスの代わりに使用するという意味が分からないという方は、こちらをご覧ください。
ButtonクラスのProcessDialogKeyメソッド(あるいはProcessCmdKeyなど)をオーバーライドして、矢印キーが押されたことを知ることもできます。
先ほどと同じように、Buttonクラスの派生クラスを作成し、ProcessDialogKeyメソッドをオーバーライドします。ここでは、左キーが押された時に、メッセージボックスを表示するようにしています。
Imports System Imports System.Windows.Forms Public Class ButtonEx Inherits Button <System.Security.Permissions.UIPermission( _ System.Security.Permissions.SecurityAction.Demand, _ Window:=System.Security.Permissions.UIPermissionWindow.AllWindows)> _ Protected Overrides Function ProcessDialogKey( _ ByVal keyData As Keys) As Boolean '左キーが押されているか調べる If (keyData And Keys.KeyCode) = Keys.Left Then MessageBox.Show("左キーが押されました。") '左キーの本来の処理(左側のコントロールにフォーカスを移す)を 'させたくないときは、Trueを返す 'Return True End If Return MyBase.ProcessDialogKey(keyData) End Function End Class
using System; using System.Windows.Forms; public class ButtonEx : Button { [System.Security.Permissions.UIPermission( System.Security.Permissions.SecurityAction.Demand, Window = System.Security.Permissions.UIPermissionWindow.AllWindows)] protected override bool ProcessDialogKey(Keys keyData) { //左キーが押されているか調べる if ((keyData & Keys.KeyCode) == Keys.Left) { MessageBox.Show("左キーが押されました。"); //左キーの本来の処理(左側のコントロールにフォーカスを移す)を //させたくないときは、trueを返す //return true; } return base.ProcessDialogKey(keyData); } }
このクラスをSystem.Windows.Forms.Buttonクラスの代わりに使うようにします。
注意:新しく作成したクラスを、基のコントロールクラスの代わりに使用するという意味が分からないという方は、こちらをご覧ください。
(この記事は、「.NETプログラミング研究 第53号」で紹介したものを基にしています。)