如何检测当前按下的键?

Windows 窗体中,由于 光标类,您可以随时知道光标的当前位置。

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

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

271355 次浏览

使用 WinForms:

if( Form.ModifierKeys == Keys.Shift )

听起来像是堆栈溢出问题 在 Windows 窗体中不使用事件按下 Detect Shift 键的复制品。

您可以 请求到 Win32GetAsyncKeyState来测试键盘上的任何键。

您可以从 Keys 枚举传入值(例如,Keys。Shift)添加到这个函数中,因此只需要几行代码就可以添加它。

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

if (Keyboard.Modifiers == ModifierKeys.Shift)

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

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

如果 Ctrl + Shift向下,这也是正确的。如果你想检查是否只按 Shift 键,

if (Control.ModifierKeys == Keys.Shift)

如果您所在的类继承了 Control(例如表单) ,则可以删除 Control.

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

光标 x/y 位置是一个属性,而按键(如鼠标单击/鼠标移动)是一个事件。最佳实践通常是让接口由事件驱动。大概你唯一需要以上的时间是如果你正在尝试做一个移动 + 鼠标清除的事情。

下面的代码是如何检测几乎所有当前按下的键,而不仅仅是 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;
}
}
if (Form.ModifierKeys == Keys.Shift)

如果上面的代码位于表单的 keydown 事件中,并且没有其他控件捕获 key down 事件,那么对于文本框就可以工作。

此外,不妨用以下方法停止进一步的密码匙处理:

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

我发现在 Windows 窗体上管理键盘输入的最佳方法是在击键之后和集中控件接收事件之前进行处理。微软维护了一个名为 。关键预览的内置 Form级别属性,以方便实现这个精确的功能:

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

然后,可以将窗体的 _ KeyDown、 _ KeyPress 和/或 _ KeyUp 事件进行编组,以便在集中的窗体控件看到它们之前访问输入事件,并且可以应用处理程序逻辑来捕获那里的事件,或允许它传递到集中的窗体控件。

尽管在结构上不如 XAML 的事件路由架构那样优美,但它使 Winforms 表单级功能的管理变得简单得多。请参阅 关于 KeyPreview 的 MSDN 说明了解注意事项。

这些答案大部分要么太复杂,要么似乎对我不起作用(例如:。窗户。输入似乎不存在)。然后我找到了一些工作正常的示例代码: 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);
}
}
}

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

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或更高版本,以便其工作。

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

表格

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
}
}

//在任何其他 Class/Object 中,现在都可以接收在“ Form”激活时触发的 KeyEvents。因此,可以监听任何 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
}
}