【发布时间】:2013-01-15 10:12:09
【问题描述】:
我想要实现的是使用 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 按下。我的方向正确吗?
附:另一种可能的方法是仅在 Ctrl 按下时订阅 Insert observable。不知道如何实现这一点。也许对此也有一些想法?
编辑: 我发现的另一个问题是 Buffer 不能完全满足我的需要。问题在于 Buffer 每两秒产生一次样本,如果我的第一次按下属于第一个缓冲区,第二次属于下一个缓冲区,那么什么也不会发生。如何克服?
【问题讨论】:
标签: c# system.reactive keypress