简体   繁体   English

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

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

I'm trying to check if a key is pressed, but I get these Error Message:我正在尝试检查是否按下了某个键,但我收到以下错误消息:

Error 1 The name 'Keyboard' does not exist in the current context错误 1 当前上下文中不存在名称“键盘”

Error 2 The name 'Key' does not exist in the current context错误 2 当前上下文中不存在名称“Key”

Can you tell me how to fix it?你能告诉我如何解决吗?

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

It looks like you are trying to create a global hotkey in the system and your application should respond when it is pressed.看起来您正在尝试在系统中创建一个全局热键,并且您的应用程序应该在按下时做出响应。

You will need two Win32 API functions RegisterHotKey and UnregisterHotKey .您将需要两个 Win32 API 函数RegisterHotKeyUnregisterHotKey

Looking at your using System.Windows.Input , it seems like you are trying to do this with WPF, which is possible.看着您using System.Windows.Input ,您似乎正在尝试使用 WPF 来执行此操作,这是可能的。

Let's start with your fairly basic P/Invokes:让我们从您相当基本的 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);
}

Now, when you register your Window , what happens is that a WM_HOTKEY message is sent to your application's message pump.现在,当您注册Window ,会发生WM_HOTKEY消息发送到您的应用程序的消息泵。 However, WPF abstracts this message pump away from you, so you'll need to add a HwndSourceHook to tap into it.但是,WPF 将这个消息泵从您那里抽象出来,因此您需要添加一个HwndSourceHook来利用它。

How do we do all this?我们如何做到这一切? Let's start by initializing our HwndSourceHook delegate.让我们从初始化我们的HwndSourceHook委托开始。 Add this snippet to your MainWindow :将此代码段添加到您的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;
    }

Alright, so now we have everything in place to respond to the WM_HOTKEY message.好的,现在我们已准备好响应WM_HOTKEY消息。 However, we need to register our hotkey still!但是,我们仍然需要注册我们的热键! Let's add another couple initialization methods:让我们添加另外几个初始化方法:

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

Alright!好吧! Where do we put these?我们把这些放在哪里? Do not put them in the constructor!不要把它们放在构造函数中! Why?为什么? Because the Handle will be 0 and invalid!因为Handle将为0且无效! Put them here (in MainWindow ):把它们放在这里(在MainWindow ):

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

You can register multiple hotkeys, un-register and re-register new ones.. it's up to you.您可以注册多个热键、取消注册和重新注册新的热键。这取决于您。 Just remember that each hotkey must have a unique ID registered to it.请记住,每个热键都必须注册一个唯一的 ID It only makes sense, as your message pump hook has to know which hotkey caused the WM_HOTKEY message! WM_HOTKEY有意义,因为您的消息泵钩必须知道是哪个热键导致了WM_HOTKEY消息!

It's also good practice to unregister all hotkeys when your application closes.在您的应用程序关闭时取消注册所有热键也是一种很好的做法。

You can use a keyboard hook.您可以使用键盘挂钩。 Check this out, from this answer to a similar question :看看 这个,从this answer to a similar question

Global keyboard hooks are not the right solution if you only want a few global hotkeys.如果您只需要几个全局热键,全局键盘钩子不是正确的解决方案。 A high level keyboard hook means that your dll will be injected into other applications, and shouldn't be done at all in managed code.高级键盘挂钩意味着您的 dll 将被注入到其他应用程序中,并且根本不应该在托管代码中完成。 A low level keyboard hook is a bit better, since it processes the keyboard events in your own application.低级键盘钩子更好一些,因为它在您自己的应用程序中处理键盘事件。 Still it requires that every keyboard event is handled by your thread.它仍然要求每个键盘事件都由您的线程处理。

The windows API function RegisterHotKey is much better suited for that. Windows API 函数 RegisterHotKey 更适合这种情况。

But using a smple F-Key as global hotkey is problematic since it might collide with a local hotkey of the application that has focus.但是使用简单的 F 键作为全局热键是有问题的,因为它可能与具有焦点的应用程序的本地热键发生冲突。 So you should make global hotkeys configurable, so the user can avoid collisions with his commonly used applications.所以你应该使全局热键可配置,这样用户就可以避免与他常用的应用程序发生冲突。

If you are trying to do this in a windows forms application, maybe you can add these codes into the Form's KeyDown event(or which key event you need to use):如果您尝试在 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;
}

You need to add PresentationCore.dll and WindowsBase to references and add to the header of the method [STAThread]您需要将PresentationCore.dllWindowsBase添加到引用并添加到方法[STAThread]的 header

The type of application is not clear.申请类型不明确。 If you have a console application, not a Windows form one, you can try this:如果你有一个控制台应用程序,而不是一个 Windows 窗体,你可以试试这个:

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

and read this if you want to have a global hotkey in a windows forms app: http://www.liensberger.it/web/blog/?p=207如果您想在 Windows 窗体应用程序中使用全局热键,请阅读此内容: http : //www.liensberger.it/web/blog/? p= 207

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

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