【问题标题】:Detect if any key is pressed in C# (not A, B, but any)检测是否在 C# 中按下了任何键(不是 A、B,而是任何键)
【发布时间】:2010-12-17 16:08:47
【问题描述】:

[编辑 3] 我通过使用“奇怪”版本来“解决它”。至少对于最重要的键。这对于我的情况就足够了,我想检查 ALT 和 ALT+A 是否不同(从而确保没有按下 A)。不完美,但对于这样一个小问题已经有很多时间了。无论如何,感谢所有答案... [编辑 3]

[EDIT 4] 多亏了 280Z28 [/EDIT 4]

我知道如何检查修饰键以及如何测试单个键。 问题是,我想检查是否按下了任何键。以下方法似乎“奇怪”:-)

用 C# 编写的 WPF 应用程序

if (Keyboard.IsKeyDown(Key.A)) return true;
if (Keyboard.IsKeyDown(Key.B)) return true;
if (Keyboard.IsKeyDown(Key.C)) return true;

我知道它是一个枚举,所以我想到了一个循环,但是要使用的“最大数字”是多少。这可能吗?顺便说一句,这是一个非常特殊的情况,通常我会使用一个事件,但在这种情况下我必须这样做。不幸的是,没有“列表”Keyboard.CurrentlyDownKeys。至少我没看到。

谢谢, 克里斯

编辑:好的,因为这似乎是一个更大的交易,这里的原因是: 我已经定义了一个“KeySet”,它作为自定义函数的 DictionaryKey。如果有人点击一个元素,包装器会遍历字典并检查是否有任何预定义的“键集”处于活动状态。

这允许我定义简单的触发器,例如如果按下 ALT+A+B,则运行此函数。另一种选择是例如如果按下了 ALT+STRG+A(在鼠标单击 WPF 元素期间),则运行此函数。

当前实现的唯一“问题”是,如果我定义了一个不包含任何 REAL 键的键集,例如按下 ALT 时运行,如果按下 ALT+A 也会触发它。哦,写这个的时候,我意识到还有一个问题。如果按下 ALT+A+B+C,ALT+A+B 当前也会触发。

也许我的方法是错误的,我应该创建一个“静态密钥跟踪器”并将密钥集与其值(通过事件获取)进行比较。我会尝试一下。

编辑 2 这是行不通的,至少不是以简单的方式。我需要一个 FrameworkElement 来附加到 KeyDown,但我在静态构造函数中没有它。而且我对某个元素的 KeyDownEvents 不感兴趣,但是“全局”...我想我只是推迟了这个问题,它并不那么重要。不过,如果有人知道更好的不同方法......

这么久了,对于任何关心的人,这里有一些代码:

public class KeyModifierSet
{
    internal readonly HashSet<Key> Keys = new HashSet<Key>();
    internal readonly HashSet<ModifierKeys> MKeys = new HashSet<ModifierKeys>();

    public override int GetHashCode()
    {
        int hash = Keys.Count + MKeys.Count;
        foreach (var t in Keys)
        {
            hash *= 17;
            hash = hash + t.GetHashCode();
        }
        foreach (var t in MKeys)
        {
            hash *= 19;
            hash = hash + t.GetHashCode();
        }
        return hash;
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as KeyModifierSet);
    }

    public bool Equals(KeyModifierSet other)
    {
        // Check for null
        if (ReferenceEquals(other, null))
            return false;

        // Check for same reference
        if (ReferenceEquals(this, other))
            return true;

        // Check for same Id and same Values
        return Keys.SetEquals(other.Keys) && MKeys.SetEquals(other.MKeys);
    }

    public bool IsActive()
    {
        foreach (var k in Keys)
            if (Keyboard.IsKeyUp(k)) return false;
        
        if ((Keys.Count == 0) && !Keyboard.IsKeyDown(Key.None)) return false;


        foreach (var k in MKeys)
            if ((Keyboard.Modifiers & k) == 0) return false;

        if ((MKeys.Count == 0) && Keyboard.Modifiers > 0) return false;

        return true;
    }


    public KeyModifierSet(ModifierKeys mKey)
    {
        MKeys.Add(mKey);
    }

    public KeyModifierSet()
    {

    }

    public KeyModifierSet(Key key)
    {
        Keys.Add(key);
    }

    public KeyModifierSet(Key key, ModifierKeys mKey)
    {
        Keys.Add(key);
        MKeys.Add(mKey);
    }

    public KeyModifierSet Add(Key key)
    {
        Keys.Add(key);
        return this;
    }

    public KeyModifierSet Add(ModifierKeys key)
    {
        MKeys.Add(key);
        return this;
    }
}

