[英]C# - Check if specific key is pressed
我正在尝试检查是否按下了某个键,但我收到以下错误消息:
错误 1 当前上下文中不存在名称“键盘”
错误 2 当前上下文中不存在名称“Key”
你能告诉我如何解决吗?
public void Main()
{
while(true)
{
if (Keyboard.IsKeyPressed(Key.A))
{
//...
}
return;
}
}
看起来您正在尝试在系统中创建一个全局热键,并且您的应用程序应该在按下时做出响应。
您将需要两个 Win32 API 函数RegisterHotKey和UnregisterHotKey 。
看着您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.dll
和WindowsBase
添加到引用并添加到方法[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.