RxJS Playground
A blank canvas to play / experiment with RxJS: https://github.com/Reactive-Extensions/RxJS
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.7/rx.all.js"></script>
JavaScript
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))