【问题讨论】:

  • 你的申请是什么?安慰? Windows 窗体? WPF?网站?
  • 看到这个问题:Capture KeyDown Event in WPF
  • 是的,这使我的“静态密钥跟踪器”方法不太可行。至少对于像“在鼠标点击时跟踪键集”这样的“简单”事情来说,它似乎过于复杂。请参阅帖子中的edit2。
  • 在 Post,WPF 应用程序中更正了它。抱歉,没有想到 winforms 和 WPF 之间的巨大差异。出于这个原因,我想避免使用事件(似乎冒泡、吃事件等过于复杂...... - 我知道它是如何完成的,但仍然......只想知道是否按下了任何字符键:-(
  • 整个问题的所有不同编辑(按 3、4、1、2 的顺序)使得阅读它比应有的困难得多..

标签: c# wpf input keyboard key


【解决方案1】:

这段代码是从哪里运行的?它在事件处理程序中吗?许多窗体和控件将触发 KeyPress 事件以及 KeyDown 事件。您可能希望查看这些事件并在其中一个发生时将您的标志设置为 true。您还必须侦听告诉您何时释放键的相应事件(我认为也是 KeyUp)。

【讨论】:

    【解决方案2】:

    如果您使用Windows.Forms,请使用KeyDown 事件并使用适当的KeyEventArgs 读出特定键。您可以访问 KeyEventArgs 变量上的 KeyCode 属性。

    要检查范围,比如在 A 和 Z 之间:

    if (e.KeyCode>=Keys.A && e.KeyCode<=Keys.Z)
    {
      // do stuff...or not
    }

    【讨论】:

      【解决方案3】:
      normally I would use an event
      

      如果您在 Windows 上编程,您应该仍然使用事件,最好是 KeyDown,因为您不介意按下什么键。如果没有,您可以使用类似 Console.ReadLine();.

      编辑:如果您正在寻找类似

      if (Keyboard.IsKeyDown(Key.AnyKey)) return true;
      

      那你一定是在开玩笑……

      编辑 2: 好吧,您的记录器的方法很有趣,但我认为您正在重新发明轮子。所有编程语言都提供了一些方法来处理按下的键,当这可以知道时。在 C# for Windows 中,这是使用事件完成的。此外,我认为您将无法在 .NET 中自己处理此类事情,因为您需要从 Win32 API 访问一些系统函数,而 AFAIK 不允许您这样做(至少很容易。 ..) 在托管代码中。一些解决方案是创建一个 HOOK 并将消息从那里发送到您的应用程序,但我不知道如何在 C# 中执行此操作。这是德尔福的方式,我有更多的经验。

      【讨论】:

      • 不是在开玩笑:-) 但显然思路错误。但我觉得这并不牵强。我的意思是为什么不,如果我想知道是否按下了任何键,可能会有一些情况。编辑条目,将尝试可用于检查的静态“记录器”...
      • 您可以使用 WinForms 或 WPF 中的 KeyUp 和 KeyDown 事件“发明”这种类型的键状态——按下键时将按下的键的值添加到列表中,按下键时将其删除—— - 您可以随时检查列表是否包含您要查找的值,并且您会知道该键是否被按下。
      【解决方案4】:

      http://sourceforge.net/projects/keystate/ 显示“特殊”键。否则,我认为您将不得不监视它们。听起来您想在整个系统范围内执行此操作?你想完成什么?

      【讨论】:

        【解决方案5】:

        您可以为每个 keydown 事件增加一个计数器,并为每个 keyup 事件减少它。当计数器为零时,没有按键按下。

        【讨论】:

        • 不可能,KeyDown 事件被一些 WPF 元素吃掉了,按下 A 时我什至可能不在我的应用程序中。然后我按住它,单击我的应用程序,它不会检查 A被按下...
        • 你在看房子。一个人进去。一个人出去。一个人进去。一个人出去。一个人出去。对于这一系列观察,您从逻辑上得出什么结论? (1) 屋子里有 -1 个人,或者 (2) 在我开始观看之前屋子里有人?
        • @Eric:我想说如果现在有人进去,房子就会空无一人。
        【解决方案6】:
        [DllImport("user32.dll", EntryPoint = "GetKeyboardState", SetLastError = true)]
        private static extern bool NativeGetKeyboardState([Out] byte[] keyStates);
        
        private static bool GetKeyboardState(byte[] keyStates)
        {
            if (keyStates == null)
                throw new ArgumentNullException("keyState");
            if (keyStates.Length != 256)
                throw new ArgumentException("The buffer must be 256 bytes long.", "keyState");
            return NativeGetKeyboardState(keyStates);
        }
        
        private static byte[] GetKeyboardState()
        {
            byte[] keyStates = new byte[256];
            if (!GetKeyboardState(keyStates))
                throw new Win32Exception(Marshal.GetLastWin32Error());
            return keyStates;
        }
        
        private static bool AnyKeyPressed()
        {
            byte[] keyState = GetKeyboardState();
            // skip the mouse buttons
            return keyState.Skip(8).Any(state => (state & 0x80) != 0);
        }
        

        【讨论】:

        • 感谢您的努力,但我收到“EntryPointNotFound”异常。可能是由于windows 7的限制,内核不同,不知道。此外,低级(即使这是唯一的方法)......
        • @Christian:请注意,我最初指定了错误的导入 - 我输入了 kernel32,但它应该是 user32。
        • @Christian:另外,我在AnyKeyPressed 中添加了一个Skip(8),所以它不会因为按下鼠标按钮而返回true。
        • 好的,很好,它有效!还有一个问题,我如何“过滤”CTRL、ALT、Windows 和 SHIFT。因为它们不应该算作键,所以我使用 ModifierKeys 处理它们(设计问题,否则需要进行大量更改)。这可能吗?无论如何都非常感谢..
        • @Christian:您可以检查除要忽略的字节之外的所有字节。如果您忽略了修饰符,您是否也忽略了 VK_NUMLOCK 等(这会检查 down,而不是切换,但是如果 numlock 键实际上是 down 怎么办) ?虚拟键码参考:msdn.microsoft.com/en-us/library/ms927178.aspx
        【解决方案7】:

        使用 XNA 框架,您可以使用 thw follow 来检查是否按下了任何键。

        Keyboard.GetState().GetPressedKeys().Length > 0
        

        【讨论】:

        • 为什么任何用户都想使用 XNA 框架来检测他们的按键? XNA 是一个用于视频游戏开发的胖客户端
        • 也许是因为 OP 试图做的事情通常只在电子游戏中完成......
        【解决方案8】:

        这是一个很老的问题,但如果有人遇到这个问题并且不想使用外部 dll,您可以枚举可能的键并遍历它们。

        bool IsAnyKeyPressed()
        {
            var allPossibleKeys = Enum.GetValues(typeof(Key));
            bool results = false;
            foreach (var currentKey in allPossibleKeys)
            {
                Key key = (Key)currentKey;
                if (key != Key.None)
                    if (Keyboard.IsKeyDown((Key)currentKey)) { results = true; break; }
            }
            return results;
        }
        

        您可以通过在函数之外执行枚举并保留列表以供以后使用来优化这一点。

        【讨论】:

          【解决方案9】:

          在 Key Enumeration 中有一个 Enumeration 值为 Zero(0),它基本上测试“No Key Pressed”,这与“Any key Pressed”相反。所以,这样的事情可能会奏效;

          If !GetKeyState(0)==True then
              Do Something
          End If
          

          或者

          If GetKeyState(0)==False then
              Do Something
          End If
          

          【讨论】:

          • 不确定这是否正确。当你用零调用GetKeyState 时,你会得到System.ComponentModel.InvalidEnumArgumentException: 'The value of argument 'key' (0) is invalid for Enum type 'Key'. Parameter name: key'
          【解决方案10】:

          要检测哪个被按下,您需要检查每个键状态以及当前按下哪个键按下。
          记住:Press & Down 有区别。

              Public Sub Main()
                  While True
                      For i As Integer = 8 To 222
                          Select Case i
                              Case 8, 13, 32, 48 To 57, 65 To 90, 186 To 192, 219 To 222
                                  If GetAsyncKeyState(i) = -32767 And Not IsKeyDown(Keys.Control) Then
                                      Console.Write(CodeToChar(i))
                                  End If
                      End Select
                  Next
              End Sub
              
              Public Function IsKeyDown(Key As Keys) As Boolean
                  Return (Control.ModifierKeys And Key) = Key
              End Function
              
              
              Function CodeToChar(i As Integer) As String
                  Dim Character = Nothing
                  IsShiftDown = IsKeyDown(Keys.Shift)
                  If i > 64 And i < 91 Then c = If(Control.IsKeyLocked(Keys.CapsLock) Or IsShiftDown, Chr(i).ToString.ToUpper, Chr(i).ToString.ToLower) 
                  If i = 8   Then Character = "[BACK]"
                  If i = 13  Then Character = vbnewline
                  If i = 32  Then Character = " "
                  If i = 48  Then Character = If(IsShiftDown, ")", "0")
                  If i = 49  Then Character = If(IsShiftDown, "!", "1")
                  If i = 50  Then Character = If(IsShiftDown, "@", "2")
                  If i = 51  Then Character = If(IsShiftDown, "#", "3")
                  If i = 52  Then Character = If(IsShiftDown, "$", "4")
                  If i = 53  Then Character = If(IsShiftDown, "%", "5")
                  If i = 54  Then Character = If(IsShiftDown, "^", "6")
                  If i = 55  Then Character = If(IsShiftDown, "&", "7")
                  If i = 56  Then Character = If(IsShiftDown, "*", "8")
                  If i = 57  Then Character = If(IsShiftDown, "(", "9")
                  If i = 186 Then Character = If(IsShiftDown, ":", ";")
                  If i = 187 Then Character = If(IsShiftDown, "+", "=")
                  If i = 188 Then Character = If(IsShiftDown, "<", ",")
                  If i = 189 Then Character = If(IsShiftDown, "_", "-")
                  If i = 190 Then Character = If(IsShiftDown, ">", ".")
                  If i = 191 Then Character = If(IsShiftDown, "?", "/")
                  If i = 192 Then Character = If(IsShiftDown, "~", "`")
                  If i = 219 Then Character = If(IsShiftDown, "{", "[")
                  If i = 220 Then Character = If(IsShiftDown, "|", "\")
                  If i = 221 Then Character = If(IsShiftDown, "}", "]")
                  If i = 222 Then Character = If(IsShiftDown, """", "'")
                  Return Character
              End Function
          

          如果要使用 c# 版本,请转换 here。 阅读 keylogger 代码以了解有关键状态的更多信息。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-08-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-10-24
            • 1970-01-01
            • 2011-06-22
            • 1970-01-01
            相关资源
            最近更新 更多