Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save roadmanfong/e119d8d1bcb74acad671e3859040bc6c to your computer and use it in GitHub Desktop.
Save roadmanfong/e119d8d1bcb74acad671e3859040bc6c to your computer and use it in GitHub Desktop.
const createKeyEventObserver = () => {
const PRESS_THRESHOULD_MS = 500
const LONG_PRESS_TIME_MS = 1500
const keyDowns = fromEvent(document.body, 'keydown')
const keyUps = fromEvent(document.body, 'keyup')
const source = keyDowns
.pipe(
merge(keyUps),
distinctUntilChanged((a, b) => a.type === b.type && a.key === b.key),
map(({ key, type}) => ({ key, type })),
scan((acc, { type, key }) => (
type === 'keydown' ? [
...acc, key
] : acc.filter(item => item !== key)
), []),
scan((prev, state) => ({
operation: state.length > prev.state.length ? 'add' : 'remove',
state,
}), { state: [] }),
mergeMap((item) => (
item.operation === 'remove'
? of(0, PRESS_THRESHOULD_MS).pipe(
delayWhen(time => timer(time)),
map( value => (
value !== 0 ? {
keyUpState: [...item.state]
} : item
))
)
: of({
...item,
keyUpState: [...item.state]
})
)),
scan((prev, current) => (
current.keyUpState ? current : {
...current,
keyUpState: prev ? prev.keyUpState : []
}
)),
filter(item => item.operation),
)
const allKeyUpSource = source.pipe(
startWith({
state: []
}),
filter(item => (
item.state.length === 0
)),
map(_ => ({
event: 'allkeyup'
})),
)
const pressSource = source.pipe(
filter(({ operation, state, keyUpState }) => (
operation === 'remove' && state.length === 0 && keyUpState.length !== 0
)),
map(val => ({
event: 'press',
keys: val.keyUpState
})),
)
const longPressSource = source.pipe(
filter(item => item.state.length !== 0),
switchMap(
item => timer(LONG_PRESS_TIME_MS).pipe(
map(_ => ({
event: 'longpress',
keys: item.state
}))
)
),
)
const eventSource = allKeyUpSource.pipe(
mergeMap(
(item) => pressSource.pipe(
merge(longPressSource),
first()
)
),
tap(val => console.log(val)),
)
return eventSource
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment