2017-04-05 13 views
1

私はRxJにはかなり新しく、これに対する解決策を読んでいません。もっと詳しい説明はコメントにありますが、基本的には特定のキーが押されたときにキーの組み合わせを処理したいと思います( "o"を押すと他のキーが押されるのを待つ)そうでない場合はキー入力を直ちに処理します( "o"が押されていない場合は "o"、 "o"の場合は "timeout"が経過しています)。RxJsのイベントに基づいてキー入力を条件付きでバッファリングする方法

Observable.fromEvent(document, 'keydown') 
    // Now I want to only continue processing the event if the user pressed "o99" in series, 
    // as in pressed "o", followed by "9" and then another "9" 
    // I think I can do it with buffer 
    .buffer(() => Observable.timer(1000)) 
    .map((e) => 'option-99') 
    // However I need to pass the keys through unbuffered if it's anything but an "o" (unless it is following an "o") 
    // In other words, "o99" is buffered or something, but "9" is not, and processed immediately 
    .map((e) => e.keyCode) 

おかげ

+0

は私にしばらくけど参照しました小さなステートマシンでロジックを実装する私の答え – user3743222

答えて

1

あなたは、その関連するアクション(すなわち、あなたは基本的なステートマシンを持っている)、いくつかの制御状態に依存するイベントのことであるに対処するための非常に一般的なケースを持っています。 SIMPLE_KEYCOMBO、およびこれら二つの事象:keyup、およびkeyupTimer、その後:あなたはそれら二つの制御状態を検討した場合、基本的にSIMPLE_KEY状態で

    • を押されたキーがoであれば、あなた
    • がないo場合は、その後、私たちは同じ状態のまま
    • COMBO状態に切り替え、その後、キー下流
    • タイマーイベントであれば、私たちPASを渡しますタイマーイベント場合SA我々はキーを蓄積下流
  • COMBO状態で
    • を除外するためのnull値は、我々はそうSIMPLE_KEY状態

に戻り、

  • を押しますあなたのイベントをアクションにマッピングするには、あなたがいる制御状態を知る必要があります。scanオペレータは、 o蓄積された状態に応じてイベントを処理する。それはこのような何か(https://jsfiddle.net/cbhmxaas/)可能性があり

    function getKeyFromEvent(ev) {return ev.key} 
    function isKeyPressedIsO(ev) {return getKeyFromEvent(ev) === 'o'} 
    
    const KEY = 'key'; 
    const TIMER = 'timer'; 
    const COMBO = 'combo'; 
    const SIMPLE_KEY = 'whatever'; 
    const timeSpanInMs = 1000; 
    const keyup$ = Rx.Observable.fromEvent(document, 'keyup') 
        .map(ev => ({event: KEY, data: getKeyFromEvent(ev)})); 
    const keyupTimer$ = keyup$.flatMapLatest(eventStruct => 
        Rx.Observable.of(eventStruct) 
    // .tap(console.warn.bind(console, 'timer event')) 
        .delay(timeSpanInMs) 
        .map(() => ({event : TIMER, data: null})) 
        ); 
    
    Rx.Observable.merge(keyup$, keyupTimer$) 
    // .tap(console.warn.bind(console)) 
        .scan((acc, eventStruct) => { 
        if (acc.control === SIMPLE_KEY) { 
         if (eventStruct.event === KEY) { 
         if (eventStruct.data === `o`) { 
          return {control: COMBO, keyOrKeys : []} 
         } 
         else { 
          return {control: SIMPLE_KEY, keyOrKeys : eventStruct.data} 
         } 
         } 
         else { 
         // TIMER event 
         return {control: SIMPLE_KEY, keyOrKeys : null} 
         } 
        } 
        else { 
         // we only have two states, so it is COMBO state here 
         if (eventStruct.event === KEY) { 
         return {control: COMBO, keyOrKeys : acc.keyOrKeys.concat([eventStruct.data])} 
         } 
         else { 
         // this is a TIMER event, we only have two events 
         return {control: SIMPLE_KEY, keyOrKeys : acc.keyOrKeys} 
         } 
        } 
        }, {control: SIMPLE_KEY, keyOrKeys : null}) 
    // .tap(console.warn.bind(console)) 
        .filter(state => state.keyOrKeys) // TIMER event in SIMPLE_KEY state 
        .map (({control, keyOrKeys}) => { 
        // Here you associate your action 
        // if keyOrKeys is an array, then you have a combo 
        // else you have a single key 
        console.log('key(s) pressed', keyOrKeys) 
        return keyOrKeys 
    }) 
        .subscribe (console.log.bind(console)) 
    
  • 関連する問題