Skip to content

Instantly share code, notes, and snippets.

@derekmc
Created August 18, 2025 03:32
Show Gist options
  • Select an option

  • Save derekmc/502f2851e668239c3e10bc3f82626820 to your computer and use it in GitHub Desktop.

Select an option

Save derekmc/502f2851e668239c3e10bc3f82626820 to your computer and use it in GitHub Desktop.
// early release is easier to understand than sync filter and processchord with a stack system.
//early release pct 50% - Early release can only move up release events by a maximum of 50% of the time a key is held.
//early release time: 15ms
let log = []
let leftovers = []
let t0 = Date.now()
let active = {}
let earlyup = 15 //release key early
let earlypct = 50 // max amount keyhold is reduced
let repeatInput = ''
let lastInput = ''
let repeatdt = 500
let processdt = 1000
let repeatTimeout = null
init()
function json(x){ return JSON.stringify(x)}
function repeat(){
if(repeatInput.length > 0){
input(repeatInput)
clearTimeout(repeatTimeout)
repeatTimeout = setTimeout(repeat, repeatdt)
}
}
function init(){
window.addEventListener('keydown', keydown)
window.addEventListener('keyup', keyup)
setInterval(process, processdt)
console.info('init')
}
function keydown(e){
if(active.hasOwnProperty(e.keyCode))
return
let now = Date.now()
active[e.keyCode] = now
keyevent('+', e.keyCode, now)
}
function keyup(e){
let t1 = active[e.keyCode]
delete active[e.keyCode]
let dt = Date.now() - t1
dt = Math.max(earlypct * dt/100, dt - earlyup)
keyevent('-', e.keyCode, t1 + dt)
release()
}
function keyevent(action, code, t){
console.info(`key: ${action}${code}`)
t -= t0
log.push({action, code, t})
}
function logsort(logarray){
logarray.sort((a,b)=>a.t - b.t)
}
function process(){
let now = Date.now()
let keep = []
let stack = []
let emitted = leftovers[0] ?? false
let l = [...leftovers.slice(1), ...log]
logsort(l)
if(l.length){
console.info('emitted', emitted, 'log', logstr(l))
//console.info('leftovers', json(leftovers))
}
for(let i=0; i<l.length; ++i){
let a = l[i]
let old = now - a.t
if(old < earlyup){ // do not process events until they are older than earlyup interval
keep.push(a)
console.info(`early ${a.code}`)
continue
}
//console.info('action', json(a))
if(a.action == '+'){
stack.push(a.code)
keep.push(a)
//console.info(`keep ${a.code}`)
if(i >= leftovers.length - 1) emitted = false
}
if(a.action == '-'){
if(!emitted) emit(stack.join(' '))
emitted = true
stack = stack.filter(x=>x!=a.code)
keep = keep.filter(x=>x.code!=a.code)
release()
}
}
log = []
leftovers = [emitted, ...keep]
}
function release(){
repeatInput = ''
}
function emit(seq){
if(seq == lastInput){
repeatInput = seq
clearTimeout(repeatTimeout)
repeatTimeout = setTimeout(repeat, repeatdt)
}
lastInput = seq
input(seq)
}
function input(seq){
console.info("input: " + seq + " [TODO]")
}
function logstr(l){
return l.map(x=>`${x.action}${x.code}/${x.t}`).join(' ')
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment