7

我必须使用什么才能获得目前在键盘上按下的“所有键”?因为Form.KeyPress += new EventHandler()当它充满控件时根本没有做太多事情。无论我做什么,它都不会调用它,无论是 KeyDown、KeyUp 还是其他任何东西……是的,我知道如何使用它们。

因此,如果系统中有任何功能可以检查按下的键,它会返回使用的键的数组或其他东西 - 我会很感激指出正确的方向。

4

4 回答 4

15

听起来您想查询键盘中所有键的状态。最好的功能是 Win32 API 调用GetKeyboardState

我不相信有一个很好的管理等效功能。它的 PInvoke 代码相当简单

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetKeyboardState(byte [] lpKeyState);

var array = new byte[256];
GetKeyboardState(array);

这将填充byte[]系统中每个虚拟键的向上/向下状态。如果设置了高位,则当前按下虚拟键。将 a映射Key到虚拟键码仅通过考虑byte数值的部分来完成Key

public static byte GetVirtualKeyCode(Key key) {
  int value = (int)key;
  return (byte)(value & 0xFF);
}

以上适用于大多数Key值,但您需要小心修饰键。values Keys.Alt, Keys.ControlandKeys.Shift在这里不起作用,因为它们在技术上是修饰符而不是键值。要使用修饰符,您需要使用实际关联的键值Keys.ControlKey,Keys.LShiftKey等...(实际上是以 Key 结尾的任何内容)

因此检查是否设置了特定键可以如下完成

var code = GetVirtualKeyCode(Key.A);
if ((array[code] & 0x80) != 0) {
  // It's pressed
} else { 
  // It's not pressed
}
于 2012-05-07T14:56:05.227 回答
6

我对 JaredPar 的回答做了一些扩展。以下方法返回当前被按下的所有键的集合:

using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Input;

private static readonly byte[] DistinctVirtualKeys = Enumerable
    .Range(0, 256)
    .Select(KeyInterop.KeyFromVirtualKey)
    .Where(item => item != Key.None)
    .Distinct()
    .Select(item => (byte)KeyInterop.VirtualKeyFromKey(item))
    .ToArray();

/// <summary>
/// Gets all keys that are currently in the down state.
/// </summary>
/// <returns>
/// A collection of all keys that are currently in the down state.
/// </returns>
public IEnumerable<Key> GetDownKeys()
{
    var keyboardState = new byte[256];
    GetKeyboardState(keyboardState);

    var downKeys = new List<Key>();
    for (var index = 0; index < DistinctVirtualKeys.Length; index++)
    {
        var virtualKey = DistinctVirtualKeys[index];
        if ((keyboardState[virtualKey] & 0x80) != 0)
        {
            downKeys.Add(KeyInterop.KeyFromVirtualKey(virtualKey));
        }
    }

    return downKeys;
}

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetKeyboardState(byte[] keyState);
于 2015-05-27T02:41:22.313 回答
1

如果您只需要在应用程序处于活动状态时知道所有击键,无论应用程序中的哪个控件具有焦点,那么您都可以使用KeyPreview表单的属性。

只需将该属性设置为 true 并订阅表单上所需的 Key 事件。现在,您将在应用程序中收到所有击键,然后将它们转发到具体控件,从而允许您对它自己做出反应并取消将其转发到控件,将Cancel属性设置为 true。

如果您需要在您的应用程序不是活动应用程序时接收按下的键,那么您需要某种低级键盘挂钩。我没有对其进行测试,但是CodeProject 上的这篇文章对于这种情况看起来很有希望。

于 2012-05-08T07:31:37.313 回答
0

我相信您正在寻找PreviewKeyDown事件,如果在表单具有焦点时按下某个键,即使该表单中的另一个子控件当前具有焦点,该事件也会触发。

于 2012-05-07T14:52:37.823 回答