Niklas
Niklas

Reputation: 81

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

Error 2 The name 'Key' does not exist in the current context

Can you tell me how to fix it?

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

Upvotes: 8

Views: 50158

Answers (5)

vitem
vitem

Reputation: 15

You need to add PresentationCore.dll and WindowsBase to references and add to the header of the method [STAThread]

Upvotes: 0

Ali Alavi
Ali Alavi

Reputation: 2467

The type of application is not clear. If you have a console application, not a Windows form one, you can try this:

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

Upvotes: 1

user8524747
user8524747

Reputation:

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):

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

Upvotes: 0

Erik
Erik

Reputation: 12868

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.

Looking at your using System.Windows.Input, it seems like you are trying to do this with WPF, which is possible.

Let's start with your fairly basic 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. However, WPF abstracts this message pump away from you, so you'll need to add a HwndSourceHook to tap into it.

How do we do all this? Let's start by initializing our HwndSourceHook delegate. Add this snippet to your 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. 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! Put them here (in 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. It only makes sense, as your message pump hook has to know which hotkey caused the WM_HOTKEY message!

It's also good practice to unregister all hotkeys when your application closes.

Upvotes: 2

DROP TABLE users
DROP TABLE users

Reputation: 1955

You can use a keyboard hook. Check this out, from 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. 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.

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. So you should make global hotkeys configurable, so the user can avoid collisions with his commonly used applications.

Upvotes: 0

Related Questions