В принятом ответе используется keybd_event
, который устарел. Официальный API теперь SendInput
. Есть также хорошая обертка для этого в http://inputsimulator.codeplex.com.
Ничто из вышеперечисленного, однако, не в полной мере отвечает сценарию "удержания ключа". Это связано с тем, что удержание клавиши будет генерировать несколько сообщений WM_KEYDOWN
, за которыми следует одно сообщение WM_KEYUP
после выпуска (вы можете проверить это с помощью Spy ++).
Частота сообщений WM_KEYDOWN
зависит от аппаратного обеспечения, настроек BIOS и нескольких настроек Windows: KeyboardDelay
и KeyboardSpeed
. Последние доступны из Windows Forms (SystemInformation.KeyboardDelay
, SystemInformation.KeyboardSpeed
).
Используя вышеупомянутую библиотеку Input Simulator, я реализовал метод удержания клавиш, который имитирует реальное поведение. Он await/async
готов и поддерживает отмену.
static Task SimulateKeyHold(VirtualKeyCode key, int holdDurationMs,
int repeatDelayMs, int repeatRateMs, CancellationToken token)
{
var tcs = new TaskCompletionSource<object>();
var ctr = new CancellationTokenRegistration();
var startCount = Environment.TickCount;
Timer timer = null;
timer = new Timer(s =>
{
lock (timer)
{
if (Environment.TickCount - startCount <= holdDurationMs)
InputSimulator.SimulateKeyDown(key);
else if (startCount != -1)
{
startCount = -1;
timer.Dispose();
ctr.Dispose();
InputSimulator.SimulateKeyUp(key);
tcs.TrySetResult(null);
}
}
});
timer.Change(repeatDelayMs, repeatRateMs);
if (token.CanBeCanceled)
ctr = token.Register(() =>
{
timer.Dispose();
tcs.TrySetCanceled();
});
return tcs.Task;
}