如何使用rxjs过滤keydowns?

如何使用rxjs过滤keydowns?

问题描述:

我需要获得干净的keydown/keyup事件而无需重复。当你按下一个按键keydown事件发生时,当你释放 - 键入。没有凌乱的重复keydowns。如何使用rxjs过滤keydowns?

这里是代码:

var keyDowns = rx.Observable.fromEvent(document, 'keydown'); 
var keyUps = rx.Observable.fromEvent(document, 'keyup'); 
var keyActions = rx.Observable.merge(keyDowns, keyUps); 

keyActions.subscribe(function(e) { 
    console.log e 
}); 

如何适应它做的工作吗?

+0

我不明白你想过滤。重复密码是什么意思?你是否想把钥匙与钥匙相提并论? – paulpdaniels

+0

当你按下一个键并按住它时,通常你会得到重复,很多keydowns。当按键被按下时,我想要1'按'事件,并且当按键被释放时,'1'释放'事件。对不起,我的英语 –

+0

而且,是的,需要匹配键盘和keydowns之间的匹配 –

查看费德里科的答案,下面是一个更优雅和习惯解决方案。


可避免重复项目从可观察到的(正如你看到的,当某个键)与distinctUntilChanged过滤掉匹配最后发出的值(其中匹配由发射值或它们的值相等确定的值由keySelector回调参数转换)。

在你的情况,这可能看起来那么简单,有点像:

var keyDowns = Rx.Observable.fromEvent(document, 'keydown'); 
var keyUps = Rx.Observable.fromEvent(document, 'keyup'); 
var keyActions = Rx.Observable 
    .merge(keyDowns, keyUps) 
    .distinctUntilChanged(function(e) { return e.type + (e.key || e.which); }); 

keyActions.subscribe(function(e) { 
    console.log(e.type, e.key || e.which, e.keyIdentifier); 
}); 

但这持有多个键时达不到。在Chrome OS X,如果我按住A,S,d,然后释放A,S,DI在控制台中执行以下操作:

keydown 65 U+0041 
keydown 83 U+0053 
keydown 68 U+0044 
keyup 65 U+0041 
keydown 68 U+0044 
keyup 83 U+0053 
keydown 68 U+0044 
keyup 68 U+0044 

注 “的keydown 68”(d)的重复时释放A和S.这是因为​​事件仅针对最近按下的键重复。使用类似的想法告诉了一个在您的评论中,我们可以改为尝试一个自定义过滤器,维护着这个键被按下列表:

var keyDowns = Rx.Observable.fromEvent(document, 'keydown'); 
var keyUps = Rx.Observable.fromEvent(document, 'keyup'); 
var keyActions = Rx.Observable 
    .merge(keyDowns, keyUps) 
    .filter((function() { 
     var keysPressed = {}; 
     return function(e) { 
      var k = e.key || e.which; 
      if (e.type == 'keyup') { 
       delete keysPressed[k]; 
       return true; 
      } else if (e.type == 'keydown') { 
       if (keysPressed[k]) { 
        return false; 
       } else { 
        keysPressed[k] = true; 
        return true; 
       } 
      } 
     }; 
    })()); 

keyActions.subscribe(function(e) { 
    console.log(e.type, e.key || e.which, e.keyIdentifier); 
}); 

按住A,S,d,然后释放, S,d现在给:

keydown 65 U+0041 
keydown 83 U+0053 
keydown 68 U+0044 
keyup 65 U+0041 
keyup 83 U+0053 
keyup 68 U+0044 

除了我们过滤合并流而不是预先过滤,使得组合流看起来我们喜欢它,这类似于你在注释中提到的方法。

我对rx.js没有足够的经验,断言这是做到这一点的最好方法,但它肯定会感觉更符合Rx风格。 (任何意见赞赏。)

+0

虽然这可行,但具有状态跟踪的代码非常**单一。 –

+0

同意。解决方案编辑为参考。 – icio

虽然它很好,它的工作原理,icio与状态跟踪的解决方案是**非常** unidiomatic。正确RxJs 5的解决办法是:

var keyDowns = Rx.Observable.fromEvent(document, "keydown") 
var keyUps = Rx.Observable.fromEvent(document, "keyup") 

var keyPresses = keyDowns 
    .merge(keyUps) 
    .groupBy(e => e.keyCode) 
    .map(group => group.distinctUntilChanged(null, e => e.type)) 
    .mergeAll() 

说明:

  • 合并所有键所有的keydown和KeyUp事件。
  • 按键(keyCode)对它们进行分组。它创建一个可观察的可观察对象,每个可观察对象将包含一个关键点的所有事件。
  • 将每个子观察对象映射到它自己的distinctUntilChanged版本。按事件类型进行操作,以便跳过额外的关键字。
  • 合并所有的钥匙回到一个可观察的