如何检测当前按下的键?


Answers:


162
if ((Control.ModifierKeys & Keys.Shift) != 0) 

如果Ctrl+ Shift向下,这也将成立。如果要检查是否仅按下Shift键,

if (Control.ModifierKeys == Keys.Shift)

如果您使用的是继承的类Control(例如表单),则可以删除Control.


8
除非我缺少任何东西,否则您将无法正确回答问题。OP正在询问所有键,并且仅使用Shift键作为示例。那么,您如何检测其他键,例如A到Z,0到9等?
Ash

2
考虑到他接受了答案,看来他只需要修饰键。如果需要其他键,则需要调用GetKeyStateAPI函数。
SLaks

2
不需要GetKeyState。您只需要添加一个消息过滤器。看我的答案。
Ash Ash

2
对于WPF解决方案,您可以使用Keyboard.Modifiers == ModifierKeys.Shift (对于那些在此处进行搜索的解决方案
Bill Tarbell,

3
而不是(Control.ModifierKeys & Keys.Shift) != 0一个人可以使用Control.ModifierKeys.HasFlag(Keys.Shift)
tomuxmon

55

下面的代码是如何检测几乎所有当前按下的键,而不仅仅是Shift键。

private KeyMessageFilter m_filter = new KeyMessageFilter();

private void Form1_Load(object sender, EventArgs e)
{
    Application.AddMessageFilter(m_filter);
}


public class KeyMessageFilter : IMessageFilter
{
    private const int WM_KEYDOWN = 0x0100;
    private const int WM_KEYUP = 0x0101;
    private bool m_keyPressed = false;

    private Dictionary<Keys, bool> m_keyTable = new Dictionary<Keys, bool>();

    public Dictionary<Keys, bool> KeyTable
    {
        get { return m_keyTable; }
        private set { m_keyTable = value; }
    }

    public bool IsKeyPressed()
    {
        return m_keyPressed;
    }

    public bool IsKeyPressed(Keys k)
    {
        bool pressed = false;

        if (KeyTable.TryGetValue(k, out pressed))
        {
            return pressed;
        }

        return false;
    }

    public bool PreFilterMessage(ref Message m)
    {
        if (m.Msg == WM_KEYDOWN)
        {
            KeyTable[(Keys)m.WParam] = true;

            m_keyPressed = true;
        }

        if (m.Msg == WM_KEYUP)
        {
            KeyTable[(Keys)m.WParam] = false;

            m_keyPressed = false;
        }

        return false;
    }
}

1
GetKeyState会更有效率。Windows已经为您完成所有键的跟踪时,没有任何意义。
SLaks 2010年

3
@Slaks,除非有一些基准数据,否则就在猜测。此外,如果您可以首先捕获该键盘事件, GetKeyState会告诉您键的状态。我的问题的解读是,在OP想知道如何在一键搞定的状态的任何时间。因此,GetKeyState本身是没有用的。
灰烬

3
您将如何精确地利用它来显示按下的键?
加布里埃尔·瑞安·纳米亚斯

Gabriel:在您的表单中创建一个KeyMessageFilter实例作为字段。将其传递给Form_Load中的Application.AddMessageFilter()。然后在这种情况下调用IsKeyPressed()每个/任一键,你是感兴趣的

@Ash谢谢您的回答-您能否编写一个代码示例来检查上面的SHIFT键等?
BKSpurgeon '18

23

如果引用System.Windows.Input,也可以查看以下内容

if (Keyboard.Modifiers == ModifierKeys.Shift)

Keyboard命名空间还可以用于通过Keyboard.IsKeyDown(Key)检查其他键的按下状态,或者,如果您正在订阅KeyDownEvent或类似事件,则事件参数将携带当前按下的键的列表。


1
实际上,Keyboard.Modifiers并不总是正常工作。必须找到硬盘的方式:discoveringdotnet.alexeyev.org/2008/09/...
马克西姆阿列克谢耶夫

除了不使用Forms修饰符外,System.Windows.Input修饰符是一个不同的命名空间,并且每次都对我们有效。
杰夫·韦恩

18

这些答案大多数要么太复杂,要么对我似乎不起作用(例如System.Windows.Input似乎不存在)。然后我发现了一些可以正常工作的示例代码:http : //www.switchonthecode.com/tutorials/winforms-accessing-mouse-and-keyboard-state

万一将来页面消失,我将在下面发布相关的源代码:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace MouseKeyboardStateTest
{
  public abstract class Keyboard
  {
    [Flags]
    private enum KeyStates
    {
      None = 0,
      Down = 1,
      Toggled = 2
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
    private static extern short GetKeyState(int keyCode);

    private static KeyStates GetKeyState(Keys key)
    {
      KeyStates state = KeyStates.None;

      short retVal = GetKeyState((int)key);

      //If the high-order bit is 1, the key is down
      //otherwise, it is up.
      if ((retVal & 0x8000) == 0x8000)
        state |= KeyStates.Down;

      //If the low-order bit is 1, the key is toggled.
      if ((retVal & 1) == 1)
        state |= KeyStates.Toggled;

      return state;
    }

    public static bool IsKeyDown(Keys key)
    { 
      return KeyStates.Down == (GetKeyState(key) & KeyStates.Down);
    }

    public static bool IsKeyToggled(Keys key)
    { 
      return KeyStates.Toggled == (GetKeyState(key) & KeyStates.Toggled);
    }
  }
}

3
System.Windows.Input存在 对于其他为此苦苦挣扎的人,您需要添加对的引用PresentationCore,以及对WindowsBase进行System.Windows.Input.Key枚举的附加引用。始终可以在MSDN上找到此信息。
阿尔菲,2014年

1
本课程应该是static,不是abstract
Little Endian

1
链接断开(404)。
彼得·莫滕森

2
“以防将来该页面消失,我将在下面发布相关的源代码”
parsley72

12

从.NET Framework 3.0版开始,可以使用Keyboard.IsKeyDownSystem.Windows.Input名称空间中的方法。例如:

if (((Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) && Keyboard.IsKeyDown(Key.F))
{
    // CTRL + F is currently pressed
}

即使它是WPF的一部分,该方法也适用于WinForm应用程序(前提是您添加了对PresentationCore.dllWindowsBase.dll的引用)。但是,不幸的是,该Keyboard.IsKeyDown方法的3.0和3.5版本不适用于WinForm应用程序。因此,如果您确实想在WinForm应用程序中使用它,则需要以.NET Framework 4.0或更高版本为目标才能使其正常运行。


请注意,这仅适用于WPF
Diego Vieira

2
@DiegoVieira实际上,那不是真的。该功能是作为WPF的一部分添加的,它要求引用那些WPF库,但是该Keyboard.IsKeyDown方法即使在WinForm项目中也有效。
Steven Doggart

实际上,您必须添加PresentationCore.dll
Diego Vieira

2
请注意,如果以.Net 3.5或更早版本(仅4.0+)为目标,则这将不起作用(在WinForms中),原因是Win32KeyboardDevice.GetKeyStatesFromSystem(Key)的实现发生了变化:(
LMK

@LMK不错的收获。我自己进行了测试,并验证了您的讲话。我更新了答案以反映该信息。谢谢!
史蒂文·多格加特2014年


5
if ((ModifierKeys == Keys.Control) && ((e.KeyChar & (char)Keys.F) != 0))
{
     // CTRL+F pressed !
}

3

我发现在Windows Forms窗体上管理键盘输入的最佳方法是在击键之后且焦点控件接收到该事件之前对其进行处理。Microsoft维护一个Form名为.KeyPreview的内置级别的属性,以简化此操作:

public frmForm()
{
    // ...
    frmForm.KeyPreview = true;
    // ...
}

然后,可以将表单的_KeyDown,_KeyPress和/或_KeyUp事件编组为访问输入事件,以使焦点表单控件看不到它们,并且您可以应用处理程序逻辑以在那里捕获事件,或允许事件传递给焦点表单控件。

尽管在结构上不如XAML的事件路由体系结构优美,但它使Winforms中的表单级功能的管理更加简单。请注意有关KeyPreviewMSDN注释


2
if (Form.ModifierKeys == Keys.Shift)

如果上面的代码在窗体的keydown事件中,并且没有其他控件捕获该keydown的keydown事件,则它确实适用于文本框。

也可能希望通过以下方法停止进一步的密钥处理:

e.Handled = true;

2
if (Control.ModifierKeys == Keys.Shift)
    //Shift is pressed

光标的x / y位置是一个属性,而按键(如鼠标单击/移动)是一个事件。最佳实践通常是让接口受事件驱动。大约只有在您需要执行上述操作时,才可以尝试执行shift +鼠标单击操作。


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.