Skip to content

Instantly share code, notes, and snippets.

@kriskowal
Created October 25, 2020 22:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kriskowal/6680391cb88856b74364cca81d7f1a10 to your computer and use it in GitHub Desktop.
Save kriskowal/6680391cb88856b74364cca81d7f1a10 to your computer and use it in GitHub Desktop.
// @ts-check
/**
* @template T
* @typedef {{
* promise: Promise<T>,
* resolve: (value:T) => void,
* reject: (reason:Error) => void
* }} Deferred
*/
/*
* @template T
* @return {Deferred<T>}
*/
const defer = () => {
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve, reject };
};
/**
* @param {number} ms
* @return {Promise<void>}
*/
function delay(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
const period = 500;
const commands = {
ArrowLeft: 'w',
ArrowUp: 'n',
ArrowDown: 's',
ArrowRight: 'e',
};
async function main() {
/**
* @type {Deferred<void>}
*/
let kick = defer();
const queue = [];
const keyboard = {};
/**
* @param {string} command
*/
function enqueue(command) {
queue.push(command);
kick.resolve();
}
window.addEventListener('keydown', function keydown(event) {
if (!event.repeat) {
keyboard[event.key] = Date.now();
}
});
window.addEventListener('keyup', function keyup(event) {
if (event.key === 'Escape') {
queue.length = 0;
}
const since = keyboard[event.key];
if (since !== undefined) {
const now = Date.now();
const threshold = now - period;
const command = commands[event.key];
if (command !== undefined && since !== undefined && since > threshold) {
enqueue(command);
}
delete keyboard[event.key];
}
});
function flush() {
const now = Date.now();
const threshold = now - period;
for (const [key, since] of Object.entries(keyboard)) {
const command = commands[key];
if (command !== undefined ) {
if (since < threshold) {
keyboard[key] += period;
enqueue(command);
}
}
}
}
async function inputloop() {
while (true) {
flush();
await delay(period);
}
}
async function execloop() {
while (true) {
await Promise.all([kick.promise, delay(period)]);
kick = defer();
console.log('queue', queue);
queue.shift();
if (queue.length) {
kick.resolve();
}
}
}
inputloop();
execloop();
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment