I'm new in programming with C#.
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?
//...
using System.Windows.Input;
class Main {
public void Main() {
while(true) {
if(Keyboard.IsKeyPressed(Key.A)) {
//...
}
return;
}
}
}
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.
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.
The type of application is not clear to me! 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
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;
}