我想要实现的是使用 Rx 处理一些复杂的按键和释放序列。我对 Rx 有一些经验,但这显然不足以满足我目前的工作,所以我在这里寻求帮助。
我的 WinForms 应用程序在后台运行,仅在系统托盘中可见。通过给定的键序列,我想激活其中一种形式。顺便说一句,要连接到全局按键,我正在使用一个不错的库http://globalmousekeyhook.codeplex.com/我能够接收每个按键按下和按键按下事件,并且当按键按下时,多个 KeyDown 事件是产生(具有标准键盘重复率)。
我要捕获的示例键序列之一是快速双 Ctrl + Insert 按键(例如按住 Ctrl 键并在给定时间段内按两次 Insert)。这是我目前在我的代码中的内容:
var keyDownSeq = Observable.FromEventPattern<KeyEventArgs>(m_KeyboardHookManager, "KeyDown");
var keyUpSeq = Observable.FromEventPattern<KeyEventArgs>(m_KeyboardHookManager, "KeyUp");
var ctrlDown = keyDownSeq.Where(ev => ev.EventArgs.KeyCode == Keys.LControlKey).Select(_ => true);
var ctrlUp = keyUpSeq.Where(ev => ev.EventArgs.KeyCode == Keys.LControlKey).Select(_ => false);
但后来我被困住了。我的想法是我需要以某种方式跟踪 Ctrl 键是否按下。一种方法是为此创建一些全局变量,并在一些合并侦听器中更新它
Observable.Merge(ctrlDown, ctrlUp)
.Do(b => globabl_bool = b)
.Subscribe();
但我认为它破坏了整个 Rx 方法。关于如何在保持 Rx 范式的同时实现这一目标的任何想法?
然后,当 Ctrl 按下时,我需要在给定时间内捕获两次 Insert 按下。我正在考虑使用缓冲区:
var insertUp = keyUpSeq.Where(ev => ev.EventArgs.KeyCode == Keys.Insert);
insertUp.Buffer(TimeSpan.FromSeconds(1), 2)
.Do((buffer) => { if (buffer.Count == 2) Debug.WriteLine("happened"); })
.Subscribe();
但是我不确定这是否是最有效的方式,因为 Buffer 会每隔一秒产生一次事件,即使没有按下任何键。有没有更好的办法?而且我还需要以某种方式将其与 Ctrl 结合起来。
所以再一次,我需要在 Ctrl 按下时跟踪两次 Insert 按下。我是否朝着正确的方向前进?
PS 另一种可能的方法是仅在 Ctrl 按下时订阅 Insert observable。不知道如何实现这一点。也许对此也有一些想法?
编辑:我发现的另一个问题是 Buffer 并不完全适合我的需要。问题在于 Buffer 每两秒产生一次样本,如果我的第一次按下属于第一个缓冲区,第二次属于下一个缓冲区,那么什么也不会发生。如何克服它?