I don't know if it's too late, but I have an answer for you.
The Rx extension method you need to use is BufferWithCount
.
I'll assume you know how to turn key press events into an IObservable<char>
.
So given you have a list of character sequences that you want to detect and then perform an action I suggest using a Dictionary<string, Action>
to hold this data, like so:
var matches = new Dictionary<string, Action>()
{
{ "ba", () => Console.WriteLine("ba") },
{ "aba", () => Console.WriteLine("aba") },
{ "baa", () => Console.WriteLine("baa") },
{ "abc\t", () => Console.WriteLine("abc\\t") },
};
So here's the Rx (and IEnumerable
) queries required:
int max =
matches
.Select(m => m.Key.Length)
.Max();
IObservable<string> chords =
Enumerable
.Range(2, max - 1)
.Select(n => keys
.BufferWithCount(n, 1)
.Select(cs => new string(cs.ToArray())))
.Merge();
IObservable<Action> actions =
chords
.Where(s => matches.ContainsKey(s))
.Select(s => matches[s]);
So finally you just have an IObservable<Action>
that you can subscribe to and you just invoke the Action
.
If you want to test out that this works use the following code:
IConnectableObservable<char> keys = "ababc\tdabaababc\tebad"
.ToObservable()
.Publish();
//`.Publish()` makes a cold observable become hot,
// but you must call `Connect()` to start producing values.
//insert above `matches` definition here.
//insert above queries here.
actions.Subscribe(a => a());
keys.Connect();
The result should be:
ba
aba
abc\t
ba
aba
baa
ba
aba
abc\t
ba
Enjoy!