Reputation: 6659
public class KeyUpper {
Func<Key, bool> _evaluate;
public void RegisterEvaluator(Func<Key, bool> evaluate){
_evaluate = evaluate;
}
public void KeyUp(object sender, KeyEventArgs e){
if (_evaluate(e.KeyCode))
SomeResponse();
}
public void SomeResponse(){
// ...
}
}
keyUpper.RegisterEvaluator(key =>
{
if (key == Key.A)
if (key == Key.W)
if (key == Key.A)
return true;
}
);
key
argument with the expectation that each line of evaluation would be awaited so that SomeResponse() would be invoked after a sequence of keyup events of 1:A 2:W 3:Akey == Key.W
will never be trueUpvotes: 2
Views: 2299
Reputation: 244777
If asynchronicity is not a requirement and you are fine with having one thread that almost always waits, you could do it by giving the lambda some blocking way to access the key. For example:
public void RegisterEvaluator(Func<Func<Key>, bool> evaluate);
…
keyUpper.RegisterEvaluator(
getKey => getKey() == Key.A && getKey() == Key.W);
RegisterEvaluator
would then spin up a new thread that calls the lambda in a loop, passing it a method that accesses the key, blocking if no key is available at the moment, for example using BlockingCollection<Key>
.
If you think doing it this way is wasteful (it is), and you can use async-await, just make the lambda async
and change the passed in method to one that is asynchronous too:
public Task RegisterEvaluator(Func<Func<Task<Key>>, Task<bool>> evaluate);
…
keyUpper.RegisterEvaluator(
async getKey => await getKey() == Key.A && await getKey() == Key.W);
Implementation of the latter version (using BlockBuffer<Key>
) could look like this:
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
}
}
Now, I'm not sure how exactly do you want to handle matching the keys, but I think it's not like this. For example, this sample code would match the sequence of keys BAW
, but not AAW
.
Another option would be not using Func<Task<Key>>
, but your custom awaitable that can be awaited multiple times and gives one key each time you do that:
public Task RegisterEvaluator(Func<KeyAwaitable, Task<bool>> evaluate);
…
keyUpper.RegisterEvaluator(
async getKey => await getKey == Key.A && await getKey == Key.W);
But I think doing it this way is more confusing and harder to do.
Upvotes: 2