3

在 VB6 中,我使用了对 Windows API GetAsyncKeyState的调用来确定用户是否按下了 ESC 键以允许他们退出长时间运行的循环。

Declare Function GetAsyncKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer

纯 .NET 中是否存在需要直接调用 API 的等效项?

4

2 回答 2

3

您可以从http://pinvoke.net/default.aspx/user32/GetAsyncKeyState.html找到 GetAsyncKeyState 的 P/Invoke 声明

例如,这是 C# 签名:

[DllImport("user32.dll")]
static extern short GetAsyncKeyState(int vKey);
于 2008-09-25T15:30:18.047 回答
1

根据您所需的用途,有几个选项,包括调用与上述相同的方法)。从控制台应用程序:

bool exitLoop = false;
for(int i=0;i<bigNumber && !exitLoop;i++)
{
    // Do Stuff.
    if(Console.KeyAvailable)
    {
        // Read the key and display it (false to hide it)
        ConsoleKeyInfo key = Console.ReadKey(true);
        if(ConsoleKey.Escape == key.Key)
        {
            exitLoop=false;
        }
    }
}

如果您正在处理 Windows 窗体,则每个窗体都有许多关键相关事件,您可以根据需要侦听和处理(简化了大部分逻辑):

public partial class Form1 : Form
{
    private bool exitLoop;
    public Form1()
    {
        InitializeComponent();
        this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyUp);
    }
    public void doSomething()
    {
        // reset our exit flag:
        this.exitLoop = false;
        System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(delegate(object notUsed)
            {
                while (!exitLoop)
                {
                    // Do something
                }
            }));
    }
    private void Form1_KeyUp(object sender, KeyEventArgs e)
    {
        if (Keys.Escape == e.KeyCode)
        {
            e.Handled = true;
            this.exitLoop = true;
        }
    }

}

请注意,这是非常简化的——它不处理任何常见的线程问题或类似问题。正如评论中指出的那样,最初的解决方案并没有解决这个问题,我添加了一个快速的小 ThreadPool 调用来线程化后台工作。另请注意,侦听关键事件的问题在于其他控件实际上可能会处理它们,因此您需要确保在正确的控件上注册事件。如果 Windows 窗体应用程序是您前进的方向,您也可以尝试将自己注入到消息循环本身中......

public override bool PreProcessMessage(ref Message msg)
{
  // Handle the message or pass it to the default handler...
  base.PreProcessMessage(msg);
}
于 2008-09-25T15:56:39.950 回答