如何通过键盘或鼠标单击来区分是否引发了Enter事件?

时间:2018-04-08 21:27:58

标签: c# winforms events focus

有没有办法区分控件上的Enter事件是通过键盘(Tab,Shift + Tab)还是通过直接鼠标点击引发的?

我只有在用户使用Tab移动到控件时才需要执行操作,但是当用户直接单击控件时则不需要。我试图直接拦截鼠标点击,但似乎在Enter之前引发Click事件。

3 个答案:

答案 0 :(得分:2)

您可以使用WM_MOUSEACTIVATE message来检测用鼠标激活控件,而不是跟踪Tab键。您可以对您使用的每种控件类型进行子类化,并覆盖WndProc方法或使用如下所示的NativeWindow侦听器类。根据您使用的控件类型,只需对这些控件进行子类化以提供指示使用鼠标选择控件的属性,可能会减少工作量和混乱。这是你的决定,但模式将是相同的。

此代码稍微修改了MS文档中显示的示例。

public class MouseActivateListener : NativeWindow
{
    private Control parent;

    public MouseActivateListener(Control parent)
    {
        parent.HandleCreated += this.OnHandleCreated;
        parent.HandleDestroyed += this.OnHandleDestroyed;
        parent.Leave += Parent_Leave;
        this.parent = parent;
        if (parent.IsHandleCreated)
        {
            AssignHandle(parent.Handle);
        }
    }

    private void Parent_Leave(object sender, EventArgs e)
    {
        MouseActivated = false;
    }

    private void OnHandleCreated(object sender, EventArgs e)
    {
        AssignHandle(((Form)sender).Handle);
    }

    private void OnHandleDestroyed(object sender, EventArgs e)
    {
        ReleaseHandle();
    }

    public bool MouseActivated { get; set; }


    [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
    protected override void WndProc(ref Message m)
    {
        const Int32 WM_MouseActivate = 0x21;

        base.WndProc(ref m);

        if (m.Msg == WM_MouseActivate && m.Result.ToInt32() < 3)
        {
            MouseActivated = true;
        }
    }
}

示例用法:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private MouseActivateListener textBox1Listener;
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        textBox1Listener = new MouseActivateListener(textBox1);
    }

    private void textBox1_Enter(object sender, EventArgs e)
    {
        if (textBox1Listener.MouseActivated)
        {
            MessageBox.Show("Mouse Enter");
        }
        else
        {
            MessageBox.Show("Tab Enter");
        }
    }
}

答案 1 :(得分:0)

您可以使用Form.KeyPreview事件并将最后一次按键存储在变量中。然后在您的控件的Enter事件中,检查最后按下的键的值。如果这是一个标签,请执行以下操作:

private Keys lastKeyCode;
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    this.lastKeyCode = e.KeyCode;
}

然后在Enter事件中,检查它:

if (lastKeyCode == Keys.Tab)
{
    // Whatever...
}

答案 2 :(得分:0)

直接使用邮件过滤器拦截WM_KEYUPWM_KEYDOWN,以检索Tab键的状态。对于这样一个看似简单的任务来说,这似乎是过分的,但显然Tab键是从大多数Windows窗体事件中被禁止的。

很乐意采取更清晰的答案,但就目前而言,就是这样:

class TabMessageFilter : IMessageFilter
{
    public bool TabState { get; set; }

    public bool PreFilterMessage(ref Message m)
    {
        const int WM_KEYUP = 0x101;
        const int WM_KEYDOWN = 0x100;

        switch (m.Msg)
        {
            case WM_KEYDOWN:
                if ((Keys)m.WParam == Keys.Tab) TabState = true;
                break;
            case WM_KEYUP:
                if ((Keys)m.WParam == Keys.Tab) TabState = false;
                break;
        }

        return false;
    }
}

class MainForm : Form
{
    TabMessageFilter tabFilter;

    public MainForm()
    {
         tabFilter = new TabMessageFilter();
         Application.AddMessageFilter(tabFilter);
    }

    protected override void OnFormClosed(FormClosedEventArgs e)
    {
         Application.RemoveMessageFilter(tabFilter);
         base.OnFormClosed(e);
    }

    void control_Enter(object sender, EventArgs e)
    {
         if (tabFilter.TabState) // do something
         else // do domething else
    }
}