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;
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With