如何检测当前按下的键?

时间:2009-07-08 20:09:10

标签: c# .net winforms keyboard

Windows Forms中,您可以随时了解光标的当前位置,这要归功于Cursors类。

同样的东西似乎不适用于键盘。是否可以知道,例如, Shift 键是否被按下了?

是否绝对需要跟踪每个键盘通知(KeyDown和KeyUp事件)?

12 个答案:

答案 0 :(得分:160)

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

如果 Ctrl + Shift 已关闭,也会出现这种情况。如果要检查是否按下了Shift,

if (Control.ModifierKeys == Keys.Shift)

如果您在继承Control的班级(例如表单)中,则可以删除Control.

答案 1 :(得分:54)

下面的代码是如何检测几乎所有当前按下的键,而不仅仅是 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;
    }
}

答案 2 :(得分:23)

如果引用System.Windows.Input

,也可以查看以下内容
if (Keyboard.Modifiers == ModifierKeys.Shift)

Keyboard命名空间也可用于通过Keyboard.IsKeyDown(Key)检查其他键的按下状态,或者如果您订阅了KeyDownEvent或类似事件,则事件参数会带有当前按下的键列表。 / p>

答案 3 :(得分:17)

这些答案中的大多数要么太复杂,要么似乎对我不起作用(例如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);
    }
  }
}

答案 4 :(得分:10)

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

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

即使它是WPF的一部分,该方法适用于WinForm应用程序(前提是您添加对 PresentationCore.dll WindowsBase.dll 的引用)。不幸的是,Keyboard.IsKeyDown方法的3.0和3.5版本对WinForm应用程序不起作用。因此,如果您确实希望在WinForm应用程序中使用它,则需要将.NET Framework 4.0或更高版本作为目标才能使用它。

答案 5 :(得分:8)

您可以P/Invoke向下到Win32 GetAsyncKeyState来测试键盘上的任何键。

您可以将Keys enum(例如Keys.Shift)中的值传递给此函数,因此只需要几行代码即可添加它。

答案 6 :(得分:5)

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

答案 7 :(得分:3)

我发现在Windows窗体表单上管理键盘输入的最佳方法是在击键后和聚焦控件接收事件之前处理它。 Microsoft维护一个名为 .KeyPreview 的内置Form级属性,以实现这一目标:

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

然后可以封送表单的_KeyDown,_KeyPress和/或_KeyUp事件以在聚焦表单控件看到它们之前访问输入事件,并且您可以应用处理程序逻辑来捕获那里的事件或允许它传递给集中形式控制。

虽然不像XAML's事件路由体系结构那样结构优雅,但它使Winforms中的表单级函数管理变得更加简单。有关警告,请参阅MSDN notes on KeyPreview

答案 8 :(得分:2)

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

光标x / y位置是属性,按键(如鼠标单击/鼠标移动)是一个事件。最佳做法通常是让界面成为事件驱动。大约只有你需要上述的时间就是你要做一个shift + mouseclick事情。

答案 9 :(得分:2)

if (Form.ModifierKeys == Keys.Shift)
如果上面的代码在表单的keydown事件中,并且没有其他控件捕获密钥的keydown事件,则

对文本框有用。

还可以通过以下方式停止进一步的密钥处理:

e.Handled = true;

答案 10 :(得分:0)

在WinForms中:

if( Form.ModifierKeys == Keys.Shift )

这听起来像Stack Overflow问题 Detect Shift key is pressed without using events in Windows Forms? 的重复。

答案 11 :(得分:0)

如果您需要监听任何通用类中的键,当“表单”窗口按下时,这是您的代码。它不监听全局窗口键事件,因此当窗口不活动时它不能用于查看键。

Form.cs

public partial class Form1 : Form
{
    public Form1()
    {
        // Some other Code
        // Register all Keys pressed
        this.KeyPreview = true;
        KeyHandler.Instance.Init();
        this.KeyDown += Form1_KeyDown;
        this.KeyUp += Form1_KeyUp;
        // Some other Code in the constructor
    }

    private void Form1_KeyUp(object sender, KeyEventArgs e)
    {
        // Fire event when a key is released
        KeyHandler.Instance.FireKeyUp(sender, e);
    }

    private void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        // Fire event when a key is pressed
        KeyHandler.Instance.FireKeyDown(sender, e);
    }
}

KeyHandler.cs KeyHandler 是一个单例类,可以通过 Handler.Instance 在任何其他对象中访问......很简单。

public class KeyHandler
{
    #region Singleton
    private static KeyHandler instance;
    private KeyHandler()
    {
        currentlyPressedKeys = new List<Keys>();
    }

    public static KeyHandler Instance
    {
        get
        {
            if (instance is null)
            {
                instance = new KeyHandler();
            }
            return instance;
        }
    }
    #endregion Singleton

    private List<Keys> currentlyPressedKeys;
    public List<Keys> GetCurrentlyPressedKeys { get { return currentlyPressedKeys; } }

    public void FireKeyDown(object sender, KeyEventArgs e)
    {
        if (!currentlyPressedKeys.Contains(e.KeyCode))
        {
            currentlyPressedKeys.Add(e.KeyCode);
            KeyEventKeyPressed(sender, e);
        }
    }

    public void FireKeyUp(object sender, KeyEventArgs e)
    {
        currentlyPressedKeys.Remove(e.KeyCode);
        KeyEventKeyReleased(sender, e);
    }

    public event EventHandler<KeyEventArgs> KeyPressed;
    protected virtual void KeyEventKeyPressed(object sender, KeyEventArgs e)
    {
        EventHandler<KeyEventArgs> handler = KeyPressed;
        handler?.Invoke(sender, e);
    }

    public event EventHandler<KeyEventArgs> KeyReleased;
    protected virtual void KeyEventKeyReleased(object sender, KeyEventArgs e)
    {
        EventHandler<KeyEventArgs> handler = KeyReleased;
        handler?.Invoke(sender, e);
    }

    public void Init()
    {
        // Nothing to initialize yet
    }
}

// 在任何其他类/对象中,现在可以接收在“表单”处于活动状态时触发的 KeyEvent。因此可以监听任何 Control 对象或其他任何对象中的关键事件。可以查看是否例如按下多个键,如 Shift+Ctrl+Q 或类似的东西。

public class SomeClass
{
    public SomeClass()
    {
        KeyHandler.instance.KeyPressed += Instance_KeyPressed
        KeyHandler.Instance.KeyReleased += Instance_KeyReleased;
    }

    public void SomeMethod()
    {
        if (KeyHandler.Instance.GetCurrentlyPressedKeys.Contains(Keys.ShiftKey))
        {
            // Do Stuff when the method has a key (e.g. Shift/Control...) pressed
        }
    }

    private void Instance_KeyPressed(object sender, KeyEventArgs e)
    {
        // Any Key was pressed, do Stuff then
    }

    private void Instance_KeyReleased(object sender, KeyEventArgs e)
    {
        // Do Stuff when a Key was Released
    }
}