[英]Console check for pressed keys like in monogame
在我的控制台应用程序中,我希望能够像在mono中那样检测按键的按下情况,在这里您可以获得当前按下的按键的列表,并检查按键是否在列表中,或者检测是否按下了按键。 。 我的使用问题
if( Console.KeyAvailable ) k = Console.ReadKey( true ).Key;
我按下第一个键后会有延迟的事实。 如果打开记事本并按住“ A”,您可以看到一个示例。 A将被按下,然后被延迟,然后A将被发送垃圾邮件。
如何获得键盘输入而没有按键之间的延迟? 我不怕使用低级功能,例如挂接到kernel32.dll
所以我根据到目前为止所读的内容编写了一些代码。
步骤1:将以下代码复制到控制台应用程序中。 它必须是STAThread,否则将引发错误。 在switch语句中输入要使用的命令。 所有其他键将被ReadKey(true)阻止。
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO;
using System;
using System.Windows.Forms;
using System.Windows.Input;
namespace ConsoleApplication10
{
class Program
{
[STAThread]
static void Main(string[] args)
{
KeyListener.RegisterHotKey(Keys.A);
KeyListener.HotKeyPressed += new EventHandler<HotKeyEventArgs>(KeyListener_HotKeyPressed);
while (true)
{
Console.ReadKey(true);
}
}
static void KeyListener_HotKeyPressed(object sender, HotKeyEventArgs e)
{
switch (e.Key)
{
case Keys.A:
{
Console.WriteLine("Do stuff");
return;
}
default:
return;
}
}
}
}
步骤2:添加对System.Windows.Forms的引用。 您需要具有隐藏的Form,这对于键盘挂钩的消息循环是必需的。
步骤3:添加以下静态类。 它为您完成了所有繁重的键盘挂钩,因此您不必这样做。
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;
namespace ConsoleApplication10
{
public static class KeyListener
{
public static event EventHandler<HotKeyEventArgs> HotKeyPressed;
public static int RegisterHotKey(Keys key, KeyModifiers modifiers)
{
_windowReadyEvent.WaitOne();
int id = System.Threading.Interlocked.Increment(ref _id);
_wnd.Invoke(new RegisterHotKeyDelegate(RegisterHotKeyInternal), _hwnd, id, (uint)modifiers, (uint)key);
return id;
}
public static int RegisterHotKey(Keys key)
{
_windowReadyEvent.WaitOne();
int id = System.Threading.Interlocked.Increment(ref _id);
_wnd.Invoke(new RegisterHotKeyDelegate(RegisterHotKeyInternal), _hwnd, id, (uint)KeyModifiers.None, (uint)key);
return id;
}
public static void UnregisterHotKey(int id)
{
_wnd.Invoke(new UnRegisterHotKeyDelegate(UnRegisterHotKeyInternal), _hwnd, id);
}
delegate void RegisterHotKeyDelegate(IntPtr hwnd, int id, uint modifiers, uint key);
delegate void UnRegisterHotKeyDelegate(IntPtr hwnd, int id);
private static void RegisterHotKeyInternal(IntPtr hwnd, int id, uint modifiers, uint key)
{
RegisterHotKey(hwnd, id, modifiers, key);
}
private static void UnRegisterHotKeyInternal(IntPtr hwnd, int id)
{
UnregisterHotKey(_hwnd, id);
}
private static void OnHotKeyPressed(HotKeyEventArgs e)
{
if (KeyListener.HotKeyPressed != null)
{
KeyListener.HotKeyPressed(null, e);
}
}
private static volatile MessageWindow _wnd;
private static volatile IntPtr _hwnd;
private static ManualResetEvent _windowReadyEvent = new ManualResetEvent(false);
static KeyListener()
{
Thread messageLoop = new Thread(delegate ()
{
Application.Run(new MessageWindow());
});
messageLoop.Name = "MessageLoopThread";
messageLoop.IsBackground = true;
messageLoop.Start();
}
private class MessageWindow : Form
{
public MessageWindow()
{
_wnd = this;
_hwnd = this.Handle;
_windowReadyEvent.Set();
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_HOTKEY)
{
HotKeyEventArgs e = new HotKeyEventArgs(m.LParam);
KeyListener.OnHotKeyPressed(e);
}
base.WndProc(ref m);
}
protected override void SetVisibleCore(bool value)
{
// Ensure the window never becomes visible
base.SetVisibleCore(false);
}
private const int WM_HOTKEY = 0x312;
}
[DllImport("user32", SetLastError = true)]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
[DllImport("user32", SetLastError = true)]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
private static int _id = 0;
}
public class HotKeyEventArgs : EventArgs
{
public readonly Keys Key;
public readonly KeyModifiers Modifiers;
public HotKeyEventArgs(Keys key, KeyModifiers modifiers)
{
this.Key = key;
this.Modifiers = modifiers;
}
public HotKeyEventArgs(IntPtr hotKeyParam)
{
uint param = (uint)hotKeyParam.ToInt64();
Key = (Keys)((param & 0xffff0000) >> 16);
Modifiers = (KeyModifiers)(param & 0x0000ffff);
}
}
[Flags]
public enum KeyModifiers
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
Windows = 8,
NoRepeat = 0x4000
}
}
第四步:
现在,仍然有延迟。 它的方式更优雅,但是您仍然需要操作系统来对抗您。 那么该怎么办?
您有两个选择。
a)您实现了一个计时选项,并且只要在计时器滴答事件中按下了一个键,您就只需重复该操作即可。 您可以复制代码,也可以将其与我提供的热键方法合并。
有关详细信息,请参见此处: 消除KeyDown事件后的延迟?
private bool _moveUp;
private bool _moveDown;
private bool _moveLeft;
private bool _moveRight;
// You can add the Timer in the Winforms Designer instead if you like;
// The Interval property can be configured there at the same time, along
// with the Tick event handler, simplifying the non-Designer code here.
private System.Windows.Forms.Timer _movementTimer = new Timer { Interval = 100 };
public MainForm()
{
InitializeComponent();
_movementTimer.Tick += movementTimer_Tick;
}
private void movementTimer_Tick(object sender, EventArgs e)
{
_DoMovement();
}
private void _DoMovement()
{
if (_moveLeft) Player.MoveLeft();
if (_moveRight) Player.MoveRight();
if (_moveUp) Player.MoveUp();
if (_moveDown) Player.MoveDown();
}
// You could of course override the OnKeyDown() method instead,
// assuming the handler is in the Form subclass generating the
// the event.
public void MainForm_KeyDown(object sender, KeyEventArgs e)
{
if (e.IsRepeat)
{
// Ignore key repeats...let the timer handle that
return;
}
switch (e.KeyCode)
{
case Keys.Up:
_moveUp = true;
break;
case Keys.Down:
_moveDown = true;
break;
case Keys.Left:
_moveLeft = true;
break;
case Keys.Right:
_moveRight = true;
break;
}
_DoMovement();
_movementTimer.Start();
}
public void MainForm_KeyUp(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Up:
_moveUp = false;
break;
case Keys.Down:
_moveDown = false;
break;
case Keys.Left:
_moveLeft = false;
break;
case Keys.Right:
_moveRight = false;
break;
}
if (!(_moveUp || _moveDown || _moveLeft || _moveRight))
{
_movementTimer.Stop();
}
}
b)在您的Main方法中,获得延迟设置,以编程方式将延迟设置为最低设置,然后在Application Exit上将其重新设置为原始设置。
在此处找到在注册表中的位置: https : //superuser.com/questions/388160/keyboard-repeat-rate-repeat-delay-values-in-win7
以及如何读取/写入注册表: https : //msdn.microsoft.com/zh-cn/library/microsoft.win32.registry_methods(v=vs.110).aspx
注意:使用这种方法,仍然会有一些延迟。 它很小,但是在那里。 祝好运。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.