繁体   English   中英

C# - 检查是否按下了特定键

[英]C# - Check if specific key is pressed

我正在尝试检查是否按下了某个键,但我收到以下错误消息:

错误 1 当前上下文中不存在名称“键盘”

错误 2 当前上下文中不存在名称“Key”

你能告诉我如何解决吗?

public void Main() 
{
    while(true) 
    {
        if (Keyboard.IsKeyPressed(Key.A)) 
        {
            //...
        }
        return;
    }
}

看起来您正在尝试在系统中创建一个全局热键,并且您的应用程序应该在按下时做出响应。

您将需要两个 Win32 API 函数RegisterHotKeyUnregisterHotKey

看着您using System.Windows.Input ,您似乎正在尝试使用 WPF 来执行此操作,这是可能的。

让我们从您相当基本的 P/Invokes 开始:

using System.Runtime.InteropServices;

internal static class NativeMethods
{
    [DllImport("user32.dll")]
    public static extern bool RegisterHotKey(IntPtr windowHandle, int hotkeyId, uint modifierKeys, uint virtualKey);

    [DllImport("user32.dll")]
    public static extern bool UnregisterHotKey(IntPtr windowHandle, int hotkeyId);
}

现在,当您注册Window ,会发生WM_HOTKEY消息发送到您的应用程序的消息泵。 但是,WPF 将这个消息泵从您那里抽象出来,因此您需要添加一个HwndSourceHook来利用它。

我们如何做到这一切? 让我们从初始化我们的HwndSourceHook委托开始。 将此代码段添加到您的MainWindow

    using System.Windows.Interop;

    static readonly int MyHotKeyId = 0x3000;
    static readonly int WM_HOTKEY = 0x312;

    void InitializeHook()
    {
        var windowHelper = new WindowInteropHelper(this);
        var windowSource = HwndSource.FromHwnd(windowHelper.Handle);

        windowSource.AddHook(MessagePumpHook);
    }

    IntPtr MessagePumpHook(IntPtr handle, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == WM_HOTKEY)
        {
            if ((int)wParam == MyHotKeyId)
            {
                // The hotkey has been pressed, do something!

                handled = true;
            }
        }

        return IntPtr.Zero;
    }

好的,现在我们已准备好响应WM_HOTKEY消息。 但是,我们仍然需要注册我们的热键! 让我们添加另外几个初始化方法:

    void InitializeHotKey()
    {
        var windowHelper = new WindowInteropHelper(this);

        // You can specify modifiers such as SHIFT, ALT, CONTROL, and WIN.
        // Remember to use the bit-wise OR operator (|) to join multiple modifiers together.
        uint modifiers = (uint)ModifierKeys.None;

        // We need to convert the WPF Key enumeration into a virtual key for the Win32 API!
        uint virtualKey = (uint)KeyInterop.VirtualKeyFromKey(Key.A);

        NativeMethods.RegisterHotKey(windowHelper.Handle, MyHotKeyId, modifiers, virtualKey);
    }

    void UninitializeHotKey()
    {
        var windowHelper = new WindowInteropHelper(this);
        NativeMethods.UnregisterHotKey(windowHelper.Handle, MyHotKeyId);
    }

好吧! 我们把这些放在哪里? 不要把它们放在构造函数中! 为什么? 因为Handle将为0且无效! 把它们放在这里(在MainWindow ):

    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized(e);
        InitializeHook();
        InitializeHotKey();
    }

您可以注册多个热键、取消注册和重新注册新的热键。这取决于您。 请记住,每个热键都必须注册一个唯一的 ID WM_HOTKEY有意义,因为您的消息泵钩必须知道是哪个热键导致了WM_HOTKEY消息!

在您的应用程序关闭时取消注册所有热键也是一种很好的做法。

您可以使用键盘挂钩。 看看 这个,从this answer to a similar question

如果您只需要几个全局热键,全局键盘钩子不是正确的解决方案。 高级键盘挂钩意味着您的 dll 将被注入到其他应用程序中,并且根本不应该在托管代码中完成。 低级键盘钩子更好一些,因为它在您自己的应用程序中处理键盘事件。 它仍然要求每个键盘事件都由您的线程处理。

Windows API 函数 RegisterHotKey 更适合这种情况。

但是使用简单的 F 键作为全局热键是有问题的,因为它可能与具有焦点的应用程序的本地热键发生冲突。 所以你应该使全局热键可配置,这样用户就可以避免与他常用的应用程序发生冲突。

如果您尝试在 windows 窗体应用程序中执行此操作,也许您可​​以将这些代码添加到窗体的 KeyDown 事件中(或您需要使用哪个键事件):

switch (e.KeyData)
{
    //Detects that you pressed the Up Arrow Key, which key do you need, just 
    //write it here.
    case Keys.Up: 
    //enter code here`
    break;
}

您需要将PresentationCore.dllWindowsBase添加到引用并添加到方法[STAThread]的 header

申请类型不明确。 如果你有一个控制台应用程序,而不是一个 Windows 窗体,你可以试试这个:

while (true)
  if (Console.KeyAvailable) 
    if (Console.ReadKey(true).Key == ConsoleKey.A)
    { 
      // Do something
    }

如果您想在 Windows 窗体应用程序中使用全局热键,请阅读此内容: http : //www.liensberger.it/web/blog/? p= 207

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM