Если асинхронность не является обязательным требованием, и у вас все в порядке с одним потоком, который почти всегда ожидает, вы можете сделать это, предоставив лямбде некоторый блокирующий доступ к ключу.Например:
public void RegisterEvaluator(Func<Func<Key>, bool> evaluate);
…
keyUpper.RegisterEvaluator(
getKey => getKey() == Key.A && getKey() == Key.W);
RegisterEvaluator
будет тогда раскручивать новый поток, который вызывает лямбда в цикле, передавая ему метод, который обращается к ключу, блокируя, если в данный момент ключ недоступен, дляпример использования BlockingCollection<Key>
.
Если вы думаете, что делать это таким образом бесполезно (так оно и есть), и вы можете использовать async-await, просто сделайте лямбду async
и измените переданный метод на тот, которыйтоже асинхронный:
public Task RegisterEvaluator(Func<Func<Task<Key>>, Task<bool>> evaluate);
…
keyUpper.RegisterEvaluator(
async getKey => await getKey() == Key.A && await getKey() == Key.W);
Реализация последней версии (с использованием BlockBuffer<Key>
) может выглядеть так:
class KeyUpper
{
private readonly BufferBlock<Key> m_keyBuffer = new BufferBlock<Key>();
public async Task RegisterEvaluator(
Func<Func<Task<Key>>, Task<bool>> evaluate)
{
while (true)
{
if (await evaluate(m_keyBuffer.ReceiveAsync))
SomeResponse();
}
}
public void KeyUp(object sender, KeyEventArgs e)
{
m_keyBuffer.Post(e.Key);
}
private void SomeResponse()
{
// whatever
}
}
Теперь я неконечно, как именно вы хотите справиться с соответствием клавишам, но я думаю, что это не так.Например, этот пример кода будет соответствовать последовательности клавиш BAW
, но не AAW
.
Другой вариант будет не использовать Func<Task<Key>>
, а ваш пользовательский ожидаемый, который можно ожидать несколько раз и даеткаждый раз, когда вы делаете это по одному ключу:
public Task RegisterEvaluator(Func<KeyAwaitable, Task<bool>> evaluate);
…
keyUpper.RegisterEvaluator(
async getKey => await getKey == Key.A && await getKey == Key.W);
Но я думаю, что делать это таким образом сложнее и сложнее.