After yesterday's coding fiasco, I got out the Giant Code Axe to fix the problem. Actually, the Small Code Hatchet probably would have done the job. Or maybe the Lesser Code Butter Knife.
Ultimately, the problem was that I was trying to use the same piece of data to solve incompatible problems (immediate input response, and inter-frame state). The code was basically fine, I just needed to track two separate states.
I also added an UpdateInput() event that gets broadcast for every mouse or keyboard event so they can get responded to properly for UI. For gameplay, I basically just want to know how far the mouse moved in a frame, and which buttons were pressed.
Once I realized the problem, it was surprisingly easy to fix.
The peril of being a solo developer: instead of explaining your problem to a co-worker before realizing you're being an idiot, you have to explain how you're being an idiot to the whole internet first. Or at least to a bunch of loyal followers. Or a bunch of spam-bots. Is there anybody out there? Hello?
The rest of the day was spent working on some level editing stuff. I ran into a little trouble with my "spawn" component, which randomly fills an area with instances chosen from a set of models. Editing the component live doesn't work very well, since it doesn't actually track what it spawned, so resetting it just spawns new models without deleting the old ones first. Since it tries not to overlap models on spawn, it typically just can't find a spawn location and asserts.
This might be a good time to get level reset / restart working.