向上,向下,向左和向右箭头键不会触发KeyDown事件


75

我正在构建一个应用程序,其中所有键输入必须由Windows本身处理。

我将tabstop设置为false,以使每个控制面板除面板外都能抓住焦点(但我不知道它是否有效果)。

我将KeyPreview设置为true,并且正在处理此表单上的KeyDown事件。

我的问题是,有时箭头键不再响应:

  • 当我仅按箭头键时,不会触发keydown事件。

  • 如果按下带有控制键的箭头键,将触发keydown事件。

您知道为什么我的箭头键突然停止触发事件吗?


您可以张贴KeyDown事件处理程序中的代码吗?
ChrisF


2
@ Maxim,我很确定如果窗口包含任何子控件,箭头键的按键事件将被抑制。您链接到的问题处理的表格没有控件。丹尼尔·沃尔特里普(Daniel Waltrip)的问题并不完全相同。
snarf

@Snarfblam我不确定我是否理解-为什么这会成为问题?
Maxim Zaslavsky

Answers:


61
    protected override bool IsInputKey(Keys keyData)
    {
        switch (keyData)
        {
            case Keys.Right:
            case Keys.Left:
            case Keys.Up:
            case Keys.Down:
                return true;
            case Keys.Shift | Keys.Right:
            case Keys.Shift | Keys.Left:
            case Keys.Shift | Keys.Up:
            case Keys.Shift | Keys.Down:
                return true;
        }
        return base.IsInputKey(keyData);
    }
    protected override void OnKeyDown(KeyEventArgs e)
    {
        base.OnKeyDown(e);
        switch (e.KeyCode)
        {
            case Keys.Left:
            case Keys.Right:
            case Keys.Up:
            case Keys.Down:
                if (e.Shift)
                {

                }
                else
                {
                }
                break;                
        }
    }

2
请注意,控件的所有制表位都应该为false。(我遇到这样的问题:D)
Iman

4
这实际上是一个hack。检查Rodolfo Neuber答案以获得正确答案。
Ghigo

76

我遇到了完全相同的问题。我考虑了@Snarfblam提供的答案;但是,如果您阅读了MSDN上的文档,则ProcessCMDKey方法将覆盖应用程序中菜单项的键事件。

最近,我偶然从Microsoft偶然发现了这篇文章,该文章看起来很有希望:http : //msdn.microsoft.com/en-us/library/system.windows.forms.control.previewkeydown.aspx。据微软称,做的最好的事情是设置e.IsInputKey=true;PreviewKeyDown检测方向键后事件。这样做会触发该KeyDown事件。

这对我来说效果很好,并且比覆盖ProcessCMDKey少了些hacker。


1
这应该是选择的答案,它更清洁并且效果很好。
AStackOverflowUser 2014年

是的,它有效!答案很明确,但我想指定IsInputKeye类中e.IsInputKey=true
T30 2014年

2
(如果您不检测箭头就对所有键进行操作,会发生什么情况?)
T30,2014年

@ T30您将失去菜单的Alt键
Google dev

18

我正在使用PreviewKeyDown

    private void _calendar_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e){
        switch (e.KeyCode){
            case Keys.Down:
            case Keys.Right:
                //action
                break;
            case Keys.Up:
            case Keys.Left:
                //action
                break;
        }
    }

2
为我工作出色,无需继承/覆盖
Paul Kapustin 2014年

1
这非常有效,谢谢。行为与我期望键事件的行为完全相同。
戴夫·库西诺

这应该是公认的答案!!!只需使用PreviewKeyDown事件。无需黑客即可使用。不能更干净或更简单。
Joe Gayetty

17

看到 Rodolfo Neuber的回复以获得最佳答案


(我的原始答案):

从控件类派生,您可以重写ProcessCmdKey方法。Microsoft选择从KeyDown事件中省略这些键,因为它们会影响多个控件并移动焦点,但是这使得使应用程序以任何其他方式对这些键做出反应非常困难。


似乎ProcessCmdKey是准确处理键盘的唯一方法。谢谢!
Martin Delille

4
这个答案是完全错误的。如果我还没有从已经处理过箭头键(以更改行为)的基本控件中覆盖OnKeyDown,那么我将不会知道这一点并很难实现它。请参阅下面的alpha答案。
2012年

1
就我的情况而言,甚至alpha的答案都行不通,但Snarfblam的答案却行不通。谢谢!
zionpi

2

不幸的是,由于KeyDown事件的限制,使用箭头键很难做到这一点。但是,有几种方法可以解决此问题:

  • 如@Snarfblam所述,您可以重写ProcessCmdKey方法,该方法保留解析箭头键按下的功能。
  • 作为此问题的公认答案,XNA具有一个名为Keyboard.GetState()的内置方法,该方法允许您使用箭头键输入。然而,的WinForms没有这一点,但它可以通过一个的P / Invoke来完成,或者通过使用一个类与它帮助

我建议尝试使用该类。这样做很简单:

var left = KeyboardInfo.GetKeyState(Keys.Left);
var right = KeyboardInfo.GetKeyState(Keys.Right);
var up = KeyboardInfo.GetKeyState(Keys.Up);
var down = KeyboardInfo.GetKeyState(Keys.Down);

if (left.IsPressed)
{
//do something...
}

//etc...

如果将此与KeyDown事件结合使用,我认为您可以可靠地实现目标。


2

从WinForms调用WPF窗口时,我遇到了类似的问题。

var wpfwindow = new ScreenBoardWPF.IzbiraProjekti();
    ElementHost.EnableModelessKeyboardInterop(wpfwindow);
    wpfwindow.Show();

但是,将window显示为对话框,它可以工作

var wpfwindow = new ScreenBoardWPF.IzbiraProjekti();
    ElementHost.EnableModelessKeyboardInterop(wpfwindow);
    wpfwindow.ShowDialog();

希望这可以帮助。


0

为了捕获Forms控件中的击键,必须派生一个新类,该类基于所需的控件类,并且您覆盖ProcessCmdKey()。

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    //handle your keys here
}

范例:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    //capture up arrow key
    if (keyData == Keys.Up )
    {
        MessageBox.Show("You pressed Up arrow key");
        return true;
    }

    return base.ProcessCmdKey(ref msg, keyData);
}

完整资料... C#中的箭头键

韦恩


0

我认为最好的方法是像MSDN上所说的那样处理它。 http://msdn.microsoft.com/en-us/library/system.windows.forms.control.previewkeydown.aspx上

但是处理它,您真正需要它的方式。我的方式(在下面的示例中)是捕获每个KeyDown ;-)

    /// <summary>
    /// onPreviewKeyDown
    /// </summary>
    /// <param name="e"></param>
    protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
    {
        e.IsInputKey = true;
    }

    /// <summary>
    /// onKeyDown
    /// </summary>
    /// <param name="e"></param>
    protected override void OnKeyDown(KeyEventArgs e)
    {
        Input.SetFlag(e.KeyCode);
        e.Handled = true;
    }

    /// <summary>
    /// onKeyUp
    /// </summary>
    /// <param name="e"></param>
    protected override void OnKeyUp(KeyEventArgs e)
    {
        Input.RemoveFlag(e.KeyCode);
        e.Handled = true;
    }


0
protected override bool IsInputKey(Keys keyData)
{
    if (((keyData & Keys.Up) == Keys.Up)
        || ((keyData & Keys.Down) == Keys.Down)
        || ((keyData & Keys.Left) == Keys.Left)
        || ((keyData & Keys.Right) == Keys.Right))
        return true;
    else
        return base.IsInputKey(keyData);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.