Write Only Log for 24 Oct 2025 - osric.uk

Commands can call a movement function that returns a (start, end) pair that identifies the character(s) indicated by the movement.

Problem is that I've been thinking in terms of "wait for next char from stdin", but what I've actually got is "wait for next key event".

Should prototype this, but could turn events into promises something like:

const nextKeyEvent = await new Promise((resolve, reject) => {
    const handler = e => {
        target.removeEventListener(handler);
        resolve(e);
    }
    target.addEventListener("keydown", handler);
});

But I don't think that would work with held down keys. Also, I don't like repeatedly adding and removing the event handler.

Maybe generators?

async function* nextKey(target) {
    const handler = e => {
        yield e;
    }

    target.addEventListener("keydown", handler);
}

That feels better. I'm going to try it.

Nope. The yield call doesn't count as being in the body of the generator (because it's in the body of handler, I guess).

nextKey needs to set the keypress handler for target. The handler needs to pass a value back to nextkey, so next key can yield that value to it's caller.

Handler can pass a value to nextKey with a promise. nextKey creates a promise in a variable shared with handler, and then awaits it. Handler gets a key and resolves the promise. nextKey yields the value from the promise, and them loops to reinitialize the promise.


async function* nextKey(target) {
  let sharedPromise;

  function handler(e) {
    sharedPromise.resolve(e);
  }

  target.addEventListener("keypress", handler);

  while (true) {
    sharedPromise = new Promise();    
    yield await sharedPromise;
  }
}

After testing, the code now looks like:

    async function* nextKey(target) {
        let q = Promise.withResolvers();

        function handler(e) {
            q.resolve(e);
        }

        target.addEventListener("keypress", handler);

        while (true) {
            yield await q.promise;
            q = Promise.withResolvers();
        }
    }

Promise.withResolvers returns an object with promise, reject, and resolve properties.

Next problem: keypress events don't capture tabs. ::SadFace::

Important tweak to the above code - use keydown, not keypress!

To remember your current position in the blog, this page must store some data in this browser.

Are you OK with that?