我想寻求一些小C#项目的帮助。我有一个windows窗体应用程序,其目的是编写用户输入的文本。它基本上由一个文本框和一个按钮组成。当你按下按钮时,程序会接收文本并跳到循环中,在循环中它总是只接收一个符号,并使用SendKeys.send()发送它。这没有任何问题,但最近我想添加一个功能,它可以让我用按键停止程序。我被困在这一点上,因为程序正在";书写";环我唯一的想法是检查循环中的按键,但除了keypress事件外,我找不到任何其他注册按键的方法。有人知道吗??
我的代码:
public partial class Form1 : Form
{
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
String textToWrite;
int delay;
bool continueWriting = true;
enum KeyModifier
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
WinKey = 8
}
public Form1()
{
InitializeComponent();
this.KeyPreview = true;
int id = 0;
RegisterHotKey(this.Handle, id, (int)KeyModifier.Shift, Keys.A.GetHashCode());
}
private void pisBut_Click(object sender, EventArgs e)
{
textToWrite= textToWriteTextBox.Text;
Console.WriteLine(zadaniText);
continueWriting = true;
Thread.Sleep(5000);
try
{
delay = Convert.ToInt32(delayBetweenSymbolsTextBox.Text);
}
catch
{
Console.WriteLine("conversion failed!");
}
for (int i = 0; i < textToWrite.Length; i++)
{
// loop intended to take one char and send it
Random nahoda = new Random();
SendKeys.Send(zadaniText[i].ToString());
int finalDelay = nahoda.Next(delay - 40, delay);
Console.WriteLine(finalDelay);
Thread.Sleep(finalDelay);
if (continueWriting == false) // stop after setting this bool false
{
break;
}
}
}
private void zadani_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
// interrupt writing
}
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == 0x0312)
{
Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF);
KeyModifier modifier = (KeyModifier)((int)m.LParam & 0xFFFF);
int id = m.WParam.ToInt32(); .
MessageBox.Show("Hotkey has been pressed!");
continueWriting = false;
}
}
private void ExampleForm_FormClosing(object sender, FormClosingEventArgs e)
{
UnregisterHotKey(this.Handle, 0);
}
}
谢谢!!
您的问题可能与UI线程被对Thread.Sleep
的重复调用阻塞有关,从而使UI没有响应。解决这个问题的一个简单方法是使Click
事件的处理程序异步(添加async
修饰符),并用await Task.Delay
替换Thread.Sleep
。这样,在发送按键的整个操作过程中,UI将保持响应。
private async void Button_Click(object sender, EventArgs e)
{
//...
await Task.Delay(5000); // Instead of Thread.Sleep(5000);
//...
}
这可能会产生另一个问题,即用户可以在进行发送密钥操作时再次单击按钮,但我相信您会找到解决此问题的方法。
我会考虑使用Microsoft的Reactive Framework(又名Rx)-NuGetSystem.Reactive.Windows.Forms
并添加using System.Reactive.Linq;
,然后你就可以这样做了:
private IDisposable _subscription = null;
private void pisBut_Click(object sender, EventArgs e)
{
if (int.TryParse(delayBetweenSymbolsTextBox.Text, out delay))
{
Random random = new Random();
_subscription =
Observable
.Generate(
0, x => x < zadaniText.Length, x => x + 1, x => x,
x => TimeSpan.FromMilliseconds(x == 0 ? 5000.0 : random.Next(delay - 40, delay)))
.ObserveOn(this)
.Subscribe(i => SendKeys.Send(zadaniText[i].ToString()));
}
}
现在要中途停止发送密钥,可以执行以下操作:_subscription?.Dispose();
。