Skip to content

Instantly share code, notes, and snippets.

@derekmc
Last active February 7, 2025 17:38
Show Gist options
  • Save derekmc/08d23c4c5e0e93cdfd0dac8c2e264a41 to your computer and use it in GitHub Desktop.
Save derekmc/08d23c4c5e0e93cdfd0dac8c2e264a41 to your computer and use it in GitHub Desktop.
chord timeline example
<!doctype html>
<html>
<head>
<title> Chord Type </title>
<style>
body{
font-family: sans-serif;
}
</style>
</head>
<body>
<h1> ChordType </h1>
<p> This is an in development chorded typing processor. </p>
<button onclick='main()'> Start </button>
<script src="main.js"></script>
</body>
</html>
//main()
function page(container = document.body){
container.innerHTML = `
<h1> Hello, World </h1>
`
}
function emitChord(keylist){
console.info('chord', keylist)
}
// Early release processing
function processTimeline({timeline, params = {earlyRelease: 15},
now = Date.now(), emitter = emitChord}){
let {earlyRelease} = params
let lastPress = 0
let lastRelease = 0
let pressed = {}
// don't modify original timeline
timeline = timeline.slice(0)
// move up release times
for(let i=0; i<timeline.length; ++i){
let ev = timeline[i]
let {keyid, downup, time} = ev
let evtime = time
if(downup == "down"){
pressed[keyid] = ev
}
if(downup == "up"){
if(!pressed[keyid]){
console.warn('keyup without keydown')
} else {
evtime = Math.max(time - earlyRelease, pressed[keyid].time + 1)
console.info('time up', evtime)
delete pressed[keyid]
}
}
ev.time = evtime
}
timeline.sort((x,y)=> x.time - y.time)
console.info('timeline sorted', timeline, earlyRelease)
// reset pressed keys
pressed = {}
let chordEmitted = false
let keylist = []
// process timeline
for(let i=0; i<timeline.length; ++i){
let ev = timeline[i]
let {keyid, downup, time} = ev
if(downup == "down"){
pressed[keyid] = ev
chordEmitted = false
if(keylist.indexOf(keyid) < 0){
keylist.push(keyid)
}
}
if(downup == "up"){
console.info('keyup', keyid)
if(!pressed[keyid]){
console.warn('keyup without keydown')
} else if(!chordEmitted){
chordEmitted = true
emitter(keylist)
keylist = keylist.filter(x=>x!==keyid)
delete pressed[keyid]
}
}
}
// create "leftover" timeline, of all pressed, but not released, keys
let leftovers = []
for(let k in pressed){
leftovers.push(pressed[k])
}
leftovers.sort((x,y)=> x.time - y.time)
return leftovers
}
// timelines are a sequence of keyevents that can be "batch" processed.
// timeline: [[keyid, "down" | "up", time]...]
function exampleTimeline(){
let timeline = []
let start = 999
timeline.push({keyid: 3, downup: "down", time: start - 100})
timeline.push({keyid: 1, downup: "down", time: start})
timeline.push({keyid: 2, downup: "down", time: start + 100})
timeline.push({keyid: 1, downup: "up", time: start + 115})
timeline.push({keyid: 2, downup: "up", time: start + 500})
return timeline
}
function main(){
console.log('main')
let t1 = exampleTimeline()
console.log('exampleTimeline', json(t1))
let t2 = processTimeline({timeline:t1})
console.log('leftovers', json(t2))
//let t2 =
page()
}
function json(x){
return JSON.stringify(x)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment