I would like to ask for help with some small C# project. I have a windows forms app, whose purpose is to write text entered by user. It basicaly consist of one text box and one button. When your press the button, the program takes the text and jumps into loop, where it always takes just one symbol and send it using SendKeys.Send(). This works without any problem, but recently I wanted to add a feature, which would allow me to stop the program with a keypress. I’m stuck at this point, because the programm is running in the "writing" loop. My only idea was to check for the keypress inside the loop, but I wasn’t able to find any other way of registering keypress, than KeyPress event. Does anyone have any idea??
my code:
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);
}
}
Thanks!!
Your problem is probably related with the UI thread being blocked by repeated calls to Thread.Sleep
, making the UI non-responsive. An easy way to solve this problem is be making the handler of the Click
event asynchronous (adding the async
modifier), and replacing the Thread.Sleep
with await Task.Delay
. This way the UI will remain responsive during the whole operation of sending the keys.
private async void Button_Click(object sender, EventArgs e)
{
//...
await Task.Delay(5000); // Instead of Thread.Sleep(5000);
//...
}
This may create another problem, that the user will be able to click the button again while a send-keys operation is in progress, but I am sure that you'll find a way to solve this problem. 😃