-
Notifications
You must be signed in to change notification settings - Fork 98
/
sequence.ts
65 lines (51 loc) · 1.64 KB
/
sequence.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import {NormalizedHotkeyString, eventToHotkeyString, normalizeHotkey} from './hotkey.js'
interface SequenceTrackerOptions {
onReset?: () => void
}
export const SEQUENCE_DELIMITER = ' '
const sequenceBrand = Symbol('sequence')
/**
* Sequence of hotkeys, separated by spaces. For example, `Mod+m g`. Obtain one through the `SequenceTracker` class or
* by normalizing a string with `normalizeSequence`.
*/
export type NormalizedSequenceString = string & {[sequenceBrand]: true}
export class SequenceTracker {
static readonly CHORD_TIMEOUT = 1500
private _path: readonly NormalizedHotkeyString[] = []
private timer: number | null = null
private onReset
constructor({onReset}: SequenceTrackerOptions = {}) {
this.onReset = onReset
}
get path(): readonly NormalizedHotkeyString[] {
return this._path
}
get sequence(): NormalizedSequenceString {
return this._path.join(SEQUENCE_DELIMITER) as NormalizedSequenceString
}
registerKeypress(event: KeyboardEvent): void {
this._path = [...this._path, eventToHotkeyString(event)]
this.startTimer()
}
reset(): void {
this.killTimer()
this._path = []
this.onReset?.()
}
private killTimer(): void {
if (this.timer != null) {
window.clearTimeout(this.timer)
}
this.timer = null
}
private startTimer(): void {
this.killTimer()
this.timer = window.setTimeout(() => this.reset(), SequenceTracker.CHORD_TIMEOUT)
}
}
export function normalizeSequence(sequence: string): NormalizedSequenceString {
return sequence
.split(SEQUENCE_DELIMITER)
.map(h => normalizeHotkey(h))
.join(SEQUENCE_DELIMITER) as NormalizedSequenceString
}