VB6 では、Windows API GetAsyncKeyStateへの呼び出しを使用して、ユーザーが ESC キーを押して実行時間の長いループから抜け出せるかどうかを判断しました。
Declare Function GetAsyncKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
API への直接呼び出しを必要とする純粋な .NET に相当するものはありますか?
GetAsyncKeyState の P/Invoke 宣言は、 http://pinvoke.net/default.aspx/user32/GetAsyncKeyState.htmlから見つけることができます。
たとえば、C# の署名は次のとおりです。
[DllImport("user32.dll")]
static extern short GetAsyncKeyState(int vKey);
目的の用途に応じて、上記と同じメソッドを呼び出すなど、いくつかのオプションがあります)。コンソールアプリから:
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);
}