DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

コントロールで矢印、Tab、Enter、Escキーが押されたことを知る

コントロールによっては、矢印、Tab、Enter、Escキーなどが押されてもKeyDown、KeyUpなどのキーイベントが発生しません。例えば、ボタンコントロールでは、矢印キーの押下を捕捉できません。ここではボタンコントロールを例にして、これらのキーが押されたことを知るための方法を紹介します。

.NET Framework 2.0以降で、PreviewKeyDownイベントを使用する方法

.NET Framework 2.0からはPreviewKeyDownイベントが追加され、これを使えば簡単です。

PreviewKeyDownイベントはKeyDownイベントの前に発生します。KeyDownやKeyUpイベントが発生しないようなキーが押された場合も発生し、押されたキーを知ることができます。

さらに、KeyDownやKeyUpイベントが発生しないようなキーが押された場合でも、PreviewKeyDownイベントハンドラでPreviewKeyDownEventArgs.IsInputKeyプロパティをTrueにすることにより、KeyDownやKeyUpイベントが発生するようになります。ただしこの場合は、そのキー本来の機能(例えば、矢印キーであれば、フォーカスの移動)は失われます。

以下の例では、ボタン(Button1)で矢印キーが押された時にそのことを表示し、また、Tabキーが押された時に本来の機能であるフォーカスの移動を無効にして、KeyDown、KeyUpイベントが発生するようにしています。

VB.NET
コードを隠すコードを選択
'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
C#
コードを隠すコードを選択
//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;
    }
}

IsInputKeyをオーバーライドする方法

ButtonクラスのIsInputKeyメソッドをオーバーライドしてtrueを返すようにすることにより、矢印キーを押した場合でもKeyDownやKeyUpイベントが発生するようになります。ただし、矢印キーが押されたときの本来の機能(フォーカスの移動)は無くなります。

まず次のようなButtonクラスの派生クラスを作成し、IsInputKeyメソッドをオーバーライドします。ここで、矢印キーが押された時に、trueを返すようにします。ここでは、Altキーが同時に押されている場合は、矢印キー本来の機能が行われるようにしています。

VB.NET
コードを隠すコードを選択
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
C#
コードを隠すコードを選択
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クラスの代わりに使うようにします。

注意:新しく作成したクラスを、基のコントロールクラスの代わりに使用するという意味が分からないという方は、こちらをご覧ください。

ProcessDialogKeyをオーバーライドする方法

ButtonクラスのProcessDialogKeyメソッド(あるいはProcessCmdKeyなど)をオーバーライドして、矢印キーが押されたことを知ることもできます。

先ほどと同じように、Buttonクラスの派生クラスを作成し、ProcessDialogKeyメソッドをオーバーライドします。ここでは、左キーが押された時に、メッセージボックスを表示するようにしています。

VB.NET
コードを隠すコードを選択
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
C#
コードを隠すコードを選択
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クラスの代わりに使うようにします。

注意:新しく作成したクラスを、基のコントロールクラスの代わりに使用するという意味が分からないという方は、こちらをご覧ください。
  • 履歴:
  • 2007/4/20 PreviewKeyDownイベントを使用する方法を追加。
  • 2010/6/30 ProcessDialogKeyにUIPermissionAttributeを付けた。
  • 2013/12/9 SecurityAction.LinkDemandの代わりにSecurityAction.Demandを使うようにした。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • イベントハンドラの意味が分からない、C#のコードをそのまま書いても動かないという方は、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。